[SCM] single/multiplayer lobby for the Spring RTS engine branch, master, updated. 28165f47675c144b846786b0435aa7f9b3396209
Marco Amadori
marco.amadori at gmail.com
Tue Oct 27 16:02:06 UTC 2009
The following commit has been merged in the master branch:
commit d69f9b99fe56ef5ca7f229b9d274622e8bffa099
Author: Marco Amadori <marco.amadori at gmail.com>
Date: Tue Oct 27 15:05:41 2009 +0100
Imported Upstream version 0.29
diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100644
index 0000000..83bc72e
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,1068 @@
+1 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. If you happen to have the `LC_ALL' or some other
+`LC_xxx' environment variables set, you should unset them before
+setting `LANG', otherwise the setting of `LANG' will not have the
+desired effect. 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://translationproject.org/', in the "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 at 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 `coordinator at translationproject.org' 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 November
+2007. 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
+ +----------------------------------------------------+
+ Compendium | [] [] [] [] |
+ a2ps | [] [] [] [] [] |
+ aegis | () |
+ ant-phone | () |
+ anubis | [] |
+ ap-utils | |
+ aspell | [] [] [] [] [] |
+ bash | [] |
+ bfd | |
+ bibshelf | [] |
+ binutils | |
+ bison | [] [] |
+ bison-runtime | [] |
+ bluez-pin | [] [] [] [] [] |
+ cflow | [] |
+ clisp | [] [] [] |
+ console-tools | [] [] |
+ coreutils | [] [] [] [] |
+ cpio | |
+ cpplib | [] [] [] |
+ cryptonit | [] |
+ dialog | |
+ diffutils | [] [] [] [] [] [] |
+ doodle | [] |
+ e2fsprogs | [] [] |
+ enscript | [] [] [] [] |
+ fetchmail | [] [] () [] [] |
+ findutils | [] |
+ findutils_stable | [] [] [] |
+ flex | [] [] [] |
+ fslint | |
+ gas | |
+ gawk | [] [] [] |
+ gcal | [] |
+ gcc | [] |
+ gettext-examples | [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] |
+ gettext-tools | [] [] |
+ gip | [] |
+ gliv | [] [] |
+ glunarclock | [] |
+ gmult | [] [] |
+ gnubiff | () |
+ gnucash | [] [] () () [] |
+ gnuedu | |
+ gnulib | [] |
+ gnunet | |
+ 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-bad | [] [] |
+ gst-plugins-base | [] [] |
+ gst-plugins-good | [] [] [] |
+ gst-plugins-ugly | [] [] |
+ gstreamer | [] [] [] [] [] [] [] |
+ gtick | () |
+ gtkam | [] [] [] [] |
+ gtkorphan | [] [] |
+ gtkspell | [] [] [] [] |
+ gutenprint | [] |
+ hello | [] [] [] [] [] |
+ herrie | [] |
+ hylafax | |
+ idutils | [] [] |
+ indent | [] [] [] [] |
+ iso_15924 | |
+ 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 | |
+ lprng | |
+ lynx | [] [] [] [] |
+ m4 | [] [] [] [] |
+ mailfromd | |
+ mailutils | [] |
+ make | [] [] |
+ man-db | [] [] [] |
+ minicom | [] [] [] |
+ nano | [] [] [] |
+ opcodes | [] |
+ parted | [] [] |
+ pilot-qof | |
+ popt | [] [] [] |
+ psmisc | [] |
+ pwdutils | |
+ qof | |
+ radius | [] |
+ recode | [] [] [] [] [] [] |
+ rpm | [] |
+ screem | |
+ scrollkeeper | [] [] [] [] [] [] [] [] |
+ sed | [] [] [] |
+ shared-mime-info | [] [] [] [] () [] [] [] |
+ sharutils | [] [] [] [] [] [] |
+ shishi | |
+ skencil | [] () |
+ solfege | |
+ soundtracker | [] [] |
+ sp | [] |
+ system-tools-ba... | [] [] [] [] [] [] [] [] [] |
+ tar | [] [] |
+ texinfo | [] [] [] |
+ tin | () () |
+ tuxpaint | [] [] [] [] [] [] |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux | [] [] [] [] |
+ util-linux-ng | [] [] [] [] |
+ 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
+ 6 0 2 1 8 26 2 40 48 2 56 88 15 1 15 18
+
+ es et eu fa fi fr ga gl gu he hi hr hu id is it
+ +--------------------------------------------------+
+ Compendium | [] [] [] [] [] |
+ a2ps | [] [] [] () |
+ aegis | |
+ ant-phone | [] |
+ anubis | [] |
+ ap-utils | [] [] |
+ aspell | [] [] [] |
+ bash | [] |
+ bfd | [] [] |
+ bibshelf | [] [] [] |
+ binutils | [] [] [] |
+ bison | [] [] [] [] [] [] |
+ bison-runtime | [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] |
+ cflow | [] |
+ clisp | [] [] |
+ console-tools | |
+ coreutils | [] [] [] [] [] [] |
+ cpio | [] [] [] |
+ cpplib | [] [] |
+ cryptonit | [] |
+ dialog | [] [] [] |
+ diffutils | [] [] [] [] [] [] [] [] [] |
+ doodle | [] [] |
+ e2fsprogs | [] [] [] |
+ enscript | [] [] [] |
+ fetchmail | [] |
+ findutils | [] [] [] |
+ findutils_stable | [] [] [] [] |
+ flex | [] [] [] |
+ fslint | |
+ gas | [] [] |
+ gawk | [] [] [] [] () |
+ gcal | [] [] |
+ gcc | [] |
+ gettext-examples | [] [] [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] [] |
+ gettext-tools | [] [] [] [] |
+ gip | [] [] [] [] |
+ gliv | () |
+ glunarclock | [] [] [] |
+ gmult | [] [] [] |
+ gnubiff | () () |
+ gnucash | () () () |
+ gnuedu | [] |
+ gnulib | [] [] [] |
+ gnunet | |
+ 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-bad | [] [] [] [] |
+ gst-plugins-base | [] [] [] [] |
+ gst-plugins-good | [] [] [] [] [] |
+ gst-plugins-ugly | [] [] [] [] |
+ gstreamer | [] [] [] |
+ gtick | [] [] [] |
+ gtkam | [] [] [] [] |
+ gtkorphan | [] [] |
+ gtkspell | [] [] [] [] [] [] [] |
+ gutenprint | [] |
+ hello | [] [] [] [] [] [] [] [] [] [] [] [] [] |
+ herrie | [] |
+ hylafax | |
+ idutils | [] [] [] [] [] |
+ indent | [] [] [] [] [] [] [] [] [] [] |
+ iso_15924 | [] |
+ 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 | [] [] [] |
+ lprng | |
+ lynx | [] [] [] |
+ m4 | [] [] [] [] |
+ mailfromd | |
+ mailutils | [] [] |
+ make | [] [] [] [] [] [] [] [] |
+ man-db | [] |
+ minicom | [] [] [] [] |
+ nano | [] [] [] [] [] [] [] |
+ opcodes | [] [] [] [] |
+ parted | [] [] [] |
+ pilot-qof | |
+ popt | [] [] [] [] |
+ psmisc | [] [] |
+ pwdutils | |
+ qof | [] |
+ radius | [] [] |
+ recode | [] [] [] [] [] [] [] [] |
+ rpm | [] [] |
+ screem | |
+ scrollkeeper | [] [] [] |
+ sed | [] [] [] [] [] |
+ shared-mime-info | [] [] [] [] [] [] |
+ sharutils | [] [] [] [] [] [] [] [] |
+ shishi | [] |
+ skencil | [] [] |
+ solfege | [] |
+ soundtracker | [] [] [] |
+ sp | [] |
+ system-tools-ba... | [] [] [] [] [] [] [] [] [] |
+ tar | [] [] [] [] [] |
+ texinfo | [] [] [] |
+ tin | [] () |
+ tuxpaint | [] [] |
+ unicode-han-tra... | |
+ unicode-transla... | [] [] |
+ util-linux | [] [] [] [] [] [] [] |
+ util-linux-ng | [] [] [] [] [] [] [] |
+ 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
+ 85 22 14 2 48 101 61 12 2 8 2 6 53 29 1 52
+
+ ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn
+ +--------------------------------------------------+
+ Compendium | [] |
+ a2ps | () [] [] |
+ aegis | () |
+ ant-phone | [] |
+ anubis | [] [] [] |
+ ap-utils | [] |
+ aspell | [] [] |
+ bash | [] |
+ bfd | |
+ bibshelf | [] |
+ binutils | |
+ bison | [] [] [] |
+ bison-runtime | [] [] [] |
+ bluez-pin | [] [] [] |
+ cflow | |
+ clisp | [] |
+ console-tools | |
+ coreutils | [] |
+ cpio | [] |
+ cpplib | [] |
+ cryptonit | [] |
+ dialog | [] [] |
+ diffutils | [] [] [] |
+ doodle | |
+ e2fsprogs | [] |
+ enscript | [] |
+ fetchmail | [] [] |
+ findutils | [] |
+ findutils_stable | [] |
+ flex | [] [] |
+ fslint | |
+ gas | |
+ gawk | [] [] |
+ gcal | |
+ gcc | |
+ gettext-examples | [] [] [] |
+ gettext-runtime | [] [] [] |
+ gettext-tools | [] [] |
+ gip | [] [] |
+ gliv | [] |
+ glunarclock | [] [] |
+ gmult | [] [] [] |
+ gnubiff | |
+ gnucash | () () () |
+ gnuedu | |
+ gnulib | [] [] |
+ gnunet | |
+ 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-bad | [] |
+ gst-plugins-base | [] |
+ gst-plugins-good | [] |
+ gst-plugins-ugly | [] |
+ gstreamer | [] |
+ gtick | [] |
+ gtkam | [] [] |
+ gtkorphan | [] |
+ gtkspell | [] [] |
+ gutenprint | [] |
+ hello | [] [] [] [] [] [] [] |
+ herrie | [] |
+ hylafax | |
+ idutils | [] |
+ indent | [] [] |
+ iso_15924 | [] |
+ 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 | [] |
+ lprng | |
+ lynx | [] [] |
+ m4 | [] [] |
+ mailfromd | |
+ mailutils | |
+ make | [] [] [] |
+ man-db | |
+ minicom | [] |
+ nano | [] [] [] |
+ opcodes | [] |
+ parted | [] [] |
+ pilot-qof | |
+ popt | [] [] [] |
+ psmisc | [] [] [] |
+ pwdutils | |
+ qof | |
+ radius | |
+ recode | [] |
+ rpm | [] [] |
+ screem | [] |
+ scrollkeeper | [] [] [] [] |
+ sed | [] [] |
+ shared-mime-info | [] [] [] [] [] [] [] |
+ sharutils | [] [] |
+ shishi | |
+ skencil | |
+ solfege | () () |
+ soundtracker | |
+ sp | () |
+ system-tools-ba... | [] [] [] [] |
+ tar | [] [] [] |
+ texinfo | [] [] |
+ tin | |
+ tuxpaint | () [] [] |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux | [] [] |
+ util-linux-ng | [] [] |
+ vorbis-tools | |
+ wastesedge | [] |
+ wdiff | [] [] |
+ wget | [] [] |
+ xchat | [] [] [] [] |
+ xkeyboard-config | [] [] [] |
+ xpad | [] [] [] |
+ +--------------------------------------------------+
+ ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn
+ 51 2 25 3 2 0 6 0 2 2 20 0 11 1 103 6
+
+ or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta
+ +--------------------------------------------------+
+ Compendium | [] [] [] [] [] |
+ a2ps | () [] [] [] [] [] [] |
+ aegis | () () |
+ ant-phone | [] [] |
+ anubis | [] [] [] |
+ ap-utils | () |
+ aspell | [] [] [] |
+ bash | [] [] |
+ bfd | |
+ bibshelf | [] |
+ binutils | [] [] |
+ bison | [] [] [] [] [] |
+ bison-runtime | [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] [] [] [] [] |
+ cflow | [] |
+ clisp | [] |
+ console-tools | [] |
+ coreutils | [] [] [] [] |
+ cpio | [] [] [] |
+ cpplib | [] |
+ cryptonit | [] [] |
+ dialog | [] |
+ diffutils | [] [] [] [] [] [] |
+ doodle | [] [] |
+ e2fsprogs | [] [] |
+ enscript | [] [] [] [] [] |
+ fetchmail | [] [] [] |
+ findutils | [] [] [] |
+ findutils_stable | [] [] [] [] [] [] |
+ flex | [] [] [] [] [] |
+ fslint | [] |
+ gas | |
+ gawk | [] [] [] [] |
+ gcal | [] |
+ gcc | [] [] |
+ gettext-examples | [] [] [] [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] [] [] [] |
+ gettext-tools | [] [] [] [] [] [] [] |
+ gip | [] [] [] [] |
+ gliv | [] [] [] [] [] [] |
+ glunarclock | [] [] [] [] [] [] |
+ gmult | [] [] [] [] |
+ gnubiff | () [] |
+ gnucash | () [] |
+ gnuedu | |
+ gnulib | [] [] [] |
+ gnunet | |
+ 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-bad | [] [] [] |
+ gst-plugins-base | [] [] |
+ gst-plugins-good | [] [] |
+ gst-plugins-ugly | [] [] [] |
+ gstreamer | [] [] [] [] |
+ gtick | [] |
+ gtkam | [] [] [] [] [] |
+ gtkorphan | [] |
+ gtkspell | [] [] [] [] [] [] [] [] |
+ gutenprint | [] |
+ hello | [] [] [] [] [] [] [] [] |
+ herrie | [] [] [] |
+ hylafax | |
+ idutils | [] [] [] [] [] |
+ indent | [] [] [] [] [] [] [] |
+ iso_15924 | |
+ 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 | [] |
+ lprng | [] |
+ lynx | [] [] [] |
+ m4 | [] [] [] [] [] |
+ mailfromd | [] |
+ mailutils | [] [] [] |
+ make | [] [] [] [] |
+ man-db | [] [] [] [] |
+ minicom | [] [] [] [] [] |
+ nano | [] [] [] [] |
+ opcodes | [] [] |
+ parted | [] |
+ pilot-qof | |
+ popt | [] [] [] [] |
+ psmisc | [] [] |
+ pwdutils | [] [] |
+ qof | [] [] |
+ radius | [] [] |
+ recode | [] [] [] [] [] [] [] |
+ rpm | [] [] [] [] |
+ screem | |
+ scrollkeeper | [] [] [] [] [] [] [] |
+ sed | [] [] [] [] [] [] [] [] [] |
+ shared-mime-info | [] [] [] [] [] [] |
+ sharutils | [] [] [] [] |
+ shishi | [] |
+ skencil | [] [] [] |
+ solfege | [] |
+ soundtracker | [] [] |
+ sp | |
+ system-tools-ba... | [] [] [] [] [] [] [] [] [] |
+ tar | [] [] [] [] |
+ texinfo | [] [] [] [] |
+ tin | () |
+ tuxpaint | [] [] [] [] [] [] |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux | [] [] [] [] |
+ util-linux-ng | [] [] [] [] |
+ vorbis-tools | [] |
+ wastesedge | |
+ wdiff | [] [] [] [] [] [] [] |
+ wget | [] [] [] [] |
+ xchat | [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] |
+ xpad | [] [] [] |
+ +--------------------------------------------------+
+ or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta
+ 0 5 77 31 53 4 58 72 3 45 46 9 45 122 3
+
+ tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu
+ +---------------------------------------------------+
+ Compendium | [] [] [] [] | 19
+ a2ps | [] [] [] | 19
+ aegis | [] | 1
+ ant-phone | [] [] | 6
+ anubis | [] [] [] | 11
+ ap-utils | () [] | 4
+ aspell | [] [] [] | 16
+ bash | [] | 6
+ bfd | | 2
+ bibshelf | [] | 7
+ binutils | [] [] [] [] | 9
+ bison | [] [] [] [] | 20
+ bison-runtime | [] [] [] [] | 18
+ bluez-pin | [] [] [] [] [] [] | 28
+ cflow | [] [] | 5
+ clisp | | 9
+ console-tools | [] [] | 5
+ coreutils | [] [] [] | 18
+ cpio | [] [] [] [] | 11
+ cpplib | [] [] [] [] [] | 12
+ cryptonit | [] | 6
+ dialog | [] [] [] | 9
+ diffutils | [] [] [] [] [] | 29
+ doodle | [] | 6
+ e2fsprogs | [] [] | 10
+ enscript | [] [] [] | 16
+ fetchmail | [] [] | 12
+ findutils | [] [] [] | 11
+ findutils_stable | [] [] [] [] | 18
+ flex | [] [] | 15
+ fslint | [] | 2
+ gas | [] | 3
+ gawk | [] [] [] | 16
+ gcal | [] | 5
+ gcc | [] [] [] | 7
+ gettext-examples | [] [] [] [] [] [] | 29
+ gettext-runtime | [] [] [] [] [] [] | 28
+ gettext-tools | [] [] [] [] [] | 20
+ gip | [] [] | 13
+ gliv | [] [] | 11
+ glunarclock | [] [] [] | 15
+ gmult | [] [] [] [] | 16
+ gnubiff | [] | 2
+ gnucash | () [] | 5
+ gnuedu | [] | 2
+ gnulib | [] | 10
+ gnunet | | 0
+ gnunet-gtk | [] [] | 3
+ gnutls | | 4
+ gpe-aerial | [] [] | 14
+ gpe-beam | [] [] | 14
+ gpe-calendar | [] [] | 7
+ gpe-clock | [] [] [] [] | 21
+ gpe-conf | [] [] [] | 16
+ gpe-contacts | [] [] | 10
+ gpe-edit | [] [] [] [] [] | 22
+ gpe-filemanager | [] [] | 7
+ gpe-go | [] [] [] [] | 19
+ gpe-login | [] [] [] [] [] | 21
+ gpe-ownerinfo | [] [] [] [] | 21
+ gpe-package | [] | 6
+ gpe-sketchbook | [] [] | 16
+ gpe-su | [] [] [] [] | 21
+ gpe-taskmanager | [] [] [] [] | 21
+ gpe-timesheet | [] [] [] [] | 18
+ gpe-today | [] [] [] [] [] | 21
+ gpe-todo | [] [] | 8
+ gphoto2 | [] [] [] [] | 21
+ gprof | [] [] | 13
+ gpsdrive | [] | 5
+ gramadoir | [] | 7
+ grep | [] | 12
+ gretl | | 6
+ gsasl | [] [] [] | 9
+ gss | [] | 7
+ gst-plugins-bad | [] [] [] | 13
+ gst-plugins-base | [] [] | 11
+ gst-plugins-good | [] [] [] [] [] | 16
+ gst-plugins-ugly | [] [] [] | 13
+ gstreamer | [] [] [] | 18
+ gtick | [] [] | 7
+ gtkam | [] | 16
+ gtkorphan | [] | 7
+ gtkspell | [] [] [] [] [] [] | 27
+ gutenprint | | 4
+ hello | [] [] [] [] [] | 38
+ herrie | [] [] | 8
+ hylafax | | 0
+ idutils | [] [] | 15
+ indent | [] [] [] [] [] | 28
+ iso_15924 | [] [] | 4
+ iso_3166 | [] [] [] [] [] [] [] [] [] | 54
+ iso_3166_2 | [] [] | 4
+ iso_4217 | [] [] [] [] [] | 24
+ iso_639 | [] [] [] [] [] | 26
+ jpilot | [] [] [] [] | 7
+ jtag | [] | 3
+ jwhois | [] [] [] | 13
+ kbd | [] [] [] | 13
+ keytouch | [] | 8
+ keytouch-editor | [] | 5
+ keytouch-keyboa... | [] | 5
+ latrine | [] [] | 5
+ ld | [] [] [] [] | 10
+ leafpad | [] [] [] [] [] | 24
+ libc | [] [] [] | 19
+ libexif | [] | 5
+ libextractor | [] | 5
+ libgpewidget | [] [] [] | 20
+ libgpg-error | [] | 6
+ libgphoto2 | [] [] | 9
+ libgphoto2_port | [] [] [] | 11
+ libgsasl | [] | 8
+ libiconv | [] [] | 11
+ libidn | [] [] | 11
+ lifelines | | 4
+ lilypond | [] | 6
+ lingoteach | [] | 6
+ lprng | [] | 2
+ lynx | [] [] [] | 15
+ m4 | [] [] [] | 18
+ mailfromd | [] [] | 3
+ mailutils | [] [] | 8
+ make | [] [] [] | 20
+ man-db | [] | 9
+ minicom | [] | 14
+ nano | [] [] [] | 20
+ opcodes | [] [] | 10
+ parted | [] [] [] | 11
+ pilot-qof | [] | 1
+ popt | [] [] [] [] | 18
+ psmisc | [] [] | 10
+ pwdutils | [] | 3
+ qof | [] | 4
+ radius | [] [] | 7
+ recode | [] [] [] | 25
+ rpm | [] [] [] [] | 13
+ screem | [] | 2
+ scrollkeeper | [] [] [] [] | 26
+ sed | [] [] [] [] | 23
+ shared-mime-info | [] [] [] | 29
+ sharutils | [] [] [] | 23
+ shishi | [] | 3
+ skencil | [] | 7
+ solfege | [] | 3
+ soundtracker | [] [] | 9
+ sp | [] | 3
+ system-tools-ba... | [] [] [] [] [] [] [] | 38
+ tar | [] [] [] | 17
+ texinfo | [] [] [] | 15
+ tin | | 1
+ tuxpaint | [] [] [] | 19
+ unicode-han-tra... | | 0
+ unicode-transla... | | 2
+ util-linux | [] [] [] | 20
+ util-linux-ng | [] [] [] | 20
+ vorbis-tools | [] [] | 4
+ wastesedge | | 1
+ wdiff | [] [] | 23
+ wget | [] [] [] | 20
+ xchat | [] [] [] [] | 29
+ xkeyboard-config | [] [] [] | 14
+ xpad | [] [] [] | 15
+ +---------------------------------------------------+
+ 76 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu
+ 163 domains 0 3 1 74 51 0 143 21 1 57 7 45 0 2036
+
+ 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 November 2007 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://translationproject.org/extra/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
+`coordinator at translationproject.org' to make the `.pot' files available
+to the translation teams.
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..865a486
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,27 @@
+The SpringLobby Team
+
+tc
+
+ Original author, responsible for basically all features.
+
+koshi
+
+ Responsible for services, site, build and packaging, portability, springsettings etc. (also BD's GUI-goto-guy ;-) )
+
+braindamage
+
+ Some features and rpm maintenance.
+
+Tobi
+
+ map selector, threaded unitsync
+
+Retired Team Members
+
+tronic
+
+ C++ and design mentor, refactoring.
+
+semi
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..7841ea1
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,441 @@
+PROJECT(SpringLobby)
+
+#set minimum cmake version
+cmake_minimum_required(VERSION 2.6)
+SET(CMAKE_COLOR_MAKEFILE ON)
+
+# Add Definitions, Compiler-Switches, etc.: -Wall -O2 -g3 ...
+# MSVC compiler (cl.exe) does not accept the same switches as gcc, although preprocessor definitions in the -D form will work for both
+IF(NOT MSVC)
+ ADD_DEFINITIONS(-Wall -Wno-strict-aliasing)
+ENDIF(NOT MSVC)
+IF(WIN32)
+ ADD_DEFINITIONS( -DWXUSINGDLL -D__WXMSW__ -D_WIN32_WINNT=0x0501)
+ENDIF(WIN32)
+IF(MSVC)
+ ADD_DEFINITIONS(-D_RC_MSVC)
+ENDIF(MSVC)
+
+
+
+
+
+#----------------------------------------------------------------------------------------------------
+# General Settings
+#----------------------------------------------------------------------------------------------------
+SET( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
+SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".lib" ".a")
+
+#----------------------------------------------------------------------------------------------------
+# Load needed Modules
+#----------------------------------------------------------------------------------------------------
+# PKG-Config
+FIND_PACKAGE( PkgConfig )
+INCLUDE(cmake/package_config.cmake)
+INCLUDE(CPack)
+IF(CMAKE_CROSSCOMPILING OR NOT WIN32)
+ INCLUDE(cmake/FindSDL.cmake)
+ INCLUDE(cmake/FindSDL_sound.cmake)
+ INCLUDE(cmake/FindSDL_mixer.cmake)
+ENDIF(CMAKE_CROSSCOMPILING OR NOT WIN32)
+
+
+#----------------------------------------------------------------------------------------------------
+# Options, that can be changed be the User in order to customise SpringLobby
+#----------------------------------------------------------------------------------------------------
+SET( OPTION_TORRENT_SYSTEM
+ 1 CACHE BOOL
+ "Enables the builtin map/mod p2p downloader (requires libtorrent-rasterbar library)" )
+SET( OPTION_SOUND
+ 1 CACHE BOOL
+ "Enables sound notification functionality (requires SDL and SDL_sound libraries)" )
+SET( OPTION_TRANSLATION_SUPPORT
+ 0 CACHE BOOL
+ "Enables translation support to the programs and adds facilities for helping translators (requires GNU Gettext)" )
+SET( BUILD_SHARED_LIBS
+ 1 CACHE BOOL
+ "Chooses whether to link dynamic or static libraries. Recommend keeping this activated unless you know what you're doing." )
+
+
+#----------------------------------------------------------------------------------------------------
+# wxWidgets lib dependency check
+#----------------------------------------------------------------------------------------------------
+
+# Here you can define, what Libraries of wxWidgets you need for your Application. You can figure out what Libraries you need here:
+# http://www.wxwidgets.org/manuals/2.8/wx_librarieslist.html
+IF(NOT CMAKE_CROSSCOMPILING)
+SET(wxWidgets_USE_LIBS base core net adv aui html xml )
+
+# We need the Find package for wxWidgets to work
+FIND_PACKAGE(wxWidgets REQUIRED base core net adv aui html xml)
+
+# Did we find wxWidgets ? This condition will fail for as long as the internal Vars do not point to the proper wxWidgets Configuration.
+IF(wxWidgets_FOUND)
+ # Include wxWidgets macros
+ INCLUDE(${wxWidgets_USE_FILE})
+ IF(MSVC)
+ INCLUDE_DIRECTORIES( ${wxWidgets_ROOT_DIR}/include/msvc )
+ ENDIF(MSVC)
+ IF(MINGW)
+ SET(wxWidgets_RC_DIR ${wxWidgets_ROOT_DIR}/include)
+ ENDIF(MINGW)
+ INCLUDE_DIRECTORIES( ${wxWidgets_INCLUDE_DIRS} )
+ELSE(wxWidgets_FOUND)
+ # For Convenience. If we cannot continue, inform the User.
+ MESSAGE( FATAL_ERROR "wxWidgets library is not found! Please install the package to continue")
+ENDIF(wxWidgets_FOUND)
+ELSE (NOT CMAKE_CROSSCOMPILING)
+ INCLUDE_DIRECTORIES( ${wxWidgets_INCLUDE_DIRS} )
+ link_directories( ${wxWidgets_LIB_DIR} )
+ENDIF(NOT CMAKE_CROSSCOMPILING)
+
+#----------------------------------------------------------------------------------------------------
+# SDL libs dependency check
+#----------------------------------------------------------------------------------------------------
+IF ( OPTION_SOUND )
+
+ IF (CMAKE_CROSSCOMPILING OR NOT WIN32)
+ FIND_PACKAGE(SDL REQUIRED)
+ FIND_PACKAGE(SDL_mixer REQUIRED)
+ FIND_PACKAGE(SDL_sound REQUIRED)
+
+ # Throw an error to the user if SDL is not found
+ if ( NOT SDL_FOUND )
+ message ( FATAL_ERROR "SDL library was not found! Please install the package or toggle OPTION_SOUND to OFF" )
+ endif( NOT SDL_FOUND )
+
+ # Throw an error to the user if SDL_mixer is not found
+ if ( NOT SDLMIXER_FOUND )
+ message ( FATAL_ERROR "SDL_mixer library was not found! Please install the package or toggle OPTION_SOUND to OFF" )
+ endif(NOT SDLMIXER_FOUND)
+
+ # Throw an error to the user if SDL_sound is not found
+ if ( NOT SDL_SOUND_FOUND )
+ message ( FATAL_ERROR "SDL_sound library was not found! Please install the package or toggle OPTION_SOUND to OFF" )
+ endif( NOT SDL_SOUND_FOUND )
+
+ # MESSAGE("sound inc dir: ${SDL_SOUND_INCLUDE_DIR}")
+ # MESSAGE("mixer inc dir: ${SDLMIXER_INCLUDE_DIR}")
+ # MESSAGE("sound libs: ${SDL_SOUND_LIBRARIES}")
+ # MESSAGE("mixer libs: ${SDLMIXER_LIBRARY}")
+ ENDIF(CMAKE_CROSSCOMPILING OR NOT WIN32)
+
+ IF(NOT WIN32)
+ # Set include paths and libraries to link.
+ INCLUDE_DIRECTORIES( ${SDL_SOUND_INCLUDE_DIR} ${SDLMIXER_INCLUDE_DIR} )
+ LINK_LIBRARIES( # ${SDL_SOUND_LIBRARIES}
+ ${SDLMIXER_LIBRARY} )
+ ELSE(NOT WIN32)
+ SET(SDL_INCLUDE_DIR "SDL_INCLUDE_DIR_NOT_SET" CACHE PATH "Path to SDL header files (sdl_mixer.h should be in the same dir as well)")
+ SET(SDLMAIN_LIBRARY "SDLMAIN_LIBRARY_NOT_SET" CACHE FILEPATH "Filepath to SDLmain.lib or libsdlmain.a, depending on whether you're using MSVC or MingW")
+ SET(SDL_LIBRARY "SDL_LIBRARY_NOT_SET" CACHE FILEPATH "Filepath to SDL.lib or libsdl.dll.a, depending on whether you're using MSVC or MingW")
+ SET(SDLMIXER_LIBRARY "SDLMIXER_LIBRARY_NOT_SET" CACHE FILEPATH "Filepath to SDL_mixer.lib or libSDL_mixer.dll.a, depending on whether you're using MSVC or MingW")
+ IF(NOT CMAKE_CROSSCOMPILING)
+ INCLUDE_DIRECTORIES( ${SDL_INCLUDE_DIR})
+ LINK_LIBRARIES(${SDLMAIN_LIBRARY} ${SDL_LIBRARY} ${SDLMIXER_LIBRARY})
+ ELSE(NOT CMAKE_CROSSCOMPILING)
+ INCLUDE_DIRECTORIES( ${sdl_INCLUDE_DIR} )
+ LINK_LIBRARIES(SDLmain SDL SDL_mixer)
+ ENDIF(NOT CMAKE_CROSSCOMPILING)
+ ENDIF(NOT WIN32)
+
+ELSE ( OPTION_SOUND )
+ # Disable sound.
+ ADD_DEFINITIONS( -DDISABLE_SOUND )
+ENDIF ( OPTION_SOUND )
+
+
+#----------------------------------------------------------------------------------------------------
+# Gettext lib dependency check
+#----------------------------------------------------------------------------------------------------
+
+if( OPTION_TRANSLATION_SUPPORT )
+ set(Gettext_DIR "po" )
+ INCLUDE(cmake/FindGettext.cmake)
+ if(GETTEXT_FOUND)
+ set(SpringLobby_INCLUDE_PATH ${SpringLobby_INCLUDE_PATH}
+ ${GETTEXT_INCLUDE_DIR} CACHE INTERNAL "" FORCE)
+
+ include("cmake/KWWidgetsInternationalizationMacros.cmake")
+ else(GETTEXT_FOUND)
+ message(FATAL_ERROR "The GNU Gettext package is not found! Please install the package or toggle OPTION_TRANSLATION_SUPPORT to OFF")
+ endif(GETTEXT_FOUND)
+endif( OPTION_TRANSLATION_SUPPORT )
+
+#----------------------------------------------------------------------------------------------------
+# libtorrent-rasterbar dependency check
+#----------------------------------------------------------------------------------------------------
+
+IF( OPTION_TORRENT_SYSTEM )
+ IF( NOT WIN32)
+ SET ( LIBTORRENT_MIN_VERSION 0.13 )
+ pkg_check_modules( LIBTORRENT libtorrent-rasterbar>=${LIBTORRENT_MIN_VERSION} )
+ IF( LIBTORRENT_FOUND )
+ INCLUDE_DIRECTORIES( ${LIBTORRENT_INCLUDE_DIRS} )
+ LINK_LIBRARIES( ${LIBTORRENT_LIBRARIES} )
+ ELSE()
+ MESSAGE(FATAL_ERROR "libtorrent-rasterbar library is not found! Please install the package or toggle OPTION_TORRENT_SYSTEM to OFF")
+ ENDIF()
+ ELSE( NOT WIN32)
+ INCLUDE_DIRECTORIES(${SpringLobby_SOURCE_DIR}/src/libtorrent/include
+ ${SpringLobby_SOURCE_DIR}/src/libtorrent/zlib
+ ${SpringLobby_SOURCE_DIR}/src/libtorrent/ )
+ INCLUDE ( ${SpringLobby_SOURCE_DIR}/cmake/libtorrent.cmake )
+ ADD_DEFINITIONS( -DBOOST_WINDOWS -DTORRENT_DISABLE_ENCRYPTION )
+ IF(NOT CMAKE_CROSSCOMPILING)
+ SET(Boost_USE_STATIC_LIBS ON)
+ SET(Boost_USE_MULTITHREADED ON)
+ SET(Boost_ADDITIONAL_VERSIONS 1.35 1.35.0 1.38 1.38.0)
+ FIND_PACKAGE(Boost COMPONENTS system thread filesystem date_time)
+ INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIRS} )
+ ELSE(NOT CMAKE_CROSSCOMPILING)
+ link_directories( ${boost_LIB_DIR} )
+ INCLUDE_DIRECTORIES( ${boost_INCLUDE_DIR} )
+ ENDIF(NOT CMAKE_CROSSCOMPILING)
+ ENDIF( NOT WIN32)
+ELSE( OPTION_TORRENT_SYSTEM )
+ ADD_DEFINITIONS( -DNO_TORRENT_SYSTEM )
+ENDIF( OPTION_TORRENT_SYSTEM )
+
+
+#----------------------------------------------------------------------------------------------------
+# Source listing
+#----------------------------------------------------------------------------------------------------
+
+# We define the include paths here, our minimal source dir is one
+
+INCLUDE_DIRECTORIES(${SpringLobby_SOURCE_DIR} ${Settings_SOURCE_DIR} )
+
+SET(SpringLobbySrc
+ src/aui/slbook.cpp
+ src/utils/math.cpp
+ src/utils/misc.cpp
+ src/utils/debug.cpp
+ src/utils/platform.cpp
+ src/utils/conversion.cpp
+ src/utils/tasutil.cpp
+ src/utils/sltipwin.cpp
+ src/utils/controls.cpp
+ src/utils/md5.c
+ src/updater/updater.cpp
+ src/updater/versionchecker.cpp
+ src/Helper/TextCompletionDatabase.cpp
+ src/Helper/imageviewer.cpp
+ src/Helper/slhtmlwindow.cpp
+ src/channel/channelchooser.cpp
+ src/channel/channelchooserdialog.cpp
+ src/Helper/wxtextctrlhist.cpp
+ src/Helper/colorbutton.cpp
+ src/filelister/filelistctrl.cpp
+ src/filelister/filelistdialog.cpp
+ src/filelister/filelistfilter.cpp
+ src/aui/auimanager.cpp
+ src/aui/artprovider.cpp
+ src/autobalancedialog.cpp
+ src/autohost.cpp
+ src/channel/autojoinchanneldialog.cpp
+ src/addbotdialog.cpp
+ src/agreementdialog.cpp
+ src/base64.cpp
+ src/battle.cpp
+ src/battlelist.cpp
+ src/battlelistctrl.cpp
+ src/battlelistfilter.cpp
+ src/battlelisttab.cpp
+ src/battlemaptab.cpp
+ src/battleoptionstab.cpp
+ src/battleroomlistctrl.cpp
+ src/battleroomtab.cpp
+ src/crc.cpp
+ src/channel/channel.cpp
+ src/channel/channellist.cpp
+ src/channel/channellistctrl.cpp
+ src/chatlog.cpp
+ src/chatoptionstab.cpp
+ src/chatpanel.cpp
+ src/connectwindow.cpp
+ src/countrycodes.cpp
+ src/crashreport.cpp
+ src/customlistctrl.cpp
+ src/flagimages.cpp
+ src/globalevents.cpp
+ src/groupoptionspanel.cpp
+ src/hostbattledialog.cpp
+ src/ibattle.cpp
+ src/iconimagelist.cpp
+ src/lobbyoptionstab.cpp
+ src/mainchattab.cpp
+ src/mainjoinbattletab.cpp
+ src/mainoptionstab.cpp
+ src/mainsingleplayertab.cpp
+ src/maintorrenttab.cpp
+ src/mainwindow.cpp
+ src/mapctrl.cpp
+ src/mapgridctrl.cpp
+ src/mapselectdialog.cpp
+ src/mmoptionwindows.cpp
+ src/mmoptionmodel.cpp
+ src/mmoptionswrapper.cpp
+ src/nicklistctrl.cpp
+ src/offlinebattle.cpp
+ src/playback/replaylist.cpp
+ src/playback/savegamelist.cpp
+ src/sdlsound.cpp
+ src/selectusersdialog.cpp
+ src/server.cpp
+ src/serverevents.cpp
+ src/settings.cpp
+ src/singleplayerbattle.cpp
+ src/singleplayertab.cpp
+ src/socket.cpp
+ src/spinctld.cpp
+ src/spring.cpp
+ src/springlobbyapp.cpp
+ src/springoptionstab.cpp
+ src/springprocess.cpp
+ src/springunitsync.cpp
+ src/springunitsynclib.cpp
+ src/tasserver.cpp
+ src/tdfcontainer.cpp
+ src/thread.cpp
+ src/torrentlistctrl.cpp
+ src/torrentoptionspanel.cpp
+ src/torrentwrapper.cpp
+ src/ui.cpp
+ src/uiutils.cpp
+ src/unitsyncthread.cpp
+ src/user.cpp
+ src/useractions.cpp
+ src/userlist.cpp
+ src/userlistctrl.cpp
+ src/widgets/downloadlistctrl.cpp
+ src/widgets/downloaddialog.cpp
+ src/widgets/downloadpanel.cpp
+ src/widgets/infopanel.cpp
+ src/widgets/widget.cpp
+ src/globalsmanager.cpp
+ src/Helper/wxTranslationHelper.cpp
+ src/Helper/tasclientimport.cpp
+)
+
+SET(SettingsSrc
+ src/settings++/custom_dialogs.cpp
+ src/settings++/frame.cpp
+ src/settings++/helpmenufunctions.cpp
+ src/settings++/panel_pathoption.cpp
+ src/settings++/se_utils.cpp
+ src/settings++/tab_abstract.cpp
+ src/settings++/tab_audio.cpp
+ src/settings++/tab_quality_video.cpp
+ src/settings++/tab_render_detail.cpp
+ src/settings++/tab_simple.cpp
+ src/settings++/tab_ui.cpp
+)
+
+SET(StandAloneSettings
+ src/settings.cpp
+ src/uiutils.cpp
+ src/settings++/Main.cpp
+)
+
+SET(SLSharedWithSettings
+ src/utils/debug.cpp
+ src/utils/platform.cpp
+ src/utils/conversion.cpp
+ src/utils/sltipwin.cpp
+ src/utils/controls.cpp
+ src/updater/versionchecker.cpp
+ src/crashreport.cpp
+ src/springunitsynclib.cpp
+ src/springunitsync.cpp
+ src/thread.cpp
+ src/spinctld.cpp
+ src/globalsmanager.cpp
+ src/mmoptionmodel.cpp
+ src/mmoptionswrapper.cpp
+)
+
+# If we build for windows Systems, we also include the Resource-File containing the Manifest, Icon and other Resources.
+IF(WIN32)
+ IF(MINGW OR CMAKE_CROSSCOMPILING)
+ FIND_PROGRAM(WINDRES NAMES windres i586-mingw32msvc-windres i686-mingw32-windres DOC "path to mingw's windres executable")
+ ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sl_icon.o COMMAND ${WINDRES} -I${SpringLobby_SOURCE_DIR}/src -I${wxWidgets_RC_DIR} -i${SpringLobby_SOURCE_DIR}/src/springlobby.rc -o ${CMAKE_CURRENT_BINARY_DIR}/sl_icon.o)
+ ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ss_icon.o COMMAND ${WINDRES} -I${SpringLobby_SOURCE_DIR}/src -I${wxWidgets_RC_DIR} -i${SpringLobby_SOURCE_DIR}/src/settings++/settings.rc -o ${CMAKE_CURRENT_BINARY_DIR}/ss_icon.o)
+ SET(SpringLobby_RC_FILE ${CMAKE_CURRENT_BINARY_DIR}/sl_icon.o )
+ SET(SpringSettings_RC_FILE ${CMAKE_CURRENT_BINARY_DIR}/ss_icon.o )
+ ENDIF(MINGW OR CMAKE_CROSSCOMPILING)
+
+ SET(SpringLobbySrc ${SpringLobbySrc} src/Helper/listctrl.cpp)
+ SET(SpringLobbySrc ${SpringLobbySrc} src/springlobby.rc)
+ SET(StandAloneSettings ${StandAloneSettings} src/settings++/settings.rc)
+ELSE(WIN32)
+# If we don't build for windows, include some source code checks as pre-build step.
+ ADD_CUSTOM_TARGET(test_susynclib ALL COMMAND tools/test-susynclib.awk src/springunitsynclib.cpp WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
+ENDIF(WIN32)
+
+#----------------------------------------------------------------------------------------------------
+# L10n support
+#----------------------------------------------------------------------------------------------------
+
+if( OPTION_TRANSLATION_SUPPORT )
+ set ( GETTEXT_XGETTEXT_EXECUTABLE "/usr/bin/xgettext" )
+ kwwidgets_create_gettext_targets(
+ DOMAIN_NAME "springlobby"
+ TARGET_BASENAME "springlobby"
+ LOCALE_LIST "ar;cs;da;de;el;es;fi;fr;it;pl;pt;ro;ru;sv;uk;zh_CN"
+ COPYRIGHT_HOLDER "The SpringLobby team"
+ SOURCES "${SpringLobbySrc};${SettingsSrc};${StandAloneSettings}"
+ PO_DIR "${CMAKE_SOURCE_DIR}/po"
+ PO_PREFIX ""
+ POT_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/po"
+ PO_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/po"
+ MO_INSTALL_DIR "/share/locale"
+ CREATE_POT_TARGET 1
+ CREATE_PO_TARGET 1
+ ADD_MO_TARGET_TO_ALL
+ )
+endif( OPTION_TRANSLATION_SUPPORT )
+
+#----------------------------------------------------------------------------------------------------
+# Build target defintions
+#----------------------------------------------------------------------------------------------------
+
+# Here we define the executable SpringLobby ( or on Windows SpringLobby.exe )
+
+#auto-remove whitespaces before/after lib paths
+cmake_policy(SET CMP0004 OLD)
+#ignore warnings about macosx app bundle output dir
+cmake_policy(SET CMP0006 OLD)
+
+
+ADD_EXECUTABLE(springlobby WIN32 MACOSX_BUNDLE ${SpringLobbySrc} ${SettingsSrc} ${SpringLobby_RC_FILE})
+ADD_EXECUTABLE(springsettings WIN32 MACOSX_BUNDLE ${StandAloneSettings} ${SpringSettings_RC_FILE} ${SettingsSrc} ${SLSharedWithSettings} )
+
+#build libtorrent as a static lib to link in on windows
+IF(WIN32 AND OPTION_TORRENT_SYSTEM)
+ADD_LIBRARY(libtorrent STATIC ${libtorrent_SRC})
+SET_TARGET_PROPERTIES(libtorrent PROPERTIES COMPILE_FLAGS -DWIN32_LEAN_AND_MEAN)
+TARGET_LINK_LIBRARIES( libtorrent ${Boost_LIBRARIES} ws2_32 mswsock )
+TARGET_LINK_LIBRARIES( springlobby libtorrent )
+ENDIF(WIN32 AND OPTION_TORRENT_SYSTEM)
+
+
+# Here the wxWidgets Libraries are added. These are set for us by the FIND Script. If you need other Libraries, you can add them here as well.
+TARGET_LINK_LIBRARIES(springlobby ${wxWidgets_LIBRARIES})
+TARGET_LINK_LIBRARIES(springsettings ${wxWidgets_LIBRARIES})
+IF(MINGW)
+ TARGET_LINK_LIBRARIES( springlobby iphlpapi )
+ TARGET_LINK_LIBRARIES( springsettings iphlpapi )
+ENDIF(MINGW)
+
+IF (WIN32)
+ install(TARGETS springlobby springsettings RUNTIME DESTINATION .)
+ install(FILES AUTHORS COPYING NEWS README THANKS DESTINATION .)
+ELSE (WIN32)
+ install(TARGETS springlobby springsettings RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin )
+ install(FILES AUTHORS COPYING NEWS README THANKS DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/springlobby )
+ install(FILES src/images/springlobby.svg DESTINATION
+ ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
+ install(FILES src/springlobby.desktop DESTINATION
+ ${CMAKE_INSTALL_PREFIX}/share/applications)
+ENDIF (WIN32)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..623b625
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. 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.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+ 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
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This 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 Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..a8697a6
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,36 @@
+2009-02-07 gettextize <bug-gnu-gettext at gnu.org>
+
+ * m4/gettext.m4: Upgrade to gettext-0.17.
+ * m4/iconv.m4: Upgrade to gettext-0.17.
+ * m4/lib-ld.m4: Upgrade to gettext-0.17.
+ * m4/lib-link.m4: Upgrade to gettext-0.17.
+ * m4/lib-prefix.m4: Upgrade to gettext-0.17.
+ * m4/nls.m4: Upgrade to gettext-0.17.
+ * m4/po.m4: Upgrade to gettext-0.17.
+ * m4/progtest.m4: Upgrade to gettext-0.17.
+ * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.17.
+
+2009-02-07 gettextize <bug-gnu-gettext at gnu.org>
+
+ * m4/gettext.m4: Upgrade to gettext-0.17.
+ * m4/iconv.m4: Upgrade to gettext-0.17.
+ * m4/lib-ld.m4: Upgrade to gettext-0.17.
+ * m4/lib-link.m4: Upgrade to gettext-0.17.
+ * m4/lib-prefix.m4: Upgrade to gettext-0.17.
+ * m4/nls.m4: Upgrade to gettext-0.17.
+ * m4/po.m4: Upgrade to gettext-0.17.
+ * m4/progtest.m4: Upgrade to gettext-0.17.
+ * configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.17.
+
+2008-02-07 gettextize <bug-gnu-gettext at gnu.org>
+
+ * m4/gettext.m4: New file, from gettext-0.16.1.
+ * m4/iconv.m4: New file, from gettext-0.16.1.
+ * m4/lib-ld.m4: New file, from gettext-0.16.1.
+ * m4/lib-link.m4: New file, from gettext-0.16.1.
+ * m4/lib-prefix.m4: New file, from gettext-0.16.1.
+ * m4/nls.m4: New file, from gettext-0.16.1.
+ * m4/po.m4: New file, from gettext-0.16.1.
+ * m4/progtest.m4: New file, from gettext-0.16.1.
+ * configure.ac (AC_CONFIG_FILES): Add po/Makefile.in.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..d3c5b40
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,237 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007 Free Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+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.
+
+ 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.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. 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.
+
+ 6. Often, you can also type `make uninstall' to remove the installed
+ files again.
+
+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 `..'.
+
+ 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.
+
+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'.
+
+ 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.
+
+ 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'.
+
+Optional Features
+=================
+
+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.
+
+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 the options to `configure', and exit.
+
+`--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.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..d60dc42
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,1081 @@
+## the following clause may NOT be split, b/c of autoreconf 2.61 and older
+## the --install requires automake 1.10 which was released in 2006
+## the --install can be edited out to use older automake
+ACLOCAL_AMFLAGS = -I m4 --install
+
+libt_dir = $(srcdir)/src/libtorrent
+libt_src_dir = $(libt_dir)/src
+
+SEARCHDIRS = \
+ -I$(srcdir)/src
+
+if USE_WINDRES
+SEARCHDIRS += \
+ -I$(libt_dir)/include -I$(libt_dir)/include/libtorrent \
+ -I$(libt_dir)/zlib -I$(libt_dir) -I $(libt_dir)/asio
+endif
+
+AM_CPPFLAGS = \
+ $(WX_CPPFLAGS) \
+ $(LIBTORRENT_CFLAGS) \
+ $(SDL_CFLAGS) \
+ -DLOCALEDIR=\"$(localedir)\" \
+ $(SEARCHDIRS)
+
+# strict aliasing check is disabled, because wxWidgets headers have problems
+AM_CXXFLAGS = \
+ -Wall \
+ -Wno-strict-aliasing
+
+desktopdir = $(datadir)/applications
+dist_desktop_DATA = \
+ src/springlobby.desktop
+
+pixmapdir = $(datadir)/pixmaps
+dist_pixmap_DATA = \
+ src/images/springlobby.svg
+SUBDIRS = po
+
+## if you don't have the required version of autoconf, comment out the
+## following clause, in which case you may NOT distribute the result!
+dist_doc_DATA = \
+ AUTHORS \
+ ChangeLog \
+ COPYING \
+ INSTALL \
+ NEWS \
+ README \
+ THANKS
+
+bin_PROGRAMS = \
+ springlobby \
+ springsettings
+
+springlobby_LDADD = \
+ $(WX_LIBS)\
+ $(LIBTORRENT_LIBS) \
+ $(SDL_LIBS)
+
+#put template source files here (those need to be present in tarball, but not compiled)
+EXTRA_DIST = \
+ src/battleroommmoptionstab.cpp \
+ src/customvirtlistctrl.cpp \
+ src/playback/playbacktab.cpp \
+ src/playback/playbackfilter.cpp \
+ src/playback/playbackthread.cpp \
+ src/playback/playbacklistctrl.cpp \
+ src/playback/playbacktraits.h \
+ src/playback/playbackstructs.h \
+ src/playback/playbacklist.h \
+ src/playback/playbacklist.cpp \
+ src/httpdownloader.cpp \
+ CMakeLists.txt
+
+
+springsettings_LDADD = \
+ $(WX_LIBS)
+
+if USE_WINDRES
+RESOURCECOMPILE = $(WINDRES) -I $(srcdir)/src $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) # $(AM_CXXFLAGS) $(CXXFLAGS)
+.rc.o:
+ $(RESOURCECOMPILE) -o $@ -i $<
+endif
+
+
+libtorrent_sources = \
+ $(libt_src_dir)/entry.cpp \
+ $(libt_src_dir)/escape_string.cpp \
+ $(libt_src_dir)/assert.cpp \
+ $(libt_src_dir)/enum_net.cpp \
+ $(libt_src_dir)/broadcast_socket.cpp \
+ $(libt_src_dir)/peer_connection.cpp \
+ $(libt_src_dir)/bt_peer_connection.cpp \
+ $(libt_src_dir)/web_peer_connection.cpp \
+ $(libt_src_dir)/natpmp.cpp \
+ $(libt_src_dir)/piece_picker.cpp \
+ $(libt_src_dir)/policy.cpp \
+ $(libt_src_dir)/session.cpp \
+ $(libt_src_dir)/session_impl.cpp \
+ $(libt_src_dir)/sha1.cpp \
+ $(libt_src_dir)/stat.cpp \
+ $(libt_src_dir)/storage.cpp \
+ $(libt_src_dir)/torrent.cpp \
+ $(libt_src_dir)/torrent_handle.cpp \
+ $(libt_src_dir)/pe_crypto.cpp \
+ $(libt_src_dir)/torrent_info.cpp \
+ $(libt_src_dir)/tracker_manager.cpp \
+ $(libt_src_dir)/http_connection.cpp \
+ $(libt_src_dir)/http_tracker_connection.cpp \
+ $(libt_src_dir)/udp_tracker_connection.cpp \
+ $(libt_src_dir)/alert.cpp \
+ $(libt_src_dir)/identify_client.cpp \
+ $(libt_src_dir)/ip_filter.cpp \
+ $(libt_src_dir)/file.cpp \
+ $(libt_src_dir)/metadata_transfer.cpp \
+ $(libt_src_dir)/logger.cpp \
+ $(libt_src_dir)/file_pool.cpp \
+ $(libt_src_dir)/ut_pex.cpp \
+ $(libt_src_dir)/lsd.cpp \
+ $(libt_src_dir)/upnp.cpp \
+ $(libt_src_dir)/instantiate_connection.cpp \
+ $(libt_src_dir)/socks5_stream.cpp \
+ $(libt_src_dir)/socks4_stream.cpp \
+ $(libt_src_dir)/http_stream.cpp \
+ $(libt_src_dir)/connection_queue.cpp \
+ $(libt_src_dir)/disk_io_thread.cpp \
+ \
+ $(libt_src_dir)/kademlia/closest_nodes.cpp \
+ $(libt_src_dir)/kademlia/dht_tracker.cpp \
+ $(libt_src_dir)/kademlia/find_data.cpp \
+ $(libt_src_dir)/kademlia/node.cpp \
+ $(libt_src_dir)/kademlia/node_id.cpp \
+ $(libt_src_dir)/kademlia/refresh.cpp \
+ $(libt_src_dir)/kademlia/routing_table.cpp \
+ $(libt_src_dir)/kademlia/rpc_manager.cpp \
+ $(libt_src_dir)/kademlia/traversal_algorithm.cpp \
+ \
+ $(libt_dir)/zlib/adler32.c \
+ $(libt_dir)/zlib/compress.c \
+ $(libt_dir)/zlib/crc32.c \
+ $(libt_dir)/zlib/deflate.c \
+ $(libt_dir)/zlib/gzio.c \
+ $(libt_dir)/zlib/infback.c \
+ $(libt_dir)/zlib/inffast.c \
+ $(libt_dir)/zlib/inflate.c \
+ $(libt_dir)/zlib/inftrees.c \
+ $(libt_dir)/zlib/trees.c \
+ $(libt_dir)/zlib/uncompr.c \
+ $(libt_dir)/zlib/zutil.c
+
+libtorrent_headers = \
+ $(libt_dir)/include/libtorrent/alert.hpp \
+ $(libt_dir)/include/libtorrent/alert_types.hpp \
+ $(libt_dir)/include/libtorrent/assert.hpp \
+ $(libt_dir)/include/libtorrent/aux_/session_impl.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_manager.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_limit.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_queue_entry.hpp \
+ $(libt_dir)/include/libtorrent/bencode.hpp \
+ $(libt_dir)/include/libtorrent/broadcast_socket.hpp \
+ $(libt_dir)/include/libtorrent/buffer.hpp \
+ $(libt_dir)/include/libtorrent/connection_queue.hpp \
+ $(libt_dir)/include/libtorrent/debug.hpp \
+ $(libt_dir)/include/libtorrent/disk_io_thread.hpp \
+ $(libt_dir)/include/libtorrent/entry.hpp \
+ $(libt_dir)/include/libtorrent/enum_net.hpp \
+ $(libt_dir)/include/libtorrent/escape_string.hpp \
+ $(libt_dir)/include/libtorrent/extensions.hpp \
+ $(libt_dir)/include/libtorrent/extensions/metadata_transfer.hpp \
+ $(libt_dir)/include/libtorrent/extensions/logger.hpp \
+ $(libt_dir)/include/libtorrent/extensions/ut_pex.hpp \
+ $(libt_dir)/include/libtorrent/file.hpp \
+ $(libt_dir)/include/libtorrent/file_pool.hpp \
+ $(libt_dir)/include/libtorrent/fingerprint.hpp \
+ $(libt_dir)/include/libtorrent/hasher.hpp \
+ $(libt_dir)/include/libtorrent/http_connection.hpp \
+ $(libt_dir)/include/libtorrent/http_stream.hpp \
+ $(libt_dir)/include/libtorrent/session_settings.hpp \
+ $(libt_dir)/include/libtorrent/http_tracker_connection.hpp \
+ $(libt_dir)/include/libtorrent/identify_client.hpp \
+ $(libt_dir)/include/libtorrent/instantiate_connection.hpp \
+ $(libt_dir)/include/libtorrent/intrusive_ptr_base.hpp \
+ $(libt_dir)/include/libtorrent/invariant_check.hpp \
+ $(libt_dir)/include/libtorrent/io.hpp \
+ $(libt_dir)/include/libtorrent/ip_filter.hpp \
+ $(libt_dir)/include/libtorrent/chained_buffer.hpp \
+ $(libt_dir)/include/libtorrent/lsd.hpp \
+ $(libt_dir)/include/libtorrent/peer.hpp \
+ $(libt_dir)/include/libtorrent/peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/bt_peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/web_peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/pe_crypto.hpp \
+ $(libt_dir)/include/libtorrent/natpmp.hpp \
+ $(libt_dir)/include/libtorrent/pch.hpp \
+ $(libt_dir)/include/libtorrent/peer_id.hpp \
+ $(libt_dir)/include/libtorrent/peer_info.hpp \
+ $(libt_dir)/include/libtorrent/peer_request.hpp \
+ $(libt_dir)/include/libtorrent/piece_block_progress.hpp \
+ $(libt_dir)/include/libtorrent/piece_picker.hpp \
+ $(libt_dir)/include/libtorrent/policy.hpp \
+ $(libt_dir)/include/libtorrent/session.hpp \
+ $(libt_dir)/include/libtorrent/size_type.hpp \
+ $(libt_dir)/include/libtorrent/socket.hpp \
+ $(libt_dir)/include/libtorrent/socket_type.hpp \
+ $(libt_dir)/include/libtorrent/socks4_stream.hpp \
+ $(libt_dir)/include/libtorrent/socks5_stream.hpp \
+ $(libt_dir)/include/libtorrent/stat.hpp \
+ $(libt_dir)/include/libtorrent/storage.hpp \
+ $(libt_dir)/include/libtorrent/time.hpp \
+ $(libt_dir)/include/libtorrent/torrent.hpp \
+ $(libt_dir)/include/libtorrent/torrent_handle.hpp \
+ $(libt_dir)/include/libtorrent/torrent_info.hpp \
+ $(libt_dir)/include/libtorrent/tracker_manager.hpp \
+ $(libt_dir)/include/libtorrent/udp_tracker_connection.hpp \
+ $(libt_dir)/include/libtorrent/utf8.hpp \
+ $(libt_dir)/include/libtorrent/xml_parse.hpp \
+ $(libt_dir)/include/libtorrent/variant_stream.hpp \
+ $(libt_dir)/include/libtorrent/version.hpp \
+ \
+ $(libt_dir)/include/libtorrent/kademlia/closest_nodes.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/dht_tracker.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/find_data.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/logging.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/msg.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node_entry.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node_id.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/observer.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/packet_iterator.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/refresh.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/routing_table.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/rpc_manager.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/traversal_algorithm.hpp \
+ \
+ $(libt_dir)/asio.hpp \
+ $(libt_dir)/asio/basic_datagram_socket.hpp \
+ $(libt_dir)/asio/basic_deadline_timer.hpp \
+ $(libt_dir)/asio/basic_io_object.hpp \
+ $(libt_dir)/asio/basic_socket.hpp \
+ $(libt_dir)/asio/basic_socket_acceptor.hpp \
+ $(libt_dir)/asio/basic_socket_iostream.hpp \
+ $(libt_dir)/asio/basic_socket_streambuf.hpp \
+ $(libt_dir)/asio/basic_stream_socket.hpp \
+ $(libt_dir)/asio/basic_streambuf.hpp \
+ $(libt_dir)/asio/buffer.hpp \
+ $(libt_dir)/asio/buffered_read_stream.hpp \
+ $(libt_dir)/asio/buffered_read_stream_fwd.hpp \
+ $(libt_dir)/asio/buffered_stream.hpp \
+ $(libt_dir)/asio/buffered_stream_fwd.hpp \
+ $(libt_dir)/asio/buffered_write_stream.hpp \
+ $(libt_dir)/asio/buffered_write_stream_fwd.hpp \
+ $(libt_dir)/asio/completion_condition.hpp \
+ $(libt_dir)/asio/datagram_socket_service.hpp \
+ $(libt_dir)/asio/deadline_timer.hpp \
+ $(libt_dir)/asio/deadline_timer_service.hpp \
+ $(libt_dir)/asio/error.hpp \
+ $(libt_dir)/asio/error_code.hpp \
+ $(libt_dir)/asio/handler_alloc_hook.hpp \
+ $(libt_dir)/asio/handler_invoke_hook.hpp \
+ $(libt_dir)/asio/io_service.hpp \
+ $(libt_dir)/asio/is_read_buffered.hpp \
+ $(libt_dir)/asio/is_write_buffered.hpp \
+ $(libt_dir)/asio/placeholders.hpp \
+ $(libt_dir)/asio/read.hpp \
+ $(libt_dir)/asio/read_until.hpp \
+ $(libt_dir)/asio/socket_acceptor_service.hpp \
+ $(libt_dir)/asio/socket_base.hpp \
+ $(libt_dir)/asio/ssl.hpp \
+ $(libt_dir)/asio/strand.hpp \
+ $(libt_dir)/asio/stream_socket_service.hpp \
+ $(libt_dir)/asio/streambuf.hpp \
+ $(libt_dir)/asio/system_error.hpp \
+ $(libt_dir)/asio/thread.hpp \
+ $(libt_dir)/asio/time_traits.hpp \
+ $(libt_dir)/asio/version.hpp \
+ $(libt_dir)/asio/write.hpp \
+ $(libt_dir)/asio/detail/bind_handler.hpp \
+ $(libt_dir)/asio/detail/buffer_resize_guard.hpp \
+ $(libt_dir)/asio/detail/buffered_stream_storage.hpp \
+ $(libt_dir)/asio/detail/call_stack.hpp \
+ $(libt_dir)/asio/detail/const_buffers_iterator.hpp \
+ $(libt_dir)/asio/detail/consuming_buffers.hpp \
+ $(libt_dir)/asio/detail/deadline_timer_service.hpp \
+ $(libt_dir)/asio/detail/dev_poll_reactor.hpp \
+ $(libt_dir)/asio/detail/dev_poll_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/epoll_reactor.hpp \
+ $(libt_dir)/asio/detail/epoll_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/event.hpp \
+ $(libt_dir)/asio/detail/fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/handler_alloc_helpers.hpp \
+ $(libt_dir)/asio/detail/handler_invoke_helpers.hpp \
+ $(libt_dir)/asio/detail/handler_queue.hpp \
+ $(libt_dir)/asio/detail/hash_map.hpp \
+ $(libt_dir)/asio/detail/io_control.hpp \
+ $(libt_dir)/asio/detail/kqueue_reactor.hpp \
+ $(libt_dir)/asio/detail/kqueue_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/local_free_on_block_exit.hpp \
+ $(libt_dir)/asio/detail/mutex.hpp \
+ $(libt_dir)/asio/detail/noncopyable.hpp \
+ $(libt_dir)/asio/detail/null_event.hpp \
+ $(libt_dir)/asio/detail/null_mutex.hpp \
+ $(libt_dir)/asio/detail/null_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/null_thread.hpp \
+ $(libt_dir)/asio/detail/null_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/old_win_sdk_compat.hpp \
+ $(libt_dir)/asio/detail/pipe_select_interrupter.hpp \
+ $(libt_dir)/asio/detail/pop_options.hpp \
+ $(libt_dir)/asio/detail/posix_event.hpp \
+ $(libt_dir)/asio/detail/posix_fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/posix_mutex.hpp \
+ $(libt_dir)/asio/detail/posix_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/posix_thread.hpp \
+ $(libt_dir)/asio/detail/posix_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/push_options.hpp \
+ $(libt_dir)/asio/detail/reactive_socket_service.hpp \
+ $(libt_dir)/asio/detail/reactor_op_queue.hpp \
+ $(libt_dir)/asio/detail/resolver_service.hpp \
+ $(libt_dir)/asio/detail/scoped_lock.hpp \
+ $(libt_dir)/asio/detail/select_interrupter.hpp \
+ $(libt_dir)/asio/detail/select_reactor.hpp \
+ $(libt_dir)/asio/detail/select_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/service_base.hpp \
+ $(libt_dir)/asio/detail/service_id.hpp \
+ $(libt_dir)/asio/detail/service_registry.hpp \
+ $(libt_dir)/asio/detail/service_registry_fwd.hpp \
+ $(libt_dir)/asio/detail/signal_blocker.hpp \
+ $(libt_dir)/asio/detail/signal_init.hpp \
+ $(libt_dir)/asio/detail/socket_holder.hpp \
+ $(libt_dir)/asio/detail/socket_ops.hpp \
+ $(libt_dir)/asio/detail/socket_option.hpp \
+ $(libt_dir)/asio/detail/socket_select_interrupter.hpp \
+ $(libt_dir)/asio/detail/socket_types.hpp \
+ $(libt_dir)/asio/detail/strand_service.hpp \
+ $(libt_dir)/asio/detail/task_io_service.hpp \
+ $(libt_dir)/asio/detail/task_io_service_fwd.hpp \
+ $(libt_dir)/asio/detail/thread.hpp \
+ $(libt_dir)/asio/detail/throw_error.hpp \
+ $(libt_dir)/asio/detail/timer_queue.hpp \
+ $(libt_dir)/asio/detail/timer_queue_base.hpp \
+ $(libt_dir)/asio/detail/tss_ptr.hpp \
+ $(libt_dir)/asio/detail/win_event.hpp \
+ $(libt_dir)/asio/detail/win_fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/win_iocp_io_service.hpp \
+ $(libt_dir)/asio/detail/win_iocp_io_service_fwd.hpp \
+ $(libt_dir)/asio/detail/win_iocp_socket_service.hpp \
+ $(libt_dir)/asio/detail/win_mutex.hpp \
+ $(libt_dir)/asio/detail/win_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/win_thread.hpp \
+ $(libt_dir)/asio/detail/win_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/wince_thread.hpp \
+ $(libt_dir)/asio/detail/winsock_init.hpp \
+ $(libt_dir)/asio/detail/wrapped_handler.hpp \
+ $(libt_dir)/asio/impl/error_code.ipp \
+ $(libt_dir)/asio/impl/io_service.ipp \
+ $(libt_dir)/asio/impl/read.ipp \
+ $(libt_dir)/asio/impl/read_until.ipp \
+ $(libt_dir)/asio/impl/write.ipp \
+ $(libt_dir)/asio/ip/address.hpp \
+ $(libt_dir)/asio/ip/address_v4.hpp \
+ $(libt_dir)/asio/ip/address_v6.hpp \
+ $(libt_dir)/asio/ip/basic_endpoint.hpp \
+ $(libt_dir)/asio/ip/basic_resolver.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_entry.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_iterator.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_query.hpp \
+ $(libt_dir)/asio/ip/host_name.hpp \
+ $(libt_dir)/asio/ip/multicast.hpp \
+ $(libt_dir)/asio/ip/resolver_query_base.hpp \
+ $(libt_dir)/asio/ip/resolver_service.hpp \
+ $(libt_dir)/asio/ip/tcp.hpp \
+ $(libt_dir)/asio/ip/udp.hpp \
+ $(libt_dir)/asio/ip/unicast.hpp \
+ $(libt_dir)/asio/ip/v6_only.hpp \
+ $(libt_dir)/asio/ip/detail/socket_option.hpp \
+ $(libt_dir)/asio/ssl/basic_context.hpp \
+ $(libt_dir)/asio/ssl/context.hpp \
+ $(libt_dir)/asio/ssl/context_base.hpp \
+ $(libt_dir)/asio/ssl/context_service.hpp \
+ $(libt_dir)/asio/ssl/stream.hpp \
+ $(libt_dir)/asio/ssl/stream_base.hpp \
+ $(libt_dir)/asio/ssl/stream_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_context_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_init.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_operation.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_stream_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_types.hpp \
+ \
+ $(libt_dir)/zlib/crc32.h \
+ $(libt_dir)/zlib/deflate.h \
+ $(libt_dir)/zlib/inffast.h \
+ $(libt_dir)/zlib/inflate.h \
+ $(libt_dir)/zlib/inftrees.h \
+ $(libt_dir)/zlib/trees.h \
+ $(libt_dir)/zlib/zconf.h \
+ $(libt_dir)/zlib/zlib.h \
+ $(libt_dir)/zlib/zutil.h
+
+
+springlobby_SOURCES = \
+ src/utils/md5.h \
+ src/utils/md5.c \
+ src/aui/slbook.cpp \
+ src/aui/slbook.h \
+ src/utils/math.cpp \
+ src/utils/math.h \
+ src/utils/misc.cpp \
+ src/utils/misc.h \
+ src/utils/debug.cpp \
+ src/utils/debug.h \
+ src/utils/platform.cpp \
+ src/utils/platform.h \
+ src/utils/conversion.cpp \
+ src/utils/conversion.h \
+ src/utils/tasutil.cpp \
+ src/utils/tasutil.h \
+ src/utils/sltipwin.cpp \
+ src/utils/sltipwin.h \
+ src/utils/controls.cpp \
+ src/utils/controls.h \
+ src/updater/versionchecker.cpp \
+ src/updater/versionchecker.h \
+ src/sounds/ring_sound.h \
+ src/sounds/pm_sound.h \
+ src/springunitsynclib.cpp \
+ src/springunitsynclib.h \
+ src/unitsyncthread.cpp \
+ src/unitsyncthread.h \
+ src/mapgridctrl.cpp \
+ src/mapgridctrl.h \
+ src/mapselectdialog.cpp \
+ src/mapselectdialog.h \
+ src/bimap.h \
+ src/chatlog.h \
+ src/chatlog.cpp \
+ src/images/broom.png.h \
+ src/images/bot_ingame.png.h \
+ src/images/bot_broom.png.h \
+ src/images/channel_options.xpm \
+ src/images/chanop_ingame.xpm \
+ src/images/chanop_away.xpm \
+ src/images/chanop_broom.xpm \
+ src/images/chanop.xpm \
+ src/images/admin_broom.png.h \
+ src/images/host_spectator.xpm \
+ src/images/host.xpm \
+ src/images/not_found_icon.xpm \
+ src/images/reload_map.xpm \
+ src/images/download_map.xpm \
+ src/images/up_downsel.xpm \
+ src/images/upsel_down.xpm \
+ src/images/up_down.xpm \
+ src/images/player.xpm \
+ src/ibattle.cpp \
+ src/ibattle.h \
+ src/nonportable.h \
+ src/addbotdialog.cpp \
+ src/addbotdialog.h \
+ src/agreementdialog.cpp \
+ src/agreementdialog.h \
+ src/autohost.cpp \
+ src/autohost.h \
+ src/base64.cpp \
+ src/base64.h \
+ src/battle.cpp \
+ src/battle.h \
+ src/maintorrenttab.cpp \
+ src/maintorrenttab.h \
+ src/battlelistctrl.cpp \
+ src/battlelistctrl.h \
+ src/battlelistfilter.cpp \
+ src/battlelistfilter.h \
+ src/battlelistfiltervalues.h \
+ src/battlelist.cpp \
+ src/battlelist.h \
+ src/battlelisttab.cpp \
+ src/battlelisttab.h \
+ src/battleroomlistctrl.cpp \
+ src/battleroomlistctrl.h \
+ src/battlemaptab.cpp \
+ src/battlemaptab.h \
+ src/battleoptionstab.cpp \
+ src/battleoptionstab.h \
+ src/battleroomtab.cpp \
+ src/battleroomtab.h \
+ src/crc.cpp \
+ src/crc.h \
+ src/channel/channel.cpp \
+ src/channel/channel.h \
+ src/channel/channellist.cpp \
+ src/channel/channellist.h \
+ src/channel/channellistctrl.cpp \
+ src/channel/channellistctrl.h \
+ src/chatoptionstab.cpp \
+ src/chatoptionstab.h \
+ src/chatpanel.cpp \
+ src/chatpanel.h \
+ src/connectwindow.cpp \
+ src/connectwindow.h \
+ src/crashreport.cpp \
+ src/crashreport.h \
+ src/countrycodes.cpp \
+ src/countrycodes.h \
+ src/flagimagedata.h \
+ src/flagimages.cpp \
+ src/flagimages.h \
+ src/hostbattledialog.h \
+ src/hostbattledialog.cpp \
+ src/iconimagelist.cpp \
+ src/iconimagelist.h \
+ src/inetclass.h \
+ src/iunitsync.h \
+ src/mainchattab.cpp \
+ src/mainchattab.h \
+ src/mainjoinbattletab.cpp \
+ src/mainjoinbattletab.h \
+ src/mainoptionstab.cpp \
+ src/mainoptionstab.h \
+ src/mainsingleplayertab.cpp \
+ src/mainsingleplayertab.h \
+ src/mainwindow.cpp \
+ src/mainwindow.h \
+ src/mapctrl.cpp \
+ src/mapctrl.h \
+ src/mutexwrapper.h \
+ src/offlinebattle.h \
+ src/offlinebattle.cpp \
+ src/nicklistctrl.cpp \
+ src/nicklistctrl.h \
+ src/playback/playbacktab.h \
+ src/playback/playbackthread.h \
+ src/playback/playbackfilter.h \
+ src/playback/replaylist.h \
+ src/playback/replaylist.cpp \
+ src/playback/playbacklistctrl.h \
+ src/playback/playbackfiltervalues.h \
+ src/sdlsound.h \
+ src/sdlsound.cpp \
+ src/server.cpp \
+ src/serverevents.cpp \
+ src/serverevents.h \
+ src/server.h \
+ src/settings.cpp \
+ src/settings.h \
+ src/socket.cpp \
+ src/socket.h \
+ src/spring.cpp \
+ src/spring.h \
+ src/singleplayerbattle.cpp \
+ src/singleplayerbattle.h \
+ src/singleplayertab.cpp \
+ src/singleplayertab.h \
+ src/springlobbyapp.cpp \
+ src/springlobbyapp.h \
+ src/springoptionstab.cpp \
+ src/springoptionstab.h \
+ src/springprocess.cpp \
+ src/springprocess.h \
+ src/springunitsync.cpp \
+ src/springunitsync.h \
+ src/tasserver.cpp \
+ src/tasserver.h \
+ src/tasservertokentable.h \
+ src/ui.cpp \
+ src/ui.h \
+ src/uiutils.cpp \
+ src/uiutils.h \
+ src/user.cpp \
+ src/user.h \
+ src/usermenu.h \
+ src/userlist.cpp \
+ src/userlist.h \
+ src/userlistctrl.cpp \
+ src/userlistctrl.h \
+ src/torrentlistctrl.cpp \
+ src/torrentlistctrl.h \
+ src/torrentoptionspanel.cpp \
+ src/torrentoptionspanel.h \
+ src/images/start_ally.xpm \
+ src/images/start_enemy.xpm \
+ src/images/start_unused.xpm \
+ src/images/admin_away.png.h \
+ src/images/admin_ingame.png.h \
+ src/images/admin.png.h \
+ src/images/no1_icon.png.h \
+ src/images/no2_icon.png.h \
+ src/images/away.png.h \
+ src/images/battle_list.xpm \
+ src/images/battle_map.xpm \
+ src/images/battle_settings.xpm \
+ src/images/battle.xpm \
+ src/images/bot.xpm \
+ src/images/bot_away.xpm \
+ src/images/channel.xpm \
+ src/images/chat_icon.png.h \
+ src/images/chat_icon_text.png.h \
+ src/images/closed_game.png.h \
+ src/images/closed_full_game.png.h \
+ src/images/closed_pw_game.png.h \
+ src/images/closed_full_pw_game.png.h \
+ src/images/torrentoptionspanel_icon.png.h \
+ src/images/close_hi.xpm \
+ src/images/close.xpm \
+ src/images/colourbox.xpm \
+ src/images/connect.xpm \
+ src/images/down.xpm \
+ src/images/exists.xpm \
+ src/images/fixcolours_palette.xpm \
+ src/images/ingame.png.h \
+ src/images/join_icon.png.h \
+ src/images/join_icon_text.png.h \
+ src/images/nexists.xpm \
+ src/images/nready_q.xpm \
+ src/images/nready_unsync.xpm \
+ src/images/open_game.png.h \
+ src/images/open_full_game.png.h \
+ src/images/open_pw_game.png.h \
+ src/images/open_full_pw_game.png.h \
+ src/images/options_icon.png.h \
+ src/images/options_icon_text.png.h \
+ src/images/arrow_refresh.png.h \
+ src/images/rank0.xpm \
+ src/images/rank1.xpm \
+ src/images/rank2.xpm \
+ src/images/rank3.xpm \
+ src/images/rank4.xpm \
+ src/images/rank5.xpm \
+ src/images/rank6.xpm \
+ src/images/rank_unknown.xpm \
+ src/images/ready_q.xpm \
+ src/images/ready_unsync.xpm \
+ src/images/downloads_icon.png.h \
+ src/images/single_player_icon.png.h \
+ src/images/downloads_icon_text.png.h \
+ src/images/warning_small.png.h \
+ src/images/spectator.png.h \
+ src/images/single_player_icon_text.png.h \
+ src/images/map_select_1.png.h \
+ src/images/map_select_2.png.h \
+ src/images/select_icon.xpm \
+ src/images/server.xpm \
+ src/images/spectator.xpm \
+ src/images/spring.xpm \
+ src/images/springlobby.xpm \
+ src/images/started_game.xpm \
+ src/images/unknown_flag.xpm \
+ src/images/up.xpm \
+ src/images/userchat.xpm \
+ src/images/flags/AD.xpm \
+ src/images/flags/AE.xpm \
+ src/images/flags/AF.xpm \
+ src/images/flags/AG.xpm \
+ src/images/flags/AI.xpm \
+ src/images/flags/AL.xpm \
+ src/images/flags/AM.xpm \
+ src/images/flags/AN.xpm \
+ src/images/flags/AO.xpm \
+ src/images/flags/AR.xpm \
+ src/images/flags/AS.xpm \
+ src/images/flags/AT.xpm \
+ src/images/flags/AU.xpm \
+ src/images/flags/AW.xpm \
+ src/images/flags/AX.xpm \
+ src/images/flags/AZ.xpm \
+ src/images/flags/BA.xpm \
+ src/images/flags/BB.xpm \
+ src/images/flags/BD.xpm \
+ src/images/flags/BE.xpm \
+ src/images/flags/BF.xpm \
+ src/images/flags/BG.xpm \
+ src/images/flags/BH.xpm \
+ src/images/flags/BI.xpm \
+ src/images/flags/BJ.xpm \
+ src/images/flags/BM.xpm \
+ src/images/flags/BN.xpm \
+ src/images/flags/BO.xpm \
+ src/images/flags/BR.xpm \
+ src/images/flags/BS.xpm \
+ src/images/flags/BT.xpm \
+ src/images/flags/BV.xpm \
+ src/images/flags/BW.xpm \
+ src/images/flags/BY.xpm \
+ src/images/flags/BZ.xpm \
+ src/images/flags/CA.xpm \
+ src/images/flags/CC.xpm \
+ src/images/flags/CD.xpm \
+ src/images/flags/CF.xpm \
+ src/images/flags/CG.xpm \
+ src/images/flags/CH.xpm \
+ src/images/flags/CI.xpm \
+ src/images/flags/CK.xpm \
+ src/images/flags/CL.xpm \
+ src/images/flags/CM.xpm \
+ src/images/flags/CN.xpm \
+ src/images/flags/CO.xpm \
+ src/images/flags/CR.xpm \
+ src/images/flags/CS.xpm \
+ src/images/flags/CU.xpm \
+ src/images/flags/CV.xpm \
+ src/images/flags/CX.xpm \
+ src/images/flags/CY.xpm \
+ src/images/flags/CZ.xpm \
+ src/images/flags/DE.xpm \
+ src/images/flags/DJ.xpm \
+ src/images/flags/DK.xpm \
+ src/images/flags/DM.xpm \
+ src/images/flags/DO.xpm \
+ src/images/flags/DZ.xpm \
+ src/images/flags/EC.xpm \
+ src/images/flags/EE.xpm \
+ src/images/flags/EG.xpm \
+ src/images/flags/EH.xpm \
+ src/images/flags/ER.xpm \
+ src/images/flags/ES.xpm \
+ src/images/flags/ET.xpm \
+ src/images/flags/FAM.xpm \
+ src/images/flags/FI.xpm \
+ src/images/flags/FJ.xpm \
+ src/images/flags/FK.xpm \
+ src/images/flags/FM.xpm \
+ src/images/flags/FO.xpm \
+ src/images/flags/FR.xpm \
+ src/images/flags/GA.xpm \
+ src/images/flags/GB.xpm \
+ src/images/flags/GD.xpm \
+ src/images/flags/GE.xpm \
+ src/images/flags/GF.xpm \
+ src/images/flags/GH.xpm \
+ src/images/flags/GI.xpm \
+ src/images/flags/GL.xpm \
+ src/images/flags/GM.xpm \
+ src/images/flags/GN.xpm \
+ src/images/flags/GP.xpm \
+ src/images/flags/GQ.xpm \
+ src/images/flags/GR.xpm \
+ src/images/flags/GS.xpm \
+ src/images/flags/GT.xpm \
+ src/images/flags/GU.xpm \
+ src/images/flags/GW.xpm \
+ src/images/flags/GY.xpm \
+ src/images/flags/HK.xpm \
+ src/images/flags/HM.xpm \
+ src/images/flags/HN.xpm \
+ src/images/flags/HR.xpm \
+ src/images/flags/HT.xpm \
+ src/images/flags/HU.xpm \
+ src/images/flags/ID.xpm \
+ src/images/flags/IE.xpm \
+ src/images/flags/IL.xpm \
+ src/images/flags/IN.xpm \
+ src/images/flags/IO.xpm \
+ src/images/flags/IQ.xpm \
+ src/images/flags/IR.xpm \
+ src/images/flags/IS.xpm \
+ src/images/flags/IT.xpm \
+ src/images/flags/JM.xpm \
+ src/images/flags/JO.xpm \
+ src/images/flags/JP.xpm \
+ src/images/flags/KE.xpm \
+ src/images/flags/KG.xpm \
+ src/images/flags/KH.xpm \
+ src/images/flags/KI.xpm \
+ src/images/flags/KM.xpm \
+ src/images/flags/KN.xpm \
+ src/images/flags/KP.xpm \
+ src/images/flags/KR.xpm \
+ src/images/flags/KW.xpm \
+ src/images/flags/KY.xpm \
+ src/images/flags/KZ.xpm \
+ src/images/flags/LA.xpm \
+ src/images/flags/LB.xpm \
+ src/images/flags/LC.xpm \
+ src/images/flags/LI.xpm \
+ src/images/flags/LK.xpm \
+ src/images/flags/LR.xpm \
+ src/images/flags/LS.xpm \
+ src/images/flags/LT.xpm \
+ src/images/flags/LU.xpm \
+ src/images/flags/LV.xpm \
+ src/images/flags/LY.xpm \
+ src/images/flags/MA.xpm \
+ src/images/flags/MC.xpm \
+ src/images/flags/MD.xpm \
+ src/images/flags/ME.xpm \
+ src/images/flags/MG.xpm \
+ src/images/flags/MH.xpm \
+ src/images/flags/MK.xpm \
+ src/images/flags/ML.xpm \
+ src/images/flags/MM.xpm \
+ src/images/flags/MN.xpm \
+ src/images/flags/MO.xpm \
+ src/images/flags/MP.xpm \
+ src/images/flags/MQ.xpm \
+ src/images/flags/MR.xpm \
+ src/images/flags/MS.xpm \
+ src/images/flags/MT.xpm \
+ src/images/flags/MU.xpm \
+ src/images/flags/MV.xpm \
+ src/images/flags/MW.xpm \
+ src/images/flags/MX.xpm \
+ src/images/flags/MY.xpm \
+ src/images/flags/MZ.xpm \
+ src/images/flags/NA.xpm \
+ src/images/flags/NC.xpm \
+ src/images/flags/NE.xpm \
+ src/images/flags/NF.xpm \
+ src/images/flags/NG.xpm \
+ src/images/flags/NI.xpm \
+ src/images/flags/NL.xpm \
+ src/images/flags/NO.xpm \
+ src/images/flags/NP.xpm \
+ src/images/flags/NR.xpm \
+ src/images/flags/NU.xpm \
+ src/images/flags/NZ.xpm \
+ src/images/flags/OM.xpm \
+ src/images/flags/PA.xpm \
+ src/images/flags/PE.xpm \
+ src/images/flags/PF.xpm \
+ src/images/flags/PG.xpm \
+ src/images/flags/PH.xpm \
+ src/images/flags/PK.xpm \
+ src/images/flags/PL.xpm \
+ src/images/flags/PM.xpm \
+ src/images/flags/PN.xpm \
+ src/images/flags/PR.xpm \
+ src/images/flags/PS.xpm \
+ src/images/flags/PT.xpm \
+ src/images/flags/PW.xpm \
+ src/images/flags/PY.xpm \
+ src/images/flags/QA.xpm \
+ src/images/flags/RE.xpm \
+ src/images/flags/RO.xpm \
+ src/images/flags/RS.xpm \
+ src/images/flags/RU.xpm \
+ src/images/flags/RW.xpm \
+ src/images/flags/SA.xpm \
+ src/images/flags/SB.xpm \
+ src/images/flags/SC.xpm \
+ src/images/flags/SD.xpm \
+ src/images/flags/SE.xpm \
+ src/images/flags/SG.xpm \
+ src/images/flags/SH.xpm \
+ src/images/flags/SI.xpm \
+ src/images/flags/SJ.xpm \
+ src/images/flags/SK.xpm \
+ src/images/flags/SL.xpm \
+ src/images/flags/SM.xpm \
+ src/images/flags/SN.xpm \
+ src/images/flags/SO.xpm \
+ src/images/flags/SR.xpm \
+ src/images/flags/ST.xpm \
+ src/images/flags/SV.xpm \
+ src/images/flags/SY.xpm \
+ src/images/flags/SZ.xpm \
+ src/images/flags/TC.xpm \
+ src/images/flags/TD.xpm \
+ src/images/flags/TF.xpm \
+ src/images/flags/TG.xpm \
+ src/images/flags/TH.xpm \
+ src/images/flags/TJ.xpm \
+ src/images/flags/TK.xpm \
+ src/images/flags/TL.xpm \
+ src/images/flags/TM.xpm \
+ src/images/flags/TN.xpm \
+ src/images/flags/TO.xpm \
+ src/images/flags/TR.xpm \
+ src/images/flags/TT.xpm \
+ src/images/flags/TV.xpm \
+ src/images/flags/TW.xpm \
+ src/images/flags/TZ.xpm \
+ src/images/flags/UA.xpm \
+ src/images/flags/UG.xpm \
+ src/images/flags/UM.xpm \
+ src/images/flags/US.xpm \
+ src/images/flags/UY.xpm \
+ src/images/flags/UZ.xpm \
+ src/images/flags/VA.xpm \
+ src/images/flags/VC.xpm \
+ src/images/flags/VE.xpm \
+ src/images/flags/VG.xpm \
+ src/images/flags/VI.xpm \
+ src/images/flags/VN.xpm \
+ src/images/flags/VU.xpm \
+ src/images/flags/WF.xpm \
+ src/images/flags/WS.xpm \
+ src/images/flags/YE.xpm \
+ src/images/flags/YT.xpm \
+ src/images/flags/ZA.xpm \
+ src/images/flags/ZM.xpm \
+ src/images/flags/ZW.xpm \
+ src/images/empty.xpm \
+ src/customlistctrl.h \
+ src/customlistctrl.cpp \
+ src/customvirtlistctrl.h \
+ src/mmoptionmodel.h \
+ src/mmoptionmodel.cpp \
+ src/mmoptionswrapper.h \
+ src/mmoptionswrapper.cpp \
+ src/battleroommmoptionstab.h \
+ src/torrentwrapper.cpp \
+ src/torrentwrapper.h \
+ src/thingdef.h \
+ src/spinctld.h \
+ src/spinctld.cpp \
+ src/autobalancedialog.cpp \
+ src/autobalancedialog.h \
+ src/tdfcontainer.cpp \
+ src/tdfcontainer.h \
+ src/globalevents.h \
+ src/globalevents.cpp \
+ src/httpdownloader.h \
+ src/Helper/TextCompletionDatabase.hpp \
+ src/Helper/TextCompletionDatabase.cpp \
+ src/Helper/wxTranslationHelper.h \
+ src/Helper/wxTranslationHelper.cpp \
+ src/Helper/tasclientimport.h \
+ src/Helper/tasclientimport.cpp \
+ src/Helper/slhtmlwindow.cpp \
+ src/Helper/slhtmlwindow.h \
+ src/channel/channelchooser.cpp \
+ src/channel/channelchooser.h \
+ src/channel/channelchooserdialog.cpp \
+ src/channel/channelchooserdialog.h \
+ src/Helper/colorbutton.cpp \
+ src/Helper/colorbutton.h \
+ src/Helper/wxtextctrlhist.cpp \
+ src/Helper/wxtextctrlhist.h \
+ src/Helper/sortutil.h \
+ src/Helper/imageviewer.h \
+ src/Helper/imageviewer.cpp \
+ src/filelister/filelistctrl.h \
+ src/filelister/filelistdialog.h \
+ src/filelister/filelistfilter.h \
+ src/filelister/filelistctrl.cpp \
+ src/filelister/filelistdialog.cpp \
+ src/filelister/filelistfilter.cpp \
+ configure.ac \
+ src/channel/autojoinchanneldialog.h \
+ src/autopointers.h \
+ src/channel/autojoinchanneldialog.cpp \
+ src/useractions.h \
+ src/useractions.cpp \
+ src/selectusersdialog.h \
+ src/selectusersdialog.cpp \
+ src/groupoptionspanel.h \
+ src/groupoptionspanel.cpp \
+ src/lobbyoptionstab.h \
+ src/lobbyoptionstab.cpp \
+ src/aui/auimanager.h \
+ src/aui/auimanager.cpp \
+ src/aui/auiutils.h \
+ src/aui/artprovider.h \
+ src/aui/artprovider.cpp \
+ src/updater/updater.h \
+ src/updater/updater.cpp \
+ src/widgets/downloadlistctrl.cpp \
+ src/widgets/downloadlistctrl.h \
+ src/widgets/downloaddialog.cpp \
+ src/widgets/downloaddialog.h \
+ src/widgets/downloadpanel.cpp \
+ src/widgets/downloadpanel.h \
+ src/widgets/infopanel.cpp \
+ src/widgets/infopanel.h \
+ src/widgets/widget.cpp \
+ src/widgets/widget.h \
+ src/usermenu.h \
+ src/thread.cpp \
+ src/thread.h \
+ src/globalsmanager.cpp \
+ src/globalsmanager.h \
+ src/mmoptionwindows.cpp \
+ src/mmoptionwindows.h \
+ src/playback/savegamelist.cpp \
+ src/playback/savegamelist.h \
+ src/images/floppy_icon.png.h \
+ src/images/replay_icon.png.h \
+ src/images/replay_icon_text.png.h
+
+
+if USE_WINDRES
+springlobby_SOURCES += \
+ src/springlobby.rc \
+ src/Helper/listctrl.cpp
+endif
+
+if USE_LIBT_INCLUDED
+springlobby_SOURCES += \
+ $(libtorrent_headers) \
+ $(libtorrent_sources)
+endif
+
+# TODO keep only a single list instead of duplicating the lists below
+# note, integrated has everything but main.cpp
+springlobby_SOURCES += \
+ src/settings++/se_utils.h \
+ src/settings++/se_utils.cpp \
+ src/settings++/frame.cpp \
+ src/settings++/main.h \
+ src/settings++/tab_ui.cpp \
+ src/settings++/tab_render_detail.cpp \
+ src/settings++/tab_quality_video.h \
+ src/settings++/frame.h \
+ src/settings++/tab_audio.h \
+ src/settings++/tab_audio.cpp \
+ src/settings++/presets.h \
+ src/settings++/tab_abstract.cpp \
+ src/settings++/Defs.hpp \
+ src/settings++/tab_simple.cpp \
+ src/settings++/tab_quality_video.cpp \
+ src/settings++/tab_ui.h \
+ src/settings++/tab_simple.h \
+ src/images/springsettings.xpm \
+ src/settings++/tab_render_detail.h \
+ src/settings++/tab_abstract.h \
+ src/settings++/panel_pathoption.h \
+ src/settings++/panel_pathoption.cpp \
+ src/settings++/custom_dialogs.h \
+ src/settings++/custom_dialogs.cpp \
+ src/settings++/helpmenufunctions.h \
+ src/settings++/helpmenufunctions.cpp
+
+springsettings_SOURCES = \
+ src/utils/debug.cpp \
+ src/utils/debug.h \
+ src/utils/platform.cpp \
+ src/utils/platform.h \
+ src/utils/conversion.cpp \
+ src/utils/conversion.h \
+ src/utils/sltipwin.cpp \
+ src/utils/sltipwin.h \
+ src/utils/controls.cpp \
+ src/utils/controls.h \
+ src/crashreport.cpp \
+ src/crashreport.h \
+ src/spinctld.h \
+ src/spinctld.cpp \
+ src/springunitsynclib.cpp \
+ src/springunitsynclib.h \
+ src/springunitsync.cpp \
+ src/springunitsync.h \
+ src/thread.cpp \
+ src/thread.h \
+ src/settings.cpp \
+ src/settings.h \
+ src/uiutils.cpp \
+ src/uiutils.h \
+ src/mmoptionmodel.h \
+ src/mmoptionmodel.cpp \
+ src/globalsmanager.cpp \
+ src/settings++/se_utils.cpp \
+ src/settings++/se_utils.h \
+ src/settings++/frame.cpp \
+ src/settings++/main.h \
+ src/settings++/tab_ui.cpp \
+ src/settings++/tab_render_detail.cpp \
+ src/settings++/tab_quality_video.h \
+ src/settings++/frame.h \
+ src/settings++/tab_audio.h \
+ src/settings++/tab_audio.cpp \
+ src/settings++/presets.h \
+ src/settings++/tab_abstract.cpp \
+ src/settings++/Main.cpp \
+ src/settings++/Defs.hpp \
+ src/settings++/tab_simple.cpp \
+ src/settings++/tab_quality_video.cpp \
+ src/settings++/tab_ui.h \
+ src/settings++/tab_simple.h \
+ src/images/springsettings.xpm \
+ src/settings++/tab_render_detail.h \
+ src/settings++/tab_abstract.h \
+ src/settings++/panel_pathoption.h \
+ src/settings++/panel_pathoption.cpp \
+ src/settings++/custom_dialogs.h \
+ src/settings++/custom_dialogs.cpp \
+ src/settings++/helpmenufunctions.h \
+ src/settings++/helpmenufunctions.cpp
+
+
+if USE_WINDRES
+springsettings_SOURCES += \
+ src/settings++/settings.rc
+endif
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..fa8568b
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,5000 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 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.
+
+ at SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@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@
+ at USE_WINDRES_TRUE@am__append_1 = \
+ at USE_WINDRES_TRUE@ -I$(libt_dir)/include -I$(libt_dir)/include/libtorrent \
+ at USE_WINDRES_TRUE@ -I$(libt_dir)/zlib -I$(libt_dir) -I $(libt_dir)/asio
+
+bin_PROGRAMS = springlobby$(EXEEXT) springsettings$(EXEEXT)
+ at USE_WINDRES_TRUE@am__append_2 = \
+ at USE_WINDRES_TRUE@ src/springlobby.rc \
+ at USE_WINDRES_TRUE@ src/Helper/listctrl.cpp
+
+ at USE_LIBT_INCLUDED_TRUE@am__append_3 = \
+ at USE_LIBT_INCLUDED_TRUE@ $(libtorrent_headers) \
+ at USE_LIBT_INCLUDED_TRUE@ $(libtorrent_sources)
+
+ at USE_WINDRES_TRUE@am__append_4 = \
+ at USE_WINDRES_TRUE@ src/settings++/settings.rc
+
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(dist_desktop_DATA) \
+ $(dist_doc_DATA) $(dist_pixmap_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(top_srcdir)/configure ABOUT-NLS AUTHORS COPYING ChangeLog \
+ INSTALL NEWS THANKS autotools-aux/config.guess \
+ autotools-aux/config.rpath autotools-aux/config.sub \
+ autotools-aux/depcomp autotools-aux/install-sh \
+ autotools-aux/missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/sdl.m4 \
+ $(top_srcdir)/m4/wxwin.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 = config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(desktopdir)" \
+ "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pixmapdir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__springlobby_SOURCES_DIST = src/utils/md5.h src/utils/md5.c \
+ src/aui/slbook.cpp src/aui/slbook.h src/utils/math.cpp \
+ src/utils/math.h src/utils/misc.cpp src/utils/misc.h \
+ src/utils/debug.cpp src/utils/debug.h src/utils/platform.cpp \
+ src/utils/platform.h src/utils/conversion.cpp \
+ src/utils/conversion.h src/utils/tasutil.cpp \
+ src/utils/tasutil.h src/utils/sltipwin.cpp \
+ src/utils/sltipwin.h src/utils/controls.cpp \
+ src/utils/controls.h src/updater/versionchecker.cpp \
+ src/updater/versionchecker.h src/sounds/ring_sound.h \
+ src/sounds/pm_sound.h src/springunitsynclib.cpp \
+ src/springunitsynclib.h src/unitsyncthread.cpp \
+ src/unitsyncthread.h src/mapgridctrl.cpp src/mapgridctrl.h \
+ src/mapselectdialog.cpp src/mapselectdialog.h src/bimap.h \
+ src/chatlog.h src/chatlog.cpp src/images/broom.png.h \
+ src/images/bot_ingame.png.h src/images/bot_broom.png.h \
+ src/images/channel_options.xpm src/images/chanop_ingame.xpm \
+ src/images/chanop_away.xpm src/images/chanop_broom.xpm \
+ src/images/chanop.xpm src/images/admin_broom.png.h \
+ src/images/host_spectator.xpm src/images/host.xpm \
+ src/images/not_found_icon.xpm src/images/reload_map.xpm \
+ src/images/download_map.xpm src/images/up_downsel.xpm \
+ src/images/upsel_down.xpm src/images/up_down.xpm \
+ src/images/player.xpm src/ibattle.cpp src/ibattle.h \
+ src/nonportable.h src/addbotdialog.cpp src/addbotdialog.h \
+ src/agreementdialog.cpp src/agreementdialog.h src/autohost.cpp \
+ src/autohost.h src/base64.cpp src/base64.h src/battle.cpp \
+ src/battle.h src/maintorrenttab.cpp src/maintorrenttab.h \
+ src/battlelistctrl.cpp src/battlelistctrl.h \
+ src/battlelistfilter.cpp src/battlelistfilter.h \
+ src/battlelistfiltervalues.h src/battlelist.cpp \
+ src/battlelist.h src/battlelisttab.cpp src/battlelisttab.h \
+ src/battleroomlistctrl.cpp src/battleroomlistctrl.h \
+ src/battlemaptab.cpp src/battlemaptab.h \
+ src/battleoptionstab.cpp src/battleoptionstab.h \
+ src/battleroomtab.cpp src/battleroomtab.h src/crc.cpp \
+ src/crc.h src/channel/channel.cpp src/channel/channel.h \
+ src/channel/channellist.cpp src/channel/channellist.h \
+ src/channel/channellistctrl.cpp src/channel/channellistctrl.h \
+ src/chatoptionstab.cpp src/chatoptionstab.h src/chatpanel.cpp \
+ src/chatpanel.h src/connectwindow.cpp src/connectwindow.h \
+ src/crashreport.cpp src/crashreport.h src/countrycodes.cpp \
+ src/countrycodes.h src/flagimagedata.h src/flagimages.cpp \
+ src/flagimages.h src/hostbattledialog.h \
+ src/hostbattledialog.cpp src/iconimagelist.cpp \
+ src/iconimagelist.h src/inetclass.h src/iunitsync.h \
+ src/mainchattab.cpp src/mainchattab.h \
+ src/mainjoinbattletab.cpp src/mainjoinbattletab.h \
+ src/mainoptionstab.cpp src/mainoptionstab.h \
+ src/mainsingleplayertab.cpp src/mainsingleplayertab.h \
+ src/mainwindow.cpp src/mainwindow.h src/mapctrl.cpp \
+ src/mapctrl.h src/mutexwrapper.h src/offlinebattle.h \
+ src/offlinebattle.cpp src/nicklistctrl.cpp src/nicklistctrl.h \
+ src/playback/playbacktab.h src/playback/playbackthread.h \
+ src/playback/playbackfilter.h src/playback/replaylist.h \
+ src/playback/replaylist.cpp src/playback/playbacklistctrl.h \
+ src/playback/playbackfiltervalues.h src/sdlsound.h \
+ src/sdlsound.cpp src/server.cpp src/serverevents.cpp \
+ src/serverevents.h src/server.h src/settings.cpp \
+ src/settings.h src/socket.cpp src/socket.h src/spring.cpp \
+ src/spring.h src/singleplayerbattle.cpp \
+ src/singleplayerbattle.h src/singleplayertab.cpp \
+ src/singleplayertab.h src/springlobbyapp.cpp \
+ src/springlobbyapp.h src/springoptionstab.cpp \
+ src/springoptionstab.h src/springprocess.cpp \
+ src/springprocess.h src/springunitsync.cpp \
+ src/springunitsync.h src/tasserver.cpp src/tasserver.h \
+ src/tasservertokentable.h src/ui.cpp src/ui.h src/uiutils.cpp \
+ src/uiutils.h src/user.cpp src/user.h src/usermenu.h \
+ src/userlist.cpp src/userlist.h src/userlistctrl.cpp \
+ src/userlistctrl.h src/torrentlistctrl.cpp \
+ src/torrentlistctrl.h src/torrentoptionspanel.cpp \
+ src/torrentoptionspanel.h src/images/start_ally.xpm \
+ src/images/start_enemy.xpm src/images/start_unused.xpm \
+ src/images/admin_away.png.h src/images/admin_ingame.png.h \
+ src/images/admin.png.h src/images/no1_icon.png.h \
+ src/images/no2_icon.png.h src/images/away.png.h \
+ src/images/battle_list.xpm src/images/battle_map.xpm \
+ src/images/battle_settings.xpm src/images/battle.xpm \
+ src/images/bot.xpm src/images/bot_away.xpm \
+ src/images/channel.xpm src/images/chat_icon.png.h \
+ src/images/chat_icon_text.png.h src/images/closed_game.png.h \
+ src/images/closed_full_game.png.h \
+ src/images/closed_pw_game.png.h \
+ src/images/closed_full_pw_game.png.h \
+ src/images/torrentoptionspanel_icon.png.h \
+ src/images/close_hi.xpm src/images/close.xpm \
+ src/images/colourbox.xpm src/images/connect.xpm \
+ src/images/down.xpm src/images/exists.xpm \
+ src/images/fixcolours_palette.xpm src/images/ingame.png.h \
+ src/images/join_icon.png.h src/images/join_icon_text.png.h \
+ src/images/nexists.xpm src/images/nready_q.xpm \
+ src/images/nready_unsync.xpm src/images/open_game.png.h \
+ src/images/open_full_game.png.h src/images/open_pw_game.png.h \
+ src/images/open_full_pw_game.png.h \
+ src/images/options_icon.png.h \
+ src/images/options_icon_text.png.h \
+ src/images/arrow_refresh.png.h src/images/rank0.xpm \
+ src/images/rank1.xpm src/images/rank2.xpm src/images/rank3.xpm \
+ src/images/rank4.xpm src/images/rank5.xpm src/images/rank6.xpm \
+ src/images/rank_unknown.xpm src/images/ready_q.xpm \
+ src/images/ready_unsync.xpm src/images/downloads_icon.png.h \
+ src/images/single_player_icon.png.h \
+ src/images/downloads_icon_text.png.h \
+ src/images/warning_small.png.h src/images/spectator.png.h \
+ src/images/single_player_icon_text.png.h \
+ src/images/map_select_1.png.h src/images/map_select_2.png.h \
+ src/images/select_icon.xpm src/images/server.xpm \
+ src/images/spectator.xpm src/images/spring.xpm \
+ src/images/springlobby.xpm src/images/started_game.xpm \
+ src/images/unknown_flag.xpm src/images/up.xpm \
+ src/images/userchat.xpm src/images/flags/AD.xpm \
+ src/images/flags/AE.xpm src/images/flags/AF.xpm \
+ src/images/flags/AG.xpm src/images/flags/AI.xpm \
+ src/images/flags/AL.xpm src/images/flags/AM.xpm \
+ src/images/flags/AN.xpm src/images/flags/AO.xpm \
+ src/images/flags/AR.xpm src/images/flags/AS.xpm \
+ src/images/flags/AT.xpm src/images/flags/AU.xpm \
+ src/images/flags/AW.xpm src/images/flags/AX.xpm \
+ src/images/flags/AZ.xpm src/images/flags/BA.xpm \
+ src/images/flags/BB.xpm src/images/flags/BD.xpm \
+ src/images/flags/BE.xpm src/images/flags/BF.xpm \
+ src/images/flags/BG.xpm src/images/flags/BH.xpm \
+ src/images/flags/BI.xpm src/images/flags/BJ.xpm \
+ src/images/flags/BM.xpm src/images/flags/BN.xpm \
+ src/images/flags/BO.xpm src/images/flags/BR.xpm \
+ src/images/flags/BS.xpm src/images/flags/BT.xpm \
+ src/images/flags/BV.xpm src/images/flags/BW.xpm \
+ src/images/flags/BY.xpm src/images/flags/BZ.xpm \
+ src/images/flags/CA.xpm src/images/flags/CC.xpm \
+ src/images/flags/CD.xpm src/images/flags/CF.xpm \
+ src/images/flags/CG.xpm src/images/flags/CH.xpm \
+ src/images/flags/CI.xpm src/images/flags/CK.xpm \
+ src/images/flags/CL.xpm src/images/flags/CM.xpm \
+ src/images/flags/CN.xpm src/images/flags/CO.xpm \
+ src/images/flags/CR.xpm src/images/flags/CS.xpm \
+ src/images/flags/CU.xpm src/images/flags/CV.xpm \
+ src/images/flags/CX.xpm src/images/flags/CY.xpm \
+ src/images/flags/CZ.xpm src/images/flags/DE.xpm \
+ src/images/flags/DJ.xpm src/images/flags/DK.xpm \
+ src/images/flags/DM.xpm src/images/flags/DO.xpm \
+ src/images/flags/DZ.xpm src/images/flags/EC.xpm \
+ src/images/flags/EE.xpm src/images/flags/EG.xpm \
+ src/images/flags/EH.xpm src/images/flags/ER.xpm \
+ src/images/flags/ES.xpm src/images/flags/ET.xpm \
+ src/images/flags/FAM.xpm src/images/flags/FI.xpm \
+ src/images/flags/FJ.xpm src/images/flags/FK.xpm \
+ src/images/flags/FM.xpm src/images/flags/FO.xpm \
+ src/images/flags/FR.xpm src/images/flags/GA.xpm \
+ src/images/flags/GB.xpm src/images/flags/GD.xpm \
+ src/images/flags/GE.xpm src/images/flags/GF.xpm \
+ src/images/flags/GH.xpm src/images/flags/GI.xpm \
+ src/images/flags/GL.xpm src/images/flags/GM.xpm \
+ src/images/flags/GN.xpm src/images/flags/GP.xpm \
+ src/images/flags/GQ.xpm src/images/flags/GR.xpm \
+ src/images/flags/GS.xpm src/images/flags/GT.xpm \
+ src/images/flags/GU.xpm src/images/flags/GW.xpm \
+ src/images/flags/GY.xpm src/images/flags/HK.xpm \
+ src/images/flags/HM.xpm src/images/flags/HN.xpm \
+ src/images/flags/HR.xpm src/images/flags/HT.xpm \
+ src/images/flags/HU.xpm src/images/flags/ID.xpm \
+ src/images/flags/IE.xpm src/images/flags/IL.xpm \
+ src/images/flags/IN.xpm src/images/flags/IO.xpm \
+ src/images/flags/IQ.xpm src/images/flags/IR.xpm \
+ src/images/flags/IS.xpm src/images/flags/IT.xpm \
+ src/images/flags/JM.xpm src/images/flags/JO.xpm \
+ src/images/flags/JP.xpm src/images/flags/KE.xpm \
+ src/images/flags/KG.xpm src/images/flags/KH.xpm \
+ src/images/flags/KI.xpm src/images/flags/KM.xpm \
+ src/images/flags/KN.xpm src/images/flags/KP.xpm \
+ src/images/flags/KR.xpm src/images/flags/KW.xpm \
+ src/images/flags/KY.xpm src/images/flags/KZ.xpm \
+ src/images/flags/LA.xpm src/images/flags/LB.xpm \
+ src/images/flags/LC.xpm src/images/flags/LI.xpm \
+ src/images/flags/LK.xpm src/images/flags/LR.xpm \
+ src/images/flags/LS.xpm src/images/flags/LT.xpm \
+ src/images/flags/LU.xpm src/images/flags/LV.xpm \
+ src/images/flags/LY.xpm src/images/flags/MA.xpm \
+ src/images/flags/MC.xpm src/images/flags/MD.xpm \
+ src/images/flags/ME.xpm src/images/flags/MG.xpm \
+ src/images/flags/MH.xpm src/images/flags/MK.xpm \
+ src/images/flags/ML.xpm src/images/flags/MM.xpm \
+ src/images/flags/MN.xpm src/images/flags/MO.xpm \
+ src/images/flags/MP.xpm src/images/flags/MQ.xpm \
+ src/images/flags/MR.xpm src/images/flags/MS.xpm \
+ src/images/flags/MT.xpm src/images/flags/MU.xpm \
+ src/images/flags/MV.xpm src/images/flags/MW.xpm \
+ src/images/flags/MX.xpm src/images/flags/MY.xpm \
+ src/images/flags/MZ.xpm src/images/flags/NA.xpm \
+ src/images/flags/NC.xpm src/images/flags/NE.xpm \
+ src/images/flags/NF.xpm src/images/flags/NG.xpm \
+ src/images/flags/NI.xpm src/images/flags/NL.xpm \
+ src/images/flags/NO.xpm src/images/flags/NP.xpm \
+ src/images/flags/NR.xpm src/images/flags/NU.xpm \
+ src/images/flags/NZ.xpm src/images/flags/OM.xpm \
+ src/images/flags/PA.xpm src/images/flags/PE.xpm \
+ src/images/flags/PF.xpm src/images/flags/PG.xpm \
+ src/images/flags/PH.xpm src/images/flags/PK.xpm \
+ src/images/flags/PL.xpm src/images/flags/PM.xpm \
+ src/images/flags/PN.xpm src/images/flags/PR.xpm \
+ src/images/flags/PS.xpm src/images/flags/PT.xpm \
+ src/images/flags/PW.xpm src/images/flags/PY.xpm \
+ src/images/flags/QA.xpm src/images/flags/RE.xpm \
+ src/images/flags/RO.xpm src/images/flags/RS.xpm \
+ src/images/flags/RU.xpm src/images/flags/RW.xpm \
+ src/images/flags/SA.xpm src/images/flags/SB.xpm \
+ src/images/flags/SC.xpm src/images/flags/SD.xpm \
+ src/images/flags/SE.xpm src/images/flags/SG.xpm \
+ src/images/flags/SH.xpm src/images/flags/SI.xpm \
+ src/images/flags/SJ.xpm src/images/flags/SK.xpm \
+ src/images/flags/SL.xpm src/images/flags/SM.xpm \
+ src/images/flags/SN.xpm src/images/flags/SO.xpm \
+ src/images/flags/SR.xpm src/images/flags/ST.xpm \
+ src/images/flags/SV.xpm src/images/flags/SY.xpm \
+ src/images/flags/SZ.xpm src/images/flags/TC.xpm \
+ src/images/flags/TD.xpm src/images/flags/TF.xpm \
+ src/images/flags/TG.xpm src/images/flags/TH.xpm \
+ src/images/flags/TJ.xpm src/images/flags/TK.xpm \
+ src/images/flags/TL.xpm src/images/flags/TM.xpm \
+ src/images/flags/TN.xpm src/images/flags/TO.xpm \
+ src/images/flags/TR.xpm src/images/flags/TT.xpm \
+ src/images/flags/TV.xpm src/images/flags/TW.xpm \
+ src/images/flags/TZ.xpm src/images/flags/UA.xpm \
+ src/images/flags/UG.xpm src/images/flags/UM.xpm \
+ src/images/flags/US.xpm src/images/flags/UY.xpm \
+ src/images/flags/UZ.xpm src/images/flags/VA.xpm \
+ src/images/flags/VC.xpm src/images/flags/VE.xpm \
+ src/images/flags/VG.xpm src/images/flags/VI.xpm \
+ src/images/flags/VN.xpm src/images/flags/VU.xpm \
+ src/images/flags/WF.xpm src/images/flags/WS.xpm \
+ src/images/flags/YE.xpm src/images/flags/YT.xpm \
+ src/images/flags/ZA.xpm src/images/flags/ZM.xpm \
+ src/images/flags/ZW.xpm src/images/empty.xpm \
+ src/customlistctrl.h src/customlistctrl.cpp \
+ src/customvirtlistctrl.h src/mmoptionmodel.h \
+ src/mmoptionmodel.cpp src/mmoptionswrapper.h \
+ src/mmoptionswrapper.cpp src/battleroommmoptionstab.h \
+ src/torrentwrapper.cpp src/torrentwrapper.h src/thingdef.h \
+ src/spinctld.h src/spinctld.cpp src/autobalancedialog.cpp \
+ src/autobalancedialog.h src/tdfcontainer.cpp \
+ src/tdfcontainer.h src/globalevents.h src/globalevents.cpp \
+ src/httpdownloader.h src/Helper/TextCompletionDatabase.hpp \
+ src/Helper/TextCompletionDatabase.cpp \
+ src/Helper/wxTranslationHelper.h \
+ src/Helper/wxTranslationHelper.cpp \
+ src/Helper/tasclientimport.h src/Helper/tasclientimport.cpp \
+ src/Helper/slhtmlwindow.cpp src/Helper/slhtmlwindow.h \
+ src/channel/channelchooser.cpp src/channel/channelchooser.h \
+ src/channel/channelchooserdialog.cpp \
+ src/channel/channelchooserdialog.h src/Helper/colorbutton.cpp \
+ src/Helper/colorbutton.h src/Helper/wxtextctrlhist.cpp \
+ src/Helper/wxtextctrlhist.h src/Helper/sortutil.h \
+ src/Helper/imageviewer.h src/Helper/imageviewer.cpp \
+ src/filelister/filelistctrl.h src/filelister/filelistdialog.h \
+ src/filelister/filelistfilter.h \
+ src/filelister/filelistctrl.cpp \
+ src/filelister/filelistdialog.cpp \
+ src/filelister/filelistfilter.cpp configure.ac \
+ src/channel/autojoinchanneldialog.h src/autopointers.h \
+ src/channel/autojoinchanneldialog.cpp src/useractions.h \
+ src/useractions.cpp src/selectusersdialog.h \
+ src/selectusersdialog.cpp src/groupoptionspanel.h \
+ src/groupoptionspanel.cpp src/lobbyoptionstab.h \
+ src/lobbyoptionstab.cpp src/aui/auimanager.h \
+ src/aui/auimanager.cpp src/aui/auiutils.h \
+ src/aui/artprovider.h src/aui/artprovider.cpp \
+ src/updater/updater.h src/updater/updater.cpp \
+ src/widgets/downloadlistctrl.cpp \
+ src/widgets/downloadlistctrl.h src/widgets/downloaddialog.cpp \
+ src/widgets/downloaddialog.h src/widgets/downloadpanel.cpp \
+ src/widgets/downloadpanel.h src/widgets/infopanel.cpp \
+ src/widgets/infopanel.h src/widgets/widget.cpp \
+ src/widgets/widget.h src/thread.cpp src/thread.h \
+ src/globalsmanager.cpp src/globalsmanager.h \
+ src/mmoptionwindows.cpp src/mmoptionwindows.h \
+ src/playback/savegamelist.cpp src/playback/savegamelist.h \
+ src/images/floppy_icon.png.h src/images/replay_icon.png.h \
+ src/images/replay_icon_text.png.h src/springlobby.rc \
+ src/Helper/listctrl.cpp \
+ $(libt_dir)/include/libtorrent/alert.hpp \
+ $(libt_dir)/include/libtorrent/alert_types.hpp \
+ $(libt_dir)/include/libtorrent/assert.hpp \
+ $(libt_dir)/include/libtorrent/aux_/session_impl.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_manager.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_limit.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_queue_entry.hpp \
+ $(libt_dir)/include/libtorrent/bencode.hpp \
+ $(libt_dir)/include/libtorrent/broadcast_socket.hpp \
+ $(libt_dir)/include/libtorrent/buffer.hpp \
+ $(libt_dir)/include/libtorrent/connection_queue.hpp \
+ $(libt_dir)/include/libtorrent/debug.hpp \
+ $(libt_dir)/include/libtorrent/disk_io_thread.hpp \
+ $(libt_dir)/include/libtorrent/entry.hpp \
+ $(libt_dir)/include/libtorrent/enum_net.hpp \
+ $(libt_dir)/include/libtorrent/escape_string.hpp \
+ $(libt_dir)/include/libtorrent/extensions.hpp \
+ $(libt_dir)/include/libtorrent/extensions/metadata_transfer.hpp \
+ $(libt_dir)/include/libtorrent/extensions/logger.hpp \
+ $(libt_dir)/include/libtorrent/extensions/ut_pex.hpp \
+ $(libt_dir)/include/libtorrent/file.hpp \
+ $(libt_dir)/include/libtorrent/file_pool.hpp \
+ $(libt_dir)/include/libtorrent/fingerprint.hpp \
+ $(libt_dir)/include/libtorrent/hasher.hpp \
+ $(libt_dir)/include/libtorrent/http_connection.hpp \
+ $(libt_dir)/include/libtorrent/http_stream.hpp \
+ $(libt_dir)/include/libtorrent/session_settings.hpp \
+ $(libt_dir)/include/libtorrent/http_tracker_connection.hpp \
+ $(libt_dir)/include/libtorrent/identify_client.hpp \
+ $(libt_dir)/include/libtorrent/instantiate_connection.hpp \
+ $(libt_dir)/include/libtorrent/intrusive_ptr_base.hpp \
+ $(libt_dir)/include/libtorrent/invariant_check.hpp \
+ $(libt_dir)/include/libtorrent/io.hpp \
+ $(libt_dir)/include/libtorrent/ip_filter.hpp \
+ $(libt_dir)/include/libtorrent/chained_buffer.hpp \
+ $(libt_dir)/include/libtorrent/lsd.hpp \
+ $(libt_dir)/include/libtorrent/peer.hpp \
+ $(libt_dir)/include/libtorrent/peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/bt_peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/web_peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/pe_crypto.hpp \
+ $(libt_dir)/include/libtorrent/natpmp.hpp \
+ $(libt_dir)/include/libtorrent/pch.hpp \
+ $(libt_dir)/include/libtorrent/peer_id.hpp \
+ $(libt_dir)/include/libtorrent/peer_info.hpp \
+ $(libt_dir)/include/libtorrent/peer_request.hpp \
+ $(libt_dir)/include/libtorrent/piece_block_progress.hpp \
+ $(libt_dir)/include/libtorrent/piece_picker.hpp \
+ $(libt_dir)/include/libtorrent/policy.hpp \
+ $(libt_dir)/include/libtorrent/session.hpp \
+ $(libt_dir)/include/libtorrent/size_type.hpp \
+ $(libt_dir)/include/libtorrent/socket.hpp \
+ $(libt_dir)/include/libtorrent/socket_type.hpp \
+ $(libt_dir)/include/libtorrent/socks4_stream.hpp \
+ $(libt_dir)/include/libtorrent/socks5_stream.hpp \
+ $(libt_dir)/include/libtorrent/stat.hpp \
+ $(libt_dir)/include/libtorrent/storage.hpp \
+ $(libt_dir)/include/libtorrent/time.hpp \
+ $(libt_dir)/include/libtorrent/torrent.hpp \
+ $(libt_dir)/include/libtorrent/torrent_handle.hpp \
+ $(libt_dir)/include/libtorrent/torrent_info.hpp \
+ $(libt_dir)/include/libtorrent/tracker_manager.hpp \
+ $(libt_dir)/include/libtorrent/udp_tracker_connection.hpp \
+ $(libt_dir)/include/libtorrent/utf8.hpp \
+ $(libt_dir)/include/libtorrent/xml_parse.hpp \
+ $(libt_dir)/include/libtorrent/variant_stream.hpp \
+ $(libt_dir)/include/libtorrent/version.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/closest_nodes.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/dht_tracker.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/find_data.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/logging.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/msg.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node_entry.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node_id.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/observer.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/packet_iterator.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/refresh.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/routing_table.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/rpc_manager.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/traversal_algorithm.hpp \
+ $(libt_dir)/asio.hpp \
+ $(libt_dir)/asio/basic_datagram_socket.hpp \
+ $(libt_dir)/asio/basic_deadline_timer.hpp \
+ $(libt_dir)/asio/basic_io_object.hpp \
+ $(libt_dir)/asio/basic_socket.hpp \
+ $(libt_dir)/asio/basic_socket_acceptor.hpp \
+ $(libt_dir)/asio/basic_socket_iostream.hpp \
+ $(libt_dir)/asio/basic_socket_streambuf.hpp \
+ $(libt_dir)/asio/basic_stream_socket.hpp \
+ $(libt_dir)/asio/basic_streambuf.hpp \
+ $(libt_dir)/asio/buffer.hpp \
+ $(libt_dir)/asio/buffered_read_stream.hpp \
+ $(libt_dir)/asio/buffered_read_stream_fwd.hpp \
+ $(libt_dir)/asio/buffered_stream.hpp \
+ $(libt_dir)/asio/buffered_stream_fwd.hpp \
+ $(libt_dir)/asio/buffered_write_stream.hpp \
+ $(libt_dir)/asio/buffered_write_stream_fwd.hpp \
+ $(libt_dir)/asio/completion_condition.hpp \
+ $(libt_dir)/asio/datagram_socket_service.hpp \
+ $(libt_dir)/asio/deadline_timer.hpp \
+ $(libt_dir)/asio/deadline_timer_service.hpp \
+ $(libt_dir)/asio/error.hpp $(libt_dir)/asio/error_code.hpp \
+ $(libt_dir)/asio/handler_alloc_hook.hpp \
+ $(libt_dir)/asio/handler_invoke_hook.hpp \
+ $(libt_dir)/asio/io_service.hpp \
+ $(libt_dir)/asio/is_read_buffered.hpp \
+ $(libt_dir)/asio/is_write_buffered.hpp \
+ $(libt_dir)/asio/placeholders.hpp $(libt_dir)/asio/read.hpp \
+ $(libt_dir)/asio/read_until.hpp \
+ $(libt_dir)/asio/socket_acceptor_service.hpp \
+ $(libt_dir)/asio/socket_base.hpp $(libt_dir)/asio/ssl.hpp \
+ $(libt_dir)/asio/strand.hpp \
+ $(libt_dir)/asio/stream_socket_service.hpp \
+ $(libt_dir)/asio/streambuf.hpp \
+ $(libt_dir)/asio/system_error.hpp $(libt_dir)/asio/thread.hpp \
+ $(libt_dir)/asio/time_traits.hpp $(libt_dir)/asio/version.hpp \
+ $(libt_dir)/asio/write.hpp \
+ $(libt_dir)/asio/detail/bind_handler.hpp \
+ $(libt_dir)/asio/detail/buffer_resize_guard.hpp \
+ $(libt_dir)/asio/detail/buffered_stream_storage.hpp \
+ $(libt_dir)/asio/detail/call_stack.hpp \
+ $(libt_dir)/asio/detail/const_buffers_iterator.hpp \
+ $(libt_dir)/asio/detail/consuming_buffers.hpp \
+ $(libt_dir)/asio/detail/deadline_timer_service.hpp \
+ $(libt_dir)/asio/detail/dev_poll_reactor.hpp \
+ $(libt_dir)/asio/detail/dev_poll_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/epoll_reactor.hpp \
+ $(libt_dir)/asio/detail/epoll_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/event.hpp \
+ $(libt_dir)/asio/detail/fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/handler_alloc_helpers.hpp \
+ $(libt_dir)/asio/detail/handler_invoke_helpers.hpp \
+ $(libt_dir)/asio/detail/handler_queue.hpp \
+ $(libt_dir)/asio/detail/hash_map.hpp \
+ $(libt_dir)/asio/detail/io_control.hpp \
+ $(libt_dir)/asio/detail/kqueue_reactor.hpp \
+ $(libt_dir)/asio/detail/kqueue_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/local_free_on_block_exit.hpp \
+ $(libt_dir)/asio/detail/mutex.hpp \
+ $(libt_dir)/asio/detail/noncopyable.hpp \
+ $(libt_dir)/asio/detail/null_event.hpp \
+ $(libt_dir)/asio/detail/null_mutex.hpp \
+ $(libt_dir)/asio/detail/null_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/null_thread.hpp \
+ $(libt_dir)/asio/detail/null_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/old_win_sdk_compat.hpp \
+ $(libt_dir)/asio/detail/pipe_select_interrupter.hpp \
+ $(libt_dir)/asio/detail/pop_options.hpp \
+ $(libt_dir)/asio/detail/posix_event.hpp \
+ $(libt_dir)/asio/detail/posix_fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/posix_mutex.hpp \
+ $(libt_dir)/asio/detail/posix_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/posix_thread.hpp \
+ $(libt_dir)/asio/detail/posix_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/push_options.hpp \
+ $(libt_dir)/asio/detail/reactive_socket_service.hpp \
+ $(libt_dir)/asio/detail/reactor_op_queue.hpp \
+ $(libt_dir)/asio/detail/resolver_service.hpp \
+ $(libt_dir)/asio/detail/scoped_lock.hpp \
+ $(libt_dir)/asio/detail/select_interrupter.hpp \
+ $(libt_dir)/asio/detail/select_reactor.hpp \
+ $(libt_dir)/asio/detail/select_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/service_base.hpp \
+ $(libt_dir)/asio/detail/service_id.hpp \
+ $(libt_dir)/asio/detail/service_registry.hpp \
+ $(libt_dir)/asio/detail/service_registry_fwd.hpp \
+ $(libt_dir)/asio/detail/signal_blocker.hpp \
+ $(libt_dir)/asio/detail/signal_init.hpp \
+ $(libt_dir)/asio/detail/socket_holder.hpp \
+ $(libt_dir)/asio/detail/socket_ops.hpp \
+ $(libt_dir)/asio/detail/socket_option.hpp \
+ $(libt_dir)/asio/detail/socket_select_interrupter.hpp \
+ $(libt_dir)/asio/detail/socket_types.hpp \
+ $(libt_dir)/asio/detail/strand_service.hpp \
+ $(libt_dir)/asio/detail/task_io_service.hpp \
+ $(libt_dir)/asio/detail/task_io_service_fwd.hpp \
+ $(libt_dir)/asio/detail/thread.hpp \
+ $(libt_dir)/asio/detail/throw_error.hpp \
+ $(libt_dir)/asio/detail/timer_queue.hpp \
+ $(libt_dir)/asio/detail/timer_queue_base.hpp \
+ $(libt_dir)/asio/detail/tss_ptr.hpp \
+ $(libt_dir)/asio/detail/win_event.hpp \
+ $(libt_dir)/asio/detail/win_fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/win_iocp_io_service.hpp \
+ $(libt_dir)/asio/detail/win_iocp_io_service_fwd.hpp \
+ $(libt_dir)/asio/detail/win_iocp_socket_service.hpp \
+ $(libt_dir)/asio/detail/win_mutex.hpp \
+ $(libt_dir)/asio/detail/win_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/win_thread.hpp \
+ $(libt_dir)/asio/detail/win_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/wince_thread.hpp \
+ $(libt_dir)/asio/detail/winsock_init.hpp \
+ $(libt_dir)/asio/detail/wrapped_handler.hpp \
+ $(libt_dir)/asio/impl/error_code.ipp \
+ $(libt_dir)/asio/impl/io_service.ipp \
+ $(libt_dir)/asio/impl/read.ipp \
+ $(libt_dir)/asio/impl/read_until.ipp \
+ $(libt_dir)/asio/impl/write.ipp \
+ $(libt_dir)/asio/ip/address.hpp \
+ $(libt_dir)/asio/ip/address_v4.hpp \
+ $(libt_dir)/asio/ip/address_v6.hpp \
+ $(libt_dir)/asio/ip/basic_endpoint.hpp \
+ $(libt_dir)/asio/ip/basic_resolver.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_entry.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_iterator.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_query.hpp \
+ $(libt_dir)/asio/ip/host_name.hpp \
+ $(libt_dir)/asio/ip/multicast.hpp \
+ $(libt_dir)/asio/ip/resolver_query_base.hpp \
+ $(libt_dir)/asio/ip/resolver_service.hpp \
+ $(libt_dir)/asio/ip/tcp.hpp $(libt_dir)/asio/ip/udp.hpp \
+ $(libt_dir)/asio/ip/unicast.hpp \
+ $(libt_dir)/asio/ip/v6_only.hpp \
+ $(libt_dir)/asio/ip/detail/socket_option.hpp \
+ $(libt_dir)/asio/ssl/basic_context.hpp \
+ $(libt_dir)/asio/ssl/context.hpp \
+ $(libt_dir)/asio/ssl/context_base.hpp \
+ $(libt_dir)/asio/ssl/context_service.hpp \
+ $(libt_dir)/asio/ssl/stream.hpp \
+ $(libt_dir)/asio/ssl/stream_base.hpp \
+ $(libt_dir)/asio/ssl/stream_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_context_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_init.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_operation.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_stream_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_types.hpp \
+ $(libt_dir)/zlib/crc32.h $(libt_dir)/zlib/deflate.h \
+ $(libt_dir)/zlib/inffast.h $(libt_dir)/zlib/inflate.h \
+ $(libt_dir)/zlib/inftrees.h $(libt_dir)/zlib/trees.h \
+ $(libt_dir)/zlib/zconf.h $(libt_dir)/zlib/zlib.h \
+ $(libt_dir)/zlib/zutil.h $(libt_src_dir)/entry.cpp \
+ $(libt_src_dir)/escape_string.cpp $(libt_src_dir)/assert.cpp \
+ $(libt_src_dir)/enum_net.cpp \
+ $(libt_src_dir)/broadcast_socket.cpp \
+ $(libt_src_dir)/peer_connection.cpp \
+ $(libt_src_dir)/bt_peer_connection.cpp \
+ $(libt_src_dir)/web_peer_connection.cpp \
+ $(libt_src_dir)/natpmp.cpp $(libt_src_dir)/piece_picker.cpp \
+ $(libt_src_dir)/policy.cpp $(libt_src_dir)/session.cpp \
+ $(libt_src_dir)/session_impl.cpp $(libt_src_dir)/sha1.cpp \
+ $(libt_src_dir)/stat.cpp $(libt_src_dir)/storage.cpp \
+ $(libt_src_dir)/torrent.cpp $(libt_src_dir)/torrent_handle.cpp \
+ $(libt_src_dir)/pe_crypto.cpp $(libt_src_dir)/torrent_info.cpp \
+ $(libt_src_dir)/tracker_manager.cpp \
+ $(libt_src_dir)/http_connection.cpp \
+ $(libt_src_dir)/http_tracker_connection.cpp \
+ $(libt_src_dir)/udp_tracker_connection.cpp \
+ $(libt_src_dir)/alert.cpp $(libt_src_dir)/identify_client.cpp \
+ $(libt_src_dir)/ip_filter.cpp $(libt_src_dir)/file.cpp \
+ $(libt_src_dir)/metadata_transfer.cpp \
+ $(libt_src_dir)/logger.cpp $(libt_src_dir)/file_pool.cpp \
+ $(libt_src_dir)/ut_pex.cpp $(libt_src_dir)/lsd.cpp \
+ $(libt_src_dir)/upnp.cpp \
+ $(libt_src_dir)/instantiate_connection.cpp \
+ $(libt_src_dir)/socks5_stream.cpp \
+ $(libt_src_dir)/socks4_stream.cpp \
+ $(libt_src_dir)/http_stream.cpp \
+ $(libt_src_dir)/connection_queue.cpp \
+ $(libt_src_dir)/disk_io_thread.cpp \
+ $(libt_src_dir)/kademlia/closest_nodes.cpp \
+ $(libt_src_dir)/kademlia/dht_tracker.cpp \
+ $(libt_src_dir)/kademlia/find_data.cpp \
+ $(libt_src_dir)/kademlia/node.cpp \
+ $(libt_src_dir)/kademlia/node_id.cpp \
+ $(libt_src_dir)/kademlia/refresh.cpp \
+ $(libt_src_dir)/kademlia/routing_table.cpp \
+ $(libt_src_dir)/kademlia/rpc_manager.cpp \
+ $(libt_src_dir)/kademlia/traversal_algorithm.cpp \
+ $(libt_dir)/zlib/adler32.c $(libt_dir)/zlib/compress.c \
+ $(libt_dir)/zlib/crc32.c $(libt_dir)/zlib/deflate.c \
+ $(libt_dir)/zlib/gzio.c $(libt_dir)/zlib/infback.c \
+ $(libt_dir)/zlib/inffast.c $(libt_dir)/zlib/inflate.c \
+ $(libt_dir)/zlib/inftrees.c $(libt_dir)/zlib/trees.c \
+ $(libt_dir)/zlib/uncompr.c $(libt_dir)/zlib/zutil.c \
+ src/settings++/se_utils.h src/settings++/se_utils.cpp \
+ src/settings++/frame.cpp src/settings++/main.h \
+ src/settings++/tab_ui.cpp src/settings++/tab_render_detail.cpp \
+ src/settings++/tab_quality_video.h src/settings++/frame.h \
+ src/settings++/tab_audio.h src/settings++/tab_audio.cpp \
+ src/settings++/presets.h src/settings++/tab_abstract.cpp \
+ src/settings++/Defs.hpp src/settings++/tab_simple.cpp \
+ src/settings++/tab_quality_video.cpp src/settings++/tab_ui.h \
+ src/settings++/tab_simple.h src/images/springsettings.xpm \
+ src/settings++/tab_render_detail.h \
+ src/settings++/tab_abstract.h \
+ src/settings++/panel_pathoption.h \
+ src/settings++/panel_pathoption.cpp \
+ src/settings++/custom_dialogs.h \
+ src/settings++/custom_dialogs.cpp \
+ src/settings++/helpmenufunctions.h \
+ src/settings++/helpmenufunctions.cpp
+am__dirstamp = $(am__leading_dot)dirstamp
+ at USE_WINDRES_TRUE@am__objects_1 = src/springlobby.$(OBJEXT) \
+ at USE_WINDRES_TRUE@ listctrl.$(OBJEXT)
+am__objects_2 =
+am__objects_3 = entry.$(OBJEXT) escape_string.$(OBJEXT) \
+ assert.$(OBJEXT) enum_net.$(OBJEXT) broadcast_socket.$(OBJEXT) \
+ peer_connection.$(OBJEXT) bt_peer_connection.$(OBJEXT) \
+ web_peer_connection.$(OBJEXT) natpmp.$(OBJEXT) \
+ piece_picker.$(OBJEXT) policy.$(OBJEXT) session.$(OBJEXT) \
+ session_impl.$(OBJEXT) sha1.$(OBJEXT) stat.$(OBJEXT) \
+ storage.$(OBJEXT) torrent.$(OBJEXT) torrent_handle.$(OBJEXT) \
+ pe_crypto.$(OBJEXT) torrent_info.$(OBJEXT) \
+ tracker_manager.$(OBJEXT) http_connection.$(OBJEXT) \
+ http_tracker_connection.$(OBJEXT) \
+ udp_tracker_connection.$(OBJEXT) alert.$(OBJEXT) \
+ identify_client.$(OBJEXT) ip_filter.$(OBJEXT) file.$(OBJEXT) \
+ metadata_transfer.$(OBJEXT) logger.$(OBJEXT) \
+ file_pool.$(OBJEXT) ut_pex.$(OBJEXT) lsd.$(OBJEXT) \
+ upnp.$(OBJEXT) instantiate_connection.$(OBJEXT) \
+ socks5_stream.$(OBJEXT) socks4_stream.$(OBJEXT) \
+ http_stream.$(OBJEXT) connection_queue.$(OBJEXT) \
+ disk_io_thread.$(OBJEXT) closest_nodes.$(OBJEXT) \
+ dht_tracker.$(OBJEXT) find_data.$(OBJEXT) node.$(OBJEXT) \
+ node_id.$(OBJEXT) refresh.$(OBJEXT) routing_table.$(OBJEXT) \
+ rpc_manager.$(OBJEXT) traversal_algorithm.$(OBJEXT) \
+ adler32.$(OBJEXT) compress.$(OBJEXT) crc32.$(OBJEXT) \
+ deflate.$(OBJEXT) gzio.$(OBJEXT) infback.$(OBJEXT) \
+ inffast.$(OBJEXT) inflate.$(OBJEXT) inftrees.$(OBJEXT) \
+ trees.$(OBJEXT) uncompr.$(OBJEXT) zutil.$(OBJEXT)
+ at USE_LIBT_INCLUDED_TRUE@am__objects_4 = $(am__objects_2) \
+ at USE_LIBT_INCLUDED_TRUE@ $(am__objects_3)
+am_springlobby_OBJECTS = md5.$(OBJEXT) slbook.$(OBJEXT) math.$(OBJEXT) \
+ misc.$(OBJEXT) debug.$(OBJEXT) platform.$(OBJEXT) \
+ conversion.$(OBJEXT) tasutil.$(OBJEXT) sltipwin.$(OBJEXT) \
+ controls.$(OBJEXT) versionchecker.$(OBJEXT) \
+ springunitsynclib.$(OBJEXT) unitsyncthread.$(OBJEXT) \
+ mapgridctrl.$(OBJEXT) mapselectdialog.$(OBJEXT) \
+ chatlog.$(OBJEXT) ibattle.$(OBJEXT) addbotdialog.$(OBJEXT) \
+ agreementdialog.$(OBJEXT) autohost.$(OBJEXT) base64.$(OBJEXT) \
+ battle.$(OBJEXT) maintorrenttab.$(OBJEXT) \
+ battlelistctrl.$(OBJEXT) battlelistfilter.$(OBJEXT) \
+ battlelist.$(OBJEXT) battlelisttab.$(OBJEXT) \
+ battleroomlistctrl.$(OBJEXT) battlemaptab.$(OBJEXT) \
+ battleoptionstab.$(OBJEXT) battleroomtab.$(OBJEXT) \
+ crc.$(OBJEXT) channel.$(OBJEXT) channellist.$(OBJEXT) \
+ channellistctrl.$(OBJEXT) chatoptionstab.$(OBJEXT) \
+ chatpanel.$(OBJEXT) connectwindow.$(OBJEXT) \
+ crashreport.$(OBJEXT) countrycodes.$(OBJEXT) \
+ flagimages.$(OBJEXT) hostbattledialog.$(OBJEXT) \
+ iconimagelist.$(OBJEXT) mainchattab.$(OBJEXT) \
+ mainjoinbattletab.$(OBJEXT) mainoptionstab.$(OBJEXT) \
+ mainsingleplayertab.$(OBJEXT) mainwindow.$(OBJEXT) \
+ mapctrl.$(OBJEXT) offlinebattle.$(OBJEXT) \
+ nicklistctrl.$(OBJEXT) replaylist.$(OBJEXT) sdlsound.$(OBJEXT) \
+ server.$(OBJEXT) serverevents.$(OBJEXT) settings.$(OBJEXT) \
+ socket.$(OBJEXT) spring.$(OBJEXT) singleplayerbattle.$(OBJEXT) \
+ singleplayertab.$(OBJEXT) springlobbyapp.$(OBJEXT) \
+ springoptionstab.$(OBJEXT) springprocess.$(OBJEXT) \
+ springunitsync.$(OBJEXT) tasserver.$(OBJEXT) ui.$(OBJEXT) \
+ uiutils.$(OBJEXT) user.$(OBJEXT) userlist.$(OBJEXT) \
+ userlistctrl.$(OBJEXT) torrentlistctrl.$(OBJEXT) \
+ torrentoptionspanel.$(OBJEXT) customlistctrl.$(OBJEXT) \
+ mmoptionmodel.$(OBJEXT) mmoptionswrapper.$(OBJEXT) \
+ torrentwrapper.$(OBJEXT) spinctld.$(OBJEXT) \
+ autobalancedialog.$(OBJEXT) tdfcontainer.$(OBJEXT) \
+ globalevents.$(OBJEXT) TextCompletionDatabase.$(OBJEXT) \
+ wxTranslationHelper.$(OBJEXT) tasclientimport.$(OBJEXT) \
+ slhtmlwindow.$(OBJEXT) channelchooser.$(OBJEXT) \
+ channelchooserdialog.$(OBJEXT) colorbutton.$(OBJEXT) \
+ wxtextctrlhist.$(OBJEXT) imageviewer.$(OBJEXT) \
+ filelistctrl.$(OBJEXT) filelistdialog.$(OBJEXT) \
+ filelistfilter.$(OBJEXT) autojoinchanneldialog.$(OBJEXT) \
+ useractions.$(OBJEXT) selectusersdialog.$(OBJEXT) \
+ groupoptionspanel.$(OBJEXT) lobbyoptionstab.$(OBJEXT) \
+ auimanager.$(OBJEXT) artprovider.$(OBJEXT) updater.$(OBJEXT) \
+ downloadlistctrl.$(OBJEXT) downloaddialog.$(OBJEXT) \
+ downloadpanel.$(OBJEXT) infopanel.$(OBJEXT) widget.$(OBJEXT) \
+ thread.$(OBJEXT) globalsmanager.$(OBJEXT) \
+ mmoptionwindows.$(OBJEXT) savegamelist.$(OBJEXT) \
+ $(am__objects_1) $(am__objects_4) se_utils.$(OBJEXT) \
+ frame.$(OBJEXT) tab_ui.$(OBJEXT) tab_render_detail.$(OBJEXT) \
+ tab_audio.$(OBJEXT) tab_abstract.$(OBJEXT) \
+ tab_simple.$(OBJEXT) tab_quality_video.$(OBJEXT) \
+ panel_pathoption.$(OBJEXT) custom_dialogs.$(OBJEXT) \
+ helpmenufunctions.$(OBJEXT)
+springlobby_OBJECTS = $(am_springlobby_OBJECTS)
+am__DEPENDENCIES_1 =
+springlobby_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am__springsettings_SOURCES_DIST = src/utils/debug.cpp \
+ src/utils/debug.h src/utils/platform.cpp src/utils/platform.h \
+ src/utils/conversion.cpp src/utils/conversion.h \
+ src/utils/sltipwin.cpp src/utils/sltipwin.h \
+ src/utils/controls.cpp src/utils/controls.h \
+ src/crashreport.cpp src/crashreport.h src/spinctld.h \
+ src/spinctld.cpp src/springunitsynclib.cpp \
+ src/springunitsynclib.h src/springunitsync.cpp \
+ src/springunitsync.h src/thread.cpp src/thread.h \
+ src/settings.cpp src/settings.h src/uiutils.cpp src/uiutils.h \
+ src/mmoptionmodel.h src/mmoptionmodel.cpp \
+ src/globalsmanager.cpp src/settings++/se_utils.cpp \
+ src/settings++/se_utils.h src/settings++/frame.cpp \
+ src/settings++/main.h src/settings++/tab_ui.cpp \
+ src/settings++/tab_render_detail.cpp \
+ src/settings++/tab_quality_video.h src/settings++/frame.h \
+ src/settings++/tab_audio.h src/settings++/tab_audio.cpp \
+ src/settings++/presets.h src/settings++/tab_abstract.cpp \
+ src/settings++/Main.cpp src/settings++/Defs.hpp \
+ src/settings++/tab_simple.cpp \
+ src/settings++/tab_quality_video.cpp src/settings++/tab_ui.h \
+ src/settings++/tab_simple.h src/images/springsettings.xpm \
+ src/settings++/tab_render_detail.h \
+ src/settings++/tab_abstract.h \
+ src/settings++/panel_pathoption.h \
+ src/settings++/panel_pathoption.cpp \
+ src/settings++/custom_dialogs.h \
+ src/settings++/custom_dialogs.cpp \
+ src/settings++/helpmenufunctions.h \
+ src/settings++/helpmenufunctions.cpp \
+ src/settings++/settings.rc
+ at USE_WINDRES_TRUE@am__objects_5 = src/settings++/settings.$(OBJEXT)
+am_springsettings_OBJECTS = debug.$(OBJEXT) platform.$(OBJEXT) \
+ conversion.$(OBJEXT) sltipwin.$(OBJEXT) controls.$(OBJEXT) \
+ crashreport.$(OBJEXT) spinctld.$(OBJEXT) \
+ springunitsynclib.$(OBJEXT) springunitsync.$(OBJEXT) \
+ thread.$(OBJEXT) settings.$(OBJEXT) uiutils.$(OBJEXT) \
+ mmoptionmodel.$(OBJEXT) globalsmanager.$(OBJEXT) \
+ se_utils.$(OBJEXT) frame.$(OBJEXT) tab_ui.$(OBJEXT) \
+ tab_render_detail.$(OBJEXT) tab_audio.$(OBJEXT) \
+ tab_abstract.$(OBJEXT) Main.$(OBJEXT) tab_simple.$(OBJEXT) \
+ tab_quality_video.$(OBJEXT) panel_pathoption.$(OBJEXT) \
+ custom_dialogs.$(OBJEXT) helpmenufunctions.$(OBJEXT) \
+ $(am__objects_5)
+springsettings_OBJECTS = $(am_springsettings_OBJECTS)
+springsettings_DEPENDENCIES = $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. at am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/autotools-aux/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+SOURCES = $(springlobby_SOURCES) $(springsettings_SOURCES)
+DIST_SOURCES = $(am__springlobby_SOURCES_DIST) \
+ $(am__springsettings_SOURCES_DIST)
+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 = `echo $$p | sed -e 's|^.*/||'`;
+dist_desktopDATA_INSTALL = $(INSTALL_DATA)
+dist_docDATA_INSTALL = $(INSTALL_DATA)
+dist_pixmapDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(dist_desktop_DATA) $(dist_doc_DATA) $(dist_pixmap_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+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); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+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@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTORRENT_CFLAGS = @LIBTORRENT_CFLAGS@
+LIBTORRENT_LIBS = @LIBTORRENT_LIBS@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+WX_CFLAGS = @WX_CFLAGS@
+WX_CFLAGS_ONLY = @WX_CFLAGS_ONLY@
+WX_CONFIG_PATH = @WX_CONFIG_PATH@
+WX_CPPFLAGS = @WX_CPPFLAGS@
+WX_CXXFLAGS = @WX_CXXFLAGS@
+WX_CXXFLAGS_ONLY = @WX_CXXFLAGS_ONLY@
+WX_LIBS = @WX_LIBS@
+WX_LIBS_STATIC = @WX_LIBS_STATIC@
+WX_VERSION = @WX_VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+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@
+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_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@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I m4 --install
+libt_dir = $(srcdir)/src/libtorrent
+libt_src_dir = $(libt_dir)/src
+SEARCHDIRS = -I$(srcdir)/src $(am__append_1)
+AM_CPPFLAGS = \
+ $(WX_CPPFLAGS) \
+ $(LIBTORRENT_CFLAGS) \
+ $(SDL_CFLAGS) \
+ -DLOCALEDIR=\"$(localedir)\" \
+ $(SEARCHDIRS)
+
+
+# strict aliasing check is disabled, because wxWidgets headers have problems
+AM_CXXFLAGS = \
+ -Wall \
+ -Wno-strict-aliasing
+
+desktopdir = $(datadir)/applications
+dist_desktop_DATA = \
+ src/springlobby.desktop
+
+pixmapdir = $(datadir)/pixmaps
+dist_pixmap_DATA = \
+ src/images/springlobby.svg
+
+SUBDIRS = po
+dist_doc_DATA = \
+ AUTHORS \
+ ChangeLog \
+ COPYING \
+ INSTALL \
+ NEWS \
+ README \
+ THANKS
+
+springlobby_LDADD = \
+ $(WX_LIBS)\
+ $(LIBTORRENT_LIBS) \
+ $(SDL_LIBS)
+
+
+#put template source files here (those need to be present in tarball, but not compiled)
+EXTRA_DIST = \
+ src/battleroommmoptionstab.cpp \
+ src/customvirtlistctrl.cpp \
+ src/playback/playbacktab.cpp \
+ src/playback/playbackfilter.cpp \
+ src/playback/playbackthread.cpp \
+ src/playback/playbacklistctrl.cpp \
+ src/playback/playbacktraits.h \
+ src/playback/playbackstructs.h \
+ src/playback/playbacklist.h \
+ src/playback/playbacklist.cpp \
+ src/httpdownloader.cpp \
+ CMakeLists.txt
+
+springsettings_LDADD = \
+ $(WX_LIBS)
+
+ at USE_WINDRES_TRUE@RESOURCECOMPILE = $(WINDRES) -I $(srcdir)/src $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ at USE_WINDRES_TRUE@ $(AM_CPPFLAGS) $(CPPFLAGS) # $(AM_CXXFLAGS) $(CXXFLAGS)
+
+libtorrent_sources = \
+ $(libt_src_dir)/entry.cpp \
+ $(libt_src_dir)/escape_string.cpp \
+ $(libt_src_dir)/assert.cpp \
+ $(libt_src_dir)/enum_net.cpp \
+ $(libt_src_dir)/broadcast_socket.cpp \
+ $(libt_src_dir)/peer_connection.cpp \
+ $(libt_src_dir)/bt_peer_connection.cpp \
+ $(libt_src_dir)/web_peer_connection.cpp \
+ $(libt_src_dir)/natpmp.cpp \
+ $(libt_src_dir)/piece_picker.cpp \
+ $(libt_src_dir)/policy.cpp \
+ $(libt_src_dir)/session.cpp \
+ $(libt_src_dir)/session_impl.cpp \
+ $(libt_src_dir)/sha1.cpp \
+ $(libt_src_dir)/stat.cpp \
+ $(libt_src_dir)/storage.cpp \
+ $(libt_src_dir)/torrent.cpp \
+ $(libt_src_dir)/torrent_handle.cpp \
+ $(libt_src_dir)/pe_crypto.cpp \
+ $(libt_src_dir)/torrent_info.cpp \
+ $(libt_src_dir)/tracker_manager.cpp \
+ $(libt_src_dir)/http_connection.cpp \
+ $(libt_src_dir)/http_tracker_connection.cpp \
+ $(libt_src_dir)/udp_tracker_connection.cpp \
+ $(libt_src_dir)/alert.cpp \
+ $(libt_src_dir)/identify_client.cpp \
+ $(libt_src_dir)/ip_filter.cpp \
+ $(libt_src_dir)/file.cpp \
+ $(libt_src_dir)/metadata_transfer.cpp \
+ $(libt_src_dir)/logger.cpp \
+ $(libt_src_dir)/file_pool.cpp \
+ $(libt_src_dir)/ut_pex.cpp \
+ $(libt_src_dir)/lsd.cpp \
+ $(libt_src_dir)/upnp.cpp \
+ $(libt_src_dir)/instantiate_connection.cpp \
+ $(libt_src_dir)/socks5_stream.cpp \
+ $(libt_src_dir)/socks4_stream.cpp \
+ $(libt_src_dir)/http_stream.cpp \
+ $(libt_src_dir)/connection_queue.cpp \
+ $(libt_src_dir)/disk_io_thread.cpp \
+ \
+ $(libt_src_dir)/kademlia/closest_nodes.cpp \
+ $(libt_src_dir)/kademlia/dht_tracker.cpp \
+ $(libt_src_dir)/kademlia/find_data.cpp \
+ $(libt_src_dir)/kademlia/node.cpp \
+ $(libt_src_dir)/kademlia/node_id.cpp \
+ $(libt_src_dir)/kademlia/refresh.cpp \
+ $(libt_src_dir)/kademlia/routing_table.cpp \
+ $(libt_src_dir)/kademlia/rpc_manager.cpp \
+ $(libt_src_dir)/kademlia/traversal_algorithm.cpp \
+ \
+ $(libt_dir)/zlib/adler32.c \
+ $(libt_dir)/zlib/compress.c \
+ $(libt_dir)/zlib/crc32.c \
+ $(libt_dir)/zlib/deflate.c \
+ $(libt_dir)/zlib/gzio.c \
+ $(libt_dir)/zlib/infback.c \
+ $(libt_dir)/zlib/inffast.c \
+ $(libt_dir)/zlib/inflate.c \
+ $(libt_dir)/zlib/inftrees.c \
+ $(libt_dir)/zlib/trees.c \
+ $(libt_dir)/zlib/uncompr.c \
+ $(libt_dir)/zlib/zutil.c
+
+libtorrent_headers = \
+ $(libt_dir)/include/libtorrent/alert.hpp \
+ $(libt_dir)/include/libtorrent/alert_types.hpp \
+ $(libt_dir)/include/libtorrent/assert.hpp \
+ $(libt_dir)/include/libtorrent/aux_/session_impl.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_manager.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_limit.hpp \
+ $(libt_dir)/include/libtorrent/bandwidth_queue_entry.hpp \
+ $(libt_dir)/include/libtorrent/bencode.hpp \
+ $(libt_dir)/include/libtorrent/broadcast_socket.hpp \
+ $(libt_dir)/include/libtorrent/buffer.hpp \
+ $(libt_dir)/include/libtorrent/connection_queue.hpp \
+ $(libt_dir)/include/libtorrent/debug.hpp \
+ $(libt_dir)/include/libtorrent/disk_io_thread.hpp \
+ $(libt_dir)/include/libtorrent/entry.hpp \
+ $(libt_dir)/include/libtorrent/enum_net.hpp \
+ $(libt_dir)/include/libtorrent/escape_string.hpp \
+ $(libt_dir)/include/libtorrent/extensions.hpp \
+ $(libt_dir)/include/libtorrent/extensions/metadata_transfer.hpp \
+ $(libt_dir)/include/libtorrent/extensions/logger.hpp \
+ $(libt_dir)/include/libtorrent/extensions/ut_pex.hpp \
+ $(libt_dir)/include/libtorrent/file.hpp \
+ $(libt_dir)/include/libtorrent/file_pool.hpp \
+ $(libt_dir)/include/libtorrent/fingerprint.hpp \
+ $(libt_dir)/include/libtorrent/hasher.hpp \
+ $(libt_dir)/include/libtorrent/http_connection.hpp \
+ $(libt_dir)/include/libtorrent/http_stream.hpp \
+ $(libt_dir)/include/libtorrent/session_settings.hpp \
+ $(libt_dir)/include/libtorrent/http_tracker_connection.hpp \
+ $(libt_dir)/include/libtorrent/identify_client.hpp \
+ $(libt_dir)/include/libtorrent/instantiate_connection.hpp \
+ $(libt_dir)/include/libtorrent/intrusive_ptr_base.hpp \
+ $(libt_dir)/include/libtorrent/invariant_check.hpp \
+ $(libt_dir)/include/libtorrent/io.hpp \
+ $(libt_dir)/include/libtorrent/ip_filter.hpp \
+ $(libt_dir)/include/libtorrent/chained_buffer.hpp \
+ $(libt_dir)/include/libtorrent/lsd.hpp \
+ $(libt_dir)/include/libtorrent/peer.hpp \
+ $(libt_dir)/include/libtorrent/peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/bt_peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/web_peer_connection.hpp \
+ $(libt_dir)/include/libtorrent/pe_crypto.hpp \
+ $(libt_dir)/include/libtorrent/natpmp.hpp \
+ $(libt_dir)/include/libtorrent/pch.hpp \
+ $(libt_dir)/include/libtorrent/peer_id.hpp \
+ $(libt_dir)/include/libtorrent/peer_info.hpp \
+ $(libt_dir)/include/libtorrent/peer_request.hpp \
+ $(libt_dir)/include/libtorrent/piece_block_progress.hpp \
+ $(libt_dir)/include/libtorrent/piece_picker.hpp \
+ $(libt_dir)/include/libtorrent/policy.hpp \
+ $(libt_dir)/include/libtorrent/session.hpp \
+ $(libt_dir)/include/libtorrent/size_type.hpp \
+ $(libt_dir)/include/libtorrent/socket.hpp \
+ $(libt_dir)/include/libtorrent/socket_type.hpp \
+ $(libt_dir)/include/libtorrent/socks4_stream.hpp \
+ $(libt_dir)/include/libtorrent/socks5_stream.hpp \
+ $(libt_dir)/include/libtorrent/stat.hpp \
+ $(libt_dir)/include/libtorrent/storage.hpp \
+ $(libt_dir)/include/libtorrent/time.hpp \
+ $(libt_dir)/include/libtorrent/torrent.hpp \
+ $(libt_dir)/include/libtorrent/torrent_handle.hpp \
+ $(libt_dir)/include/libtorrent/torrent_info.hpp \
+ $(libt_dir)/include/libtorrent/tracker_manager.hpp \
+ $(libt_dir)/include/libtorrent/udp_tracker_connection.hpp \
+ $(libt_dir)/include/libtorrent/utf8.hpp \
+ $(libt_dir)/include/libtorrent/xml_parse.hpp \
+ $(libt_dir)/include/libtorrent/variant_stream.hpp \
+ $(libt_dir)/include/libtorrent/version.hpp \
+ \
+ $(libt_dir)/include/libtorrent/kademlia/closest_nodes.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/dht_tracker.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/find_data.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/logging.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/msg.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node_entry.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/node_id.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/observer.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/packet_iterator.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/refresh.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/routing_table.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/rpc_manager.hpp \
+ $(libt_dir)/include/libtorrent/kademlia/traversal_algorithm.hpp \
+ \
+ $(libt_dir)/asio.hpp \
+ $(libt_dir)/asio/basic_datagram_socket.hpp \
+ $(libt_dir)/asio/basic_deadline_timer.hpp \
+ $(libt_dir)/asio/basic_io_object.hpp \
+ $(libt_dir)/asio/basic_socket.hpp \
+ $(libt_dir)/asio/basic_socket_acceptor.hpp \
+ $(libt_dir)/asio/basic_socket_iostream.hpp \
+ $(libt_dir)/asio/basic_socket_streambuf.hpp \
+ $(libt_dir)/asio/basic_stream_socket.hpp \
+ $(libt_dir)/asio/basic_streambuf.hpp \
+ $(libt_dir)/asio/buffer.hpp \
+ $(libt_dir)/asio/buffered_read_stream.hpp \
+ $(libt_dir)/asio/buffered_read_stream_fwd.hpp \
+ $(libt_dir)/asio/buffered_stream.hpp \
+ $(libt_dir)/asio/buffered_stream_fwd.hpp \
+ $(libt_dir)/asio/buffered_write_stream.hpp \
+ $(libt_dir)/asio/buffered_write_stream_fwd.hpp \
+ $(libt_dir)/asio/completion_condition.hpp \
+ $(libt_dir)/asio/datagram_socket_service.hpp \
+ $(libt_dir)/asio/deadline_timer.hpp \
+ $(libt_dir)/asio/deadline_timer_service.hpp \
+ $(libt_dir)/asio/error.hpp \
+ $(libt_dir)/asio/error_code.hpp \
+ $(libt_dir)/asio/handler_alloc_hook.hpp \
+ $(libt_dir)/asio/handler_invoke_hook.hpp \
+ $(libt_dir)/asio/io_service.hpp \
+ $(libt_dir)/asio/is_read_buffered.hpp \
+ $(libt_dir)/asio/is_write_buffered.hpp \
+ $(libt_dir)/asio/placeholders.hpp \
+ $(libt_dir)/asio/read.hpp \
+ $(libt_dir)/asio/read_until.hpp \
+ $(libt_dir)/asio/socket_acceptor_service.hpp \
+ $(libt_dir)/asio/socket_base.hpp \
+ $(libt_dir)/asio/ssl.hpp \
+ $(libt_dir)/asio/strand.hpp \
+ $(libt_dir)/asio/stream_socket_service.hpp \
+ $(libt_dir)/asio/streambuf.hpp \
+ $(libt_dir)/asio/system_error.hpp \
+ $(libt_dir)/asio/thread.hpp \
+ $(libt_dir)/asio/time_traits.hpp \
+ $(libt_dir)/asio/version.hpp \
+ $(libt_dir)/asio/write.hpp \
+ $(libt_dir)/asio/detail/bind_handler.hpp \
+ $(libt_dir)/asio/detail/buffer_resize_guard.hpp \
+ $(libt_dir)/asio/detail/buffered_stream_storage.hpp \
+ $(libt_dir)/asio/detail/call_stack.hpp \
+ $(libt_dir)/asio/detail/const_buffers_iterator.hpp \
+ $(libt_dir)/asio/detail/consuming_buffers.hpp \
+ $(libt_dir)/asio/detail/deadline_timer_service.hpp \
+ $(libt_dir)/asio/detail/dev_poll_reactor.hpp \
+ $(libt_dir)/asio/detail/dev_poll_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/epoll_reactor.hpp \
+ $(libt_dir)/asio/detail/epoll_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/event.hpp \
+ $(libt_dir)/asio/detail/fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/handler_alloc_helpers.hpp \
+ $(libt_dir)/asio/detail/handler_invoke_helpers.hpp \
+ $(libt_dir)/asio/detail/handler_queue.hpp \
+ $(libt_dir)/asio/detail/hash_map.hpp \
+ $(libt_dir)/asio/detail/io_control.hpp \
+ $(libt_dir)/asio/detail/kqueue_reactor.hpp \
+ $(libt_dir)/asio/detail/kqueue_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/local_free_on_block_exit.hpp \
+ $(libt_dir)/asio/detail/mutex.hpp \
+ $(libt_dir)/asio/detail/noncopyable.hpp \
+ $(libt_dir)/asio/detail/null_event.hpp \
+ $(libt_dir)/asio/detail/null_mutex.hpp \
+ $(libt_dir)/asio/detail/null_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/null_thread.hpp \
+ $(libt_dir)/asio/detail/null_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/old_win_sdk_compat.hpp \
+ $(libt_dir)/asio/detail/pipe_select_interrupter.hpp \
+ $(libt_dir)/asio/detail/pop_options.hpp \
+ $(libt_dir)/asio/detail/posix_event.hpp \
+ $(libt_dir)/asio/detail/posix_fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/posix_mutex.hpp \
+ $(libt_dir)/asio/detail/posix_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/posix_thread.hpp \
+ $(libt_dir)/asio/detail/posix_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/push_options.hpp \
+ $(libt_dir)/asio/detail/reactive_socket_service.hpp \
+ $(libt_dir)/asio/detail/reactor_op_queue.hpp \
+ $(libt_dir)/asio/detail/resolver_service.hpp \
+ $(libt_dir)/asio/detail/scoped_lock.hpp \
+ $(libt_dir)/asio/detail/select_interrupter.hpp \
+ $(libt_dir)/asio/detail/select_reactor.hpp \
+ $(libt_dir)/asio/detail/select_reactor_fwd.hpp \
+ $(libt_dir)/asio/detail/service_base.hpp \
+ $(libt_dir)/asio/detail/service_id.hpp \
+ $(libt_dir)/asio/detail/service_registry.hpp \
+ $(libt_dir)/asio/detail/service_registry_fwd.hpp \
+ $(libt_dir)/asio/detail/signal_blocker.hpp \
+ $(libt_dir)/asio/detail/signal_init.hpp \
+ $(libt_dir)/asio/detail/socket_holder.hpp \
+ $(libt_dir)/asio/detail/socket_ops.hpp \
+ $(libt_dir)/asio/detail/socket_option.hpp \
+ $(libt_dir)/asio/detail/socket_select_interrupter.hpp \
+ $(libt_dir)/asio/detail/socket_types.hpp \
+ $(libt_dir)/asio/detail/strand_service.hpp \
+ $(libt_dir)/asio/detail/task_io_service.hpp \
+ $(libt_dir)/asio/detail/task_io_service_fwd.hpp \
+ $(libt_dir)/asio/detail/thread.hpp \
+ $(libt_dir)/asio/detail/throw_error.hpp \
+ $(libt_dir)/asio/detail/timer_queue.hpp \
+ $(libt_dir)/asio/detail/timer_queue_base.hpp \
+ $(libt_dir)/asio/detail/tss_ptr.hpp \
+ $(libt_dir)/asio/detail/win_event.hpp \
+ $(libt_dir)/asio/detail/win_fd_set_adapter.hpp \
+ $(libt_dir)/asio/detail/win_iocp_io_service.hpp \
+ $(libt_dir)/asio/detail/win_iocp_io_service_fwd.hpp \
+ $(libt_dir)/asio/detail/win_iocp_socket_service.hpp \
+ $(libt_dir)/asio/detail/win_mutex.hpp \
+ $(libt_dir)/asio/detail/win_signal_blocker.hpp \
+ $(libt_dir)/asio/detail/win_thread.hpp \
+ $(libt_dir)/asio/detail/win_tss_ptr.hpp \
+ $(libt_dir)/asio/detail/wince_thread.hpp \
+ $(libt_dir)/asio/detail/winsock_init.hpp \
+ $(libt_dir)/asio/detail/wrapped_handler.hpp \
+ $(libt_dir)/asio/impl/error_code.ipp \
+ $(libt_dir)/asio/impl/io_service.ipp \
+ $(libt_dir)/asio/impl/read.ipp \
+ $(libt_dir)/asio/impl/read_until.ipp \
+ $(libt_dir)/asio/impl/write.ipp \
+ $(libt_dir)/asio/ip/address.hpp \
+ $(libt_dir)/asio/ip/address_v4.hpp \
+ $(libt_dir)/asio/ip/address_v6.hpp \
+ $(libt_dir)/asio/ip/basic_endpoint.hpp \
+ $(libt_dir)/asio/ip/basic_resolver.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_entry.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_iterator.hpp \
+ $(libt_dir)/asio/ip/basic_resolver_query.hpp \
+ $(libt_dir)/asio/ip/host_name.hpp \
+ $(libt_dir)/asio/ip/multicast.hpp \
+ $(libt_dir)/asio/ip/resolver_query_base.hpp \
+ $(libt_dir)/asio/ip/resolver_service.hpp \
+ $(libt_dir)/asio/ip/tcp.hpp \
+ $(libt_dir)/asio/ip/udp.hpp \
+ $(libt_dir)/asio/ip/unicast.hpp \
+ $(libt_dir)/asio/ip/v6_only.hpp \
+ $(libt_dir)/asio/ip/detail/socket_option.hpp \
+ $(libt_dir)/asio/ssl/basic_context.hpp \
+ $(libt_dir)/asio/ssl/context.hpp \
+ $(libt_dir)/asio/ssl/context_base.hpp \
+ $(libt_dir)/asio/ssl/context_service.hpp \
+ $(libt_dir)/asio/ssl/stream.hpp \
+ $(libt_dir)/asio/ssl/stream_base.hpp \
+ $(libt_dir)/asio/ssl/stream_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_context_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_init.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_operation.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_stream_service.hpp \
+ $(libt_dir)/asio/ssl/detail/openssl_types.hpp \
+ \
+ $(libt_dir)/zlib/crc32.h \
+ $(libt_dir)/zlib/deflate.h \
+ $(libt_dir)/zlib/inffast.h \
+ $(libt_dir)/zlib/inflate.h \
+ $(libt_dir)/zlib/inftrees.h \
+ $(libt_dir)/zlib/trees.h \
+ $(libt_dir)/zlib/zconf.h \
+ $(libt_dir)/zlib/zlib.h \
+ $(libt_dir)/zlib/zutil.h
+
+
+# TODO keep only a single list instead of duplicating the lists below
+# note, integrated has everything but main.cpp
+springlobby_SOURCES = src/utils/md5.h src/utils/md5.c \
+ src/aui/slbook.cpp src/aui/slbook.h src/utils/math.cpp \
+ src/utils/math.h src/utils/misc.cpp src/utils/misc.h \
+ src/utils/debug.cpp src/utils/debug.h src/utils/platform.cpp \
+ src/utils/platform.h src/utils/conversion.cpp \
+ src/utils/conversion.h src/utils/tasutil.cpp \
+ src/utils/tasutil.h src/utils/sltipwin.cpp \
+ src/utils/sltipwin.h src/utils/controls.cpp \
+ src/utils/controls.h src/updater/versionchecker.cpp \
+ src/updater/versionchecker.h src/sounds/ring_sound.h \
+ src/sounds/pm_sound.h src/springunitsynclib.cpp \
+ src/springunitsynclib.h src/unitsyncthread.cpp \
+ src/unitsyncthread.h src/mapgridctrl.cpp src/mapgridctrl.h \
+ src/mapselectdialog.cpp src/mapselectdialog.h src/bimap.h \
+ src/chatlog.h src/chatlog.cpp src/images/broom.png.h \
+ src/images/bot_ingame.png.h src/images/bot_broom.png.h \
+ src/images/channel_options.xpm src/images/chanop_ingame.xpm \
+ src/images/chanop_away.xpm src/images/chanop_broom.xpm \
+ src/images/chanop.xpm src/images/admin_broom.png.h \
+ src/images/host_spectator.xpm src/images/host.xpm \
+ src/images/not_found_icon.xpm src/images/reload_map.xpm \
+ src/images/download_map.xpm src/images/up_downsel.xpm \
+ src/images/upsel_down.xpm src/images/up_down.xpm \
+ src/images/player.xpm src/ibattle.cpp src/ibattle.h \
+ src/nonportable.h src/addbotdialog.cpp src/addbotdialog.h \
+ src/agreementdialog.cpp src/agreementdialog.h src/autohost.cpp \
+ src/autohost.h src/base64.cpp src/base64.h src/battle.cpp \
+ src/battle.h src/maintorrenttab.cpp src/maintorrenttab.h \
+ src/battlelistctrl.cpp src/battlelistctrl.h \
+ src/battlelistfilter.cpp src/battlelistfilter.h \
+ src/battlelistfiltervalues.h src/battlelist.cpp \
+ src/battlelist.h src/battlelisttab.cpp src/battlelisttab.h \
+ src/battleroomlistctrl.cpp src/battleroomlistctrl.h \
+ src/battlemaptab.cpp src/battlemaptab.h \
+ src/battleoptionstab.cpp src/battleoptionstab.h \
+ src/battleroomtab.cpp src/battleroomtab.h src/crc.cpp \
+ src/crc.h src/channel/channel.cpp src/channel/channel.h \
+ src/channel/channellist.cpp src/channel/channellist.h \
+ src/channel/channellistctrl.cpp src/channel/channellistctrl.h \
+ src/chatoptionstab.cpp src/chatoptionstab.h src/chatpanel.cpp \
+ src/chatpanel.h src/connectwindow.cpp src/connectwindow.h \
+ src/crashreport.cpp src/crashreport.h src/countrycodes.cpp \
+ src/countrycodes.h src/flagimagedata.h src/flagimages.cpp \
+ src/flagimages.h src/hostbattledialog.h \
+ src/hostbattledialog.cpp src/iconimagelist.cpp \
+ src/iconimagelist.h src/inetclass.h src/iunitsync.h \
+ src/mainchattab.cpp src/mainchattab.h \
+ src/mainjoinbattletab.cpp src/mainjoinbattletab.h \
+ src/mainoptionstab.cpp src/mainoptionstab.h \
+ src/mainsingleplayertab.cpp src/mainsingleplayertab.h \
+ src/mainwindow.cpp src/mainwindow.h src/mapctrl.cpp \
+ src/mapctrl.h src/mutexwrapper.h src/offlinebattle.h \
+ src/offlinebattle.cpp src/nicklistctrl.cpp src/nicklistctrl.h \
+ src/playback/playbacktab.h src/playback/playbackthread.h \
+ src/playback/playbackfilter.h src/playback/replaylist.h \
+ src/playback/replaylist.cpp src/playback/playbacklistctrl.h \
+ src/playback/playbackfiltervalues.h src/sdlsound.h \
+ src/sdlsound.cpp src/server.cpp src/serverevents.cpp \
+ src/serverevents.h src/server.h src/settings.cpp \
+ src/settings.h src/socket.cpp src/socket.h src/spring.cpp \
+ src/spring.h src/singleplayerbattle.cpp \
+ src/singleplayerbattle.h src/singleplayertab.cpp \
+ src/singleplayertab.h src/springlobbyapp.cpp \
+ src/springlobbyapp.h src/springoptionstab.cpp \
+ src/springoptionstab.h src/springprocess.cpp \
+ src/springprocess.h src/springunitsync.cpp \
+ src/springunitsync.h src/tasserver.cpp src/tasserver.h \
+ src/tasservertokentable.h src/ui.cpp src/ui.h src/uiutils.cpp \
+ src/uiutils.h src/user.cpp src/user.h src/usermenu.h \
+ src/userlist.cpp src/userlist.h src/userlistctrl.cpp \
+ src/userlistctrl.h src/torrentlistctrl.cpp \
+ src/torrentlistctrl.h src/torrentoptionspanel.cpp \
+ src/torrentoptionspanel.h src/images/start_ally.xpm \
+ src/images/start_enemy.xpm src/images/start_unused.xpm \
+ src/images/admin_away.png.h src/images/admin_ingame.png.h \
+ src/images/admin.png.h src/images/no1_icon.png.h \
+ src/images/no2_icon.png.h src/images/away.png.h \
+ src/images/battle_list.xpm src/images/battle_map.xpm \
+ src/images/battle_settings.xpm src/images/battle.xpm \
+ src/images/bot.xpm src/images/bot_away.xpm \
+ src/images/channel.xpm src/images/chat_icon.png.h \
+ src/images/chat_icon_text.png.h src/images/closed_game.png.h \
+ src/images/closed_full_game.png.h \
+ src/images/closed_pw_game.png.h \
+ src/images/closed_full_pw_game.png.h \
+ src/images/torrentoptionspanel_icon.png.h \
+ src/images/close_hi.xpm src/images/close.xpm \
+ src/images/colourbox.xpm src/images/connect.xpm \
+ src/images/down.xpm src/images/exists.xpm \
+ src/images/fixcolours_palette.xpm src/images/ingame.png.h \
+ src/images/join_icon.png.h src/images/join_icon_text.png.h \
+ src/images/nexists.xpm src/images/nready_q.xpm \
+ src/images/nready_unsync.xpm src/images/open_game.png.h \
+ src/images/open_full_game.png.h src/images/open_pw_game.png.h \
+ src/images/open_full_pw_game.png.h \
+ src/images/options_icon.png.h \
+ src/images/options_icon_text.png.h \
+ src/images/arrow_refresh.png.h src/images/rank0.xpm \
+ src/images/rank1.xpm src/images/rank2.xpm src/images/rank3.xpm \
+ src/images/rank4.xpm src/images/rank5.xpm src/images/rank6.xpm \
+ src/images/rank_unknown.xpm src/images/ready_q.xpm \
+ src/images/ready_unsync.xpm src/images/downloads_icon.png.h \
+ src/images/single_player_icon.png.h \
+ src/images/downloads_icon_text.png.h \
+ src/images/warning_small.png.h src/images/spectator.png.h \
+ src/images/single_player_icon_text.png.h \
+ src/images/map_select_1.png.h src/images/map_select_2.png.h \
+ src/images/select_icon.xpm src/images/server.xpm \
+ src/images/spectator.xpm src/images/spring.xpm \
+ src/images/springlobby.xpm src/images/started_game.xpm \
+ src/images/unknown_flag.xpm src/images/up.xpm \
+ src/images/userchat.xpm src/images/flags/AD.xpm \
+ src/images/flags/AE.xpm src/images/flags/AF.xpm \
+ src/images/flags/AG.xpm src/images/flags/AI.xpm \
+ src/images/flags/AL.xpm src/images/flags/AM.xpm \
+ src/images/flags/AN.xpm src/images/flags/AO.xpm \
+ src/images/flags/AR.xpm src/images/flags/AS.xpm \
+ src/images/flags/AT.xpm src/images/flags/AU.xpm \
+ src/images/flags/AW.xpm src/images/flags/AX.xpm \
+ src/images/flags/AZ.xpm src/images/flags/BA.xpm \
+ src/images/flags/BB.xpm src/images/flags/BD.xpm \
+ src/images/flags/BE.xpm src/images/flags/BF.xpm \
+ src/images/flags/BG.xpm src/images/flags/BH.xpm \
+ src/images/flags/BI.xpm src/images/flags/BJ.xpm \
+ src/images/flags/BM.xpm src/images/flags/BN.xpm \
+ src/images/flags/BO.xpm src/images/flags/BR.xpm \
+ src/images/flags/BS.xpm src/images/flags/BT.xpm \
+ src/images/flags/BV.xpm src/images/flags/BW.xpm \
+ src/images/flags/BY.xpm src/images/flags/BZ.xpm \
+ src/images/flags/CA.xpm src/images/flags/CC.xpm \
+ src/images/flags/CD.xpm src/images/flags/CF.xpm \
+ src/images/flags/CG.xpm src/images/flags/CH.xpm \
+ src/images/flags/CI.xpm src/images/flags/CK.xpm \
+ src/images/flags/CL.xpm src/images/flags/CM.xpm \
+ src/images/flags/CN.xpm src/images/flags/CO.xpm \
+ src/images/flags/CR.xpm src/images/flags/CS.xpm \
+ src/images/flags/CU.xpm src/images/flags/CV.xpm \
+ src/images/flags/CX.xpm src/images/flags/CY.xpm \
+ src/images/flags/CZ.xpm src/images/flags/DE.xpm \
+ src/images/flags/DJ.xpm src/images/flags/DK.xpm \
+ src/images/flags/DM.xpm src/images/flags/DO.xpm \
+ src/images/flags/DZ.xpm src/images/flags/EC.xpm \
+ src/images/flags/EE.xpm src/images/flags/EG.xpm \
+ src/images/flags/EH.xpm src/images/flags/ER.xpm \
+ src/images/flags/ES.xpm src/images/flags/ET.xpm \
+ src/images/flags/FAM.xpm src/images/flags/FI.xpm \
+ src/images/flags/FJ.xpm src/images/flags/FK.xpm \
+ src/images/flags/FM.xpm src/images/flags/FO.xpm \
+ src/images/flags/FR.xpm src/images/flags/GA.xpm \
+ src/images/flags/GB.xpm src/images/flags/GD.xpm \
+ src/images/flags/GE.xpm src/images/flags/GF.xpm \
+ src/images/flags/GH.xpm src/images/flags/GI.xpm \
+ src/images/flags/GL.xpm src/images/flags/GM.xpm \
+ src/images/flags/GN.xpm src/images/flags/GP.xpm \
+ src/images/flags/GQ.xpm src/images/flags/GR.xpm \
+ src/images/flags/GS.xpm src/images/flags/GT.xpm \
+ src/images/flags/GU.xpm src/images/flags/GW.xpm \
+ src/images/flags/GY.xpm src/images/flags/HK.xpm \
+ src/images/flags/HM.xpm src/images/flags/HN.xpm \
+ src/images/flags/HR.xpm src/images/flags/HT.xpm \
+ src/images/flags/HU.xpm src/images/flags/ID.xpm \
+ src/images/flags/IE.xpm src/images/flags/IL.xpm \
+ src/images/flags/IN.xpm src/images/flags/IO.xpm \
+ src/images/flags/IQ.xpm src/images/flags/IR.xpm \
+ src/images/flags/IS.xpm src/images/flags/IT.xpm \
+ src/images/flags/JM.xpm src/images/flags/JO.xpm \
+ src/images/flags/JP.xpm src/images/flags/KE.xpm \
+ src/images/flags/KG.xpm src/images/flags/KH.xpm \
+ src/images/flags/KI.xpm src/images/flags/KM.xpm \
+ src/images/flags/KN.xpm src/images/flags/KP.xpm \
+ src/images/flags/KR.xpm src/images/flags/KW.xpm \
+ src/images/flags/KY.xpm src/images/flags/KZ.xpm \
+ src/images/flags/LA.xpm src/images/flags/LB.xpm \
+ src/images/flags/LC.xpm src/images/flags/LI.xpm \
+ src/images/flags/LK.xpm src/images/flags/LR.xpm \
+ src/images/flags/LS.xpm src/images/flags/LT.xpm \
+ src/images/flags/LU.xpm src/images/flags/LV.xpm \
+ src/images/flags/LY.xpm src/images/flags/MA.xpm \
+ src/images/flags/MC.xpm src/images/flags/MD.xpm \
+ src/images/flags/ME.xpm src/images/flags/MG.xpm \
+ src/images/flags/MH.xpm src/images/flags/MK.xpm \
+ src/images/flags/ML.xpm src/images/flags/MM.xpm \
+ src/images/flags/MN.xpm src/images/flags/MO.xpm \
+ src/images/flags/MP.xpm src/images/flags/MQ.xpm \
+ src/images/flags/MR.xpm src/images/flags/MS.xpm \
+ src/images/flags/MT.xpm src/images/flags/MU.xpm \
+ src/images/flags/MV.xpm src/images/flags/MW.xpm \
+ src/images/flags/MX.xpm src/images/flags/MY.xpm \
+ src/images/flags/MZ.xpm src/images/flags/NA.xpm \
+ src/images/flags/NC.xpm src/images/flags/NE.xpm \
+ src/images/flags/NF.xpm src/images/flags/NG.xpm \
+ src/images/flags/NI.xpm src/images/flags/NL.xpm \
+ src/images/flags/NO.xpm src/images/flags/NP.xpm \
+ src/images/flags/NR.xpm src/images/flags/NU.xpm \
+ src/images/flags/NZ.xpm src/images/flags/OM.xpm \
+ src/images/flags/PA.xpm src/images/flags/PE.xpm \
+ src/images/flags/PF.xpm src/images/flags/PG.xpm \
+ src/images/flags/PH.xpm src/images/flags/PK.xpm \
+ src/images/flags/PL.xpm src/images/flags/PM.xpm \
+ src/images/flags/PN.xpm src/images/flags/PR.xpm \
+ src/images/flags/PS.xpm src/images/flags/PT.xpm \
+ src/images/flags/PW.xpm src/images/flags/PY.xpm \
+ src/images/flags/QA.xpm src/images/flags/RE.xpm \
+ src/images/flags/RO.xpm src/images/flags/RS.xpm \
+ src/images/flags/RU.xpm src/images/flags/RW.xpm \
+ src/images/flags/SA.xpm src/images/flags/SB.xpm \
+ src/images/flags/SC.xpm src/images/flags/SD.xpm \
+ src/images/flags/SE.xpm src/images/flags/SG.xpm \
+ src/images/flags/SH.xpm src/images/flags/SI.xpm \
+ src/images/flags/SJ.xpm src/images/flags/SK.xpm \
+ src/images/flags/SL.xpm src/images/flags/SM.xpm \
+ src/images/flags/SN.xpm src/images/flags/SO.xpm \
+ src/images/flags/SR.xpm src/images/flags/ST.xpm \
+ src/images/flags/SV.xpm src/images/flags/SY.xpm \
+ src/images/flags/SZ.xpm src/images/flags/TC.xpm \
+ src/images/flags/TD.xpm src/images/flags/TF.xpm \
+ src/images/flags/TG.xpm src/images/flags/TH.xpm \
+ src/images/flags/TJ.xpm src/images/flags/TK.xpm \
+ src/images/flags/TL.xpm src/images/flags/TM.xpm \
+ src/images/flags/TN.xpm src/images/flags/TO.xpm \
+ src/images/flags/TR.xpm src/images/flags/TT.xpm \
+ src/images/flags/TV.xpm src/images/flags/TW.xpm \
+ src/images/flags/TZ.xpm src/images/flags/UA.xpm \
+ src/images/flags/UG.xpm src/images/flags/UM.xpm \
+ src/images/flags/US.xpm src/images/flags/UY.xpm \
+ src/images/flags/UZ.xpm src/images/flags/VA.xpm \
+ src/images/flags/VC.xpm src/images/flags/VE.xpm \
+ src/images/flags/VG.xpm src/images/flags/VI.xpm \
+ src/images/flags/VN.xpm src/images/flags/VU.xpm \
+ src/images/flags/WF.xpm src/images/flags/WS.xpm \
+ src/images/flags/YE.xpm src/images/flags/YT.xpm \
+ src/images/flags/ZA.xpm src/images/flags/ZM.xpm \
+ src/images/flags/ZW.xpm src/images/empty.xpm \
+ src/customlistctrl.h src/customlistctrl.cpp \
+ src/customvirtlistctrl.h src/mmoptionmodel.h \
+ src/mmoptionmodel.cpp src/mmoptionswrapper.h \
+ src/mmoptionswrapper.cpp src/battleroommmoptionstab.h \
+ src/torrentwrapper.cpp src/torrentwrapper.h src/thingdef.h \
+ src/spinctld.h src/spinctld.cpp src/autobalancedialog.cpp \
+ src/autobalancedialog.h src/tdfcontainer.cpp \
+ src/tdfcontainer.h src/globalevents.h src/globalevents.cpp \
+ src/httpdownloader.h src/Helper/TextCompletionDatabase.hpp \
+ src/Helper/TextCompletionDatabase.cpp \
+ src/Helper/wxTranslationHelper.h \
+ src/Helper/wxTranslationHelper.cpp \
+ src/Helper/tasclientimport.h src/Helper/tasclientimport.cpp \
+ src/Helper/slhtmlwindow.cpp src/Helper/slhtmlwindow.h \
+ src/channel/channelchooser.cpp src/channel/channelchooser.h \
+ src/channel/channelchooserdialog.cpp \
+ src/channel/channelchooserdialog.h src/Helper/colorbutton.cpp \
+ src/Helper/colorbutton.h src/Helper/wxtextctrlhist.cpp \
+ src/Helper/wxtextctrlhist.h src/Helper/sortutil.h \
+ src/Helper/imageviewer.h src/Helper/imageviewer.cpp \
+ src/filelister/filelistctrl.h src/filelister/filelistdialog.h \
+ src/filelister/filelistfilter.h \
+ src/filelister/filelistctrl.cpp \
+ src/filelister/filelistdialog.cpp \
+ src/filelister/filelistfilter.cpp configure.ac \
+ src/channel/autojoinchanneldialog.h src/autopointers.h \
+ src/channel/autojoinchanneldialog.cpp src/useractions.h \
+ src/useractions.cpp src/selectusersdialog.h \
+ src/selectusersdialog.cpp src/groupoptionspanel.h \
+ src/groupoptionspanel.cpp src/lobbyoptionstab.h \
+ src/lobbyoptionstab.cpp src/aui/auimanager.h \
+ src/aui/auimanager.cpp src/aui/auiutils.h \
+ src/aui/artprovider.h src/aui/artprovider.cpp \
+ src/updater/updater.h src/updater/updater.cpp \
+ src/widgets/downloadlistctrl.cpp \
+ src/widgets/downloadlistctrl.h src/widgets/downloaddialog.cpp \
+ src/widgets/downloaddialog.h src/widgets/downloadpanel.cpp \
+ src/widgets/downloadpanel.h src/widgets/infopanel.cpp \
+ src/widgets/infopanel.h src/widgets/widget.cpp \
+ src/widgets/widget.h src/usermenu.h src/thread.cpp \
+ src/thread.h src/globalsmanager.cpp src/globalsmanager.h \
+ src/mmoptionwindows.cpp src/mmoptionwindows.h \
+ src/playback/savegamelist.cpp src/playback/savegamelist.h \
+ src/images/floppy_icon.png.h src/images/replay_icon.png.h \
+ src/images/replay_icon_text.png.h $(am__append_2) \
+ $(am__append_3) src/settings++/se_utils.h \
+ src/settings++/se_utils.cpp src/settings++/frame.cpp \
+ src/settings++/main.h src/settings++/tab_ui.cpp \
+ src/settings++/tab_render_detail.cpp \
+ src/settings++/tab_quality_video.h src/settings++/frame.h \
+ src/settings++/tab_audio.h src/settings++/tab_audio.cpp \
+ src/settings++/presets.h src/settings++/tab_abstract.cpp \
+ src/settings++/Defs.hpp src/settings++/tab_simple.cpp \
+ src/settings++/tab_quality_video.cpp src/settings++/tab_ui.h \
+ src/settings++/tab_simple.h src/images/springsettings.xpm \
+ src/settings++/tab_render_detail.h \
+ src/settings++/tab_abstract.h \
+ src/settings++/panel_pathoption.h \
+ src/settings++/panel_pathoption.cpp \
+ src/settings++/custom_dialogs.h \
+ src/settings++/custom_dialogs.cpp \
+ src/settings++/helpmenufunctions.h \
+ src/settings++/helpmenufunctions.cpp
+springsettings_SOURCES = src/utils/debug.cpp src/utils/debug.h \
+ src/utils/platform.cpp src/utils/platform.h \
+ src/utils/conversion.cpp src/utils/conversion.h \
+ src/utils/sltipwin.cpp src/utils/sltipwin.h \
+ src/utils/controls.cpp src/utils/controls.h \
+ src/crashreport.cpp src/crashreport.h src/spinctld.h \
+ src/spinctld.cpp src/springunitsynclib.cpp \
+ src/springunitsynclib.h src/springunitsync.cpp \
+ src/springunitsync.h src/thread.cpp src/thread.h \
+ src/settings.cpp src/settings.h src/uiutils.cpp src/uiutils.h \
+ src/mmoptionmodel.h src/mmoptionmodel.cpp \
+ src/globalsmanager.cpp src/settings++/se_utils.cpp \
+ src/settings++/se_utils.h src/settings++/frame.cpp \
+ src/settings++/main.h src/settings++/tab_ui.cpp \
+ src/settings++/tab_render_detail.cpp \
+ src/settings++/tab_quality_video.h src/settings++/frame.h \
+ src/settings++/tab_audio.h src/settings++/tab_audio.cpp \
+ src/settings++/presets.h src/settings++/tab_abstract.cpp \
+ src/settings++/Main.cpp src/settings++/Defs.hpp \
+ src/settings++/tab_simple.cpp \
+ src/settings++/tab_quality_video.cpp src/settings++/tab_ui.h \
+ src/settings++/tab_simple.h src/images/springsettings.xpm \
+ src/settings++/tab_render_detail.h \
+ src/settings++/tab_abstract.h \
+ src/settings++/panel_pathoption.h \
+ src/settings++/panel_pathoption.cpp \
+ src/settings++/custom_dialogs.h \
+ src/settings++/custom_dialogs.cpp \
+ src/settings++/helpmenufunctions.h \
+ src/settings++/helpmenufunctions.cpp $(am__append_4)
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .cpp .o .obj .rc
+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 '; \
+ cd $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ 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)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+src/$(am__dirstamp):
+ @$(MKDIR_P) src
+ @: > src/$(am__dirstamp)
+src/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) src/$(DEPDIR)
+ @: > src/$(DEPDIR)/$(am__dirstamp)
+src/springlobby.$(OBJEXT): src/$(am__dirstamp) \
+ src/$(DEPDIR)/$(am__dirstamp)
+springlobby$(EXEEXT): $(springlobby_OBJECTS) $(springlobby_DEPENDENCIES)
+ @rm -f springlobby$(EXEEXT)
+ $(CXXLINK) $(springlobby_OBJECTS) $(springlobby_LDADD) $(LIBS)
+src/settings++/$(am__dirstamp):
+ @$(MKDIR_P) src/settings++
+ @: > src/settings++/$(am__dirstamp)
+src/settings++/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) src/settings++/$(DEPDIR)
+ @: > src/settings++/$(DEPDIR)/$(am__dirstamp)
+src/settings++/settings.$(OBJEXT): src/settings++/$(am__dirstamp) \
+ src/settings++/$(DEPDIR)/$(am__dirstamp)
+springsettings$(EXEEXT): $(springsettings_OBJECTS) $(springsettings_DEPENDENCIES)
+ @rm -f springsettings$(EXEEXT)
+ $(CXXLINK) $(springsettings_OBJECTS) $(springsettings_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f src/settings++/settings.$(OBJEXT)
+ -rm -f src/springlobby.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Main.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/TextCompletionDatabase.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/addbotdialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/adler32.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/agreementdialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/alert.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/artprovider.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/assert.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auimanager.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/autobalancedialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/autohost.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/autojoinchanneldialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/base64.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battle.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battlelist.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battlelistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battlelistfilter.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battlelisttab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battlemaptab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battleoptionstab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battleroomlistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/battleroomtab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/broadcast_socket.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/bt_peer_connection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/channel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/channelchooser.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/channelchooserdialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/channellist.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/channellistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/chatlog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/chatoptionstab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/chatpanel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/closest_nodes.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/colorbutton.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/compress.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/connection_queue.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/connectwindow.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/controls.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/conversion.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/countrycodes.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/crashreport.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/crc.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/crc32.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/custom_dialogs.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/customlistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/debug.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/deflate.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/dht_tracker.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/disk_io_thread.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/downloaddialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/downloadlistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/downloadpanel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/entry.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/enum_net.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/escape_string.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/file.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/file_pool.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/filelistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/filelistdialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/filelistfilter.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/find_data.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/flagimages.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/frame.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/globalevents.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/globalsmanager.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/groupoptionspanel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gzio.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/helpmenufunctions.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/hostbattledialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_connection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_stream.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_tracker_connection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ibattle.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/iconimagelist.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/identify_client.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imageviewer.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/infback.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/inffast.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/inflate.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/infopanel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/inftrees.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/instantiate_connection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ip_filter.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/listctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/lobbyoptionstab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/logger.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/lsd.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mainchattab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mainjoinbattletab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mainoptionstab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mainsingleplayertab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/maintorrenttab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mainwindow.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mapctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mapgridctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mapselectdialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/math.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/md5.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/metadata_transfer.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/misc.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mmoptionmodel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mmoptionswrapper.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mmoptionwindows.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/natpmp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nicklistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/node.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/node_id.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/offlinebattle.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/panel_pathoption.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pe_crypto.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/peer_connection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/piece_picker.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/platform.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/policy.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/refresh.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/replaylist.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/routing_table.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/rpc_manager.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/savegamelist.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdlsound.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/se_utils.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/selectusersdialog.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/server.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/serverevents.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/session.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/session_impl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/settings.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sha1.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/singleplayerbattle.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/singleplayertab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/slbook.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/slhtmlwindow.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sltipwin.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/socket.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/socks4_stream.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/socks5_stream.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/spinctld.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/spring.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/springlobbyapp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/springoptionstab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/springprocess.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/springunitsync.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/springunitsynclib.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stat.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/storage.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tab_abstract.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tab_audio.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tab_quality_video.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tab_render_detail.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tab_simple.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tab_ui.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tasclientimport.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tasserver.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tasutil.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tdfcontainer.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/thread.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torrent.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torrent_handle.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torrent_info.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torrentlistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torrentoptionspanel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torrentwrapper.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tracker_manager.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/traversal_algorithm.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/trees.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/udp_tracker_connection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ui.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/uiutils.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/uncompr.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/unitsyncthread.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/updater.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/upnp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/user.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/useractions.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/userlist.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/userlistctrl.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ut_pex.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/versionchecker.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/web_peer_connection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/widget.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/wxTranslationHelper.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/wxtextctrlhist.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/zutil.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+md5.o: src/utils/md5.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md5.o -MD -MP -MF $(DEPDIR)/md5.Tpo -c -o md5.o `test -f 'src/utils/md5.c' || echo '$(srcdir)/'`src/utils/md5.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/md5.Tpo $(DEPDIR)/md5.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/utils/md5.c' object='md5.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md5.o `test -f 'src/utils/md5.c' || echo '$(srcdir)/'`src/utils/md5.c
+
+md5.obj: src/utils/md5.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md5.obj -MD -MP -MF $(DEPDIR)/md5.Tpo -c -o md5.obj `if test -f 'src/utils/md5.c'; then $(CYGPATH_W) 'src/utils/md5.c'; else $(CYGPATH_W) '$(srcdir)/src/utils/md5.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/md5.Tpo $(DEPDIR)/md5.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/utils/md5.c' object='md5.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md5.obj `if test -f 'src/utils/md5.c'; then $(CYGPATH_W) 'src/utils/md5.c'; else $(CYGPATH_W) '$(srcdir)/src/utils/md5.c'; fi`
+
+adler32.o: $(libt_dir)/zlib/adler32.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT adler32.o -MD -MP -MF $(DEPDIR)/adler32.Tpo -c -o adler32.o `test -f '$(libt_dir)/zlib/adler32.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/adler32.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/adler32.Tpo $(DEPDIR)/adler32.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/adler32.c' object='adler32.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o adler32.o `test -f '$(libt_dir)/zlib/adler32.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/adler32.c
+
+adler32.obj: $(libt_dir)/zlib/adler32.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT adler32.obj -MD -MP -MF $(DEPDIR)/adler32.Tpo -c -o adler32.obj `if test -f '$(libt_dir)/zlib/adler32.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/adler32.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/adler32.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/adler32.Tpo $(DEPDIR)/adler32.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/adler32.c' object='adler32.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o adler32.obj `if test -f '$(libt_dir)/zlib/adler32.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/adler32.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/adler32.c'; fi`
+
+compress.o: $(libt_dir)/zlib/compress.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT compress.o -MD -MP -MF $(DEPDIR)/compress.Tpo -c -o compress.o `test -f '$(libt_dir)/zlib/compress.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/compress.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/compress.Tpo $(DEPDIR)/compress.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/compress.c' object='compress.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o compress.o `test -f '$(libt_dir)/zlib/compress.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/compress.c
+
+compress.obj: $(libt_dir)/zlib/compress.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT compress.obj -MD -MP -MF $(DEPDIR)/compress.Tpo -c -o compress.obj `if test -f '$(libt_dir)/zlib/compress.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/compress.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/compress.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/compress.Tpo $(DEPDIR)/compress.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/compress.c' object='compress.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o compress.obj `if test -f '$(libt_dir)/zlib/compress.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/compress.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/compress.c'; fi`
+
+crc32.o: $(libt_dir)/zlib/crc32.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crc32.o -MD -MP -MF $(DEPDIR)/crc32.Tpo -c -o crc32.o `test -f '$(libt_dir)/zlib/crc32.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/crc32.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/crc32.Tpo $(DEPDIR)/crc32.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/crc32.c' object='crc32.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crc32.o `test -f '$(libt_dir)/zlib/crc32.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/crc32.c
+
+crc32.obj: $(libt_dir)/zlib/crc32.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crc32.obj -MD -MP -MF $(DEPDIR)/crc32.Tpo -c -o crc32.obj `if test -f '$(libt_dir)/zlib/crc32.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/crc32.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/crc32.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/crc32.Tpo $(DEPDIR)/crc32.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/crc32.c' object='crc32.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crc32.obj `if test -f '$(libt_dir)/zlib/crc32.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/crc32.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/crc32.c'; fi`
+
+deflate.o: $(libt_dir)/zlib/deflate.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT deflate.o -MD -MP -MF $(DEPDIR)/deflate.Tpo -c -o deflate.o `test -f '$(libt_dir)/zlib/deflate.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/deflate.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/deflate.Tpo $(DEPDIR)/deflate.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/deflate.c' object='deflate.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o deflate.o `test -f '$(libt_dir)/zlib/deflate.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/deflate.c
+
+deflate.obj: $(libt_dir)/zlib/deflate.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT deflate.obj -MD -MP -MF $(DEPDIR)/deflate.Tpo -c -o deflate.obj `if test -f '$(libt_dir)/zlib/deflate.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/deflate.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/deflate.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/deflate.Tpo $(DEPDIR)/deflate.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/deflate.c' object='deflate.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o deflate.obj `if test -f '$(libt_dir)/zlib/deflate.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/deflate.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/deflate.c'; fi`
+
+gzio.o: $(libt_dir)/zlib/gzio.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gzio.o -MD -MP -MF $(DEPDIR)/gzio.Tpo -c -o gzio.o `test -f '$(libt_dir)/zlib/gzio.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/gzio.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/gzio.Tpo $(DEPDIR)/gzio.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/gzio.c' object='gzio.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gzio.o `test -f '$(libt_dir)/zlib/gzio.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/gzio.c
+
+gzio.obj: $(libt_dir)/zlib/gzio.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gzio.obj -MD -MP -MF $(DEPDIR)/gzio.Tpo -c -o gzio.obj `if test -f '$(libt_dir)/zlib/gzio.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/gzio.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/gzio.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/gzio.Tpo $(DEPDIR)/gzio.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/gzio.c' object='gzio.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gzio.obj `if test -f '$(libt_dir)/zlib/gzio.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/gzio.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/gzio.c'; fi`
+
+infback.o: $(libt_dir)/zlib/infback.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT infback.o -MD -MP -MF $(DEPDIR)/infback.Tpo -c -o infback.o `test -f '$(libt_dir)/zlib/infback.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/infback.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/infback.Tpo $(DEPDIR)/infback.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/infback.c' object='infback.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o infback.o `test -f '$(libt_dir)/zlib/infback.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/infback.c
+
+infback.obj: $(libt_dir)/zlib/infback.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT infback.obj -MD -MP -MF $(DEPDIR)/infback.Tpo -c -o infback.obj `if test -f '$(libt_dir)/zlib/infback.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/infback.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/infback.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/infback.Tpo $(DEPDIR)/infback.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/infback.c' object='infback.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o infback.obj `if test -f '$(libt_dir)/zlib/infback.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/infback.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/infback.c'; fi`
+
+inffast.o: $(libt_dir)/zlib/inffast.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inffast.o -MD -MP -MF $(DEPDIR)/inffast.Tpo -c -o inffast.o `test -f '$(libt_dir)/zlib/inffast.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/inffast.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/inffast.Tpo $(DEPDIR)/inffast.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/inffast.c' object='inffast.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inffast.o `test -f '$(libt_dir)/zlib/inffast.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/inffast.c
+
+inffast.obj: $(libt_dir)/zlib/inffast.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inffast.obj -MD -MP -MF $(DEPDIR)/inffast.Tpo -c -o inffast.obj `if test -f '$(libt_dir)/zlib/inffast.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/inffast.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/inffast.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/inffast.Tpo $(DEPDIR)/inffast.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/inffast.c' object='inffast.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inffast.obj `if test -f '$(libt_dir)/zlib/inffast.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/inffast.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/inffast.c'; fi`
+
+inflate.o: $(libt_dir)/zlib/inflate.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inflate.o -MD -MP -MF $(DEPDIR)/inflate.Tpo -c -o inflate.o `test -f '$(libt_dir)/zlib/inflate.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/inflate.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/inflate.Tpo $(DEPDIR)/inflate.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/inflate.c' object='inflate.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inflate.o `test -f '$(libt_dir)/zlib/inflate.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/inflate.c
+
+inflate.obj: $(libt_dir)/zlib/inflate.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inflate.obj -MD -MP -MF $(DEPDIR)/inflate.Tpo -c -o inflate.obj `if test -f '$(libt_dir)/zlib/inflate.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/inflate.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/inflate.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/inflate.Tpo $(DEPDIR)/inflate.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/inflate.c' object='inflate.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inflate.obj `if test -f '$(libt_dir)/zlib/inflate.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/inflate.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/inflate.c'; fi`
+
+inftrees.o: $(libt_dir)/zlib/inftrees.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inftrees.o -MD -MP -MF $(DEPDIR)/inftrees.Tpo -c -o inftrees.o `test -f '$(libt_dir)/zlib/inftrees.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/inftrees.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/inftrees.Tpo $(DEPDIR)/inftrees.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/inftrees.c' object='inftrees.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inftrees.o `test -f '$(libt_dir)/zlib/inftrees.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/inftrees.c
+
+inftrees.obj: $(libt_dir)/zlib/inftrees.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inftrees.obj -MD -MP -MF $(DEPDIR)/inftrees.Tpo -c -o inftrees.obj `if test -f '$(libt_dir)/zlib/inftrees.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/inftrees.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/inftrees.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/inftrees.Tpo $(DEPDIR)/inftrees.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/inftrees.c' object='inftrees.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inftrees.obj `if test -f '$(libt_dir)/zlib/inftrees.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/inftrees.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/inftrees.c'; fi`
+
+trees.o: $(libt_dir)/zlib/trees.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trees.o -MD -MP -MF $(DEPDIR)/trees.Tpo -c -o trees.o `test -f '$(libt_dir)/zlib/trees.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/trees.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/trees.Tpo $(DEPDIR)/trees.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/trees.c' object='trees.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trees.o `test -f '$(libt_dir)/zlib/trees.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/trees.c
+
+trees.obj: $(libt_dir)/zlib/trees.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trees.obj -MD -MP -MF $(DEPDIR)/trees.Tpo -c -o trees.obj `if test -f '$(libt_dir)/zlib/trees.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/trees.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/trees.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/trees.Tpo $(DEPDIR)/trees.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/trees.c' object='trees.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trees.obj `if test -f '$(libt_dir)/zlib/trees.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/trees.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/trees.c'; fi`
+
+uncompr.o: $(libt_dir)/zlib/uncompr.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT uncompr.o -MD -MP -MF $(DEPDIR)/uncompr.Tpo -c -o uncompr.o `test -f '$(libt_dir)/zlib/uncompr.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/uncompr.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/uncompr.Tpo $(DEPDIR)/uncompr.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/uncompr.c' object='uncompr.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o uncompr.o `test -f '$(libt_dir)/zlib/uncompr.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/uncompr.c
+
+uncompr.obj: $(libt_dir)/zlib/uncompr.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT uncompr.obj -MD -MP -MF $(DEPDIR)/uncompr.Tpo -c -o uncompr.obj `if test -f '$(libt_dir)/zlib/uncompr.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/uncompr.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/uncompr.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/uncompr.Tpo $(DEPDIR)/uncompr.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/uncompr.c' object='uncompr.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o uncompr.obj `if test -f '$(libt_dir)/zlib/uncompr.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/uncompr.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/uncompr.c'; fi`
+
+zutil.o: $(libt_dir)/zlib/zutil.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zutil.o -MD -MP -MF $(DEPDIR)/zutil.Tpo -c -o zutil.o `test -f '$(libt_dir)/zlib/zutil.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/zutil.c
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/zutil.Tpo $(DEPDIR)/zutil.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/zutil.c' object='zutil.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zutil.o `test -f '$(libt_dir)/zlib/zutil.c' || echo '$(srcdir)/'`$(libt_dir)/zlib/zutil.c
+
+zutil.obj: $(libt_dir)/zlib/zutil.c
+ at am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zutil.obj -MD -MP -MF $(DEPDIR)/zutil.Tpo -c -o zutil.obj `if test -f '$(libt_dir)/zlib/zutil.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/zutil.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/zutil.c'; fi`
+ at am__fastdepCC_TRUE@ mv -f $(DEPDIR)/zutil.Tpo $(DEPDIR)/zutil.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(libt_dir)/zlib/zutil.c' object='zutil.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zutil.obj `if test -f '$(libt_dir)/zlib/zutil.c'; then $(CYGPATH_W) '$(libt_dir)/zlib/zutil.c'; else $(CYGPATH_W) '$(srcdir)/$(libt_dir)/zlib/zutil.c'; fi`
+
+.cpp.o:
+ at am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+ at am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+slbook.o: src/aui/slbook.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT slbook.o -MD -MP -MF $(DEPDIR)/slbook.Tpo -c -o slbook.o `test -f 'src/aui/slbook.cpp' || echo '$(srcdir)/'`src/aui/slbook.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/slbook.Tpo $(DEPDIR)/slbook.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/aui/slbook.cpp' object='slbook.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o slbook.o `test -f 'src/aui/slbook.cpp' || echo '$(srcdir)/'`src/aui/slbook.cpp
+
+slbook.obj: src/aui/slbook.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT slbook.obj -MD -MP -MF $(DEPDIR)/slbook.Tpo -c -o slbook.obj `if test -f 'src/aui/slbook.cpp'; then $(CYGPATH_W) 'src/aui/slbook.cpp'; else $(CYGPATH_W) '$(srcdir)/src/aui/slbook.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/slbook.Tpo $(DEPDIR)/slbook.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/aui/slbook.cpp' object='slbook.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o slbook.obj `if test -f 'src/aui/slbook.cpp'; then $(CYGPATH_W) 'src/aui/slbook.cpp'; else $(CYGPATH_W) '$(srcdir)/src/aui/slbook.cpp'; fi`
+
+math.o: src/utils/math.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT math.o -MD -MP -MF $(DEPDIR)/math.Tpo -c -o math.o `test -f 'src/utils/math.cpp' || echo '$(srcdir)/'`src/utils/math.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/math.Tpo $(DEPDIR)/math.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/math.cpp' object='math.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o math.o `test -f 'src/utils/math.cpp' || echo '$(srcdir)/'`src/utils/math.cpp
+
+math.obj: src/utils/math.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT math.obj -MD -MP -MF $(DEPDIR)/math.Tpo -c -o math.obj `if test -f 'src/utils/math.cpp'; then $(CYGPATH_W) 'src/utils/math.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/math.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/math.Tpo $(DEPDIR)/math.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/math.cpp' object='math.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o math.obj `if test -f 'src/utils/math.cpp'; then $(CYGPATH_W) 'src/utils/math.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/math.cpp'; fi`
+
+misc.o: src/utils/misc.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT misc.o -MD -MP -MF $(DEPDIR)/misc.Tpo -c -o misc.o `test -f 'src/utils/misc.cpp' || echo '$(srcdir)/'`src/utils/misc.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/misc.Tpo $(DEPDIR)/misc.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/misc.cpp' object='misc.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o misc.o `test -f 'src/utils/misc.cpp' || echo '$(srcdir)/'`src/utils/misc.cpp
+
+misc.obj: src/utils/misc.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT misc.obj -MD -MP -MF $(DEPDIR)/misc.Tpo -c -o misc.obj `if test -f 'src/utils/misc.cpp'; then $(CYGPATH_W) 'src/utils/misc.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/misc.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/misc.Tpo $(DEPDIR)/misc.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/misc.cpp' object='misc.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o misc.obj `if test -f 'src/utils/misc.cpp'; then $(CYGPATH_W) 'src/utils/misc.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/misc.cpp'; fi`
+
+debug.o: src/utils/debug.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT debug.o -MD -MP -MF $(DEPDIR)/debug.Tpo -c -o debug.o `test -f 'src/utils/debug.cpp' || echo '$(srcdir)/'`src/utils/debug.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/debug.Tpo $(DEPDIR)/debug.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/debug.cpp' object='debug.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o debug.o `test -f 'src/utils/debug.cpp' || echo '$(srcdir)/'`src/utils/debug.cpp
+
+debug.obj: src/utils/debug.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT debug.obj -MD -MP -MF $(DEPDIR)/debug.Tpo -c -o debug.obj `if test -f 'src/utils/debug.cpp'; then $(CYGPATH_W) 'src/utils/debug.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/debug.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/debug.Tpo $(DEPDIR)/debug.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/debug.cpp' object='debug.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o debug.obj `if test -f 'src/utils/debug.cpp'; then $(CYGPATH_W) 'src/utils/debug.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/debug.cpp'; fi`
+
+platform.o: src/utils/platform.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT platform.o -MD -MP -MF $(DEPDIR)/platform.Tpo -c -o platform.o `test -f 'src/utils/platform.cpp' || echo '$(srcdir)/'`src/utils/platform.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/platform.Tpo $(DEPDIR)/platform.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/platform.cpp' object='platform.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o platform.o `test -f 'src/utils/platform.cpp' || echo '$(srcdir)/'`src/utils/platform.cpp
+
+platform.obj: src/utils/platform.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT platform.obj -MD -MP -MF $(DEPDIR)/platform.Tpo -c -o platform.obj `if test -f 'src/utils/platform.cpp'; then $(CYGPATH_W) 'src/utils/platform.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/platform.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/platform.Tpo $(DEPDIR)/platform.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/platform.cpp' object='platform.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o platform.obj `if test -f 'src/utils/platform.cpp'; then $(CYGPATH_W) 'src/utils/platform.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/platform.cpp'; fi`
+
+conversion.o: src/utils/conversion.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT conversion.o -MD -MP -MF $(DEPDIR)/conversion.Tpo -c -o conversion.o `test -f 'src/utils/conversion.cpp' || echo '$(srcdir)/'`src/utils/conversion.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/conversion.Tpo $(DEPDIR)/conversion.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/conversion.cpp' object='conversion.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o conversion.o `test -f 'src/utils/conversion.cpp' || echo '$(srcdir)/'`src/utils/conversion.cpp
+
+conversion.obj: src/utils/conversion.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT conversion.obj -MD -MP -MF $(DEPDIR)/conversion.Tpo -c -o conversion.obj `if test -f 'src/utils/conversion.cpp'; then $(CYGPATH_W) 'src/utils/conversion.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/conversion.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/conversion.Tpo $(DEPDIR)/conversion.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/conversion.cpp' object='conversion.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o conversion.obj `if test -f 'src/utils/conversion.cpp'; then $(CYGPATH_W) 'src/utils/conversion.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/conversion.cpp'; fi`
+
+tasutil.o: src/utils/tasutil.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tasutil.o -MD -MP -MF $(DEPDIR)/tasutil.Tpo -c -o tasutil.o `test -f 'src/utils/tasutil.cpp' || echo '$(srcdir)/'`src/utils/tasutil.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tasutil.Tpo $(DEPDIR)/tasutil.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/tasutil.cpp' object='tasutil.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tasutil.o `test -f 'src/utils/tasutil.cpp' || echo '$(srcdir)/'`src/utils/tasutil.cpp
+
+tasutil.obj: src/utils/tasutil.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tasutil.obj -MD -MP -MF $(DEPDIR)/tasutil.Tpo -c -o tasutil.obj `if test -f 'src/utils/tasutil.cpp'; then $(CYGPATH_W) 'src/utils/tasutil.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/tasutil.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tasutil.Tpo $(DEPDIR)/tasutil.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/tasutil.cpp' object='tasutil.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tasutil.obj `if test -f 'src/utils/tasutil.cpp'; then $(CYGPATH_W) 'src/utils/tasutil.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/tasutil.cpp'; fi`
+
+sltipwin.o: src/utils/sltipwin.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sltipwin.o -MD -MP -MF $(DEPDIR)/sltipwin.Tpo -c -o sltipwin.o `test -f 'src/utils/sltipwin.cpp' || echo '$(srcdir)/'`src/utils/sltipwin.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/sltipwin.Tpo $(DEPDIR)/sltipwin.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/sltipwin.cpp' object='sltipwin.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sltipwin.o `test -f 'src/utils/sltipwin.cpp' || echo '$(srcdir)/'`src/utils/sltipwin.cpp
+
+sltipwin.obj: src/utils/sltipwin.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sltipwin.obj -MD -MP -MF $(DEPDIR)/sltipwin.Tpo -c -o sltipwin.obj `if test -f 'src/utils/sltipwin.cpp'; then $(CYGPATH_W) 'src/utils/sltipwin.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/sltipwin.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/sltipwin.Tpo $(DEPDIR)/sltipwin.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/sltipwin.cpp' object='sltipwin.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sltipwin.obj `if test -f 'src/utils/sltipwin.cpp'; then $(CYGPATH_W) 'src/utils/sltipwin.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/sltipwin.cpp'; fi`
+
+controls.o: src/utils/controls.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT controls.o -MD -MP -MF $(DEPDIR)/controls.Tpo -c -o controls.o `test -f 'src/utils/controls.cpp' || echo '$(srcdir)/'`src/utils/controls.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/controls.Tpo $(DEPDIR)/controls.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/controls.cpp' object='controls.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o controls.o `test -f 'src/utils/controls.cpp' || echo '$(srcdir)/'`src/utils/controls.cpp
+
+controls.obj: src/utils/controls.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT controls.obj -MD -MP -MF $(DEPDIR)/controls.Tpo -c -o controls.obj `if test -f 'src/utils/controls.cpp'; then $(CYGPATH_W) 'src/utils/controls.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/controls.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/controls.Tpo $(DEPDIR)/controls.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utils/controls.cpp' object='controls.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o controls.obj `if test -f 'src/utils/controls.cpp'; then $(CYGPATH_W) 'src/utils/controls.cpp'; else $(CYGPATH_W) '$(srcdir)/src/utils/controls.cpp'; fi`
+
+versionchecker.o: src/updater/versionchecker.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT versionchecker.o -MD -MP -MF $(DEPDIR)/versionchecker.Tpo -c -o versionchecker.o `test -f 'src/updater/versionchecker.cpp' || echo '$(srcdir)/'`src/updater/versionchecker.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/versionchecker.Tpo $(DEPDIR)/versionchecker.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/updater/versionchecker.cpp' object='versionchecker.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o versionchecker.o `test -f 'src/updater/versionchecker.cpp' || echo '$(srcdir)/'`src/updater/versionchecker.cpp
+
+versionchecker.obj: src/updater/versionchecker.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT versionchecker.obj -MD -MP -MF $(DEPDIR)/versionchecker.Tpo -c -o versionchecker.obj `if test -f 'src/updater/versionchecker.cpp'; then $(CYGPATH_W) 'src/updater/versionchecker.cpp'; else $(CYGPATH_W) '$(srcdir)/src/updater/versionchecker.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/versionchecker.Tpo $(DEPDIR)/versionchecker.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/updater/versionchecker.cpp' object='versionchecker.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o versionchecker.obj `if test -f 'src/updater/versionchecker.cpp'; then $(CYGPATH_W) 'src/updater/versionchecker.cpp'; else $(CYGPATH_W) '$(srcdir)/src/updater/versionchecker.cpp'; fi`
+
+springunitsynclib.o: src/springunitsynclib.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springunitsynclib.o -MD -MP -MF $(DEPDIR)/springunitsynclib.Tpo -c -o springunitsynclib.o `test -f 'src/springunitsynclib.cpp' || echo '$(srcdir)/'`src/springunitsynclib.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springunitsynclib.Tpo $(DEPDIR)/springunitsynclib.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springunitsynclib.cpp' object='springunitsynclib.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springunitsynclib.o `test -f 'src/springunitsynclib.cpp' || echo '$(srcdir)/'`src/springunitsynclib.cpp
+
+springunitsynclib.obj: src/springunitsynclib.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springunitsynclib.obj -MD -MP -MF $(DEPDIR)/springunitsynclib.Tpo -c -o springunitsynclib.obj `if test -f 'src/springunitsynclib.cpp'; then $(CYGPATH_W) 'src/springunitsynclib.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springunitsynclib.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springunitsynclib.Tpo $(DEPDIR)/springunitsynclib.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springunitsynclib.cpp' object='springunitsynclib.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springunitsynclib.obj `if test -f 'src/springunitsynclib.cpp'; then $(CYGPATH_W) 'src/springunitsynclib.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springunitsynclib.cpp'; fi`
+
+unitsyncthread.o: src/unitsyncthread.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT unitsyncthread.o -MD -MP -MF $(DEPDIR)/unitsyncthread.Tpo -c -o unitsyncthread.o `test -f 'src/unitsyncthread.cpp' || echo '$(srcdir)/'`src/unitsyncthread.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/unitsyncthread.Tpo $(DEPDIR)/unitsyncthread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/unitsyncthread.cpp' object='unitsyncthread.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o unitsyncthread.o `test -f 'src/unitsyncthread.cpp' || echo '$(srcdir)/'`src/unitsyncthread.cpp
+
+unitsyncthread.obj: src/unitsyncthread.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT unitsyncthread.obj -MD -MP -MF $(DEPDIR)/unitsyncthread.Tpo -c -o unitsyncthread.obj `if test -f 'src/unitsyncthread.cpp'; then $(CYGPATH_W) 'src/unitsyncthread.cpp'; else $(CYGPATH_W) '$(srcdir)/src/unitsyncthread.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/unitsyncthread.Tpo $(DEPDIR)/unitsyncthread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/unitsyncthread.cpp' object='unitsyncthread.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o unitsyncthread.obj `if test -f 'src/unitsyncthread.cpp'; then $(CYGPATH_W) 'src/unitsyncthread.cpp'; else $(CYGPATH_W) '$(srcdir)/src/unitsyncthread.cpp'; fi`
+
+mapgridctrl.o: src/mapgridctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mapgridctrl.o -MD -MP -MF $(DEPDIR)/mapgridctrl.Tpo -c -o mapgridctrl.o `test -f 'src/mapgridctrl.cpp' || echo '$(srcdir)/'`src/mapgridctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mapgridctrl.Tpo $(DEPDIR)/mapgridctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mapgridctrl.cpp' object='mapgridctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mapgridctrl.o `test -f 'src/mapgridctrl.cpp' || echo '$(srcdir)/'`src/mapgridctrl.cpp
+
+mapgridctrl.obj: src/mapgridctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mapgridctrl.obj -MD -MP -MF $(DEPDIR)/mapgridctrl.Tpo -c -o mapgridctrl.obj `if test -f 'src/mapgridctrl.cpp'; then $(CYGPATH_W) 'src/mapgridctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mapgridctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mapgridctrl.Tpo $(DEPDIR)/mapgridctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mapgridctrl.cpp' object='mapgridctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mapgridctrl.obj `if test -f 'src/mapgridctrl.cpp'; then $(CYGPATH_W) 'src/mapgridctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mapgridctrl.cpp'; fi`
+
+mapselectdialog.o: src/mapselectdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mapselectdialog.o -MD -MP -MF $(DEPDIR)/mapselectdialog.Tpo -c -o mapselectdialog.o `test -f 'src/mapselectdialog.cpp' || echo '$(srcdir)/'`src/mapselectdialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mapselectdialog.Tpo $(DEPDIR)/mapselectdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mapselectdialog.cpp' object='mapselectdialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mapselectdialog.o `test -f 'src/mapselectdialog.cpp' || echo '$(srcdir)/'`src/mapselectdialog.cpp
+
+mapselectdialog.obj: src/mapselectdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mapselectdialog.obj -MD -MP -MF $(DEPDIR)/mapselectdialog.Tpo -c -o mapselectdialog.obj `if test -f 'src/mapselectdialog.cpp'; then $(CYGPATH_W) 'src/mapselectdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mapselectdialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mapselectdialog.Tpo $(DEPDIR)/mapselectdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mapselectdialog.cpp' object='mapselectdialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mapselectdialog.obj `if test -f 'src/mapselectdialog.cpp'; then $(CYGPATH_W) 'src/mapselectdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mapselectdialog.cpp'; fi`
+
+chatlog.o: src/chatlog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT chatlog.o -MD -MP -MF $(DEPDIR)/chatlog.Tpo -c -o chatlog.o `test -f 'src/chatlog.cpp' || echo '$(srcdir)/'`src/chatlog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/chatlog.Tpo $(DEPDIR)/chatlog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/chatlog.cpp' object='chatlog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o chatlog.o `test -f 'src/chatlog.cpp' || echo '$(srcdir)/'`src/chatlog.cpp
+
+chatlog.obj: src/chatlog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT chatlog.obj -MD -MP -MF $(DEPDIR)/chatlog.Tpo -c -o chatlog.obj `if test -f 'src/chatlog.cpp'; then $(CYGPATH_W) 'src/chatlog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/chatlog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/chatlog.Tpo $(DEPDIR)/chatlog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/chatlog.cpp' object='chatlog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o chatlog.obj `if test -f 'src/chatlog.cpp'; then $(CYGPATH_W) 'src/chatlog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/chatlog.cpp'; fi`
+
+ibattle.o: src/ibattle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ibattle.o -MD -MP -MF $(DEPDIR)/ibattle.Tpo -c -o ibattle.o `test -f 'src/ibattle.cpp' || echo '$(srcdir)/'`src/ibattle.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ibattle.Tpo $(DEPDIR)/ibattle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/ibattle.cpp' object='ibattle.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ibattle.o `test -f 'src/ibattle.cpp' || echo '$(srcdir)/'`src/ibattle.cpp
+
+ibattle.obj: src/ibattle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ibattle.obj -MD -MP -MF $(DEPDIR)/ibattle.Tpo -c -o ibattle.obj `if test -f 'src/ibattle.cpp'; then $(CYGPATH_W) 'src/ibattle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/ibattle.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ibattle.Tpo $(DEPDIR)/ibattle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/ibattle.cpp' object='ibattle.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ibattle.obj `if test -f 'src/ibattle.cpp'; then $(CYGPATH_W) 'src/ibattle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/ibattle.cpp'; fi`
+
+addbotdialog.o: src/addbotdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT addbotdialog.o -MD -MP -MF $(DEPDIR)/addbotdialog.Tpo -c -o addbotdialog.o `test -f 'src/addbotdialog.cpp' || echo '$(srcdir)/'`src/addbotdialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/addbotdialog.Tpo $(DEPDIR)/addbotdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/addbotdialog.cpp' object='addbotdialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o addbotdialog.o `test -f 'src/addbotdialog.cpp' || echo '$(srcdir)/'`src/addbotdialog.cpp
+
+addbotdialog.obj: src/addbotdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT addbotdialog.obj -MD -MP -MF $(DEPDIR)/addbotdialog.Tpo -c -o addbotdialog.obj `if test -f 'src/addbotdialog.cpp'; then $(CYGPATH_W) 'src/addbotdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/addbotdialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/addbotdialog.Tpo $(DEPDIR)/addbotdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/addbotdialog.cpp' object='addbotdialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o addbotdialog.obj `if test -f 'src/addbotdialog.cpp'; then $(CYGPATH_W) 'src/addbotdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/addbotdialog.cpp'; fi`
+
+agreementdialog.o: src/agreementdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT agreementdialog.o -MD -MP -MF $(DEPDIR)/agreementdialog.Tpo -c -o agreementdialog.o `test -f 'src/agreementdialog.cpp' || echo '$(srcdir)/'`src/agreementdialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/agreementdialog.Tpo $(DEPDIR)/agreementdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/agreementdialog.cpp' object='agreementdialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o agreementdialog.o `test -f 'src/agreementdialog.cpp' || echo '$(srcdir)/'`src/agreementdialog.cpp
+
+agreementdialog.obj: src/agreementdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT agreementdialog.obj -MD -MP -MF $(DEPDIR)/agreementdialog.Tpo -c -o agreementdialog.obj `if test -f 'src/agreementdialog.cpp'; then $(CYGPATH_W) 'src/agreementdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/agreementdialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/agreementdialog.Tpo $(DEPDIR)/agreementdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/agreementdialog.cpp' object='agreementdialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o agreementdialog.obj `if test -f 'src/agreementdialog.cpp'; then $(CYGPATH_W) 'src/agreementdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/agreementdialog.cpp'; fi`
+
+autohost.o: src/autohost.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT autohost.o -MD -MP -MF $(DEPDIR)/autohost.Tpo -c -o autohost.o `test -f 'src/autohost.cpp' || echo '$(srcdir)/'`src/autohost.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/autohost.Tpo $(DEPDIR)/autohost.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/autohost.cpp' object='autohost.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o autohost.o `test -f 'src/autohost.cpp' || echo '$(srcdir)/'`src/autohost.cpp
+
+autohost.obj: src/autohost.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT autohost.obj -MD -MP -MF $(DEPDIR)/autohost.Tpo -c -o autohost.obj `if test -f 'src/autohost.cpp'; then $(CYGPATH_W) 'src/autohost.cpp'; else $(CYGPATH_W) '$(srcdir)/src/autohost.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/autohost.Tpo $(DEPDIR)/autohost.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/autohost.cpp' object='autohost.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o autohost.obj `if test -f 'src/autohost.cpp'; then $(CYGPATH_W) 'src/autohost.cpp'; else $(CYGPATH_W) '$(srcdir)/src/autohost.cpp'; fi`
+
+base64.o: src/base64.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT base64.o -MD -MP -MF $(DEPDIR)/base64.Tpo -c -o base64.o `test -f 'src/base64.cpp' || echo '$(srcdir)/'`src/base64.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/base64.Tpo $(DEPDIR)/base64.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base64.cpp' object='base64.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o base64.o `test -f 'src/base64.cpp' || echo '$(srcdir)/'`src/base64.cpp
+
+base64.obj: src/base64.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT base64.obj -MD -MP -MF $(DEPDIR)/base64.Tpo -c -o base64.obj `if test -f 'src/base64.cpp'; then $(CYGPATH_W) 'src/base64.cpp'; else $(CYGPATH_W) '$(srcdir)/src/base64.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/base64.Tpo $(DEPDIR)/base64.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base64.cpp' object='base64.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o base64.obj `if test -f 'src/base64.cpp'; then $(CYGPATH_W) 'src/base64.cpp'; else $(CYGPATH_W) '$(srcdir)/src/base64.cpp'; fi`
+
+battle.o: src/battle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battle.o -MD -MP -MF $(DEPDIR)/battle.Tpo -c -o battle.o `test -f 'src/battle.cpp' || echo '$(srcdir)/'`src/battle.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battle.Tpo $(DEPDIR)/battle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battle.cpp' object='battle.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battle.o `test -f 'src/battle.cpp' || echo '$(srcdir)/'`src/battle.cpp
+
+battle.obj: src/battle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battle.obj -MD -MP -MF $(DEPDIR)/battle.Tpo -c -o battle.obj `if test -f 'src/battle.cpp'; then $(CYGPATH_W) 'src/battle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battle.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battle.Tpo $(DEPDIR)/battle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battle.cpp' object='battle.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battle.obj `if test -f 'src/battle.cpp'; then $(CYGPATH_W) 'src/battle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battle.cpp'; fi`
+
+maintorrenttab.o: src/maintorrenttab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT maintorrenttab.o -MD -MP -MF $(DEPDIR)/maintorrenttab.Tpo -c -o maintorrenttab.o `test -f 'src/maintorrenttab.cpp' || echo '$(srcdir)/'`src/maintorrenttab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/maintorrenttab.Tpo $(DEPDIR)/maintorrenttab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/maintorrenttab.cpp' object='maintorrenttab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o maintorrenttab.o `test -f 'src/maintorrenttab.cpp' || echo '$(srcdir)/'`src/maintorrenttab.cpp
+
+maintorrenttab.obj: src/maintorrenttab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT maintorrenttab.obj -MD -MP -MF $(DEPDIR)/maintorrenttab.Tpo -c -o maintorrenttab.obj `if test -f 'src/maintorrenttab.cpp'; then $(CYGPATH_W) 'src/maintorrenttab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/maintorrenttab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/maintorrenttab.Tpo $(DEPDIR)/maintorrenttab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/maintorrenttab.cpp' object='maintorrenttab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o maintorrenttab.obj `if test -f 'src/maintorrenttab.cpp'; then $(CYGPATH_W) 'src/maintorrenttab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/maintorrenttab.cpp'; fi`
+
+battlelistctrl.o: src/battlelistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelistctrl.o -MD -MP -MF $(DEPDIR)/battlelistctrl.Tpo -c -o battlelistctrl.o `test -f 'src/battlelistctrl.cpp' || echo '$(srcdir)/'`src/battlelistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelistctrl.Tpo $(DEPDIR)/battlelistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelistctrl.cpp' object='battlelistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelistctrl.o `test -f 'src/battlelistctrl.cpp' || echo '$(srcdir)/'`src/battlelistctrl.cpp
+
+battlelistctrl.obj: src/battlelistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelistctrl.obj -MD -MP -MF $(DEPDIR)/battlelistctrl.Tpo -c -o battlelistctrl.obj `if test -f 'src/battlelistctrl.cpp'; then $(CYGPATH_W) 'src/battlelistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelistctrl.Tpo $(DEPDIR)/battlelistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelistctrl.cpp' object='battlelistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelistctrl.obj `if test -f 'src/battlelistctrl.cpp'; then $(CYGPATH_W) 'src/battlelistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelistctrl.cpp'; fi`
+
+battlelistfilter.o: src/battlelistfilter.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelistfilter.o -MD -MP -MF $(DEPDIR)/battlelistfilter.Tpo -c -o battlelistfilter.o `test -f 'src/battlelistfilter.cpp' || echo '$(srcdir)/'`src/battlelistfilter.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelistfilter.Tpo $(DEPDIR)/battlelistfilter.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelistfilter.cpp' object='battlelistfilter.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelistfilter.o `test -f 'src/battlelistfilter.cpp' || echo '$(srcdir)/'`src/battlelistfilter.cpp
+
+battlelistfilter.obj: src/battlelistfilter.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelistfilter.obj -MD -MP -MF $(DEPDIR)/battlelistfilter.Tpo -c -o battlelistfilter.obj `if test -f 'src/battlelistfilter.cpp'; then $(CYGPATH_W) 'src/battlelistfilter.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelistfilter.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelistfilter.Tpo $(DEPDIR)/battlelistfilter.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelistfilter.cpp' object='battlelistfilter.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelistfilter.obj `if test -f 'src/battlelistfilter.cpp'; then $(CYGPATH_W) 'src/battlelistfilter.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelistfilter.cpp'; fi`
+
+battlelist.o: src/battlelist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelist.o -MD -MP -MF $(DEPDIR)/battlelist.Tpo -c -o battlelist.o `test -f 'src/battlelist.cpp' || echo '$(srcdir)/'`src/battlelist.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelist.Tpo $(DEPDIR)/battlelist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelist.cpp' object='battlelist.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelist.o `test -f 'src/battlelist.cpp' || echo '$(srcdir)/'`src/battlelist.cpp
+
+battlelist.obj: src/battlelist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelist.obj -MD -MP -MF $(DEPDIR)/battlelist.Tpo -c -o battlelist.obj `if test -f 'src/battlelist.cpp'; then $(CYGPATH_W) 'src/battlelist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelist.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelist.Tpo $(DEPDIR)/battlelist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelist.cpp' object='battlelist.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelist.obj `if test -f 'src/battlelist.cpp'; then $(CYGPATH_W) 'src/battlelist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelist.cpp'; fi`
+
+battlelisttab.o: src/battlelisttab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelisttab.o -MD -MP -MF $(DEPDIR)/battlelisttab.Tpo -c -o battlelisttab.o `test -f 'src/battlelisttab.cpp' || echo '$(srcdir)/'`src/battlelisttab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelisttab.Tpo $(DEPDIR)/battlelisttab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelisttab.cpp' object='battlelisttab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelisttab.o `test -f 'src/battlelisttab.cpp' || echo '$(srcdir)/'`src/battlelisttab.cpp
+
+battlelisttab.obj: src/battlelisttab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlelisttab.obj -MD -MP -MF $(DEPDIR)/battlelisttab.Tpo -c -o battlelisttab.obj `if test -f 'src/battlelisttab.cpp'; then $(CYGPATH_W) 'src/battlelisttab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelisttab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlelisttab.Tpo $(DEPDIR)/battlelisttab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlelisttab.cpp' object='battlelisttab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlelisttab.obj `if test -f 'src/battlelisttab.cpp'; then $(CYGPATH_W) 'src/battlelisttab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlelisttab.cpp'; fi`
+
+battleroomlistctrl.o: src/battleroomlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battleroomlistctrl.o -MD -MP -MF $(DEPDIR)/battleroomlistctrl.Tpo -c -o battleroomlistctrl.o `test -f 'src/battleroomlistctrl.cpp' || echo '$(srcdir)/'`src/battleroomlistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battleroomlistctrl.Tpo $(DEPDIR)/battleroomlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battleroomlistctrl.cpp' object='battleroomlistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battleroomlistctrl.o `test -f 'src/battleroomlistctrl.cpp' || echo '$(srcdir)/'`src/battleroomlistctrl.cpp
+
+battleroomlistctrl.obj: src/battleroomlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battleroomlistctrl.obj -MD -MP -MF $(DEPDIR)/battleroomlistctrl.Tpo -c -o battleroomlistctrl.obj `if test -f 'src/battleroomlistctrl.cpp'; then $(CYGPATH_W) 'src/battleroomlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battleroomlistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battleroomlistctrl.Tpo $(DEPDIR)/battleroomlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battleroomlistctrl.cpp' object='battleroomlistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battleroomlistctrl.obj `if test -f 'src/battleroomlistctrl.cpp'; then $(CYGPATH_W) 'src/battleroomlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battleroomlistctrl.cpp'; fi`
+
+battlemaptab.o: src/battlemaptab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlemaptab.o -MD -MP -MF $(DEPDIR)/battlemaptab.Tpo -c -o battlemaptab.o `test -f 'src/battlemaptab.cpp' || echo '$(srcdir)/'`src/battlemaptab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlemaptab.Tpo $(DEPDIR)/battlemaptab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlemaptab.cpp' object='battlemaptab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlemaptab.o `test -f 'src/battlemaptab.cpp' || echo '$(srcdir)/'`src/battlemaptab.cpp
+
+battlemaptab.obj: src/battlemaptab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battlemaptab.obj -MD -MP -MF $(DEPDIR)/battlemaptab.Tpo -c -o battlemaptab.obj `if test -f 'src/battlemaptab.cpp'; then $(CYGPATH_W) 'src/battlemaptab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlemaptab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battlemaptab.Tpo $(DEPDIR)/battlemaptab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battlemaptab.cpp' object='battlemaptab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battlemaptab.obj `if test -f 'src/battlemaptab.cpp'; then $(CYGPATH_W) 'src/battlemaptab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battlemaptab.cpp'; fi`
+
+battleoptionstab.o: src/battleoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battleoptionstab.o -MD -MP -MF $(DEPDIR)/battleoptionstab.Tpo -c -o battleoptionstab.o `test -f 'src/battleoptionstab.cpp' || echo '$(srcdir)/'`src/battleoptionstab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battleoptionstab.Tpo $(DEPDIR)/battleoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battleoptionstab.cpp' object='battleoptionstab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battleoptionstab.o `test -f 'src/battleoptionstab.cpp' || echo '$(srcdir)/'`src/battleoptionstab.cpp
+
+battleoptionstab.obj: src/battleoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battleoptionstab.obj -MD -MP -MF $(DEPDIR)/battleoptionstab.Tpo -c -o battleoptionstab.obj `if test -f 'src/battleoptionstab.cpp'; then $(CYGPATH_W) 'src/battleoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battleoptionstab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battleoptionstab.Tpo $(DEPDIR)/battleoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battleoptionstab.cpp' object='battleoptionstab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battleoptionstab.obj `if test -f 'src/battleoptionstab.cpp'; then $(CYGPATH_W) 'src/battleoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battleoptionstab.cpp'; fi`
+
+battleroomtab.o: src/battleroomtab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battleroomtab.o -MD -MP -MF $(DEPDIR)/battleroomtab.Tpo -c -o battleroomtab.o `test -f 'src/battleroomtab.cpp' || echo '$(srcdir)/'`src/battleroomtab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battleroomtab.Tpo $(DEPDIR)/battleroomtab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battleroomtab.cpp' object='battleroomtab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battleroomtab.o `test -f 'src/battleroomtab.cpp' || echo '$(srcdir)/'`src/battleroomtab.cpp
+
+battleroomtab.obj: src/battleroomtab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT battleroomtab.obj -MD -MP -MF $(DEPDIR)/battleroomtab.Tpo -c -o battleroomtab.obj `if test -f 'src/battleroomtab.cpp'; then $(CYGPATH_W) 'src/battleroomtab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battleroomtab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/battleroomtab.Tpo $(DEPDIR)/battleroomtab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/battleroomtab.cpp' object='battleroomtab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o battleroomtab.obj `if test -f 'src/battleroomtab.cpp'; then $(CYGPATH_W) 'src/battleroomtab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/battleroomtab.cpp'; fi`
+
+crc.o: src/crc.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT crc.o -MD -MP -MF $(DEPDIR)/crc.Tpo -c -o crc.o `test -f 'src/crc.cpp' || echo '$(srcdir)/'`src/crc.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/crc.Tpo $(DEPDIR)/crc.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/crc.cpp' object='crc.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o crc.o `test -f 'src/crc.cpp' || echo '$(srcdir)/'`src/crc.cpp
+
+crc.obj: src/crc.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT crc.obj -MD -MP -MF $(DEPDIR)/crc.Tpo -c -o crc.obj `if test -f 'src/crc.cpp'; then $(CYGPATH_W) 'src/crc.cpp'; else $(CYGPATH_W) '$(srcdir)/src/crc.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/crc.Tpo $(DEPDIR)/crc.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/crc.cpp' object='crc.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o crc.obj `if test -f 'src/crc.cpp'; then $(CYGPATH_W) 'src/crc.cpp'; else $(CYGPATH_W) '$(srcdir)/src/crc.cpp'; fi`
+
+channel.o: src/channel/channel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channel.o -MD -MP -MF $(DEPDIR)/channel.Tpo -c -o channel.o `test -f 'src/channel/channel.cpp' || echo '$(srcdir)/'`src/channel/channel.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channel.Tpo $(DEPDIR)/channel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channel.cpp' object='channel.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channel.o `test -f 'src/channel/channel.cpp' || echo '$(srcdir)/'`src/channel/channel.cpp
+
+channel.obj: src/channel/channel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channel.obj -MD -MP -MF $(DEPDIR)/channel.Tpo -c -o channel.obj `if test -f 'src/channel/channel.cpp'; then $(CYGPATH_W) 'src/channel/channel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channel.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channel.Tpo $(DEPDIR)/channel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channel.cpp' object='channel.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channel.obj `if test -f 'src/channel/channel.cpp'; then $(CYGPATH_W) 'src/channel/channel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channel.cpp'; fi`
+
+channellist.o: src/channel/channellist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channellist.o -MD -MP -MF $(DEPDIR)/channellist.Tpo -c -o channellist.o `test -f 'src/channel/channellist.cpp' || echo '$(srcdir)/'`src/channel/channellist.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channellist.Tpo $(DEPDIR)/channellist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channellist.cpp' object='channellist.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channellist.o `test -f 'src/channel/channellist.cpp' || echo '$(srcdir)/'`src/channel/channellist.cpp
+
+channellist.obj: src/channel/channellist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channellist.obj -MD -MP -MF $(DEPDIR)/channellist.Tpo -c -o channellist.obj `if test -f 'src/channel/channellist.cpp'; then $(CYGPATH_W) 'src/channel/channellist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channellist.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channellist.Tpo $(DEPDIR)/channellist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channellist.cpp' object='channellist.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channellist.obj `if test -f 'src/channel/channellist.cpp'; then $(CYGPATH_W) 'src/channel/channellist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channellist.cpp'; fi`
+
+channellistctrl.o: src/channel/channellistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channellistctrl.o -MD -MP -MF $(DEPDIR)/channellistctrl.Tpo -c -o channellistctrl.o `test -f 'src/channel/channellistctrl.cpp' || echo '$(srcdir)/'`src/channel/channellistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channellistctrl.Tpo $(DEPDIR)/channellistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channellistctrl.cpp' object='channellistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channellistctrl.o `test -f 'src/channel/channellistctrl.cpp' || echo '$(srcdir)/'`src/channel/channellistctrl.cpp
+
+channellistctrl.obj: src/channel/channellistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channellistctrl.obj -MD -MP -MF $(DEPDIR)/channellistctrl.Tpo -c -o channellistctrl.obj `if test -f 'src/channel/channellistctrl.cpp'; then $(CYGPATH_W) 'src/channel/channellistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channellistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channellistctrl.Tpo $(DEPDIR)/channellistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channellistctrl.cpp' object='channellistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channellistctrl.obj `if test -f 'src/channel/channellistctrl.cpp'; then $(CYGPATH_W) 'src/channel/channellistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channellistctrl.cpp'; fi`
+
+chatoptionstab.o: src/chatoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT chatoptionstab.o -MD -MP -MF $(DEPDIR)/chatoptionstab.Tpo -c -o chatoptionstab.o `test -f 'src/chatoptionstab.cpp' || echo '$(srcdir)/'`src/chatoptionstab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/chatoptionstab.Tpo $(DEPDIR)/chatoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/chatoptionstab.cpp' object='chatoptionstab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o chatoptionstab.o `test -f 'src/chatoptionstab.cpp' || echo '$(srcdir)/'`src/chatoptionstab.cpp
+
+chatoptionstab.obj: src/chatoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT chatoptionstab.obj -MD -MP -MF $(DEPDIR)/chatoptionstab.Tpo -c -o chatoptionstab.obj `if test -f 'src/chatoptionstab.cpp'; then $(CYGPATH_W) 'src/chatoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/chatoptionstab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/chatoptionstab.Tpo $(DEPDIR)/chatoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/chatoptionstab.cpp' object='chatoptionstab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o chatoptionstab.obj `if test -f 'src/chatoptionstab.cpp'; then $(CYGPATH_W) 'src/chatoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/chatoptionstab.cpp'; fi`
+
+chatpanel.o: src/chatpanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT chatpanel.o -MD -MP -MF $(DEPDIR)/chatpanel.Tpo -c -o chatpanel.o `test -f 'src/chatpanel.cpp' || echo '$(srcdir)/'`src/chatpanel.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/chatpanel.Tpo $(DEPDIR)/chatpanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/chatpanel.cpp' object='chatpanel.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o chatpanel.o `test -f 'src/chatpanel.cpp' || echo '$(srcdir)/'`src/chatpanel.cpp
+
+chatpanel.obj: src/chatpanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT chatpanel.obj -MD -MP -MF $(DEPDIR)/chatpanel.Tpo -c -o chatpanel.obj `if test -f 'src/chatpanel.cpp'; then $(CYGPATH_W) 'src/chatpanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/chatpanel.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/chatpanel.Tpo $(DEPDIR)/chatpanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/chatpanel.cpp' object='chatpanel.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o chatpanel.obj `if test -f 'src/chatpanel.cpp'; then $(CYGPATH_W) 'src/chatpanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/chatpanel.cpp'; fi`
+
+connectwindow.o: src/connectwindow.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT connectwindow.o -MD -MP -MF $(DEPDIR)/connectwindow.Tpo -c -o connectwindow.o `test -f 'src/connectwindow.cpp' || echo '$(srcdir)/'`src/connectwindow.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/connectwindow.Tpo $(DEPDIR)/connectwindow.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/connectwindow.cpp' object='connectwindow.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o connectwindow.o `test -f 'src/connectwindow.cpp' || echo '$(srcdir)/'`src/connectwindow.cpp
+
+connectwindow.obj: src/connectwindow.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT connectwindow.obj -MD -MP -MF $(DEPDIR)/connectwindow.Tpo -c -o connectwindow.obj `if test -f 'src/connectwindow.cpp'; then $(CYGPATH_W) 'src/connectwindow.cpp'; else $(CYGPATH_W) '$(srcdir)/src/connectwindow.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/connectwindow.Tpo $(DEPDIR)/connectwindow.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/connectwindow.cpp' object='connectwindow.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o connectwindow.obj `if test -f 'src/connectwindow.cpp'; then $(CYGPATH_W) 'src/connectwindow.cpp'; else $(CYGPATH_W) '$(srcdir)/src/connectwindow.cpp'; fi`
+
+crashreport.o: src/crashreport.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT crashreport.o -MD -MP -MF $(DEPDIR)/crashreport.Tpo -c -o crashreport.o `test -f 'src/crashreport.cpp' || echo '$(srcdir)/'`src/crashreport.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/crashreport.Tpo $(DEPDIR)/crashreport.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/crashreport.cpp' object='crashreport.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o crashreport.o `test -f 'src/crashreport.cpp' || echo '$(srcdir)/'`src/crashreport.cpp
+
+crashreport.obj: src/crashreport.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT crashreport.obj -MD -MP -MF $(DEPDIR)/crashreport.Tpo -c -o crashreport.obj `if test -f 'src/crashreport.cpp'; then $(CYGPATH_W) 'src/crashreport.cpp'; else $(CYGPATH_W) '$(srcdir)/src/crashreport.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/crashreport.Tpo $(DEPDIR)/crashreport.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/crashreport.cpp' object='crashreport.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o crashreport.obj `if test -f 'src/crashreport.cpp'; then $(CYGPATH_W) 'src/crashreport.cpp'; else $(CYGPATH_W) '$(srcdir)/src/crashreport.cpp'; fi`
+
+countrycodes.o: src/countrycodes.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT countrycodes.o -MD -MP -MF $(DEPDIR)/countrycodes.Tpo -c -o countrycodes.o `test -f 'src/countrycodes.cpp' || echo '$(srcdir)/'`src/countrycodes.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/countrycodes.Tpo $(DEPDIR)/countrycodes.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/countrycodes.cpp' object='countrycodes.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o countrycodes.o `test -f 'src/countrycodes.cpp' || echo '$(srcdir)/'`src/countrycodes.cpp
+
+countrycodes.obj: src/countrycodes.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT countrycodes.obj -MD -MP -MF $(DEPDIR)/countrycodes.Tpo -c -o countrycodes.obj `if test -f 'src/countrycodes.cpp'; then $(CYGPATH_W) 'src/countrycodes.cpp'; else $(CYGPATH_W) '$(srcdir)/src/countrycodes.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/countrycodes.Tpo $(DEPDIR)/countrycodes.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/countrycodes.cpp' object='countrycodes.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o countrycodes.obj `if test -f 'src/countrycodes.cpp'; then $(CYGPATH_W) 'src/countrycodes.cpp'; else $(CYGPATH_W) '$(srcdir)/src/countrycodes.cpp'; fi`
+
+flagimages.o: src/flagimages.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT flagimages.o -MD -MP -MF $(DEPDIR)/flagimages.Tpo -c -o flagimages.o `test -f 'src/flagimages.cpp' || echo '$(srcdir)/'`src/flagimages.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/flagimages.Tpo $(DEPDIR)/flagimages.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/flagimages.cpp' object='flagimages.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o flagimages.o `test -f 'src/flagimages.cpp' || echo '$(srcdir)/'`src/flagimages.cpp
+
+flagimages.obj: src/flagimages.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT flagimages.obj -MD -MP -MF $(DEPDIR)/flagimages.Tpo -c -o flagimages.obj `if test -f 'src/flagimages.cpp'; then $(CYGPATH_W) 'src/flagimages.cpp'; else $(CYGPATH_W) '$(srcdir)/src/flagimages.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/flagimages.Tpo $(DEPDIR)/flagimages.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/flagimages.cpp' object='flagimages.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o flagimages.obj `if test -f 'src/flagimages.cpp'; then $(CYGPATH_W) 'src/flagimages.cpp'; else $(CYGPATH_W) '$(srcdir)/src/flagimages.cpp'; fi`
+
+hostbattledialog.o: src/hostbattledialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT hostbattledialog.o -MD -MP -MF $(DEPDIR)/hostbattledialog.Tpo -c -o hostbattledialog.o `test -f 'src/hostbattledialog.cpp' || echo '$(srcdir)/'`src/hostbattledialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/hostbattledialog.Tpo $(DEPDIR)/hostbattledialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/hostbattledialog.cpp' object='hostbattledialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o hostbattledialog.o `test -f 'src/hostbattledialog.cpp' || echo '$(srcdir)/'`src/hostbattledialog.cpp
+
+hostbattledialog.obj: src/hostbattledialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT hostbattledialog.obj -MD -MP -MF $(DEPDIR)/hostbattledialog.Tpo -c -o hostbattledialog.obj `if test -f 'src/hostbattledialog.cpp'; then $(CYGPATH_W) 'src/hostbattledialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/hostbattledialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/hostbattledialog.Tpo $(DEPDIR)/hostbattledialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/hostbattledialog.cpp' object='hostbattledialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o hostbattledialog.obj `if test -f 'src/hostbattledialog.cpp'; then $(CYGPATH_W) 'src/hostbattledialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/hostbattledialog.cpp'; fi`
+
+iconimagelist.o: src/iconimagelist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT iconimagelist.o -MD -MP -MF $(DEPDIR)/iconimagelist.Tpo -c -o iconimagelist.o `test -f 'src/iconimagelist.cpp' || echo '$(srcdir)/'`src/iconimagelist.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/iconimagelist.Tpo $(DEPDIR)/iconimagelist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/iconimagelist.cpp' object='iconimagelist.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o iconimagelist.o `test -f 'src/iconimagelist.cpp' || echo '$(srcdir)/'`src/iconimagelist.cpp
+
+iconimagelist.obj: src/iconimagelist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT iconimagelist.obj -MD -MP -MF $(DEPDIR)/iconimagelist.Tpo -c -o iconimagelist.obj `if test -f 'src/iconimagelist.cpp'; then $(CYGPATH_W) 'src/iconimagelist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/iconimagelist.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/iconimagelist.Tpo $(DEPDIR)/iconimagelist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/iconimagelist.cpp' object='iconimagelist.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o iconimagelist.obj `if test -f 'src/iconimagelist.cpp'; then $(CYGPATH_W) 'src/iconimagelist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/iconimagelist.cpp'; fi`
+
+mainchattab.o: src/mainchattab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainchattab.o -MD -MP -MF $(DEPDIR)/mainchattab.Tpo -c -o mainchattab.o `test -f 'src/mainchattab.cpp' || echo '$(srcdir)/'`src/mainchattab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainchattab.Tpo $(DEPDIR)/mainchattab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainchattab.cpp' object='mainchattab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainchattab.o `test -f 'src/mainchattab.cpp' || echo '$(srcdir)/'`src/mainchattab.cpp
+
+mainchattab.obj: src/mainchattab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainchattab.obj -MD -MP -MF $(DEPDIR)/mainchattab.Tpo -c -o mainchattab.obj `if test -f 'src/mainchattab.cpp'; then $(CYGPATH_W) 'src/mainchattab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainchattab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainchattab.Tpo $(DEPDIR)/mainchattab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainchattab.cpp' object='mainchattab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainchattab.obj `if test -f 'src/mainchattab.cpp'; then $(CYGPATH_W) 'src/mainchattab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainchattab.cpp'; fi`
+
+mainjoinbattletab.o: src/mainjoinbattletab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainjoinbattletab.o -MD -MP -MF $(DEPDIR)/mainjoinbattletab.Tpo -c -o mainjoinbattletab.o `test -f 'src/mainjoinbattletab.cpp' || echo '$(srcdir)/'`src/mainjoinbattletab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainjoinbattletab.Tpo $(DEPDIR)/mainjoinbattletab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainjoinbattletab.cpp' object='mainjoinbattletab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainjoinbattletab.o `test -f 'src/mainjoinbattletab.cpp' || echo '$(srcdir)/'`src/mainjoinbattletab.cpp
+
+mainjoinbattletab.obj: src/mainjoinbattletab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainjoinbattletab.obj -MD -MP -MF $(DEPDIR)/mainjoinbattletab.Tpo -c -o mainjoinbattletab.obj `if test -f 'src/mainjoinbattletab.cpp'; then $(CYGPATH_W) 'src/mainjoinbattletab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainjoinbattletab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainjoinbattletab.Tpo $(DEPDIR)/mainjoinbattletab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainjoinbattletab.cpp' object='mainjoinbattletab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainjoinbattletab.obj `if test -f 'src/mainjoinbattletab.cpp'; then $(CYGPATH_W) 'src/mainjoinbattletab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainjoinbattletab.cpp'; fi`
+
+mainoptionstab.o: src/mainoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainoptionstab.o -MD -MP -MF $(DEPDIR)/mainoptionstab.Tpo -c -o mainoptionstab.o `test -f 'src/mainoptionstab.cpp' || echo '$(srcdir)/'`src/mainoptionstab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainoptionstab.Tpo $(DEPDIR)/mainoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainoptionstab.cpp' object='mainoptionstab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainoptionstab.o `test -f 'src/mainoptionstab.cpp' || echo '$(srcdir)/'`src/mainoptionstab.cpp
+
+mainoptionstab.obj: src/mainoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainoptionstab.obj -MD -MP -MF $(DEPDIR)/mainoptionstab.Tpo -c -o mainoptionstab.obj `if test -f 'src/mainoptionstab.cpp'; then $(CYGPATH_W) 'src/mainoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainoptionstab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainoptionstab.Tpo $(DEPDIR)/mainoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainoptionstab.cpp' object='mainoptionstab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainoptionstab.obj `if test -f 'src/mainoptionstab.cpp'; then $(CYGPATH_W) 'src/mainoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainoptionstab.cpp'; fi`
+
+mainsingleplayertab.o: src/mainsingleplayertab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainsingleplayertab.o -MD -MP -MF $(DEPDIR)/mainsingleplayertab.Tpo -c -o mainsingleplayertab.o `test -f 'src/mainsingleplayertab.cpp' || echo '$(srcdir)/'`src/mainsingleplayertab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainsingleplayertab.Tpo $(DEPDIR)/mainsingleplayertab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainsingleplayertab.cpp' object='mainsingleplayertab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainsingleplayertab.o `test -f 'src/mainsingleplayertab.cpp' || echo '$(srcdir)/'`src/mainsingleplayertab.cpp
+
+mainsingleplayertab.obj: src/mainsingleplayertab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainsingleplayertab.obj -MD -MP -MF $(DEPDIR)/mainsingleplayertab.Tpo -c -o mainsingleplayertab.obj `if test -f 'src/mainsingleplayertab.cpp'; then $(CYGPATH_W) 'src/mainsingleplayertab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainsingleplayertab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainsingleplayertab.Tpo $(DEPDIR)/mainsingleplayertab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainsingleplayertab.cpp' object='mainsingleplayertab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainsingleplayertab.obj `if test -f 'src/mainsingleplayertab.cpp'; then $(CYGPATH_W) 'src/mainsingleplayertab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainsingleplayertab.cpp'; fi`
+
+mainwindow.o: src/mainwindow.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainwindow.o -MD -MP -MF $(DEPDIR)/mainwindow.Tpo -c -o mainwindow.o `test -f 'src/mainwindow.cpp' || echo '$(srcdir)/'`src/mainwindow.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainwindow.Tpo $(DEPDIR)/mainwindow.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainwindow.cpp' object='mainwindow.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainwindow.o `test -f 'src/mainwindow.cpp' || echo '$(srcdir)/'`src/mainwindow.cpp
+
+mainwindow.obj: src/mainwindow.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainwindow.obj -MD -MP -MF $(DEPDIR)/mainwindow.Tpo -c -o mainwindow.obj `if test -f 'src/mainwindow.cpp'; then $(CYGPATH_W) 'src/mainwindow.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainwindow.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mainwindow.Tpo $(DEPDIR)/mainwindow.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mainwindow.cpp' object='mainwindow.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainwindow.obj `if test -f 'src/mainwindow.cpp'; then $(CYGPATH_W) 'src/mainwindow.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mainwindow.cpp'; fi`
+
+mapctrl.o: src/mapctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mapctrl.o -MD -MP -MF $(DEPDIR)/mapctrl.Tpo -c -o mapctrl.o `test -f 'src/mapctrl.cpp' || echo '$(srcdir)/'`src/mapctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mapctrl.Tpo $(DEPDIR)/mapctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mapctrl.cpp' object='mapctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mapctrl.o `test -f 'src/mapctrl.cpp' || echo '$(srcdir)/'`src/mapctrl.cpp
+
+mapctrl.obj: src/mapctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mapctrl.obj -MD -MP -MF $(DEPDIR)/mapctrl.Tpo -c -o mapctrl.obj `if test -f 'src/mapctrl.cpp'; then $(CYGPATH_W) 'src/mapctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mapctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mapctrl.Tpo $(DEPDIR)/mapctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mapctrl.cpp' object='mapctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mapctrl.obj `if test -f 'src/mapctrl.cpp'; then $(CYGPATH_W) 'src/mapctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mapctrl.cpp'; fi`
+
+offlinebattle.o: src/offlinebattle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT offlinebattle.o -MD -MP -MF $(DEPDIR)/offlinebattle.Tpo -c -o offlinebattle.o `test -f 'src/offlinebattle.cpp' || echo '$(srcdir)/'`src/offlinebattle.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/offlinebattle.Tpo $(DEPDIR)/offlinebattle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/offlinebattle.cpp' object='offlinebattle.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o offlinebattle.o `test -f 'src/offlinebattle.cpp' || echo '$(srcdir)/'`src/offlinebattle.cpp
+
+offlinebattle.obj: src/offlinebattle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT offlinebattle.obj -MD -MP -MF $(DEPDIR)/offlinebattle.Tpo -c -o offlinebattle.obj `if test -f 'src/offlinebattle.cpp'; then $(CYGPATH_W) 'src/offlinebattle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/offlinebattle.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/offlinebattle.Tpo $(DEPDIR)/offlinebattle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/offlinebattle.cpp' object='offlinebattle.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o offlinebattle.obj `if test -f 'src/offlinebattle.cpp'; then $(CYGPATH_W) 'src/offlinebattle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/offlinebattle.cpp'; fi`
+
+nicklistctrl.o: src/nicklistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT nicklistctrl.o -MD -MP -MF $(DEPDIR)/nicklistctrl.Tpo -c -o nicklistctrl.o `test -f 'src/nicklistctrl.cpp' || echo '$(srcdir)/'`src/nicklistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/nicklistctrl.Tpo $(DEPDIR)/nicklistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/nicklistctrl.cpp' object='nicklistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o nicklistctrl.o `test -f 'src/nicklistctrl.cpp' || echo '$(srcdir)/'`src/nicklistctrl.cpp
+
+nicklistctrl.obj: src/nicklistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT nicklistctrl.obj -MD -MP -MF $(DEPDIR)/nicklistctrl.Tpo -c -o nicklistctrl.obj `if test -f 'src/nicklistctrl.cpp'; then $(CYGPATH_W) 'src/nicklistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/nicklistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/nicklistctrl.Tpo $(DEPDIR)/nicklistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/nicklistctrl.cpp' object='nicklistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o nicklistctrl.obj `if test -f 'src/nicklistctrl.cpp'; then $(CYGPATH_W) 'src/nicklistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/nicklistctrl.cpp'; fi`
+
+replaylist.o: src/playback/replaylist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT replaylist.o -MD -MP -MF $(DEPDIR)/replaylist.Tpo -c -o replaylist.o `test -f 'src/playback/replaylist.cpp' || echo '$(srcdir)/'`src/playback/replaylist.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/replaylist.Tpo $(DEPDIR)/replaylist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/playback/replaylist.cpp' object='replaylist.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o replaylist.o `test -f 'src/playback/replaylist.cpp' || echo '$(srcdir)/'`src/playback/replaylist.cpp
+
+replaylist.obj: src/playback/replaylist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT replaylist.obj -MD -MP -MF $(DEPDIR)/replaylist.Tpo -c -o replaylist.obj `if test -f 'src/playback/replaylist.cpp'; then $(CYGPATH_W) 'src/playback/replaylist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/playback/replaylist.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/replaylist.Tpo $(DEPDIR)/replaylist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/playback/replaylist.cpp' object='replaylist.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o replaylist.obj `if test -f 'src/playback/replaylist.cpp'; then $(CYGPATH_W) 'src/playback/replaylist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/playback/replaylist.cpp'; fi`
+
+sdlsound.o: src/sdlsound.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sdlsound.o -MD -MP -MF $(DEPDIR)/sdlsound.Tpo -c -o sdlsound.o `test -f 'src/sdlsound.cpp' || echo '$(srcdir)/'`src/sdlsound.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/sdlsound.Tpo $(DEPDIR)/sdlsound.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/sdlsound.cpp' object='sdlsound.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sdlsound.o `test -f 'src/sdlsound.cpp' || echo '$(srcdir)/'`src/sdlsound.cpp
+
+sdlsound.obj: src/sdlsound.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sdlsound.obj -MD -MP -MF $(DEPDIR)/sdlsound.Tpo -c -o sdlsound.obj `if test -f 'src/sdlsound.cpp'; then $(CYGPATH_W) 'src/sdlsound.cpp'; else $(CYGPATH_W) '$(srcdir)/src/sdlsound.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/sdlsound.Tpo $(DEPDIR)/sdlsound.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/sdlsound.cpp' object='sdlsound.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sdlsound.obj `if test -f 'src/sdlsound.cpp'; then $(CYGPATH_W) 'src/sdlsound.cpp'; else $(CYGPATH_W) '$(srcdir)/src/sdlsound.cpp'; fi`
+
+server.o: src/server.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT server.o -MD -MP -MF $(DEPDIR)/server.Tpo -c -o server.o `test -f 'src/server.cpp' || echo '$(srcdir)/'`src/server.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/server.Tpo $(DEPDIR)/server.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/server.cpp' object='server.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o server.o `test -f 'src/server.cpp' || echo '$(srcdir)/'`src/server.cpp
+
+server.obj: src/server.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT server.obj -MD -MP -MF $(DEPDIR)/server.Tpo -c -o server.obj `if test -f 'src/server.cpp'; then $(CYGPATH_W) 'src/server.cpp'; else $(CYGPATH_W) '$(srcdir)/src/server.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/server.Tpo $(DEPDIR)/server.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/server.cpp' object='server.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o server.obj `if test -f 'src/server.cpp'; then $(CYGPATH_W) 'src/server.cpp'; else $(CYGPATH_W) '$(srcdir)/src/server.cpp'; fi`
+
+serverevents.o: src/serverevents.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT serverevents.o -MD -MP -MF $(DEPDIR)/serverevents.Tpo -c -o serverevents.o `test -f 'src/serverevents.cpp' || echo '$(srcdir)/'`src/serverevents.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/serverevents.Tpo $(DEPDIR)/serverevents.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/serverevents.cpp' object='serverevents.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o serverevents.o `test -f 'src/serverevents.cpp' || echo '$(srcdir)/'`src/serverevents.cpp
+
+serverevents.obj: src/serverevents.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT serverevents.obj -MD -MP -MF $(DEPDIR)/serverevents.Tpo -c -o serverevents.obj `if test -f 'src/serverevents.cpp'; then $(CYGPATH_W) 'src/serverevents.cpp'; else $(CYGPATH_W) '$(srcdir)/src/serverevents.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/serverevents.Tpo $(DEPDIR)/serverevents.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/serverevents.cpp' object='serverevents.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o serverevents.obj `if test -f 'src/serverevents.cpp'; then $(CYGPATH_W) 'src/serverevents.cpp'; else $(CYGPATH_W) '$(srcdir)/src/serverevents.cpp'; fi`
+
+settings.o: src/settings.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT settings.o -MD -MP -MF $(DEPDIR)/settings.Tpo -c -o settings.o `test -f 'src/settings.cpp' || echo '$(srcdir)/'`src/settings.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/settings.Tpo $(DEPDIR)/settings.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings.cpp' object='settings.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o settings.o `test -f 'src/settings.cpp' || echo '$(srcdir)/'`src/settings.cpp
+
+settings.obj: src/settings.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT settings.obj -MD -MP -MF $(DEPDIR)/settings.Tpo -c -o settings.obj `if test -f 'src/settings.cpp'; then $(CYGPATH_W) 'src/settings.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/settings.Tpo $(DEPDIR)/settings.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings.cpp' object='settings.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o settings.obj `if test -f 'src/settings.cpp'; then $(CYGPATH_W) 'src/settings.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings.cpp'; fi`
+
+socket.o: src/socket.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT socket.o -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.o `test -f 'src/socket.cpp' || echo '$(srcdir)/'`src/socket.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/socket.cpp' object='socket.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o socket.o `test -f 'src/socket.cpp' || echo '$(srcdir)/'`src/socket.cpp
+
+socket.obj: src/socket.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT socket.obj -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.obj `if test -f 'src/socket.cpp'; then $(CYGPATH_W) 'src/socket.cpp'; else $(CYGPATH_W) '$(srcdir)/src/socket.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/socket.cpp' object='socket.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o socket.obj `if test -f 'src/socket.cpp'; then $(CYGPATH_W) 'src/socket.cpp'; else $(CYGPATH_W) '$(srcdir)/src/socket.cpp'; fi`
+
+spring.o: src/spring.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT spring.o -MD -MP -MF $(DEPDIR)/spring.Tpo -c -o spring.o `test -f 'src/spring.cpp' || echo '$(srcdir)/'`src/spring.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/spring.Tpo $(DEPDIR)/spring.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/spring.cpp' object='spring.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o spring.o `test -f 'src/spring.cpp' || echo '$(srcdir)/'`src/spring.cpp
+
+spring.obj: src/spring.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT spring.obj -MD -MP -MF $(DEPDIR)/spring.Tpo -c -o spring.obj `if test -f 'src/spring.cpp'; then $(CYGPATH_W) 'src/spring.cpp'; else $(CYGPATH_W) '$(srcdir)/src/spring.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/spring.Tpo $(DEPDIR)/spring.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/spring.cpp' object='spring.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o spring.obj `if test -f 'src/spring.cpp'; then $(CYGPATH_W) 'src/spring.cpp'; else $(CYGPATH_W) '$(srcdir)/src/spring.cpp'; fi`
+
+singleplayerbattle.o: src/singleplayerbattle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT singleplayerbattle.o -MD -MP -MF $(DEPDIR)/singleplayerbattle.Tpo -c -o singleplayerbattle.o `test -f 'src/singleplayerbattle.cpp' || echo '$(srcdir)/'`src/singleplayerbattle.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/singleplayerbattle.Tpo $(DEPDIR)/singleplayerbattle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/singleplayerbattle.cpp' object='singleplayerbattle.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o singleplayerbattle.o `test -f 'src/singleplayerbattle.cpp' || echo '$(srcdir)/'`src/singleplayerbattle.cpp
+
+singleplayerbattle.obj: src/singleplayerbattle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT singleplayerbattle.obj -MD -MP -MF $(DEPDIR)/singleplayerbattle.Tpo -c -o singleplayerbattle.obj `if test -f 'src/singleplayerbattle.cpp'; then $(CYGPATH_W) 'src/singleplayerbattle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/singleplayerbattle.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/singleplayerbattle.Tpo $(DEPDIR)/singleplayerbattle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/singleplayerbattle.cpp' object='singleplayerbattle.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o singleplayerbattle.obj `if test -f 'src/singleplayerbattle.cpp'; then $(CYGPATH_W) 'src/singleplayerbattle.cpp'; else $(CYGPATH_W) '$(srcdir)/src/singleplayerbattle.cpp'; fi`
+
+singleplayertab.o: src/singleplayertab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT singleplayertab.o -MD -MP -MF $(DEPDIR)/singleplayertab.Tpo -c -o singleplayertab.o `test -f 'src/singleplayertab.cpp' || echo '$(srcdir)/'`src/singleplayertab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/singleplayertab.Tpo $(DEPDIR)/singleplayertab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/singleplayertab.cpp' object='singleplayertab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o singleplayertab.o `test -f 'src/singleplayertab.cpp' || echo '$(srcdir)/'`src/singleplayertab.cpp
+
+singleplayertab.obj: src/singleplayertab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT singleplayertab.obj -MD -MP -MF $(DEPDIR)/singleplayertab.Tpo -c -o singleplayertab.obj `if test -f 'src/singleplayertab.cpp'; then $(CYGPATH_W) 'src/singleplayertab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/singleplayertab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/singleplayertab.Tpo $(DEPDIR)/singleplayertab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/singleplayertab.cpp' object='singleplayertab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o singleplayertab.obj `if test -f 'src/singleplayertab.cpp'; then $(CYGPATH_W) 'src/singleplayertab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/singleplayertab.cpp'; fi`
+
+springlobbyapp.o: src/springlobbyapp.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springlobbyapp.o -MD -MP -MF $(DEPDIR)/springlobbyapp.Tpo -c -o springlobbyapp.o `test -f 'src/springlobbyapp.cpp' || echo '$(srcdir)/'`src/springlobbyapp.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springlobbyapp.Tpo $(DEPDIR)/springlobbyapp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springlobbyapp.cpp' object='springlobbyapp.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springlobbyapp.o `test -f 'src/springlobbyapp.cpp' || echo '$(srcdir)/'`src/springlobbyapp.cpp
+
+springlobbyapp.obj: src/springlobbyapp.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springlobbyapp.obj -MD -MP -MF $(DEPDIR)/springlobbyapp.Tpo -c -o springlobbyapp.obj `if test -f 'src/springlobbyapp.cpp'; then $(CYGPATH_W) 'src/springlobbyapp.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springlobbyapp.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springlobbyapp.Tpo $(DEPDIR)/springlobbyapp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springlobbyapp.cpp' object='springlobbyapp.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springlobbyapp.obj `if test -f 'src/springlobbyapp.cpp'; then $(CYGPATH_W) 'src/springlobbyapp.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springlobbyapp.cpp'; fi`
+
+springoptionstab.o: src/springoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springoptionstab.o -MD -MP -MF $(DEPDIR)/springoptionstab.Tpo -c -o springoptionstab.o `test -f 'src/springoptionstab.cpp' || echo '$(srcdir)/'`src/springoptionstab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springoptionstab.Tpo $(DEPDIR)/springoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springoptionstab.cpp' object='springoptionstab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springoptionstab.o `test -f 'src/springoptionstab.cpp' || echo '$(srcdir)/'`src/springoptionstab.cpp
+
+springoptionstab.obj: src/springoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springoptionstab.obj -MD -MP -MF $(DEPDIR)/springoptionstab.Tpo -c -o springoptionstab.obj `if test -f 'src/springoptionstab.cpp'; then $(CYGPATH_W) 'src/springoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springoptionstab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springoptionstab.Tpo $(DEPDIR)/springoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springoptionstab.cpp' object='springoptionstab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springoptionstab.obj `if test -f 'src/springoptionstab.cpp'; then $(CYGPATH_W) 'src/springoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springoptionstab.cpp'; fi`
+
+springprocess.o: src/springprocess.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springprocess.o -MD -MP -MF $(DEPDIR)/springprocess.Tpo -c -o springprocess.o `test -f 'src/springprocess.cpp' || echo '$(srcdir)/'`src/springprocess.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springprocess.Tpo $(DEPDIR)/springprocess.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springprocess.cpp' object='springprocess.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springprocess.o `test -f 'src/springprocess.cpp' || echo '$(srcdir)/'`src/springprocess.cpp
+
+springprocess.obj: src/springprocess.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springprocess.obj -MD -MP -MF $(DEPDIR)/springprocess.Tpo -c -o springprocess.obj `if test -f 'src/springprocess.cpp'; then $(CYGPATH_W) 'src/springprocess.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springprocess.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springprocess.Tpo $(DEPDIR)/springprocess.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springprocess.cpp' object='springprocess.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springprocess.obj `if test -f 'src/springprocess.cpp'; then $(CYGPATH_W) 'src/springprocess.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springprocess.cpp'; fi`
+
+springunitsync.o: src/springunitsync.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springunitsync.o -MD -MP -MF $(DEPDIR)/springunitsync.Tpo -c -o springunitsync.o `test -f 'src/springunitsync.cpp' || echo '$(srcdir)/'`src/springunitsync.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springunitsync.Tpo $(DEPDIR)/springunitsync.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springunitsync.cpp' object='springunitsync.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springunitsync.o `test -f 'src/springunitsync.cpp' || echo '$(srcdir)/'`src/springunitsync.cpp
+
+springunitsync.obj: src/springunitsync.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT springunitsync.obj -MD -MP -MF $(DEPDIR)/springunitsync.Tpo -c -o springunitsync.obj `if test -f 'src/springunitsync.cpp'; then $(CYGPATH_W) 'src/springunitsync.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springunitsync.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/springunitsync.Tpo $(DEPDIR)/springunitsync.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/springunitsync.cpp' object='springunitsync.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o springunitsync.obj `if test -f 'src/springunitsync.cpp'; then $(CYGPATH_W) 'src/springunitsync.cpp'; else $(CYGPATH_W) '$(srcdir)/src/springunitsync.cpp'; fi`
+
+tasserver.o: src/tasserver.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tasserver.o -MD -MP -MF $(DEPDIR)/tasserver.Tpo -c -o tasserver.o `test -f 'src/tasserver.cpp' || echo '$(srcdir)/'`src/tasserver.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tasserver.Tpo $(DEPDIR)/tasserver.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tasserver.cpp' object='tasserver.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tasserver.o `test -f 'src/tasserver.cpp' || echo '$(srcdir)/'`src/tasserver.cpp
+
+tasserver.obj: src/tasserver.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tasserver.obj -MD -MP -MF $(DEPDIR)/tasserver.Tpo -c -o tasserver.obj `if test -f 'src/tasserver.cpp'; then $(CYGPATH_W) 'src/tasserver.cpp'; else $(CYGPATH_W) '$(srcdir)/src/tasserver.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tasserver.Tpo $(DEPDIR)/tasserver.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tasserver.cpp' object='tasserver.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tasserver.obj `if test -f 'src/tasserver.cpp'; then $(CYGPATH_W) 'src/tasserver.cpp'; else $(CYGPATH_W) '$(srcdir)/src/tasserver.cpp'; fi`
+
+ui.o: src/ui.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ui.o -MD -MP -MF $(DEPDIR)/ui.Tpo -c -o ui.o `test -f 'src/ui.cpp' || echo '$(srcdir)/'`src/ui.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ui.Tpo $(DEPDIR)/ui.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/ui.cpp' object='ui.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ui.o `test -f 'src/ui.cpp' || echo '$(srcdir)/'`src/ui.cpp
+
+ui.obj: src/ui.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ui.obj -MD -MP -MF $(DEPDIR)/ui.Tpo -c -o ui.obj `if test -f 'src/ui.cpp'; then $(CYGPATH_W) 'src/ui.cpp'; else $(CYGPATH_W) '$(srcdir)/src/ui.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ui.Tpo $(DEPDIR)/ui.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/ui.cpp' object='ui.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ui.obj `if test -f 'src/ui.cpp'; then $(CYGPATH_W) 'src/ui.cpp'; else $(CYGPATH_W) '$(srcdir)/src/ui.cpp'; fi`
+
+uiutils.o: src/uiutils.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT uiutils.o -MD -MP -MF $(DEPDIR)/uiutils.Tpo -c -o uiutils.o `test -f 'src/uiutils.cpp' || echo '$(srcdir)/'`src/uiutils.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/uiutils.Tpo $(DEPDIR)/uiutils.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/uiutils.cpp' object='uiutils.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o uiutils.o `test -f 'src/uiutils.cpp' || echo '$(srcdir)/'`src/uiutils.cpp
+
+uiutils.obj: src/uiutils.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT uiutils.obj -MD -MP -MF $(DEPDIR)/uiutils.Tpo -c -o uiutils.obj `if test -f 'src/uiutils.cpp'; then $(CYGPATH_W) 'src/uiutils.cpp'; else $(CYGPATH_W) '$(srcdir)/src/uiutils.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/uiutils.Tpo $(DEPDIR)/uiutils.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/uiutils.cpp' object='uiutils.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o uiutils.obj `if test -f 'src/uiutils.cpp'; then $(CYGPATH_W) 'src/uiutils.cpp'; else $(CYGPATH_W) '$(srcdir)/src/uiutils.cpp'; fi`
+
+user.o: src/user.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT user.o -MD -MP -MF $(DEPDIR)/user.Tpo -c -o user.o `test -f 'src/user.cpp' || echo '$(srcdir)/'`src/user.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/user.Tpo $(DEPDIR)/user.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/user.cpp' object='user.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o user.o `test -f 'src/user.cpp' || echo '$(srcdir)/'`src/user.cpp
+
+user.obj: src/user.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT user.obj -MD -MP -MF $(DEPDIR)/user.Tpo -c -o user.obj `if test -f 'src/user.cpp'; then $(CYGPATH_W) 'src/user.cpp'; else $(CYGPATH_W) '$(srcdir)/src/user.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/user.Tpo $(DEPDIR)/user.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/user.cpp' object='user.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o user.obj `if test -f 'src/user.cpp'; then $(CYGPATH_W) 'src/user.cpp'; else $(CYGPATH_W) '$(srcdir)/src/user.cpp'; fi`
+
+userlist.o: src/userlist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT userlist.o -MD -MP -MF $(DEPDIR)/userlist.Tpo -c -o userlist.o `test -f 'src/userlist.cpp' || echo '$(srcdir)/'`src/userlist.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/userlist.Tpo $(DEPDIR)/userlist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/userlist.cpp' object='userlist.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o userlist.o `test -f 'src/userlist.cpp' || echo '$(srcdir)/'`src/userlist.cpp
+
+userlist.obj: src/userlist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT userlist.obj -MD -MP -MF $(DEPDIR)/userlist.Tpo -c -o userlist.obj `if test -f 'src/userlist.cpp'; then $(CYGPATH_W) 'src/userlist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/userlist.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/userlist.Tpo $(DEPDIR)/userlist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/userlist.cpp' object='userlist.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o userlist.obj `if test -f 'src/userlist.cpp'; then $(CYGPATH_W) 'src/userlist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/userlist.cpp'; fi`
+
+userlistctrl.o: src/userlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT userlistctrl.o -MD -MP -MF $(DEPDIR)/userlistctrl.Tpo -c -o userlistctrl.o `test -f 'src/userlistctrl.cpp' || echo '$(srcdir)/'`src/userlistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/userlistctrl.Tpo $(DEPDIR)/userlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/userlistctrl.cpp' object='userlistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o userlistctrl.o `test -f 'src/userlistctrl.cpp' || echo '$(srcdir)/'`src/userlistctrl.cpp
+
+userlistctrl.obj: src/userlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT userlistctrl.obj -MD -MP -MF $(DEPDIR)/userlistctrl.Tpo -c -o userlistctrl.obj `if test -f 'src/userlistctrl.cpp'; then $(CYGPATH_W) 'src/userlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/userlistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/userlistctrl.Tpo $(DEPDIR)/userlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/userlistctrl.cpp' object='userlistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o userlistctrl.obj `if test -f 'src/userlistctrl.cpp'; then $(CYGPATH_W) 'src/userlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/userlistctrl.cpp'; fi`
+
+torrentlistctrl.o: src/torrentlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrentlistctrl.o -MD -MP -MF $(DEPDIR)/torrentlistctrl.Tpo -c -o torrentlistctrl.o `test -f 'src/torrentlistctrl.cpp' || echo '$(srcdir)/'`src/torrentlistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrentlistctrl.Tpo $(DEPDIR)/torrentlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/torrentlistctrl.cpp' object='torrentlistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrentlistctrl.o `test -f 'src/torrentlistctrl.cpp' || echo '$(srcdir)/'`src/torrentlistctrl.cpp
+
+torrentlistctrl.obj: src/torrentlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrentlistctrl.obj -MD -MP -MF $(DEPDIR)/torrentlistctrl.Tpo -c -o torrentlistctrl.obj `if test -f 'src/torrentlistctrl.cpp'; then $(CYGPATH_W) 'src/torrentlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/torrentlistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrentlistctrl.Tpo $(DEPDIR)/torrentlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/torrentlistctrl.cpp' object='torrentlistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrentlistctrl.obj `if test -f 'src/torrentlistctrl.cpp'; then $(CYGPATH_W) 'src/torrentlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/torrentlistctrl.cpp'; fi`
+
+torrentoptionspanel.o: src/torrentoptionspanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrentoptionspanel.o -MD -MP -MF $(DEPDIR)/torrentoptionspanel.Tpo -c -o torrentoptionspanel.o `test -f 'src/torrentoptionspanel.cpp' || echo '$(srcdir)/'`src/torrentoptionspanel.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrentoptionspanel.Tpo $(DEPDIR)/torrentoptionspanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/torrentoptionspanel.cpp' object='torrentoptionspanel.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrentoptionspanel.o `test -f 'src/torrentoptionspanel.cpp' || echo '$(srcdir)/'`src/torrentoptionspanel.cpp
+
+torrentoptionspanel.obj: src/torrentoptionspanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrentoptionspanel.obj -MD -MP -MF $(DEPDIR)/torrentoptionspanel.Tpo -c -o torrentoptionspanel.obj `if test -f 'src/torrentoptionspanel.cpp'; then $(CYGPATH_W) 'src/torrentoptionspanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/torrentoptionspanel.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrentoptionspanel.Tpo $(DEPDIR)/torrentoptionspanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/torrentoptionspanel.cpp' object='torrentoptionspanel.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrentoptionspanel.obj `if test -f 'src/torrentoptionspanel.cpp'; then $(CYGPATH_W) 'src/torrentoptionspanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/torrentoptionspanel.cpp'; fi`
+
+customlistctrl.o: src/customlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT customlistctrl.o -MD -MP -MF $(DEPDIR)/customlistctrl.Tpo -c -o customlistctrl.o `test -f 'src/customlistctrl.cpp' || echo '$(srcdir)/'`src/customlistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/customlistctrl.Tpo $(DEPDIR)/customlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/customlistctrl.cpp' object='customlistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o customlistctrl.o `test -f 'src/customlistctrl.cpp' || echo '$(srcdir)/'`src/customlistctrl.cpp
+
+customlistctrl.obj: src/customlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT customlistctrl.obj -MD -MP -MF $(DEPDIR)/customlistctrl.Tpo -c -o customlistctrl.obj `if test -f 'src/customlistctrl.cpp'; then $(CYGPATH_W) 'src/customlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/customlistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/customlistctrl.Tpo $(DEPDIR)/customlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/customlistctrl.cpp' object='customlistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o customlistctrl.obj `if test -f 'src/customlistctrl.cpp'; then $(CYGPATH_W) 'src/customlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/customlistctrl.cpp'; fi`
+
+mmoptionmodel.o: src/mmoptionmodel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mmoptionmodel.o -MD -MP -MF $(DEPDIR)/mmoptionmodel.Tpo -c -o mmoptionmodel.o `test -f 'src/mmoptionmodel.cpp' || echo '$(srcdir)/'`src/mmoptionmodel.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mmoptionmodel.Tpo $(DEPDIR)/mmoptionmodel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mmoptionmodel.cpp' object='mmoptionmodel.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mmoptionmodel.o `test -f 'src/mmoptionmodel.cpp' || echo '$(srcdir)/'`src/mmoptionmodel.cpp
+
+mmoptionmodel.obj: src/mmoptionmodel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mmoptionmodel.obj -MD -MP -MF $(DEPDIR)/mmoptionmodel.Tpo -c -o mmoptionmodel.obj `if test -f 'src/mmoptionmodel.cpp'; then $(CYGPATH_W) 'src/mmoptionmodel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mmoptionmodel.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mmoptionmodel.Tpo $(DEPDIR)/mmoptionmodel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mmoptionmodel.cpp' object='mmoptionmodel.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mmoptionmodel.obj `if test -f 'src/mmoptionmodel.cpp'; then $(CYGPATH_W) 'src/mmoptionmodel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mmoptionmodel.cpp'; fi`
+
+mmoptionswrapper.o: src/mmoptionswrapper.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mmoptionswrapper.o -MD -MP -MF $(DEPDIR)/mmoptionswrapper.Tpo -c -o mmoptionswrapper.o `test -f 'src/mmoptionswrapper.cpp' || echo '$(srcdir)/'`src/mmoptionswrapper.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mmoptionswrapper.Tpo $(DEPDIR)/mmoptionswrapper.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mmoptionswrapper.cpp' object='mmoptionswrapper.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mmoptionswrapper.o `test -f 'src/mmoptionswrapper.cpp' || echo '$(srcdir)/'`src/mmoptionswrapper.cpp
+
+mmoptionswrapper.obj: src/mmoptionswrapper.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mmoptionswrapper.obj -MD -MP -MF $(DEPDIR)/mmoptionswrapper.Tpo -c -o mmoptionswrapper.obj `if test -f 'src/mmoptionswrapper.cpp'; then $(CYGPATH_W) 'src/mmoptionswrapper.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mmoptionswrapper.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mmoptionswrapper.Tpo $(DEPDIR)/mmoptionswrapper.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mmoptionswrapper.cpp' object='mmoptionswrapper.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mmoptionswrapper.obj `if test -f 'src/mmoptionswrapper.cpp'; then $(CYGPATH_W) 'src/mmoptionswrapper.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mmoptionswrapper.cpp'; fi`
+
+torrentwrapper.o: src/torrentwrapper.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrentwrapper.o -MD -MP -MF $(DEPDIR)/torrentwrapper.Tpo -c -o torrentwrapper.o `test -f 'src/torrentwrapper.cpp' || echo '$(srcdir)/'`src/torrentwrapper.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrentwrapper.Tpo $(DEPDIR)/torrentwrapper.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/torrentwrapper.cpp' object='torrentwrapper.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrentwrapper.o `test -f 'src/torrentwrapper.cpp' || echo '$(srcdir)/'`src/torrentwrapper.cpp
+
+torrentwrapper.obj: src/torrentwrapper.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrentwrapper.obj -MD -MP -MF $(DEPDIR)/torrentwrapper.Tpo -c -o torrentwrapper.obj `if test -f 'src/torrentwrapper.cpp'; then $(CYGPATH_W) 'src/torrentwrapper.cpp'; else $(CYGPATH_W) '$(srcdir)/src/torrentwrapper.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrentwrapper.Tpo $(DEPDIR)/torrentwrapper.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/torrentwrapper.cpp' object='torrentwrapper.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrentwrapper.obj `if test -f 'src/torrentwrapper.cpp'; then $(CYGPATH_W) 'src/torrentwrapper.cpp'; else $(CYGPATH_W) '$(srcdir)/src/torrentwrapper.cpp'; fi`
+
+spinctld.o: src/spinctld.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT spinctld.o -MD -MP -MF $(DEPDIR)/spinctld.Tpo -c -o spinctld.o `test -f 'src/spinctld.cpp' || echo '$(srcdir)/'`src/spinctld.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/spinctld.Tpo $(DEPDIR)/spinctld.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/spinctld.cpp' object='spinctld.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o spinctld.o `test -f 'src/spinctld.cpp' || echo '$(srcdir)/'`src/spinctld.cpp
+
+spinctld.obj: src/spinctld.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT spinctld.obj -MD -MP -MF $(DEPDIR)/spinctld.Tpo -c -o spinctld.obj `if test -f 'src/spinctld.cpp'; then $(CYGPATH_W) 'src/spinctld.cpp'; else $(CYGPATH_W) '$(srcdir)/src/spinctld.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/spinctld.Tpo $(DEPDIR)/spinctld.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/spinctld.cpp' object='spinctld.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o spinctld.obj `if test -f 'src/spinctld.cpp'; then $(CYGPATH_W) 'src/spinctld.cpp'; else $(CYGPATH_W) '$(srcdir)/src/spinctld.cpp'; fi`
+
+autobalancedialog.o: src/autobalancedialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT autobalancedialog.o -MD -MP -MF $(DEPDIR)/autobalancedialog.Tpo -c -o autobalancedialog.o `test -f 'src/autobalancedialog.cpp' || echo '$(srcdir)/'`src/autobalancedialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/autobalancedialog.Tpo $(DEPDIR)/autobalancedialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/autobalancedialog.cpp' object='autobalancedialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o autobalancedialog.o `test -f 'src/autobalancedialog.cpp' || echo '$(srcdir)/'`src/autobalancedialog.cpp
+
+autobalancedialog.obj: src/autobalancedialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT autobalancedialog.obj -MD -MP -MF $(DEPDIR)/autobalancedialog.Tpo -c -o autobalancedialog.obj `if test -f 'src/autobalancedialog.cpp'; then $(CYGPATH_W) 'src/autobalancedialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/autobalancedialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/autobalancedialog.Tpo $(DEPDIR)/autobalancedialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/autobalancedialog.cpp' object='autobalancedialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o autobalancedialog.obj `if test -f 'src/autobalancedialog.cpp'; then $(CYGPATH_W) 'src/autobalancedialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/autobalancedialog.cpp'; fi`
+
+tdfcontainer.o: src/tdfcontainer.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tdfcontainer.o -MD -MP -MF $(DEPDIR)/tdfcontainer.Tpo -c -o tdfcontainer.o `test -f 'src/tdfcontainer.cpp' || echo '$(srcdir)/'`src/tdfcontainer.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tdfcontainer.Tpo $(DEPDIR)/tdfcontainer.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tdfcontainer.cpp' object='tdfcontainer.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tdfcontainer.o `test -f 'src/tdfcontainer.cpp' || echo '$(srcdir)/'`src/tdfcontainer.cpp
+
+tdfcontainer.obj: src/tdfcontainer.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tdfcontainer.obj -MD -MP -MF $(DEPDIR)/tdfcontainer.Tpo -c -o tdfcontainer.obj `if test -f 'src/tdfcontainer.cpp'; then $(CYGPATH_W) 'src/tdfcontainer.cpp'; else $(CYGPATH_W) '$(srcdir)/src/tdfcontainer.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tdfcontainer.Tpo $(DEPDIR)/tdfcontainer.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tdfcontainer.cpp' object='tdfcontainer.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tdfcontainer.obj `if test -f 'src/tdfcontainer.cpp'; then $(CYGPATH_W) 'src/tdfcontainer.cpp'; else $(CYGPATH_W) '$(srcdir)/src/tdfcontainer.cpp'; fi`
+
+globalevents.o: src/globalevents.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT globalevents.o -MD -MP -MF $(DEPDIR)/globalevents.Tpo -c -o globalevents.o `test -f 'src/globalevents.cpp' || echo '$(srcdir)/'`src/globalevents.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/globalevents.Tpo $(DEPDIR)/globalevents.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/globalevents.cpp' object='globalevents.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o globalevents.o `test -f 'src/globalevents.cpp' || echo '$(srcdir)/'`src/globalevents.cpp
+
+globalevents.obj: src/globalevents.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT globalevents.obj -MD -MP -MF $(DEPDIR)/globalevents.Tpo -c -o globalevents.obj `if test -f 'src/globalevents.cpp'; then $(CYGPATH_W) 'src/globalevents.cpp'; else $(CYGPATH_W) '$(srcdir)/src/globalevents.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/globalevents.Tpo $(DEPDIR)/globalevents.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/globalevents.cpp' object='globalevents.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o globalevents.obj `if test -f 'src/globalevents.cpp'; then $(CYGPATH_W) 'src/globalevents.cpp'; else $(CYGPATH_W) '$(srcdir)/src/globalevents.cpp'; fi`
+
+TextCompletionDatabase.o: src/Helper/TextCompletionDatabase.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TextCompletionDatabase.o -MD -MP -MF $(DEPDIR)/TextCompletionDatabase.Tpo -c -o TextCompletionDatabase.o `test -f 'src/Helper/TextCompletionDatabase.cpp' || echo '$(srcdir)/'`src/Helper/TextCompletionDatabase.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/TextCompletionDatabase.Tpo $(DEPDIR)/TextCompletionDatabase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/TextCompletionDatabase.cpp' object='TextCompletionDatabase.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o TextCompletionDatabase.o `test -f 'src/Helper/TextCompletionDatabase.cpp' || echo '$(srcdir)/'`src/Helper/TextCompletionDatabase.cpp
+
+TextCompletionDatabase.obj: src/Helper/TextCompletionDatabase.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TextCompletionDatabase.obj -MD -MP -MF $(DEPDIR)/TextCompletionDatabase.Tpo -c -o TextCompletionDatabase.obj `if test -f 'src/Helper/TextCompletionDatabase.cpp'; then $(CYGPATH_W) 'src/Helper/TextCompletionDatabase.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/TextCompletionDatabase.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/TextCompletionDatabase.Tpo $(DEPDIR)/TextCompletionDatabase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/TextCompletionDatabase.cpp' object='TextCompletionDatabase.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o TextCompletionDatabase.obj `if test -f 'src/Helper/TextCompletionDatabase.cpp'; then $(CYGPATH_W) 'src/Helper/TextCompletionDatabase.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/TextCompletionDatabase.cpp'; fi`
+
+wxTranslationHelper.o: src/Helper/wxTranslationHelper.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wxTranslationHelper.o -MD -MP -MF $(DEPDIR)/wxTranslationHelper.Tpo -c -o wxTranslationHelper.o `test -f 'src/Helper/wxTranslationHelper.cpp' || echo '$(srcdir)/'`src/Helper/wxTranslationHelper.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/wxTranslationHelper.Tpo $(DEPDIR)/wxTranslationHelper.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/wxTranslationHelper.cpp' object='wxTranslationHelper.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wxTranslationHelper.o `test -f 'src/Helper/wxTranslationHelper.cpp' || echo '$(srcdir)/'`src/Helper/wxTranslationHelper.cpp
+
+wxTranslationHelper.obj: src/Helper/wxTranslationHelper.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wxTranslationHelper.obj -MD -MP -MF $(DEPDIR)/wxTranslationHelper.Tpo -c -o wxTranslationHelper.obj `if test -f 'src/Helper/wxTranslationHelper.cpp'; then $(CYGPATH_W) 'src/Helper/wxTranslationHelper.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/wxTranslationHelper.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/wxTranslationHelper.Tpo $(DEPDIR)/wxTranslationHelper.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/wxTranslationHelper.cpp' object='wxTranslationHelper.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wxTranslationHelper.obj `if test -f 'src/Helper/wxTranslationHelper.cpp'; then $(CYGPATH_W) 'src/Helper/wxTranslationHelper.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/wxTranslationHelper.cpp'; fi`
+
+tasclientimport.o: src/Helper/tasclientimport.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tasclientimport.o -MD -MP -MF $(DEPDIR)/tasclientimport.Tpo -c -o tasclientimport.o `test -f 'src/Helper/tasclientimport.cpp' || echo '$(srcdir)/'`src/Helper/tasclientimport.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tasclientimport.Tpo $(DEPDIR)/tasclientimport.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/tasclientimport.cpp' object='tasclientimport.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tasclientimport.o `test -f 'src/Helper/tasclientimport.cpp' || echo '$(srcdir)/'`src/Helper/tasclientimport.cpp
+
+tasclientimport.obj: src/Helper/tasclientimport.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tasclientimport.obj -MD -MP -MF $(DEPDIR)/tasclientimport.Tpo -c -o tasclientimport.obj `if test -f 'src/Helper/tasclientimport.cpp'; then $(CYGPATH_W) 'src/Helper/tasclientimport.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/tasclientimport.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tasclientimport.Tpo $(DEPDIR)/tasclientimport.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/tasclientimport.cpp' object='tasclientimport.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tasclientimport.obj `if test -f 'src/Helper/tasclientimport.cpp'; then $(CYGPATH_W) 'src/Helper/tasclientimport.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/tasclientimport.cpp'; fi`
+
+slhtmlwindow.o: src/Helper/slhtmlwindow.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT slhtmlwindow.o -MD -MP -MF $(DEPDIR)/slhtmlwindow.Tpo -c -o slhtmlwindow.o `test -f 'src/Helper/slhtmlwindow.cpp' || echo '$(srcdir)/'`src/Helper/slhtmlwindow.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/slhtmlwindow.Tpo $(DEPDIR)/slhtmlwindow.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/slhtmlwindow.cpp' object='slhtmlwindow.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o slhtmlwindow.o `test -f 'src/Helper/slhtmlwindow.cpp' || echo '$(srcdir)/'`src/Helper/slhtmlwindow.cpp
+
+slhtmlwindow.obj: src/Helper/slhtmlwindow.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT slhtmlwindow.obj -MD -MP -MF $(DEPDIR)/slhtmlwindow.Tpo -c -o slhtmlwindow.obj `if test -f 'src/Helper/slhtmlwindow.cpp'; then $(CYGPATH_W) 'src/Helper/slhtmlwindow.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/slhtmlwindow.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/slhtmlwindow.Tpo $(DEPDIR)/slhtmlwindow.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/slhtmlwindow.cpp' object='slhtmlwindow.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o slhtmlwindow.obj `if test -f 'src/Helper/slhtmlwindow.cpp'; then $(CYGPATH_W) 'src/Helper/slhtmlwindow.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/slhtmlwindow.cpp'; fi`
+
+channelchooser.o: src/channel/channelchooser.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channelchooser.o -MD -MP -MF $(DEPDIR)/channelchooser.Tpo -c -o channelchooser.o `test -f 'src/channel/channelchooser.cpp' || echo '$(srcdir)/'`src/channel/channelchooser.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channelchooser.Tpo $(DEPDIR)/channelchooser.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channelchooser.cpp' object='channelchooser.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channelchooser.o `test -f 'src/channel/channelchooser.cpp' || echo '$(srcdir)/'`src/channel/channelchooser.cpp
+
+channelchooser.obj: src/channel/channelchooser.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channelchooser.obj -MD -MP -MF $(DEPDIR)/channelchooser.Tpo -c -o channelchooser.obj `if test -f 'src/channel/channelchooser.cpp'; then $(CYGPATH_W) 'src/channel/channelchooser.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channelchooser.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channelchooser.Tpo $(DEPDIR)/channelchooser.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channelchooser.cpp' object='channelchooser.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channelchooser.obj `if test -f 'src/channel/channelchooser.cpp'; then $(CYGPATH_W) 'src/channel/channelchooser.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channelchooser.cpp'; fi`
+
+channelchooserdialog.o: src/channel/channelchooserdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channelchooserdialog.o -MD -MP -MF $(DEPDIR)/channelchooserdialog.Tpo -c -o channelchooserdialog.o `test -f 'src/channel/channelchooserdialog.cpp' || echo '$(srcdir)/'`src/channel/channelchooserdialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channelchooserdialog.Tpo $(DEPDIR)/channelchooserdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channelchooserdialog.cpp' object='channelchooserdialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channelchooserdialog.o `test -f 'src/channel/channelchooserdialog.cpp' || echo '$(srcdir)/'`src/channel/channelchooserdialog.cpp
+
+channelchooserdialog.obj: src/channel/channelchooserdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT channelchooserdialog.obj -MD -MP -MF $(DEPDIR)/channelchooserdialog.Tpo -c -o channelchooserdialog.obj `if test -f 'src/channel/channelchooserdialog.cpp'; then $(CYGPATH_W) 'src/channel/channelchooserdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channelchooserdialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/channelchooserdialog.Tpo $(DEPDIR)/channelchooserdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/channelchooserdialog.cpp' object='channelchooserdialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o channelchooserdialog.obj `if test -f 'src/channel/channelchooserdialog.cpp'; then $(CYGPATH_W) 'src/channel/channelchooserdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/channelchooserdialog.cpp'; fi`
+
+colorbutton.o: src/Helper/colorbutton.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT colorbutton.o -MD -MP -MF $(DEPDIR)/colorbutton.Tpo -c -o colorbutton.o `test -f 'src/Helper/colorbutton.cpp' || echo '$(srcdir)/'`src/Helper/colorbutton.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/colorbutton.Tpo $(DEPDIR)/colorbutton.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/colorbutton.cpp' object='colorbutton.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o colorbutton.o `test -f 'src/Helper/colorbutton.cpp' || echo '$(srcdir)/'`src/Helper/colorbutton.cpp
+
+colorbutton.obj: src/Helper/colorbutton.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT colorbutton.obj -MD -MP -MF $(DEPDIR)/colorbutton.Tpo -c -o colorbutton.obj `if test -f 'src/Helper/colorbutton.cpp'; then $(CYGPATH_W) 'src/Helper/colorbutton.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/colorbutton.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/colorbutton.Tpo $(DEPDIR)/colorbutton.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/colorbutton.cpp' object='colorbutton.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o colorbutton.obj `if test -f 'src/Helper/colorbutton.cpp'; then $(CYGPATH_W) 'src/Helper/colorbutton.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/colorbutton.cpp'; fi`
+
+wxtextctrlhist.o: src/Helper/wxtextctrlhist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wxtextctrlhist.o -MD -MP -MF $(DEPDIR)/wxtextctrlhist.Tpo -c -o wxtextctrlhist.o `test -f 'src/Helper/wxtextctrlhist.cpp' || echo '$(srcdir)/'`src/Helper/wxtextctrlhist.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/wxtextctrlhist.Tpo $(DEPDIR)/wxtextctrlhist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/wxtextctrlhist.cpp' object='wxtextctrlhist.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wxtextctrlhist.o `test -f 'src/Helper/wxtextctrlhist.cpp' || echo '$(srcdir)/'`src/Helper/wxtextctrlhist.cpp
+
+wxtextctrlhist.obj: src/Helper/wxtextctrlhist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wxtextctrlhist.obj -MD -MP -MF $(DEPDIR)/wxtextctrlhist.Tpo -c -o wxtextctrlhist.obj `if test -f 'src/Helper/wxtextctrlhist.cpp'; then $(CYGPATH_W) 'src/Helper/wxtextctrlhist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/wxtextctrlhist.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/wxtextctrlhist.Tpo $(DEPDIR)/wxtextctrlhist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/wxtextctrlhist.cpp' object='wxtextctrlhist.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wxtextctrlhist.obj `if test -f 'src/Helper/wxtextctrlhist.cpp'; then $(CYGPATH_W) 'src/Helper/wxtextctrlhist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/wxtextctrlhist.cpp'; fi`
+
+imageviewer.o: src/Helper/imageviewer.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT imageviewer.o -MD -MP -MF $(DEPDIR)/imageviewer.Tpo -c -o imageviewer.o `test -f 'src/Helper/imageviewer.cpp' || echo '$(srcdir)/'`src/Helper/imageviewer.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/imageviewer.Tpo $(DEPDIR)/imageviewer.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/imageviewer.cpp' object='imageviewer.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o imageviewer.o `test -f 'src/Helper/imageviewer.cpp' || echo '$(srcdir)/'`src/Helper/imageviewer.cpp
+
+imageviewer.obj: src/Helper/imageviewer.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT imageviewer.obj -MD -MP -MF $(DEPDIR)/imageviewer.Tpo -c -o imageviewer.obj `if test -f 'src/Helper/imageviewer.cpp'; then $(CYGPATH_W) 'src/Helper/imageviewer.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/imageviewer.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/imageviewer.Tpo $(DEPDIR)/imageviewer.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/imageviewer.cpp' object='imageviewer.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o imageviewer.obj `if test -f 'src/Helper/imageviewer.cpp'; then $(CYGPATH_W) 'src/Helper/imageviewer.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/imageviewer.cpp'; fi`
+
+filelistctrl.o: src/filelister/filelistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filelistctrl.o -MD -MP -MF $(DEPDIR)/filelistctrl.Tpo -c -o filelistctrl.o `test -f 'src/filelister/filelistctrl.cpp' || echo '$(srcdir)/'`src/filelister/filelistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/filelistctrl.Tpo $(DEPDIR)/filelistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/filelister/filelistctrl.cpp' object='filelistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filelistctrl.o `test -f 'src/filelister/filelistctrl.cpp' || echo '$(srcdir)/'`src/filelister/filelistctrl.cpp
+
+filelistctrl.obj: src/filelister/filelistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filelistctrl.obj -MD -MP -MF $(DEPDIR)/filelistctrl.Tpo -c -o filelistctrl.obj `if test -f 'src/filelister/filelistctrl.cpp'; then $(CYGPATH_W) 'src/filelister/filelistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/filelister/filelistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/filelistctrl.Tpo $(DEPDIR)/filelistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/filelister/filelistctrl.cpp' object='filelistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filelistctrl.obj `if test -f 'src/filelister/filelistctrl.cpp'; then $(CYGPATH_W) 'src/filelister/filelistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/filelister/filelistctrl.cpp'; fi`
+
+filelistdialog.o: src/filelister/filelistdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filelistdialog.o -MD -MP -MF $(DEPDIR)/filelistdialog.Tpo -c -o filelistdialog.o `test -f 'src/filelister/filelistdialog.cpp' || echo '$(srcdir)/'`src/filelister/filelistdialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/filelistdialog.Tpo $(DEPDIR)/filelistdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/filelister/filelistdialog.cpp' object='filelistdialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filelistdialog.o `test -f 'src/filelister/filelistdialog.cpp' || echo '$(srcdir)/'`src/filelister/filelistdialog.cpp
+
+filelistdialog.obj: src/filelister/filelistdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filelistdialog.obj -MD -MP -MF $(DEPDIR)/filelistdialog.Tpo -c -o filelistdialog.obj `if test -f 'src/filelister/filelistdialog.cpp'; then $(CYGPATH_W) 'src/filelister/filelistdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/filelister/filelistdialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/filelistdialog.Tpo $(DEPDIR)/filelistdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/filelister/filelistdialog.cpp' object='filelistdialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filelistdialog.obj `if test -f 'src/filelister/filelistdialog.cpp'; then $(CYGPATH_W) 'src/filelister/filelistdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/filelister/filelistdialog.cpp'; fi`
+
+filelistfilter.o: src/filelister/filelistfilter.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filelistfilter.o -MD -MP -MF $(DEPDIR)/filelistfilter.Tpo -c -o filelistfilter.o `test -f 'src/filelister/filelistfilter.cpp' || echo '$(srcdir)/'`src/filelister/filelistfilter.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/filelistfilter.Tpo $(DEPDIR)/filelistfilter.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/filelister/filelistfilter.cpp' object='filelistfilter.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filelistfilter.o `test -f 'src/filelister/filelistfilter.cpp' || echo '$(srcdir)/'`src/filelister/filelistfilter.cpp
+
+filelistfilter.obj: src/filelister/filelistfilter.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filelistfilter.obj -MD -MP -MF $(DEPDIR)/filelistfilter.Tpo -c -o filelistfilter.obj `if test -f 'src/filelister/filelistfilter.cpp'; then $(CYGPATH_W) 'src/filelister/filelistfilter.cpp'; else $(CYGPATH_W) '$(srcdir)/src/filelister/filelistfilter.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/filelistfilter.Tpo $(DEPDIR)/filelistfilter.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/filelister/filelistfilter.cpp' object='filelistfilter.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filelistfilter.obj `if test -f 'src/filelister/filelistfilter.cpp'; then $(CYGPATH_W) 'src/filelister/filelistfilter.cpp'; else $(CYGPATH_W) '$(srcdir)/src/filelister/filelistfilter.cpp'; fi`
+
+autojoinchanneldialog.o: src/channel/autojoinchanneldialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT autojoinchanneldialog.o -MD -MP -MF $(DEPDIR)/autojoinchanneldialog.Tpo -c -o autojoinchanneldialog.o `test -f 'src/channel/autojoinchanneldialog.cpp' || echo '$(srcdir)/'`src/channel/autojoinchanneldialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/autojoinchanneldialog.Tpo $(DEPDIR)/autojoinchanneldialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/autojoinchanneldialog.cpp' object='autojoinchanneldialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o autojoinchanneldialog.o `test -f 'src/channel/autojoinchanneldialog.cpp' || echo '$(srcdir)/'`src/channel/autojoinchanneldialog.cpp
+
+autojoinchanneldialog.obj: src/channel/autojoinchanneldialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT autojoinchanneldialog.obj -MD -MP -MF $(DEPDIR)/autojoinchanneldialog.Tpo -c -o autojoinchanneldialog.obj `if test -f 'src/channel/autojoinchanneldialog.cpp'; then $(CYGPATH_W) 'src/channel/autojoinchanneldialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/autojoinchanneldialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/autojoinchanneldialog.Tpo $(DEPDIR)/autojoinchanneldialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/channel/autojoinchanneldialog.cpp' object='autojoinchanneldialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o autojoinchanneldialog.obj `if test -f 'src/channel/autojoinchanneldialog.cpp'; then $(CYGPATH_W) 'src/channel/autojoinchanneldialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/channel/autojoinchanneldialog.cpp'; fi`
+
+useractions.o: src/useractions.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT useractions.o -MD -MP -MF $(DEPDIR)/useractions.Tpo -c -o useractions.o `test -f 'src/useractions.cpp' || echo '$(srcdir)/'`src/useractions.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/useractions.Tpo $(DEPDIR)/useractions.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/useractions.cpp' object='useractions.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o useractions.o `test -f 'src/useractions.cpp' || echo '$(srcdir)/'`src/useractions.cpp
+
+useractions.obj: src/useractions.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT useractions.obj -MD -MP -MF $(DEPDIR)/useractions.Tpo -c -o useractions.obj `if test -f 'src/useractions.cpp'; then $(CYGPATH_W) 'src/useractions.cpp'; else $(CYGPATH_W) '$(srcdir)/src/useractions.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/useractions.Tpo $(DEPDIR)/useractions.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/useractions.cpp' object='useractions.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o useractions.obj `if test -f 'src/useractions.cpp'; then $(CYGPATH_W) 'src/useractions.cpp'; else $(CYGPATH_W) '$(srcdir)/src/useractions.cpp'; fi`
+
+selectusersdialog.o: src/selectusersdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT selectusersdialog.o -MD -MP -MF $(DEPDIR)/selectusersdialog.Tpo -c -o selectusersdialog.o `test -f 'src/selectusersdialog.cpp' || echo '$(srcdir)/'`src/selectusersdialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/selectusersdialog.Tpo $(DEPDIR)/selectusersdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/selectusersdialog.cpp' object='selectusersdialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o selectusersdialog.o `test -f 'src/selectusersdialog.cpp' || echo '$(srcdir)/'`src/selectusersdialog.cpp
+
+selectusersdialog.obj: src/selectusersdialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT selectusersdialog.obj -MD -MP -MF $(DEPDIR)/selectusersdialog.Tpo -c -o selectusersdialog.obj `if test -f 'src/selectusersdialog.cpp'; then $(CYGPATH_W) 'src/selectusersdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/selectusersdialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/selectusersdialog.Tpo $(DEPDIR)/selectusersdialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/selectusersdialog.cpp' object='selectusersdialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o selectusersdialog.obj `if test -f 'src/selectusersdialog.cpp'; then $(CYGPATH_W) 'src/selectusersdialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/selectusersdialog.cpp'; fi`
+
+groupoptionspanel.o: src/groupoptionspanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT groupoptionspanel.o -MD -MP -MF $(DEPDIR)/groupoptionspanel.Tpo -c -o groupoptionspanel.o `test -f 'src/groupoptionspanel.cpp' || echo '$(srcdir)/'`src/groupoptionspanel.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/groupoptionspanel.Tpo $(DEPDIR)/groupoptionspanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/groupoptionspanel.cpp' object='groupoptionspanel.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o groupoptionspanel.o `test -f 'src/groupoptionspanel.cpp' || echo '$(srcdir)/'`src/groupoptionspanel.cpp
+
+groupoptionspanel.obj: src/groupoptionspanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT groupoptionspanel.obj -MD -MP -MF $(DEPDIR)/groupoptionspanel.Tpo -c -o groupoptionspanel.obj `if test -f 'src/groupoptionspanel.cpp'; then $(CYGPATH_W) 'src/groupoptionspanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/groupoptionspanel.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/groupoptionspanel.Tpo $(DEPDIR)/groupoptionspanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/groupoptionspanel.cpp' object='groupoptionspanel.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o groupoptionspanel.obj `if test -f 'src/groupoptionspanel.cpp'; then $(CYGPATH_W) 'src/groupoptionspanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/groupoptionspanel.cpp'; fi`
+
+lobbyoptionstab.o: src/lobbyoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lobbyoptionstab.o -MD -MP -MF $(DEPDIR)/lobbyoptionstab.Tpo -c -o lobbyoptionstab.o `test -f 'src/lobbyoptionstab.cpp' || echo '$(srcdir)/'`src/lobbyoptionstab.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/lobbyoptionstab.Tpo $(DEPDIR)/lobbyoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/lobbyoptionstab.cpp' object='lobbyoptionstab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lobbyoptionstab.o `test -f 'src/lobbyoptionstab.cpp' || echo '$(srcdir)/'`src/lobbyoptionstab.cpp
+
+lobbyoptionstab.obj: src/lobbyoptionstab.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lobbyoptionstab.obj -MD -MP -MF $(DEPDIR)/lobbyoptionstab.Tpo -c -o lobbyoptionstab.obj `if test -f 'src/lobbyoptionstab.cpp'; then $(CYGPATH_W) 'src/lobbyoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/lobbyoptionstab.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/lobbyoptionstab.Tpo $(DEPDIR)/lobbyoptionstab.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/lobbyoptionstab.cpp' object='lobbyoptionstab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lobbyoptionstab.obj `if test -f 'src/lobbyoptionstab.cpp'; then $(CYGPATH_W) 'src/lobbyoptionstab.cpp'; else $(CYGPATH_W) '$(srcdir)/src/lobbyoptionstab.cpp'; fi`
+
+auimanager.o: src/aui/auimanager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT auimanager.o -MD -MP -MF $(DEPDIR)/auimanager.Tpo -c -o auimanager.o `test -f 'src/aui/auimanager.cpp' || echo '$(srcdir)/'`src/aui/auimanager.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/auimanager.Tpo $(DEPDIR)/auimanager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/aui/auimanager.cpp' object='auimanager.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o auimanager.o `test -f 'src/aui/auimanager.cpp' || echo '$(srcdir)/'`src/aui/auimanager.cpp
+
+auimanager.obj: src/aui/auimanager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT auimanager.obj -MD -MP -MF $(DEPDIR)/auimanager.Tpo -c -o auimanager.obj `if test -f 'src/aui/auimanager.cpp'; then $(CYGPATH_W) 'src/aui/auimanager.cpp'; else $(CYGPATH_W) '$(srcdir)/src/aui/auimanager.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/auimanager.Tpo $(DEPDIR)/auimanager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/aui/auimanager.cpp' object='auimanager.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o auimanager.obj `if test -f 'src/aui/auimanager.cpp'; then $(CYGPATH_W) 'src/aui/auimanager.cpp'; else $(CYGPATH_W) '$(srcdir)/src/aui/auimanager.cpp'; fi`
+
+artprovider.o: src/aui/artprovider.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT artprovider.o -MD -MP -MF $(DEPDIR)/artprovider.Tpo -c -o artprovider.o `test -f 'src/aui/artprovider.cpp' || echo '$(srcdir)/'`src/aui/artprovider.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/artprovider.Tpo $(DEPDIR)/artprovider.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/aui/artprovider.cpp' object='artprovider.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o artprovider.o `test -f 'src/aui/artprovider.cpp' || echo '$(srcdir)/'`src/aui/artprovider.cpp
+
+artprovider.obj: src/aui/artprovider.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT artprovider.obj -MD -MP -MF $(DEPDIR)/artprovider.Tpo -c -o artprovider.obj `if test -f 'src/aui/artprovider.cpp'; then $(CYGPATH_W) 'src/aui/artprovider.cpp'; else $(CYGPATH_W) '$(srcdir)/src/aui/artprovider.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/artprovider.Tpo $(DEPDIR)/artprovider.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/aui/artprovider.cpp' object='artprovider.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o artprovider.obj `if test -f 'src/aui/artprovider.cpp'; then $(CYGPATH_W) 'src/aui/artprovider.cpp'; else $(CYGPATH_W) '$(srcdir)/src/aui/artprovider.cpp'; fi`
+
+updater.o: src/updater/updater.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT updater.o -MD -MP -MF $(DEPDIR)/updater.Tpo -c -o updater.o `test -f 'src/updater/updater.cpp' || echo '$(srcdir)/'`src/updater/updater.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/updater.Tpo $(DEPDIR)/updater.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/updater/updater.cpp' object='updater.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o updater.o `test -f 'src/updater/updater.cpp' || echo '$(srcdir)/'`src/updater/updater.cpp
+
+updater.obj: src/updater/updater.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT updater.obj -MD -MP -MF $(DEPDIR)/updater.Tpo -c -o updater.obj `if test -f 'src/updater/updater.cpp'; then $(CYGPATH_W) 'src/updater/updater.cpp'; else $(CYGPATH_W) '$(srcdir)/src/updater/updater.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/updater.Tpo $(DEPDIR)/updater.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/updater/updater.cpp' object='updater.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o updater.obj `if test -f 'src/updater/updater.cpp'; then $(CYGPATH_W) 'src/updater/updater.cpp'; else $(CYGPATH_W) '$(srcdir)/src/updater/updater.cpp'; fi`
+
+downloadlistctrl.o: src/widgets/downloadlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT downloadlistctrl.o -MD -MP -MF $(DEPDIR)/downloadlistctrl.Tpo -c -o downloadlistctrl.o `test -f 'src/widgets/downloadlistctrl.cpp' || echo '$(srcdir)/'`src/widgets/downloadlistctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/downloadlistctrl.Tpo $(DEPDIR)/downloadlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/downloadlistctrl.cpp' object='downloadlistctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o downloadlistctrl.o `test -f 'src/widgets/downloadlistctrl.cpp' || echo '$(srcdir)/'`src/widgets/downloadlistctrl.cpp
+
+downloadlistctrl.obj: src/widgets/downloadlistctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT downloadlistctrl.obj -MD -MP -MF $(DEPDIR)/downloadlistctrl.Tpo -c -o downloadlistctrl.obj `if test -f 'src/widgets/downloadlistctrl.cpp'; then $(CYGPATH_W) 'src/widgets/downloadlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/downloadlistctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/downloadlistctrl.Tpo $(DEPDIR)/downloadlistctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/downloadlistctrl.cpp' object='downloadlistctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o downloadlistctrl.obj `if test -f 'src/widgets/downloadlistctrl.cpp'; then $(CYGPATH_W) 'src/widgets/downloadlistctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/downloadlistctrl.cpp'; fi`
+
+downloaddialog.o: src/widgets/downloaddialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT downloaddialog.o -MD -MP -MF $(DEPDIR)/downloaddialog.Tpo -c -o downloaddialog.o `test -f 'src/widgets/downloaddialog.cpp' || echo '$(srcdir)/'`src/widgets/downloaddialog.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/downloaddialog.Tpo $(DEPDIR)/downloaddialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/downloaddialog.cpp' object='downloaddialog.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o downloaddialog.o `test -f 'src/widgets/downloaddialog.cpp' || echo '$(srcdir)/'`src/widgets/downloaddialog.cpp
+
+downloaddialog.obj: src/widgets/downloaddialog.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT downloaddialog.obj -MD -MP -MF $(DEPDIR)/downloaddialog.Tpo -c -o downloaddialog.obj `if test -f 'src/widgets/downloaddialog.cpp'; then $(CYGPATH_W) 'src/widgets/downloaddialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/downloaddialog.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/downloaddialog.Tpo $(DEPDIR)/downloaddialog.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/downloaddialog.cpp' object='downloaddialog.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o downloaddialog.obj `if test -f 'src/widgets/downloaddialog.cpp'; then $(CYGPATH_W) 'src/widgets/downloaddialog.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/downloaddialog.cpp'; fi`
+
+downloadpanel.o: src/widgets/downloadpanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT downloadpanel.o -MD -MP -MF $(DEPDIR)/downloadpanel.Tpo -c -o downloadpanel.o `test -f 'src/widgets/downloadpanel.cpp' || echo '$(srcdir)/'`src/widgets/downloadpanel.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/downloadpanel.Tpo $(DEPDIR)/downloadpanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/downloadpanel.cpp' object='downloadpanel.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o downloadpanel.o `test -f 'src/widgets/downloadpanel.cpp' || echo '$(srcdir)/'`src/widgets/downloadpanel.cpp
+
+downloadpanel.obj: src/widgets/downloadpanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT downloadpanel.obj -MD -MP -MF $(DEPDIR)/downloadpanel.Tpo -c -o downloadpanel.obj `if test -f 'src/widgets/downloadpanel.cpp'; then $(CYGPATH_W) 'src/widgets/downloadpanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/downloadpanel.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/downloadpanel.Tpo $(DEPDIR)/downloadpanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/downloadpanel.cpp' object='downloadpanel.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o downloadpanel.obj `if test -f 'src/widgets/downloadpanel.cpp'; then $(CYGPATH_W) 'src/widgets/downloadpanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/downloadpanel.cpp'; fi`
+
+infopanel.o: src/widgets/infopanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT infopanel.o -MD -MP -MF $(DEPDIR)/infopanel.Tpo -c -o infopanel.o `test -f 'src/widgets/infopanel.cpp' || echo '$(srcdir)/'`src/widgets/infopanel.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/infopanel.Tpo $(DEPDIR)/infopanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/infopanel.cpp' object='infopanel.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o infopanel.o `test -f 'src/widgets/infopanel.cpp' || echo '$(srcdir)/'`src/widgets/infopanel.cpp
+
+infopanel.obj: src/widgets/infopanel.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT infopanel.obj -MD -MP -MF $(DEPDIR)/infopanel.Tpo -c -o infopanel.obj `if test -f 'src/widgets/infopanel.cpp'; then $(CYGPATH_W) 'src/widgets/infopanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/infopanel.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/infopanel.Tpo $(DEPDIR)/infopanel.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/infopanel.cpp' object='infopanel.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o infopanel.obj `if test -f 'src/widgets/infopanel.cpp'; then $(CYGPATH_W) 'src/widgets/infopanel.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/infopanel.cpp'; fi`
+
+widget.o: src/widgets/widget.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT widget.o -MD -MP -MF $(DEPDIR)/widget.Tpo -c -o widget.o `test -f 'src/widgets/widget.cpp' || echo '$(srcdir)/'`src/widgets/widget.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/widget.Tpo $(DEPDIR)/widget.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/widget.cpp' object='widget.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o widget.o `test -f 'src/widgets/widget.cpp' || echo '$(srcdir)/'`src/widgets/widget.cpp
+
+widget.obj: src/widgets/widget.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT widget.obj -MD -MP -MF $(DEPDIR)/widget.Tpo -c -o widget.obj `if test -f 'src/widgets/widget.cpp'; then $(CYGPATH_W) 'src/widgets/widget.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/widget.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/widget.Tpo $(DEPDIR)/widget.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/widgets/widget.cpp' object='widget.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o widget.obj `if test -f 'src/widgets/widget.cpp'; then $(CYGPATH_W) 'src/widgets/widget.cpp'; else $(CYGPATH_W) '$(srcdir)/src/widgets/widget.cpp'; fi`
+
+thread.o: src/thread.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT thread.o -MD -MP -MF $(DEPDIR)/thread.Tpo -c -o thread.o `test -f 'src/thread.cpp' || echo '$(srcdir)/'`src/thread.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/thread.Tpo $(DEPDIR)/thread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/thread.cpp' object='thread.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o thread.o `test -f 'src/thread.cpp' || echo '$(srcdir)/'`src/thread.cpp
+
+thread.obj: src/thread.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT thread.obj -MD -MP -MF $(DEPDIR)/thread.Tpo -c -o thread.obj `if test -f 'src/thread.cpp'; then $(CYGPATH_W) 'src/thread.cpp'; else $(CYGPATH_W) '$(srcdir)/src/thread.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/thread.Tpo $(DEPDIR)/thread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/thread.cpp' object='thread.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o thread.obj `if test -f 'src/thread.cpp'; then $(CYGPATH_W) 'src/thread.cpp'; else $(CYGPATH_W) '$(srcdir)/src/thread.cpp'; fi`
+
+globalsmanager.o: src/globalsmanager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT globalsmanager.o -MD -MP -MF $(DEPDIR)/globalsmanager.Tpo -c -o globalsmanager.o `test -f 'src/globalsmanager.cpp' || echo '$(srcdir)/'`src/globalsmanager.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/globalsmanager.Tpo $(DEPDIR)/globalsmanager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/globalsmanager.cpp' object='globalsmanager.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o globalsmanager.o `test -f 'src/globalsmanager.cpp' || echo '$(srcdir)/'`src/globalsmanager.cpp
+
+globalsmanager.obj: src/globalsmanager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT globalsmanager.obj -MD -MP -MF $(DEPDIR)/globalsmanager.Tpo -c -o globalsmanager.obj `if test -f 'src/globalsmanager.cpp'; then $(CYGPATH_W) 'src/globalsmanager.cpp'; else $(CYGPATH_W) '$(srcdir)/src/globalsmanager.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/globalsmanager.Tpo $(DEPDIR)/globalsmanager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/globalsmanager.cpp' object='globalsmanager.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o globalsmanager.obj `if test -f 'src/globalsmanager.cpp'; then $(CYGPATH_W) 'src/globalsmanager.cpp'; else $(CYGPATH_W) '$(srcdir)/src/globalsmanager.cpp'; fi`
+
+mmoptionwindows.o: src/mmoptionwindows.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mmoptionwindows.o -MD -MP -MF $(DEPDIR)/mmoptionwindows.Tpo -c -o mmoptionwindows.o `test -f 'src/mmoptionwindows.cpp' || echo '$(srcdir)/'`src/mmoptionwindows.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mmoptionwindows.Tpo $(DEPDIR)/mmoptionwindows.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mmoptionwindows.cpp' object='mmoptionwindows.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mmoptionwindows.o `test -f 'src/mmoptionwindows.cpp' || echo '$(srcdir)/'`src/mmoptionwindows.cpp
+
+mmoptionwindows.obj: src/mmoptionwindows.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mmoptionwindows.obj -MD -MP -MF $(DEPDIR)/mmoptionwindows.Tpo -c -o mmoptionwindows.obj `if test -f 'src/mmoptionwindows.cpp'; then $(CYGPATH_W) 'src/mmoptionwindows.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mmoptionwindows.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mmoptionwindows.Tpo $(DEPDIR)/mmoptionwindows.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mmoptionwindows.cpp' object='mmoptionwindows.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mmoptionwindows.obj `if test -f 'src/mmoptionwindows.cpp'; then $(CYGPATH_W) 'src/mmoptionwindows.cpp'; else $(CYGPATH_W) '$(srcdir)/src/mmoptionwindows.cpp'; fi`
+
+savegamelist.o: src/playback/savegamelist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT savegamelist.o -MD -MP -MF $(DEPDIR)/savegamelist.Tpo -c -o savegamelist.o `test -f 'src/playback/savegamelist.cpp' || echo '$(srcdir)/'`src/playback/savegamelist.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/savegamelist.Tpo $(DEPDIR)/savegamelist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/playback/savegamelist.cpp' object='savegamelist.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o savegamelist.o `test -f 'src/playback/savegamelist.cpp' || echo '$(srcdir)/'`src/playback/savegamelist.cpp
+
+savegamelist.obj: src/playback/savegamelist.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT savegamelist.obj -MD -MP -MF $(DEPDIR)/savegamelist.Tpo -c -o savegamelist.obj `if test -f 'src/playback/savegamelist.cpp'; then $(CYGPATH_W) 'src/playback/savegamelist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/playback/savegamelist.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/savegamelist.Tpo $(DEPDIR)/savegamelist.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/playback/savegamelist.cpp' object='savegamelist.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o savegamelist.obj `if test -f 'src/playback/savegamelist.cpp'; then $(CYGPATH_W) 'src/playback/savegamelist.cpp'; else $(CYGPATH_W) '$(srcdir)/src/playback/savegamelist.cpp'; fi`
+
+listctrl.o: src/Helper/listctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT listctrl.o -MD -MP -MF $(DEPDIR)/listctrl.Tpo -c -o listctrl.o `test -f 'src/Helper/listctrl.cpp' || echo '$(srcdir)/'`src/Helper/listctrl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/listctrl.Tpo $(DEPDIR)/listctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/listctrl.cpp' object='listctrl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o listctrl.o `test -f 'src/Helper/listctrl.cpp' || echo '$(srcdir)/'`src/Helper/listctrl.cpp
+
+listctrl.obj: src/Helper/listctrl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT listctrl.obj -MD -MP -MF $(DEPDIR)/listctrl.Tpo -c -o listctrl.obj `if test -f 'src/Helper/listctrl.cpp'; then $(CYGPATH_W) 'src/Helper/listctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/listctrl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/listctrl.Tpo $(DEPDIR)/listctrl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/Helper/listctrl.cpp' object='listctrl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o listctrl.obj `if test -f 'src/Helper/listctrl.cpp'; then $(CYGPATH_W) 'src/Helper/listctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/src/Helper/listctrl.cpp'; fi`
+
+entry.o: $(libt_src_dir)/entry.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT entry.o -MD -MP -MF $(DEPDIR)/entry.Tpo -c -o entry.o `test -f '$(libt_src_dir)/entry.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/entry.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/entry.Tpo $(DEPDIR)/entry.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/entry.cpp' object='entry.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o entry.o `test -f '$(libt_src_dir)/entry.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/entry.cpp
+
+entry.obj: $(libt_src_dir)/entry.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT entry.obj -MD -MP -MF $(DEPDIR)/entry.Tpo -c -o entry.obj `if test -f '$(libt_src_dir)/entry.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/entry.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/entry.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/entry.Tpo $(DEPDIR)/entry.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/entry.cpp' object='entry.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o entry.obj `if test -f '$(libt_src_dir)/entry.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/entry.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/entry.cpp'; fi`
+
+escape_string.o: $(libt_src_dir)/escape_string.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT escape_string.o -MD -MP -MF $(DEPDIR)/escape_string.Tpo -c -o escape_string.o `test -f '$(libt_src_dir)/escape_string.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/escape_string.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/escape_string.Tpo $(DEPDIR)/escape_string.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/escape_string.cpp' object='escape_string.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o escape_string.o `test -f '$(libt_src_dir)/escape_string.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/escape_string.cpp
+
+escape_string.obj: $(libt_src_dir)/escape_string.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT escape_string.obj -MD -MP -MF $(DEPDIR)/escape_string.Tpo -c -o escape_string.obj `if test -f '$(libt_src_dir)/escape_string.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/escape_string.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/escape_string.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/escape_string.Tpo $(DEPDIR)/escape_string.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/escape_string.cpp' object='escape_string.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o escape_string.obj `if test -f '$(libt_src_dir)/escape_string.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/escape_string.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/escape_string.cpp'; fi`
+
+assert.o: $(libt_src_dir)/assert.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT assert.o -MD -MP -MF $(DEPDIR)/assert.Tpo -c -o assert.o `test -f '$(libt_src_dir)/assert.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/assert.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/assert.Tpo $(DEPDIR)/assert.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/assert.cpp' object='assert.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o assert.o `test -f '$(libt_src_dir)/assert.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/assert.cpp
+
+assert.obj: $(libt_src_dir)/assert.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT assert.obj -MD -MP -MF $(DEPDIR)/assert.Tpo -c -o assert.obj `if test -f '$(libt_src_dir)/assert.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/assert.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/assert.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/assert.Tpo $(DEPDIR)/assert.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/assert.cpp' object='assert.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o assert.obj `if test -f '$(libt_src_dir)/assert.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/assert.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/assert.cpp'; fi`
+
+enum_net.o: $(libt_src_dir)/enum_net.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT enum_net.o -MD -MP -MF $(DEPDIR)/enum_net.Tpo -c -o enum_net.o `test -f '$(libt_src_dir)/enum_net.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/enum_net.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/enum_net.Tpo $(DEPDIR)/enum_net.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/enum_net.cpp' object='enum_net.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o enum_net.o `test -f '$(libt_src_dir)/enum_net.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/enum_net.cpp
+
+enum_net.obj: $(libt_src_dir)/enum_net.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT enum_net.obj -MD -MP -MF $(DEPDIR)/enum_net.Tpo -c -o enum_net.obj `if test -f '$(libt_src_dir)/enum_net.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/enum_net.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/enum_net.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/enum_net.Tpo $(DEPDIR)/enum_net.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/enum_net.cpp' object='enum_net.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o enum_net.obj `if test -f '$(libt_src_dir)/enum_net.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/enum_net.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/enum_net.cpp'; fi`
+
+broadcast_socket.o: $(libt_src_dir)/broadcast_socket.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT broadcast_socket.o -MD -MP -MF $(DEPDIR)/broadcast_socket.Tpo -c -o broadcast_socket.o `test -f '$(libt_src_dir)/broadcast_socket.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/broadcast_socket.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/broadcast_socket.Tpo $(DEPDIR)/broadcast_socket.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/broadcast_socket.cpp' object='broadcast_socket.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o broadcast_socket.o `test -f '$(libt_src_dir)/broadcast_socket.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/broadcast_socket.cpp
+
+broadcast_socket.obj: $(libt_src_dir)/broadcast_socket.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT broadcast_socket.obj -MD -MP -MF $(DEPDIR)/broadcast_socket.Tpo -c -o broadcast_socket.obj `if test -f '$(libt_src_dir)/broadcast_socket.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/broadcast_socket.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/broadcast_socket.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/broadcast_socket.Tpo $(DEPDIR)/broadcast_socket.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/broadcast_socket.cpp' object='broadcast_socket.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o broadcast_socket.obj `if test -f '$(libt_src_dir)/broadcast_socket.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/broadcast_socket.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/broadcast_socket.cpp'; fi`
+
+peer_connection.o: $(libt_src_dir)/peer_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT peer_connection.o -MD -MP -MF $(DEPDIR)/peer_connection.Tpo -c -o peer_connection.o `test -f '$(libt_src_dir)/peer_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/peer_connection.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/peer_connection.Tpo $(DEPDIR)/peer_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/peer_connection.cpp' object='peer_connection.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o peer_connection.o `test -f '$(libt_src_dir)/peer_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/peer_connection.cpp
+
+peer_connection.obj: $(libt_src_dir)/peer_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT peer_connection.obj -MD -MP -MF $(DEPDIR)/peer_connection.Tpo -c -o peer_connection.obj `if test -f '$(libt_src_dir)/peer_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/peer_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/peer_connection.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/peer_connection.Tpo $(DEPDIR)/peer_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/peer_connection.cpp' object='peer_connection.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o peer_connection.obj `if test -f '$(libt_src_dir)/peer_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/peer_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/peer_connection.cpp'; fi`
+
+bt_peer_connection.o: $(libt_src_dir)/bt_peer_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bt_peer_connection.o -MD -MP -MF $(DEPDIR)/bt_peer_connection.Tpo -c -o bt_peer_connection.o `test -f '$(libt_src_dir)/bt_peer_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/bt_peer_connection.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/bt_peer_connection.Tpo $(DEPDIR)/bt_peer_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/bt_peer_connection.cpp' object='bt_peer_connection.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bt_peer_connection.o `test -f '$(libt_src_dir)/bt_peer_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/bt_peer_connection.cpp
+
+bt_peer_connection.obj: $(libt_src_dir)/bt_peer_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bt_peer_connection.obj -MD -MP -MF $(DEPDIR)/bt_peer_connection.Tpo -c -o bt_peer_connection.obj `if test -f '$(libt_src_dir)/bt_peer_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/bt_peer_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/bt_peer_connection.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/bt_peer_connection.Tpo $(DEPDIR)/bt_peer_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/bt_peer_connection.cpp' object='bt_peer_connection.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bt_peer_connection.obj `if test -f '$(libt_src_dir)/bt_peer_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/bt_peer_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/bt_peer_connection.cpp'; fi`
+
+web_peer_connection.o: $(libt_src_dir)/web_peer_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT web_peer_connection.o -MD -MP -MF $(DEPDIR)/web_peer_connection.Tpo -c -o web_peer_connection.o `test -f '$(libt_src_dir)/web_peer_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/web_peer_connection.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/web_peer_connection.Tpo $(DEPDIR)/web_peer_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/web_peer_connection.cpp' object='web_peer_connection.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o web_peer_connection.o `test -f '$(libt_src_dir)/web_peer_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/web_peer_connection.cpp
+
+web_peer_connection.obj: $(libt_src_dir)/web_peer_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT web_peer_connection.obj -MD -MP -MF $(DEPDIR)/web_peer_connection.Tpo -c -o web_peer_connection.obj `if test -f '$(libt_src_dir)/web_peer_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/web_peer_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/web_peer_connection.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/web_peer_connection.Tpo $(DEPDIR)/web_peer_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/web_peer_connection.cpp' object='web_peer_connection.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o web_peer_connection.obj `if test -f '$(libt_src_dir)/web_peer_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/web_peer_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/web_peer_connection.cpp'; fi`
+
+natpmp.o: $(libt_src_dir)/natpmp.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT natpmp.o -MD -MP -MF $(DEPDIR)/natpmp.Tpo -c -o natpmp.o `test -f '$(libt_src_dir)/natpmp.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/natpmp.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/natpmp.Tpo $(DEPDIR)/natpmp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/natpmp.cpp' object='natpmp.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o natpmp.o `test -f '$(libt_src_dir)/natpmp.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/natpmp.cpp
+
+natpmp.obj: $(libt_src_dir)/natpmp.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT natpmp.obj -MD -MP -MF $(DEPDIR)/natpmp.Tpo -c -o natpmp.obj `if test -f '$(libt_src_dir)/natpmp.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/natpmp.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/natpmp.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/natpmp.Tpo $(DEPDIR)/natpmp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/natpmp.cpp' object='natpmp.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o natpmp.obj `if test -f '$(libt_src_dir)/natpmp.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/natpmp.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/natpmp.cpp'; fi`
+
+piece_picker.o: $(libt_src_dir)/piece_picker.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT piece_picker.o -MD -MP -MF $(DEPDIR)/piece_picker.Tpo -c -o piece_picker.o `test -f '$(libt_src_dir)/piece_picker.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/piece_picker.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/piece_picker.Tpo $(DEPDIR)/piece_picker.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/piece_picker.cpp' object='piece_picker.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o piece_picker.o `test -f '$(libt_src_dir)/piece_picker.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/piece_picker.cpp
+
+piece_picker.obj: $(libt_src_dir)/piece_picker.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT piece_picker.obj -MD -MP -MF $(DEPDIR)/piece_picker.Tpo -c -o piece_picker.obj `if test -f '$(libt_src_dir)/piece_picker.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/piece_picker.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/piece_picker.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/piece_picker.Tpo $(DEPDIR)/piece_picker.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/piece_picker.cpp' object='piece_picker.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o piece_picker.obj `if test -f '$(libt_src_dir)/piece_picker.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/piece_picker.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/piece_picker.cpp'; fi`
+
+policy.o: $(libt_src_dir)/policy.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT policy.o -MD -MP -MF $(DEPDIR)/policy.Tpo -c -o policy.o `test -f '$(libt_src_dir)/policy.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/policy.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/policy.Tpo $(DEPDIR)/policy.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/policy.cpp' object='policy.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o policy.o `test -f '$(libt_src_dir)/policy.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/policy.cpp
+
+policy.obj: $(libt_src_dir)/policy.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT policy.obj -MD -MP -MF $(DEPDIR)/policy.Tpo -c -o policy.obj `if test -f '$(libt_src_dir)/policy.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/policy.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/policy.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/policy.Tpo $(DEPDIR)/policy.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/policy.cpp' object='policy.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o policy.obj `if test -f '$(libt_src_dir)/policy.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/policy.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/policy.cpp'; fi`
+
+session.o: $(libt_src_dir)/session.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT session.o -MD -MP -MF $(DEPDIR)/session.Tpo -c -o session.o `test -f '$(libt_src_dir)/session.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/session.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/session.Tpo $(DEPDIR)/session.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/session.cpp' object='session.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o session.o `test -f '$(libt_src_dir)/session.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/session.cpp
+
+session.obj: $(libt_src_dir)/session.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT session.obj -MD -MP -MF $(DEPDIR)/session.Tpo -c -o session.obj `if test -f '$(libt_src_dir)/session.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/session.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/session.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/session.Tpo $(DEPDIR)/session.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/session.cpp' object='session.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o session.obj `if test -f '$(libt_src_dir)/session.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/session.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/session.cpp'; fi`
+
+session_impl.o: $(libt_src_dir)/session_impl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT session_impl.o -MD -MP -MF $(DEPDIR)/session_impl.Tpo -c -o session_impl.o `test -f '$(libt_src_dir)/session_impl.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/session_impl.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/session_impl.Tpo $(DEPDIR)/session_impl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/session_impl.cpp' object='session_impl.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o session_impl.o `test -f '$(libt_src_dir)/session_impl.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/session_impl.cpp
+
+session_impl.obj: $(libt_src_dir)/session_impl.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT session_impl.obj -MD -MP -MF $(DEPDIR)/session_impl.Tpo -c -o session_impl.obj `if test -f '$(libt_src_dir)/session_impl.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/session_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/session_impl.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/session_impl.Tpo $(DEPDIR)/session_impl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/session_impl.cpp' object='session_impl.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o session_impl.obj `if test -f '$(libt_src_dir)/session_impl.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/session_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/session_impl.cpp'; fi`
+
+sha1.o: $(libt_src_dir)/sha1.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sha1.o -MD -MP -MF $(DEPDIR)/sha1.Tpo -c -o sha1.o `test -f '$(libt_src_dir)/sha1.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/sha1.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/sha1.Tpo $(DEPDIR)/sha1.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/sha1.cpp' object='sha1.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sha1.o `test -f '$(libt_src_dir)/sha1.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/sha1.cpp
+
+sha1.obj: $(libt_src_dir)/sha1.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sha1.obj -MD -MP -MF $(DEPDIR)/sha1.Tpo -c -o sha1.obj `if test -f '$(libt_src_dir)/sha1.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/sha1.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/sha1.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/sha1.Tpo $(DEPDIR)/sha1.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/sha1.cpp' object='sha1.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sha1.obj `if test -f '$(libt_src_dir)/sha1.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/sha1.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/sha1.cpp'; fi`
+
+stat.o: $(libt_src_dir)/stat.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stat.o -MD -MP -MF $(DEPDIR)/stat.Tpo -c -o stat.o `test -f '$(libt_src_dir)/stat.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/stat.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stat.Tpo $(DEPDIR)/stat.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/stat.cpp' object='stat.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stat.o `test -f '$(libt_src_dir)/stat.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/stat.cpp
+
+stat.obj: $(libt_src_dir)/stat.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stat.obj -MD -MP -MF $(DEPDIR)/stat.Tpo -c -o stat.obj `if test -f '$(libt_src_dir)/stat.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/stat.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/stat.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stat.Tpo $(DEPDIR)/stat.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/stat.cpp' object='stat.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stat.obj `if test -f '$(libt_src_dir)/stat.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/stat.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/stat.cpp'; fi`
+
+storage.o: $(libt_src_dir)/storage.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT storage.o -MD -MP -MF $(DEPDIR)/storage.Tpo -c -o storage.o `test -f '$(libt_src_dir)/storage.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/storage.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/storage.Tpo $(DEPDIR)/storage.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/storage.cpp' object='storage.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o storage.o `test -f '$(libt_src_dir)/storage.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/storage.cpp
+
+storage.obj: $(libt_src_dir)/storage.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT storage.obj -MD -MP -MF $(DEPDIR)/storage.Tpo -c -o storage.obj `if test -f '$(libt_src_dir)/storage.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/storage.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/storage.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/storage.Tpo $(DEPDIR)/storage.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/storage.cpp' object='storage.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o storage.obj `if test -f '$(libt_src_dir)/storage.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/storage.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/storage.cpp'; fi`
+
+torrent.o: $(libt_src_dir)/torrent.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrent.o -MD -MP -MF $(DEPDIR)/torrent.Tpo -c -o torrent.o `test -f '$(libt_src_dir)/torrent.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/torrent.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrent.Tpo $(DEPDIR)/torrent.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/torrent.cpp' object='torrent.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrent.o `test -f '$(libt_src_dir)/torrent.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/torrent.cpp
+
+torrent.obj: $(libt_src_dir)/torrent.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrent.obj -MD -MP -MF $(DEPDIR)/torrent.Tpo -c -o torrent.obj `if test -f '$(libt_src_dir)/torrent.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/torrent.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/torrent.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrent.Tpo $(DEPDIR)/torrent.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/torrent.cpp' object='torrent.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrent.obj `if test -f '$(libt_src_dir)/torrent.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/torrent.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/torrent.cpp'; fi`
+
+torrent_handle.o: $(libt_src_dir)/torrent_handle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrent_handle.o -MD -MP -MF $(DEPDIR)/torrent_handle.Tpo -c -o torrent_handle.o `test -f '$(libt_src_dir)/torrent_handle.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/torrent_handle.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrent_handle.Tpo $(DEPDIR)/torrent_handle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/torrent_handle.cpp' object='torrent_handle.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrent_handle.o `test -f '$(libt_src_dir)/torrent_handle.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/torrent_handle.cpp
+
+torrent_handle.obj: $(libt_src_dir)/torrent_handle.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrent_handle.obj -MD -MP -MF $(DEPDIR)/torrent_handle.Tpo -c -o torrent_handle.obj `if test -f '$(libt_src_dir)/torrent_handle.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/torrent_handle.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/torrent_handle.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrent_handle.Tpo $(DEPDIR)/torrent_handle.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/torrent_handle.cpp' object='torrent_handle.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrent_handle.obj `if test -f '$(libt_src_dir)/torrent_handle.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/torrent_handle.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/torrent_handle.cpp'; fi`
+
+pe_crypto.o: $(libt_src_dir)/pe_crypto.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pe_crypto.o -MD -MP -MF $(DEPDIR)/pe_crypto.Tpo -c -o pe_crypto.o `test -f '$(libt_src_dir)/pe_crypto.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/pe_crypto.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/pe_crypto.Tpo $(DEPDIR)/pe_crypto.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/pe_crypto.cpp' object='pe_crypto.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pe_crypto.o `test -f '$(libt_src_dir)/pe_crypto.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/pe_crypto.cpp
+
+pe_crypto.obj: $(libt_src_dir)/pe_crypto.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pe_crypto.obj -MD -MP -MF $(DEPDIR)/pe_crypto.Tpo -c -o pe_crypto.obj `if test -f '$(libt_src_dir)/pe_crypto.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/pe_crypto.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/pe_crypto.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/pe_crypto.Tpo $(DEPDIR)/pe_crypto.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/pe_crypto.cpp' object='pe_crypto.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pe_crypto.obj `if test -f '$(libt_src_dir)/pe_crypto.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/pe_crypto.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/pe_crypto.cpp'; fi`
+
+torrent_info.o: $(libt_src_dir)/torrent_info.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrent_info.o -MD -MP -MF $(DEPDIR)/torrent_info.Tpo -c -o torrent_info.o `test -f '$(libt_src_dir)/torrent_info.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/torrent_info.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrent_info.Tpo $(DEPDIR)/torrent_info.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/torrent_info.cpp' object='torrent_info.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrent_info.o `test -f '$(libt_src_dir)/torrent_info.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/torrent_info.cpp
+
+torrent_info.obj: $(libt_src_dir)/torrent_info.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT torrent_info.obj -MD -MP -MF $(DEPDIR)/torrent_info.Tpo -c -o torrent_info.obj `if test -f '$(libt_src_dir)/torrent_info.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/torrent_info.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/torrent_info.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/torrent_info.Tpo $(DEPDIR)/torrent_info.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/torrent_info.cpp' object='torrent_info.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o torrent_info.obj `if test -f '$(libt_src_dir)/torrent_info.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/torrent_info.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/torrent_info.cpp'; fi`
+
+tracker_manager.o: $(libt_src_dir)/tracker_manager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tracker_manager.o -MD -MP -MF $(DEPDIR)/tracker_manager.Tpo -c -o tracker_manager.o `test -f '$(libt_src_dir)/tracker_manager.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/tracker_manager.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tracker_manager.Tpo $(DEPDIR)/tracker_manager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/tracker_manager.cpp' object='tracker_manager.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tracker_manager.o `test -f '$(libt_src_dir)/tracker_manager.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/tracker_manager.cpp
+
+tracker_manager.obj: $(libt_src_dir)/tracker_manager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tracker_manager.obj -MD -MP -MF $(DEPDIR)/tracker_manager.Tpo -c -o tracker_manager.obj `if test -f '$(libt_src_dir)/tracker_manager.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/tracker_manager.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/tracker_manager.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tracker_manager.Tpo $(DEPDIR)/tracker_manager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/tracker_manager.cpp' object='tracker_manager.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tracker_manager.obj `if test -f '$(libt_src_dir)/tracker_manager.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/tracker_manager.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/tracker_manager.cpp'; fi`
+
+http_connection.o: $(libt_src_dir)/http_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT http_connection.o -MD -MP -MF $(DEPDIR)/http_connection.Tpo -c -o http_connection.o `test -f '$(libt_src_dir)/http_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/http_connection.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/http_connection.Tpo $(DEPDIR)/http_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/http_connection.cpp' object='http_connection.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o http_connection.o `test -f '$(libt_src_dir)/http_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/http_connection.cpp
+
+http_connection.obj: $(libt_src_dir)/http_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT http_connection.obj -MD -MP -MF $(DEPDIR)/http_connection.Tpo -c -o http_connection.obj `if test -f '$(libt_src_dir)/http_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/http_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/http_connection.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/http_connection.Tpo $(DEPDIR)/http_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/http_connection.cpp' object='http_connection.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o http_connection.obj `if test -f '$(libt_src_dir)/http_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/http_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/http_connection.cpp'; fi`
+
+http_tracker_connection.o: $(libt_src_dir)/http_tracker_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT http_tracker_connection.o -MD -MP -MF $(DEPDIR)/http_tracker_connection.Tpo -c -o http_tracker_connection.o `test -f '$(libt_src_dir)/http_tracker_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/http_tracker_connection.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/http_tracker_connection.Tpo $(DEPDIR)/http_tracker_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/http_tracker_connection.cpp' object='http_tracker_connection.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o http_tracker_connection.o `test -f '$(libt_src_dir)/http_tracker_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/http_tracker_connection.cpp
+
+http_tracker_connection.obj: $(libt_src_dir)/http_tracker_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT http_tracker_connection.obj -MD -MP -MF $(DEPDIR)/http_tracker_connection.Tpo -c -o http_tracker_connection.obj `if test -f '$(libt_src_dir)/http_tracker_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/http_tracker_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/http_tracker_connection.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/http_tracker_connection.Tpo $(DEPDIR)/http_tracker_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/http_tracker_connection.cpp' object='http_tracker_connection.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o http_tracker_connection.obj `if test -f '$(libt_src_dir)/http_tracker_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/http_tracker_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/http_tracker_connection.cpp'; fi`
+
+udp_tracker_connection.o: $(libt_src_dir)/udp_tracker_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT udp_tracker_connection.o -MD -MP -MF $(DEPDIR)/udp_tracker_connection.Tpo -c -o udp_tracker_connection.o `test -f '$(libt_src_dir)/udp_tracker_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/udp_tracker_connection.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/udp_tracker_connection.Tpo $(DEPDIR)/udp_tracker_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/udp_tracker_connection.cpp' object='udp_tracker_connection.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o udp_tracker_connection.o `test -f '$(libt_src_dir)/udp_tracker_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/udp_tracker_connection.cpp
+
+udp_tracker_connection.obj: $(libt_src_dir)/udp_tracker_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT udp_tracker_connection.obj -MD -MP -MF $(DEPDIR)/udp_tracker_connection.Tpo -c -o udp_tracker_connection.obj `if test -f '$(libt_src_dir)/udp_tracker_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/udp_tracker_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/udp_tracker_connection.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/udp_tracker_connection.Tpo $(DEPDIR)/udp_tracker_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/udp_tracker_connection.cpp' object='udp_tracker_connection.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o udp_tracker_connection.obj `if test -f '$(libt_src_dir)/udp_tracker_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/udp_tracker_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/udp_tracker_connection.cpp'; fi`
+
+alert.o: $(libt_src_dir)/alert.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT alert.o -MD -MP -MF $(DEPDIR)/alert.Tpo -c -o alert.o `test -f '$(libt_src_dir)/alert.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/alert.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/alert.Tpo $(DEPDIR)/alert.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/alert.cpp' object='alert.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o alert.o `test -f '$(libt_src_dir)/alert.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/alert.cpp
+
+alert.obj: $(libt_src_dir)/alert.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT alert.obj -MD -MP -MF $(DEPDIR)/alert.Tpo -c -o alert.obj `if test -f '$(libt_src_dir)/alert.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/alert.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/alert.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/alert.Tpo $(DEPDIR)/alert.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/alert.cpp' object='alert.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o alert.obj `if test -f '$(libt_src_dir)/alert.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/alert.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/alert.cpp'; fi`
+
+identify_client.o: $(libt_src_dir)/identify_client.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT identify_client.o -MD -MP -MF $(DEPDIR)/identify_client.Tpo -c -o identify_client.o `test -f '$(libt_src_dir)/identify_client.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/identify_client.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/identify_client.Tpo $(DEPDIR)/identify_client.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/identify_client.cpp' object='identify_client.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o identify_client.o `test -f '$(libt_src_dir)/identify_client.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/identify_client.cpp
+
+identify_client.obj: $(libt_src_dir)/identify_client.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT identify_client.obj -MD -MP -MF $(DEPDIR)/identify_client.Tpo -c -o identify_client.obj `if test -f '$(libt_src_dir)/identify_client.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/identify_client.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/identify_client.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/identify_client.Tpo $(DEPDIR)/identify_client.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/identify_client.cpp' object='identify_client.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o identify_client.obj `if test -f '$(libt_src_dir)/identify_client.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/identify_client.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/identify_client.cpp'; fi`
+
+ip_filter.o: $(libt_src_dir)/ip_filter.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ip_filter.o -MD -MP -MF $(DEPDIR)/ip_filter.Tpo -c -o ip_filter.o `test -f '$(libt_src_dir)/ip_filter.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/ip_filter.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ip_filter.Tpo $(DEPDIR)/ip_filter.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/ip_filter.cpp' object='ip_filter.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ip_filter.o `test -f '$(libt_src_dir)/ip_filter.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/ip_filter.cpp
+
+ip_filter.obj: $(libt_src_dir)/ip_filter.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ip_filter.obj -MD -MP -MF $(DEPDIR)/ip_filter.Tpo -c -o ip_filter.obj `if test -f '$(libt_src_dir)/ip_filter.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/ip_filter.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/ip_filter.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ip_filter.Tpo $(DEPDIR)/ip_filter.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/ip_filter.cpp' object='ip_filter.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ip_filter.obj `if test -f '$(libt_src_dir)/ip_filter.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/ip_filter.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/ip_filter.cpp'; fi`
+
+file.o: $(libt_src_dir)/file.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file.o -MD -MP -MF $(DEPDIR)/file.Tpo -c -o file.o `test -f '$(libt_src_dir)/file.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/file.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/file.Tpo $(DEPDIR)/file.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/file.cpp' object='file.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file.o `test -f '$(libt_src_dir)/file.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/file.cpp
+
+file.obj: $(libt_src_dir)/file.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file.obj -MD -MP -MF $(DEPDIR)/file.Tpo -c -o file.obj `if test -f '$(libt_src_dir)/file.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/file.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/file.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/file.Tpo $(DEPDIR)/file.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/file.cpp' object='file.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file.obj `if test -f '$(libt_src_dir)/file.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/file.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/file.cpp'; fi`
+
+metadata_transfer.o: $(libt_src_dir)/metadata_transfer.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT metadata_transfer.o -MD -MP -MF $(DEPDIR)/metadata_transfer.Tpo -c -o metadata_transfer.o `test -f '$(libt_src_dir)/metadata_transfer.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/metadata_transfer.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/metadata_transfer.Tpo $(DEPDIR)/metadata_transfer.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/metadata_transfer.cpp' object='metadata_transfer.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o metadata_transfer.o `test -f '$(libt_src_dir)/metadata_transfer.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/metadata_transfer.cpp
+
+metadata_transfer.obj: $(libt_src_dir)/metadata_transfer.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT metadata_transfer.obj -MD -MP -MF $(DEPDIR)/metadata_transfer.Tpo -c -o metadata_transfer.obj `if test -f '$(libt_src_dir)/metadata_transfer.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/metadata_transfer.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/metadata_transfer.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/metadata_transfer.Tpo $(DEPDIR)/metadata_transfer.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/metadata_transfer.cpp' object='metadata_transfer.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o metadata_transfer.obj `if test -f '$(libt_src_dir)/metadata_transfer.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/metadata_transfer.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/metadata_transfer.cpp'; fi`
+
+logger.o: $(libt_src_dir)/logger.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT logger.o -MD -MP -MF $(DEPDIR)/logger.Tpo -c -o logger.o `test -f '$(libt_src_dir)/logger.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/logger.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/logger.Tpo $(DEPDIR)/logger.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/logger.cpp' object='logger.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o logger.o `test -f '$(libt_src_dir)/logger.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/logger.cpp
+
+logger.obj: $(libt_src_dir)/logger.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT logger.obj -MD -MP -MF $(DEPDIR)/logger.Tpo -c -o logger.obj `if test -f '$(libt_src_dir)/logger.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/logger.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/logger.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/logger.Tpo $(DEPDIR)/logger.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/logger.cpp' object='logger.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o logger.obj `if test -f '$(libt_src_dir)/logger.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/logger.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/logger.cpp'; fi`
+
+file_pool.o: $(libt_src_dir)/file_pool.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_pool.o -MD -MP -MF $(DEPDIR)/file_pool.Tpo -c -o file_pool.o `test -f '$(libt_src_dir)/file_pool.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/file_pool.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/file_pool.Tpo $(DEPDIR)/file_pool.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/file_pool.cpp' object='file_pool.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_pool.o `test -f '$(libt_src_dir)/file_pool.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/file_pool.cpp
+
+file_pool.obj: $(libt_src_dir)/file_pool.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_pool.obj -MD -MP -MF $(DEPDIR)/file_pool.Tpo -c -o file_pool.obj `if test -f '$(libt_src_dir)/file_pool.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/file_pool.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/file_pool.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/file_pool.Tpo $(DEPDIR)/file_pool.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/file_pool.cpp' object='file_pool.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_pool.obj `if test -f '$(libt_src_dir)/file_pool.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/file_pool.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/file_pool.cpp'; fi`
+
+ut_pex.o: $(libt_src_dir)/ut_pex.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ut_pex.o -MD -MP -MF $(DEPDIR)/ut_pex.Tpo -c -o ut_pex.o `test -f '$(libt_src_dir)/ut_pex.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/ut_pex.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ut_pex.Tpo $(DEPDIR)/ut_pex.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/ut_pex.cpp' object='ut_pex.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ut_pex.o `test -f '$(libt_src_dir)/ut_pex.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/ut_pex.cpp
+
+ut_pex.obj: $(libt_src_dir)/ut_pex.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ut_pex.obj -MD -MP -MF $(DEPDIR)/ut_pex.Tpo -c -o ut_pex.obj `if test -f '$(libt_src_dir)/ut_pex.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/ut_pex.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/ut_pex.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/ut_pex.Tpo $(DEPDIR)/ut_pex.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/ut_pex.cpp' object='ut_pex.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ut_pex.obj `if test -f '$(libt_src_dir)/ut_pex.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/ut_pex.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/ut_pex.cpp'; fi`
+
+lsd.o: $(libt_src_dir)/lsd.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lsd.o -MD -MP -MF $(DEPDIR)/lsd.Tpo -c -o lsd.o `test -f '$(libt_src_dir)/lsd.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/lsd.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/lsd.Tpo $(DEPDIR)/lsd.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/lsd.cpp' object='lsd.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lsd.o `test -f '$(libt_src_dir)/lsd.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/lsd.cpp
+
+lsd.obj: $(libt_src_dir)/lsd.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lsd.obj -MD -MP -MF $(DEPDIR)/lsd.Tpo -c -o lsd.obj `if test -f '$(libt_src_dir)/lsd.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/lsd.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/lsd.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/lsd.Tpo $(DEPDIR)/lsd.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/lsd.cpp' object='lsd.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lsd.obj `if test -f '$(libt_src_dir)/lsd.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/lsd.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/lsd.cpp'; fi`
+
+upnp.o: $(libt_src_dir)/upnp.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT upnp.o -MD -MP -MF $(DEPDIR)/upnp.Tpo -c -o upnp.o `test -f '$(libt_src_dir)/upnp.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/upnp.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/upnp.Tpo $(DEPDIR)/upnp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/upnp.cpp' object='upnp.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o upnp.o `test -f '$(libt_src_dir)/upnp.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/upnp.cpp
+
+upnp.obj: $(libt_src_dir)/upnp.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT upnp.obj -MD -MP -MF $(DEPDIR)/upnp.Tpo -c -o upnp.obj `if test -f '$(libt_src_dir)/upnp.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/upnp.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/upnp.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/upnp.Tpo $(DEPDIR)/upnp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/upnp.cpp' object='upnp.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o upnp.obj `if test -f '$(libt_src_dir)/upnp.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/upnp.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/upnp.cpp'; fi`
+
+instantiate_connection.o: $(libt_src_dir)/instantiate_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT instantiate_connection.o -MD -MP -MF $(DEPDIR)/instantiate_connection.Tpo -c -o instantiate_connection.o `test -f '$(libt_src_dir)/instantiate_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/instantiate_connection.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/instantiate_connection.Tpo $(DEPDIR)/instantiate_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/instantiate_connection.cpp' object='instantiate_connection.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o instantiate_connection.o `test -f '$(libt_src_dir)/instantiate_connection.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/instantiate_connection.cpp
+
+instantiate_connection.obj: $(libt_src_dir)/instantiate_connection.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT instantiate_connection.obj -MD -MP -MF $(DEPDIR)/instantiate_connection.Tpo -c -o instantiate_connection.obj `if test -f '$(libt_src_dir)/instantiate_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/instantiate_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/instantiate_connection.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/instantiate_connection.Tpo $(DEPDIR)/instantiate_connection.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/instantiate_connection.cpp' object='instantiate_connection.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o instantiate_connection.obj `if test -f '$(libt_src_dir)/instantiate_connection.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/instantiate_connection.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/instantiate_connection.cpp'; fi`
+
+socks5_stream.o: $(libt_src_dir)/socks5_stream.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT socks5_stream.o -MD -MP -MF $(DEPDIR)/socks5_stream.Tpo -c -o socks5_stream.o `test -f '$(libt_src_dir)/socks5_stream.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/socks5_stream.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/socks5_stream.Tpo $(DEPDIR)/socks5_stream.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/socks5_stream.cpp' object='socks5_stream.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o socks5_stream.o `test -f '$(libt_src_dir)/socks5_stream.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/socks5_stream.cpp
+
+socks5_stream.obj: $(libt_src_dir)/socks5_stream.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT socks5_stream.obj -MD -MP -MF $(DEPDIR)/socks5_stream.Tpo -c -o socks5_stream.obj `if test -f '$(libt_src_dir)/socks5_stream.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/socks5_stream.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/socks5_stream.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/socks5_stream.Tpo $(DEPDIR)/socks5_stream.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/socks5_stream.cpp' object='socks5_stream.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o socks5_stream.obj `if test -f '$(libt_src_dir)/socks5_stream.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/socks5_stream.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/socks5_stream.cpp'; fi`
+
+socks4_stream.o: $(libt_src_dir)/socks4_stream.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT socks4_stream.o -MD -MP -MF $(DEPDIR)/socks4_stream.Tpo -c -o socks4_stream.o `test -f '$(libt_src_dir)/socks4_stream.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/socks4_stream.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/socks4_stream.Tpo $(DEPDIR)/socks4_stream.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/socks4_stream.cpp' object='socks4_stream.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o socks4_stream.o `test -f '$(libt_src_dir)/socks4_stream.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/socks4_stream.cpp
+
+socks4_stream.obj: $(libt_src_dir)/socks4_stream.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT socks4_stream.obj -MD -MP -MF $(DEPDIR)/socks4_stream.Tpo -c -o socks4_stream.obj `if test -f '$(libt_src_dir)/socks4_stream.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/socks4_stream.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/socks4_stream.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/socks4_stream.Tpo $(DEPDIR)/socks4_stream.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/socks4_stream.cpp' object='socks4_stream.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o socks4_stream.obj `if test -f '$(libt_src_dir)/socks4_stream.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/socks4_stream.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/socks4_stream.cpp'; fi`
+
+http_stream.o: $(libt_src_dir)/http_stream.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT http_stream.o -MD -MP -MF $(DEPDIR)/http_stream.Tpo -c -o http_stream.o `test -f '$(libt_src_dir)/http_stream.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/http_stream.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/http_stream.Tpo $(DEPDIR)/http_stream.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/http_stream.cpp' object='http_stream.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o http_stream.o `test -f '$(libt_src_dir)/http_stream.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/http_stream.cpp
+
+http_stream.obj: $(libt_src_dir)/http_stream.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT http_stream.obj -MD -MP -MF $(DEPDIR)/http_stream.Tpo -c -o http_stream.obj `if test -f '$(libt_src_dir)/http_stream.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/http_stream.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/http_stream.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/http_stream.Tpo $(DEPDIR)/http_stream.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/http_stream.cpp' object='http_stream.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o http_stream.obj `if test -f '$(libt_src_dir)/http_stream.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/http_stream.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/http_stream.cpp'; fi`
+
+connection_queue.o: $(libt_src_dir)/connection_queue.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT connection_queue.o -MD -MP -MF $(DEPDIR)/connection_queue.Tpo -c -o connection_queue.o `test -f '$(libt_src_dir)/connection_queue.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/connection_queue.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/connection_queue.Tpo $(DEPDIR)/connection_queue.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/connection_queue.cpp' object='connection_queue.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o connection_queue.o `test -f '$(libt_src_dir)/connection_queue.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/connection_queue.cpp
+
+connection_queue.obj: $(libt_src_dir)/connection_queue.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT connection_queue.obj -MD -MP -MF $(DEPDIR)/connection_queue.Tpo -c -o connection_queue.obj `if test -f '$(libt_src_dir)/connection_queue.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/connection_queue.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/connection_queue.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/connection_queue.Tpo $(DEPDIR)/connection_queue.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/connection_queue.cpp' object='connection_queue.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o connection_queue.obj `if test -f '$(libt_src_dir)/connection_queue.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/connection_queue.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/connection_queue.cpp'; fi`
+
+disk_io_thread.o: $(libt_src_dir)/disk_io_thread.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT disk_io_thread.o -MD -MP -MF $(DEPDIR)/disk_io_thread.Tpo -c -o disk_io_thread.o `test -f '$(libt_src_dir)/disk_io_thread.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/disk_io_thread.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/disk_io_thread.Tpo $(DEPDIR)/disk_io_thread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/disk_io_thread.cpp' object='disk_io_thread.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o disk_io_thread.o `test -f '$(libt_src_dir)/disk_io_thread.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/disk_io_thread.cpp
+
+disk_io_thread.obj: $(libt_src_dir)/disk_io_thread.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT disk_io_thread.obj -MD -MP -MF $(DEPDIR)/disk_io_thread.Tpo -c -o disk_io_thread.obj `if test -f '$(libt_src_dir)/disk_io_thread.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/disk_io_thread.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/disk_io_thread.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/disk_io_thread.Tpo $(DEPDIR)/disk_io_thread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/disk_io_thread.cpp' object='disk_io_thread.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o disk_io_thread.obj `if test -f '$(libt_src_dir)/disk_io_thread.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/disk_io_thread.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/disk_io_thread.cpp'; fi`
+
+closest_nodes.o: $(libt_src_dir)/kademlia/closest_nodes.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT closest_nodes.o -MD -MP -MF $(DEPDIR)/closest_nodes.Tpo -c -o closest_nodes.o `test -f '$(libt_src_dir)/kademlia/closest_nodes.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/closest_nodes.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/closest_nodes.Tpo $(DEPDIR)/closest_nodes.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/closest_nodes.cpp' object='closest_nodes.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o closest_nodes.o `test -f '$(libt_src_dir)/kademlia/closest_nodes.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/closest_nodes.cpp
+
+closest_nodes.obj: $(libt_src_dir)/kademlia/closest_nodes.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT closest_nodes.obj -MD -MP -MF $(DEPDIR)/closest_nodes.Tpo -c -o closest_nodes.obj `if test -f '$(libt_src_dir)/kademlia/closest_nodes.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/closest_nodes.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/closest_nodes.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/closest_nodes.Tpo $(DEPDIR)/closest_nodes.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/closest_nodes.cpp' object='closest_nodes.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o closest_nodes.obj `if test -f '$(libt_src_dir)/kademlia/closest_nodes.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/closest_nodes.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/closest_nodes.cpp'; fi`
+
+dht_tracker.o: $(libt_src_dir)/kademlia/dht_tracker.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dht_tracker.o -MD -MP -MF $(DEPDIR)/dht_tracker.Tpo -c -o dht_tracker.o `test -f '$(libt_src_dir)/kademlia/dht_tracker.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/dht_tracker.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dht_tracker.Tpo $(DEPDIR)/dht_tracker.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/dht_tracker.cpp' object='dht_tracker.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dht_tracker.o `test -f '$(libt_src_dir)/kademlia/dht_tracker.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/dht_tracker.cpp
+
+dht_tracker.obj: $(libt_src_dir)/kademlia/dht_tracker.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dht_tracker.obj -MD -MP -MF $(DEPDIR)/dht_tracker.Tpo -c -o dht_tracker.obj `if test -f '$(libt_src_dir)/kademlia/dht_tracker.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/dht_tracker.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/dht_tracker.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dht_tracker.Tpo $(DEPDIR)/dht_tracker.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/dht_tracker.cpp' object='dht_tracker.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dht_tracker.obj `if test -f '$(libt_src_dir)/kademlia/dht_tracker.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/dht_tracker.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/dht_tracker.cpp'; fi`
+
+find_data.o: $(libt_src_dir)/kademlia/find_data.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT find_data.o -MD -MP -MF $(DEPDIR)/find_data.Tpo -c -o find_data.o `test -f '$(libt_src_dir)/kademlia/find_data.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/find_data.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/find_data.Tpo $(DEPDIR)/find_data.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/find_data.cpp' object='find_data.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o find_data.o `test -f '$(libt_src_dir)/kademlia/find_data.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/find_data.cpp
+
+find_data.obj: $(libt_src_dir)/kademlia/find_data.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT find_data.obj -MD -MP -MF $(DEPDIR)/find_data.Tpo -c -o find_data.obj `if test -f '$(libt_src_dir)/kademlia/find_data.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/find_data.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/find_data.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/find_data.Tpo $(DEPDIR)/find_data.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/find_data.cpp' object='find_data.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o find_data.obj `if test -f '$(libt_src_dir)/kademlia/find_data.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/find_data.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/find_data.cpp'; fi`
+
+node.o: $(libt_src_dir)/kademlia/node.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT node.o -MD -MP -MF $(DEPDIR)/node.Tpo -c -o node.o `test -f '$(libt_src_dir)/kademlia/node.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/node.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/node.Tpo $(DEPDIR)/node.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/node.cpp' object='node.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o node.o `test -f '$(libt_src_dir)/kademlia/node.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/node.cpp
+
+node.obj: $(libt_src_dir)/kademlia/node.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT node.obj -MD -MP -MF $(DEPDIR)/node.Tpo -c -o node.obj `if test -f '$(libt_src_dir)/kademlia/node.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/node.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/node.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/node.Tpo $(DEPDIR)/node.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/node.cpp' object='node.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o node.obj `if test -f '$(libt_src_dir)/kademlia/node.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/node.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/node.cpp'; fi`
+
+node_id.o: $(libt_src_dir)/kademlia/node_id.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT node_id.o -MD -MP -MF $(DEPDIR)/node_id.Tpo -c -o node_id.o `test -f '$(libt_src_dir)/kademlia/node_id.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/node_id.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/node_id.Tpo $(DEPDIR)/node_id.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/node_id.cpp' object='node_id.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o node_id.o `test -f '$(libt_src_dir)/kademlia/node_id.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/node_id.cpp
+
+node_id.obj: $(libt_src_dir)/kademlia/node_id.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT node_id.obj -MD -MP -MF $(DEPDIR)/node_id.Tpo -c -o node_id.obj `if test -f '$(libt_src_dir)/kademlia/node_id.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/node_id.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/node_id.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/node_id.Tpo $(DEPDIR)/node_id.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/node_id.cpp' object='node_id.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o node_id.obj `if test -f '$(libt_src_dir)/kademlia/node_id.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/node_id.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/node_id.cpp'; fi`
+
+refresh.o: $(libt_src_dir)/kademlia/refresh.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT refresh.o -MD -MP -MF $(DEPDIR)/refresh.Tpo -c -o refresh.o `test -f '$(libt_src_dir)/kademlia/refresh.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/refresh.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/refresh.Tpo $(DEPDIR)/refresh.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/refresh.cpp' object='refresh.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o refresh.o `test -f '$(libt_src_dir)/kademlia/refresh.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/refresh.cpp
+
+refresh.obj: $(libt_src_dir)/kademlia/refresh.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT refresh.obj -MD -MP -MF $(DEPDIR)/refresh.Tpo -c -o refresh.obj `if test -f '$(libt_src_dir)/kademlia/refresh.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/refresh.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/refresh.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/refresh.Tpo $(DEPDIR)/refresh.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/refresh.cpp' object='refresh.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o refresh.obj `if test -f '$(libt_src_dir)/kademlia/refresh.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/refresh.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/refresh.cpp'; fi`
+
+routing_table.o: $(libt_src_dir)/kademlia/routing_table.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT routing_table.o -MD -MP -MF $(DEPDIR)/routing_table.Tpo -c -o routing_table.o `test -f '$(libt_src_dir)/kademlia/routing_table.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/routing_table.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/routing_table.Tpo $(DEPDIR)/routing_table.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/routing_table.cpp' object='routing_table.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o routing_table.o `test -f '$(libt_src_dir)/kademlia/routing_table.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/routing_table.cpp
+
+routing_table.obj: $(libt_src_dir)/kademlia/routing_table.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT routing_table.obj -MD -MP -MF $(DEPDIR)/routing_table.Tpo -c -o routing_table.obj `if test -f '$(libt_src_dir)/kademlia/routing_table.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/routing_table.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/routing_table.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/routing_table.Tpo $(DEPDIR)/routing_table.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/routing_table.cpp' object='routing_table.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o routing_table.obj `if test -f '$(libt_src_dir)/kademlia/routing_table.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/routing_table.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/routing_table.cpp'; fi`
+
+rpc_manager.o: $(libt_src_dir)/kademlia/rpc_manager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT rpc_manager.o -MD -MP -MF $(DEPDIR)/rpc_manager.Tpo -c -o rpc_manager.o `test -f '$(libt_src_dir)/kademlia/rpc_manager.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/rpc_manager.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/rpc_manager.Tpo $(DEPDIR)/rpc_manager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/rpc_manager.cpp' object='rpc_manager.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o rpc_manager.o `test -f '$(libt_src_dir)/kademlia/rpc_manager.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/rpc_manager.cpp
+
+rpc_manager.obj: $(libt_src_dir)/kademlia/rpc_manager.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT rpc_manager.obj -MD -MP -MF $(DEPDIR)/rpc_manager.Tpo -c -o rpc_manager.obj `if test -f '$(libt_src_dir)/kademlia/rpc_manager.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/rpc_manager.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/rpc_manager.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/rpc_manager.Tpo $(DEPDIR)/rpc_manager.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/rpc_manager.cpp' object='rpc_manager.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o rpc_manager.obj `if test -f '$(libt_src_dir)/kademlia/rpc_manager.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/rpc_manager.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/rpc_manager.cpp'; fi`
+
+traversal_algorithm.o: $(libt_src_dir)/kademlia/traversal_algorithm.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT traversal_algorithm.o -MD -MP -MF $(DEPDIR)/traversal_algorithm.Tpo -c -o traversal_algorithm.o `test -f '$(libt_src_dir)/kademlia/traversal_algorithm.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/traversal_algorithm.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/traversal_algorithm.Tpo $(DEPDIR)/traversal_algorithm.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/traversal_algorithm.cpp' object='traversal_algorithm.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o traversal_algorithm.o `test -f '$(libt_src_dir)/kademlia/traversal_algorithm.cpp' || echo '$(srcdir)/'`$(libt_src_dir)/kademlia/traversal_algorithm.cpp
+
+traversal_algorithm.obj: $(libt_src_dir)/kademlia/traversal_algorithm.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT traversal_algorithm.obj -MD -MP -MF $(DEPDIR)/traversal_algorithm.Tpo -c -o traversal_algorithm.obj `if test -f '$(libt_src_dir)/kademlia/traversal_algorithm.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/traversal_algorithm.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/traversal_algorithm.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/traversal_algorithm.Tpo $(DEPDIR)/traversal_algorithm.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(libt_src_dir)/kademlia/traversal_algorithm.cpp' object='traversal_algorithm.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o traversal_algorithm.obj `if test -f '$(libt_src_dir)/kademlia/traversal_algorithm.cpp'; then $(CYGPATH_W) '$(libt_src_dir)/kademlia/traversal_algorithm.cpp'; else $(CYGPATH_W) '$(srcdir)/$(libt_src_dir)/kademlia/traversal_algorithm.cpp'; fi`
+
+se_utils.o: src/settings++/se_utils.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT se_utils.o -MD -MP -MF $(DEPDIR)/se_utils.Tpo -c -o se_utils.o `test -f 'src/settings++/se_utils.cpp' || echo '$(srcdir)/'`src/settings++/se_utils.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/se_utils.Tpo $(DEPDIR)/se_utils.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/se_utils.cpp' object='se_utils.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o se_utils.o `test -f 'src/settings++/se_utils.cpp' || echo '$(srcdir)/'`src/settings++/se_utils.cpp
+
+se_utils.obj: src/settings++/se_utils.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT se_utils.obj -MD -MP -MF $(DEPDIR)/se_utils.Tpo -c -o se_utils.obj `if test -f 'src/settings++/se_utils.cpp'; then $(CYGPATH_W) 'src/settings++/se_utils.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/se_utils.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/se_utils.Tpo $(DEPDIR)/se_utils.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/se_utils.cpp' object='se_utils.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o se_utils.obj `if test -f 'src/settings++/se_utils.cpp'; then $(CYGPATH_W) 'src/settings++/se_utils.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/se_utils.cpp'; fi`
+
+frame.o: src/settings++/frame.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT frame.o -MD -MP -MF $(DEPDIR)/frame.Tpo -c -o frame.o `test -f 'src/settings++/frame.cpp' || echo '$(srcdir)/'`src/settings++/frame.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/frame.Tpo $(DEPDIR)/frame.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/frame.cpp' object='frame.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o frame.o `test -f 'src/settings++/frame.cpp' || echo '$(srcdir)/'`src/settings++/frame.cpp
+
+frame.obj: src/settings++/frame.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT frame.obj -MD -MP -MF $(DEPDIR)/frame.Tpo -c -o frame.obj `if test -f 'src/settings++/frame.cpp'; then $(CYGPATH_W) 'src/settings++/frame.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/frame.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/frame.Tpo $(DEPDIR)/frame.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/frame.cpp' object='frame.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o frame.obj `if test -f 'src/settings++/frame.cpp'; then $(CYGPATH_W) 'src/settings++/frame.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/frame.cpp'; fi`
+
+tab_ui.o: src/settings++/tab_ui.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_ui.o -MD -MP -MF $(DEPDIR)/tab_ui.Tpo -c -o tab_ui.o `test -f 'src/settings++/tab_ui.cpp' || echo '$(srcdir)/'`src/settings++/tab_ui.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_ui.Tpo $(DEPDIR)/tab_ui.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_ui.cpp' object='tab_ui.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_ui.o `test -f 'src/settings++/tab_ui.cpp' || echo '$(srcdir)/'`src/settings++/tab_ui.cpp
+
+tab_ui.obj: src/settings++/tab_ui.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_ui.obj -MD -MP -MF $(DEPDIR)/tab_ui.Tpo -c -o tab_ui.obj `if test -f 'src/settings++/tab_ui.cpp'; then $(CYGPATH_W) 'src/settings++/tab_ui.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_ui.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_ui.Tpo $(DEPDIR)/tab_ui.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_ui.cpp' object='tab_ui.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_ui.obj `if test -f 'src/settings++/tab_ui.cpp'; then $(CYGPATH_W) 'src/settings++/tab_ui.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_ui.cpp'; fi`
+
+tab_render_detail.o: src/settings++/tab_render_detail.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_render_detail.o -MD -MP -MF $(DEPDIR)/tab_render_detail.Tpo -c -o tab_render_detail.o `test -f 'src/settings++/tab_render_detail.cpp' || echo '$(srcdir)/'`src/settings++/tab_render_detail.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_render_detail.Tpo $(DEPDIR)/tab_render_detail.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_render_detail.cpp' object='tab_render_detail.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_render_detail.o `test -f 'src/settings++/tab_render_detail.cpp' || echo '$(srcdir)/'`src/settings++/tab_render_detail.cpp
+
+tab_render_detail.obj: src/settings++/tab_render_detail.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_render_detail.obj -MD -MP -MF $(DEPDIR)/tab_render_detail.Tpo -c -o tab_render_detail.obj `if test -f 'src/settings++/tab_render_detail.cpp'; then $(CYGPATH_W) 'src/settings++/tab_render_detail.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_render_detail.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_render_detail.Tpo $(DEPDIR)/tab_render_detail.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_render_detail.cpp' object='tab_render_detail.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_render_detail.obj `if test -f 'src/settings++/tab_render_detail.cpp'; then $(CYGPATH_W) 'src/settings++/tab_render_detail.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_render_detail.cpp'; fi`
+
+tab_audio.o: src/settings++/tab_audio.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_audio.o -MD -MP -MF $(DEPDIR)/tab_audio.Tpo -c -o tab_audio.o `test -f 'src/settings++/tab_audio.cpp' || echo '$(srcdir)/'`src/settings++/tab_audio.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_audio.Tpo $(DEPDIR)/tab_audio.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_audio.cpp' object='tab_audio.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_audio.o `test -f 'src/settings++/tab_audio.cpp' || echo '$(srcdir)/'`src/settings++/tab_audio.cpp
+
+tab_audio.obj: src/settings++/tab_audio.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_audio.obj -MD -MP -MF $(DEPDIR)/tab_audio.Tpo -c -o tab_audio.obj `if test -f 'src/settings++/tab_audio.cpp'; then $(CYGPATH_W) 'src/settings++/tab_audio.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_audio.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_audio.Tpo $(DEPDIR)/tab_audio.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_audio.cpp' object='tab_audio.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_audio.obj `if test -f 'src/settings++/tab_audio.cpp'; then $(CYGPATH_W) 'src/settings++/tab_audio.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_audio.cpp'; fi`
+
+tab_abstract.o: src/settings++/tab_abstract.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_abstract.o -MD -MP -MF $(DEPDIR)/tab_abstract.Tpo -c -o tab_abstract.o `test -f 'src/settings++/tab_abstract.cpp' || echo '$(srcdir)/'`src/settings++/tab_abstract.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_abstract.Tpo $(DEPDIR)/tab_abstract.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_abstract.cpp' object='tab_abstract.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_abstract.o `test -f 'src/settings++/tab_abstract.cpp' || echo '$(srcdir)/'`src/settings++/tab_abstract.cpp
+
+tab_abstract.obj: src/settings++/tab_abstract.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_abstract.obj -MD -MP -MF $(DEPDIR)/tab_abstract.Tpo -c -o tab_abstract.obj `if test -f 'src/settings++/tab_abstract.cpp'; then $(CYGPATH_W) 'src/settings++/tab_abstract.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_abstract.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_abstract.Tpo $(DEPDIR)/tab_abstract.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_abstract.cpp' object='tab_abstract.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_abstract.obj `if test -f 'src/settings++/tab_abstract.cpp'; then $(CYGPATH_W) 'src/settings++/tab_abstract.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_abstract.cpp'; fi`
+
+tab_simple.o: src/settings++/tab_simple.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_simple.o -MD -MP -MF $(DEPDIR)/tab_simple.Tpo -c -o tab_simple.o `test -f 'src/settings++/tab_simple.cpp' || echo '$(srcdir)/'`src/settings++/tab_simple.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_simple.Tpo $(DEPDIR)/tab_simple.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_simple.cpp' object='tab_simple.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_simple.o `test -f 'src/settings++/tab_simple.cpp' || echo '$(srcdir)/'`src/settings++/tab_simple.cpp
+
+tab_simple.obj: src/settings++/tab_simple.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_simple.obj -MD -MP -MF $(DEPDIR)/tab_simple.Tpo -c -o tab_simple.obj `if test -f 'src/settings++/tab_simple.cpp'; then $(CYGPATH_W) 'src/settings++/tab_simple.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_simple.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_simple.Tpo $(DEPDIR)/tab_simple.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_simple.cpp' object='tab_simple.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_simple.obj `if test -f 'src/settings++/tab_simple.cpp'; then $(CYGPATH_W) 'src/settings++/tab_simple.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_simple.cpp'; fi`
+
+tab_quality_video.o: src/settings++/tab_quality_video.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_quality_video.o -MD -MP -MF $(DEPDIR)/tab_quality_video.Tpo -c -o tab_quality_video.o `test -f 'src/settings++/tab_quality_video.cpp' || echo '$(srcdir)/'`src/settings++/tab_quality_video.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_quality_video.Tpo $(DEPDIR)/tab_quality_video.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_quality_video.cpp' object='tab_quality_video.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_quality_video.o `test -f 'src/settings++/tab_quality_video.cpp' || echo '$(srcdir)/'`src/settings++/tab_quality_video.cpp
+
+tab_quality_video.obj: src/settings++/tab_quality_video.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT tab_quality_video.obj -MD -MP -MF $(DEPDIR)/tab_quality_video.Tpo -c -o tab_quality_video.obj `if test -f 'src/settings++/tab_quality_video.cpp'; then $(CYGPATH_W) 'src/settings++/tab_quality_video.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_quality_video.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/tab_quality_video.Tpo $(DEPDIR)/tab_quality_video.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/tab_quality_video.cpp' object='tab_quality_video.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o tab_quality_video.obj `if test -f 'src/settings++/tab_quality_video.cpp'; then $(CYGPATH_W) 'src/settings++/tab_quality_video.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/tab_quality_video.cpp'; fi`
+
+panel_pathoption.o: src/settings++/panel_pathoption.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT panel_pathoption.o -MD -MP -MF $(DEPDIR)/panel_pathoption.Tpo -c -o panel_pathoption.o `test -f 'src/settings++/panel_pathoption.cpp' || echo '$(srcdir)/'`src/settings++/panel_pathoption.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/panel_pathoption.Tpo $(DEPDIR)/panel_pathoption.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/panel_pathoption.cpp' object='panel_pathoption.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o panel_pathoption.o `test -f 'src/settings++/panel_pathoption.cpp' || echo '$(srcdir)/'`src/settings++/panel_pathoption.cpp
+
+panel_pathoption.obj: src/settings++/panel_pathoption.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT panel_pathoption.obj -MD -MP -MF $(DEPDIR)/panel_pathoption.Tpo -c -o panel_pathoption.obj `if test -f 'src/settings++/panel_pathoption.cpp'; then $(CYGPATH_W) 'src/settings++/panel_pathoption.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/panel_pathoption.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/panel_pathoption.Tpo $(DEPDIR)/panel_pathoption.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/panel_pathoption.cpp' object='panel_pathoption.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o panel_pathoption.obj `if test -f 'src/settings++/panel_pathoption.cpp'; then $(CYGPATH_W) 'src/settings++/panel_pathoption.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/panel_pathoption.cpp'; fi`
+
+custom_dialogs.o: src/settings++/custom_dialogs.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT custom_dialogs.o -MD -MP -MF $(DEPDIR)/custom_dialogs.Tpo -c -o custom_dialogs.o `test -f 'src/settings++/custom_dialogs.cpp' || echo '$(srcdir)/'`src/settings++/custom_dialogs.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/custom_dialogs.Tpo $(DEPDIR)/custom_dialogs.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/custom_dialogs.cpp' object='custom_dialogs.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o custom_dialogs.o `test -f 'src/settings++/custom_dialogs.cpp' || echo '$(srcdir)/'`src/settings++/custom_dialogs.cpp
+
+custom_dialogs.obj: src/settings++/custom_dialogs.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT custom_dialogs.obj -MD -MP -MF $(DEPDIR)/custom_dialogs.Tpo -c -o custom_dialogs.obj `if test -f 'src/settings++/custom_dialogs.cpp'; then $(CYGPATH_W) 'src/settings++/custom_dialogs.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/custom_dialogs.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/custom_dialogs.Tpo $(DEPDIR)/custom_dialogs.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/custom_dialogs.cpp' object='custom_dialogs.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o custom_dialogs.obj `if test -f 'src/settings++/custom_dialogs.cpp'; then $(CYGPATH_W) 'src/settings++/custom_dialogs.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/custom_dialogs.cpp'; fi`
+
+helpmenufunctions.o: src/settings++/helpmenufunctions.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT helpmenufunctions.o -MD -MP -MF $(DEPDIR)/helpmenufunctions.Tpo -c -o helpmenufunctions.o `test -f 'src/settings++/helpmenufunctions.cpp' || echo '$(srcdir)/'`src/settings++/helpmenufunctions.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/helpmenufunctions.Tpo $(DEPDIR)/helpmenufunctions.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/helpmenufunctions.cpp' object='helpmenufunctions.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o helpmenufunctions.o `test -f 'src/settings++/helpmenufunctions.cpp' || echo '$(srcdir)/'`src/settings++/helpmenufunctions.cpp
+
+helpmenufunctions.obj: src/settings++/helpmenufunctions.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT helpmenufunctions.obj -MD -MP -MF $(DEPDIR)/helpmenufunctions.Tpo -c -o helpmenufunctions.obj `if test -f 'src/settings++/helpmenufunctions.cpp'; then $(CYGPATH_W) 'src/settings++/helpmenufunctions.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/helpmenufunctions.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/helpmenufunctions.Tpo $(DEPDIR)/helpmenufunctions.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/helpmenufunctions.cpp' object='helpmenufunctions.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o helpmenufunctions.obj `if test -f 'src/settings++/helpmenufunctions.cpp'; then $(CYGPATH_W) 'src/settings++/helpmenufunctions.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/helpmenufunctions.cpp'; fi`
+
+Main.o: src/settings++/Main.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Main.o -MD -MP -MF $(DEPDIR)/Main.Tpo -c -o Main.o `test -f 'src/settings++/Main.cpp' || echo '$(srcdir)/'`src/settings++/Main.cpp
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Main.Tpo $(DEPDIR)/Main.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/Main.cpp' object='Main.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Main.o `test -f 'src/settings++/Main.cpp' || echo '$(srcdir)/'`src/settings++/Main.cpp
+
+Main.obj: src/settings++/Main.cpp
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Main.obj -MD -MP -MF $(DEPDIR)/Main.Tpo -c -o Main.obj `if test -f 'src/settings++/Main.cpp'; then $(CYGPATH_W) 'src/settings++/Main.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/Main.cpp'; fi`
+ at am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/Main.Tpo $(DEPDIR)/Main.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/settings++/Main.cpp' object='Main.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Main.obj `if test -f 'src/settings++/Main.cpp'; then $(CYGPATH_W) 'src/settings++/Main.cpp'; else $(CYGPATH_W) '$(srcdir)/src/settings++/Main.cpp'; fi`
+install-dist_desktopDATA: $(dist_desktop_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(desktopdir)" || $(MKDIR_P) "$(DESTDIR)$(desktopdir)"
+ @list='$(dist_desktop_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(dist_desktopDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(desktopdir)/$$f'"; \
+ $(dist_desktopDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(desktopdir)/$$f"; \
+ done
+
+uninstall-dist_desktopDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_desktop_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(desktopdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(desktopdir)/$$f"; \
+ done
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
+ @list='$(dist_doc_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \
+ $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(docdir)/$$f"; \
+ done
+install-dist_pixmapDATA: $(dist_pixmap_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pixmapdir)" || $(MKDIR_P) "$(DESTDIR)$(pixmapdir)"
+ @list='$(dist_pixmap_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(dist_pixmapDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pixmapdir)/$$f'"; \
+ $(dist_pixmapDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pixmapdir)/$$f"; \
+ done
+
+uninstall-dist_pixmapDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pixmap_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(pixmapdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(pixmapdir)/$$f"; \
+ done
+
+# 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):
+ @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; \
+ (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):
+ @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; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (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; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ 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 || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) 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; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) 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)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && 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 $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$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; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -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-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) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lzma*) \
+ unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(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)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && 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
+ $(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:
+ @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 $(PROGRAMS) $(DATA) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pixmapdir)"; 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)
+ -rm -f src/$(DEPDIR)/$(am__dirstamp)
+ -rm -f src/$(am__dirstamp)
+ -rm -f src/settings++/$(DEPDIR)/$(am__dirstamp)
+ -rm -f src/settings++/$(am__dirstamp)
+
+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-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-dist_desktopDATA install-dist_docDATA \
+ install-dist_pixmapDATA
+
+install-dvi: install-dvi-recursive
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-recursive
+
+install-info: install-info-recursive
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-ps: install-ps-recursive
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-dist_desktopDATA \
+ uninstall-dist_docDATA uninstall-dist_pixmapDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+ install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am am--refresh check check-am clean clean-binPROGRAMS \
+ clean-generic ctags ctags-recursive dist dist-all dist-bzip2 \
+ dist-gzip dist-lzma dist-shar dist-tarZ dist-zip distcheck \
+ distclean distclean-compile distclean-generic distclean-hdr \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am \
+ install-dist_desktopDATA install-dist_docDATA \
+ install-dist_pixmapDATA 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-compile mostlyclean-generic pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-dist_desktopDATA \
+ uninstall-dist_docDATA uninstall-dist_pixmapDATA
+
+ at USE_WINDRES_TRUE@.rc.o:
+ at USE_WINDRES_TRUE@ $(RESOURCECOMPILE) -o $@ -i $<
+# 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:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..fdfb2e0
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,6 @@
+we provide two mailinglists:
+http://springlobby.info/cgi-bin/mailman/listinfo/devel for general discussion
+http://springlobby.info/cgi-bin/mailman/listinfo/releases for release notifications and such
+
+you may also want to visit our wiki, especially the roadmap:
+http://trac.springlobby.info/roadmap
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..f39bf7c
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+all installation information can be found here:
+http://springlobby.info/wiki/springlobby/Install
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..409feed
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,15 @@
+accAgon for suse open build service maintenance for several rpm-based distros
+MelTrax for windows installer, news reporter, in-battle table sorting and fixed various windows-only bugs
+dizekat for help on wxwidgets logging functions and unicode
+tombom for adding channel automatic joining, option to disable join/part messages and rank selection for hosting
+heze for apache and zonefile consultation
+AF for consultation on generating TASClient compatible scripts
+www.famfamfam.com for the flag icons
+tango.freedesktop.org for sidebar icons
+kNeu and Nuovo projects for some icons
+curved for current rank icons
+everybody who has put in an effort translating
+danuker for the sword icon
+morphriz for his patch to allow to play sounds using SDL_sound
+all the translators for their hard work
+Lamego (from wxForum) for the textcontrol with built-in history
\ No newline at end of file
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..3ea1a8d
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,880 @@
+# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 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.
+
+# 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(AC_AUTOCONF_VERSION, [2.61],,
+[m4_warning([this file was generated for autoconf 2.61.
+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 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.10'
+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.10.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 AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.10.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(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
+# 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 8
+
+# 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
+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
+# 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
+
+# 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
+ 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
+
+ case $depmode in
+ 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
+ ;;
+ none) break ;;
+ esac
+ # 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.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} 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 sub/conftest.${OBJEXT-o} 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
+# 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 3
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; 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 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 13
+
+# 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.60])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)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+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
+])
+])
+
+
+# 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 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
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+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 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 3
+
+# 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 done
+.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
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 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 5
+
+# 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
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# 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 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 3
+
+# _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],
+[AC_FOREACH([_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])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 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.
+
+# serial 4
+
+# 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
+# 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) 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 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_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_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 <conftest.tar])
+ grep GrepMe conftest.dir/file >/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/gettext.m4])
+m4_include([m4/iconv.m4])
+m4_include([m4/intlmacosx.m4])
+m4_include([m4/lib-ld.m4])
+m4_include([m4/lib-link.m4])
+m4_include([m4/lib-prefix.m4])
+m4_include([m4/nls.m4])
+m4_include([m4/pkg.m4])
+m4_include([m4/po.m4])
+m4_include([m4/progtest.m4])
+m4_include([m4/sdl.m4])
+m4_include([m4/wxwin.m4])
diff --git a/autotools-aux/config.guess b/autotools-aux/config.guess
new file mode 100755
index 0000000..278f9e9
--- /dev/null
+++ b/autotools-aux/config.guess
@@ -0,0 +1,1516 @@
+#! /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 Free Software Foundation,
+# Inc.
+
+timestamp='2007-07-22'
+
+# 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 <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>. Submit a context
+# diff and a properly formatted 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.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+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 <config-patches at gnu.org>."
+
+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
+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 at 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 __ELF__ >/dev/null
+ 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 at 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 ;;
+ 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:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ echo i386-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 <stdio.h> /* 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 <sys/systemcfg.h>
+
+ 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:*:[45])
+ 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 <stdlib.h>
+ #include <unistd.h>
+
+ 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 __LP64__ >/dev/null
+ 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 <unistd.h>
+ 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*:[3456]*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ EM64T | authenticamd)
+ echo x86_64-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 ;;
+ 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 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ 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 ;;
+ 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:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ 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 ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ 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 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-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 xtensa-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^LIBC/{
+ s: ::g
+ p
+ }'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; 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.0*:*)
+ 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' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/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 i386.
+ echo i386-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; } ;;
+ 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.0*:*)
+ 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 <Richard.M.Bartel at ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes at openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf at swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green at stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green at 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 ;;
+ 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
+ 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 ;;
+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 <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#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 <sys/param.h>
+ 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 <sys/param.h>
+# 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 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> 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:
diff --git a/autotools-aux/config.rpath b/autotools-aux/config.rpath
new file mode 100755
index 0000000..c547c68
--- /dev/null
+++ b/autotools-aux/config.rpath
@@ -0,0 +1,666 @@
+#! /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-2007 Free Software Foundation, Inc.
+# Taken from GNU libtool, 2001
+# Originally by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 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* | cygwin* | pw32* | os2*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ wl='-Wl,'
+ ;;
+ irix5* | irix6* | nonstopux*)
+ wl='-Wl,'
+ ;;
+ newsos6)
+ ;;
+ linux* | k*bsd*-gnu)
+ 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,'
+ ;;
+ rdos*)
+ ;;
+ solaris*)
+ wl='-Wl,'
+ ;;
+ sunos4*)
+ wl='-Qoption ld '
+ ;;
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ wl='-Wl,'
+ ;;
+ sysv4*MP*)
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ wl='-Wl,'
+ ;;
+ 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 <kc5tja at dolphin.openprojects.net> 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
+ ;;
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ gnu* | linux* | k*bsd*-gnu)
+ 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
+ :
+ 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* | 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*)
+ if test -f /usr/libexec/ld.so; then
+ 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
+ else
+ ld_shlibs=no
+ 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* | sco3.2v5.0.[024]*)
+ ;;
+ 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.
+# Unlike libtool.m4, here we don't care about _all_ names of the library, but
+# only about the one the linker finds when passed -lNAME. This is the last
+# element of library_names_spec in libtool.m4, or possibly two of them if the
+# linker has special search rules.
+library_names_spec= # the last element of library_names_spec in libtool.m4
+libname_spec='lib$name'
+case "$host_os" in
+ aix3*)
+ library_names_spec='$libname.a'
+ ;;
+ aix4* | aix5*)
+ library_names_spec='$libname$shrext'
+ ;;
+ amigaos*)
+ library_names_spec='$libname.a'
+ ;;
+ beos*)
+ library_names_spec='$libname$shrext'
+ ;;
+ bsdi[45]*)
+ library_names_spec='$libname$shrext'
+ ;;
+ cygwin* | mingw* | pw32*)
+ shrext=.dll
+ library_names_spec='$libname.dll.a $libname.lib'
+ ;;
+ darwin* | rhapsody*)
+ shrext=.dylib
+ library_names_spec='$libname$shrext'
+ ;;
+ dgux*)
+ library_names_spec='$libname$shrext'
+ ;;
+ freebsd1*)
+ ;;
+ freebsd* | dragonfly*)
+ case "$host_os" in
+ freebsd[123]*)
+ library_names_spec='$libname$shrext$versuffix' ;;
+ *)
+ library_names_spec='$libname$shrext' ;;
+ esac
+ ;;
+ gnu*)
+ library_names_spec='$libname$shrext'
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $host_cpu in
+ ia64*)
+ shrext=.so
+ ;;
+ hppa*64*)
+ shrext=.sl
+ ;;
+ *)
+ shrext=.sl
+ ;;
+ esac
+ library_names_spec='$libname$shrext'
+ ;;
+ interix[3-9]*)
+ library_names_spec='$libname$shrext'
+ ;;
+ irix5* | irix6* | nonstopux*)
+ library_names_spec='$libname$shrext'
+ 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* | k*bsd*-gnu)
+ library_names_spec='$libname$shrext'
+ ;;
+ knetbsd*-gnu)
+ library_names_spec='$libname$shrext'
+ ;;
+ netbsd*)
+ library_names_spec='$libname$shrext'
+ ;;
+ newsos6)
+ library_names_spec='$libname$shrext'
+ ;;
+ nto-qnx*)
+ library_names_spec='$libname$shrext'
+ ;;
+ openbsd*)
+ library_names_spec='$libname$shrext$versuffix'
+ ;;
+ os2*)
+ libname_spec='$name'
+ shrext=.dll
+ library_names_spec='$libname.a'
+ ;;
+ osf3* | osf4* | osf5*)
+ library_names_spec='$libname$shrext'
+ ;;
+ rdos*)
+ ;;
+ solaris*)
+ library_names_spec='$libname$shrext'
+ ;;
+ sunos4*)
+ library_names_spec='$libname$shrext$versuffix'
+ ;;
+ sysv4 | sysv4.3*)
+ library_names_spec='$libname$shrext'
+ ;;
+ sysv4*MP*)
+ library_names_spec='$libname$shrext'
+ ;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ library_names_spec='$libname$shrext'
+ ;;
+ uts4*)
+ library_names_spec='$libname$shrext'
+ ;;
+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_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+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=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Format of library name prefix.
+libname_spec="$escaped_libname_spec"
+
+# Library names that the linker finds when passed -lNAME.
+library_names_spec="$escaped_library_names_spec"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/autotools-aux/config.sub b/autotools-aux/config.sub
new file mode 100755
index 0000000..1761d8b
--- /dev/null
+++ b/autotools-aux/config.sub
@@ -0,0 +1,1626 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2007-06-28'
+
+# 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 <config-patches at gnu.org>. Submit a context
+# diff and a properly formatted 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.
+
+# 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 <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+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* | \
+ 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)
+ os=
+ basic_machine=$1
+ ;;
+ -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 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | score \
+ | sh | sh[1234] | sh[24]a | 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 \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # 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-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | 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-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | 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-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # 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
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ 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
+ ;;
+ 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
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ 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
+ ;;
+ 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
+ ;;
+ 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
+ ;;
+ 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[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.
+ -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* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -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* \
+ | -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*)
+ # 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
+ ;;
+ -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
+ ;;
+ -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:
diff --git a/autotools-aux/depcomp b/autotools-aux/depcomp
new file mode 100755
index 0000000..e5f9736
--- /dev/null
+++ b/autotools-aux/depcomp
@@ -0,0 +1,589 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2007-03-29.01
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007 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, 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 Alexandre Oliva <oliva at dcc.unicamp.br>.
+
+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 <bug-automake at gnu.org>.
+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
+
+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 $1 != '--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 $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ 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.
+ -*|$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 $1 != '--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, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+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-end: "$"
+# End:
diff --git a/autotools-aux/install-sh b/autotools-aux/install-sh
new file mode 100755
index 0000000..a5897de
--- /dev/null
+++ b/autotools-aux/install-sh
@@ -0,0 +1,519 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2006-12-25.00
+
+# 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-end: "$"
+# End:
diff --git a/autotools-aux/missing b/autotools-aux/missing
new file mode 100755
index 0000000..1c8ff70
--- /dev/null
+++ b/autotools-aux/missing
@@ -0,0 +1,367 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2006-05-10.23
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard at iro.umontreal.ca>, 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, 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.
+
+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]
+
+Send bug reports to <bug-automake at gnu.org>."
+ 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
+
+# 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).
+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 $1 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 1
+ 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-end: "$"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..0e01c54
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,50 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* */
+#undef AUX_VERSION
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#undef ENABLE_NLS
+
+/* 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 if the GNU dcgettext() function is already present or preinstalled.
+ */
+#undef HAVE_DCGETTEXT
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#undef HAVE_GETTEXT
+
+/* Define if you have the iconv() function and it works. */
+#undef HAVE_ICONV
+
+/* Define to 1 if wxWidgets is at least version 2.8.0 */
+#undef HAVE_WX28
+
+/* 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 version of this package. */
+#undef PACKAGE_VERSION
+
+/* Version number of package */
+#undef VERSION
diff --git a/configure b/configure
new file mode 100755
index 0000000..7566630
--- /dev/null
+++ b/configure
@@ -0,0 +1,8643 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.61 for SpringLobby 0.29.
+#
+# Report bugs to <devel at www.springlobby.info>.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 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=:
+ # 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
+
+
+
+
+# PATH needs CR
+# 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
+
+# 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
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+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.)
+as_nl='
+'
+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
+ echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+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
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+ if (eval ":") 2>/dev/null; then
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+
+ if test $as_have_required = yes && (eval ":
+(as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=\$LINENO
+ as_lineno_2=\$LINENO
+ test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+ test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+ :
+else
+ as_candidate_shells=
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ case $as_dir in
+ /*)
+ for as_base in sh bash ksh sh5; do
+ as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+ done;;
+ esac
+done
+IFS=$as_save_IFS
+
+
+ for as_shell in $as_candidate_shells $SHELL; do
+ # Try only shells that exist, to save several forks.
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { ("$as_shell") 2> /dev/null <<\_ASEOF
+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
+
+
+:
+_ASEOF
+}; then
+ CONFIG_SHELL=$as_shell
+ as_have_required=yes
+ if { "$as_shell" 2> /dev/null <<\_ASEOF
+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
+
+
+:
+(as_func_return () {
+ (exit $1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+ break
+fi
+
+fi
+
+ done
+
+ if test "x$CONFIG_SHELL" != x; then
+ for as_var in BASH_ENV ENV
+ do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ done
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+ if test $as_have_required = no; then
+ echo This script requires a shell more modern than all the
+ echo shells that I found on your system. Please install a
+ echo modern shell, or manually run the script under such a
+ echo shell if you do have one.
+ { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+ echo No shell found that supports shell functions.
+ echo Please tell autoconf at gnu.org about your system,
+ echo including any error possibly output before this
+ echo message
+}
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. 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" ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); 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
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+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
+fi
+echo >conf$$.file
+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
+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=:
+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 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, 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=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='SpringLobby'
+PACKAGE_TARNAME='springlobby'
+PACKAGE_VERSION='0.29'
+PACKAGE_STRING='SpringLobby 0.29'
+PACKAGE_BUGREPORT='devel at www.springlobby.info'
+
+ac_unique_file="src/springlobbyapp.cpp"
+gt_needs=
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+am__isrc
+CYGPATH_W
+PACKAGE
+VERSION
+ACLOCAL
+AUTOCONF
+AUTOMAKE
+AUTOHEADER
+MAKEINFO
+install_sh
+STRIP
+INSTALL_STRIP_PROGRAM
+mkdir_p
+AWK
+SET_MAKE
+am__leading_dot
+AMTAR
+am__tar
+am__untar
+PKG_CONFIG
+build
+build_cpu
+build_vendor
+build_os
+host
+host_cpu
+host_vendor
+host_os
+CXX
+CXXFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CXX
+EXEEXT
+OBJEXT
+DEPDIR
+am__include
+am__quote
+AMDEP_TRUE
+AMDEP_FALSE
+AMDEPBACKSLASH
+CXXDEPMODE
+am__fastdepCXX_TRUE
+am__fastdepCXX_FALSE
+WX_CONFIG_PATH
+WX_CPPFLAGS
+WX_CFLAGS
+WX_CXXFLAGS
+WX_CFLAGS_ONLY
+WX_CXXFLAGS_ONLY
+WX_LIBS
+WX_LIBS_STATIC
+WX_VERSION
+WINDRES
+LIBTORRENT_CFLAGS
+LIBTORRENT_LIBS
+SDL_CONFIG
+SDL_CFLAGS
+SDL_LIBS
+USE_WINDRES_TRUE
+USE_WINDRES_FALSE
+USE_LIBT_INCLUDED_TRUE
+USE_LIBT_INCLUDED_FALSE
+USE_NLS
+GETTEXT_MACRO_VERSION
+MSGFMT
+GMSGFMT
+MSGFMT_015
+GMSGFMT_015
+XGETTEXT
+XGETTEXT_015
+MSGMERGE
+XGETTEXT_EXTRA_OPTIONS
+CC
+CFLAGS
+ac_ct_CC
+CCDEPMODE
+am__fastdepCC_TRUE
+am__fastdepCC_FALSE
+INTL_MACOSX_LIBS
+LIBICONV
+LTLIBICONV
+INTLLIBS
+LIBINTL
+LTLIBINTL
+POSUB
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+PKG_CONFIG
+CXX
+CXXFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CCC
+WINDRES
+CC
+CFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# 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=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_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+ eval enable_$ac_feature=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_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+ eval enable_$ac_feature=\$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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+ eval with_$ac_package=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+ eval with_$ac_package=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 ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ 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'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+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
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; }
+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
+ 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 .` ||
+ { echo "$as_me: error: Working directory cannot be determined" >&2
+ { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ { echo "$as_me: error: pwd does not report name of working directory" >&2
+ { (exit 1); exit 1; }; }
+
+
+# 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 -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+ 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 .."
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+ { (exit 1); exit 1; }; }
+ 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 SpringLobby 0.29 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/springlobby]
+ --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
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of SpringLobby 0.29:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-torrent-system Disable automatic content downloads via torrent (avoids libtorrent dependency)
+ --disable-sound Enable sound using SDL, needs SDL
+ --enable-debug Enable debugging
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --disable-sdltest Do not try to compile and run a test SDL program
+ --disable-nls do not use Native Language Support
+ --disable-rpath do not hardcode runtime library paths
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-sdl-config=/path/to/sdl-config (optional) for finding right sdl includes
+ --with-boost-prefix=/path/to/boost_topdir (optional) for finding right boost includes
+ --with-opt-level=N (optional) with N = 0..3
+ --with-aux-version='some string' (packager use only)
+ --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH
+ --with-wx-config=CONFIG wx-config script to use (optional)
+ --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional)
+ --with-wx-exec-prefix=PREFIX
+ Exec prefix where wxWidgets is installed (optional)
+ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)
+ --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)
+ --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-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib
+ --without-libintl-prefix don't search for libintl in includedir and libdir
+
+Some influential environment variables:
+ PKG_CONFIG path to pkg-config utility
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ WINDRES Windows resource file compiler command
+ CC C compiler command
+ CFLAGS C compiler flags
+
+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 <devel at www.springlobby.info>.
+_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" || continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`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
+ 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
+SpringLobby configure 0.29
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 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
+cat >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 SpringLobby $as_me 0.29, which was
+generated by GNU Autoconf 2.61. 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=.
+ 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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$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
+ ac_configure_args="$ac_configure_args '$ac_arg'"
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ 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_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ *) $as_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
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ 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'; { (exit 1); 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
+
+# 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
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+ set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+ set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+ set x "$ac_default_prefix/share/config.site" \
+ "$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ 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.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+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,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+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
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`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.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+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_config_headers="$ac_config_headers config.h"
+
+
+ac_aux_dir=
+for ac_dir in autotools-aux "$srcdir"/autotools-aux; 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
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in autotools-aux \"$srcdir\"/autotools-aux" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in autotools-aux \"$srcdir\"/autotools-aux" >&2;}
+ { (exit 1); exit 1; }; }
+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.
+
+
+am__api_version='1.10'
+
+# 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.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+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
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$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'
+
+{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# 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".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}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 $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm -f conftest.sed
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5
+echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; }
+if test -z "$MKDIR_P"; then
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+
+ 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.
+ test -d ./--version && rmdir ./--version
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5
+echo "${ECHO_T}$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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; }
+set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ SET_MAKE=
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+ 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='springlobby'
+ VERSION='0.29'
+
+
+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"}
+
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+
+# 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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&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"
+
+# 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 -'
+
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_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_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_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_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5
+echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5
+echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ PKG_CONFIG=""
+ fi
+
+fi
+
+usetorrent=yes
+# Check whether --enable-torrent-system was given.
+if test "${enable_torrent_system+set}" = set; then
+ enableval=$enable_torrent_system; usetorrent=$enableval
+
+fi
+
+
+sound=yes
+# Check whether --enable-sound was given.
+if test "${enable_sound+set}" = set; then
+ enableval=$enable_sound; sound=$enableval
+
+fi
+
+
+debug=no
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then
+ enableval=$enable_debug; debug=$enableval
+
+fi
+
+
+
+# Check whether --with-sdl-config was given.
+if test "${with_sdl_config+set}" = set; then
+ withval=$with_sdl_config; SDL_CONFIG="$withval"
+fi
+
+
+
+# Check whether --with-boost-prefix was given.
+if test "${with_boost_prefix+set}" = set; then
+ withval=$with_boost_prefix; CXXFLAGS="$CXXFLAGS -I$withval "
+fi
+
+
+
+# Check whether --with-opt-level was given.
+if test "${with_opt_level+set}" = set; then
+ withval=$with_opt_level; CXXFLAGS="$CXXFLAGS -O$withval "
+fi
+
+
+
+# Check whether --with-aux-version was given.
+if test "${with_aux_version+set}" = set; then
+ withval=$with_aux_version;
+cat >>confdefs.h <<_ACEOF
+#define AUX_VERSION " $withval"
+_ACEOF
+
+fi
+
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+{ echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+echo "$as_me: error: invalid value of canonical build" >&2;}
+ { (exit 1); exit 1; }; };;
+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
+
+
+{ echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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` ||
+ { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+echo "$as_me: error: invalid value of canonical host" >&2;}
+ { (exit 1); exit 1; }; };;
+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
+
+
+
+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
+
+
+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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $CXX" >&5
+echo "${ECHO_T}$CXX" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+echo "${ECHO_T}$ac_ct_CXX" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C++ compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler --version >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -v >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -V >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out 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.
+{ echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5
+echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort. b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions. Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; 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 | *.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
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C++ compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C++ compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5
+echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C++ compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; 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 | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; 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 ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; }
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ 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
+{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; }
+GXX=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cxx_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ CXXFLAGS=""
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cxx_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+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
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+echo "${ECHO_T}$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=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
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+{ echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_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="$CXX" am_compiler_list=
+
+{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; }
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ 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
+
+ case $depmode in
+ 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
+ ;;
+ none) break ;;
+ esac
+ # 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.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} 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 sub/conftest.${OBJEXT-o} 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
+{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
+echo "${ECHO_T}$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
+
+
+
+
+
+# Check whether --with-wxdir was given.
+if test "${with_wxdir+set}" = set; then
+ withval=$with_wxdir; wx_config_name="$withval/wx-config"
+ wx_config_args="--inplace"
+fi
+
+
+# Check whether --with-wx-config was given.
+if test "${with_wx_config+set}" = set; then
+ withval=$with_wx_config; wx_config_name="$withval"
+fi
+
+
+# Check whether --with-wx-prefix was given.
+if test "${with_wx_prefix+set}" = set; then
+ withval=$with_wx_prefix; wx_config_prefix="$withval"
+else
+ wx_config_prefix=""
+fi
+
+
+# Check whether --with-wx-exec-prefix was given.
+if test "${with_wx_exec_prefix+set}" = set; then
+ withval=$with_wx_exec_prefix; wx_config_exec_prefix="$withval"
+else
+ wx_config_exec_prefix=""
+fi
+
+
+
+
+
+ if test x${WX_CONFIG_NAME+set} != xset ; then
+ WX_CONFIG_NAME=wx-config
+ fi
+
+ if test "x$wx_config_name" != x ; then
+ WX_CONFIG_NAME="$wx_config_name"
+ fi
+
+ if test x$wx_config_exec_prefix != x ; then
+ wx_config_args="$wx_config_args --exec-prefix=$wx_config_exec_prefix"
+ WX_LOOKUP_PATH="$wx_config_exec_prefix/bin"
+ fi
+ if test x$wx_config_prefix != x ; then
+ wx_config_args="$wx_config_args --prefix=$wx_config_prefix"
+ WX_LOOKUP_PATH="$WX_LOOKUP_PATH:$wx_config_prefix/bin"
+ fi
+ if test "$cross_compiling" = "yes"; then
+ wx_config_args="$wx_config_args --host=$host_alias"
+ fi
+
+ if test -x "$WX_CONFIG_NAME" ; then
+ { echo "$as_me:$LINENO: checking for wx-config" >&5
+echo $ECHO_N "checking for wx-config... $ECHO_C" >&6; }
+ WX_CONFIG_PATH="$WX_CONFIG_NAME"
+ { echo "$as_me:$LINENO: result: $WX_CONFIG_PATH" >&5
+echo "${ECHO_T}$WX_CONFIG_PATH" >&6; }
+ else
+ # Extract the first word of "$WX_CONFIG_NAME", so it can be a program name with args.
+set dummy $WX_CONFIG_NAME; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_WX_CONFIG_PATH+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $WX_CONFIG_PATH in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_WX_CONFIG_PATH="$WX_CONFIG_PATH" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy=""$WX_LOOKUP_PATH:$PATH""
+for as_dir in $as_dummy
+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_WX_CONFIG_PATH="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_WX_CONFIG_PATH" && ac_cv_path_WX_CONFIG_PATH="no"
+ ;;
+esac
+fi
+WX_CONFIG_PATH=$ac_cv_path_WX_CONFIG_PATH
+if test -n "$WX_CONFIG_PATH"; then
+ { echo "$as_me:$LINENO: result: $WX_CONFIG_PATH" >&5
+echo "${ECHO_T}$WX_CONFIG_PATH" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ fi
+
+ if test "$WX_CONFIG_PATH" != "no" ; then
+ WX_VERSION=""
+
+ min_wx_version=2.8.2
+ if test -z "" ; then
+ { echo "$as_me:$LINENO: checking for wxWidgets version >= $min_wx_version" >&5
+echo $ECHO_N "checking for wxWidgets version >= $min_wx_version... $ECHO_C" >&6; }
+ else
+ { echo "$as_me:$LINENO: checking for wxWidgets version >= $min_wx_version ()" >&5
+echo $ECHO_N "checking for wxWidgets version >= $min_wx_version ()... $ECHO_C" >&6; }
+ fi
+
+ WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args base,core,net,adv,aui,xml,html"
+
+ WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null`
+ wx_config_major_version=`echo $WX_VERSION | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'`
+ wx_config_minor_version=`echo $WX_VERSION | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'`
+ wx_config_micro_version=`echo $WX_VERSION | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'`
+
+ wx_requested_major_version=`echo $min_wx_version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'`
+ wx_requested_minor_version=`echo $min_wx_version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'`
+ wx_requested_micro_version=`echo $min_wx_version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'`
+
+
+ wx_ver_ok=""
+ if test "x$WX_VERSION" != x ; then
+ if test $wx_config_major_version -gt $wx_requested_major_version; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_major_version -eq $wx_requested_major_version; then
+ if test $wx_config_minor_version -gt $wx_requested_minor_version; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_minor_version -eq $wx_requested_minor_version; then
+ if test $wx_config_micro_version -ge $wx_requested_micro_version; then
+ wx_ver_ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+
+
+ if test -n "$wx_ver_ok"; then
+
+ { echo "$as_me:$LINENO: result: yes (version $WX_VERSION)" >&5
+echo "${ECHO_T}yes (version $WX_VERSION)" >&6; }
+ WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs`
+
+ { echo "$as_me:$LINENO: checking for wxWidgets static library" >&5
+echo $ECHO_N "checking for wxWidgets static library... $ECHO_C" >&6; }
+ WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs 2>/dev/null`
+ if test "x$WX_LIBS_STATIC" = "x"; then
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ fi
+
+ wx_has_cppflags=""
+ if test $wx_config_major_version -gt 2; then
+ wx_has_cppflags=yes
+ else
+ if test $wx_config_major_version -eq 2; then
+ if test $wx_config_minor_version -gt 2; then
+ wx_has_cppflags=yes
+ else
+ if test $wx_config_minor_version -eq 2; then
+ if test $wx_config_micro_version -ge 6; then
+ wx_has_cppflags=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+
+ if test "x$wx_has_cppflags" = x ; then
+ WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags`
+ WX_CPPFLAGS=$WX_CFLAGS
+ WX_CXXFLAGS=$WX_CFLAGS
+
+ WX_CFLAGS_ONLY=$WX_CFLAGS
+ WX_CXXFLAGS_ONLY=$WX_CFLAGS
+ else
+ WX_CPPFLAGS=`$WX_CONFIG_WITH_ARGS --cppflags`
+ WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags`
+ WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags`
+
+ WX_CFLAGS_ONLY=`echo $WX_CFLAGS | sed "s@^$WX_CPPFLAGS *@@"`
+ WX_CXXFLAGS_ONLY=`echo $WX_CXXFLAGS | sed "s@^$WX_CFLAGS *@@"`
+ fi
+
+ :
+
+ else
+
+ if test "x$WX_VERSION" = x; then
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: no (version $WX_VERSION is not new enough)" >&5
+echo "${ECHO_T}no (version $WX_VERSION is not new enough)" >&6; }
+ fi
+
+ WX_CFLAGS=""
+ WX_CPPFLAGS=""
+ WX_CXXFLAGS=""
+ WX_LIBS=""
+ WX_LIBS_STATIC=""
+ { { echo "$as_me:$LINENO: error:
+ wxWidgets must be installed on your system
+ but wx-config script couldn't be found.
+
+ Please check that wx-config is in path, the directory
+ where wxWidgets libraries are installed (returned by
+ 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+ equivalent variable and wxWidgets version is 2.8.2 or above.
+ " >&5
+echo "$as_me: error:
+ wxWidgets must be installed on your system
+ but wx-config script couldn't be found.
+
+ Please check that wx-config is in path, the directory
+ where wxWidgets libraries are installed (returned by
+ 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+ equivalent variable and wxWidgets version is 2.8.2 or above.
+ " >&2;}
+ { (exit 1); exit 1; }; }
+
+ fi
+ else
+
+ WX_CFLAGS=""
+ WX_CPPFLAGS=""
+ WX_CXXFLAGS=""
+ WX_LIBS=""
+ WX_LIBS_STATIC=""
+ { { echo "$as_me:$LINENO: error:
+ wxWidgets must be installed on your system
+ but wx-config script couldn't be found.
+
+ Please check that wx-config is in path, the directory
+ where wxWidgets libraries are installed (returned by
+ 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+ equivalent variable and wxWidgets version is 2.8.2 or above.
+ " >&5
+echo "$as_me: error:
+ wxWidgets must be installed on your system
+ but wx-config script couldn't be found.
+
+ Please check that wx-config is in path, the directory
+ where wxWidgets libraries are installed (returned by
+ 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+ equivalent variable and wxWidgets version is 2.8.2 or above.
+ " >&2;}
+ { (exit 1); exit 1; }; }
+
+ fi
+
+
+
+
+
+
+
+
+
+
+win_build=0
+
+if test x$host_os = xmingw32msvc ; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args.
+set dummy ${ac_tool_prefix}windres; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_WINDRES+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$WINDRES"; then
+ ac_cv_prog_WINDRES="$WINDRES" # 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_WINDRES="${ac_tool_prefix}windres"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+WINDRES=$ac_cv_prog_WINDRES
+if test -n "$WINDRES"; then
+ { echo "$as_me:$LINENO: result: $WINDRES" >&5
+echo "${ECHO_T}$WINDRES" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_WINDRES"; then
+ ac_ct_WINDRES=$WINDRES
+ # Extract the first word of "windres", so it can be a program name with args.
+set dummy windres; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_WINDRES+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_WINDRES"; then
+ ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # 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_WINDRES="windres"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_WINDRES=$ac_cv_prog_ac_ct_WINDRES
+if test -n "$ac_ct_WINDRES"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_WINDRES" >&5
+echo "${ECHO_T}$ac_ct_WINDRES" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_WINDRES" = x; then
+ WINDRES=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ WINDRES=$ac_ct_WINDRES
+ fi
+else
+ WINDRES="$ac_cv_prog_WINDRES"
+fi
+
+ win_build=1
+ LIBS="$LIBS -liphlpapi"
+ if test x$WINDRES = x: ; then
+ { { echo "$as_me:$LINENO: error: missing required windres windows resource compiler." >&5
+echo "$as_me: error: missing required windres windows resource compiler." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+fi
+
+
+
+if test "$win_build" = 0 ; then
+ if test x$usetorrent = xyes ; then
+ { echo "$as_me:$LINENO: checking for libtorrent from Rasterbar software" >&5
+echo $ECHO_N "checking for libtorrent from Rasterbar software... $ECHO_C" >&6; }
+
+ # Check for libtorrent using the following names: libtorrent-rasterbar, rb-libtorrent,
+ # libtorrent.
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 0.13\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 0.13") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ usetorrent=libtorrent-rasterbar
+else
+ usetorrent=fail
+fi
+ if test x$usetorrent = xfail ; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"rb-libtorrent >= 0.13\"") >&5
+ ($PKG_CONFIG --exists --print-errors "rb-libtorrent >= 0.13") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ usetorrent=rb-libtorrent
+else
+ usetorrent=fail
+fi
+ if test x$usetorrent = xfail ; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libtorrent >= 0.13\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libtorrent >= 0.13") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ usetorrent=libtorrent
+else
+ usetorrent=fail
+fi
+ if test x$usetorrent = xfail ; then
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ { { echo "$as_me:$LINENO: error:
+ Missing required libtorrent library. You can get it from
+ <http://www.rasterbar.com/products/libtorrent/>.
+
+ Please note that some distributions name it rb-libtorrent or
+ libtorrent-rasterbar. This is NOT libtorrent from rakshasa!
+
+ You can skip this dependency by using --disable-torrent-system" >&5
+echo "$as_me: error:
+ Missing required libtorrent library. You can get it from
+ <http://www.rasterbar.com/products/libtorrent/>.
+
+ Please note that some distributions name it rb-libtorrent or
+ libtorrent-rasterbar. This is NOT libtorrent from rakshasa!
+
+ You can skip this dependency by using --disable-torrent-system" >&2;}
+ { (exit 1); exit 1; }; };
+
+ exit
+ fi
+ fi
+ fi
+
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+ # Need to manually define these, since only used PKG_CHECK_EXISTS and not
+ # PKG_CHECK_MODULES above.
+ LIBTORRENT_CFLAGS=`pkg-config $usetorrent --cflags`
+ LIBTORRENT_LIBS=`pkg-config $usetorrent --libs`
+
+
+
+ else
+ CXXFLAGS="$CXXFLAGS -DNO_TORRENT_SYSTEM"
+ fi
+else
+ if test x$usetorrent = xyes ; then
+ CXXFLAGS="$CXXFLAGS -D_WIN32_WINNT=0x0500 -DBOOST_WINDOWS -DTORRENT_DISABLE_ENCRYPTION "
+ LIBS="$LIBS -mthreads -Wl,-allow-multiple-definition -L/var/lib/buildbot/lib/mingw/lib -lboost_thread-mt -lboost_filesystem-mt -lws2_32 -lmswsock -lboost_date_time-mt"
+ else
+ CXXFLAGS="$CXXFLAGS -DNO_TORRENT_SYSTEM"
+ fi
+fi
+
+if test x$sound = xyes ; then
+
+
+# Check whether --with-sdl-prefix was given.
+if test "${with_sdl_prefix+set}" = set; then
+ withval=$with_sdl_prefix; sdl_prefix="$withval"
+else
+ sdl_prefix=""
+fi
+
+
+# Check whether --with-sdl-exec-prefix was given.
+if test "${with_sdl_exec_prefix+set}" = set; then
+ withval=$with_sdl_exec_prefix; sdl_exec_prefix="$withval"
+else
+ sdl_exec_prefix=""
+fi
+
+# Check whether --enable-sdltest was given.
+if test "${enable_sdltest+set}" = set; then
+ enableval=$enable_sdltest;
+else
+ enable_sdltest=yes
+fi
+
+
+ if test x$sdl_exec_prefix != x ; then
+ sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
+ if test x${SDL_CONFIG+set} != xset ; then
+ SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
+ fi
+ fi
+ if test x$sdl_prefix != x ; then
+ sdl_args="$sdl_args --prefix=$sdl_prefix"
+ if test x${SDL_CONFIG+set} != xset ; then
+ SDL_CONFIG=$sdl_prefix/bin/sdl-config
+ fi
+ fi
+
+ if test "x$prefix" != xNONE; then
+ PATH="$prefix/bin:$prefix/usr/bin:$PATH"
+ fi
+ # Extract the first word of "sdl-config", so it can be a program name with args.
+set dummy sdl-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_SDL_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $SDL_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_SDL_CONFIG="$SDL_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_SDL_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_SDL_CONFIG" && ac_cv_path_SDL_CONFIG="no"
+ ;;
+esac
+fi
+SDL_CONFIG=$ac_cv_path_SDL_CONFIG
+if test -n "$SDL_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $SDL_CONFIG" >&5
+echo "${ECHO_T}$SDL_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ min_sdl_version=1.2.10
+ { echo "$as_me:$LINENO: checking for SDL - version >= $min_sdl_version" >&5
+echo $ECHO_N "checking for SDL - version >= $min_sdl_version... $ECHO_C" >&6; }
+ no_sdl=""
+ if test "$SDL_CONFIG" = "no" ; then
+ no_sdl=yes
+ else
+ SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
+ SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
+ SDL_LIBS="$SDL_LIBS -lSDL_mixer"
+
+ sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'`
+ sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'`
+ sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'`
+ if test "x$enable_sdltest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+ rm -f conf.sdltest
+ if test "$cross_compiling" = yes; then
+ echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+ char *new_str;
+
+ if (str)
+ {
+ new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+ strcpy (new_str, str);
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ /* This hangs on some systems (?)
+ system ("touch conf.sdltest");
+ */
+ { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = my_strdup("$min_sdl_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) {
+ printf("%s, bad version string\n", "$min_sdl_version");
+ exit(1);
+ }
+
+ if (($sdl_major_version > major) ||
+ (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+ (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+ printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
+ printf("*** best to upgrade to the required version.\n");
+ printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
+ printf("*** to point to the correct copy of sdl-config, and remove the file\n");
+ printf("*** config.cache before re-running configure\n");
+ return 1;
+ }
+}
+
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+no_sdl=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ if test "x$no_sdl" = x ; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ true
+ else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ if test "$SDL_CONFIG" = "no" ; then
+ echo "*** The sdl-config script installed by SDL could not be found"
+ echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the SDL_CONFIG environment variable to the"
+ echo "*** full path to sdl-config."
+ else
+ if test -f conf.sdltest ; then
+ :
+ else
+ echo "*** Could not run SDL test program, checking why..."
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include "SDL.h"
+
+int main(int argc, char *argv[])
+{ return 0; }
+#undef main
+#define main K_and_R_C_main
+
+int
+main ()
+{
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding SDL or finding the wrong"
+ echo "*** version of SDL. If it is not finding SDL, 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"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means SDL was incorrectly installed"
+ echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+ echo "*** may want to edit the sdl-config script: $SDL_CONFIG"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ SDL_CFLAGS=""
+ SDL_LIBS=""
+ { { echo "$as_me:$LINENO: error: \"Sound requires SDL > 1.2.10 SDL_sound and SDL_mixer use --disable-sound to skip the dependency and the feature\"" >&5
+echo "$as_me: error: \"Sound requires SDL > 1.2.10 SDL_sound and SDL_mixer use --disable-sound to skip the dependency and the feature\"" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+
+ rm -f conf.sdltest
+
+else
+ CXXFLAGS="$CXXFLAGS -DDISABLE_SOUND "
+fi
+
+if test x$debug = xyes ; then
+ CXXFLAGS="$CXXFLAGS -DDEBUG -g"
+else
+ CXXFLAGS="$CXXFLAGS -DNDEBUG "
+fi
+
+#on windows append identifier to version string
+if test "$win_build" = 1 ; then
+ cat >>confdefs.h <<\_ACEOF
+#define VERSION "0.29 on Windows"
+_ACEOF
+
+fi
+
+ if test "$win_build" = 1; then
+ USE_WINDRES_TRUE=
+ USE_WINDRES_FALSE='#'
+else
+ USE_WINDRES_TRUE='#'
+ USE_WINDRES_FALSE=
+fi
+
+ if test x$usetorrent = xyes && test "$win_build" = 1; then
+ USE_LIBT_INCLUDED_TRUE=
+ USE_LIBT_INCLUDED_FALSE='#'
+else
+ USE_LIBT_INCLUDED_TRUE='#'
+ USE_LIBT_INCLUDED_FALSE=
+fi
+
+
+{ echo "$as_me:$LINENO: checking if we can enable extra features that need wxWidgets-2.8" >&5
+echo $ECHO_N "checking if we can enable extra features that need wxWidgets-2.8... $ECHO_C" >&6; }
+
+ wx_ver_ok=""
+ if test "x$WX_VERSION" != x ; then
+ if test $wx_config_major_version -gt 2; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_major_version -eq 2; then
+ if test $wx_config_minor_version -gt 8; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_minor_version -eq 8; then
+ if test $wx_config_micro_version -ge 0; then
+ wx_ver_ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+
+if test -n "$wx_ver_ok"; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WX28 1
+_ACEOF
+
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ { echo "$as_me:$LINENO: checking whether NLS is requested" >&5
+echo $ECHO_N "checking whether NLS is requested... $ECHO_C" >&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
+
+ { echo "$as_me:$LINENO: result: $USE_NLS" >&5
+echo "${ECHO_T}$USE_NLS" >&6; }
+
+
+
+
+ GETTEXT_MACRO_VERSION=0.17
+
+
+
+
+# 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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_MSGFMT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ { echo "$as_me:$LINENO: result: $MSGFMT" >&5
+echo "${ECHO_T}$MSGFMT" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ # Extract the first word of "gmsgfmt", so it can be a program name with args.
+set dummy gmsgfmt; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_GMSGFMT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $GMSGFMT" >&5
+echo "${ECHO_T}$GMSGFMT" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_XGETTEXT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ { echo "$as_me:$LINENO: result: $XGETTEXT" >&5
+echo "${ECHO_T}$XGETTEXT" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_MSGMERGE+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ { echo "$as_me:$LINENO: result: $MSGMERGE" >&5
+echo "${ECHO_T}$MSGMERGE" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$localedir" || localedir='${datadir}/locale'
+
+
+ test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS=
+
+
+ ac_config_commands="$ac_config_commands po-directories"
+
+
+
+ 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"
+
+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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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"
+ echo "$as_me:$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
+ { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler --version >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -v >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -V >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ 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
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ CFLAGS=""
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+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
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$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
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* 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"
+ 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_c89=$ac_arg
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+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)
+ { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+ xno)
+ { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+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
+
+depcc="$CC" am_compiler_list=
+
+{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ 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
+
+ case $depmode in
+ 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
+ ;;
+ none) break ;;
+ esac
+ # 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.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} 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 sub/conftest.${OBJEXT-o} 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
+{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$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
+
+
+
+# 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.
+ { echo "$as_me:$LINENO: checking for ld used by GCC" >&5
+echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&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
+ { echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; }
+else
+ { echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; }
+fi
+if test "${acl_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+ { echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; }
+if test "${acl_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ acl_cv_prog_gnu_ld=yes ;;
+*)
+ acl_cv_prog_gnu_ld=no ;;
+esac
+fi
+{ echo "$as_me:$LINENO: result: $acl_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$acl_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$acl_cv_prog_gnu_ld
+
+
+
+
+ { echo "$as_me:$LINENO: checking for shared library run path origin" >&5
+echo $ECHO_N "checking for shared library run path origin... $ECHO_C" >&6; }
+if test "${acl_cv_rpath+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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
+{ echo "$as_me:$LINENO: result: $acl_cv_rpath" >&5
+echo "${ECHO_T}$acl_cv_rpath" >&6; }
+ wl="$acl_cv_wl"
+ acl_libext="$acl_cv_libext"
+ acl_shlibext="$acl_cv_shlibext"
+ acl_libname_spec="$acl_cv_libname_spec"
+ acl_library_names_spec="$acl_cv_library_names_spec"
+ acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ acl_hardcode_direct="$acl_cv_hardcode_direct"
+ acl_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=
+ LIBICONV_PREFIX=
+ 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=
+ eval libname=\"$acl_libname_spec\" # typically: libname=lib$name
+ if test -n "$acl_shlibext"; then
+ shrext=".$acl_shlibext" # typically: shrext=.so
+ else
+ shrext=
+ fi
+ if test $use_additional = yes; then
+ dir="$additional_libdir"
+ if test -n "$acl_shlibext"; then
+ if test -f "$dir/$libname$shrext"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext"
+ else
+ if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+ ver=`(cd "$dir" && \
+ for f in "$libname$shrext".*; do echo "$f"; done \
+ | sed -e "s,^$libname$shrext\\\\.,," \
+ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+ | sed 1q ) 2>/dev/null`
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext.$ver"
+ fi
+ else
+ eval library_names=\"$acl_library_names_spec\"
+ for f in $library_names; do
+ if test -f "$dir/$f"; then
+ found_dir="$dir"
+ found_so="$dir/$f"
+ break
+ fi
+ done
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ if test -f "$dir/$libname.$acl_libext"; then
+ found_dir="$dir"
+ found_a="$dir/$libname.$acl_libext"
+ fi
+ fi
+ if test "X$found_dir" != "X"; then
+ if test -f "$dir/$libname.la"; then
+ found_la="$dir/$libname.la"
+ 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 "$acl_shlibext"; then
+ if test -f "$dir/$libname$shrext"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext"
+ else
+ if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+ ver=`(cd "$dir" && \
+ for f in "$libname$shrext".*; do echo "$f"; done \
+ | sed -e "s,^$libname$shrext\\\\.,," \
+ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+ | sed 1q ) 2>/dev/null`
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext.$ver"
+ fi
+ else
+ eval library_names=\"$acl_library_names_spec\"
+ for f in $library_names; do
+ if test -f "$dir/$f"; then
+ found_dir="$dir"
+ found_so="$dir/$f"
+ break
+ fi
+ done
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ if test -f "$dir/$libname.$acl_libext"; then
+ found_dir="$dir"
+ found_a="$dir/$libname.$acl_libext"
+ fi
+ fi
+ if test "X$found_dir" != "X"; then
+ if test -f "$dir/$libname.la"; then
+ found_la="$dir/$libname.la"
+ 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 "$acl_hardcode_direct" = yes; then
+ LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so"
+ else
+ if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_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 "$acl_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/"'*$,,'`
+ LIBICONV_PREFIX="$basedir"
+ 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 "$acl_hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$acl_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=\"$acl_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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { echo "$as_me:$LINENO: checking for CFPreferencesCopyAppValue" >&5
+echo $ECHO_N "checking for CFPreferencesCopyAppValue... $ECHO_C" >&6; }
+if test "${gt_cv_func_CFPreferencesCopyAppValue+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <CoreFoundation/CFPreferences.h>
+int
+main ()
+{
+CFPreferencesCopyAppValue(NULL, NULL)
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ gt_cv_func_CFPreferencesCopyAppValue=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ gt_cv_func_CFPreferencesCopyAppValue=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$gt_save_LIBS"
+fi
+{ echo "$as_me:$LINENO: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5
+echo "${ECHO_T}$gt_cv_func_CFPreferencesCopyAppValue" >&6; }
+ if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CFPREFERENCESCOPYAPPVALUE 1
+_ACEOF
+
+ fi
+ { echo "$as_me:$LINENO: checking for CFLocaleCopyCurrent" >&5
+echo $ECHO_N "checking for CFLocaleCopyCurrent... $ECHO_C" >&6; }
+if test "${gt_cv_func_CFLocaleCopyCurrent+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <CoreFoundation/CFLocale.h>
+int
+main ()
+{
+CFLocaleCopyCurrent();
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ gt_cv_func_CFLocaleCopyCurrent=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ gt_cv_func_CFLocaleCopyCurrent=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$gt_save_LIBS"
+fi
+{ echo "$as_me:$LINENO: result: $gt_cv_func_CFLocaleCopyCurrent" >&5
+echo "${ECHO_T}$gt_cv_func_CFLocaleCopyCurrent" >&6; }
+ if test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CFLOCALECOPYCURRENT 1
+_ACEOF
+
+ 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
+
+ { echo "$as_me:$LINENO: checking for GNU gettext in libc" >&5
+echo $ECHO_N "checking for GNU gettext in libc... $ECHO_C" >&6; }
+if { as_var=$gt_func_gnugettext_libc; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <libintl.h>
+$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
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$gt_func_gnugettext_libc=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$gt_func_gnugettext_libc=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$gt_func_gnugettext_libc'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$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
+
+
+ { echo "$as_me:$LINENO: checking for iconv" >&5
+echo $ECHO_N "checking for iconv... $ECHO_C" >&6; }
+if test "${am_cv_func_iconv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ am_cv_func_iconv="no, consider installing GNU libiconv"
+ am_cv_lib_iconv=no
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <iconv.h>
+int
+main ()
+{
+iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ am_cv_func_iconv=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ if test "$am_cv_func_iconv" != yes; then
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBICONV"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <iconv.h>
+int
+main ()
+{
+iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);
+ ;
+ return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ am_cv_lib_iconv=yes
+ am_cv_func_iconv=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$am_save_LIBS"
+ fi
+
+fi
+{ echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5
+echo "${ECHO_T}$am_cv_func_iconv" >&6; }
+ if test "$am_cv_func_iconv" = yes; then
+ { echo "$as_me:$LINENO: checking for working iconv" >&5
+echo $ECHO_N "checking for working iconv... $ECHO_C" >&6; }
+if test "${am_cv_func_iconv_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ am_save_LIBS="$LIBS"
+ if test $am_cv_lib_iconv = yes; then
+ LIBS="$LIBS $LIBICONV"
+ fi
+ if test "$cross_compiling" = yes; then
+ case "$host_os" in
+ aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
+ *) am_cv_func_iconv_works="guessing yes" ;;
+ esac
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <iconv.h>
+#include <string.h>
+int main ()
+{
+ /* Test against AIX 5.1 bug: Failures are not distinguishable from successful
+ returns. */
+ {
+ iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
+ if (cd_utf8_to_88591 != (iconv_t)(-1))
+ {
+ static const char input[] = "\342\202\254"; /* EURO SIGN */
+ char buf[10];
+ const char *inptr = input;
+ size_t inbytesleft = strlen (input);
+ char *outptr = buf;
+ size_t outbytesleft = sizeof (buf);
+ size_t res = iconv (cd_utf8_to_88591,
+ (char **) &inptr, &inbytesleft,
+ &outptr, &outbytesleft);
+ if (res == 0)
+ return 1;
+ }
+ }
+#if 0 /* This bug could be worked around by the caller. */
+ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */
+ {
+ iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591");
+ if (cd_88591_to_utf8 != (iconv_t)(-1))
+ {
+ static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
+ char buf[50];
+ const char *inptr = input;
+ size_t inbytesleft = strlen (input);
+ char *outptr = buf;
+ size_t outbytesleft = sizeof (buf);
+ size_t res = iconv (cd_88591_to_utf8,
+ (char **) &inptr, &inbytesleft,
+ &outptr, &outbytesleft);
+ if ((int)res > 0)
+ return 1;
+ }
+ }
+#endif
+ /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
+ provided. */
+ if (/* Try standardized names. */
+ iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
+ /* Try IRIX, OSF/1 names. */
+ && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
+ /* Try AIX names. */
+ && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
+ /* Try HP-UX names. */
+ && iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
+ return 1;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ am_cv_func_iconv_works=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+am_cv_func_iconv_works=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+ LIBS="$am_save_LIBS"
+
+fi
+{ echo "$as_me:$LINENO: result: $am_cv_func_iconv_works" >&5
+echo "${ECHO_T}$am_cv_func_iconv_works" >&6; }
+ case "$am_cv_func_iconv_works" in
+ *no) am_func_iconv=no am_cv_lib_iconv=no ;;
+ *) am_func_iconv=yes ;;
+ esac
+ else
+ am_func_iconv=no am_cv_lib_iconv=no
+ fi
+ if test "$am_func_iconv" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ICONV 1
+_ACEOF
+
+ fi
+ if test "$am_cv_lib_iconv" = yes; then
+ { echo "$as_me:$LINENO: checking how to link with libiconv" >&5
+echo $ECHO_N "checking how to link with libiconv... $ECHO_C" >&6; }
+ { echo "$as_me:$LINENO: result: $LIBICONV" >&5
+echo "${ECHO_T}$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=
+ LIBINTL_PREFIX=
+ 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=
+ eval libname=\"$acl_libname_spec\" # typically: libname=lib$name
+ if test -n "$acl_shlibext"; then
+ shrext=".$acl_shlibext" # typically: shrext=.so
+ else
+ shrext=
+ fi
+ if test $use_additional = yes; then
+ dir="$additional_libdir"
+ if test -n "$acl_shlibext"; then
+ if test -f "$dir/$libname$shrext"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext"
+ else
+ if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+ ver=`(cd "$dir" && \
+ for f in "$libname$shrext".*; do echo "$f"; done \
+ | sed -e "s,^$libname$shrext\\\\.,," \
+ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+ | sed 1q ) 2>/dev/null`
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext.$ver"
+ fi
+ else
+ eval library_names=\"$acl_library_names_spec\"
+ for f in $library_names; do
+ if test -f "$dir/$f"; then
+ found_dir="$dir"
+ found_so="$dir/$f"
+ break
+ fi
+ done
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ if test -f "$dir/$libname.$acl_libext"; then
+ found_dir="$dir"
+ found_a="$dir/$libname.$acl_libext"
+ fi
+ fi
+ if test "X$found_dir" != "X"; then
+ if test -f "$dir/$libname.la"; then
+ found_la="$dir/$libname.la"
+ 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 "$acl_shlibext"; then
+ if test -f "$dir/$libname$shrext"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext"
+ else
+ if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+ ver=`(cd "$dir" && \
+ for f in "$libname$shrext".*; do echo "$f"; done \
+ | sed -e "s,^$libname$shrext\\\\.,," \
+ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+ | sed 1q ) 2>/dev/null`
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext.$ver"
+ fi
+ else
+ eval library_names=\"$acl_library_names_spec\"
+ for f in $library_names; do
+ if test -f "$dir/$f"; then
+ found_dir="$dir"
+ found_so="$dir/$f"
+ break
+ fi
+ done
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ if test -f "$dir/$libname.$acl_libext"; then
+ found_dir="$dir"
+ found_a="$dir/$libname.$acl_libext"
+ fi
+ fi
+ if test "X$found_dir" != "X"; then
+ if test -f "$dir/$libname.la"; then
+ found_la="$dir/$libname.la"
+ 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 "$acl_hardcode_direct" = yes; then
+ LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so"
+ else
+ if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_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 "$acl_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/"'*$,,'`
+ LIBINTL_PREFIX="$basedir"
+ 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 "$acl_hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$acl_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=\"$acl_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
+
+ { echo "$as_me:$LINENO: checking for GNU gettext in libintl" >&5
+echo $ECHO_N "checking for GNU gettext in libintl... $ECHO_C" >&6; }
+if { as_var=$gt_func_gnugettext_libintl; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ gt_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $INCINTL"
+ gt_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBINTL"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <libintl.h>
+$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
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$gt_func_gnugettext_libintl=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$gt_func_gnugettext_libintl=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ 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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <libintl.h>
+$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
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ LIBINTL="$LIBINTL $LIBICONV"
+ LTLIBINTL="$LTLIBINTL $LTLIBICONV"
+ eval "$gt_func_gnugettext_libintl=yes"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+ CPPFLAGS="$gt_save_CPPFLAGS"
+ LIBS="$gt_save_LIBS"
+fi
+ac_res=`eval echo '${'$gt_func_gnugettext_libintl'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$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
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_NLS 1
+_ACEOF
+
+ else
+ USE_NLS=no
+ fi
+ fi
+
+ { echo "$as_me:$LINENO: checking whether to use NLS" >&5
+echo $ECHO_N "checking whether to use NLS... $ECHO_C" >&6; }
+ { echo "$as_me:$LINENO: result: $USE_NLS" >&5
+echo "${ECHO_T}$USE_NLS" >&6; }
+ if test "$USE_NLS" = "yes"; then
+ { echo "$as_me:$LINENO: checking where the gettext function comes from" >&5
+echo $ECHO_N "checking where the gettext function comes from... $ECHO_C" >&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
+ { echo "$as_me:$LINENO: result: $gt_source" >&5
+echo "${ECHO_T}$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
+ { echo "$as_me:$LINENO: checking how to link with libintl" >&5
+echo $ECHO_N "checking how to link with libintl... $ECHO_C" >&6; }
+ { echo "$as_me:$LINENO: result: $LIBINTL" >&5
+echo "${ECHO_T}$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
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETTEXT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DCGETTEXT 1
+_ACEOF
+
+ fi
+
+ POSUB=po
+ fi
+
+
+
+ INTLLIBS="$LIBINTL"
+
+
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files Makefile po/Makefile.in"
+
+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_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ *) $as_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" &&
+ { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+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=
+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=`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.
+ ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${USE_WINDRES_TRUE}" && test -z "${USE_WINDRES_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"USE_WINDRES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"USE_WINDRES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${USE_LIBT_INCLUDED_TRUE}" && test -z "${USE_LIBT_INCLUDED_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"USE_LIBT_INCLUDED\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"USE_LIBT_INCLUDED\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $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}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## 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=:
+ # 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
+
+
+
+
+# PATH needs CR
+# 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
+
+# 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
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+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.)
+as_nl='
+'
+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
+ echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+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
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. 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" ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); 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
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+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
+fi
+echo >conf$$.file
+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
+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=:
+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
+
+# 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 SpringLobby $as_me 0.29, which was
+generated by GNU Autoconf 2.61. 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
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# 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_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ -q, --quiet 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 <bug-autoconf at gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+SpringLobby config.status 0.29
+configured by $0, generated by GNU Autoconf 2.61,
+ with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 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'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+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=$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 )
+ echo "$ac_cs_version"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ 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.
+ -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$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
+if \$ac_cs_recheck; then
+ echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ CONFIG_SHELL=$SHELL
+ export CONFIG_SHELL
+ exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+# 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
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;;
+
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ 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 '{ (exit 1); 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")
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+am__isrc!$am__isrc$ac_delim
+CYGPATH_W!$CYGPATH_W$ac_delim
+PACKAGE!$PACKAGE$ac_delim
+VERSION!$VERSION$ac_delim
+ACLOCAL!$ACLOCAL$ac_delim
+AUTOCONF!$AUTOCONF$ac_delim
+AUTOMAKE!$AUTOMAKE$ac_delim
+AUTOHEADER!$AUTOHEADER$ac_delim
+MAKEINFO!$MAKEINFO$ac_delim
+install_sh!$install_sh$ac_delim
+STRIP!$STRIP$ac_delim
+INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim
+mkdir_p!$mkdir_p$ac_delim
+AWK!$AWK$ac_delim
+SET_MAKE!$SET_MAKE$ac_delim
+am__leading_dot!$am__leading_dot$ac_delim
+AMTAR!$AMTAR$ac_delim
+am__tar!$am__tar$ac_delim
+am__untar!$am__untar$ac_delim
+PKG_CONFIG!$PKG_CONFIG$ac_delim
+build!$build$ac_delim
+build_cpu!$build_cpu$ac_delim
+build_vendor!$build_vendor$ac_delim
+build_os!$build_os$ac_delim
+host!$host$ac_delim
+host_cpu!$host_cpu$ac_delim
+host_vendor!$host_vendor$ac_delim
+host_os!$host_os$ac_delim
+CXX!$CXX$ac_delim
+CXXFLAGS!$CXXFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CXX!$ac_ct_CXX$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+DEPDIR!$DEPDIR$ac_delim
+am__include!$am__include$ac_delim
+am__quote!$am__quote$ac_delim
+AMDEP_TRUE!$AMDEP_TRUE$ac_delim
+AMDEP_FALSE!$AMDEP_FALSE$ac_delim
+AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim
+CXXDEPMODE!$CXXDEPMODE$ac_delim
+am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim
+am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim
+WX_CONFIG_PATH!$WX_CONFIG_PATH$ac_delim
+WX_CPPFLAGS!$WX_CPPFLAGS$ac_delim
+WX_CFLAGS!$WX_CFLAGS$ac_delim
+WX_CXXFLAGS!$WX_CXXFLAGS$ac_delim
+WX_CFLAGS_ONLY!$WX_CFLAGS_ONLY$ac_delim
+WX_CXXFLAGS_ONLY!$WX_CXXFLAGS_ONLY$ac_delim
+WX_LIBS!$WX_LIBS$ac_delim
+WX_LIBS_STATIC!$WX_LIBS_STATIC$ac_delim
+WX_VERSION!$WX_VERSION$ac_delim
+WINDRES!$WINDRES$ac_delim
+LIBTORRENT_CFLAGS!$LIBTORRENT_CFLAGS$ac_delim
+LIBTORRENT_LIBS!$LIBTORRENT_LIBS$ac_delim
+SDL_CONFIG!$SDL_CONFIG$ac_delim
+_ACEOF
+
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
+ break
+ elif $ac_last_try; then
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+ ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+ ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+CEOF$ac_eof
+_ACEOF
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ cat >conf$$subs.sed <<_ACEOF
+SDL_CFLAGS!$SDL_CFLAGS$ac_delim
+SDL_LIBS!$SDL_LIBS$ac_delim
+USE_WINDRES_TRUE!$USE_WINDRES_TRUE$ac_delim
+USE_WINDRES_FALSE!$USE_WINDRES_FALSE$ac_delim
+USE_LIBT_INCLUDED_TRUE!$USE_LIBT_INCLUDED_TRUE$ac_delim
+USE_LIBT_INCLUDED_FALSE!$USE_LIBT_INCLUDED_FALSE$ac_delim
+USE_NLS!$USE_NLS$ac_delim
+GETTEXT_MACRO_VERSION!$GETTEXT_MACRO_VERSION$ac_delim
+MSGFMT!$MSGFMT$ac_delim
+GMSGFMT!$GMSGFMT$ac_delim
+MSGFMT_015!$MSGFMT_015$ac_delim
+GMSGFMT_015!$GMSGFMT_015$ac_delim
+XGETTEXT!$XGETTEXT$ac_delim
+XGETTEXT_015!$XGETTEXT_015$ac_delim
+MSGMERGE!$MSGMERGE$ac_delim
+XGETTEXT_EXTRA_OPTIONS!$XGETTEXT_EXTRA_OPTIONS$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+CCDEPMODE!$CCDEPMODE$ac_delim
+am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim
+am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim
+INTL_MACOSX_LIBS!$INTL_MACOSX_LIBS$ac_delim
+LIBICONV!$LIBICONV$ac_delim
+LTLIBICONV!$LTLIBICONV$ac_delim
+INTLLIBS!$INTLLIBS$ac_delim
+LIBINTL!$LIBINTL$ac_delim
+LTLIBINTL!$LTLIBINTL$ac_delim
+POSUB!$POSUB$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 31; then
+ break
+ elif $ac_last_try; then
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+ ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+ ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ 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[ ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[ ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+ { (exit 1); exit 1; }; };;
+ :[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 ||
+ { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+ ac_file_inputs="$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 "`IFS=:
+ echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ fi
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin";;
+ 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 ||
+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"
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`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 ||
+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" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+ { (exit 1); exit 1; }; }; }
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`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
+# 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=
+
+case `sed -n '/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ 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
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;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
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out
+
+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"; } &&
+ { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&5
+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
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status. If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless. But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*'
+ac_dB='\\)[ (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+ sed -n '
+ t rset
+ :rset
+ s/^[ ]*#[ ]*define[ ][ ]*//
+ t ok
+ d
+ :ok
+ s/[\\&,]/\\&/g
+ s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+ s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+ ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then 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.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[ #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+ # Write a here document:
+ cat >>$CONFIG_STATUS <<_ACEOF
+ # First, check the format of the line:
+ cat >"\$tmp/defines.sed" <<\\CEOF
+/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def
+/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def
+b
+:def
+_ACEOF
+ sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+ ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+ sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+ grep . conftest.tail >/dev/null || break
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+ if test x"$ac_file" != x-; then
+ echo "/* $configure_input */" >"$tmp/config.h"
+ cat "$ac_result" >>"$tmp/config.h"
+ if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f $ac_file
+ mv "$tmp/config.h" $ac_file
+ fi
+ else
+ echo "/* $configure_input */"
+ cat "$ac_result"
+ fi
+ rm -f "$tmp/out12"
+# 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 ||
+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) { echo "$as_me:$LINENO: executing $ac_file commands" >&5
+echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; 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 ||
+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 ||
+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
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`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 ||
+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" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+ { (exit 1); exit 1; }; }; }
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+ "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
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# 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 || { (exit 1); exit 1; }
+fi
+
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..dd4022a
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,170 @@
+dnl it is possible to make these work with older versions of autoconf+automake
+dnl but the developers will NOT support you if it fails
+dnl you really should just upgrade your autotools instead
+
+dnl if you have too old autoconf, comment out the following prereq AND edit Makefile.am
+
+AC_INIT([SpringLobby],[0.29],[devel at www.springlobby.info])
+
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_SRCDIR([src/springlobbyapp.cpp])
+AC_CONFIG_AUX_DIR([autotools-aux])
+dnl if you have too old automake, delete the version number from below AND edit Makefile.am
+dnl we use filter-out GNU make extension in Makefile.am so we can't use -Werror below
+dnl we can't use -Wall either because we don't want to see the filter-out warning
+dnl FIXME add at least some warning categories. obviously we can't use -Wportability
+AM_INIT_AUTOMAKE([1.10 -Wnone])
+
+PKG_PROG_PKG_CONFIG
+
+usetorrent=yes
+AC_ARG_ENABLE(torrent-system,
+ [ --disable-torrent-system Disable automatic content downloads via torrent (avoids libtorrent dependency)],
+ [ usetorrent=$enableval
+ ])
+
+sound=yes
+AC_ARG_ENABLE(sound,
+ [ --disable-sound Enable sound using SDL, needs SDL],
+ [ sound=$enableval
+ ])
+
+debug=no
+AC_ARG_ENABLE(debug,
+ [ --enable-debug Enable debugging],
+ [ debug=$enableval
+ ])
+
+AC_ARG_WITH(sdl-config,[ --with-sdl-config=/path/to/sdl-config (optional) for finding right sdl includes],
+ SDL_CONFIG="$withval")
+
+AC_ARG_WITH(boost-prefix,[ --with-boost-prefix=/path/to/boost_topdir (optional) for finding right boost includes],
+ CXXFLAGS="$CXXFLAGS -I$withval ")
+
+AC_ARG_WITH(opt-level,[ --with-opt-level=N (optional) with N = 0..3],
+ CXXFLAGS="$CXXFLAGS -O$withval ")
+
+AC_ARG_WITH(aux-version,[ --with-aux-version='some string' (packager use only)],
+ AC_DEFINE_UNQUOTED([AUX_VERSION], " $withval", [] ) )
+
+
+AC_CANONICAL_HOST
+
+AC_LANG([C++])
+
+AC_PROG_CXX
+
+AM_OPTIONS_WXCONFIG
+
+
+AM_PATH_WXCONFIG([2.8.2], [],
+ [AC_MSG_ERROR([
+ wxWidgets must be installed on your system
+ but wx-config script couldn't be found.
+
+ Please check that wx-config is in path, the directory
+ where wxWidgets libraries are installed (returned by
+ 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+ equivalent variable and wxWidgets version is 2.8.2 or above.
+ ])], [base,core,net,adv,aui,xml,html])
+win_build=0
+AC_ARG_VAR([WINDRES], [Windows resource file compiler command])
+if test x$host_os = xmingw32msvc ; then
+ AC_CHECK_TOOL([WINDRES], [windres], [:])
+ win_build=1
+ LIBS="$LIBS -liphlpapi"
+ if test x$WINDRES = x: ; then
+ AC_MSG_ERROR([missing required windres windows resource compiler.])
+ fi
+fi
+
+
+
+dnl On non-Windows build use external libtorrent, on win use included source
+if test "$win_build" = 0 ; then
+ if test x$usetorrent = xyes ; then
+ AC_MSG_CHECKING([for libtorrent from Rasterbar software])
+
+ # Check for libtorrent using the following names: libtorrent-rasterbar, rb-libtorrent,
+ # libtorrent.
+ PKG_CHECK_EXISTS([libtorrent-rasterbar >= 0.13],[usetorrent=libtorrent-rasterbar],[usetorrent=fail])
+ if test x$usetorrent = xfail ; then
+ PKG_CHECK_EXISTS([rb-libtorrent >= 0.13],[usetorrent=rb-libtorrent],[usetorrent=fail])
+ if test x$usetorrent = xfail ; then
+ PKG_CHECK_EXISTS([libtorrent >= 0.13],[usetorrent=libtorrent],[usetorrent=fail])
+ if test x$usetorrent = xfail ; then
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([
+ Missing required libtorrent library. You can get it from
+ <http://www.rasterbar.com/products/libtorrent/>.
+
+ Please note that some distributions name it rb-libtorrent or
+ libtorrent-rasterbar. This is NOT libtorrent from rakshasa!
+
+ You can skip this dependency by using --disable-torrent-system]);
+
+ exit
+ fi
+ fi
+ fi
+
+ AC_MSG_RESULT(yes)
+
+ # Need to manually define these, since only used PKG_CHECK_EXISTS and not
+ # PKG_CHECK_MODULES above.
+ LIBTORRENT_CFLAGS=`pkg-config $usetorrent --cflags`
+ LIBTORRENT_LIBS=`pkg-config $usetorrent --libs`
+
+ AC_SUBST(LIBTORRENT_CFLAGS)
+ AC_SUBST(LIBTORRENT_LIBS)
+ else
+ CXXFLAGS="$CXXFLAGS -DNO_TORRENT_SYSTEM"
+ fi
+else
+ if test x$usetorrent = xyes ; then
+ CXXFLAGS="$CXXFLAGS -D_WIN32_WINNT=0x0500 -DBOOST_WINDOWS -DTORRENT_DISABLE_ENCRYPTION "
+ LIBS="$LIBS -mthreads -Wl,-allow-multiple-definition -L/var/lib/buildbot/lib/mingw/lib -lboost_thread-mt -lboost_filesystem-mt -lws2_32 -lmswsock -lboost_date_time-mt"
+ else
+ CXXFLAGS="$CXXFLAGS -DNO_TORRENT_SYSTEM"
+ fi
+fi
+
+dnl check if sound configure is enables, if yes check for SDL
+if test x$sound = xyes ; then
+ AM_PATH_SDL(1.2.10, true , AC_ERROR("Sound requires SDL > 1.2.10 SDL_sound and SDL_mixer use --disable-sound to skip the dependency and the feature") )
+else
+ CXXFLAGS="$CXXFLAGS -DDISABLE_SOUND "
+fi
+
+if test x$debug = xyes ; then
+ CXXFLAGS="$CXXFLAGS -DDEBUG -g"
+else
+ CXXFLAGS="$CXXFLAGS -DNDEBUG "
+fi
+
+#on windows append identifier to version string
+if test "$win_build" = 1 ; then
+ AC_DEFINE([VERSION],["0.29 on Windows"] )
+fi
+
+AM_CONDITIONAL([USE_WINDRES], test "$win_build" = 1)
+AM_CONDITIONAL([USE_LIBT_INCLUDED], test x$usetorrent = xyes && test "$win_build" = 1)
+
+AC_MSG_CHECKING([if we can enable extra features that need wxWidgets-2.8])
+dnl we probably aren't supposed to use the function below, but it is the simplest way
+_WX_PRIVATE_CHECK_VERSION([2], [8], [0])
+if test -n "$wx_ver_ok"; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_WX28], [1], [Define to 1 if wxWidgets is at least version 2.8.0])
+else
+ AC_MSG_RESULT([no])
+fi
+
+AM_GNU_GETTEXT([external])
+AM_GNU_GETTEXT_VERSION([0.17])
+
+
+
+AC_CONFIG_FILES([Makefile po/Makefile.in])
+AC_OUTPUT
+
diff --git a/m4/gettext.m4 b/m4/gettext.m4
new file mode 100644
index 0000000..c9ae1f7
--- /dev/null
+++ b/m4/gettext.m4
@@ -0,0 +1,381 @@
+# gettext.m4 serial 60 (gettext-0.17)
+dnl Copyright (C) 1995-2007 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 <drepper at cygnus.com>, 1995-2000.
+dnl Bruno Haible <haible at clisp.cons.org>, 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 <inttypes.h> 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 <libintl.h>
+$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 <libintl.h>
+$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 <libintl.h>
+$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 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], [])
diff --git a/m4/iconv.m4 b/m4/iconv.m4
new file mode 100644
index 0000000..66bc76f
--- /dev/null
+++ b/m4/iconv.m4
@@ -0,0 +1,180 @@
+# iconv.m4 serial AM6 (gettext-0.17)
+dnl Copyright (C) 2000-2002, 2007 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).
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+ 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 <stdlib.h>
+#include <iconv.h>],
+ [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 <stdlib.h>
+#include <iconv.h>],
+ [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_CACHE_CHECK([for working iconv], am_cv_func_iconv_works, [
+ dnl This tests against bugs in AIX 5.1 and HP-UX 11.11.
+ am_save_LIBS="$LIBS"
+ if test $am_cv_lib_iconv = yes; then
+ LIBS="$LIBS $LIBICONV"
+ fi
+ AC_TRY_RUN([
+#include <iconv.h>
+#include <string.h>
+int main ()
+{
+ /* Test against AIX 5.1 bug: Failures are not distinguishable from successful
+ returns. */
+ {
+ iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
+ if (cd_utf8_to_88591 != (iconv_t)(-1))
+ {
+ static const char input[] = "\342\202\254"; /* EURO SIGN */
+ char buf[10];
+ const char *inptr = input;
+ size_t inbytesleft = strlen (input);
+ char *outptr = buf;
+ size_t outbytesleft = sizeof (buf);
+ size_t res = iconv (cd_utf8_to_88591,
+ (char **) &inptr, &inbytesleft,
+ &outptr, &outbytesleft);
+ if (res == 0)
+ return 1;
+ }
+ }
+#if 0 /* This bug could be worked around by the caller. */
+ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */
+ {
+ iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591");
+ if (cd_88591_to_utf8 != (iconv_t)(-1))
+ {
+ static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
+ char buf[50];
+ const char *inptr = input;
+ size_t inbytesleft = strlen (input);
+ char *outptr = buf;
+ size_t outbytesleft = sizeof (buf);
+ size_t res = iconv (cd_88591_to_utf8,
+ (char **) &inptr, &inbytesleft,
+ &outptr, &outbytesleft);
+ if ((int)res > 0)
+ return 1;
+ }
+ }
+#endif
+ /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
+ provided. */
+ if (/* Try standardized names. */
+ iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
+ /* Try IRIX, OSF/1 names. */
+ && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
+ /* Try AIX names. */
+ && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
+ /* Try HP-UX names. */
+ && iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
+ return 1;
+ return 0;
+}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no],
+ [case "$host_os" in
+ aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
+ *) am_cv_func_iconv_works="guessing yes" ;;
+ esac])
+ LIBS="$am_save_LIBS"
+ ])
+ case "$am_cv_func_iconv_works" in
+ *no) am_func_iconv=no am_cv_lib_iconv=no ;;
+ *) am_func_iconv=yes ;;
+ esac
+ else
+ am_func_iconv=no am_cv_lib_iconv=no
+ fi
+ if test "$am_func_iconv" = yes; then
+ AC_DEFINE(HAVE_ICONV, 1,
+ [Define if you have the iconv() function and it works.])
+ 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 <stdlib.h>
+#include <iconv.h>
+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
+])
diff --git a/m4/intlmacosx.m4 b/m4/intlmacosx.m4
new file mode 100644
index 0000000..d3f0d90
--- /dev/null
+++ b/m4/intlmacosx.m4
@@ -0,0 +1,51 @@
+# intlmacosx.m4 serial 1 (gettext-0.17)
+dnl Copyright (C) 2004-2007 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 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 <CoreFoundation/CFPreferences.h>],
+ [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 <CoreFoundation/CFLocale.h>], [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])
+])
diff --git a/m4/lib-ld.m4 b/m4/lib-ld.m4
new file mode 100644
index 0000000..96c4e2c
--- /dev/null
+++ b/m4/lib-ld.m4
@@ -0,0 +1,110 @@
+# 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 </dev/null` in
+*GNU* | *'with BFD'*)
+ acl_cv_prog_gnu_ld=yes ;;
+*)
+ acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# 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.
+ 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
+])
diff --git a/m4/lib-link.m4 b/m4/lib-link.m4
new file mode 100644
index 0000000..e3d26fc
--- /dev/null
+++ b/m4/lib-link.m4
@@ -0,0 +1,709 @@
+# lib-link.m4 serial 13 (gettext-0.17)
+dnl Copyright (C) 2001-2007 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.54)
+
+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.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+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"
+ ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX"
+ ])
+ LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+ LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+ INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+ LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ AC_SUBST([LIB]NAME[_PREFIX])
+ 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.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+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=
+ LIB[]NAME[]_PREFIX=
+ fi
+ AC_SUBST([HAVE_LIB]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ AC_SUBST([LIB]NAME[_PREFIX])
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl acl_libext,
+dnl acl_shlibext,
+dnl acl_hardcode_libdir_flag_spec,
+dnl acl_hardcode_libdir_separator,
+dnl acl_hardcode_direct,
+dnl acl_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"
+ acl_libext="$acl_cv_libext"
+ acl_shlibext="$acl_cv_shlibext"
+ acl_libname_spec="$acl_cv_libname_spec"
+ acl_library_names_spec="$acl_cv_library_names_spec"
+ acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ acl_hardcode_direct="$acl_cv_hardcode_direct"
+ acl_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.
+dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found
+dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ dnl Autoconf >= 2.61 supports dots in --with options.
+ define([N_A_M_E],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit([$1],[.],[_])],[$1])])
+ 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]N_A_M_E[-prefix],
+[ --with-lib]N_A_M_E[-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib
+ --without-lib]N_A_M_E[-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=
+ LIB[]NAME[]_PREFIX=
+ 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=
+ eval libname=\"$acl_libname_spec\" # typically: libname=lib$name
+ if test -n "$acl_shlibext"; then
+ shrext=".$acl_shlibext" # typically: shrext=.so
+ else
+ shrext=
+ fi
+ if test $use_additional = yes; then
+ dir="$additional_libdir"
+ dnl The same code as in the loop below:
+ dnl First look for a shared library.
+ if test -n "$acl_shlibext"; then
+ if test -f "$dir/$libname$shrext"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext"
+ else
+ if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+ ver=`(cd "$dir" && \
+ for f in "$libname$shrext".*; do echo "$f"; done \
+ | sed -e "s,^$libname$shrext\\\\.,," \
+ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+ | sed 1q ) 2>/dev/null`
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext.$ver"
+ fi
+ else
+ eval library_names=\"$acl_library_names_spec\"
+ for f in $library_names; do
+ if test -f "$dir/$f"; then
+ found_dir="$dir"
+ found_so="$dir/$f"
+ break
+ fi
+ done
+ fi
+ fi
+ fi
+ dnl Then look for a static library.
+ if test "X$found_dir" = "X"; then
+ if test -f "$dir/$libname.$acl_libext"; then
+ found_dir="$dir"
+ found_a="$dir/$libname.$acl_libext"
+ fi
+ fi
+ if test "X$found_dir" != "X"; then
+ if test -f "$dir/$libname.la"; then
+ found_la="$dir/$libname.la"
+ 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//'`
+ dnl First look for a shared library.
+ if test -n "$acl_shlibext"; then
+ if test -f "$dir/$libname$shrext"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext"
+ else
+ if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+ ver=`(cd "$dir" && \
+ for f in "$libname$shrext".*; do echo "$f"; done \
+ | sed -e "s,^$libname$shrext\\\\.,," \
+ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+ | sed 1q ) 2>/dev/null`
+ if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+ found_dir="$dir"
+ found_so="$dir/$libname$shrext.$ver"
+ fi
+ else
+ eval library_names=\"$acl_library_names_spec\"
+ for f in $library_names; do
+ if test -f "$dir/$f"; then
+ found_dir="$dir"
+ found_so="$dir/$f"
+ break
+ fi
+ done
+ fi
+ fi
+ fi
+ dnl Then look for a static library.
+ if test "X$found_dir" = "X"; then
+ if test -f "$dir/$libname.$acl_libext"; then
+ found_dir="$dir"
+ found_a="$dir/$libname.$acl_libext"
+ fi
+ fi
+ if test "X$found_dir" != "X"; then
+ if test -f "$dir/$libname.la"; then
+ found_la="$dir/$libname.la"
+ 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 "$acl_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 "$acl_hardcode_libdir_flag_spec" && test "$acl_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 "$acl_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 $acl_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/"'*$,,'`
+ LIB[]NAME[]_PREFIX="$basedir"
+ 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 "$acl_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:+$acl_hardcode_libdir_separator}$found_dir"
+ done
+ dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl.
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$acl_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=\"$acl_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 "$acl_hardcode_libdir_flag_spec" && test "$acl_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 "$acl_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:+$acl_hardcode_libdir_separator}$dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$acl_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=\"$acl_hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ $1="${$1}${$1:+ }$flag"
+ done
+ fi
+ fi
+ fi
+ fi
+ fi
+ AC_SUBST([$1])
+])
diff --git a/m4/lib-prefix.m4 b/m4/lib-prefix.m4
new file mode 100644
index 0000000..a8684e1
--- /dev/null
+++ b/m4/lib-prefix.m4
@@ -0,0 +1,185 @@
+# 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
+])
diff --git a/m4/nls.m4 b/m4/nls.m4
new file mode 100644
index 0000000..7967cc2
--- /dev/null
+++ b/m4/nls.m4
@@ -0,0 +1,31 @@
+# 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 <drepper at cygnus.com>, 1995-2000.
+dnl Bruno Haible <haible at clisp.cons.org>, 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)
+])
diff --git a/m4/pkg.m4 b/m4/pkg.m4
new file mode 100644
index 0000000..0048a3f
--- /dev/null
+++ b/m4/pkg.m4
@@ -0,0 +1,157 @@
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott at netsplit.com>.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$PKG_CONFIG"; then
+ if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ else
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+ [pkg_failed=yes])
+ fi
+else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+ [AC_MSG_RESULT([no])
+ $4])
+elif test $pkg_failed = untried; then
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
+ [$4])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
diff --git a/m4/po.m4 b/m4/po.m4
new file mode 100644
index 0000000..0734762
--- /dev/null
+++ b/m4/po.m4
@@ -0,0 +1,449 @@
+# po.m4 serial 15 (gettext-0.17)
+dnl Copyright (C) 1995-2007 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 <drepper at cygnus.com>, 1995-2000.
+dnl Bruno Haible <haible at clisp.cons.org>, 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 Release version of the gettext macros. This is used to ensure that
+ dnl the gettext macros and po/Makefile.in.in are in sync.
+ AC_SUBST([GETTEXT_MACRO_VERSION], [0.17])
+
+ 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])
+
+ dnl Support for AM_XGETTEXT_OPTION.
+ test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS=
+ AC_SUBST([XGETTEXT_EXTRA_OPTIONS])
+
+ 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 <<EOT
+$*
+EOT
+ }
+ gt_echo='echo_func'
+ fi
+ fi
+
+ # A sed script that extracts the value of VARIABLE from a Makefile.
+ sed_x_variable='
+# Test if the hold space is empty.
+x
+s/P/P/
+x
+ta
+# Yes it was empty. Look if we have the expected variable definition.
+/^[ ]*VARIABLE[ ]*=/{
+ # Seen the first line of the variable definition.
+ s/^[ ]*VARIABLE[ ]*=//
+ ba
+}
+bd
+:a
+# Here we are processing a line from the variable definition.
+# Remove comment, more precisely replace it with a space.
+s/#.*$/ /
+# See if the line ends in a backslash.
+tb
+:b
+s/\\$//
+# Print the line, without the trailing backslash.
+p
+tc
+# There was no trailing backslash. The end of the variable definition is
+# reached. Clear the hold space.
+s/^.*$//
+x
+bd
+:c
+# A trailing backslash means that the variable definition continues in the
+# next line. Put a nonempty string into the hold space to indicate this.
+s/^.*$/P/
+x
+:d
+'
+changequote([,])dnl
+
+ # Set POTFILES to the value of the Makefile variable POTFILES.
+ sed_x_POTFILES=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'`
+ POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"`
+ # Compute POTFILES_DEPS as
+ # $(foreach file, $(POTFILES), $(top_srcdir)/$(file))
+ POTFILES_DEPS=
+ for file in $POTFILES; do
+ POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file"
+ done
+ POMAKEFILEDEPS=""
+
+ 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
+ if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+ # The LINGUAS file contains the set of available languages.
+ ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+ POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+ else
+ # Set ALL_LINGUAS to the value of the Makefile variable LINGUAS.
+ sed_x_LINGUAS=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'`
+ ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"`
+ fi
+ # Hide the ALL_LINGUAS assigment from automake < 1.5.
+ eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+ # 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)
+ # Compute PROPERTIESFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties)
+ # Compute CLASSFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class)
+ # Compute QMFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm)
+ # Compute MSGFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg)
+ # Compute RESOURCESDLLFILES
+ # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll)
+ case "$ac_given_srcdir" in
+ .) srcdirpre= ;;
+ *) srcdirpre='$(srcdir)/' ;;
+ esac
+ POFILES=
+ UPDATEPOFILES=
+ DUMMYPOFILES=
+ GMOFILES=
+ PROPERTIESFILES=
+ CLASSFILES=
+ QMFILES=
+ MSGFILES=
+ RESOURCESDLLFILES=
+ 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"
+ PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties"
+ CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class"
+ QMFILES="$QMFILES $srcdirpre$lang.qm"
+ frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+ MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg"
+ 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/'`
+ RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll"
+ 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=
+ JAVACATALOGS=
+ QTCATALOGS=
+ TCLCATALOGS=
+ CSHARPCATALOGS=
+ if test -n "$INST_LINGUAS"; then
+ for lang in $INST_LINGUAS; do
+ CATALOGS="$CATALOGS $lang.gmo"
+ JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties"
+ QTCATALOGS="$QTCATALOGS $lang.qm"
+ frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+ TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg"
+ 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/'`
+ CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll"
+ done
+ fi
+
+ sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$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" <<EOF
+$frobbedlang.msg: $lang.po
+ @echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \
+ \$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+ done
+ fi
+ if grep -l '@CSHARPCATALOGS@' "$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/_/-/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" <<EOF
+$frobbedlang/\$(DOMAIN).resources.dll: $lang.po
+ @echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \
+ \$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+ done
+ fi
+ if test -n "$POMAKEFILEDEPS"; then
+ cat >> "$ac_file.tmp" <<EOF
+Makefile: $POMAKEFILEDEPS
+EOF
+ fi
+ mv "$ac_file.tmp" "$ac_file"
+])
+
+dnl Initializes the accumulator used by AM_XGETTEXT_OPTION.
+AC_DEFUN([AM_XGETTEXT_OPTION_INIT],
+[
+ XGETTEXT_EXTRA_OPTIONS=
+])
+
+dnl Registers an option to be passed to xgettext in the po subdirectory.
+AC_DEFUN([AM_XGETTEXT_OPTION],
+[
+ AC_REQUIRE([AM_XGETTEXT_OPTION_INIT])
+ XGETTEXT_EXTRA_OPTIONS="$XGETTEXT_EXTRA_OPTIONS $1"
+])
diff --git a/m4/progtest.m4 b/m4/progtest.m4
new file mode 100644
index 0000000..a56365c
--- /dev/null
+++ b/m4/progtest.m4
@@ -0,0 +1,92 @@
+# 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 <drepper at cygnus.com>, 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
+])
diff --git a/m4/sdl.m4 b/m4/sdl.m4
new file mode 100644
index 0000000..211de0d
--- /dev/null
+++ b/m4/sdl.m4
@@ -0,0 +1,182 @@
+# Configure paths for SDL
+# Sam Lantinga 9/21/99
+# stolen from Manish Singh
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
+dnl
+AC_DEFUN([AM_PATH_SDL],
+[dnl
+dnl Get the cflags and libraries from the sdl-config script
+dnl
+AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)],
+ sdl_prefix="$withval", sdl_prefix="")
+AC_ARG_WITH(sdl-exec-prefix,[ --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)],
+ sdl_exec_prefix="$withval", sdl_exec_prefix="")
+AC_ARG_ENABLE(sdltest, [ --disable-sdltest Do not try to compile and run a test SDL program],
+ , enable_sdltest=yes)
+
+ if test x$sdl_exec_prefix != x ; then
+ sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
+ if test x${SDL_CONFIG+set} != xset ; then
+ SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
+ fi
+ fi
+ if test x$sdl_prefix != x ; then
+ sdl_args="$sdl_args --prefix=$sdl_prefix"
+ if test x${SDL_CONFIG+set} != xset ; then
+ SDL_CONFIG=$sdl_prefix/bin/sdl-config
+ fi
+ fi
+
+ if test "x$prefix" != xNONE; then
+ PATH="$prefix/bin:$prefix/usr/bin:$PATH"
+ fi
+ AC_PATH_PROG(SDL_CONFIG, sdl-config, no, [$PATH])
+ min_sdl_version=ifelse([$1], ,0.11.0,$1)
+ AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
+ no_sdl=""
+ if test "$SDL_CONFIG" = "no" ; then
+ no_sdl=yes
+ else
+ SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
+ SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
+ SDL_LIBS="$SDL_LIBS -lSDL_mixer"
+
+ sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ if test "x$enable_sdltest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+dnl
+dnl Now check if the installed SDL is sufficiently new. (Also sanity
+dnl checks the results of sdl-config to some extent
+dnl
+ rm -f conf.sdltest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+ char *new_str;
+
+ if (str)
+ {
+ new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+ strcpy (new_str, str);
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ /* This hangs on some systems (?)
+ system ("touch conf.sdltest");
+ */
+ { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = my_strdup("$min_sdl_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) {
+ printf("%s, bad version string\n", "$min_sdl_version");
+ exit(1);
+ }
+
+ if (($sdl_major_version > major) ||
+ (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+ (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+ printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
+ printf("*** best to upgrade to the required version.\n");
+ printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
+ printf("*** to point to the correct copy of sdl-config, and remove the file\n");
+ printf("*** config.cache before re-running configure\n");
+ return 1;
+ }
+}
+
+],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ if test "x$no_sdl" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test "$SDL_CONFIG" = "no" ; then
+ echo "*** The sdl-config script installed by SDL could not be found"
+ echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the SDL_CONFIG environment variable to the"
+ echo "*** full path to sdl-config."
+ else
+ if test -f conf.sdltest ; then
+ :
+ else
+ echo "*** Could not run SDL test program, checking why..."
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include "SDL.h"
+
+int main(int argc, char *argv[])
+{ return 0; }
+#undef main
+#define main K_and_R_C_main
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding SDL or finding the wrong"
+ echo "*** version of SDL. If it is not finding SDL, 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 SDL was incorrectly installed"
+ echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+ echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ SDL_CFLAGS=""
+ SDL_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(SDL_CFLAGS)
+ AC_SUBST(SDL_LIBS)
+ rm -f conf.sdltest
+])
diff --git a/m4/wxwin.m4 b/m4/wxwin.m4
new file mode 100644
index 0000000..24c258a
--- /dev/null
+++ b/m4/wxwin.m4
@@ -0,0 +1,345 @@
+dnl ---------------------------------------------------------------------------
+dnl Macros for wxWidgets detection. Typically used in configure.in as:
+dnl
+dnl AC_ARG_ENABLE(...)
+dnl AC_ARG_WITH(...)
+dnl ...
+dnl AM_OPTIONS_WXCONFIG
+dnl ...
+dnl ...
+dnl AM_PATH_WXCONFIG(2.6.0, wxWin=1)
+dnl if test "$wxWin" != 1; then
+dnl AC_MSG_ERROR([
+dnl wxWidgets must be installed on your system
+dnl but wx-config script couldn't be found.
+dnl
+dnl Please check that wx-config is in path, the directory
+dnl where wxWidgets libraries are installed (returned by
+dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+dnl equivalent variable and wxWidgets version is 2.3.4 or above.
+dnl ])
+dnl fi
+dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS"
+dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY"
+dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY"
+dnl
+dnl LIBS="$LIBS $WX_LIBS"
+dnl ---------------------------------------------------------------------------
+
+dnl ---------------------------------------------------------------------------
+dnl AM_OPTIONS_WXCONFIG
+dnl
+dnl adds support for --wx-prefix, --wx-exec-prefix, --with-wxdir and
+dnl --wx-config command line options
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([AM_OPTIONS_WXCONFIG],
+[
+ AC_ARG_WITH(wxdir,
+ [ --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH],
+ [ wx_config_name="$withval/wx-config"
+ wx_config_args="--inplace"])
+ AC_ARG_WITH(wx-config,
+ [ --with-wx-config=CONFIG wx-config script to use (optional)],
+ wx_config_name="$withval" )
+ AC_ARG_WITH(wx-prefix,
+ [ --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional)],
+ wx_config_prefix="$withval", wx_config_prefix="")
+ AC_ARG_WITH(wx-exec-prefix,
+ [ --with-wx-exec-prefix=PREFIX
+ Exec prefix where wxWidgets is installed (optional)],
+ wx_config_exec_prefix="$withval", wx_config_exec_prefix="")
+])
+
+dnl Helper macro for checking if wx version is at least $1.$2.$3, set's
+dnl wx_ver_ok=yes if it is:
+AC_DEFUN([_WX_PRIVATE_CHECK_VERSION],
+[
+ wx_ver_ok=""
+ if test "x$WX_VERSION" != x ; then
+ if test $wx_config_major_version -gt $1; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_major_version -eq $1; then
+ if test $wx_config_minor_version -gt $2; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_minor_version -eq $2; then
+ if test $wx_config_micro_version -ge $3; then
+ wx_ver_ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+])
+
+dnl ---------------------------------------------------------------------------
+dnl AM_PATH_WXCONFIG(VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND
+dnl [, WX-LIBS [, ADDITIONAL-WX-CONFIG-FLAGS]]]])
+dnl
+dnl Test for wxWidgets, and define WX_C*FLAGS, WX_LIBS and WX_LIBS_STATIC
+dnl (the latter is for static linking against wxWidgets). Set WX_CONFIG_NAME
+dnl environment variable to override the default name of the wx-config script
+dnl to use. Set WX_CONFIG_PATH to specify the full path to wx-config - in this
+dnl case the macro won't even waste time on tests for its existence.
+dnl
+dnl Optional WX-LIBS argument contains comma- or space-separated list of
+dnl wxWidgets libraries to link against (it may include contrib libraries). If
+dnl it is not specified then WX_LIBS and WX_LIBS_STATIC will contain flags to
+dnl link with all of the core wxWidgets libraries.
+dnl
+dnl Optional ADDITIONAL-WX-CONFIG-FLAGS argument is appended to wx-config
+dnl invocation command in present. It can be used to fine-tune lookup of
+dnl best wxWidgets build available.
+dnl
+dnl Example use:
+dnl AM_PATH_WXCONFIG([2.6.0], [wxWin=1], [wxWin=0], [html,core,net]
+dnl [--unicode --debug])
+dnl ---------------------------------------------------------------------------
+
+dnl
+dnl Get the cflags and libraries from the wx-config script
+dnl
+AC_DEFUN([AM_PATH_WXCONFIG],
+[
+ dnl do we have wx-config name: it can be wx-config or wxd-config or ...
+ if test x${WX_CONFIG_NAME+set} != xset ; then
+ WX_CONFIG_NAME=wx-config
+ fi
+
+ if test "x$wx_config_name" != x ; then
+ WX_CONFIG_NAME="$wx_config_name"
+ fi
+
+ dnl deal with optional prefixes
+ if test x$wx_config_exec_prefix != x ; then
+ wx_config_args="$wx_config_args --exec-prefix=$wx_config_exec_prefix"
+ WX_LOOKUP_PATH="$wx_config_exec_prefix/bin"
+ fi
+ if test x$wx_config_prefix != x ; then
+ wx_config_args="$wx_config_args --prefix=$wx_config_prefix"
+ WX_LOOKUP_PATH="$WX_LOOKUP_PATH:$wx_config_prefix/bin"
+ fi
+ if test "$cross_compiling" = "yes"; then
+ wx_config_args="$wx_config_args --host=$host_alias"
+ fi
+
+ dnl don't search the PATH if WX_CONFIG_NAME is absolute filename
+ if test -x "$WX_CONFIG_NAME" ; then
+ AC_MSG_CHECKING(for wx-config)
+ WX_CONFIG_PATH="$WX_CONFIG_NAME"
+ AC_MSG_RESULT($WX_CONFIG_PATH)
+ else
+ AC_PATH_PROG(WX_CONFIG_PATH, $WX_CONFIG_NAME, no, "$WX_LOOKUP_PATH:$PATH")
+ fi
+
+ if test "$WX_CONFIG_PATH" != "no" ; then
+ WX_VERSION=""
+
+ min_wx_version=ifelse([$1], ,2.2.1,$1)
+ if test -z "$5" ; then
+ AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version])
+ else
+ AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version ($5)])
+ fi
+
+ WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args $5 $4"
+
+ WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null`
+ wx_config_major_version=`echo $WX_VERSION | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ wx_config_minor_version=`echo $WX_VERSION | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ wx_config_micro_version=`echo $WX_VERSION | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+ wx_requested_major_version=`echo $min_wx_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ wx_requested_minor_version=`echo $min_wx_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ wx_requested_micro_version=`echo $min_wx_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+ _WX_PRIVATE_CHECK_VERSION([$wx_requested_major_version],
+ [$wx_requested_minor_version],
+ [$wx_requested_micro_version])
+
+ if test -n "$wx_ver_ok"; then
+
+ AC_MSG_RESULT(yes (version $WX_VERSION))
+ WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs`
+
+ dnl is this even still appropriate? --static is a real option now
+ dnl and WX_CONFIG_WITH_ARGS is likely to contain it if that is
+ dnl what the user actually wants, making this redundant at best.
+ dnl For now keep it in case anyone actually used it in the past.
+ AC_MSG_CHECKING([for wxWidgets static library])
+ WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs 2>/dev/null`
+ if test "x$WX_LIBS_STATIC" = "x"; then
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT(yes)
+ fi
+
+ dnl starting with version 2.2.6 wx-config has --cppflags argument
+ wx_has_cppflags=""
+ if test $wx_config_major_version -gt 2; then
+ wx_has_cppflags=yes
+ else
+ if test $wx_config_major_version -eq 2; then
+ if test $wx_config_minor_version -gt 2; then
+ wx_has_cppflags=yes
+ else
+ if test $wx_config_minor_version -eq 2; then
+ if test $wx_config_micro_version -ge 6; then
+ wx_has_cppflags=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+
+ if test "x$wx_has_cppflags" = x ; then
+ dnl no choice but to define all flags like CFLAGS
+ WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags`
+ WX_CPPFLAGS=$WX_CFLAGS
+ WX_CXXFLAGS=$WX_CFLAGS
+
+ WX_CFLAGS_ONLY=$WX_CFLAGS
+ WX_CXXFLAGS_ONLY=$WX_CFLAGS
+ else
+ dnl we have CPPFLAGS included in CFLAGS included in CXXFLAGS
+ WX_CPPFLAGS=`$WX_CONFIG_WITH_ARGS --cppflags`
+ WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags`
+ WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags`
+
+ WX_CFLAGS_ONLY=`echo $WX_CFLAGS | sed "s@^$WX_CPPFLAGS *@@"`
+ WX_CXXFLAGS_ONLY=`echo $WX_CXXFLAGS | sed "s@^$WX_CFLAGS *@@"`
+ fi
+
+ ifelse([$2], , :, [$2])
+
+ else
+
+ if test "x$WX_VERSION" = x; then
+ dnl no wx-config at all
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT(no (version $WX_VERSION is not new enough))
+ fi
+
+ WX_CFLAGS=""
+ WX_CPPFLAGS=""
+ WX_CXXFLAGS=""
+ WX_LIBS=""
+ WX_LIBS_STATIC=""
+ ifelse([$3], , :, [$3])
+
+ fi
+ else
+
+ WX_CFLAGS=""
+ WX_CPPFLAGS=""
+ WX_CXXFLAGS=""
+ WX_LIBS=""
+ WX_LIBS_STATIC=""
+ ifelse([$3], , :, [$3])
+
+ fi
+
+ AC_SUBST(WX_CPPFLAGS)
+ AC_SUBST(WX_CFLAGS)
+ AC_SUBST(WX_CXXFLAGS)
+ AC_SUBST(WX_CFLAGS_ONLY)
+ AC_SUBST(WX_CXXFLAGS_ONLY)
+ AC_SUBST(WX_LIBS)
+ AC_SUBST(WX_LIBS_STATIC)
+ AC_SUBST(WX_VERSION)
+])
+
+dnl ---------------------------------------------------------------------------
+dnl Get information on the wxrc program for making C++, Python and xrs
+dnl resource files.
+dnl
+dnl AC_ARG_ENABLE(...)
+dnl AC_ARG_WITH(...)
+dnl ...
+dnl AM_OPTIONS_WXCONFIG
+dnl AM_OPTIONS_WXRC
+dnl ...
+dnl AM_PATH_WXCONFIG(2.6.0, wxWin=1)
+dnl if test "$wxWin" != 1; then
+dnl AC_MSG_ERROR([
+dnl wxWidgets must be installed on your system
+dnl but wx-config script couldn't be found.
+dnl
+dnl Please check that wx-config is in path, the directory
+dnl where wxWidgets libraries are installed (returned by
+dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+dnl equivalent variable and wxWidgets version is 2.6.0 or above.
+dnl ])
+dnl fi
+dnl
+dnl AM_PATH_WXRC([HAVE_WXRC=1], [HAVE_WXRC=0])
+dnl if test "x$HAVE_WXRC" != x1; then
+dnl AC_MSG_ERROR([
+dnl The wxrc program was not installed or not found.
+dnl
+dnl Please check the wxWidgets installation.
+dnl ])
+dnl fi
+dnl
+dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS"
+dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY"
+dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY"
+dnl
+dnl LDFLAGS="$LDFLAGS $WX_LIBS"
+dnl ---------------------------------------------------------------------------
+
+
+
+dnl ---------------------------------------------------------------------------
+dnl AM_PATH_WXRC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl
+dnl Test for wxWidgets' wxrc program for creating either C++, Python or XRS
+dnl resources. The variable WXRC will be set and substituted in the configure
+dnl script and Makefiles.
+dnl
+dnl Example use:
+dnl AM_PATH_WXRC([wxrc=1], [wxrc=0])
+dnl ---------------------------------------------------------------------------
+
+dnl
+dnl wxrc program from the wx-config script
+dnl
+AC_DEFUN([AM_PATH_WXRC],
+[
+ AC_ARG_VAR([WXRC], [Path to wxWidget's wxrc resource compiler])
+
+ if test "x$WX_CONFIG_NAME" = x; then
+ AC_MSG_ERROR([The wxrc tests must run after wxWidgets test.])
+ else
+
+ AC_MSG_CHECKING([for wxrc])
+
+ if test "x$WXRC" = x ; then
+ dnl wx-config --utility is a new addition to wxWidgets:
+ _WX_PRIVATE_CHECK_VERSION(2,5,3)
+ if test -n "$wx_ver_ok"; then
+ WXRC=`$WX_CONFIG_WITH_ARGS --utility=wxrc`
+ fi
+ fi
+
+ if test "x$WXRC" = x ; then
+ AC_MSG_RESULT([not found])
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT([$WXRC])
+ ifelse([$1], , :, [$1])
+ fi
+
+ AC_SUBST(WXRC)
+ fi
+])
diff --git a/po/ChangeLog b/po/ChangeLog
new file mode 100644
index 0000000..983cc16
--- /dev/null
+++ b/po/ChangeLog
@@ -0,0 +1,19 @@
+2009-02-07 gettextize <bug-gnu-gettext at gnu.org>
+
+ * Makefile.in.in: Upgrade to gettext-0.17.
+
+2009-02-07 gettextize <bug-gnu-gettext at gnu.org>
+
+ * Makefile.in.in: Upgrade to gettext-0.17.
+
+2008-02-07 gettextize <bug-gnu-gettext at gnu.org>
+
+ * Makefile.in.in: New file, from gettext-0.16.1.
+ * boldquot.sed: New file, from gettext-0.16.1.
+ * en at boldquot.header: New file, from gettext-0.16.1.
+ * en at quot.header: New file, from gettext-0.16.1.
+ * insert-header.sin: New file, from gettext-0.16.1.
+ * quot.sed: New file, from gettext-0.16.1.
+ * remove-potcdate.sin: New file, from gettext-0.16.1.
+ * Rules-quot: New file, from gettext-0.16.1.
+
diff --git a/po/LINGUAS b/po/LINGUAS
new file mode 100644
index 0000000..3977b09
--- /dev/null
+++ b/po/LINGUAS
@@ -0,0 +1,17 @@
+ar
+cs
+de
+da
+el
+es
+fi
+fr
+it
+pl
+pt
+ro
+ru
+sv
+uk
+zh_CN
+en_US
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
new file mode 100644
index 0000000..fecf500
--- /dev/null
+++ b/po/Makefile.in.in
@@ -0,0 +1,429 @@
+# Makefile for PO directory in any package using GNU gettext.
+# Copyright (C) 1995-1997, 2000-2007 by Ulrich Drepper <drepper at gnu.ai.mit.edu>
+#
+# 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.17
+GETTEXT_MACRO_VERSION = 0.17
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+
+SHELL = /bin/sh
+ at 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: check-macro-version all- at USE_NLS@
+
+all-yes: stamp-po
+all-no:
+
+# Ensure that the gettext macros and this Makefile.in.in are in sync.
+check-macro-version:
+ @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \
+ || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \
+ exit 1; \
+ }
+
+# $(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 LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \
+ package_gnu='GNU '; \
+ else \
+ package_gnu=''; \
+ fi; \
+ 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; \
+ case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
+ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \
+ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
+ --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
+ --files-from=$(srcdir)/POTFILES.in \
+ --copyright-holder='$(COPYRIGHT_HOLDER)' \
+ --msgid-bugs-address="$$msgid_bugs_address" \
+ ;; \
+ *) \
+ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
+ --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
+ --files-from=$(srcdir)/POTFILES.in \
+ --copyright-holder='$(COPYRIGHT_HOLDER)' \
+ --package-name="$${package_gnu}@PACKAGE@" \
+ --package-version='@VERSION@' \
+ --msgid-bugs-address="$$msgid_bugs_address" \
+ ;; \
+ esac
+ 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- at 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- at 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- at 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:
diff --git a/po/Makevars b/po/Makevars
new file mode 100644
index 0000000..3b569ce
--- /dev/null
+++ b/po/Makevars
@@ -0,0 +1,41 @@
+# 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 = The SpringLobby team
+
+# 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 =
+
+# 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 =
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..e2932f8
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,85 @@
+src/addbotdialog.cpp
+src/agreementdialog.cpp
+src/autobalancedialog.cpp
+src/battlelistctrl.cpp
+src/battlelistfilter.cpp
+src/battlelisttab.cpp
+src/battlemaptab.cpp
+src/battleoptionstab.cpp
+src/battleroomlistctrl.cpp
+src/battleroommmoptionstab.cpp
+src/battleroomtab.cpp
+src/channel/autojoinchanneldialog.cpp
+src/channel/channelchooser.cpp
+src/channel/channelchooserdialog.cpp
+src/channel/channellistctrl.cpp
+src/chatlog.cpp
+src/chatoptionstab.cpp
+src/chatpanel.cpp
+src/connectwindow.cpp
+src/countrycodes.cpp
+src/crashreport.cpp
+src/filelister/filelistctrl.cpp
+src/filelister/filelistdialog.cpp
+src/filelister/filelistfilter.cpp
+src/globalevents.cpp
+src/groupoptionspanel.cpp
+src/Helper/imageviewer.cpp
+src/Helper/wxtextctrlhist.h
+src/Helper/wxTranslationHelper.cpp
+src/hostbattledialog.cpp
+src/httpdownloader.cpp
+src/lobbyoptionstab.cpp
+src/mainchattab.cpp
+src/mainjoinbattletab.cpp
+src/mainoptionstab.cpp
+src/mainsingleplayertab.cpp
+src/maintorrenttab.cpp
+src/mainwindow.cpp
+src/mainwindow.h
+src/mapctrl.cpp
+src/mapselectdialog.cpp
+src/mmoptionswrapper.cpp
+src/mmoptionwindows.cpp
+src/nicklistctrl.cpp
+src/nonportable.h
+src/playback/playbackfilter.cpp
+src/playback/playbacklistctrl.cpp
+src/playback/playbacktab.cpp
+src/selectusersdialog.cpp
+src/selectusersdialog.h
+src/serverevents.cpp
+src/settings++/Defs.hpp
+src/settings++/frame.cpp
+src/settings++/helpmenufunctions.cpp
+src/settings++/Main.cpp
+src/settings++/panel_pathoption.cpp
+src/settings++/presets.h
+src/settings++/se_utils.cpp
+src/settings++/tab_abstract.cpp
+src/settings++/tab_audio.cpp
+src/settings++/tab_quality_video.cpp
+src/settings++/tab_render_detail.cpp
+src/settings++/tab_simple.cpp
+src/settings++/tab_ui.cpp
+src/singleplayerbattle.cpp
+src/singleplayertab.cpp
+src/springlobbyapp.cpp
+src/springoptionstab.cpp
+src/tasserver.cpp
+src/tdfcontainer.cpp
+src/torrentlistctrl.cpp
+src/torrentoptionspanel.cpp
+src/torrentwrapper.cpp
+src/ui.cpp
+src/uiutils.h
+src/httpdownloader.cpp
+src/updater/updater.cpp
+src/useractions.cpp
+src/useractions.h
+src/user.cpp
+src/userlistctrl.cpp
+src/usermenu.h
+src/widgets/downloaddialog.cpp
+src/widgets/downloadlistctrl.cpp
+src/widgets/infopanel.cpp
diff --git a/po/Rules-quot b/po/Rules-quot
new file mode 100644
index 0000000..9c2a995
--- /dev/null
+++ b/po/Rules-quot
@@ -0,0 +1,47 @@
+# Special Makefile rules for English message catalogs with quotation marks.
+
+DISTFILES.common.extra1 = quot.sed boldquot.sed en at quot.header en at boldquot.header insert-header.sin Rules-quot
+
+.SUFFIXES: .insert-header .po-update-en
+
+en at quot.po-create:
+ $(MAKE) en at quot.po-update
+en at boldquot.po-create:
+ $(MAKE) en at boldquot.po-update
+
+en at quot.po-update: en at quot.po-update-en
+en at boldquot.po-update: en at 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 at quot.insert-header: insert-header.sin
+ sed -e '/^#/d' -e 's/HEADER/en at quot.header/g' $(srcdir)/insert-header.sin > en at quot.insert-header
+
+en at boldquot.insert-header: insert-header.sin
+ sed -e '/^#/d' -e 's/HEADER/en at boldquot.header/g' $(srcdir)/insert-header.sin > en at boldquot.insert-header
+
+mostlyclean: mostlyclean-quot
+mostlyclean-quot:
+ rm -f *.insert-header
diff --git a/po/ar.gmo b/po/ar.gmo
new file mode 100644
index 0000000..7455de0
Binary files /dev/null and b/po/ar.gmo differ
diff --git a/po/ar.po b/po/ar.po
new file mode 100644
index 0000000..0382347
--- /dev/null
+++ b/po/ar.po
@@ -0,0 +1,5962 @@
+# Arabic translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-07-30 23:38+0000\n"
+"Last-Translator: SpringLobby_Buildbot <Unknown>\n"
+"Language-Team: Arabic <ar at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "إضاÙØ© بÙت"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "اÙÙÙÙØ©:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "اÙØ°Ùاء اÙاصطÙاعÙ:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "اختار Ù
Ùتبة اÙØ°Ùاء اÙاصطÙاع٠ÙاستخداÙ
Ùا Ù
ع اÙبÙت."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "ÙÙÙ
Ø©"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Ø¥Ùغاء"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "إضاÙØ© بÙت"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "ÙÙ
ÙتÙ
اÙعثÙر عÙ٠أ٠بÙتات Ø°Ùاء اصطÙاع٠عÙÙ Ùسخت٠Ù
Ù Spring."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "ÙÙ
ÙتÙ
اÙعثÙر عÙÙ Ù
Ùتبات اÙبÙت"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "ÙبÙ٠اÙاتÙاÙ"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Ù٠تÙب٠شرÙØ· Ùذا اÙاتÙاÙØ"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "ÙعÙ
"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Ùا"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "طرÙÙØ©"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr ""
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "عشÙائÙ"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "ÙرÙ"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Ùا Ø´ÙØ¡"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Ù
عتدÙ"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "دائÙ
اÙ"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+msgid "Number of allies"
+msgstr ""
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "إعادة اÙاتصاÙ"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ù
ÙاÙÙ"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "ÙصÙ"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "خارطة"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr ""
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Ù
ستضÙÙ"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "اÙÙ
تابعÙÙ:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "اÙÙÙاعبÙÙ:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "خارطة"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "تÙزÙ٠اÙ&خارطة"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr ""
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "اÙÙ
تابعÙÙ:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "اÙÙÙاعبÙÙ:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "اÙÙ
ستضÙÙ:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "اÙØاÙØ©:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Ù
ÙÙÙ"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Ù
ÙÙ٠بÙÙÙ
Ø© سرÙ"
+
+#: src/battlelistfilter.cpp:122
+msgid "Highlighted only"
+msgstr ""
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Øد٠اÙترتÙب:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "ÙصÙ:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "بدئت"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "ÙاÙ
ÙØ©"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "ÙتØ"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Ùاعب:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "اÙÙÙ"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "اÙخارطة:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "ÙÙØ· اÙخرائط٠اÙت٠أÙ
ÙÙÙا"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "اÙØد٠اÙأعÙÙ ÙÙاعبÙÙ:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr ""
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Ù
تابع:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "اÙÙÙاعبÙÙ:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+msgid " Filter "
+msgstr ""
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "بدئت"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+msgid " Battle infos "
+msgstr ""
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "استضاÙØ© جدÙدة..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "اÙضÙ
اÙ
"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "غÙر Ù
تصÙ."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "خطأ Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "خطأ Ù٠بدأ اÙÙ
عرÙØ©."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "ÙÙ
ÙتÙ
اÙعثÙر عÙ٠أ٠خرÙطة"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+msgid "Already in this battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+
+#: src/battlelisttab.cpp:523
+msgid "Already in another battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:523
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr ""
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr ""
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr ""
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "أدخ٠ÙÙÙ
Ø© اÙسرÙ"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Ø¥ÙتÙاء..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Ø®Ùار"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "ÙÙÙ
Ø©"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "ØجÙ
"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr ""
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr ""
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "اÙجاذبÙÙØ©"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr ""
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr ""
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "ثابت"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "اختار Ù٠اÙÙعبة"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "اختار Ù٠اÙÙعبة"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Ù
ÙاÙع اÙبدء"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr ""
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr ""
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "تÙعÙÙ Ù٠اÙÙØدات."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "تÙعÙÙ Ù٠اÙÙØدات."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "تÙعÙÙ Ù٠اÙÙØدات."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr ""
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+msgid "Unit restriction"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "اÙÙÙÙØ©"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "ÙرÙÙ"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "ØÙÙÙ"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "جÙØ©"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "تعÙÙ٠اÙÙÙÙ"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Ù
تابع"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "طرد"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "رجاء إدخا٠رÙÙ
بÙÙ 0 Ù100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "إضاÙØ© بÙت"
+
+#: src/battleroomlistctrl.cpp:719
+msgid "Human\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Ù
تابع"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Ùاعب:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Ù
ستضÙÙ"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "اÙعÙ
ÙÙ"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "دائÙ
اÙ"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "غÙر جاÙز"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+msgid "Set name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "تØÙ
ÙÙ..."
+
+#: src/battleroommmoptionstab.cpp:63
+msgid "Load a saved set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "ØÙظ..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+msgid "Save a set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Ø¥ÙتÙاء..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+msgid "Delete a set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "اÙÙ
بدئÙ"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+#, fuzzy
+msgid "Mod Options"
+msgstr "Ø®Ùارات اÙخارطة"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Ø®Ùارات اÙخارطة"
+
+#: src/battleroommmoptionstab.cpp:152
+msgid "no options available"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "اÙÙ
بدئÙ"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Ø£Ùا جاÙز"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "اÙÙÙÙ"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Ù
غادرة"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "بدء"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "إضاÙØ© بÙت..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "إعادة اÙاتصاÙ"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "بدء"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+msgid "Ring ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "غÙر جاÙز"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+msgid "Force spectate ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "تثبÙت اÙØ£ÙÙاÙ"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "ØÙظ..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr ""
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "اÙÙ
بدئÙ"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr ""
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr ""
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "غÙر جاÙز"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "اÙÙ
بدئÙ"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "ÙÙاة"
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "ÙÙاة"
+
+#: src/channel/channellistctrl.cpp:29
+msgid "# users"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr ""
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr ""
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr ""
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Ø®ÙÙÙÙÙØ©"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "اجراء"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr ""
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr ""
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "راساÙتÙ"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "اÙخادÙÙ
"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "اÙعÙ
ÙÙ"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "خطأ"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr ""
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "اشعار"
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "اÙخطÙ:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "اÙÙ
بدئÙ"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Ø¥ÙتÙاء..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "سÙÙÙ"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "سجÙÙات اÙدردشة"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "ØÙظ سجÙÙات اÙدردشة"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr ""
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, c-format
+msgid "%d users"
+msgstr ""
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "إرساÙ"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Ùسخ"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Ù
سØ"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr ""
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr ""
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Ù
عÙÙÙ
ات اÙÙÙاة"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "تعÙÙ٠اÙÙ
ÙضÙع..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "رساÙØ© اÙÙÙاة..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "ÙÙÙ..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Ø¥Ùغاء اÙÙÙÙ"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "تسجÙÙ..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Ø¥Ùغاء اÙتسجÙÙ"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr ""
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr ""
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr ""
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr ""
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr ""
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr ""
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "إعادة اÙاتصاÙ"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr ""
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "تغÙÙر ÙÙÙ
Ø© اÙسرÙ"
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr ""
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Øسابات"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "إذاعة..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "اÙإدارÙ"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "خادÙÙ
"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "ÙØªØ Ø§Ùدردشة"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr ""
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr ""
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr ""
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr ""
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr ""
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr ""
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr ""
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "طرد..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Ù
Ùع..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "رÙع اÙÙ
Ùع"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "صÙع!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr ""
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Ø£Ù
ر: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr ""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "ÙÙاة"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "Ù
عرÙØ©"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "خادÙÙ
"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr ""
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr ""
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Ù
عÙÙÙ
ات اÙÙÙاة"
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr ""
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Ùد أغÙÙت اÙدردشة."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr ""
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr ""
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr ""
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr ""
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr ""
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr ""
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr ""
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr ""
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr ""
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr ""
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr ""
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr ""
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr ""
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr ""
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr ""
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr ""
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr ""
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr ""
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr ""
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "رÙÙ
غÙر صاÙØ"
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr ""
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr ""
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr ""
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr ""
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr ""
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr ""
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr ""
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr ""
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr ""
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr ""
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr ""
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr ""
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr ""
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr ""
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr ""
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr ""
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr ""
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr ""
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr ""
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr ""
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr ""
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr ""
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr ""
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr ""
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr ""
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr ""
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr ""
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr ""
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr ""
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr ""
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr ""
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr ""
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr ""
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr ""
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr ""
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr ""
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr ""
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr ""
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr ""
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr ""
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr ""
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr ""
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr ""
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr ""
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr ""
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr ""
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr ""
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr ""
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr ""
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr ""
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr ""
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr ""
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr ""
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr ""
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr ""
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr ""
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr ""
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr ""
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr ""
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr ""
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr ""
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr ""
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr ""
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr ""
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr ""
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr ""
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr ""
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr ""
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr ""
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr ""
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr ""
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr ""
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr ""
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr ""
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr ""
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr ""
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr ""
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr ""
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr ""
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr ""
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr ""
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr ""
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr ""
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr ""
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr ""
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr ""
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr ""
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr ""
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr ""
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr ""
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr ""
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr ""
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr ""
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr ""
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr ""
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr ""
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr ""
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr ""
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr ""
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr ""
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr ""
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr ""
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr ""
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr ""
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr ""
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr ""
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr ""
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr ""
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr ""
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr ""
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr ""
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr ""
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr ""
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr ""
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr ""
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr ""
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr ""
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr ""
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr ""
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr ""
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr ""
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr ""
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr ""
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr ""
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr ""
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr ""
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr ""
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr ""
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr ""
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr ""
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr ""
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr ""
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr ""
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr ""
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr ""
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr ""
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr ""
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr ""
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr ""
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr ""
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr ""
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr ""
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr ""
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr ""
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr ""
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr ""
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr ""
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr ""
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr ""
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr ""
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr ""
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr ""
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr ""
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr ""
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr ""
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr ""
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr ""
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr ""
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr ""
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr ""
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr ""
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr ""
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr ""
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr ""
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr ""
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr ""
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr ""
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr ""
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr ""
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr ""
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr ""
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr ""
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr ""
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr ""
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr ""
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr ""
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr ""
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr ""
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr ""
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr ""
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr ""
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr ""
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr ""
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr ""
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr ""
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr ""
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr ""
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr ""
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr ""
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr ""
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr ""
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr ""
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr ""
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr ""
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr ""
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr ""
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr ""
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr ""
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr ""
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr ""
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr ""
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr ""
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr ""
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr ""
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr ""
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr ""
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr ""
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr ""
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr ""
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr ""
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr ""
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr ""
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr ""
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr ""
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr ""
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr ""
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr ""
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr ""
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr ""
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr ""
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "اÙÙÙÙØ©"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "تÙزÙ٠اÙ&خارطة"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+msgid "Remove"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+msgid "Rename.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "إضاÙØ© بÙت..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "اجراء"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "ÙØªØ Ø§Ùدردشة"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+msgid "Highlight Color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "إضاÙØ© بÙت..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+msgid "Remove users from group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Ø¥ÙتÙاء..."
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "اختار Ù٠اÙÙعبة"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "اÙÙ
بدئÙ"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Ù
عÙÙÙ
ات اÙÙÙاة"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr ""
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "ÙصÙ"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr ""
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr ""
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Randomly picks an available one"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr ""
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr ""
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "إعادة اÙاتصاÙ"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+msgid "Autoconnect on lobby start"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "بدء"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+msgid "Disconnected from server, chat closed."
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Ø®Ùارات"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+msgid "Unit Restrictions"
+msgstr ""
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr ""
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr ""
+
+#: src/mainoptionstab.cpp:75
+msgid "General"
+msgstr ""
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr ""
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr ""
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr ""
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "تÙزÙ٠اÙ&خارطة"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr ""
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr ""
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr ""
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Ø®Ùارات اÙخارطة"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr ""
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Ù
عÙÙÙ
ات اÙÙÙاة"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr ""
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr ""
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr ""
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr ""
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Ù
عÙÙÙ
ات اÙÙÙاة"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr ""
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr ""
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr ""
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr ""
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "إعادة اÙاتصاÙ"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr ""
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "ÙÙ
ÙتÙ
اÙعثÙر عÙ٠أ٠خرÙطة"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+msgid "Which profile do you want to be default?"
+msgstr ""
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "ØÙظ..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "دائÙ
اÙ"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "تÙزÙ٠اÙ&خارطة"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr ""
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr ""
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr ""
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr ""
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "Ù
عتدÙ"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Ø®Ùارات اÙخارطة"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Ù
ÙاÙع اÙبدء"
+
+#: src/mapselectdialog.cpp:265
+msgid "Minimum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Ù
تابع"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Ù
ÙاÙع اÙبدء"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "اختار Ù٠اÙÙعبة"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "اختار Ù٠اÙÙعبة"
+
+#: src/mmoptionswrapper.cpp:131
+msgid "List of restricted units"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Ø®Ùارات اÙخارطة"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr ""
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr ""
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr ""
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr ""
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+msgid "Duration (hh:mm:ss):"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Ù
عرÙØ©"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "اÙÙÙÙØ©"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "اÙÙÙÙØ©"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "ÙصÙ"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "خطأ Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "تØÙ
ÙÙ..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "دائÙ
اÙ"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "ØÙظ..."
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "رÙÙ
غÙر صاÙØ"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Ø¥ÙتÙاء اÙÙÙ"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+msgid " is online"
+msgstr ""
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+msgid " just went offline"
+msgstr ""
+
+#: src/serverevents.cpp:260
+msgid " opened battle "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr ""
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr ""
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "تÙزÙ٠اÙ&خارطة"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "اشعار"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "رÙÙ
غÙر صاÙØ"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Ùذا ÙÙس رÙÙ
"
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "بدئت"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "إعادة اÙاتصاÙ"
+
+#: src/serverevents.cpp:999
+msgid "Unknown Error"
+msgstr ""
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "تÙزÙ٠اÙ&خارطة"
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Ø®Ùارات اÙخارطة"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Ø®Ùارات اÙخارطة"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "Battle volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "اجراء"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "اÙÙ
بدئÙ"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr ""
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "اجراء"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "اجراء"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "اجراء"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "اجراء"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "اجراء"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr ""
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr ""
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr ""
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr ""
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr ""
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr ""
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr ""
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr ""
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Ù
تابع"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Ù
ÙاÙع اÙبدء"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr ""
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr ""
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Ùا Ø´ÙØ¡"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+msgid "Import settings?"
+msgstr ""
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "ÙØªØ Ø§Ùدردشة"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr ""
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "ثابت"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr ""
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr ""
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr ""
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr ""
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr ""
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr ""
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+msgid "MB downloaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "اÙØاÙØ©:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr ""
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr ""
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr ""
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr ""
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr ""
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr ""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr ""
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr ""
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:661
+msgid "Disconnected from server."
+msgstr ""
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+msgid "Connection failure"
+msgstr ""
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr ""
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid "Not up to date"
+msgstr ""
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr ""
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Ùا Ø´ÙØ¡"
+
+#: src/useractions.h:11
+msgid "highlight"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify hosted battle"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "دائÙ
اÙ"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "اÙÙÙÙØ©"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr ""
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr ""
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr ""
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr ""
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr ""
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr ""
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr ""
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "إضاÙØ© بÙت..."
+
+#: src/usermenu.h:30
+msgid "Remove from group"
+msgstr ""
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+msgid "Author"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "خطأ Spring"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "تÙزÙ٠اÙ&خارطة"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Ø¥Ùغاء"
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "اÙÙ
تابعÙÙ:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "اÙÙÙاعبÙÙ:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "ÙرÙÙ"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "ØÙÙÙ"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Ùد أغÙÙت اÙدردشة."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Ø®Ùارات اÙخارطة"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "اختار Ù٠اÙÙعبة"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "تÙزÙ٠اÙ&خارطة"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "إعادة اÙاتصاÙ"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Ùاعب:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "تعÙÙ٠اÙÙÙÙ"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "اجراء"
+
+#~ msgid "a"
+#~ msgstr "Ø£"
+
+#~ msgid "m"
+#~ msgstr "Ù
"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Ù
عÙÙÙ
ات اÙÙÙاة"
+
+#~ msgid "_SERVER"
+#~ msgstr "_خادÙÙ
"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "غÙر Ù
تصÙ."
+
+#~ msgid "Select all"
+#~ msgstr "Ø¥ÙتÙاء اÙÙÙ"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "خطأ Spring"
+
+#~ msgid "End condition"
+#~ msgstr "شرط اÙØ¥ÙتÙاء"
+
+#~ msgid "Resources"
+#~ msgstr "اÙÙ
Ùارد"
+
+#~ msgid "Save to:"
+#~ msgstr "ØÙظ ÙÙ:"
+
+#~ msgid "Browse..."
+#~ msgstr "استعراض..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "اختÙار دÙÙÙ"
diff --git a/po/boldquot.sed b/po/boldquot.sed
new file mode 100644
index 0000000..4b937aa
--- /dev/null
+++ b/po/boldquot.sed
@@ -0,0 +1,10 @@
+s/"\([^"]*\)"/â\1â/g
+s/`\([^`']*\)'/â\1â/g
+s/ '\([^`']*\)' / â\1â /g
+s/ '\([^`']*\)'$/ â\1â/g
+s/^'\([^`']*\)' /â\1â /g
+s/ââ/""/g
+s/â/â[1m/g
+s/â/[0mâ/g
+s/â/â[1m/g
+s/â/[0mâ/g
diff --git a/po/cs.gmo b/po/cs.gmo
new file mode 100644
index 0000000..764e8d2
Binary files /dev/null and b/po/cs.gmo differ
diff --git a/po/cs.po b/po/cs.po
new file mode 100644
index 0000000..4e8f1c7
--- /dev/null
+++ b/po/cs.po
@@ -0,0 +1,6374 @@
+# Czech translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-09-06 12:50+0000\n"
+"Last-Translator: vejha_cz <vejha1 at gmail.com>\n"
+"Language-Team: Czech <cs at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr ""
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "PÅezdÃvka:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "UI:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Vyberte knihovnu UI pro tohoto protihráÄe."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Hodnota"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Zrušit"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr ""
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr ""
+"Ve vaÅ¡Ã Spring instalaci nebyly nalezeny žádné UI pro poÄÃtaÄové hráÄe."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Nebyly nalelezeny žádné bot-libs"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "PÅijmout PodmÃnky"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr ""
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Ano"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Ne"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "Automaticky vyrovnat poÄet hráÄů v týmech"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "Metoda"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "RozdÄl hodnosti rovnomÄrnÄ"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Náhodný"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Klany"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Žádný"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Slušný"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Vždy"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"PÅemÃstit hráÄe stejného klanu (se stejným klan-tagem, jako [smurfzor]Alice' "
+"and '[smurfzor]Bob' ) do spoleÄné aliance. \n"
+"Žádné: nepÅemisÅ¥ovat hráÄe podle klanů\n"
+"Vyrovnané: pÅesunout Äleny klanu do jedné aliance, pokud tak bude hra "
+"vyrovaná\n"
+"Vždy pÅemÃstit: hráÄi jednoho klanu budou pÅesunuti vždy do jedné aliance"
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "PoÄet hráÄů"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Znovu se pÅipojit"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Popis"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Host"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Pozorovatelé:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "HráÄi:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Stáhnout &mapu"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "Stáhnout mod"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Pozorovatelé:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "HráÄi:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Stav:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "UzamÄeno"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Zaheslováno"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "ZvýraznÄnÃ"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Omezenà Hodnosti:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Popis:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "SpuÅ¡tÄno"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Plný"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "OtevÅÃt"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "HráÄ:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "VÅ¡echny"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Mapa:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Mapy, které mám"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Max. HráÄů:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Mody, které mám"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Pozorovatel:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "HráÄi:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "Soubor"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "SpuÅ¡tÄno"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "Seznam bitev"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Založit novou..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "PÅipojit"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Nemůžete zakládat hru, když jste offline. ProsÃm pÅipojte se k lobby serveru."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Nenà pÅipojený."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "Nemůžete zakládat hru, protože máte nekompatibilnà verzi"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Spring error"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Již máte jednu spuÅ¡tÄnu instanci Spring, nejdÅÃve ji vypnÄte, aby jste mohli "
+"založit novou hru"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"PoužÃváte wxWidgety pÅedcházejÃcà verze 2.8\n"
+" testovánà portů nenà podporováno\n"
+" Zakládánà bitev nemusà fungovat."
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"Server použil pro testovánà váš port %d je nedostupný. \n"
+"Zakládánà her s tÃmto nastavenÃm nemusà fungovat."
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"Bitva nemohla být zahájena, protože vámi vybraný port (%d) nenà schopen "
+"pÅÃjmu pÅÃchozÃch packetů.\n"
+" zkontrolujte znovu vaÅ¡i konfiguraci routeru & firewallu a zmÄÅte port v "
+"dialogu."
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+"Bitva nemohla být zahájena, protože vámi vybraný mod nemůže být nalezen. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Error pÅi startovánà bitvy."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Ve vašà instalaci Springu nebyly nalezeny žádné mapy. Může to být způsobeno "
+"Å¡patným nastavenÃm Springu."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Mapy nenalezeny"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"PÅipojovánà k bitvám je zakázáno, ptotože použÃváte nekopmatibilnà verzi "
+"springu."
+
+#: src/battlelisttab.cpp:509
+msgid "Already in this battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Již jste zapojeni v bitvÄ.\n"
+"\n"
+"Chcete opustit souÄasnou bitvu a pÅipojit se k této?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Založit bitvu"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Již jste zapojeni v bitvÄ.\n"
+"\n"
+"Chcete opustit souÄasnou bitvu a pÅipojit se k této?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Již máte spuÅ¡tÄnu jedno instanci Springu, nejprve ji zavÅete, aby jste se "
+"mohli pÅidat k dalÅ¡Ã bitvÄ."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "Chcete se pÅemÃstit na stránku stahovánÃ?"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+#, fuzzy
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+"Mám se pokusit to stáhnout?\n"
+"PrůbÄh můžete vidÄt v záložce \"Správce StahovánÃ\"."
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+"Než se pÅipojÃte k této hÅe, musÃte stáhnout mod.\n"
+"\n"
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Mod nenà dostupný"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+"MusÃte nejprve stáhnout mapu, aby jste mohli hrát tuto hru.\n"
+"\n"
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Mapa nenà dostupná"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Heslo bitvy"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Zadejte heslo"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Vyber..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Možnost"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Hodnota"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Velikost"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Rychlost vÄtru"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "SÃla pÅÃlivu"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravitace"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Dosah extraktoru"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Max kov"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "NemÄnný"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Nastavit ve hÅe"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "Nastavit ve hÅe"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Startovnà pozice"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Omezenà jednotky"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Povolené jednotky"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "jednotky v tomto seznamu budou ve hÅe povoleny."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Povolit všechny jednotky."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Povolit všechny jednotky."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Povolit všechny jednotky."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Zakázané jednotky"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "jednotky v tomto seznamu nebudou ve hÅe povoleny."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Omezenà jednotky"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "PÅezdÃvka"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Tým"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Spojenec"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Bonus Surovin"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Frakce"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Nastavit barvu"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Nastavit bonus surovit"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Pozorovatel"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Vykopnout"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Zazvonit"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "ProsÃm vložte hodnotu mezi 0 a 100"
+
+#: src/battleroomlistctrl.cpp:717
+msgid "AI (bot)\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Omán"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Pozorovatel"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "HráÄ:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Host"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Klient"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Vždy"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "NepÅipraven"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "Zapnout v-sync"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Nastavit pÅistup..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "NaÄÃtánÃ..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "NáÄÃst uložený seznam omezenÃ."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Uložit..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Uložit seznam omezenÃ."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Vyber..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Uložit seznam omezenÃ."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "výchozÃ"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Nastavenà Modu"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Nastavenà Mapy"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "nepoužitelné"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "chyba"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "výchozÃ"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr "HráÄà se stejným ÄÃslem týmu se dÄli o kontrolu jejich nad jednotkami."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+"HráÄà se stejným ÄÃslem spojenectvà hrajà se pokouÅ¡ejà spoleÄnÄ dosáhnout "
+"vÃtÄzstvÃ."
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "Zvolte barvu pro identifikaci vaÅ¡ich jednotek ve hÅe."
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "Zvolte vaši frakci"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "Pozorovat bitvu namÃsto hranÃ."
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Jsem pÅipraven"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "KliknÄte sem, pokud jste pÅipraveni k zaÄátku hry."
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Barva"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"Náhled zvolené mapy. Můžete vidÄt startovnà pozice nebo (pokud nastaveno) "
+"startovnà boxy."
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "OdejÃt"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "Zahájit bitvu"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr ""
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "PÅidat poÄÃtaÄem kontrolovaného hráÄe do hry"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "Zakázat dalÅ¡Ãm hráÄům pÅipojit se k bitvÄ"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Znovu se pÅipojit"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+#, fuzzy
+msgid "Lock Balance"
+msgstr "RozdÄlit"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "Zapnout v-sync"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Zazvonit"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "NepÅipraven"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "Vynutit zaÄátek?"
+
+#: src/battleroomtab.cpp:239
+#, fuzzy
+msgid "Balance alliances"
+msgstr "Pouze zakladatel může vyrovnávat aliance."
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr "Automaticky rodÄlit hráÄe do dvou nebo vÃce aliancÃ"
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "Uzamknout barvy"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "Nastavit barvu hráÄe jedineÄnou"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid "Balance teams"
+msgstr "RozdÄlit"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr "Automaticky rodÄlit hráÄe do dvou nebo vÃce aliancÃ"
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Uložit..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr ""
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "výchozÃ"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "Boxy"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr "Vybrat"
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "PokraÄovat"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "Konec"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "Mapa neexistuje."
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"NÄkteÅà hráÄi jeÅ¡tÄ nejsou pÅipraveni.\n"
+"Zazvonit na nÄ?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "NepÅipraven"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "výchozÃ"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "&Autotomaticky vstoupit do mÃstnostÃ..."
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "Vstoupit do mÃstnosti..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "Jméno mÃstnosti k pÅipojenÃ"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "mÃstnost"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d uživatelé)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Sezenà UkonÄeno v ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Nemohu vytvoÅit složku. \n"
+"PÅesvÄdÄte se, že je povoleno zapisovánÃ.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "Zaznamenávánà vypnuto do restartovánà SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"Nemohu zapsal zprávu do záznamu.\n"
+"Zaznamenávánà pro mÃstnost bude vypnuto. "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"Znovu se pÅipojte do mÃstnosti, pro aktivaci zaznamenávánÃ."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Nemohu otevÅÃt soubor záznamu. \n"
+"UjistÄte se, že je povoleno zapisovánÃ.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Barvy a font"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "PožÃvat systémové barvy"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "NormálnÃ"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "PozadÃ"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Akce"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "ZvýraznÄnÃ"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "PÅpojit/Odpojit se"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Mé zprávy"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Server"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Klient"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Chyba"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Äasová znaÄka"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "UpozornÄnÃ"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Connected to TAS Server.\n"
+"[22:30] <Typan> zdravim\n"
+"[22:30] ** Lama joined the channel.\n"
+"[22:30] * Lama si mysli ze ty barvy jsou proste super\n"
+"[22:45] <Typan> Lama: fakt?\n"
+"[22:46] <Lama> jeste bych to mel nejak vic prohazet...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "PÃsmo:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "výchozÃ"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Vyber..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "ChovánÃ"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr "PÅehrávat zvuky upozornÄnÃ"
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Záznamy chatů"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Ukládat záznamy chatů"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Zvýraznit slova"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Slova k zvýraznÄnà v chatu:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "vložte ; rozdÄlený list"
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr "mÃstnost_"
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d uživatelé)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "kliknÄte pravým tlaÄÃtkem pro možnosti (jako automatické pÅipojenÃ)"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Odeslat"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "KopÃrovat"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Vymazat"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "Automaticky se pÅipojit do této mÃstnosti"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "Zobrazovat Zprávy PÅipojenÃ/OdpojenÃ"
+
+#: src/chatpanel.cpp:433
+#, fuzzy
+msgid "Show mute list"
+msgstr "Zobrazit tipy"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Informace o mÃstnosti"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Nastavit téma..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Zpráva mÃstnost..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Uzamknout..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Odemknout"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Registrovat se..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Zrušit registraci"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Zapnout"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Vypnout"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "Je zapnuto?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Ochrana pÅed spamem"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Odpojit"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Znovu se pÅipojit"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Odstranit..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "ZmÄnit heslo..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Nastavit pÅistup..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "ÃÄty"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "VysÃlánÃ"
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Administrátor"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Vykopnout uživatele"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "OtevÅÃt Chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "PÅidat se ke stejné bitvÄ"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Äas ve hÅe"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Utlumit..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Utlumit na 5 minut"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Utlumit na 10 minut"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Utlumit na 30 minut"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Utlumit na 2 hodiny"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Utlumit na 1 den"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "ZruÅ¡it utlumenÃ"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Utlumit"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Vykopnout..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Ban..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Unban"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "Slap!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Op"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "DeOp"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! PÅÃkaz: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" parametry: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "mÃstnost"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "Bitva"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "server"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " se pÅipojil k "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " odešel z "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Informace o mÃstnosti"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * Nastaven od "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat zavÅen."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Opravdu chcete vložit %d Åádků?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Vaše verze SpringLobby je"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Nejste v mÃstnosti nebo mÃstnost neexistuje."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" Chyba: PÅÃkaz (%s) neexistuje, použijte /help pro seznam možných pÅÃkazů."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+" Nejste v bitvÄ, nebo bitva neexistuje, použijte /help pro seznam dostupných "
+"pÅÃkazů."
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Uživatel nenà pÅipojen."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Odesláno: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ChanServ error"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ nenà v této mÃstnosti."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Jaké by mÄlo být nové téma?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Zpráva:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "Ukamknout mÃstnost"
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Jaké by mÄlo nové heslo?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "Odemknout MÃstnost"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Opravdu chctete odemknout tuto mÃstnost?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ nenà na tomto serveru."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Registrovat MÃstnost"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "Odhlásit MÃstnost"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "Opravdu chcete odhlásit tuto mÃstnost?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Odstranit Uživatelský ÃÄet"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Který uživatelský úÄet si pÅejete odstranit?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Odstranit úÄet"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Opravdu si pÅejete odstranit úÄet? "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "ZmÄnit Heslo Uživatelského ÃÄtu"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Pro jaký uživatelský úÄet si pÅejete zmÄnit heslo?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Jaké bude nové heslo?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Neimplementováno"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "Nemáte tento mod "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "Tato bitva je chránÄna heslem,zadejte heslo."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr ""
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Vykopnout uživatele"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Důvod:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Vykopnout uživatele"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Doba trvánÃ:"
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "PÅipojit se k lobby serveru"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Server k pÅipojenÃ. Můžete se pÅipojit k jakémukoli serveru, napsánÃm textu "
+"ve formátu hostaddress:port."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Heslo"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "Zapamtovat si heslo"
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"pamatovat si detaily pÅipojenà a automaticky se pÅipojit k serveru pÅi "
+"dalÅ¡Ãm startu lobby"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"Poznámka: pokud nemáte úÄet, můžete\n"
+"si ho zdarma registrovat pod\n"
+"záložkou \"Registrovat\"."
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "PÅihlášenÃ"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Registrace"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "PÅezdÃvka"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Neplatný port."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Neplatný port"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"ÄÃslo portu mimo meze.\n"
+"\n"
+"Musà být celoÄÃselnou hodnotou mezi 1 a 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Neplatné ÄÃslo"
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Registrace selhala."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Spojené Arabské Emiráty"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afghánistán"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua a Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albánie"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Arménie"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Nizozemské Antily"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antarktida"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentina"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Americká Samoa"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Rakousko"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Austrálie"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azerbajdžán"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosna a Hercegovina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladéš"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgie"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulharsko"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahrajn"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermudy"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunej"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "BolÃvie"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "BrazÃlie"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamy"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhútán"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Bouvetův ostrov"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "BÄlorusko"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Kanada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "kosové ostrovy"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "StÅedoafrická republika"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Kongo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Švýcarsko"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr ""
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Cookovy ostrovy"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Kamerun"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "ÄÃna"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Kolumbie"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Kostarika"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Kuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Kapverdské ostrovy"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "VánoÄnà ostrov"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Kypr"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "Äeská republika"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "NÄmecko"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Džibuti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Dánsko"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominika"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Dominikánská republika"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "AlžÃr"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ekvádor"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estonsko"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Egypt"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Západnà Sahara"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritrea"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Å panÄlsko"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Etiopie"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finsko"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fidži"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Fallandské ostrovy (MalvÃny)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Mikronésie"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Faerské ostrovy"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "Francie"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "Francie, metropolitnÃ"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Gruzie"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Francouzská Guayana"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Grónsko"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambie"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guinea"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadeloupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "RovnÃková Guinea"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Åecko"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "Ostrovy svatá Georgia a Sandwich"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guinea-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guayana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Chorvatsko"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "MaÄarsko"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonésie"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irsko"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Izrael"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "Indie"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Britské teritorium v Indickém oceánu"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Irák"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Ãrán"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Island"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Itálie"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamajka"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Jordánsko"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japonsko"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "KeÅa"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Kambodža"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Komory"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "Svatý Kryštof a Nevis"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Korejská lidovÄ demokratická republika (Severnà Korea)"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Korejská republika (Jižnà Korea)"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuvajt"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Kajmanské ostrovy"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kazachstán"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Libanon"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Svatá Lucie"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Lichtenštejnsko"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Srà Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Libérie"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Litva"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Lucembursko"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Lotyšsko"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Libye"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Maroko"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monako"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldávie"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Äerná hora"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagaskar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Marshallovy ostrovy"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Makedonie"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Myanmar"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongolsko"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macao"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Severnà Mariánské Ostrovy"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinik"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauritánie"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Mauritius"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Maledivy"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Mexiko"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malajsie"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mosambik"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "NamÃbie"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Nová Kaledonie"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Nigerie"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Norfolkský ostrov"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigérie"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nikaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "NizozemÃ"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norsko"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepál"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Neutrálnà Ãzemà (Saudská Arabie/irák)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "Nový Zéland"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Omán"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panama"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Peru"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Francouzská Polynésie"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua Nová Guinea"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "FilipÃny"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pákistán"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Polsko"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "St. Pierre a Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Pitcairnovy ostrovy"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Portoriko"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugalsko"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palauská republika"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Katar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Reunion"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Rumunsko"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Srbsko"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Ruská federace"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Rwanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Saudská Arábie"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Å alamounovy ostrovy"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychelské ostrovy"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Súdán"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Švédsko"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapur"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "Sv. Helena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slovinsko"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Ostrovy Svalbard a Jan Mayen"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Slovensko"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Leone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somálsko"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Surinam"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "Svatý Tomáš a Princův ostrov"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "SovÄtský Svaz (bývalý)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "Salvádor"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Sýrie"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Svazijsko"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Ostrovy Turks a Caicos"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Äad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Francouzská Jižnà Teritoria"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Thajsko"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tádžikistán"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Tokelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistán"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunis"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Východnà Timor"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Turecko"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad a Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Tchaj-wan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tanzanie"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ukrajina"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "Velká Británie"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "US menÅ¡Ã pobÅežnà ostrovy"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "Spojené státy"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Uzbekistán"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Vatikánský mÄstský stát (Svatý stolec)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "Svatý Vincenc a Grenadiny"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Panenské ostrovy"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Panenské ostrovy"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vietnam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Ostrovy Wallis a Futuna"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Jemen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Jugoslávie"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Jižnà Afrika"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Zambie"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zair"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "Plné jméno zemÄ nenalezeno"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "Systémové informace"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Naposledy vytvoÅený skript spouÅ¡tÃcà spring"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Hra"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+#, fuzzy
+msgid "Search and download files"
+msgstr "Hledat soubor"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Stahovánà selhalo"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+#, fuzzy
+msgid "unknown hash "
+msgstr "neznámý"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Odstranit..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Odstranit..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "PÅidat poÄÃtaÄ..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Akce"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "OtevÅÃt Chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Zvýraznit slova"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "PÅidat poÄÃtaÄ..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Odstranit Uživatelský ÃÄet"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Jméno uživatele"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Vyber..."
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Nastavit ve hÅe"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"úspÄÅ¡nÄ uloženo do:\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "Nastavit pÅistup..."
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "Nemohl uložit\n"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "výchozÃ"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Informace o mÃstnosti"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr ""
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Popis"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Vyberte mod, který chcete hrát."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr "Pro vstup do hry je nutné heslo. Ponechte prázdné pro žádné heslo"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Port"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "nepoužitelné"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "PoÄet hráÄů"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Minimálnà potÅebná hodnost"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Založit bitvu"
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "MusÃte nejdÅÃv vybrat mód."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Nebyl vybrán žádný mod."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"úspÄÅ¡nÄ uloženo do:\n"
+
+#: src/httpdownloader.cpp:78
+#, fuzzy
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"úspÄÅ¡nÄ uloženo do:\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr "Nemohl uložit\n"
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"do:\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Webový prohlÞeÄ"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Standardnà prohlÞeÄ."
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Specifikovat:"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr "UrÄete webový prohlÞeÄ,který chcete použÃvat"
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Procházet"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "Znovu se pÅipojit"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "PÅipojit se k lobby serveru"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "&Nástroje"
+
+#: src/lobbyoptionstab.cpp:121
+#, fuzzy
+msgid "Show Tooltips?"
+msgstr "Zobrazit tipy"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "PoÄáteÄnà kov"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Neznámá zpravá ze serveru"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "Seznam bitev"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "MÃstnost hry"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "NastavenÃ"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Omezenà jednotky"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "P2P"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Senegal"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Vrátit"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "PoužÃt"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Hra"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "neznámý"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "ZruÅ¡it stahovánÃ"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "UveÅejnit nový soubor"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "Hledat soubor"
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Stahovánà selhalo"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "nepoužitelné"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "Stav: nepÅipojený"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "Stav: pÅipojen"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "Stav: neznámý"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "Celkový výstup: %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "Celkový vstup: %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr ""
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr ""
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "nastavenà UI"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Konec"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Informace o mÃstnosti"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr "&Autotomaticky vstoupit do mÃstnostÃ..."
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&Znovu zavést mapy/módy"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr ""
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "SpringNastavenÃ"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&O programu"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Informace o mÃstnosti"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&Nahlásit bug..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Dokumentace"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&Soubor"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Nástroje"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&NápovÄda"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Stav: pÅipojen"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "Vstoupit do mÃstnosti..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Jméno mÃstnosti k pÅipojenÃ"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Jméno uživatele"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Mapy nenalezeny"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "RuÄnÄ &Spustit Torrent Systém"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "RuÄnÄ &Zastavit Torrent Systém"
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Který uživatelský úÄet si pÅejete odstranit?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Uložit..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "Vždy"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Stáhnout"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Aktualizovat"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Stáhnout"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "frakce:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "Soubor"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Max kov"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Startovnà pozice"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Minimálnà potÅebná hodnost"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "PrůmÄrný"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Pozorovatel"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Náhodné startovnà pozice"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Typ Startovnà Pozice"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Jak hráÄi vyberou, kde se objevà na mapÄ\n"
+"0: pevné pozice na mapÄ\n"
+"1: náhodné pozice na mapÄ\n"
+"2: vybrat za hry\n"
+"3: vybrat z lobby pÅed zahájenÃm"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Nastavit ve hÅe"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Nastavit ve hÅe"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Zakázané jednotky"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "nastavenà UI"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "c"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Spustitelné Soubory (*.exe)|*.exe|Jakýkoliv Soubor (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Jakýkoliv soubor (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+#, fuzzy
+msgid "Filter settings"
+msgstr "Uložit nastavenÃ"
+
+#: src/playback/playbackfilter.cpp:164
+#, fuzzy
+msgid "Filesize in KB:"
+msgstr "Velikost souboru (MB)"
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Doba trvánÃ:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Bitva"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Mód"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Panama"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Doba trvánÃ:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Spring error"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "Velikost souboru (MB)"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "Velikost souboru (MB)"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "Soubor"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "NaÄÃtánÃ..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Vždy"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Uložit..."
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+#, fuzzy
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+"Než se pÅipojÃte k této hÅe, musÃte stáhnout mod.\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Neplatný port"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Vybrat vše"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Uživatel nenà pÅipojen."
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Uživatel nenà pÅipojen."
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " se pÅipojil k "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "NepodaÅilo se pÅipojit do mÃstnosti"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Nemohu se pÅipojit k mÃstnosti "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " protože: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " má ip=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "Seznam bitev"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Stahovánà selhalo"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"Nastal problém pÅi ovÄÅovánà poslednà verze.\n"
+"ProsÃm zopakujte pozdÄji.\n"
+"Pokud problém pÅetrvává, použijte NápovÄda->Nahlásit Bug, aby jste na chybu "
+"upozornili."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "UpozornÄnÃ"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Neplatné ÄÃslo"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Nenà Äislo"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "Mapa neexistuje."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "SpuÅ¡tÄno"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Znovu se pÅipojit"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "neznámý"
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Stahovánà selhalo"
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+"VÄtÅ¡Ã hodnoty zrychlujà pÅibližovánÃ/oddalovánà pomocà koleÄka myÅ¡i.\n"
+"Záporné hodnoty invertujà smÄr pÅibližovánÃ/oddalovánÃ.\n"
+"Výsledek může záviset na módu kamery!"
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"vÄtÅ¡Ã hodnota = lépe vypadajÃcà stÃny\n"
+"možné hodnoty: 1024, 2048, 4096, 8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Grafické detaily"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Grafické detaily"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "limituje kolik Äástic je zobrazeno najednou"
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "Mód dvou obrazovek"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "Zapnout v-sync"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+#, fuzzy
+msgid "16-bit Z-buffer"
+msgstr "24-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr "24-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "MÃstnost hry"
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "Akce"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+#, fuzzy
+msgid "Issue commands on mini-map"
+msgstr "Zobrazit pÅÃkazy na mini-mapÄ"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "Zobrazit pÅÃkazy na mini-mapÄ"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+#, fuzzy
+msgid "Draw icons on mini-map"
+msgstr "Zobrazit pÅÃkazy na mini-mapÄ"
+
+#: src/settings++/Defs.hpp:306
+#, fuzzy
+msgid "Draw markers on mini-map"
+msgstr "Zobrazit pÅÃkazy na mini-mapÄ"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "levá je standardnÃ"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+#, fuzzy
+msgid "Use less colors"
+msgstr "PožÃvat systémové barvy"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+#, fuzzy
+msgid "Show in-game player information"
+msgstr "Systémové informace"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "PÅevrátit Y-osu myÅ¡i v FPS módu"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "nastavit rychlost rolovánà (myš+klávesnice) pro tento mód"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+#, fuzzy
+msgid "First person camera"
+msgstr "Prvnà osoba"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "ZákladnÃ"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Akce"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "ZrcadlÃcà + lomivý"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "Dynamický"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+#, fuzzy
+msgid "Invert mouse y-axis"
+msgstr "PÅevrátit Y-osu myÅ¡i v FPS módu"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "Prvnà osoba"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "Å¡ÃÅka obrazovky"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "výška obrazovky"
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Akce"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Akce"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Akce"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "omezenÃ"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Vypnout"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "Kombinované nastavenÃ"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "Kvalita vykreslovánÃ/Zobrazovacà mód"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "nastavenà UI"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Audio"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "Chyba!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "Uložit nastavenà Springu pÅed ukonÄenÃm?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "Nastavenà Springu (expertnà mód)"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "Nastavenà Springu (jednoduchý mód)"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "Uložit nastavenÃ"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "Restartovat nastavenà na standardnà hodnoty"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "Konec"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Kontakt"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "Nahlásit chybu"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Mód"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Info/NápovÄda"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "Restartovat všechna nastavenà na standardnà hodnoty?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Kritická chyba"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "PoužÃt tuto cestu"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Libovolný soubor"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "nÃzké"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "stÅednÃ"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "vysoké"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Audio volby"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Rozlišenà obrazovky"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Kvalita vody"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "Rozlišenà v bitech"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "Nastavenà kvality vykreslovánÃ"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "Nastavenà zobrazovacÃho módu"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "Nastavenà vyhlazovánÃ"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "ÃrovnÄ vykreslovaných detailů"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Grafické detaily"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Rozlišenà obrazovky"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "PÅepnout do expertnÃho módu"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (aktuálnÃ)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Info"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "Rychlost rolovánà (myš+klávesnice)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "Standardnà režim kamery"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "ZvÄtÅ¡it"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "PÅidat poÄÃtaÄ..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Pozorovatel"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Náhodné startovnà pozice"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr ""
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "Chyba hernÃho nastavenÃ"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Nejprve musÃte vybrat mapu"
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Ahoj "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "VÃtejte"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Žádný"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "Uložit nastavenÃ"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "OtevÅÃt Chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "Seznam bitev"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Najdi"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "UmÃstÄnÃ"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Najdi"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "UnitSync knihovna"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Automatické nastavenÃ"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Knihovna"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "Zvolte složku"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Äas spojenà vyprÅ¡el"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Neznámá zpravá ze serveru"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "ÄÃsla"
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "Stáhnout"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Stav:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s up"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s down"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "Velikost souboru (MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "Automatický start torrentového systému"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "ruÄnÄ"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "Pozastavit všechny torrenty"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "upload (KB/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "stahovánà (KB/s)"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "ÄÃsla"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "maximálnà rychlost uploadu v KB/sec"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "maximálnà rychlost stahovánà v KB/sec"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "port je použit pro pÅipojenà torrentů"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "maximálnà poÄet soubÄžných pÅipojenÃ"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+#, fuzzy
+msgid "Torrent system failure"
+msgstr "Automatický start torrentového systému"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Serverové heslo"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr ""
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr ""
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Globálnà pÅÃkazy:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr ""
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr ""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr ""
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr ""
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "PÅedmÄt \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Online hranà bude zakázáno."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "Neznámá zpravá ze serveru"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Äas spojenà vyprÅ¡el"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d uživatelé)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Serverová zpráva"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "Aktuálnà bitva byla uzavÅena hostem."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "UzavÅená bitva"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Chyba v nastavenà Springu"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Nastal problém pÅi ovÄÅovánà poslednà verze.\n"
+"ProsÃm zopakujte pozdÄji.\n"
+"Pokud problém pÅetrvává, použijte NápovÄda->Nahlásit Bug, aby jste na chybu "
+"upozornili."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Vaše verze: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Poslednà verze: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"VaÅ¡e SpringLobby verze nenà aktuálnÃ.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Nenà aktuálnÃ"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Nenà aktuálnÃ"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+#, fuzzy
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Nastal problém pÅi ovÄÅovánà poslednà verze.\n"
+"ProsÃm zopakujte pozdÄji.\n"
+"Pokud problém pÅetrvává, použijte NápovÄda->Nahlásit Bug, aby jste na chybu "
+"upozornili."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, fuzzy, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"Nastal problém pÅi ovÄÅovánà poslednà verze.\n"
+"ProsÃm zopakujte pozdÄji.\n"
+"Pokud problém pÅetrvává, použijte NápovÄda->Nahlásit Bug, aby jste na chybu "
+"upozornili."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Žádný"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "ZvýraznÄnÃ"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "PÅidat se ke stejné bitvÄ"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Vždy"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "PÅezdÃvka"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "NováÄek"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "ZaÄáteÄnÃk"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "PrůmÄrný"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "NadprůmÄrný"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "Zkušený"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "NejzkuÅ¡enÄjÅ¡Ã"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Veterán"
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "neznámý"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "PÅidat poÄÃtaÄ..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Odstranit Uživatelský ÃÄet"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Rakousko"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Vaše verze springu"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "Stáhnout"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "UveÅejnit nový soubor"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Zrušit"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "Rozlišenà obrazovky"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Pozorovatelé:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "HráÄi:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Tým"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Spojenec"
+
+#~ msgid "cpu"
+#~ msgstr "procesor"
+
+#~ msgid "Test firewall"
+#~ msgstr "Test firewallu"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat zavÅen."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Nastavenà Mapy"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "Nastavit ve hÅe"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Stahovánà selhalo"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Odpojit"
+
+#~ msgid "Debug"
+#~ msgstr "LadÄnÃ"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "HráÄ:"
+
+#~ msgid "status"
+#~ msgstr "stav"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Zvolte složku"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Akce"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "p"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "Hodnota mimo meze\n"
+#~ " Vložte celé ÄÃslo mezi 0 & 100."
+
+#~ msgid ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+#~ msgstr ""
+#~ "Dva nebo vÃce poÄÃtaÄů se nacházà v jednom týmu, protože poÄÃtaÄ nevÃm "
+#~ "jak sdÃlet, toto nebude fungovat."
+
+#~ msgid "Bot team sharing."
+#~ msgstr "SdÃlenà v týmu s poÄÃtaÄem."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "PoÄet hráÄů"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Informace o mÃstnosti"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "PÅedmÄt \""
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#, fuzzy
+#~ msgid ""
+#~ "You need to download the map to be able to watch this replay.\n"
+#~ "\n"
+#~ msgstr ""
+#~ "MusÃte nejprve stáhnout mapu, aby jste mohli hrát tuto hru.\n"
+#~ "\n"
+
+#~ msgid "Missing Functionality"
+#~ msgstr "ChybÄjÃcà závislost"
+
+#~ msgid "Download OTA content?"
+#~ msgstr "Stáhnout obsah OTA?"
+
+#, fuzzy
+#~ msgid "Create a spring directory in my documents folder"
+#~ msgstr "VytvoÅit .spring soubor v domovském adresáÅi (doporuÄeno)"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "Neznámá zpravá ze serveru"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Nenà pÅipojený."
+
+#, fuzzy
+#~ msgid "Only the host can change the game options"
+#~ msgstr "Pouze zakladatel může uzamknout hru."
+
+#~ msgid "Only the host can start the battle."
+#~ msgstr "Pouze zakladatel může zaÄÃt bitvu."
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "Pouze zakladatel může uzamknout hru."
+
+#~ msgid "Only the host can lock the game."
+#~ msgstr "Pouze zakladatel může uzamknout hru."
+
+#, fuzzy
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "Pouze zakladatel může uzamknout hru."
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Neplatné host/port nebo jméno serveru."
+
+#~ msgid "no rank"
+#~ msgstr "bez hodnosti"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "Seznam bitev"
+
+#~ msgid "Only the host can fix player colours."
+#~ msgstr "Pouze zakladatel může pÅidÄlovat barvy hráÄům."
+
+#~ msgid "Select all"
+#~ msgstr "Vybrat vše"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d uživatelé)"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Nebyl vybrán žádný mod."
+
+#, fuzzy
+#~ msgid "you can also enter a ';' seperated list of usernames:"
+#~ msgstr "vložte ; rozdÄlený list"
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Neplatné ÄÃslo"
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "Vyberte mod, který chcete hrát."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "NormálnÃ"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "UnitSync knihovna"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "PokraÄovat, když velitel zemÅe"
+
+#~ msgid "End if commander dies"
+#~ msgstr "SkonÄit, když velitel zemÅe"
+
+#~ msgid "End condition"
+#~ msgstr "PodmÃnka konce"
+
+#~ msgid "Resources"
+#~ msgstr "Suroviny"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Množstvà kovu, se kterým hrÃ¡Ä zaÄÃná."
+
+#~ msgid "Start Energy"
+#~ msgstr "PoÄáteÄnà energie"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Množstvà energie, se kterou hrÃ¡Ä zaÄÃná."
+
+#~ msgid "Max units"
+#~ msgstr "Max jednotek"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "Maximálnà poÄet jednotek na jednoho hráÄe."
+
+#~ msgid "Limit d-gun"
+#~ msgstr "Omezit d-gun"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "VyÄerpávánà ložisek kovu"
+
+#~ msgid "This chat is exclusively for participants of this battle."
+#~ msgstr "Tento chat je pouze pro úÄastnÃky této bitvy."
+
+#~ msgid "Cannot add bot, maximum number of players already reached."
+#~ msgstr "Nemohu pÅidat poÄÃtaÄ, maximálnà poÄet hráÄů byl již dosažen."
+
+#~ msgid "Max players reached"
+#~ msgstr "Maximálnà poÄet hráÄů dosažen"
+
+#~ msgid "Autoconnect last server"
+#~ msgstr "Znovu se pÅipojit k poslednÃmu serveru"
+
+#~ msgid "Save to:"
+#~ msgstr "Uložit do:"
+
+#~ msgid "Browse..."
+#~ msgstr "Procházet..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Zvolte adresáÅ"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "Nastavenà Map/Módů"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "VaÅ¡e SpringLobby verze je aktuálnÃ!\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "AktuálnÃ"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "Chcete zobrazit stránku s instrukcemi, jak stáhnout nejnovÄjÅ¡Ã verzi?"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "Omezit D-Gun"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr ""
+#~ "Zakáže veliteli použÃvat jeho D-Gun, pokud je pÅÃliÅ¡ daleko od startovnà "
+#~ "pozice"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "Nastavuje množstvà kovu, s kterým hrÃ¡Ä zaÄÃná"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "Nastavuje množstvà energie, s kterou hrÃ¡Ä zaÄÃná"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "Nastavuje maximálnà poÄet jednotek, které může hrÃ¡Ä postavit"
+
+#~ msgid "Reset"
+#~ msgstr "Resetovat"
+
+#~ msgid "Spring directory"
+#~ msgstr "adresáŠSpringu"
+
+#~ msgid "Default location."
+#~ msgstr "Standardnà umÃstÄnÃ."
diff --git a/po/da.gmo b/po/da.gmo
new file mode 100644
index 0000000..6ac78c4
Binary files /dev/null and b/po/da.gmo differ
diff --git a/po/da.po b/po/da.po
new file mode 100644
index 0000000..e0050ed
--- /dev/null
+++ b/po/da.po
@@ -0,0 +1,6149 @@
+# Danish translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-08-02 17:25+0000\n"
+"Last-Translator: nanker <Unknown>\n"
+"Language-Team: Danish <da at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr ""
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Alias:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr ""
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr ""
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Værdi"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Fortryd"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr ""
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr ""
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr ""
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Akcepter aftale"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Akcepterer du denne aftales betingelser?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Ja"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Nej"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr ""
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr ""
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Tilfældig"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr ""
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Ingen"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr ""
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Altid"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Antal spillere"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Opret forbindelse"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "OK"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Beskrivelse"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Kort"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr ""
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Vært"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Tilskuere:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Spillere:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Kort"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Download &kort"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr ""
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Tilskuere:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Spillere:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Vært:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Status:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "LÃ¥st"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Adgangsbeskyttet"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Fremhæv"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Beskrivelse:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Startet"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Fuld"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Ã
bn"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Spiller:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Alt"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Kort:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Kun kort jeg har"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Maks.spiller:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr ""
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Tilskuer:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Spillere:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "Fil"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Startet"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "Slagliste"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Vært ny..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "Tilslut"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Du kan ikke være vært for et spil når du er offline. Forbind venligst til en "
+"lobby server."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Ikke online."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Spring fejl"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Er allerede i et slag"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Du deltager allerede i et slag.\n"
+"\n"
+"Vil du forlade det nuværende og starte et nyt?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Fejl ved start af slag."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Fandt ingen kort"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Er allerede i et slag"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Du deltager allerede i et slag.\n"
+"\n"
+"Vil du forlade det nuværende og starte et nyt?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Er allerede i et slag"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Du deltager allerede i et slag.\n"
+"\n"
+"Vil du forlade det nuværende og deltage i dette?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "Ãnsker du at jeg tager dig til download siden?"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr ""
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Kort ikke tilgængeligt"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Adgangskode til slag"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Indtast adgangskode"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Vælg..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Mulighed"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Værdi"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Størrelse"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Vindhastighed"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr ""
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Tyngdekraft"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr ""
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr ""
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Fast"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Vælg i spil"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "Vælg i spil"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Start position"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Enheds begrænsninger"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Tilladte enheder"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Enheder på denne liste vil være tilgængelige i spillet."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Tillad alle enheder."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Tillad alle enheder."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Tillad alle enheder."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Begrænsede enheder"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Enheder på denne liste vil ikke være tilgængelige i spillet."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Enheds begrænsninger"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Kaldenavn"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Hold"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Vælg farve"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Sæt ressourcebonus"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Tilskuer"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Spark"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Ring"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Indtast venligst en værdi mellem 0 og 100"
+
+#: src/battleroomlistctrl.cpp:717
+msgid "AI (bot)\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Oman"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Tilskuer"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Spiller:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Vært"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Klient"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Altid"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Ikke parat"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Sæt adgang..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Indlæs..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Indlæs et gemt sæt af begrænsninger."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Gem..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Gen et sæt af begrænsninger."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Vælg..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Gen et sæt af begrænsninger."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "standard"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+#, fuzzy
+msgid "Mod Options"
+msgstr "Kort indstillinger"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Kort indstillinger"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "Kort ikke tilgængeligt"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "fejl"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Vælg"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "standard"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Jeg er klar"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Farve"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Forlad"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "Forlad slaget og returner til slagsiden"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr ""
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "Tilføj en computer-kontrolleret spiller til spillet"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Opret forbindelse"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Ring"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Ikke parat"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+msgid "Force spectate ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Gem..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "Vælg"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "standard"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "Fortsæt"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "Afslut"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Nogle spillere er endnu ikke klar.\n"
+"Ring til disse?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Ikke parat"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "standard"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "kanal"
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "kanal"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d brugere)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Log advarsel"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Farver og skrifttyper"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Brug systemets farver"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Baggrund"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Handling"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Fremhæv"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Deltag/forlad"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Min meddelelse"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Server"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Klient"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Fejl"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Tidsstempel"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "PÃ¥mindelse"
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Skrifttype:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "standard"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Vælg..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Opførsel"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Chat log"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Gem chat log"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr ""
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "nr."
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d brugere)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Send"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Kopiér"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Ryd"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr ""
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr ""
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Kanal info"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Sæt emne..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Kanal meddelelse..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "LÃ¥s..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "LÃ¥s op"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Tilmeld..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Frameld..."
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Til"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Fra"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "Er på?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Span beskyttelse"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr ""
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Afbryd forbindelse"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Opret forbindelse"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Slet..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Skift adgangskode..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Sæt adgang..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Konti"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr ""
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Admin"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Spark bruger"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Ã
ben chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "Deltag i samme slag"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr ""
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Uden lyd..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Uden lyd i 5 minutter"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Uden lyd i 10 minutter"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Uden lyd i 30 minutter"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Uden lyd i 2 timer"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Uden lyd i 1 dag"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Aktiver lyd"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Uden lyd"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Spark..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr ""
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr ""
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "Slå!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Op"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr ""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "kanal"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "slag"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "server"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr ""
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr ""
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Kanal info"
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr ""
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat lukket."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr ""
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr ""
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Bruger er offline."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr ""
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Hvad skal være det nye emne?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Meddelelse:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "LÃ¥s kanal..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Hvad skal den nye adgangskode være?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "LÃ¥s kanal op"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Er du sikker på at du vil låse denne kanal op?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Fjern brugerkonto"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Hvilken brugerkonto vil du fjerne idag?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Fjern konto"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Er du sikker på at du vil fjerne kontoen "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Ãndre brugerens adgangskode til konto"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Hvilken brugerkonto vil du ændre adgangskode for?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Hvad skal den nye adgangskode være?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Ikke implementeret"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "Slaget er beskyttet af en adgangskode, angiv denne."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr ""
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Spark bruger"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Grund:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Spark bruger"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Varighed:"
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Forbind til lobby server"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Adgangskode"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Logind"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Registrér"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Alias"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Ugyldig port."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Ugyldig port"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Ugyldig vært/port"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Ugyldig vært"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Ugyldigt tal."
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Registrering mislykkedes."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Forenede Arabiske emirater"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afghanistan"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua og Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albanien"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Armenien"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Nederlandske Antiller"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antarktis"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentina"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Amerikansk Samoa"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Ãstrig"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Australien"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azerbajdzjan"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosnien-Hercegovina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladesh"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgien"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgarien"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahrain"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermuda"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunei"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Bolivia"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brasilien"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamas"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhutan"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Bouvetøen"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Hviderusland"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Canada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "Centralafrikanske Republik"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Congo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Schweiz"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Guldkysten"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Cook øerne"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Cameroon"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "Kina"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Colombia"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Cuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Kap Verde"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Juleøen"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Cypern"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "Tjekkiet"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Tyskland"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Djibouti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Danmark"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominica"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Dominikanske Republik"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Algeriet"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ecuador"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estland"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Egypten"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Vest Sahara"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritrea"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Spanien"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Etiopien"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finland"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fiji"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Falklandsøerne"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Mikronesien"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Færøerne"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "Frankrig"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr ""
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Georgien"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Fransk Guyana"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Grønland"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambia"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guinea"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadeloupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Ãkvatorialguinea"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Grækenland"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guinea-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guyana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Heard og McDonald øerne"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Kroatien"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Ungarn"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonesien"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irland"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israel"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "Indien"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Det britiske territorium i Indiske Ocean"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Irak"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Iran"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Island"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Italien"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamaica"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Jordan"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japan"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Kenya"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "Kirgisistan"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Kambodia"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Comoros"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "Sankt Kitts og Nevis"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Nordkorea"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Sydkorea"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuwait"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Cayman øerne"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kazakhstan"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Libanon"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Sankt Lucia"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Liberia"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Litauen"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Luxembourg"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Letland"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Libyen"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Marokko"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldova"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Montenegro"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagaskar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Marshall øerne"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Makedonien"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Myanmar"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongoliet"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macau"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Nordmaria øerne"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinique"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauretanien"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Mauritius"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Maldiverne"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Mexico"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malaysia"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mocambique"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "Namibia"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Ny Caledonien"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Niger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Norfolk øen"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigeria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nicaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Nederlandene (\"Holland\")"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norge"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Neutral zone (Saudiarabien/Irak)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "New Zeeland"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Oman"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panama"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Peru"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Fransk Polynesien"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua New Guinea"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Filippinerne"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pakistan"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Polen"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "Saint-Pierre og Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Pitcairn"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Puerto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugal"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palau"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Qatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Reunion"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Rumænien"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Serbien"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Russiske føderation"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Rwanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Saudiarabien"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Salomon øerne"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychellerne"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Sudan"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Sverige"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapore"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "St. Helena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slovenien"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Svalbard og Jan Mayen øerne"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Slovakiet"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Leone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somalia"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Surinam"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "São Tomé og PrÃncipe"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "Sovjetunionen (tidligere)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "El Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Syrien"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Swaziland"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Turks- og Caicos øerne"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Tchad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Sydlige Franske Territorier"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Thailand"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tadzjikistan"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Tokelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistan"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunesien"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Ãst-Timor"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Tyrkiet"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad og Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Taiwan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tanzania"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ukraine"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "England"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "USA"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Uzbekistan"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Vatikanstaten"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "De britisk vestindiske ører"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Vestindiske øer (USA)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vietnam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Svalbard og Jan Mayen øerne"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Yemen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Jugoslavien"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Sydafrika"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Zambia"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zaire"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Hele landenavnet ikke fundet)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "System informationer"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Spil"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Download"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Slet..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Slet..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+msgid "Add New.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Handling"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Ã
ben chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "Vær vært for nyt slag"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Fremhæv"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+msgid "Add.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Fjern brugerkonto"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Brugernavn"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Vælg"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Vælg i spil"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "Sæt adgang..."
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "standard"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Kanal info"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Vær vært for nyt slag"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "En kort beskrivelse af slaget, som vil blive vist på slaglisten."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Beskrivelse"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr ""
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Port"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "Kort ikke tilgængeligt"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Antal spillere"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "Det maksimale antal spillere tilladt i slaget."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr ""
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Start som vært for slaget."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Webbrowser"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Gennemse"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "Opret forbindelse"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "Forbind til lobby server"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "Værk&tøjer"
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Start metal"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Ukendt svar fra server"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "Slagliste"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Valgmuligheder"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Enheds begrænsninger"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Senegal"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Gendan"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "Anvend"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Spil"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Download"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Forbind..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&Afbryd forbindelse"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Gem indstillinger"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Afslut"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Kanal info"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Ã
ben prival &chat..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr ""
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "Tjek for nye versioner"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "Spring opsætning"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&Om"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Kanal info"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr ""
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Dokumentation"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&Fil"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "Værk&tøjer"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Hjælp"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Opret forbindelse"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Ã
ben privat chat..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Brugernavn"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Fandt ingen kort"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Hvilken brugerkonto vil du fjerne idag?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Gem..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "Altid"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Download"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Genopfrisk"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Download"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr ""
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+#, fuzzy
+msgid "Show"
+msgstr "Vis alt"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "Fil"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Grafiske deltaljer"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Start position"
+
+#: src/mapselectdialog.cpp:265
+msgid "Minimum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Tilskuer"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Start position"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Vælg i spil"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Vælg i spil"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Begrænsede enheder"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Gem indstillinger"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr ""
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "c"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr ""
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+#, fuzzy
+msgid "Filter settings"
+msgstr "Gem indstillinger"
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Varighed:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Vælg"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Tilstand"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Panama"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Varighed:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Spring fejl"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "Fil"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "Fil"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Indlæs..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Altid"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Gem..."
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Ugyldig port"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Vælg"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Bruger er offline."
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Bruger er offline."
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr "Vær vært for nyt slag"
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " fordi: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Server meddelelse"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "Du blev sparket ud af slaget!"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "Sparket ud af vært"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "Slagliste"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Download &kort"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "PÃ¥mindelse"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Ugyldigt tal."
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Ikke et tal"
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Startet"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Opret forbindelse"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "Ukendt svar fra server"
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Download"
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Grafiske deltaljer"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Grafiske deltaljer"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "hvis du har to skærme kan du bruge begge"
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Slag lukket"
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "Skygger (langsom)"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "Vælg"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "standard"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "brug færre fraver"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr "gør forskel i højde klarere"
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "Vis spilleur"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+#, fuzzy
+msgid "Show in-game player information"
+msgstr "Vis spilleur"
+
+#: src/settings++/Defs.hpp:319
+#, fuzzy
+msgid "Show in-game framerate"
+msgstr "Vis spilleur"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+#, fuzzy
+msgid "Total war camera"
+msgstr "Total krig"
+
+#: src/settings++/Defs.hpp:338
+#, fuzzy
+msgid "First person camera"
+msgstr "Første person"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "Grundlæggende"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Vælg"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "Dynamisk"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr "Total krig"
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "Første person"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "skærm bredde"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "skærm højde"
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Vælg"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Vælg"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Vælg"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Varighed:"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Fra"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Lyd"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "Fejl!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "Gem Spring opsætning før det forlades?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "Bekræftelse nødvendig"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "Gem indstillinger"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "Afslut"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "Simpel (få muligheder)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "Ekspert (alle muligheder)"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "Om"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Kontakt"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "Rapportér en Fejl (Bug)"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Tilstand"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Info/hjælp"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Tip"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "SpringLobby teamet"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Kritisk fejl"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "Brug denne sti"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "Sti opsætning"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "lav"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "middel"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "høj"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "meget lav"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "meget høj"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "Spring opsætningsfejl"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Lydindstillinger"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Skærmopløsning"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Vand kvalitet"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "Grafisk kvalitet"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Grafiske deltaljer"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Skærmopløsning"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "Skift til ekspert tilstand"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (denne)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Info"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "Zoom"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr ""
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Tilskuer"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Start position"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "- Vælg en -"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Du skal vælge et kort først"
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Hej "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+",\n"
+"Det ser ud som om det er første gang du bruger SpringLobby. Jeg har gættet "
+"på en opsætning, som jeg tror vil virke for dig, men du bør tjekke den, "
+"særligt Spring opsætningen. \n"
+"Når du er færdig kan du gå til filmenuen, tilslutte dig til en server og "
+"nyde et godt spil Spring :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Welcome"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Ingen"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "Sti opsætning"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Ã
ben chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "Slagliste"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Søg"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Placering"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Søg"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Konfigurer automatisk"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Bibliotek"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Tidsudløb på forbindelsen"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Ukendt svar fra server"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "Download"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Status:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Adgangskode til server"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Registrering lykkedes,\n"
+"du skulle nu kunne logge ind."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Registrering lykkedes"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr ""
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr ""
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr ""
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr ""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr ""
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr ""
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Ingen emner skrevet endnu."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Emnet \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+"\" blev ikke fundet. Skriv \"/hjælp emner\" kun for tilgængelige emner."
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "Ukendt svar fra server"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Tidsudløb på forbindelsen"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d brugere)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Server meddelelse"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "Det aktuelle slag blev lukket af værten."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "Slag lukket"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Spring opsætningsfejl"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Din version: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Sidste version: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"Din SpringLobby version er ikke opdateret!\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Ikke opdateret"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Ikke opdateret"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Ingen"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Fremhæv"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "Deltag i samme slag"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Altid"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Kaldenavn"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr ""
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr ""
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr ""
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr ""
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr ""
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr ""
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr ""
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+msgid "Add to group..."
+msgstr ""
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Fjern brugerkonto"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Ãstrig"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Din Spring version"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "Download"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Fortryd"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "Skærmopløsning"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Tilskuere:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "Spillere:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Hold"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Italien"
+
+#~ msgid "cpu"
+#~ msgstr "cpu"
+
+#~ msgid "Test firewall"
+#~ msgstr "Test firewall"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat lukket."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Kort indstillinger"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "Vælg i spil"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Download"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Afbryd forbindelse"
+
+#~ msgid "Debug"
+#~ msgstr "Fejlfinding"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Spiller:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Vælg farve"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Handling"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "Værdi udenfor interval.\n"
+#~ " Indtast en værdi mellem 0 og 100."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "Antal spillere"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Kanal info"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Emnet \""
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Unit detail"
+#~ msgstr "Detaljer om enheder"
+
+#~ msgid "Missing Functionality"
+#~ msgstr "Manglende funktionalitet"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "Ukendt svar fra server"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Ikke online."
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Ugyldig vært/port eller servernavn."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "Aktive chat kanaler:"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "Slagliste"
+
+#~ msgid "Select all"
+#~ msgstr "Vælg alle"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d brugere)"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Fjern brugerkonto"
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Ugyldigt tal."
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "En kort beskrivelse af slaget, som vil blive vist på slaglisten."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normal"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "Kritisk fejl"
+
+#~ msgid "&Edit"
+#~ msgstr "&Redigér"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "Fortsæt hvis kommandør dør"
+
+#~ msgid "End if commander dies"
+#~ msgstr "Slut hvis kommandør dør"
+
+#~ msgid "End condition"
+#~ msgstr "Slut betingelser"
+
+#~ msgid "Resources"
+#~ msgstr "Ressourcer"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Mængden af metal til hver spiller ved start."
+
+#~ msgid "Start Energy"
+#~ msgstr "Start energi"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Mængden af energi hos hver spiller ved start."
+
+#~ msgid "Max units"
+#~ msgstr "Maks enheder"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "Det maksimale antal enheder tilladt pr. spiller."
+
+#~ msgid "Save to:"
+#~ msgstr "Gem til:"
+
+#~ msgid "Browse..."
+#~ msgstr "Gennemse..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Vælg et katalog"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Din SpringLobby version er opdateret!\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "Opdateret"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "Slutbetingelser for spil"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "Maks antal tilladte enheder"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "Sæt det maksimale antal enheder en spiller må bygge"
+
+#~ msgid "Reset"
+#~ msgstr "Nulstil"
+
+#~ msgid "Spring directory"
+#~ msgstr "Spring katalog"
diff --git a/po/de.gmo b/po/de.gmo
new file mode 100644
index 0000000..902f88a
Binary files /dev/null and b/po/de.gmo differ
diff --git a/po/de.po b/po/de.po
new file mode 100644
index 0000000..494ad5c
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,6594 @@
+# German translations for SpringLobby package
+# German messages for SpringLobby.
+# Copyright (C) 2008 The SpringLobby team
+# This file is distributed under the same license as the SpringLobby package.
+# root <marenz at supradigital.org>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: SpringLobby 0.0.1.10128\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-08-26 18:16+0000\n"
+"Last-Translator: derDaimon <Unknown>\n"
+"Language-Team: German\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Bot hinzufügen"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Spitzname:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "KI:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Wähle die KI Programmbibliothek für diesen Bot"
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr "Eigenschaft"
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Wert"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Abbrechen"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Bot hinzufügen"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Keine KI Bots gefunden"
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Keine Bot-Libs gefunden"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Akzeptiere Lizenzbestimmungen"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Lizenzbestimmungen akzeptieren?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Ja"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Nein"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "Teams automatisch aufteilen"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "Methode"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "Ränge gleich verteilen"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Zufällig"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Clans"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Keine"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Gerecht"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Immer"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Anzahl der Spieler"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Neu Verbinden"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Beschreibung"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Karte"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Modifikation"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Host"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Zuschauer:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Spieler:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Karte"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Karte &herunterladen"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "M&odifikation herunterladen"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Zuschauer:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Aktive Spieler:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Host:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Status:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Gesperrt"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "kennwortgeschützt"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Nur Hervorgehobene"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Rang Limit"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Beschreibung:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Gestartet"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Voll"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Öffnen"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Spieler:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Alle"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Karte:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Nur bereits heruntergeladene Karten"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Max. Spieler:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Nur bereits heruntergeladene Mods"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Zuschauer:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Spieler:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "Datei"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Gestartet"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "Schlachten Liste"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Host eröffnen"
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "Teilnehmen"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Du kannst kein Spiel eröffnen, solange du nicht mit einem Lobby-Server "
+"verbunden bist"
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Offline"
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+"Da deine Version des Spiels inkomatibel ist, kannst du kein Spiel eröffnen"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Spring Fehler"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Ein Spring Prozess läuft bereits.Schliesse diesen erst bevor du ein neues "
+"Spiel aufmachst"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Spiel läuft bereits"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Du bist bereits in einem Spiel\n"
+"\n"
+"Möchtest du das aktuelle Spiel verlassen um ein neues zu starten?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+"Die Schlacht wurde nicht gestartet, weil der gewählte Mod nicht gefunden "
+"wurde. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Fehler beim Starten des Spiels"
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Es wurden keine Karten in ihrer Spring Installation gefunden. Die kann "
+"passieren, wenn ihre Spring einstellungen falsch gesetzt wurden."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Keine Karten gefunden"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"Aufgrund inkompatibler Spring Versionen kannst du keinen Schlachten "
+"beitreten."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Spiel läuft bereits"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Du bist bereits in einem Spiel\n"
+"\n"
+"Möchtest du das aktuelle Spiel verlassen um ein neues zu starten?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Spiel läuft bereits"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Du bist bereits in einer Schlacht.\n"
+"\n"
+"Möchtest du die aktive verlassen und dieser beitreten?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Du hast bereits eine Instanz von Spring offen. Schliesse diese zuerst, um "
+"einer anderen Schlacht beizutreten."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Mod nicht verfügbar"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Karte nicht verfügbar"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Passwort der Schlacht"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Passwort eingeben"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Auswählen..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Option"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Wert"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Größe"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Windgeschwindigkeit"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Gezeitenstärke"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Schwerkraft"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Extraktorradius"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Max Metall"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Fixiert"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Im Spiel wählbar"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "Im Spiel wählbar"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Startpositionen"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Einheitenbeschränkungen"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Erlaubte Einheiten"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Einheiten in dieser Liste werden im Spiel verfügbar sein."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Erlaube alle Einheiten"
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Erlaube alle Einheiten"
+
+#: src/battleoptionstab.cpp:83
+#, fuzzy
+msgid "<<"
+msgstr "<"
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Erlaube alle Einheiten"
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Verbotene Einheiten"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Einheiten in dieser Liste werden im Spiel nicht verfügbar sein."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Einheitenbeschränkungen"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Spitzname"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Team"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Bündnis"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Rohstoff-Bonus"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Seite"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Farbe setzen"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Rohstoff-Bonus setzen"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Zuschauer"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Rauswerfen"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Klingeln"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Bitte einen Wert zwischen 0 und 100 eingeben"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Bot hinzufügen"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Oman"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Zuschauer"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Spieler:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Host"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Client"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Aufzeichnungen der Spiele"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Nicht Bereit"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "Aktiviere V-Sync"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr "Namen eingeben"
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Setzte Zugriff..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Laden..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Lade eine gespeicherte Zusammenstellung von Beschränkungen."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Speichern..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Speichere eine Zusammenstellung von Beschränkungen"
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Auswählen..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Speichere eine Zusammenstellung von Beschränkungen"
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "Standart"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Mod Optionen"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Karten Optionen"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "Mod nicht verfügbar"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "Fehler"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Auswählen"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "Standart"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+"Spieler mit der gleichen Team-Nummer teilen die Kontrolle über ihre "
+"Einheiten."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+"Suche dir eine Farbe aus um deine Einheiten im Spiel identifizieren zu können"
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "Wähle deine Fraktion"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "Beobachte das Spiel anstatt aktiv daran teil zu nehmen."
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Bereit"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "Klicke hier wenn du zufireden bist mit den Einstellungen"
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Farbe"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"Eine Vorschau der Map. Du kannst die Startpositionen oder die Startboxen "
+"sehen."
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Verlassen"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "Verlasse das Spiel und gehe zurück zur Spiele-Liste."
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "Starte die Schlacht"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr "Spielerverwaltung"
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Bot hinzufügen..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "Füge einen Computer-Spieler zum Spiel hinzu."
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr "Automatisches Sperren beim Start"
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "Verhindert dass weitere Spieler dem Spiel beitreten"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Neu Verbinden"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "Aktiviere V-Sync"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Klingeln"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Nicht Bereit"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "Start erzwingen?"
+
+#: src/battleroomtab.cpp:239
+#, fuzzy
+msgid "Balance alliances"
+msgstr "Nur der Host kann die Allianzen aufteilen."
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "Farben korrigieren"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "Gib jedem Spieler eine andere Farbe"
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr "Teams ausbalancieren"
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Speichern..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "Auswählen"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "Standart"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "Boxen"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "Weiter"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "Ende"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "Die Map ist nicht verfügbar."
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Nicht alle Spieler sind bereit.\n"
+"Betreffende anklingeln?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Nicht Bereit"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "Ping Timeout!"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "Automatisch diesen Channel betreten"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "Channel beitreten..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "Name des Channels dem beigetreten wird"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "Raum"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d Benutzer)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Sitzung geschlossen um ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Konnte Ordner nicht erstellen. \n"
+"Überprüfe ob die Zugriffsrechte korrekt sind (Schreibschutz?)\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "Starte SpringLobby neu um die Log Funktion zu aktivieren."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Log Warnung"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"Konnte Nachricht nicht in den Log schreiben.\n"
+"Loggen wird deaktiviert für den Raum "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"Betrete den Raum neu um Loggen zu reaktivieren"
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr "Konnte Log Datei nicht öffnen.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Schrift und Farben"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Benutze Systemfarben"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Hintergrund"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Aktion"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Hervorheben"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Betreten/Verlassen"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Meine Nachrichten"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Server"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Client"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Fehler"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Zeitstempel"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Benachrichtigung"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Verbunden zum TAS Server.\n"
+"[22:30] <Dude> moin allerseits\n"
+"[22:30] ** Dude2 hat den Raum betreten.\n"
+"[22:30] * Dude2 findet seine Farben schön\n"
+"[22:45] <Dude> Dude2: achja?\n"
+"[22:46] <Dude2> Naja, könnte besser sein.. werd noch ein wenig dran "
+"arbeiten...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Schrift:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "Standart"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Auswählen..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Verhalten"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Chat Logs"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Speichere Chat Logs"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Hervorzuhebende Wörter"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Wörter die im Chat hervorgehoben werden sollen:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "gib eine Liste mit ; als Trennzeichen ein"
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr "zusätzlich Ton abspielen/ Titelzeile blinken "
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d Benutzer)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "Rechtsklick für Optionen (wie Autojoin)"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Senden"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Kopieren"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Reset"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "Automatisch diesen Channel betreten"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "Zeige Betreten/Verlassen Meldungen"
+
+#: src/chatpanel.cpp:433
+#, fuzzy
+msgid "Show mute list"
+msgstr "Zeige Tooltips"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Raum Info"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Setze Thema..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Raum Nachricht..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Sperren..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Entsperren"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Registrieren..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Entregistrieren"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "An"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Aus"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "Ist an?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Spamschutz"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Trennen"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Neu Verbinden"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Entfernen..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Passwort ändern..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Setzte Zugriff..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Konten"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "Broadcast..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Admin"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Benutzer muten"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Öffne Chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "Betrete gleiche Schlacht"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Spielinterne Zeit"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "IP Adressen und Smurfs anzeigen"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Muten..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Für 5 Minuten muten"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Für 10 Minuten muten"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Für 30 Minuten muten"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Für 2 Stunden muten"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Für einen Tag muten"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Entmuten"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Mute"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Kicken..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Bannen..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Entbannen..."
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "Slap!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "OP"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "EntOPen"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Befehl: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" Parameter: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "Raum"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "Kampf"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "Server"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " hat die "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " verliess die "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Raum Info"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * Gesetzt von "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat geschlossen"
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Bist du sicher das du %d Zeilen einfügen willst?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Flutwarnung"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Du hast SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Du bist nicht im Kanal oder der Kanal existiert nicht"
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" Fehler: Der Befehl (%s) existiert nicht, benutze '/help' um alle "
+"verfügbaren Befehle zu sehen."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Benutzer ist offline"
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Gesendet: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ChanServ Fehler"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ ist nicht in diesem Raum."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Wie soll das neue Thema lauten?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Nachricht:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "Raum sperren..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Wie soll das neue Passwort sein?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "Raum entsprerren"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Bist du sicher, dass du diesen Raum entsperren willst?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ existiert nicht auf diesem Server."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Raum registrieren"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Wer soll der eingetragene Besitzer für diesen Raum sein?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "Raum deregistrieren"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "Bist du dir sicher, dass du diesen Raum deregistrieren willst?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Benutzer entfernen"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Welchen Benutzer willst du entfernen?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Benutzer entfernen"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Bist du dir sicher, dass du diesen Benutzer entfernen willst? "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Ändere Benutzerpasswort"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Wessen Benutzerpasswort willst du ändern?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Wie soll das neue Passwort lauten?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Nicht Implementiert"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "Broadcast Nachricht"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "Nachricht die gebroadcasted werden soll:"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "Du hast nicht den benötigten Mod "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . Bitte downloade ihn zuerst"
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "Diese Schlacht ist mit passwortgeschützt. Gib das Passwort ein."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Benutzer muten"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Für wieviele Minuten soll der Benutzer gemutet werden?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Benutzer rauswerfen"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Grund:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Benutzer kicken"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "Benutzer stummschalten"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Dauer:"
+
+#: src/chatpanel.cpp:1797
+#, fuzzy
+msgid "couldn't add user"
+msgstr "Der Browser konnte nicht geladen werden."
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Verbinde zu Lobbyserver"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Server zu dem verbunden wird. Du kannst zu jedem beliebigen Server "
+"verbinden, indem du das serveradresse:port Format benutzt."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Kennwort"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "Kennwort merken"
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "Beim nächsten Start automatisch verbinden"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"Merke die Verbindungsdaten und verbinde beim nächsten Start der Lobby "
+"automatisch."
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"Hinweis: Falls du keinen Benutzernamen hast,\n"
+" kannst du einen kostenlos unter der \"Registrieren\"\n"
+" Registerkarte registrieren."
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Anmelden"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Registrieren"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Nick"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Ungültiger Port."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Ungültiger Port"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Portnummer ausserhalb des gültigen Wertebreichs.\n"
+"\n"
+"Sie muss eine ganze Zahl zwischen 1 und 65536 sein"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Ungültiger Host/Port."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Ungültiger Host"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Ungültige Zahl"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"Registrierung fehlgeschlagen. Grund:\n"
+"Passwort und Bestätigung stimmen nicht überein"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Registrierung fehlgeschlagen."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Vereinigte Arabische Emirate"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afghanistan"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua und Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albanien"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Armenien"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Niederländische Antillen"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antarktis"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentinien"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Amerikanisch-Samoa"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Österreich"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Australien"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Aserbaidschan"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosnien und Herzegowina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladesch"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgien"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgarien"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahrain"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermuda"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunei Darussalam"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Bolivien"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brasilien"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamas"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhutan"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Bouvetinsel"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botsuana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Weißrussland"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Kanada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "Kokosinseln"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "Zentralafrikanische Republik"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Kongo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Schweiz"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Elfenbeinküste"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Cookinseln"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Kamerun"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "China"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Kolumbien"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Kuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Kap Verde"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Weihnachtsinsel (Australien)"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Republik Zypern"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "Tschechien"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Deutschland"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Dschibuti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Dänemark"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominica"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Dominikanische Republik"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Algerien"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ecuador"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estland"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Ägypten"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Westsahara"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritrea"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Spanien"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Äthiopien"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finnland"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fidschi"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Falklandinseln (Malvinas)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Mikronesien"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Färöer Inseln"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "Frankreich"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "Frankreich, Metropolitan"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Georgien"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Französisch-Guinea"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Grönland"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambia"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guinea"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Gouadeloupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Äquatorial-Guinea"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Griechenland"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "S. Georgia und S. Sandwich Inslen"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guinea-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guyana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong-Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Heard- und McDonald-Inseln"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Kroatien"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Ungarn"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonesien"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irland"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israel"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "Indien"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Britisches Territorium im Indischen Ozean"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Irak"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Iran"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Island"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Italien"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamaika"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Jordanien"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japan"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Kenia"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "Kyrgyzstan"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Kambodscha"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Komoren"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "St. Kitts und Nevis"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Nordkorea"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Südkorea"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuwait"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Cayman Inseln"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kasachstan"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Libanon"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "St. Lucia"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Liberia"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Litauen"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Luxemburg"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Litauen"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Libyen"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Marokko"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldawien"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Montenegro"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagaskar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Marshall Inseln"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Mazedonien"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Myanmar"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongolei"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macao"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Nördliche Mariana-Inseln"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinique"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauretanien"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Mauritius"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Malediven"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Mexiko"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malaysia"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mosambik"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "Namibia"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Neu Kaledonien"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Niger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Norfolkinsel"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigeria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nikaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Holland"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norwegen"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauruanisch"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Neutrale Zone (Saudi Arabien/Irak)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "Neuseeland"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Oman"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panama"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Peru"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Französisch Polinesien"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua-Neuguinea"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Philippinen"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pakistan"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Polen"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "St. Pierre und Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Pitcairninsel"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Puerto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugal"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palau"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Quatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Réunion"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Rumänien"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Serbien"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Russische Föderation"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Ruanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Saudi-Arabien"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Salomoninseln"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychellen"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Sudan"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Schweden"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapur"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "St. Helena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slowenien"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Svalbard- und Jan Mayen-Inseln"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Leone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somalia"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Surinam"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "Sao Tomé und Príncipe"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "Soejetunion (UdSSR)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "El Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Syrien"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Swaziland"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Turks- und Caicosinseln"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Tschad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Südliche Französische Territorien"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Thailand"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tadschikistan"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr ""
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistan"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunesien"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Ost-Timor"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Türkei"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad und Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Taiwan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tansania"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ukraine"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "Vereinigtes Königreich (Großbritannien)"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "Kleinere, auswärtige US-Inseln"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "Vereinigte Staaten"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Usbekistan"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Vatikan"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "Saint Vincent und die Grenadines Inseln"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Jungfraueninseln (GB)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Jungfraueninseln (US)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vietnam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Wallis- und Futuna-Inseln"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Jemen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Jugoslawien"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Südafrika"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Sambia"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zaire"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Simbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Vollen Ländernamen nicht gefunden)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "System Informationen"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "Ausführliche Anwendungs Log"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Zuletzt erstelltes Spring Startskript"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Spiel"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+#, fuzzy
+msgid "Search and download files"
+msgstr "Suche eine Datei"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Kein Mod ausgewählt."
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+#, fuzzy
+msgid "unknown hash "
+msgstr "Unbekannt"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Entfernen..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr "Entferne eine existierende Gruppe"
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Entfernen..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr "Benenne eine existierende Gruppe um"
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "Bot hinzufügen..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr "Füge eine neue Gruppe hinzu"
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Aktion"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr "Melde An-/Abmeldungen"
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr "Melde, wenn Benutzer dieser Gruppe on-/offline gehen"
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Öffne Chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+"Ignoriere alles, was im Kanal von irgendeinem Benutzer dieser Gruppe gesagt "
+"wird"
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "Neue Schlacht eröffnen"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr "Melde, wenn Benutzer dieser Grupper Schlachten eröffnen"
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr "Ignoriere Privatnachrichten (PM)"
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+"Ignoriere alles, was im privaten Dialog von irgendeinem Benutzer dieser "
+"Gruppe gesagt wird"
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr "Melde Statusveränderungen"
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr "Melde, wenn sich der Status eines Benutzers dieser Gruppe ändert"
+
+#: src/groupoptionspanel.cpp:119
+#, fuzzy
+msgid "Autokick"
+msgstr "/kick"
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+"Werfe jeden Benutzer dieser Gruppe automatisch raus, wenn er deiner "
+"eröffneten Schlacht beitritt"
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr "Hebe Schlachten und Namen von Benutzern dieser Gruppe hervor"
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Hervorzuhebende Wörter"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr "Wähle Farbe zum Hervorheben"
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr "Benutzer in dieser Gruppe"
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "Bot hinzufügen..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr "Füge Benutzer zur Gruppe hinzu"
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Benutzer entfernen"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Name des Benutzers"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Auswählen"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Im Spiel wählbar"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"Erfolgreich gespeichert in:\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "Setzte Zugriff..."
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "Der Browser konnte nicht geladen werden."
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "Standart"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Raum Info"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Neue Schlacht eröffnen"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+"Eine kurze Beschreibung des Spiels, welche in der Liste der Schlachten "
+"auftauchen wird."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Beschreibung"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Wähle den Mod aus mit dem du spielen willst."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+"Welches Passwort benötigt wird um der Schlacht beizutreten. Leerlassen für "
+"kein Passwort"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Port"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "UDP Port auf dem das Spiel laufen wird. Standart ist 8452."
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "Mod nicht verfügbar"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Anzahl der Spieler"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "Maximale Anzahl an Spielern die in dieser Schlacht erlaubt sind."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "Hole Punching"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "NAT traversal"
+
+#: src/hostbattledialog.cpp:177
+#, fuzzy
+msgid "NAT traversal to use."
+msgstr "NAT traversal"
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Mindestrang benötigt"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Starte Host für eine Schlacht."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "Sie müssen erst einen Mod auswählen."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Kein Mod ausgewählt."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"Erfolgreich gespeichert in:\n"
+
+#: src/httpdownloader.cpp:78
+#, fuzzy
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"Erfolgreich gespeichert in:\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"nach:\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Web Browser"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Standard Brwoser"
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Angeben:"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Durchsuchen"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "Neu Verbinden"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "Verbinde zu Lobbyserver"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "&Werkzeuge"
+
+#: src/lobbyoptionstab.cpp:121
+#, fuzzy
+msgid "Show Tooltips?"
+msgstr "Zeige Tooltips"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+#, fuzzy
+msgid "Match exact"
+msgstr "Exakte Übereinstimmung"
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr "Dichteste Übereinstimmung"
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Start Metall"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "Einen Browser (ausführbare Datei) auswählen."
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "Einen Browser (ausführbare Datei) auswählen."
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Unbekannte Antwort vom Server"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "Schlachtenliste"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "Schlachtraum"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Optionen"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Einheitenbeschränkungen"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "P2P"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Senegal"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr "Gruppen"
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Wiederherstellen"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "Übernehmen"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Spiel"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr "Aktive Übertragungen: "
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "Gesamt ausgehend: "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "Gesamt eingehend: "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "Unbekannt"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "Breche Download ab"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "Veröffentliche neue Datei:"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "Suche eine Datei"
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "LuaUi Widgets einschalten"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "nicht verfügbar"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "sende"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr "sauge"
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr "in Warteschlange"
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "Status: nicht verbunden"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "Status: verbunden"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr "Status: gebremst oder angehalten (im Spiel)"
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "Status: unbekannt"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "Gesamt ausgehend: %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "Gesamt eingehend: %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Verbinden..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&Trennen"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "UI Optionen"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Beenden"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "&Channel beitreten..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Rauminfo"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Öffne privaten &Chat..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&Maps/Mods neu laden"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "Auf neue Version prüfen"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "Spring Einstellungen"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&Über uns"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Raum Info"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&Bug melden"
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Dokumentation"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&Datei"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Werkzeuge"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Hilfe"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Status: verbunden"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "Channel beitreten..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Name des Channels dem beigetreten wird"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Öffne privaten Chat"
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Name des Benutzers"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+"Die SpringLobby ist ein Cross-Plattform Lobby-Client für die RTS-Spring "
+"Spiele-Engine"
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Keine Karten gefunden"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "Torrentsystem manuell %starten"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "Torrentsystem manuell %stoppen"
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr "Neustart erforderlich"
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr "Andordnungsverwalter"
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr "Gibt ein Profilname an"
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr "Welches Profil soll geladen werden?"
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Welchen Benutzer willst du entfernen?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr "Mehrspieler"
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr "Einzelspieler"
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Speichern..."
+
+#: src/mainwindow.h:184
+msgid "Replays"
+msgstr "Aufzeichnungen der Spiele"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Herunterladen"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr "Metall: %.1f%%"
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Aktualisieren"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Herunterladen"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "Seite:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "Bündnis: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "Bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+#, fuzzy
+msgid "Show"
+msgstr "Alle anzeigen"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "Datei"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Max Metall"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Startpositionen"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Mindestrang benötigt"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "Durchschnittlich"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Zuschauer"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Startpositionen"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Typ der Startposition"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Wie Spieler auf der Karte platziert werden\n"
+"0: feste Position\n"
+"1: zufällige Position\n"
+"2: Position nach Spielstart auswählen\n"
+"3: In der Lobby vor dem Spielstart auswählen"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Im Spiel wählbar"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Im Spiel wählbar"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Verbotene Einheiten"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr "Kartenname"
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "UI Optionen"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "l"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Ausführbare Dateien (*.exe)|*.exe|Alle Dateien (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Alle Dateien (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+#, fuzzy
+msgid "Filter settings"
+msgstr "Speichere Einstellungen"
+
+#: src/playback/playbackfilter.cpp:164
+#, fuzzy
+msgid "Filesize in KB:"
+msgstr "Dateigrösse (MB)"
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Dauer:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Auswählen"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Modus"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Kartenname"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Dauer:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Spring Fehler"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "Dateigrösse (MB)"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "Dateigrösse (MB)"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "Datei"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Laden..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Aufzeichnungen der Spiele"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Speichern..."
+
+#: src/playback/playbacktab.cpp:286
+#, fuzzy
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"Konnte deine Spring version nicht per unitsync ermitteln. \n"
+" \n"
+" Online spielen wird deaktiviert."
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Ungültiger Port"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Wähle Benutzer"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Benutzer ist offline"
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() fehlgeschlagen ! (Ausnahme)"
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Benutzer ist offline"
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " hat die "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "Betreten des Channels fehlgeschlagen"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Konnte dem Channel nicht beitreten "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " weil: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Server Nachricht"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " hat die ip=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " unterstützt kein NAT-Translation"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "SIe wurden aus der Schlacht gekickt!"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "Vom Host rausgeworfen"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "Schlachten Liste"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr "%d Minuten ausstehend"
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Download komplett"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Benachrichtigung"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Ungültige Zahl"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Das ist doch keine Zahl.."
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "Die Map ist nicht verfügbar."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Gestartet"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Neu Verbinden"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "Unbekannt"
+
+#: src/serverevents.cpp:1009
+#, fuzzy
+msgid "Download complete, location is: "
+msgstr "Download komplett"
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Download komplett"
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "Konnte den Browser nicht laden. Die URL ist: "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "Der Browser konnte nicht geladen werden."
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr "Mausrad geschwindigkeit"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+"Höhere Werte meinen schnelleren Zoom mit dem Mausrad.\n"
+"Negative Werte invertieren die Zoom richtung.\n"
+"Ergebnisse hängen von dem Kamera Modus ab!"
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr "Shadow-map grösse"
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"höherer Wert = schönere Schatten\n"
+"mögliche Werte: 1024, 2048, 4096, 8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr "Baum anzeige Entfernung"
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr "setzt die maximale Distanz bis zu der Bäume noch gezeichnet werden"
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr "Oberflächen Detail"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr "höherer Wert = höher detailierte Oberfläsche"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "Unit LOD distance"
+msgstr "Entfernung Einheitenicons"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr "höherer Wert = höher detailierte Einheiten"
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr "Gras Detail"
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "higher value = more detailed grass"
+msgstr "höherer Wert = höher detailiertes Gras"
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr "Boden-Details"
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr "Entfernung Einheitenicons"
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+"bestimmt bis zu welcher Entfernung Einheiten vollständig gerendert werden\n"
+"höherer Wert = grössere Entfernung = mehr Einheiten müssen zur selben Zeit "
+"gerendert werden"
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr "Max Anzahl gleichzeitiger Partikel"
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "beschränkt wieviele Partikel gleichzeitig gerendert werden"
+
+#: src/settings++/Defs.hpp:233
+#, fuzzy
+msgid "Max nano simultaneous particles"
+msgstr "Max Anzahl gleichzeitiger Partikel"
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr "Vollbildmodus"
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr "Vollbild- oder Fesntermodus"
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "Dual-Monitor modus"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "wenn du zwei Monitore hast kannst du beide benutzen"
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "Aktiviere V-Sync"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr "V-Sync an/aus"
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr "16-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr "Platzhalter"
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr "24-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:257
+#, fuzzy
+msgid "Full-scene anti-aliasing samples"
+msgstr "Wie viel Anti-Aliasing angewendet werden soll"
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr "Wie viel Anti-Aliasing angewendet werden soll"
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr "Maximum an gleichzeitigen Klängen"
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+"Maximum an verschiedenen Klängen die gleichzeitigen gespielt werden\n"
+"Setze sie dies auf 0 um Klang komplett zu deaktivieren."
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "Master sound volume"
+msgstr "Insgesamte Lautstärke"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "master sound volume"
+msgstr "Insgesamte Lautstärke"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "General sound volume"
+msgstr "Insgesamte Lautstärke"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "general volume relative to master volume"
+msgstr "Lautstärke der Einheiten im vergleich zur globalen Lautstärke"
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr "Lautstärke der Einheiten"
+
+#: src/settings++/Defs.hpp:273
+#, fuzzy
+msgid "reply volume relative to master volume"
+msgstr "Lautstärke der Einheiten im vergleich zur globalen Lautstärke"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Schlachtraum"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "battle volume relative to global volume"
+msgstr "Lautstärke der Einheiten im vergleich zur globalen Lautstärke"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "User interface volume"
+msgstr "Lautstärke der Einheiten"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "ui volume relative to global volume"
+msgstr "Lautstärke der Einheiten im vergleich zur globalen Lautstärke"
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "Schatten (langsam)"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr "Schatten aktivieren?"
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr "3D Bäume"
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+"Wollen sie schönere Bäume?\n"
+"Geforce 2/Radeon 8500/Intel 830 oder Grafikkarten neuerer Generation benötigt"
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr "Hochauflösende Wolken"
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"Wollen sie einen schöneren Himmel?\n"
+"Geforce 2/Radeon 8500/Intel 830 oder Grafikkarten neuerer Generation benötigt"
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr "Dynamische Wolken (langsam)"
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr "Wollen sie sich bewegende Wolken im Himmel?"
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr "Reflektierende Einheiten"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"Wollen sie glänzende Einheiten?\n"
+"Geforce 5/Radeon 9500/Intel 915 oder Grafikkarten neuerer Generation "
+"benörtigt"
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr "Niemals Shader beim Rendern von SM3 Karten verwenden"
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr "Probleme mit SM3 Karten? Aktivieren Sie dies"
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr "Aktiviere LuaShaders Unterstützung"
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr "Hochauflösende LOS (Line of Sight) Texturen"
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr "Weichere LOS (Line of Sight) Einblendungen"
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr "Punkte weichzeichnen"
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr "Anti-Aliasing für Punkte?"
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr "Linien weichzeichnen"
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr "Sollen Linien weichgezeichnet werden?"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr "Befehle über die Minikarte erlauben"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr "GIb Kommandos auf der Minimap "
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "Befehle auf Minimap zeigen"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr "Standardwert ist \"an\""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr "Symbole auf Minimap zeichnen"
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr "Markierungen auf Minimap zeichnen"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "links ist der Standard"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr "Einfache Minimap Farben"
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "weniger Farben verwenden"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr "Nanospray in Teamfarbe"
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr "Nanopartikel werden mit Teamfarbe eingefärbt"
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr "Farbige Höhen-Anzeigen"
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr "macht Höhenunterschieder klarer"
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "Zeige Ingame-Uhr"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+"Benötigt 'LuaWidgets' um aktiviert zu werden.\n"
+"Wird in der rechten unteren Ecke angezeigt werden."
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr "Zeige in-game Spieler Informationen"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr "Zeige in-game FPS"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr "Grafikfehler bei Alt-Tab beheben"
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr "Nicht ändern, wenn es nicht benötigt ist"
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+"Econonmy AI, etc abschalten\n"
+"falls aktiviert kann LuaUI Fehlermeldungen produzieren"
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr "Scrollen am Fensterrand"
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr "Scrollen wenn Maus den Fensterrand erreicht"
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr "Maustasten umkehren"
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "Invertiert die Y-Achse der Maus im FPS-Modus"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "Scrollgeschwindigkeit (Maus+tastatur) setzen"
+
+#: src/settings++/Defs.hpp:336
+#, fuzzy
+msgid "Rotatable overhead camera"
+msgstr "Drehbar Von-oben"
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr "FPS Kamera"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+#, fuzzy
+msgid "Free camera"
+msgstr "FPS Kamera"
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr "Menge an Konsolenausgabe (0=min,10=max)"
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr "Wie viele Informationen sollen ausgegeben werden?"
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr "KI Ausnahmen abfangen"
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr "deaktiviert Fehlerdiagnose für KI"
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr "Spiegelnd"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "Reflektierend und lichtbrechend"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "Dynamisch"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr "Invertiere Y-Achse der Maus"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr "hoch/runter mit runter/hoch tauschen"
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr "3-Tasten-Maus-Unterstützung für die Minimap"
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr "Drehbar Von-oben"
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr "Draufsicht"
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "First Person"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr "Kamera aus Sicht einer Einheit"
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "Bildschirmbreite"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "Bildschirmhöhe"
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Spiegelnd"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Shore waves"
+msgstr "Schatten aktivieren?"
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Enables shorewaves"
+msgstr "Schatten aktivieren?"
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Spiegelnd"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Spiegelnd"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Dauer:"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Aus"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "Kombinierte Optionen"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "Renderer Qualität / Video-Optionen"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "Render-Details"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "UI Optionen"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Audio"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+"Änderungen im Expertenmodus werden verworfen\n"
+"sobald Du Änderungen im simplen Modus machst.\n"
+"Die Optionen dort orientieren sich NICHT an den\n"
+"Einstellungen im Expertenmodus.\n"
+"(Du kannst diese Nachricht im \"Datei\" Menü ausschalten)"
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "Fehler!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "Speichere Einstellungen vor dem Speichern?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "Bestätigung benötigt"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "Spring Einstellungen (Experten-Modus)"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "Spring Einstellungen (Einfacher Modus)"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "Speichere Einstellungen"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "Resette die Einstellungen auf die Standard-Optionen"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "Deaktiviere Experten-Modus Warnung"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "Beenden"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "Einfach (wenig Optionen)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "Experte (alle optionen)"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "Über"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Kontakt"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "Mitwirkende"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "Einen Fehler melden"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Modus"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Information / Hilfe"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "Setze ALLE Optionen zurück?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Tipp"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+"SpringSettings ist eine Graphische Oberfläche für die Einstellungen der "
+"Spring-Engine"
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "Das SpringLobby Team"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Kritischer Fehler"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "Pfad zur Unitsync-Library"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "Benutze diesen Pfad"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "unitsync.so unter linux, unitsync.dll unter windows"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "Pfad-Einstellungen"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "Wähle eine unitsync-Library"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "Niedrig"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "Mittel"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "Hoch"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "Sehr niedirg"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "Sehr hoch"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "Der Standard-Browser kann nicht gestartet werden"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "Konnte den Browser nicht laden. Die URL ist: "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "Der Browser konnte nicht geladen werden."
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "Es konnte nicht auf die Einstellungen zugegriffen werden\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "Konnte nicht speichern, unitsync wurde nicht korrekt geladen"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "SpringSettings Fehler"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Audio-Einstellungen"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Bildschirmauflösung"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+"Wenn eine option spezielle hardware braucht um zu funkionieren\n"
+"wird sie im Tooltip aufgeführt sein."
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Wasserqualität"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "Auflösung in Bit"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "Renderer Qualitätseinstellungen"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "Video-Modus Optionen"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "Anti-Aliasing Optionen"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "Renderer-Detail Level"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "Grafik-Qualität"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Grafik-Details"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Bildschirmauflösung"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "Wechsle zum Experten-Modus"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (aktuell)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+"Setze alle Qualitäts-Einstellungen auf die Vordefinierten Werte nach deiner "
+"Auswahl"
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+"Setze alle Detail-Einstellungen auf die Vordefinierten Werte nach deiner "
+"Auswahl"
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Info"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "Scroll-Geschwindigkeiten (Maus+Tastatur)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "Standard Kamera-Modus"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "Verschiedene UI-Optionen"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "Zoom"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "Bot hinzufügen..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Zuschauer"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Startpositionen"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- Wähle einen aus --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Sie müssen zuerst eine Karte auswählen"
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "Kein Bot hinzugefügt"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+"Sie können kein Spring starten, während ein anderer Spring Prozess schon "
+"läuft."
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Hi "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Willkommen"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Keine"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "Pfad-Einstellungen"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Öffne Chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "/kick"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Finde"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Ort"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Finde"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "UnitSync Bibliothek"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Automatisch konfigurieren"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "Die Spring Anwendung auswählen"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Bibliothek"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr "Mache nichts (Nur benutzen, wenn sie wirklich wissen was sie machen)"
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+"Beim erstellen eines Ordners trat ein Fehler auf\n"
+"Bitte erstellen sie Manuell folgenden Ordner:"
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Verbindung wegen Zeitüberschreitung geschlossen"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Unbekannte Antwort vom Server"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "MB hochgeladen"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "MB hochgeladen"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Status:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr "% complete"
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s up"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s down"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "ETA (s)"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "Dateigrösse (MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "Pausiere alle Torrents"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "Upload (KB/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "Maximale Upload Geschwindigkeit in KB/sek(-1 für unendlich)"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "Maximale Download Geschwindigkeit in KB/sek(-1 für unendlich)"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Server Passwort"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Registrierung war erfolgreich,\n"
+"du solltest dich jetzt einloggen können."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Registrierung erfolgreich"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "Registrierung fehlgeschlafen. Grund:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"Browser Pfad ist: "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "Hilfe Fehler"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "Tippe /help in einem Chatraum."
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "SpringLobby Kommando Hilfe."
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Globale Kommandos:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - Setzt deine Status auf abwesend."
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - Setzt deinen Abwesenheits Status zurück."
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+" \"/changepassword altespasswort neuespasswort\" - Ändert das Passwort des "
+"momentan aktiven Accounts."
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - Zeigt momentan aktive Chaträume an."
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr " \"/help [topic]\" - Zeigt Informationen zum Thema \"topic\" an.."
+
+#: src/ui.cpp:495
+#, fuzzy
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+" \"/join channel [password] [,channel2 [password2]]\" - Einem Chatraum "
+"beitreten."
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Alias für /join."
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+" \"/ingame\" - Zeigt an wieviel zeit du schon im Spiel verbracht hast."
+
+#: src/ui.cpp:498
+#, fuzzy
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+" \"/msg benurtzername [text]\" - sendet eine private Nachricht mit text als "
+"Inhalt an benutzername."
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - Zeigt momentan aktive Chaträume an."
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - Alias für /join."
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename newalias\" - Ändert deinen Benutzernamen zu newalias."
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " \"/sayver\" - Meldet deine SpringLobby Version im Chatraum."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+" \"/testmd5 text\" - Gibt einen md5-b64 Hash des gegeben Textes zurück."
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - Zeigt dir deine Springlobby Version an."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Chat Kommandos:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me action\" - Gibt Aktionsnachricht im IRC Stil aus.."
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+"Wenn du irgendein Kommando vermisst, versuche es in #springlobby "
+"einzutippen :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Keine Themen bisher."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Das Thema \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr "\" nicht gefunden. Tippe \"/help topics\" nur für vorhandene Themen."
+
+#: src/ui.cpp:609
+#, fuzzy
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Konnte deine Spring version nicht per unitsync ermitteln. \n"
+" \n"
+" Online spielen wird deaktiviert."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Online spielen wird deaktiviert."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "Unbekannte Antwort vom Server"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Verbindung wegen Zeitüberschreitung geschlossen"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d Benutzer)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Server Nachricht"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "Die aktuelle Schlacht wurde vom Host geschlossen."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "Schlacht geschlossen"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Deine Spring Einstellungen sind wahrscheinlich nicht korrekt,\n"
+" du solltest sie nochmal überprüfen,\n"
+" bevor du versuchst online zu spielen."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Spring settings Fehler"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Ihre Version: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Neuste Version: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"Ihre SpringLobby Version ist nicht auf dem neusten Stand.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Nicht auf dem neusten Stand"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Nicht auf dem neusten Stand"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Keine"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Hervorheben"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "autokick"
+msgstr "/kick"
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "Betrete gleiche Schlacht"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Norwegen"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Spitzname"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "Neuling"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "Anfänger"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "Durchschnittlich"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Überduchschnittlich"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "Erfahren"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "Sehr erfahren"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Veteran"
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "Unbekannt"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "Bot hinzufügen..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Benutzer entfernen"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Österreich"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Deine Spring Version"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "MB hochgeladen"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "Veröffentliche neue Datei:"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Abbrechen"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "Bildschirmauflösung"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Zuschauer:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "Spieler:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Team"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Bündnis"
+
+#~ msgid "cpu"
+#~ msgstr "CPU"
+
+#~ msgid "Test firewall"
+#~ msgstr "Port testen"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat geschlossen"
+
+#, fuzzy
+#~ msgid "Game is in progress."
+#~ msgstr "Aktive Übertragungen: "
+
+#, fuzzy
+#~ msgid "Game is in progress and full."
+#~ msgstr "Aktive Übertragungen: "
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Karten Optionen"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "Im Spiel wählbar"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Kein Mod ausgewählt."
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Trennen"
+
+#~ msgid "Debug"
+#~ msgstr "Fehlerdiagnose"
+
+#~ msgid "Debug Options"
+#~ msgstr "Debug Optionen"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Spieler:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Farbe setzen"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Aktion"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "p"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr "Wert muss zwischen 0 und 100 liegen!"
+
+#~ msgid "Bot team sharing."
+#~ msgstr "Bots teilen Spieler ."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "Anzahl der Spieler"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Raum Info"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Das Thema \""
+
+#~ msgid "Use smart scrolling"
+#~ msgstr "Benutze weichen Bildlauf"
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Download failed"
+#~ msgstr "Download fehlgeschlagen"
+
+#~ msgid "Unit detail"
+#~ msgstr "Einheiten Detail"
+
+#~ msgid "only on/off available at this time"
+#~ msgstr "nur an/aus möglich im Moment"
+
+#~ msgid "Global sound volume"
+#~ msgstr "Globale Lautstärke"
+
+#~ msgid "mark to be able to use"
+#~ msgstr "anklicken um LuaUi Wigets verfügbar zu machen"
+
+#~ msgid "Send debug info to console"
+#~ msgstr "Gibt Fehlerdiagnose auf der Konsole aus"
+
+#~ msgid "if disabled these will only be logged"
+#~ msgstr "wenn ausgeschaltet, wird es nur geloggt"
+
+#~ msgid "Missing Functionality"
+#~ msgstr "Fehlende Funktionen"
+
+#~ msgid "Download OTA content?"
+#~ msgstr "OTA-content herunterladen?"
+
+#, fuzzy
+#~ msgid "Do nothing"
+#~ msgstr "Hole Punching"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "Unbekannte Antwort vom Server"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Offline"
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "Diese Schlacht benutzt NAT-Traversal, dies ist mit einer wx 2.6 Version "
+#~ "von SpringLobby nicht möglich.\n"
+#~ " \n"
+#~ " Du kannst dieser Schlacht nihct beitreten.\n"
+#~ " Update auf wx 2.8 oder neuer um NAT support zu ermöglichen."
+
+#, fuzzy
+#~ msgid "Only the host can change the game options"
+#~ msgstr "Nur der Host kann das Spiel für neue Mitspieler sperren"
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "Nur der Host kann das Spiel für neue Mitspieler sperren"
+
+#~ msgid "Only the host can lock the game."
+#~ msgstr "Nur der Host kann das Spiel für neue Mitspieler sperren"
+
+#, fuzzy
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "Nur der Host kann das Spiel für neue Mitspieler sperren"
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Ungültiger host/port oder Servername."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "Aktive Chaträume:"
+
+#~ msgid "no rank"
+#~ msgstr "kein rang"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "Schlachten Liste"
+
+#~ msgid "Only the host can fix player colours."
+#~ msgstr "Nur der Host kann die Spieler-Farben verteilen"
+
+#~ msgid "Select all"
+#~ msgstr "Alles auswählen"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d Benutzer)"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Kein Mod ausgewählt."
+
+#, fuzzy
+#~ msgid "you can also enter a ';' seperated list of usernames:"
+#~ msgstr "gib eine Liste mit ; als Trennzeichen ein"
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Ungültige Zahl"
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr ""
+#~ "Eine kurze Beschreibung des Spiels, welche in der Liste der Schlachten "
+#~ "auftauchen wird."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "Wähle den Mod aus mit dem du spielen willst."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normal"
+
+#~ msgid "NAT traversal to use. Experimental support."
+#~ msgstr "NAT Translation. Experimentelle unterstützung."
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "Unitsync Problem"
+
+#~ msgid "You have one or more bots sharing team, this is not possible."
+#~ msgstr "Du hast mehr als einen Bot in einem Team, das ist nicht möglich"
+
+#~ msgid ""
+#~ "Please enter password needed to join this channel, leave blank for no "
+#~ "passwrd."
+#~ msgstr ""
+#~ "Passwort für diese Schlacht eingeben, leer lassen für kein Passwort."
+
+#~ msgid "Fixed source ports"
+#~ msgstr "Feste Ursprungsports"
+
+#~ msgid "&Edit"
+#~ msgstr "&Bearbeiten"
+
+#~ msgid "LuaAI"
+#~ msgstr "LuaAI"
+
+#~ msgid "Bot%d"
+#~ msgstr "Bot%d"
+
+#~ msgid "%Y-%m-%d %H:%M"
+#~ msgstr "%d.%m.%Y %H:%M"
+
+#~ msgid "["
+#~ msgstr "["
+
+#~ msgid "%H:%M"
+#~ msgstr "%H:%M"
+
+#~ msgid "?"
+#~ msgstr "?"
+
+#~ msgid "="
+#~ msgstr "="
+
+#~ msgid ">"
+#~ msgstr ">"
+
+#~ msgid ""
+#~ "Couldn't find any maps in you spring installation. This could happen when "
+#~ "you set the Spring settings incorrectly."
+#~ msgstr ""
+#~ "Keine Karten in deiner Spring Installation gefunden. Dies kann passieren, "
+#~ "wenn die Spring Einstellungen falsch gesetzt wurden."
+
+#~ msgid "The maximun number of units allowed per player."
+#~ msgstr "Die Anzahl von Einheiten die jeder Spieler maximal haben kann."
+
+#~ msgid "You have one or more bots shring team, this is not possible."
+#~ msgstr ""
+#~ "Zwei oder mehr Bots teilen sich einen Spieler. Dies ist nicht möglich."
+
+#~ msgid ""
+#~ " \n"
+#~ " \n"
+#~ " \n"
+#~ msgstr ""
+#~ " \n"
+#~ " \n"
+#~ " \n"
+
+#~ msgid " "
+#~ msgstr " "
+
+#~ msgid "\n"
+#~ msgstr "\n"
+
+#~ msgid "_BATTLE_"
+#~ msgstr "_BATTLE_"
+
+#~ msgid "IP and Smurfs"
+#~ msgstr "IP und Fake-Accounts"
+
+#~ msgid "/ban"
+#~ msgstr "/ban"
+
+#~ msgid ""
+#~ "You should add a bot before starting a game.\n"
+#~ "If you don't want an opponent add TestGlobalAi"
+#~ msgstr ""
+#~ "Sie sollten dem Spiel einen Bot hinzufügen bevor sie das Spiel starten.\n"
+#~ "Wenn sie keinen Gegner wollen, fügen sie TestGlobalAi hinzu."
+
+#~ msgid "Stop system"
+#~ msgstr "System stoppen"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "Nicht Verloren trotz Commanderverlust"
+
+#~ msgid "End if commander dies"
+#~ msgstr "Verloren wenn der Commander stirbt"
+
+#~ msgid "End condition"
+#~ msgstr "Siegesbedingungen"
+
+#~ msgid "Resources"
+#~ msgstr "Ressourcen"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Die Menge an Metall mit der jeder Spieler startet"
+
+#~ msgid "Start Energy"
+#~ msgstr "Start Energie"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Die Menge der Energy mit der jeder Spieler startet"
+
+#~ msgid "Max units"
+#~ msgstr "Max Einheiten"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "Maximal erlaubte Einheitenanzahl pro Spieler"
+
+#~ msgid "Limit d-gun"
+#~ msgstr "Limitiere D-Gun"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "Einmal gesichtete Gebäude bleiben sichtbar"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "Abnehmende Metal Maker"
+
+#~ msgid "This chat is exclusively for participants of this battle."
+#~ msgstr "Dieser Chat ist nur für Teilnehmer dieses Spiels."
+
+#~ msgid "Max players reached"
+#~ msgstr "Die Maximale Spieleranzahl ist erreicht."
+
+#~ msgid "Save to:"
+#~ msgstr "Speichern unter:"
+
+#~ msgid "Browse..."
+#~ msgstr "Durchsuchen..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Verzeichnis wählen"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "Map/Mod Optionen"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Ihre SpringLobby Version ist auf dem neusten Stand!\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "Auf dem neusten Stand"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "Wollen sie eine Internetseite mit Anweisungen wie man die neuste Version "
+#~ "herunterläd besuchen?"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "D-Gun begrenzen"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr ""
+#~ "Deaktiviert die D-Gun des Commander, wenn er zu weit von seinem "
+#~ "Startpunkt entfernt ist."
+
+#~ msgid "Ghosted Buildings"
+#~ msgstr "Schatten Gebäude"
+
+#~ msgid ""
+#~ "Enemy buildings will leave a ghost image on the map after losing LoS on "
+#~ "them"
+#~ msgstr ""
+#~ "Feindliche Gebäude lassen einen transparenten Umriss auf der Karte nach "
+#~ "dem sie aus dem eigenen Sichtfeld sind"
+
+#~ msgid ""
+#~ "Efficiency of MetalMakers will progressively reduce as much as you build "
+#~ "them"
+#~ msgstr "Effizienz von MetalMakern nimmt ab je mehr du baust"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "Spiel Endbedinung"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "Setzt die Menge Metall mit der der Spieler starten wird"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "Setzt die Menge Energie mit der der Spieler starten wird"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "Max erlaubte Einheiten"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "Setzte die maximale Anzahl an Einheiten die ein Spieler bauen darf"
+
+#~ msgid "Reset"
+#~ msgstr "zurücksetzen"
+
+#~ msgid "Spring directory"
+#~ msgstr "Spring Verzeichnis"
+
+#~ msgid "Default location."
+#~ msgstr "Standard Ort."
+
+#~ msgid ""
+#~ "Unitsync loading was aborted because your spring data directory is not "
+#~ "writable. Please check."
+#~ msgstr ""
+#~ "Das laden von Unitsync wurde abgebrochen weil dein Spring "
+#~ "Datenverzeichnis nicht beschreibbar ist. Bitte überprüfe das."
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "wird nicht unterstützt vom Lobbyserver; Vorraussetzung ist Version"
+
+#~ msgid ""
+#~ "This is the SpringLobby channel, please report any problems you are "
+#~ "having with SpringLobby here and the friendly developers will help you."
+#~ msgstr ""
+#~ "Dies ist der SpringLobby Chatraum, bitte melde Probleme mit SpringLobby "
+#~ "hier und einer der freundlichen Entwickler wird dir helfen."
diff --git a/po/el.gmo b/po/el.gmo
new file mode 100644
index 0000000..03b6a3d
Binary files /dev/null and b/po/el.gmo differ
diff --git a/po/el.po b/po/el.po
new file mode 100644
index 0000000..249a3f2
--- /dev/null
+++ b/po/el.po
@@ -0,0 +1,6759 @@
+# Greek translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# Antonis Kanouras <antonis at metadosis.gr>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-08-31 17:39+0000\n"
+"Last-Translator: Antonis Kanouras <antonis at metadosis.gr>\n"
+"Language-Team: Greek <el at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+"X-Poedit-Language: Greek\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Î ÏοÏθήκη bot"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "ΨεÏ
δÏνÏ
μο:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "ΤÏÏÎ¿Ï bot:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "ÎÏιλÎξÏε Ïον ÏÏÏο ÏοÏ
bot."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Τιμή"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "ÎκÏÏÏÏη"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Î ÏοÏθήκη Bot"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Îεν βÏÎθηκαν bot ÏÏην εγκαÏάÏÏαÏη ÏαÏ."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Îεν βÏÎθηκαν bot"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "ÎÏοδοÏή ΣÏ
μÏÏνίαÏ"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "ÎÏοδÎÏεÏÏε ÏοÏ
Ï ÏÏοÏ
Ï Î±Ï
ÏÎ®Ï ÏÎ·Ï ÏÏ
μÏÏνίαÏ;"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Îαι"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "ÎÏι"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "ÎξιÏοÏÏÏÏηÏη ÏαικÏÏν Ïε ομάδεÏ"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "ÎÎθοδοÏ"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "ÎμοιÏμοÏÏο μοίÏαÏμα βαθμÏν"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "ΤÏ
Ïαίο"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "ÎμάδεÏ"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "ÎαθÏλοÏ
"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "ÎÎÏÏια"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "ΠάνÏα"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"ΤοÏοθÎÏηÏη μελÏν ÏÎ·Ï Î¯Î´Î¹Î±Ï Î¿Î¼Î¬Î´Î±Ï (ÏαίκÏÎµÏ ÏοÏ
ÎÏοÏ
ν Ïο ίδιο Ïag ομάδαÏ, "
+"ÏÏÏÏ '[smurfzor]Alice' και '[smurfzor]Bob') ÏÏην ίδια ÏÏ
μμαÏία.\n"
+"ÎαθÏλοÏ
: ÏίÏοÏα ιδιαίÏεÏο για ÏÎ¹Ï Î¿Î¼Î¬Î´ÎµÏ.\n"
+"ÎÎÏÏια: ÏοÏοθÎÏηÏη μελÏν ÏÎ·Ï Î¯Î´Î¹Î±Ï Î¿Î¼Î¬Î´Î±Ï ÏÏην ίδια ÏÏ
μμαÏία, εκÏÏÏ ÎºÎ¹ αν "
+"αÏ
ÏÏ Ïην κάνει άδικη.\n"
+"ΠάνÏα: ÏοÏοθÎÏηÏη μελÏν ÏÎ·Ï Î¯Î´Î¹Î±Ï Î¿Î¼Î¬Î´Î±Ï ÏÏην ίδια ÏÏ
μμαÏία, ακÏμα κι αν "
+"αÏ
ÏÏ Ïην κάνει άδικη."
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "ÎÏιθμÏÏ ÏαικÏÏν"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "ÎÏαναÏÏνδεÏη"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "ÎνÏάξει"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "ΠεÏιγÏαÏή"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "ΧάÏÏηÏ"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "ÎικοδεÏÏÏÏηÏ"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "ÎεαÏÎÏ:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "ΠαίκÏεÏ:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "ΧάÏÏηÏ"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "ÎαÏÎβαÏμα ÏάÏÏη"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "ÎαÏÎβαÏμα mod"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "ÎεαÏÎÏ:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "ΠαίκÏεÏ:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "ÎικοδεÏÏÏÏηÏ:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "ÎαÏάÏÏαÏη:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "ÎλειδÏμÎνο"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Îε κÏδικÏ"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "ÎÏιÏήμανÏη"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "ÎÏιο βαθμοÏ:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "ΠεÏιγÏαÏή:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "ÎεκίνηÏε"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "ΠλήÏηÏ"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "ÎνοιÏÏÏ"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "ΠαίκÏεÏ:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Îλα"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "ΧάÏÏηÏ:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "ÎÏνο ÏάÏÏÎµÏ ÏοÏ
ÎÏÏ"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Îεγ. ΠαίκÏεÏ:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "ÎÏνο mod ÏοÏ
ÎÏÏ"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " ÎεαÏÎÏ:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "ΠαίκÏεÏ:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "ÎÏÏείο"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "ÎεκίνηÏε"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "ÎίÏÏα μαÏÏν"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Φιλοξενία νÎοÏ
..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "ΣÏ
μμεÏοÏή"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Îεν μÏοÏείÏε να ÏιλοξενήÏεÏε ÏαιÏνίδι εκÏÏÏ ÏÏνδεÏηÏ. ΠαÏÎ±ÎºÎ±Î»Ï ÏÏ
νδεθείÏε "
+"ÏÏο lobby."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "ÎκÏÏÏ Î£ÏνδεÏηÏ."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "Î Ïιλοξενία ÎÏει αÏενεÏγοÏοιηθεί λÏÎ³Ï Î±ÏÏ
μβαÏÏÏηÏÎ±Ï ÎκδοÏηÏ"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Î ÏÏβλημα ÏοÏ
Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Το Spring ÏÏÎÏει ήδη, ÏαÏÎ±ÎºÎ±Î»Ï ÎºÎ»ÎµÎ¯ÏÏε Ïο για να ÏιλοξενήÏεÏε νÎο ÏαιÏνίδι"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Îδη Ïε μάÏη"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr "ÎίÏÏε ήδη Ïε μάÏη."
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"ΧÏηÏιμοÏοιείÏε wxWidgets ÏαλαιÏÏεÏα αÏÏ Ïην ÎκδοÏη 2.8.\n"
+" Î ÎλεγÏÎ¿Ï ÏείÏοÏ
Ï ÏÏοÏÏαÏÎ¯Î±Ï Î´ÎµÎ½ Ï
ÏοÏÏηÏίζεÏαι.\n"
+" Î Ïιλοξενία ÏαιÏνιδιÏν μÏοÏεί να μην δοÏ
λεÏει."
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"ΠεξÏ
ÏηÏεÏηÏÎ®Ï ÏοÏ
ÏÏηÏιμοÏοιείÏαι για να ελεγÏθεί η θÏÏα %d δεν είναι "
+"ÏÏοÏÏελάÏιμοÏ.\n"
+"Î Ïιλοξενία ÏαιÏνιδιÏν μÏοÏεί να μην δοÏ
λεÏει με αÏ
Ïή Ïην ÏÏθμιÏη."
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"ΠμάÏη δεν ξεκίνηÏε εÏειδή η εÏιλεγμÎνη θÏÏα (%d) δεν λαμβάνει ειÏεÏÏÏμενα "
+"ÏακÎÏα.\n"
+" ΠαÏÎ±ÎºÎ±Î»Ï ÎµÎ»ÎγξÏε ÏÎ¹Ï ÏÏ
θμίÏÎµÎ¹Ï Î´Î¹Î±Î½ÎµÎ¼Î·Ïή και ÏείÏοÏ
Ï ÏÏοÏÏαÏÎ¯Î±Ï Î® αλλάξÏε "
+"θÏÏα ÏÏον διάλογο.\n"
+"\n"
+"Îν αÏοÏÏÏοÏ
ν Ïλα, ενεÏγοÏοιήÏÏε Ïη ÎιάÏÏηÏη NAT ÏÏÎ¹Ï ÏÏ
θμίÏÎµÎ¹Ï ÏιλοξενίαÏ."
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "ΠμάÏη δεν ξεκίνηÏε εÏειδή Ïο mod ÏοÏ
εÏιλÎξαÏε δεν βÏÎθηκε. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Î ÏÏβλημα ÏÏην εκκίνηÏη μάÏηÏ."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Îεν βÏÎθηκαν ÏάÏÏÎµÏ ÏÏην εγκαÏάÏÏαÏή ÏαÏ. ÎÏ
ÏÏ Î¼ÏοÏεί να ÏÏ
μβεί ÏÏαν είναι "
+"Î»Î¬Î¸Î¿Ï Î¿Î¹ ÏÏ
θμίÏÎµÎ¹Ï ÏοÏ
Spring."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Îεν βÏÎθηκαν ÏάÏÏεÏ"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"Î ÏÏ
μμεÏοÏή Ïε μάÏÎµÏ ÎÏει αÏενεÏγοÏοιηθεί εÏειδή ÏÏηÏιμοÏοιείÏε αÏÏμβαÏη "
+"ÎκδοÏη ÏοÏ
Spring."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Îδη Ïε μάÏη"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr "ÎίÏÏε ήδη Ïε μάÏη."
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Îδη Ïε μάÏη"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"ÎίÏÏε ήδη Ïε μάÏη.\n"
+"\n"
+"ÎÎλεÏε να εγκαÏαλείÏεÏε Ïην ÏÏÎÏοÏ
Ïα μάÏη και να ÏÏ
μμεÏάÏÏεÏε ÏÏην νÎα;"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Το Spring ÏÏÎÏει ήδη, ÏαÏÎ±ÎºÎ±Î»Ï ÎºÎ»ÎµÎ¯ÏÏε Ïο για να ÏÏ
μμεÏάÏÏεÏε Ïε άλλη μάÏη."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "ÎÎλεÏε να Î±Î½Î¿Î¯Î¾Ï Ïην Ïελίδα λήÏεÏν;"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+#, fuzzy
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+"ÎÎλεÏε να δοκιμάÏÏ Î½Î± Ïο καÏεβάÏÏ Î³Î¹Î± εÏάÏ;\n"
+"ÎÏοÏείÏε να δείÏε Ïην εξÎλιξη ÏÏην καÏÏÎλα \"ÎιαÏειÏιÏÏÎ®Ï ÎήÏεÏν.\""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+"Î ÏÎÏει να καÏεβάÏεÏε Ïο mod ÏÏιν να ÏÏ
μμεÏάÏÏεÏε Ïε αÏ
ÏÏ Ïο ÏαιÏνίδι.\n"
+"\n"
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Το mod δεν είναι διαθÎÏιμο"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+"Î ÏÎÏει να καÏεβάÏεÏε Ïον ÏάÏÏη ÏÏιν να ÏÏ
μμεÏάÏÏεÏε Ïε αÏ
ÏÏ Ïο ÏαιÏνίδι.\n"
+"\n"
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Î ÏάÏÏÎ·Ï Î´ÎµÎ½ είναι διαθÎÏιμοÏ"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "ÎÏδικÏÏ Î¼Î¬ÏηÏ"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "ÎιÏάγεÏε κÏδικÏ"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "ÎÏιλογή..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "ÎÏιλογή"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Τιμή"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "ÎÎγεθοÏ"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "ΤαÏÏÏηÏα ανÎμοÏ
"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "ÎÏναμη κÏ
μάÏÏν"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "ÎαÏÏÏηÏα"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "ÎκÏίνα εξαγÏγÎÏν"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Îεγ. μÎÏαλλο"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "ΣÏαθεÏÏ"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "ÎÏιλ. ÏÏο ÏαιÏνίδι"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "ÎÏιλ. ÏÏο ÏαιÏνίδι"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "ÎÏÏικÎÏ Î¸ÎÏειÏ"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "ΠεÏιοÏιÏμοί μονάδÏν"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "ÎÏιÏÏεÏÏÎÏ Î¼Î¿Î½Î¬Î´ÎµÏ"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Îι Î¼Î¿Î½Î¬Î´ÎµÏ Î±Ï
ÏÎ®Ï ÏÎ·Ï Î»Î¯ÏÏÎ±Ï Î¸Î± είναι διαθÎÏÎ¹Î¼ÎµÏ ÏÏο ÏαιÏνίδι."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "ÎνεÏγοÏοίηÏη ÏλÏν ÏÏν μονάδÏν."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "ÎνεÏγοÏοίηÏη ÏλÏν ÏÏν μονάδÏν."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "ÎνεÏγοÏοίηÏη ÏλÏν ÏÏν μονάδÏν."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "ΠεÏιοÏιÏμÎÎ½ÎµÏ Î¼Î¿Î½Î¬Î´ÎµÏ"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Îι Î¼Î¿Î½Î¬Î´ÎµÏ Î±Ï
ÏÎ®Ï ÏÎ·Ï Î»Î¯ÏÏÎ±Ï Î´ÎµÎ½ θα είναι διαθÎÏÎ¹Î¼ÎµÏ ÏÏο ÏαιÏνίδι."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "ΠεÏιοÏιÏμοί μονάδÏν"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "ΨεÏ
δÏνÏ
μο"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Îμάδα"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "ΣÏ
μμαÏία"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "ÎÏίδομα Î ÏÏÏν"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "ΠλεÏ
Ïά"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "ÎÏιÏμÏÏ ÏÏÏμαÏοÏ"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "ÎÏιÏμÏÏ ÎÏιδÏμαÏÎ¿Ï Î ÏÏÏν"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "ÎεαÏήÏ"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "ÎÏοÏομÏή"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "ÎλήÏη"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "ΠαÏÎ±ÎºÎ±Î»Ï ÎµÎ¹ÏάγεÏε μια Ïιμή αÏÏ 0 εÏÏ 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Î ÏοÏθήκη bot"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Îμάν"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "ÎεαÏήÏ"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "ΠαίκÏεÏ:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "ÎικοδεÏÏÏÏηÏ"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "ΠελάÏηÏ"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "ΠάνÏα"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Îεν είναι ÎÏοιμο"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "ÎνεÏγοÏοίηÏη κάθεÏοÏ
ÏÏ
γÏÏονιÏμοÏ"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "ÎÏιÏμÏÏ ÏÏÏÏβαÏηÏ..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "ΦÏÏÏÏÏη..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "ΦÏÏÏÏÏη αÏοθηκεÏ
μÎÎ½Î·Ï Î»Î¯ÏÏÎ±Ï ÏεÏιοÏιÏμÏν"
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "ÎÏοθήκεÏ
Ïη..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "ÎÏοθήκεÏ
Ïη λίÏÏÎ±Ï ÏεÏιοÏιÏμÏν."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "ÎÏιλογή..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "ÎÏοθήκεÏ
Ïη λίÏÏÎ±Ï ÏεÏιοÏιÏμÏν."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "ÏÏοεÏιλογή"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "ÎÏιλογÎÏ Mod"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "ÎÏιλογÎÏ Î§Î¬ÏÏη"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "μη διαθÎÏιμο"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "ÏÏάλμα"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Îε ανάκλαÏη"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "ÏÏοεÏιλογή"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+"Îι ÏαίκÏÎµÏ Î¼Îµ Ïον ίδιο αÏÎ¹Î¸Î¼Ï Î¿Î¼Î¬Î´Î±Ï Î¼Î¿Î¹ÏάζονÏαι ÏÏν ÎλεγÏο ÏÏν μονάδÏν ÏοÏ
Ï."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+"Îι ÏαίκÏÎµÏ Î¼Îµ Ïον ίδιο αÏÎ¹Î¸Î¼Ï ÏÏ
μμαÏÎ¯Î±Ï ÏÏ
νεÏγάζονÏαι για να ÏεÏÏÏοÏ
ν Ïη "
+"νίκη."
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "ÎÏιλÎξÏε Îνα ÏÏÏμα για να ξεÏÏÏίζοÏ
ν οι Î¼Î¿Î½Î¬Î´ÎµÏ ÏÎ±Ï ÏÏο ÏαιÏνίδι"
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "ÎÏιλÎξÏε Ïην ÏαÏÏιά ÏαÏ"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "ΠαÏακολοÏ
θήÏÏε Ïη μάÏη ανÏί να ÏÏ
μμεÏάÏÏεÏε"
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Îίμαι ÎÏοιμοÏ"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "ÎÏιλÎξÏε ÎµÎ´Ï Î±Î½ ÏÏ
μÏÏνείÏε με ÏÎ¹Ï ÏÏ
θμίÏÎµÎ¹Ï ÏÎ·Ï Î¼Î¬ÏηÏ."
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "ΧÏÏμα"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"Î ÏοεÏιÏκÏÏηÏη ÏοÏ
εÏιλεγμÎνοÏ
ÏάÏÏη. ÎιακÏίνεÏε ÏÎ¹Ï Î±ÏÏικÎÏ Î¸ÎÏÎµÎ¹Ï Î® (αν "
+"ÎÏοÏ
ν ÏÏ
θμιÏÏεί) ÏÎ¹Ï Î±ÏÏικÎÏ ÏεÏιοÏÎÏ."
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "ÎÏοÏÏÏηÏη"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "ÎÏοÏÏÏηÏη αÏÏ Ïη μάÏη και εÏιÏÏÏοÏή ÏÏη λίÏÏα μαÏÏν"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "ÎναÏξη"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "ÎναÏξη μάÏηÏ"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Î ÏοÏθήκη Bot..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "Î ÏοÏθήκη bot ÏÏο ÏαιÏνίδι"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "ÎÏοÏÏοÏή ÏÏ
μμεÏοÏÎ®Ï ÎµÏιÏλÎον ÏαιÏÏÏν ÏÏη μάÏη"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "ÎÏαναÏÏνδεÏη"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "ÎναÏξη"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+#, fuzzy
+msgid "Lock Balance"
+msgstr "ÎξιÏοÏÏÏÏηÏη"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "ÎνεÏγοÏοίηÏη κάθεÏοÏ
ÏÏ
γÏÏονιÏμοÏ"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "ÎλήÏη"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Îεν είναι ÎÏοιμο"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "ÎναγκαÏÏική εκκίνηÏη;"
+
+#: src/battleroomtab.cpp:239
+#, fuzzy
+msgid "Balance alliances"
+msgstr "ÎÏνο ο οικοδεÏÏÏÏÎ·Ï Î¼ÏοÏεί να εξιÏοÏÏοÏήÏει ÏÎ¹Ï ÏÏ
μμαÏίεÏ."
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr "ÎÏ
ÏÏμαÏη εξιÏοÏÏÏÏηÏη ÏαιÏÏÏν Ïε δÏο ή ÏεÏιÏÏÏÏεÏÎµÏ ÏÏ
μμαÏίεÏ"
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "ÎÏιδιÏÏθÏÏη ÏÏÏμάÏÏν"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "Îάνει Ïα ÏÏÏμαÏα ÏÏν ÏαικÏÏν μοναδικά"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid "Balance teams"
+msgstr "ÎξιÏοÏÏÏÏηÏη"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr "ÎÏ
ÏÏμαÏη εξιÏοÏÏÏÏηÏη ÏαιÏÏÏν Ïε δÏο ή ÏεÏιÏÏÏÏεÏÎµÏ ÏÏ
μμαÏίεÏ"
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "ÎÏοθήκεÏ
Ïη..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "Îε ανάκλαÏη"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "ÏÏοεÏιλογή"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "ΠεÏιοÏÎÏ"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr "ÎÏιλογή"
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "ΣÏ
νÎÏεια"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "ΤÎλοÏ"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr "ÎαÏαγÏγή"
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "Îεν Ï
ÏάÏÏει ο ÏάÏÏηÏ."
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"ÎάÏοιοι ÏαίκÏÎµÏ Î´ÎµÎ½ είναι ÎÏοιμοι.\n"
+"ÎλήÏη αÏ
ÏÏν ÏÏν ÏαιÏÏÏν;"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Îεν είναι ÎÏοιμο"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "Îήξη ÏÏοθεÏÎ¼Î¯Î±Ï Ping!"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "ÎÏ
ÏÏμαÏη είÏÎ¿Î´Î¿Ï Ïε κανάλια..."
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "ÎίÏÎ¿Î´Î¿Ï Ïε κανάλι..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "Îνομα καναλιοÏ"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "κανάλι"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d ÏÏήÏÏεÏ)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### ΠΣÏÎ½Î¿Î´Î¿Ï ÎκλειÏε ÏÏÎ¹Ï ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"ÎδÏναÏη η δημιοÏ
Ïγία ÏακÎλοÏ
. \n"
+"ΠαÏÎ±ÎºÎ±Î»Ï Î²ÎµÎ²Î±Î¹ÏθείÏε ÏÏι δεν Ï
ÏάÏÏει ÏÏοÏÏαÏία εγγÏαÏήÏ.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+"ΠδÏ
ναÏÏÏηÏα καÏαγÏαÏÎ®Ï ÎÏει αÏενεÏγοÏοιηθεί μÎÏÏι να εÏανεκκινήÏεÏε Ïο "
+"SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "ÎαÏαγÏαÏή Î ÏοειδοÏοίηÏηÏ"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"ÎδÏναÏη η καÏαγÏαÏή.\n"
+"ΠκαÏαγÏαÏή θα αÏενεÏγοÏοιηθεί για Ïο δÏμάÏιο "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÎµÏανειÏÎλθεÏε ÏÏο δÏμάÏιο για να ενεÏγοÏοιηθεί η καÏαγÏαÏή."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"ÎδÏναÏο Ïο άνοιγμα ÏοÏ
αÏÏείοÏ
καÏαγÏαÏήÏ. \n"
+"ÎεβαιÏθείÏε ÏÏι δεν Ï
ÏάÏÏει ÏÏοÏÏαÏία εγγÏαÏήÏ.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "ΧÏÏμαÏα και γÏαμμαÏοÏειÏά"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "ΧÏήÏη ÏÏÏμάÏÏν ÏÏ
ÏÏήμαÏοÏ"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "ÎανονικÏ"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "ΦÏνÏο"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "ÎνÎÏγεια"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "ÎÏιÏήμανÏη"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "ÎίÏοδοÏ/ÎξοδοÏ"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Τα μηνÏμαÏά μοÏ
"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "ÎξÏ
ÏηÏεÏηÏήÏ"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "ΠελάÏηÏ"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "ΣÏάλμα"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "ΧÏονÏÏημο"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "ÎιδοÏοίηÏη"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Connected to TAS Server.\n"
+"[22:30] <Dude> γεια ÏαÏ\n"
+"[22:30] ** Dude2 ειÏήλθε ÏÏο κανάλι.\n"
+"[22:30] * Dude2 ÏοÏ
αÏÎÏοÏ
ν Ïα ÏÏÏμαÏά ÏοÏ
\n"
+"[22:45] <Dude> Dude2: Ïλάκα κάνειÏ!\n"
+"[22:46] <Dude2> Îα μÏοÏοÏÏαν να είναι καλÏÏεÏα, ÏÏÎÏει να Ïα ÏειÏÎ¬Î¾Ï Î»Î¯Î³Î¿ "
+"ακÏμα...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "ÎÏαμμαÏοÏειÏά:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "ÏÏοεÏιλογή"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "ÎÏιλογή..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "ΣÏ
μÏεÏιÏοÏά"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr "ΧÏήÏη ήÏÏν ειδοÏοίηÏηÏ"
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "ÎαÏαγÏαÏÎÏ ÏÏ
νομιλιÏν"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "ÎÏοθήκεÏ
Ïη καÏαγÏαÏÏν ÏÏ
νομιλιÏν"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "ÎÏιÏήμανÏη λÎξεÏν"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "ÎÎÎ¾ÎµÎ¹Ï ÏÏÎ¿Ï ÎµÏιÏήμανÏη Ïε ÏÏ
νομιλίεÏ:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "ÎιÏάγεÏε λίÏÏα ÏÏÏιÏμÎνη με \";\""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr "ÎÏιÏλÎον ÏÏήÏη ήÏÏν/αναβÏÏβημα ÏίÏλοÏ
ÏαÏαθÏÏοÏ
"
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr "κανάλι_"
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d ÏÏήÏÏεÏ)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "κάνεÏε δεξί κλικ για εÏιλογÎÏ (ÏÏÏÏ Î±Ï
ÏÏμαÏη είÏοδοÏ)"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "ÎÏοÏÏολή"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "ÎνÏιγÏαÏή"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "ÎκκαθάÏιÏη"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "ÎÏ
ÏÏμαÏη είÏÎ¿Î´Î¿Ï Ïε αÏ
ÏÏ Ïο κανάλι"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "ÎμÏάνιÏη μηνÏ
μάÏÏν ÎιÏÏδοÏ
/ÎξÏδοÏ
"
+
+#: src/chatpanel.cpp:433
+#, fuzzy
+msgid "Show mute list"
+msgstr "ÎμÏάνιÏη ÏÏ
μβοÏ
λÏν"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "ΠληÏοÏοÏÎ¯ÎµÏ ÎºÎ±Î½Î±Î»Î¹Î¿Ï"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "ÎÏιÏμÏÏ Î¸ÎμαÏοÏ..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "ÎήνÏ
μα καναλιοÏ..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "ÎλείδÏμα..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "ÎεκλείδÏμα"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "ÎγγÏαÏή..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "ÎιαγÏαÏή"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "ÎνοιÏÏÏ"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "ÎλειÏÏÏ"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "Îίναι ανοιÏÏÏ;"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Î ÏοÏÏαÏία αÏÏ Î±Î½ÎµÏιθÏμηÏα μηνÏμαÏα"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "ÎÏοÏÏνδεÏη"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "ÎÏαναÏÏνδεÏη"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "ÎÏαίÏεÏη..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Îλλαγή κÏδικοÏ..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "ÎÏιÏμÏÏ ÏÏÏÏβαÏηÏ..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "ÎογαÏιαÏμοί"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "ÎεÏάδοÏη..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "ÎιαÏειÏιÏÏήÏ"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "ÎÏοÏιÏÏηÏη ΧÏήÏÏη"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "ÎνοιÏÏή ΣÏ
νομιλία"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "ΣÏνδεÏη ÏÏην ίδια μάÏη"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "ΧÏÏÎ½Î¿Ï ÏαιÏνιδιοÏ"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "ÎÏÏεÏη διεÏθÏ
νÏÎ·Ï IP και Smurf"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "ÎÏοÏιÏÏηÏη..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "ÎÏοÏιÏÏηÏη για 5 λεÏÏά"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "ÎÏοÏιÏÏηÏη για 10 λεÏÏά"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "ÎÏοÏιÏÏηÏη για 30 λεÏÏά"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "ÎÏοÏιÏÏηÏη για 2 ÏÏεÏ"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "ÎÏοÏιÏÏηÏη για 1 ημÎÏα"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "ÎναίÏεÏη αÏοÏιÏÏηÏηÏ"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "ÎÏοÏιÏÏηÏη"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "ÎÏοÏομÏή..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "ÎÏοκλειÏμÏÏ..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "ÎÏÏη αÏοκλειÏμοÏ"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "ÎÏÏε μÏάÏÏα!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Îάνε διαÏειÏιÏÏή"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "ÎÏÏη δικαιÏμαÏÎ¿Ï Î´Î¹Î±ÏείÏηÏηÏ"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! ÎνÏολή: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" ÏαÏάμεÏÏοι: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "κανάλι"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "μάÏη"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "εξÏ
ÏηÏεÏηÏήÏ"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " ειÏήλθε ÏÏο "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " εξήλθε αÏÏ Ïο "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "ΠληÏοÏοÏÎ¯ÎµÏ ÎºÎ±Î½Î±Î»Î¹Î¿Ï"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * ÎÏίÏÏηκε αÏÏ "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Î ÏÏ
νομιλία ÎκλειÏε."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "ÎίÏÏε βÎÎ²Î±Î¹Î¿Ï ÏÏι θÎλεÏε να κάνεÏε εÏικÏλληÏη %d γÏαμμÏν;"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Î ÏοειδοÏοίηÏη ÏλημμÏÏαÏ"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " ΧÏηÏιμοÏοιείÏε Ïο SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Îεν είÏÏε Ïε κανάλι ή Ïο κανάλι δεν Ï
ÏάÏÏει."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" ΣÏάλμα: ΠενÏολή (%s) δεν Ï
ÏάÏÏει. ΠληκÏÏολογήÏÏε /help για μια λίÏÏα ÏÏν "
+"διαθÎÏιμÏν ενÏολÏν."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+" Îεν είÏÏε Ïε μάÏη ή η μάÏη δεν Ï
ÏάÏÏει. ΠληκÏÏολογήÏÏε /help για μια λίÏÏα "
+"ÏÏν διαθÎÏιμÏν ενÏολÏν."
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Î ÏÏήÏÏÎ·Ï ÎµÎ¯Î½Î±Î¹ εκÏÏÏ ÏÏνδεÏηÏ."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " ΣÏάλθηκε: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ΣÏάλμα ChanServ"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "Το ChanServ δεν είναι Ïε αÏ
ÏÏ Ïο κανάλι"
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Ποιο ÏÏÎÏει να είναι Ïο νÎο θÎμα;"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "ÎήνÏ
μα:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "ÎλείδÏμα καναλιοÏ..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Î Î¿Î¹Î¿Ï ÏÏÎÏει να είναι ο νÎÎ¿Ï ÎºÏδικÏÏ;"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "ÎεκλείδÏμα ÎαναλιοÏ"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "ÎÏιβεβαίÏÏη ξεκλειδÏμαÏÎ¿Ï ÏοÏ
καναλιοÏ;"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "Το ChanServ δεν είναι Ïε αÏ
ÏÏ Ïον εξÏ
ÏηÏεÏηÏή."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "ÎήλÏÏη ÎαναλιοÏ"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Î Î¿Î¹Î¿Ï ÏÏÎÏει να δηλÏθεί ÏÏ Î´Î·Î¼Î¹Î¿Ï
ÏγÏÏ ÏοÏ
καναλιοÏ;"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "ÎιαγÏαÏή ÎαναλιοÏ"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "ÎÏιβεβαίÏÏη διαγÏαÏÎ®Ï ÏοÏ
καναλιοÏ;"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "ÎιαγÏαÏή ÎογαÏιαÏÎ¼Î¿Ï Î§ÏήÏÏη"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Ποιον λογαÏιαÏÎ¼Ï ÏÏήÏÏη θÎλεÏε να διαγÏάÏεÏε ÏήμεÏα;"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "ÎιαγÏαÏή λογαÏιαÏμοÏ"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "ÎÏιβεβαίÏÏη διαγÏαÏÎ®Ï Î»Î¿Î³Î±ÏιαÏÎ¼Î¿Ï "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Îλλαγή ÎÏÎ´Î¹ÎºÎ¿Ï ÎογαÏιαÏÎ¼Î¿Ï Î§ÏήÏÏη"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Îια Ïοιον λογαÏιαÏÎ¼Ï Î¸ÎλεÏε να αλλάξεÏε Ïον κÏδικÏ;"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Î Î¿Î¹Î¿Ï Î¸Î± είναι ο νÎÎ¿Ï ÎºÏδικÏÏ;"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Îεν ÎÏει Ï
λοÏοιηθεί"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "ÎεÏάδοÏη ÎηνÏμαÏοÏ"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "ÎήνÏ
μα ÏÏÎ¿Ï Î¼ÎµÏάδοÏη:"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "Îεν ÎÏεÏε Ïο mod "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . ΠαÏÎ±ÎºÎ±Î»Ï ÎºÎ±ÏεβάÏÏε Ïο ÏÏÏÏα"
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr "Mod μη διαθÎÏιμο"
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr ""
+"ÎÏ
Ïή η μάÏη είναι ÏÏοÏÏαÏεÏ
μÎνη με κÏδικÏ, ÏαÏÎ±ÎºÎ±Î»Ï ÎµÎ¹ÏάγεÏε Ïον κÏδικÏ:"
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "ÎÏοÏιÏÏηÏη ΧÏήÏÏη"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Î ÏÏα λεÏÏά να διαÏκÎÏει η αÏοÏιÏÏηÏη ÏοÏ
ÏÏήÏÏη;"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "ÎÏοÏομÏή ΧÏήÏÏη"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "ÎιÏία:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "ÎÏοÏομÏή ÏÏήÏÏη"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "ÎÏοÏιÏÏηÏη ÏÏήÏÏη"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "ÎιάÏκεια:"
+
+#: src/chatpanel.cpp:1797
+#, fuzzy
+msgid "couldn't add user"
+msgstr "ÎδÏ
ναμία εκκίνηÏÎ·Ï ÏεÏιηγηÏή."
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "ΣÏνδεÏη ÏÏον εξÏ
ÏηÏεÏηÏή lobby"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"ÎξÏ
ÏηÏεÏηÏÎ®Ï ÏÏον οÏοίο θα γίνει ÏÏνδεÏη. ÎÏοÏείÏε να ÏÏ
νδεθείÏε Ïε ÏÏοιον "
+"εξÏ
ÏηÏεÏηÏή θÎλεÏε δηλÏνονÏÎ±Ï Ïον ÏÏη μοÏÏή \"εξÏ
ÏηÏεÏηÏήÏ:θÏÏα\""
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "ÎÏδικÏÏ ÏÏÏÏβαÏηÏ"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "ÎÏοθήκεÏ
Ïη κÏÎ´Î¹ÎºÎ¿Ï ÏÏÏÏβαÏηÏ"
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "ÎÏ
ÏÏμαÏη ÏÏνδεÏη Ïην εÏÏμενη ÏοÏά"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"ÎÏοθήκεÏ
Ïη ÏÏν ÏÏοιÏείÏν ÏÏνδεÏÎ·Ï ÎºÎ±Î¹ αÏ
ÏÏμαÏη ÏÏνδεÏη ÏÏον εξÏ
ÏηÏεÏηÏή καÏά "
+"Ïην εÏÏμενη εκκίνηÏη ÏοÏ
lobby"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"ΣημείÏÏη: Îν δεν ÎÏεÏε λογαÏιαÏμÏ,\n"
+"μÏοÏείÏε να εγγÏαÏείÏε δÏÏεάν ÏÏην\n"
+"καÏÏÎλα \"ÎγγÏαÏή\""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "ÎίÏοδοÏ"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "ÎγγÏαÏή"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "ΨεÏ
δÏνÏ
μο"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Îη ÎγκÏ
Ïη θÏÏα."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Îη ÎγκÏ
Ïη θÏÏα"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"ÎÏιθμÏÏ Î¸ÏÏÎ±Ï ÎµÎºÏÏÏ Î¿ÏίÏν.\n"
+"\n"
+"Î ÏÎÏει να είναι ακÎÏÎ±Î¹Î¿Ï Î±ÏÏ 1 εÏÏ 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Îη ÎγκÏ
ÏÎ¿Ï ÎµÎ¾Ï
ÏηÏεÏηÏήÏ/θÏÏα"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Îη ÎγκÏ
ÏÎ¿Ï ÎµÎ¾Ï
ÏηÏεÏηÏήÏ"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Îη ÎγκÏ
ÏÎ¿Ï Î±ÏιθμÏÏ"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"ΠεγγÏαÏή αÏÎÏÏ
Ïε, ο λÏÎ³Î¿Ï Î®Ïαν:\n"
+"ÎÏÏ
μÏÏνία κÏÎ´Î¹ÎºÎ¿Ï ÎºÎ±Î¹ εÏιβεβαίÏÏÎ®Ï ÏοÏ
"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "ÎÏοÏÏ
Ïία εγγÏαÏήÏ."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " ÎνδÏÏα"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "ÎνÏμÎνα ÎÏαβικά ÎμιÏάÏα"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "ÎÏγανιÏÏάν"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "ÎνÏίγκοÏ
α και ÎÏαÏμÏοÏνÏα"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Îνγκίλα"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Îλβανία"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "ÎÏμενία"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "ÎλλανδικÎÏ ÎνÏίλλεÏ"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "ÎνγκÏλα"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "ÎνÏαÏκÏική"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "ÎÏγενÏινή"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "ÎμεÏικανική ΣαμÏα"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "ÎÏ
ÏÏÏία"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "ÎÏ
ÏÏÏαλία"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "ÎÏοÏμÏα"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "ÎζεÏμÏαÏÏζάν"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "ÎοÏνία-ÎÏζεγοβίνη"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "ÎÏαÏμÏάνÏοÏ"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "ÎÏανγκλανÏÎÏ"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "ÎÎλγιο"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "ÎÏοÏ
Ïκίνα ΦάÏο"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "ÎοÏ
λγαÏία"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "ÎÏαÏÏÎιν"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "ÎÏοÏ
ÏοÏνÏι"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "ÎÏενίν"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "ÎεÏμοÏδεÏ"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "ÎÏÏοÏ
νÎι ÎÏαÏοÏ
Ïαλάμ"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Îολιβία"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "ÎÏαζιλία"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "ÎÏαÏάμεÏ"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "ÎÏοÏ
Ïάν"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "ÎήÏÎ¿Ï ÎÏοÏ
βÎ"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "ÎÏοÏÏοÏ
άνα"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "ÎεÏ
κοÏÏÏία"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "ÎÏελίζ"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "ÎαναδάÏ"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "ÎήÏοι ÎÏÎºÎ¿Ï (Îήλινγκ)"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "ÎενÏÏική ÎÏÏικανική ÎημοκÏαÏία"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "ÎονγκÏ"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "ÎλβεÏία"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "ÎκÏή ÎλεÏανÏοÏÏοÏ"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "ÎήÏοι ÎοÏ
κ"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Χιλή"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "ÎαμεÏοÏν"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "Îίνα"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Îολομβία"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "ÎÏÏÏα Ρίκα"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "ÎοÏβα"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Î ÏάÏινο ÎκÏÏÏήÏιο"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "ÎήÏοι ΧÏιÏÏοÏ
γÎννÏν"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "ÎÏÏÏοÏ"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "ΤÏεÏική ÎημοκÏαÏία"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "ÎεÏμανία"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "ΤζιμÏοÏ
Ïί"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Îανία"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Îομηνίκη"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Îομινικανή ÎημοκÏαÏία"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "ÎλγεÏία"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "ÎÏημεÏινÏÏ"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "ÎÏθονία"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "ÎίγÏ
ÏÏοÏ"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "ÎÏ
Ïική ΣαÏάÏα"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "ÎÏÏ
θÏαία"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "ÎÏÏανία"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "ÎιθιοÏία"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Φινλανδία"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "ΦίÏζι"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "ÎήÏοι ΦÏÎºÎ»Î±Î½Ï (ÎαλβίνεÏ)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "ÎικÏονηÏία"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "ÎήÏοι ΦεÏÏεÏ"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "Îαλλία"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "Îαλλία, ÎηÏÏοÏολιÏική"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "ÎκαμÏÏν"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "ÎÏενάδα"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "ÎεÏÏγία"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Îαλλική ÎοÏ
Ïάνα"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Îκάνα"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "ÎιβÏαλÏάÏ"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "ÎÏοιλανδία"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "ÎκάμÏια"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "ÎοÏ
ÏνÎα"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "ÎοÏ
αδελοÏÏη"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "ÎÏημεÏινή ÎοÏ
ÏνÎα"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Îλλάδα"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "Î. ÎεÏÏγία και Î. ΣάνÏοÏ
ιÏÏ ÎήÏοι"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "ÎοÏ
αÏεμάλα"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "ÎκοÏ
άμ"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "ÎοÏ
ÏνÎα-ÎÏιÏάοÏ
"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "ÎοÏ
Ïάνα"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Χονγκ Îονγκ"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "ÎήÏοι ΧεÏÎ½Ï ÎºÎ±Î¹ ÎακÎÏÏναλÏ"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "ÎνδοÏÏα"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "ÎÏοαÏία"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "ÎÏÏή"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "ÎÏ
γγαÏία"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "ÎνδονηÏία"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "ÎÏλανδία"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "ÎÏÏαήλ"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "Îνδία"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "ÎÏεÏανικά ÎδάÏη ÎÎ½Î´Î¹ÎºÎ¿Ï Î©ÎºÎµÎ±Î½Î¿Ï"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "ÎÏάκ"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "ÎÏάν"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "ÎÏλανδία"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "ÎÏαλία"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Τζαμάικα"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "ÎοÏδανία"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "ÎαÏÏνία"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "ÎÎνÏ
α"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "ÎιÏγιÏÏάν (ÎημοκÏαÏία ÏÎ·Ï ÎιÏγιζίαÏ)"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "ÎαμÏÏÏζη"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "ÎιÏιμÏάÏι"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "ÎομÏÏεÏ"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "ÎÎ³Î¹Î¿Ï Î§ÏιÏÏÏÏοÏÎ¿Ï ÎºÎ±Î¹ ÎÎβιÏ"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "ÎοÏÎα (ÎÏÏεια) (Îαική ÎημοκÏαÏία)"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "ÎοÏÎα (ÎÏÏια) (ÎημοκÏαÏία)"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "ÎοÏ
βÎιÏ"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "ÎήÏοι ÎÎÏ
μαν"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "ÎαζακÏÏάν"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "ÎάοÏ"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "ÎίβανοÏ"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Îγία ÎοÏ
κία"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "ÎιÏÏενÏÏάιν"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "ΣÏι Îάνκα"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "ÎιβεÏία"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "ÎεÏÏÏο"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "ÎιθοÏ
ανία"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "ÎοÏ
ξεμβοÏÏγο"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "ÎεÏÏονία"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "ÎιβÏη"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "ÎαÏÏκο"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "ÎονακÏ"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Îολδαβία"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "ÎαÏ
ÏοβοÏνιο"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "ÎαδαγαÏκάÏη"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "ÎήÏοι ÎάÏÏαλ"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Fyrom"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Îάλι"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "ÎιανμάÏ"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Îογγολία"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Îακάο"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "ÎήÏοι ÎοÏείÏν ÎαÏιάννÏν"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "ÎαÏÏινίκα"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "ÎαÏ
ÏιÏανία"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "ÎονÏεÏάÏ"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "ÎάλÏα"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "ÎαÏ
ÏίκιοÏ"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "ÎαλδίβεÏ"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "ÎαλάοÏ
ι"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "ÎεξικÏ"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "ÎαλαιÏία"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Îοζαμβίκη"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "ÎαμίμÏια"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "ÎÎα Îαληδονία"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "ÎίγηÏαÏ"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "ÎήÏοι ÎÏÏÏολκ"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "ÎιγηÏία"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "ÎικαÏάγοÏ
α"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Îλλανδία"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "ÎοÏβηγία"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "ÎεÏάλ"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "ÎαοÏÏοÏ
"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "ÎÏ
δÎÏεÏη ÎÏνη ΣαοÏ
Î´Î¹ÎºÎ®Ï ÎÏαβίαÏ/ÎÏάκ"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "ÎιοÏε"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "ÎÎα Îηλανδία"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Îμάν"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "ΠαναμάÏ"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "ΠεÏοÏ"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Îαλλική ΠολÏ
νηÏία"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "ΠαÏοÏα-ÎÎα ÎοÏ
ινÎα"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "ΦιλιÏÏίνεÏ"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "ΠακιÏÏάν"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "ΠολÏνία"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "Σαν ΠιÎÏ ÎºÎ±Î¹ ÎικελÏν"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "ÎήÏοι ΠίÏκαιÏν"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Î ÏÏÏο Ρίκο"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "ΠοÏÏογαλία"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "ΠαλάοÏ
"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "ΠαÏαγοÏ
άη"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "ÎαÏάÏ"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "ÎήÏÎ¿Ï ÎÏανÎνÏÏηÏ"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "ΡοÏ
μανία"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "ΣεÏβία"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "ΡÏÏική ÎμοÏÏονδία"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "ΡοÏ
άνÏα"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "ΣαοÏ
δική ÎÏαβία"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "ÎήÏοι ΣολομÏνÏα"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "ΣεÏÏÎλλεÏ"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "ΣοÏ
δάν"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "ΣοÏ
ηδία"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "ΣιγκαÏοÏÏη"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "Îγία ÎλÎνη"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Σλοβενία"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "ÎήÏοι ΣβάλμÏαÏÎ½Ï ÎºÎ±Î¹ Îαν ÎαγιÎν"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Σλοβακία (Σλοβάκικη ÎημοκÏαÏία)"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "ΣιÎÏÏα ÎεÏνε"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "Σαν ÎαÏίνο"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Σενεγάλη"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Σομαλία"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "ΣοÏ
Ïινάμ"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "Σάο ΤομΠκαι Î ÏίνÏιÏε"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "ΣοβιεÏική ÎνÏÏη (ÏÏÏην)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "Îλ ΣαλβαδÏÏ"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "ΣÏ
Ïία"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "ΣοÏ
αζιλάνδη"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "ÎήÏοι ΤοÏÏÎºÏ ÎºÎ±Î¹ ÎαÎκοÏ"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "ΤÏανÏ"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Îαλλικά ÎÏÏια ÎδάÏη"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "ΤÏγκο"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "ΤαÏλάνδη"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "ΤαÏζικιÏÏάν"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "ΤοκελάοÏ
"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "ΤοÏ
ÏκμενιÏÏάν"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "ΤÏ
νηÏία"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "ΤÏγκα"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "ÎναÏÎ¿Î»Î¹ÎºÏ Î¤Î¹Î¼Î¿ÏÏ"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "ΤοÏ
Ïκία"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "ΤÏινιδάδ και ΤομÏάγκο"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "ΤοÏ
βαλοÏ"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "ΤαÏβάν"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Τανζανία"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "ÎÏ
κÏανία"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "ÎÏ
γκάνÏα"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "ÎνÏμÎνο ÎαÏίλειο (Îεγάλη ÎÏεÏανία)"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "ÎικÏοί ÎÏÏμεÏοι ÎήÏοι ÏÏν ÎÎ Î"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "ÎνÏμÎÎ½ÎµÏ Î Î¿Î»Î¹ÏείεÏ"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "ÎÏ
ÏοÏ
γοÏ
άη"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "ÎÏ
ζμÏεκιÏÏάν"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Î Ïλη ÏοÏ
ÎαÏÎ¹ÎºÎ±Î½Î¿Ï (Îγία ÎδÏα)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "ÎÎ³Î¹Î¿Ï ÎικÎνÏÎ¹Î¿Ï ÎºÎ±Î¹ ÎÏεναδίνεÏ"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "ÎενεζοÏ
Îλα"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "ΠαÏθÎνοι ÎήÏοι (ÎÏεÏανικÎÏ)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "ΠαÏθÎνοι ÎήÏοι (ÎνÏμÎνÏν ΠολιÏειÏν)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "ÎιεÏνάμ"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "ÎανοÏ
άÏοÏ
"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "ÎήÏοι ÎÏ
ÏÎ»Î»Î¹Ï ÎºÎ±Î¹ ΦοÏ
ÏοÏνα"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "ΣαμÏα"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "ΥεμÎνη"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "ÎαγιÏÏ"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "ÎιοÏ
γκοÏλαβία"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "ÎÏÏια ÎÏÏική"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "ÎάμÏια"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "ÎαÎÏ"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "ÎιμÏάμÏοÏ
ε"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Îεν βÏÎθηκε ονομαÏία κÏάÏοÏ
Ï)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "ΠληÏοÏοÏÎ¯ÎµÏ ÏÏ
ÏÏήμαÏοÏ"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "ÎναλÏ
Ïική καÏαγÏαÏή εÏαÏμογήÏ"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "ΤελεÏ
Ïαία δημιοÏ
ÏγημÎνο script εκÏÎλεÏηÏ"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "ΠαιÏνίδι"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+#, fuzzy
+msgid "Search and download files"
+msgstr "ÎναζήÏηÏη αÏÏείοÏ
"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "ÎήÏη ολοκληÏÏθηκε"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+#, fuzzy
+msgid "unknown hash "
+msgstr "άγνÏÏÏο"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "ÎÏαίÏεÏη..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "ÎÏαίÏεÏη..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "Î ÏοÏθήκη Bot..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "ÎνÎÏγεια"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "ÎνοιÏÏή ΣÏ
νομιλία"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "Φιλοξενία νÎÎ±Ï Î¼Î¬ÏηÏ"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "ÎÏιÏήμανÏη λÎξεÏν"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "Î ÏοÏθήκη Bot..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "ÎιαγÏαÏή ÎογαÏιαÏÎ¼Î¿Ï Î§ÏήÏÏη"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Îνομα ÏÏήÏÏη"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Îε ανάκλαÏη"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "ÎÏιλ. ÏÏο ÏαιÏνίδι"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"αÏοθηκεÏÏηκε εÏιÏÏ
ÏÏÏ ÏÏο:\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "ÎÏιÏμÏÏ ÏÏÏÏβαÏηÏ..."
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "ÎδÏναÏη η αÏοθήκεÏ
Ïη\n"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "ÏÏοεÏιλογή"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "ΠληÏοÏοÏÎ¯ÎµÏ ÎºÎ±Î½Î±Î»Î¹Î¿Ï"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+#, fuzzy
+msgid "Language"
+msgstr "ÎαÏαγÏγή"
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Φιλοξενία νÎÎ±Ï Î¼Î¬ÏηÏ"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "ΣÏνÏομη ÏεÏιγÏαÏή ÏοÏ
ÏαιÏνιδιοÏ, θα εμÏανιÏÏεί ÏÏη λίÏÏα μαÏÏν."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "ΠεÏιγÏαÏή"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "ÎÏιλÎξÏε Ïο mod ÏοÏ
θÎλεÏε να ÏαίξεÏε."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr "ÎÏδικÏÏ Î³Î¹Î± ÏÏ
μμεÏοÏή ÏÏο ÏαιÏνίδι. ÎÏήÏÏε ÎºÎµÎ½Ï Î³Î¹Î± ελεÏθεÏη ÏÏ
μμεÏοÏή"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "ÎÏÏα"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+"ÎÏÏα UDP για Ïιλοξενία ÏοÏ
ÏαιÏνιδιοÏ. Îξ οÏιÏÎ¼Î¿Ï ÏÏηÏιμοÏοιείÏαι η 8452."
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "μη διαθÎÏιμο"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "ÎÏιθμÏÏ ÏαικÏÏν"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "ΠμÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ ÏαιÏÏÏν ÏοÏ
θα εÏιÏÏαÏεί ÏÏη μάÏη."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "ÎιάÏÏηÏη"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "ÎιάÏÏηÏη NAT"
+
+#: src/hostbattledialog.cpp:177
+#, fuzzy
+msgid "NAT traversal to use."
+msgstr "ÎιάÏÏηÏη NAT"
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "ÎαÏÏÏεÏÎ¿Ï Î²Î±Î¸Î¼ÏÏ"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "ÎναÏξη ÏÎ¹Î»Î¿Î¾ÎµÎ½Î¯Î±Ï ÏÎ·Ï Î¼Î¬ÏηÏ."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "Î ÏÎÏει ÏÏÏÏα να εÏιλÎξεÏε Îνα mod."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Îεν εÏιλÎÏθηκε mod."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"αÏοθηκεÏÏηκε εÏιÏÏ
ÏÏÏ ÏÏο:\n"
+
+#: src/httpdownloader.cpp:78
+#, fuzzy
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"αÏοθηκεÏÏηκε εÏιÏÏ
ÏÏÏ ÏÏο:\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr "ÎδÏναÏη η αÏοθήκεÏ
Ïη\n"
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"ÏÏοÏ:\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "ΠεÏιηγηÏÎ®Ï Î¹ÏÏοÏελίδÏν"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Îξ οÏιÏμοÏ"
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr "ΧÏήÏη ÏÎ·Ï ÏÏθμιÏÎ·Ï ÏÏ
ÏÏήμαÏοÏ"
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Î ÏοÏδιοÏίÏÏε:"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr "Î ÏοÏδιοÏίÏÏε Ïον ÏεÏιηγηÏή ÏοÏ
θÎλεÏε να ÏÏηÏιμοÏοιήÏεÏε"
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "ÎναζήÏηÏη"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr "ΧÏήÏη διαλÏγοÏ
αÏÏείÏν για αναζήÏηÏη ÏοÏ
ÏεÏιηγηÏή"
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+#, fuzzy
+msgid "Use a file dialog to find the editor binary"
+msgstr "ΧÏήÏη διαλÏγοÏ
αÏÏείÏν για αναζήÏηÏη ÏοÏ
ÏεÏιηγηÏή"
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "ÎÏαναÏÏνδεÏη"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "ΣÏνδεÏη ÏÏον εξÏ
ÏηÏεÏηÏή lobby"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "&ÎÏγαλεία"
+
+#: src/lobbyoptionstab.cpp:121
+#, fuzzy
+msgid "Show Tooltips?"
+msgstr "ÎμÏάνιÏη ÏÏ
μβοÏ
λÏν"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+#, fuzzy
+msgid "Match exact"
+msgstr "ÎÏÏαγή εξαιÏÎÏεÏν AI (exceptions)"
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "ÎÏÏÎ¹ÎºÏ ÎÎÏαλλο"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "ÎÏιλÎξÏε Ïο εκÏελÎÏιμο ÏοÏ
ÏεÏιηγηÏή"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "ÎÏιλÎξÏε Ïο εκÏελÎÏιμο ÏοÏ
ÏεÏιηγηÏή"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "ÎγνÏÏÏη αÏάνÏηÏη αÏÏ Ïον εξÏ
ÏηÏεÏηÏή"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "ÎίÏÏα μαÏÏν"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "ÎÏμάÏιο μάÏηÏ"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "ÎÏιλογÎÏ"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "ΠεÏιοÏιÏμοί μονάδÏν"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "P2P"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "ΣÏ
νομιλία"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Σενεγάλη"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "ÎÏαναÏοÏά"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "ÎÏαÏμογή"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "ΠαιÏνίδι"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr "ÎήÏÎµÎ¹Ï Ïε εξÎλιξη: "
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "ΣÏ
νολικά εξεÏÏÏμενα: "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "ΣÏ
νολικά ειÏεÏÏÏμενα: "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "άγνÏÏÏο"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "ÎκÏÏÏÏη λήÏηÏ"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "ÎκδοÏη νÎοÏ
αÏÏείοÏ
"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "ÎναζήÏηÏη αÏÏείοÏ
"
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "ÎνεÏγοÏοίηÏη LuaUI widget"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "μη διαθÎÏιμο"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "ÏÏοÏοδοÏία"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr "ÏοÏ
Ïάει"
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr "Ïε ÏειÏά"
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "ÎαÏάÏÏαÏη: ΧÏÏÎ¯Ï ÏÏνδεÏη"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "ÎαÏάÏÏαÏη: ΣÏ
νδεμÎνο"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr "ÎαÏάÏÏαÏη: ÎÏιβÏαδÏ
νÏμενο ή ÏÏαμαÏημÎνο (Ïε ÏαιÏνίδι)"
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "ÎαÏάÏÏαÏη: ÎγνÏÏÏο"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "ΣÏ
νολικά ÎξεÏÏÏμενα: %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "ΣÏ
νολικά ÎιÏεÏÏÏμενα: %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&ΣÏνδεÏη..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&ÎÏοÏÏνδεÏη"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "ÎÏιλογÎÏ Î´Î¹ÎµÏαÏήÏ"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&ΤεÏμαÏιÏμÏÏ"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "ÎίÏÎ¿Î´Î¿Ï Ïε κανάλι..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "ΠληÏοÏοÏÎ¯ÎµÏ ÎºÎ±Î½Î±Î»Î¹Î¿Ï"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "ÎναÏξη prive ÏÏ
νομιλίαÏ..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr "ÎÏ
ÏÏμαÏη είÏÎ¿Î´Î¿Ï Ïε κανάλια..."
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "ÎνανÎÏÏη ÏαÏÏÏν/mod"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "ÎλεγÏÎ¿Ï Î³Î¹Î± νÎα ÎκδοÏη"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "ΡÏ
θμίÏÎµÎ¹Ï Spring"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&ΠεÏί"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "ΠληÏοÏοÏÎ¯ÎµÏ ÎºÎ±Î½Î±Î»Î¹Î¿Ï"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "ÎναÏοÏά ÏÏοβλήμαÏοÏ..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&ΤεκμηÏίÏÏη"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&ÎÏÏείο"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&ÎÏγαλεία"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Îοήθεια"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "ÎαÏάÏÏαÏη: ΣÏ
νδεμÎνο"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "ÎίÏÎ¿Î´Î¿Ï Ïε κανάλι..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Îνομα καναλιοÏ"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "ÎναÏξη prive ÏÏ
νομιλίαÏ..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Îνομα ÏÏήÏÏη"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+"Το SpringLobby είναι ÎÎ½Î±Ï ÏελάÏÎ·Ï lobby ÏÎ·Ï Î¼Î·ÏÎ±Î½Î®Ï RTS Spring για ÏολλαÏλά "
+"λειÏοÏ
Ïγικά ÏεÏιβάλλονÏα"
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Îεν βÏÎθηκαν ÏάÏÏεÏ"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "ΧειÏοκίνηÏη ÎναÏξη ÏÏ
ÏÏήμαÏÎ¿Ï Torrent"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "ΧειÏοκίνηÏη διακοÏή ÏÏ
ÏÏήμαÏÎ¿Ï Torrent"
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Ποιον λογαÏιαÏÎ¼Ï ÏÏήÏÏη θÎλεÏε να διαγÏάÏεÏε ÏήμεÏα;"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "ÎÏοθήκεÏ
Ïη..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "ΠάνÏα"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "ÎήÏη αÏÏείοÏ
"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "ÎνανÎÏÏη"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "ÎήÏη αÏÏείοÏ
"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "ÏλεÏ
Ïά:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "ÏÏ
μμαÏία: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "εÏίδομα: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "ÎÏÏείο"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Îεγ. μÎÏαλλο"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "ÎÏÏικÎÏ Î¸ÎÏειÏ"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "ÎαÏÏÏεÏÎ¿Ï Î²Î±Î¸Î¼ÏÏ"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "ÎÎÏοÏ"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "ÎεαÏήÏ"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "ΤÏ
ÏÎ±Î¯ÎµÏ Î±ÏÏικÎÏ Î¸ÎÏειÏ"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "ΤÏÏÎ¿Ï ÎÏÏÎ¹ÎºÎ®Ï ÎÎÏηÏ"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Î ÏÏ Î¸Î± εÏιλÎγοÏ
ν οι ÏαίκÏÎµÏ Ïο ÏοÏ
θα εμÏανιÏÏοÏν ÏÏον ÏάÏÏη\n"
+"0: ÏÏαθεÏÎÏ Î¸ÎÏÎµÎ¹Ï ÏÏον ÏάÏÏη\n"
+"1: ÏÏ
ÏÎ±Î¯ÎµÏ Î¸ÎÏÎµÎ¹Ï ÏÏον ÏάÏÏη\n"
+"2: θα εÏιλÎγοÏ
ν μÎÏα ÏÏο ÏαιÏνίδι\n"
+"3: θα εÏιλÎγοÏ
ν ÏÏο lobby ÏÏιν ξεκινήÏοÏ
ν"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "ÎÏιλ. ÏÏο ÏαιÏνίδι"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "ÎÏιλ. ÏÏο ÏαιÏνίδι"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "ΠεÏιοÏιÏμÎÎ½ÎµÏ Î¼Î¿Î½Î¬Î´ÎµÏ"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "ÎÏιλογÎÏ Î´Î¹ÎµÏαÏήÏ"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "κ"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "Ï"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "β"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "ÎκÏελÎÏιμα (*.exe)|*.exe|Îλα Ïα αÏÏεία (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Îλα Ïα αÏÏεία (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr "ΠακÎÏα ÎÏαÏμογÏν (*.app)|*.app|Îλα Ïα αÏÏεία (*.*)|*.*"
+
+#: src/playback/playbackfilter.cpp:60
+#, fuzzy
+msgid "Filter settings"
+msgstr "ÎÏοθήκεÏ
Ïη ÏÏ
θμίÏεÏν"
+
+#: src/playback/playbackfilter.cpp:164
+#, fuzzy
+msgid "Filesize in KB:"
+msgstr "μÎÎ³ÎµÎ¸Î¿Ï (MB)"
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "ÎιάÏκεια:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Îε ανάκλαÏη"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "ÎαÏάÏÏαÏη"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "ΠαναμάÏ"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "ÎιάÏκεια:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Î ÏÏβλημα ÏοÏ
Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "μÎÎ³ÎµÎ¸Î¿Ï (MB)"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "μÎÎ³ÎµÎ¸Î¿Ï (MB)"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "ÎÏÏείο"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "ΦÏÏÏÏÏη..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "ΠάνÏα"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "ÎÏοθήκεÏ
Ïη..."
+
+#: src/playback/playbacktab.cpp:286
+#, fuzzy
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"Îεν βÏÎθηκε η ÎκδοÏη ÏοÏ
Spring αÏÏ Ïη μονάδα UnitSync.\n"
+"\n"
+"Τα δικÏÏ
ακά ÏαιÏνίδια θα αÏενεÏγοÏοιηθοÏν."
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+#, fuzzy
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+"Î ÏÎÏει να καÏεβάÏεÏε Ïο mod ÏÏιν να ÏÏ
μμεÏάÏÏεÏε Ïε αÏ
ÏÏ Ïο ÏαιÏνίδι.\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Îη ÎγκÏ
Ïη θÏÏα"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "ÎÏιλογή ÏλÏν"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Î ÏÏήÏÏÎ·Ï ÎµÎ¯Î½Î±Î¹ εκÏÏÏ ÏÏνδεÏηÏ."
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() αÏÎÏÏ
Ïε ! (εξαίÏεÏη)"
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Î ÏÏήÏÏÎ·Ï ÎµÎ¯Î½Î±Î¹ εκÏÏÏ ÏÏνδεÏηÏ."
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " ειÏήλθε ÏÏο "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "ΠείÏÎ¿Î´Î¿Ï ÏÏο κανάλι αÏÎÏÏ
Ïε"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "ÎÏÎÏÏ
Ïε η είÏÎ¿Î´Î¿Ï ÏÏο κανάλι "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " εÏειδή: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Îήνημα ÎξÏ
ÏηÏεÏηÏή"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " ÎÏει διεÏθÏ
νÏη IP=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " δεν Ï
ÏοÏÏηÏίζει ÏÏαγμαÏικά Ïην ÎιάÏÏηÏη NAT"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "ÎκδιÏÏθήκαÏε αÏÏ Ïη μάÏη!"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "ÎÏοÏομÏή αÏÏ ÎικοδεÏÏÏÏη"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "ÎίÏÏα μαÏÏν"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "ÎήÏη ολοκληÏÏθηκε"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"ΠαÏοÏ
ÏιάÏÏηκε ÏÏÏβλημα καÏά Ïον ÎλεγÏο για νÎα ÎκδοÏη.\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÏÏοÏÏαθήÏÏε αÏγÏÏεÏα.\n"
+"Îν Ïο ÏÏÏβλημα ÏαÏαμÎνει, ÏαÏÎ±ÎºÎ±Î»Ï ÏÏηÏιμοÏοιήÏÏε Ïο Îοηθεία -> ÎναÏοÏά "
+"Î ÏοβλήμαÏÎ¿Ï Î³Î¹Î± να αναÏÎÏεÏε αÏ
ÏÏ Ïο ÏÏÏβλημα."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "ÎιδοÏοίηÏη"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Îη ÎγκÏ
ÏÎ¿Ï Î±ÏιθμÏÏ"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Îεν είναι αÏιθμÏÏ"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "Îεν Ï
ÏάÏÏει ο ÏάÏÏηÏ."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "ÎεκίνηÏε"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "ÎÏαναÏÏνδεÏη"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "άγνÏÏÏο"
+
+#: src/serverevents.cpp:1009
+#, fuzzy
+msgid "Download complete, location is: "
+msgstr "ÎήÏη ολοκληÏÏθηκε"
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "ÎήÏη ολοκληÏÏθηκε"
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "ÎδÏ
ναμία εκκίνηÏÎ·Ï ÏεÏιηγηÏή. Το URL είναι: "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "ÎδÏ
ναμία εκκίνηÏÎ·Ï ÏεÏιηγηÏή."
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr "ΤαÏÏÏηÏα ÏοδÎÎ»Î±Ï ÎºÏλιÏηÏ"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+"ÎεγαλÏÏεÏÎµÏ ÏιμÎÏ ÏημαίνοÏ
ν γÏηγοÏÏÏεÏη μεγÎθÏ
νÏη με Ïη ÏοδÎλα ÏοÏ
"
+"ÏονÏικιοÏ.\n"
+"ÎÏνηÏικÎÏ ÏιμÎÏ Î±Î½ÏιÏÏÏÎÏοÏ
ν Ïην ÏοÏά μεγÎθÏ
νÏηÏ.\n"
+"ΦÎÏει διαÏοÏεÏικά αÏοÏελÎÏμαÏα ανάλογα με Ïον ÏÏÏο κάμεÏαÏ!"
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr "ÎÎÎ³ÎµÎ¸Î¿Ï ÏάÏÏη ÏκιÏν"
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"μεγαλÏÏεÏη Ïιμή = καλÏÏεÏÎµÏ ÏκιεÏ\n"
+"εÏιÏÏεÏÏÎÏ ÏιμεÏ: 1024, 2048, 4096, 8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr "ÎÏÏÏÏαÏη εμÏάνιÏÎ·Ï Î´ÎνÏÏÏν"
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr "ÎÏίζει Ïη μÎγιÏÏη αÏÏÏÏαÏη ÏοÏ
θα ÏÏεδιάζονÏαι Ïα δÎνÏÏα"
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr "ÎεÏÏομÎÏÎµÎ¹ÎµÏ ÎµÎ´Î¬ÏοÏ
Ï"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr "μεγαλÏÏεÏÎµÏ ÏιμÎÏ = ÏεÏιÏÏÏÏεÏÎµÏ Î»ÎµÏÏομÎÏÎµÎ¹ÎµÏ ÎµÎ´Î¬ÏοÏ
Ï"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "Unit LOD distance"
+msgstr "ÎÏÏÏÏαÏη εικονιδίÏν μονάδÏν"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr "μεγαλÏÏεÏÎµÏ ÏιμÎÏ = Ïιο λεÏÏομεÏÎµÎ¯Ï Î¼Î¿Î½Î¬Î´ÎµÏ"
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr "ÎεÏÏομÎÏεια ÏοÏÏαÏιοÏ"
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "higher value = more detailed grass"
+msgstr "μεγαλÏÏεÏÎµÏ ÏιμÎÏ = Ïιο λεÏÏομεÏÎÏ ÏÏÏÏο"
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr "Decal εδάÏοÏ
Ï"
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr "ÎÏÏÏÏαÏη εικονιδίÏν μονάδÏν"
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+"Î ÏοÏδιοÏίζει μÎÏÏι Ïια αÏÏÏÏαÏη θα ÏÏεδιάζονÏαι ÏλήÏÏÏ Î¿Î¹ μονάδεÏ\n"
+"μεγαλÏÏεÏÎµÏ ÏιμÎÏ = μεγαλÏÏεÏη αÏÏÏÏαÏη = ÏεÏιÏÏÏÏεÏÎµÏ Î¼Î¿Î½Î¬Î´ÎµÏ ÏÏεδιάζονÏαι "
+"ÏαÏ
ÏÏÏÏονα"
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr "ÎÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ ÏαÏ
ÏÏÏÏονÏν ÏÏμαÏιδίÏν"
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "ÏεÏιοÏίζει Ïο ÏÏÏα ÏÏμαÏίδια (κομμαÏάκια) θα εμÏανίζονÏαι ÏαÏ
ÏÏÏÏονα"
+
+#: src/settings++/Defs.hpp:233
+#, fuzzy
+msgid "Max nano simultaneous particles"
+msgstr "ÎÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ ÏαÏ
ÏÏÏÏονÏν ÏÏμαÏιδίÏν"
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr "ÎκÏÎλεÏη Ïε ÏλήÏη οθÏνη"
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr "εκÏÎλεÏη Ïε ÏλήÏη οθÏνη ή Ïε ÏαÏάθÏ
Ïο;"
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "ÎειÏοÏ
Ïγία διÏÎ»Î®Ï Î¿Î¸ÏνηÏ"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "αν ÎÏεÏε δÏο οθÏÎ½ÎµÏ Î¼ÏοÏείÏε να ÏÎ¹Ï ÏÏηÏιμοÏοιήÏεÏε ÏαÏ
ÏÏÏÏονα"
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "ÎνεÏγοÏοίηÏη κάθεÏοÏ
ÏÏ
γÏÏονιÏμοÏ"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr "ÎνεÏγÏÏ/ανενεÏγÏÏ ÎºÎ¬Î¸ÎµÏÎ¿Ï ÏÏ
γÏÏονιÏμÏÏ (V-Sync)"
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr "Î Î¯Î½Î±ÎºÎ±Ï Î²Î¬Î¸Î¿Ï
Ï (Z-buffer) ανάλÏ
ÏÎ·Ï 16-bit"
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr "placeholder"
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr "Î Î¯Î½Î±ÎºÎ±Ï Î²Î¬Î¸Î¿Ï
Ï (Z-buffer) ανάλÏ
ÏÎ·Ï 24-bit"
+
+#: src/settings++/Defs.hpp:257
+#, fuzzy
+msgid "Full-scene anti-aliasing samples"
+msgstr "ÎείγμαÏα εξομάλÏ
νÏÎ·Ï Î³ÏνιÏν ÏλήÏοÏ
Ï Î¿Î¸ÏÎ½Î·Ï (FSAA)"
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr "ÏÏÏη εξομάλÏ
νÏη γÏνιÏν ÏÏÎÏει να εÏαÏμοÏÏεί"
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr "ÎÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ ÏαÏ
ÏÏÏÏονÏν ήÏÏν"
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+"ÎÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ Î´Î¹Î±ÏοÏεÏικÏν ήÏÏν ÏοÏ
θα αναÏαÏάγονÏαι ÏαÏ
ÏÏÏÏονα\n"
+"ÎÏίÏÏε ÏÏ 0 για να αÏεÏγοÏοιηθεί ÏλήÏÏÏ Î¿ ήÏοÏ."
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "Master sound volume"
+msgstr "Îενική ÎνÏαÏη ήÏοÏ
"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "master sound volume"
+msgstr "Îενική ÎνÏαÏη ήÏοÏ
"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "General sound volume"
+msgstr "Îενική ÎνÏαÏη ήÏοÏ
"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "general volume relative to master volume"
+msgstr "ÎνÏαÏη αÏανÏήÏεÏν μονάδÏν ÏÏεÏική ÏÏÎ¿Ï Ïην Îενική ÎνÏαÏη ήÏοÏ
"
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr "ÎνÏαÏη αÏανÏήÏεÏν μονάδÏν"
+
+#: src/settings++/Defs.hpp:273
+#, fuzzy
+msgid "reply volume relative to master volume"
+msgstr "ÎνÏαÏη αÏανÏήÏεÏν μονάδÏν ÏÏεÏική ÏÏÎ¿Ï Ïην Îενική ÎνÏαÏη ήÏοÏ
"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "ÎÏμάÏιο μάÏηÏ"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "battle volume relative to global volume"
+msgstr "ÎνÏαÏη αÏανÏήÏεÏν μονάδÏν ÏÏεÏική ÏÏÎ¿Ï Ïην Îενική ÎνÏαÏη ήÏοÏ
"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "User interface volume"
+msgstr "ÎνÏαÏη αÏανÏήÏεÏν μονάδÏν"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "ui volume relative to global volume"
+msgstr "ÎνÏαÏη αÏανÏήÏεÏν μονάδÏν ÏÏεÏική ÏÏÎ¿Ï Ïην Îενική ÎνÏαÏη ήÏοÏ
"
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "ΣκιÎÏ (αÏγÏ)"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr "ÎνεÏγοÏοίηÏη ÏκιÏν;"
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr "ΤÏιÏδιάÏÏαÏα δÎνÏÏα"
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+"θÎλεÏε Ïιο ÏμοÏÏα δÎνÏÏα;\n"
+"αÏαιÏεί Geforce 2/Radeon 8500/Intel 830 ή μεÏαγενÎÏÏεÏÎµÏ ÎºÎ¬ÏÏÎµÏ Î³ÏαÏικÏν"
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr "ΣÏννεÏα Ï
ÏÎ·Î»Î®Ï Î±Î½Î¬Î»Ï
ÏηÏ"
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"θÎλεÏε Ïιο ÏμοÏÏο οÏ
ÏανÏ;\n"
+"αÏαιÏεί Geforce 5/Radeon 9500/Intel 915 ή μεÏαγενÎÏÏεÏÎµÏ ÎºÎ¬ÏÏÎµÏ Î³ÏαÏικÏν"
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr "ÎÏ
ναμικά ÏÏννεÏα (αÏγÏ)"
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr "θÎλεÏε κινοÏμενα ÏÏννεÏα ÏÏον οÏ
ÏανÏ;"
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr "ÎνάκλαÏη ÏÏÎ¹Ï Î¼Î¿Î½Î¬Î´ÎµÏ"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"γÏ
αλιÏÏεÏÎÏ Î¼Î¿Î½Î¬Î´ÎµÏ;\n"
+"αÏαιÏεί Geforce 5/Radeon 9500/Intel 915 ή μεÏαγενÎÏÏεÏÎµÏ ÎºÎ¬ÏÏÎµÏ Î³ÏαÏικÏν"
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+"Îα μην ÏÏηÏιμοÏοιοÏνÏαι ÏκιαÏÏÎÏ (shaders) ÏÏαν ÏÏεδιάζονÏαι ÏάÏÏÎµÏ SM3"
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr "ÏÏοβλήμαÏα με ÏάÏÏÎµÏ sm3; ενεÏγοÏοιήÏÏε αÏ
ÏÏ"
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr "ÎνεÏγοÏοίηÏη Ï
ÏοÏÏήÏÎ¹Î¾Î·Ï LuaShader"
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr "για cool εÏÎ"
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr "Î¥ÏÎ·Î»Î®Ï Î±Î½Î¬Î»Ï
ÏÎ·Ï texture ÎÏÏÎ¹ÎºÎ®Ï ÎÏαÏήÏ"
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr "Ïιο ομαλÎÏ ÎµÏικαλÏÏÎµÎ¹Ï ÎÏÏÎ¹ÎºÎ®Ï ÎÏαÏήÏ"
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr "ΣÏεδίαÏη ομαλÏν ÏημείÏν"
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr "να εξομαλÏνονÏαι οι γÏÎ½Î¯ÎµÏ ÏημείÏν"
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr "ΣÏεδίαÏη ομαλÏν γÏαμμÏν"
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr "να εξομαλÏνονÏαι οι γÏÎ½Î¯ÎµÏ Î³ÏαμμÏν"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr "ÎκδοÏη ενÏολÏν ÏÏον Ï
ÏοÏάÏÏη"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr "ÎÏÏÏε ενÏολÎÏ ÏÏον Ï
ÏοÏάÏÏη ÏÏÏÏ Î¸Î± κάναÏε "
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "ÎμÏάνιÏη ενÏολÏν ÏÏον Ï
ÏοÏάÏÏη"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr "η εξ οÏιÏÎ¼Î¿Ï Ïιμή είναι \"on\""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr "ΣÏεδίαÏη εικονιδίÏν ÏÏον Ï
ÏοÏάÏÏη"
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr "ΣÏεδίαÏη δεικÏÏν ÏÏον Ï
ÏοÏάÏÏη"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr "Î¥ÏοÏάÏÏÎ·Ï ÏÏα αÏιÏÏεÏά (μονή οθÏνη)"
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "εξ οÏιÏÎ¼Î¿Ï ÎµÎ¯Î½Î±Î¹ αÏιÏÏεÏά"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr "Î¥ÏοÏάÏÏÎ·Ï ÏÏα αÏιÏÏεÏά (διÏλή οθÏνη)"
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr "ÎÏλοÏοιημÎνα ÏÏÏμαÏα Ï
ÏοÏάÏÏη"
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "ΧÏήÏη λιγÏÏεÏÏν ÏÏÏμάÏÏν"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr "ΧÏÏμαÏα Î¿Î¼Î¬Î´Î±Ï Î³Î¹Î± ÏÏÏάÏ
ÏÏν nano-turret"
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+"Îα ÏÏηÏιμοÏοιοÏνÏαι Ïα ÏÏÏμαÏα ÏÎ·Ï Î¿Î¼Î¬Î´Î±Ï Î³Î¹Î± Ïα ÏÏμαÏίδια ÏÏν nano-turret;"
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr "ΧÏÏμαÏιÏÏÏÏ Ï
ÏομεÏÏικÏÏ ÏάÏÏηÏ"
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr "κάνει Ïιο εμÏÎ±Î½ÎµÎ¯Ï ÏÎ¹Ï Ï
ÏομεÏÏικÎÏ Î´Î¹Î±ÏοÏÎÏ"
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "ÎμÏάνιÏη ÏÏÏνοÏ
ÏαιÏνιδιοÏ"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+"αÏαιÏεί να είναι οÏιÏμÎνο Ïο \"ÎνεÏγοÏοίηÏη LuaWidgets\".\n"
+"ÎμÏανίζεÏαι ÏÏην κάÏÏ Î´ÎµÎ¾Î¹Î¬ γÏνία"
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr "ÎμÏάνιÏη ÏληÏοÏοÏιÏν ÏαικÏÏν"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr "ÎμÏάνιÏη ÏÏ
Î¸Î¼Î¿Ï ÎºÎ±ÏÎ (FPS)"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr "ÎÏιδιÏÏθÏÏη ÏÏεδίαÏÎ·Ï ÎºÎ±Ïά Ïο Alt-Tab"
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr "Îην Ïο αλλάζεÏε αν δεν ÏÏειαÏÏεί"
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr "ÎÏενεÏγοÏοίηÏη ÏÏν μονάδÏν ÎοηθηÏÎ¹ÎºÎ®Ï ÎογικήÏ"
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+"ÎÏενεÏγοÏοιεί Ïα Economy AI κλÏ.\n"
+"Îν ενεÏγοÏοιηθεί μÏοÏεί να δημιοÏ
ÏγήÏει ÏÏοβλήμαÏα με Ïο LuaUI."
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr "ÎνεÏγοÏοίηÏη κÏλιÏÎ·Ï ÏÏÎ¹Ï Î¬ÎºÏÎµÏ ÏοÏ
ÏαÏαθÏÏοÏ
"
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr "ÎÏλιÏÎ·Ï ÏÎ·Ï Î¿Î¸ÏÎ½Î·Ï ÏÏαν Ïο ÏονÏίκι ÏÏάνει ÏÎ¹Ï Î¬ÎºÏÎµÏ ÏÎ·Ï Î¿Î¸ÏνηÏ."
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr "ÎνÏιÏÏÏοÏή ΠονÏικιοÏ"
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "ÎνÏιÏÏÏÎÏει Ïον κάθεÏο άξονα ÏοÏ
ÏονÏÎ¹ÎºÎ¹Î¿Ï Ïε λειÏοÏ
Ïγία FPS"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr "Î¥ÏεÏÏ
ÏÏμÎνη κάμεÏα"
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+"οÏίÏÏε Ïην ÏαÏÏÏηÏα κÏλιÏÎ·Ï (ÏονÏίκι + ÏληκÏÏολÏγιο) για αÏ
Ïή Ïη λειÏοÏ
Ïγία"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr "ΠεÏιÏÏÏεÏÏμενη Ï
ÏεÏÏ
ÏÏμÎνη κάμεÏα"
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr "ÎάμεÏα Total War"
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr "ÎάμεÏα ÏÏÏÏοÏ
ÏλάνοÏ
"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr "ÎλεÏθεÏη κάμεÏα"
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+"Îα γίνει Ïο εξ οÏιÏÎ¼Î¿Ï ÏÏαν ξεκινάει Ïο Spring.\n"
+"ÎÏοÏεί να αλλαÏθεί μÎÏα ÏÏο ÏαιÏνίδι."
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr "ÎαθμÏÏ Î±Î½Î±Î»Ï
ÏικÏÏηÏÎ±Ï ÎºÎ¿Î½ÏÏÎ»Î±Ï (0=ελαÏ,10=μεγ)"
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr "Î ÏÏο αναλÏ
ÏικÎÏ ÏληÏοÏοÏÎ¯ÎµÏ Î½Î± εκδίδονÏαι;"
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr "ÎÏÏαγή εξαιÏÎÏεÏν AI (exceptions)"
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr "αÏενεÏγοÏοιήÏÏε για εκÏÏαλμάÏÏÏη AI"
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "ÎαÏική"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+"ΠεÏιλογή μεγαλÏÏεÏÎ·Ï ÏοιÏÏηÏÎ±Ï Î±ÏÏ Ïην βαÏική\n"
+"μÏοÏεί να εÏηÏεάÏει δÏαμαÏικά Ïην αÏÏδοÏη ÏοÏ
Spring,\n"
+"ανάλογα με Ïην ιÏÏÏ ÏÎ·Ï ÎºÎ¬ÏÏÎ±Ï Î³ÏαÏικÏν ÏαÏ,\n"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr "Îε ανάκλαÏη"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "Îε ανάκλαÏη και διάθλαÏη"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "ÎÏ
ναμική"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr "ÎνÏιÏÏÏοÏή κάθεÏοÏ
άξονα ÏονÏικιοÏ"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr "Ïο ÏάνÏ/κάÏÏ Î³Î¯Î½ÎµÏαι κάÏÏ/ÏάνÏ"
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr "Î¥ÏοÏÏήÏιξη Ï
ÏοÏάÏÏη για ÏονÏίκια με 3 ÏλήκÏÏα"
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+"αν δεν θÎλεÏε να μÏοÏείÏε να ÏÏηÏιμοÏοιείÏε εκείνο Ïο κοÏ
μÏί, "
+"αÏενεÏγοÏοιήÏÏε Ïο εδÏ"
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr "Î¥ÏεÏÏ
ÏÏμÎνη"
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr "ΣÏαÏική οÏÏική ÏοÏ
λιοÏ"
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr "ΠεÏιÏÏÏεÏÏμενη Ï
ÏεÏÏ
ÏÏμÎνη"
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+"Îδια με Ïην Ï
ÏεÏÏ
ÏÏμÎνη, αλλά μÏοÏείÏε να ÏεÏιÏÏÏÎÏεÏÏε γÏÏÏ Î±ÏÏ Ïον άξονα "
+"ÏÏοÏ
Ï"
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr "Total war"
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr "ÎάμεÏα αÏÏ ÏάνÏ, με δÏ
ναÏÏÏηÏα κλίÏÎ·Ï ÏÏον οÏιζÏνÏιο άξονα"
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "Î ÏÏÏοÏ
ÏÏοÏÏÏοÏ
"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr "ÎάμεÏα αÏÏ Ïην οÏÏική ÏÎ·Ï Î¼Î¿Î½Î¬Î´Î±Ï"
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr "ΤÏοÏοÏοιήÏÏε Ïη θÎα ÏÏÏÏ Î¸ÎλεÏε"
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "ÏλάÏÎ¿Ï Î¿Î¸ÏνηÏ"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "ÏÏÎ¿Ï Î¿Î¸ÏνηÏ"
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Îε ανάκλαÏη"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Shore waves"
+msgstr "ÎνεÏγοÏοίηÏη ÏκιÏν;"
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Enables shorewaves"
+msgstr "ÎνεÏγοÏοίηÏη ÏκιÏν;"
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Îε ανάκλαÏη"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Îε ανάκλαÏη"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "ÏεÏιοÏιÏμοί"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "ÎλειÏÏÏ"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "ΣÏ
νδÏ
αÏμÎÎ½ÎµÏ ÎÏιλογÎÏ"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "ΠοιÏÏηÏα ÏÏεδίαÏÎ·Ï / ÎειÏοÏ
Ïγία video"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "ÎεÏÏομÎÏεια ÏÏεδιάÏηÏ"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "ÎÏιλογÎÏ Î´Î¹ÎµÏαÏήÏ"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "ÎÏοÏ"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+"Îι αλλαγÎÏ ÏοÏ
ÏÏ
ÏÏν κάνεÏε ÏÏÎ¹Ï ÎºÎ±ÏÏÎÎ»ÎµÏ Î Î¿Î¹ÏÏηÏα/ÎεÏÏομÎÏÎµÎ¹ÎµÏ Ïε\n"
+" λειÏοÏ
Ïγία για ÏÏοÏÏÏημÎνοÏ
Ï Î¸Î± ÏαθοÏν αν αλλάξεÏε ÏÎ¹Ï Î±ÏλÎÏ ÏÏ
θμίÏειÏ\n"
+"μεÏÎÏειÏα. ÎÏίÏηÏ, αÏ
ÏÎÏ Î¿Î¹ αλλαγÎÏ ÎÎΠανÏικαÏοÏÏÏίζονÏαι αÏÏ ÏιÏ\n"
+"εÏιλογÎÏ ÏÏην καÏÏÎλα ΣÏ
νδÏ
αÏμÎνÏν εÏιλογÏν.\n"
+"(αÏ
ÏÏ Ïο μήνÏ
μα μÏοÏεί να αÏενεÏγοÏοιηθÎι αÏÏ Ïο Î¼ÎµÎ½Î¿Ï \"ÎÏÏείο\")"
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "ΣÏάλμα!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "ÎÏοθήκεÏ
Ïη ÏÏν ÏÏ
θμίÏεÏν ÏοÏ
Spring ÏÏιν Ïην Îξοδο;"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "ÎÏαιÏείÏαι εÏιβεβαίÏÏη"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "ΡÏ
θμίÏÎµÎ¹Ï Spring (για ÏÏοÏÏÏημÎνοÏ
Ï)"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "ΡÏ
θμίÏÎµÎ¹Ï Spring (αÏλή λειÏοÏ
Ïγία)"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "ÎÏοθήκεÏ
Ïη ÏÏ
θμίÏεÏν"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "ÎÏαναÏοÏά αÏÏικÏν ÏÏ
θμίÏεÏν"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "ÎÏενεÏγοÏοίηÏη ÏÏοειδοÏοίηÏÎ·Ï Î»ÎµÎ¹ÏοÏ
ÏÎ³Î¯Î±Ï Î³Î¹Î± ÏÏοÏÏÏημÎνοÏ
Ï"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "ÎξοδοÏ"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "ÎÏÎ»Ï (λιγÏÏεÏÎµÏ ÎµÏιλογÎÏ)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "Îια ÏÏοÏÏÏημÎνοÏ
Ï (ÏÎ»ÎµÏ Î¿Î¹ εÏιλογÎÏ)"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "ΠεÏί"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "ÎÏαÏή"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "Îνεία"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "ÎναÏοÏά ÏÏάλμαÏοÏ"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "ÎαÏάÏÏαÏη"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Îοήθεια"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "ÎÏαναÏοÏά ÎÎΩΠÏÏν ÏÏ
θμίÏεÏν ÏÏÎ¹Ï Î±ÏÏικÎÏ ÏιμÎÏ;"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Î¥ÏÏδειξη"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr "Το SpringSettings είναι Îνα γÏaÏÎ¹ÎºÏ ÎºÎλÏ
ÏÎ¿Ï Î³Î¹Î± Ïη ÏÏθμιÏη ÏοÏ
Spring"
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr "Kloot"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "The SpringLobby team"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr "everyone reporting bugs/suggestions"
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+"ΠεÏαÏμογή ÏÏοκάλεÏε Îνα μοιÏαίο ÏÏάλμα και θα ÏεÏμαÏιÏÏεί\n"
+"Îεν είναι δÏ
ναÏή η δημιοÏ
Ïγία αναÏοÏÎ¬Ï ÏÏοβλήμαÏοÏ\n"
+"\n"
+"ÏαÏÎ±ÎºÎ±Î»Ï ÎµÎ½ÎµÏγοÏοιείÏÏε Ïο wxUSE_DEBUGREPORT"
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "ÎÏίÏιμο ÏÏάλμα"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "ÎιαδÏομή για Ïη μονάδα unitsync"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+"Î¥ÏήÏξε κάÏοιο ÏÏÏβλημα καÏά Ïην ανάκÏηÏη ÏÏν ÏÏ
θμίÏεÏν ÏαÏ.\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÎµÎ»ÎξÏε αν η ÏαÏακάÏÏ Î´Î¹Î±Î´Ïομή είναι ÏÏÏÏή.\n"
+"ÎεÏά εÏιλÎξÏε Ïο \"ΧÏήÏη αÏ
ÏÎ®Ï ÏÎ·Ï Î´Î¹Î±Î´ÏομήÏ\" για να\n"
+"ÏÏοÏÏαθήÏεÏε ξανά."
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "ΧÏήÏη αÏ
ÏÎ®Ï ÏÎ·Ï Î´Î¹Î±Î´ÏομήÏ"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "unitsync.so ÏÏο Linux, unitsync.dll ÏÏα Windows"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "ΡÏ
θμίÏÎµÎ¹Ï Î´Î¹Î±Î´ÏομήÏ"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "ÎÏιλÎξÏε μια μονάδα unitsync"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Îλα Ïα αÏÏεία"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+"ÎδÏναÏη η ÏÏÏÏÏÏη ÏÎ·Ï Î¼Î¿Î½Î¬Î´Î±Ï unitsync.\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÎµÏιβεβαιÏÏÏε Ïη ÏÏθμιÏη unitsync.\n"
+"Î ÎκδοÏη ÏοÏ
Spring ÏÏÎÏει να είναι ÏοÏ
λάÏιÏÏον 0.76,\n"
+"διαÏοÏεÏικά αÏ
ÏÏ Î¸Î± αÏοÏÏÏει Ïε κάθε ÏεÏίÏÏÏÏη."
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "Ïαμηλή"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "μεÏαία"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "Ï
Ïηλή"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "ÏÎ¿Î»Ï Ïαμηλή"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "ÏÎ¿Î»Ï Ï
Ïηλή"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "ÎδÏ
ναμία εκκίνηÏÎ·Ï ÏοÏ
εξ οÏιÏÎ¼Î¿Ï ÏεÏιηγηÏή"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "ÎδÏ
ναμία εκκίνηÏÎ·Ï ÏεÏιηγηÏή. Το URL είναι: "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "ÎδÏ
ναμία εκκίνηÏÎ·Ï ÏεÏιηγηÏή."
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "ÎδÏναÏη η ÏÏοÏÏÎλαÏη ÏÏν ÏÏ
θμίÏεÏν ÏαÏ.\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "ÎδÏναÏη η αÏοθήκεÏ
Ïη, Ïο unitsync δεν ÏοÏÏÏθηκε ÏÏÏÏά"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "ΣÏάλμα SpringSettings"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "ÎÏιλογÎÏ ÎÏοÏ
"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "ÎνάλÏ
Ïη ÎθÏνηÏ"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+"Îν μια εÏιλογή ÏÏειάζεÏαι ÎµÎ¹Î´Î¹ÎºÏ hardware για να λειÏοÏ
ÏγήÏει,\n"
+"θα αναÏÎÏεÏαι ÏÏην Ï
ÏÏδειξη."
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "ΠοιÏÏηÏα ÎεÏοÏ"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "ÎνάλÏ
Ïη Ïε bit"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "ÎÏιλογÎÏ Î Î¿Î¹ÏÏηÏÎ±Ï Î£ÏεδίαÏηÏ"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "ÎÏιλογÎÏ ÎειÏοÏ
ÏÎ³Î¯Î±Ï Video"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "ÎÏιλογÎÏ ÎξομάλÏ
νÏÎ·Ï ÎÏνιÏν"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr "Î Î¯Î½Î±ÎºÎ±Ï ÎάθοÏ
Ï (Î-Buffer)"
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "ÎÏίÏεδα λεÏÏομεÏειÏν ÏÏεδίαÏηÏ"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+"ÎÏ
ÏÎÏ Î¿Î¹ εÏιλογÎÏ ÏÎ±Ï Î´Î¯Î½Î¿Ï
ν Ïη δÏ
ναÏÏÏηÏα να ελÎγξεÏε ÏονδÏικά\n"
+"Ïη ÏÏεδίαÏη ÏοÏ
Spring. ÎοκιμάÏÏε να ÏÎ¹Ï ÎµÎ»Î±ÏÏÏÏεÏε για μεγαλÏÏεÏη\n"
+"ÏαÏÏÏηÏα. ΠλήÏÎ·Ï ÎλεγÏÎ¿Ï Ïε ÏÎ»ÎµÏ ÏÎ¹Ï ÏÏ
θμίÏÎµÎ¹Ï ÎµÎ¯Î½Î±Î¹ διαθÎÏÎ¹Î¼Î¿Ï ÏÏη\n"
+"λειÏοÏ
Ïγία \"Îια ÏÏοÏÏÏημÎνοÏ
Ï\", κάνεÏε κλικ είÏε ÏÏο κοÏ
μÏί ÏÏα\n"
+"δεξιά είÏε ÏÏηÏιμοÏοιήÏÏε Ïο Î¼ÎµÎ½Î¿Ï \"ÎειÏοÏ
Ïγία\" ÏÏην μÏάÏα μενοÏ.\n"
+"ÎÏοÏείÏε να εÏιÏÏÏÎÏεÏε Ïε αÏ
Ïή Ïη λειÏοÏ
Ïγία κάθε ÏÏιγμή\n"
+"εÏιλÎγονÏÎ±Ï \"ÎÏλή λειÏοÏ
Ïγία\" αÏÏ Ïο Î¼ÎµÎ½Î¿Ï \"ÎειÏοÏ
Ïγία\". Îν\n"
+"ÏÏ
νανÏήÏεÏε μηνÏμαÏα λάθοÏ
Ï ÏÏεÏικά με Ïα γÏαÏικά καθÏÏ\n"
+"εκÏελείÏαι Ïο Spring μÏοÏεί να ÏÏειαÏÏεί να αÏενεÏγοÏοιήÏεÏε\n"
+"κάÏÎ¿Î¹ÎµÏ ÎµÏιλογÎÏ ÏÏη λειÏοÏ
Ïγία για ÏÏοÏÏÏημÎνοÏ
Ï.\n"
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "ΠοιÏÏηÏα γÏαÏικÏν"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "ÎεÏÏομÎÏεια γÏαÏικÏν"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "ÎνάλÏ
Ïη οθÏνηÏ"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "Îλλαγή Ïε λειÏοÏ
Ïγία για ÏÏοÏÏÏημÎνοÏ
Ï"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (ÏÏÎÏοÏ
Ïα)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+"ÎÎÏει ÏÎ»ÎµÏ ÏÎ¹Ï ÎµÏιλογÎÏ ÏοιÏÏηÏÎ±Ï Ïε εξ οÏιÏÎ¼Î¿Ï ÏιμÎÏ Î±Î½Î¬Î»Î¿Î³Î± με Ïην εÏιλογή "
+"ÏαÏ."
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+"ÎÎÏει ÏÎ»ÎµÏ ÏÎ¹Ï ÎµÏιλογÎÏ Î»ÎµÏÏομεÏειÏν Ïε εξ οÏιÏÎ¼Î¿Ï ÏιμÎÏ Î±Î½Î¬Î»Î¿Î³Î± με Ïην "
+"εÏιλογή ÏαÏ."
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+"ÎÏιλÎξÏε Ïην ανάλÏ
Ïη ÏοÏ
ÏαιÏιάζει ÏÏην/ÏÏÎ¹Ï Î¿Î¸ÏÎ½ÎµÏ ÏαÏ.\n"
+"ΠεÏιλογή αναλÏÏÎ·Ï Î´Î¹ÏÎ»Î®Ï Î¿Î¸ÏÎ½Î·Ï Î¸Î± ενεÏγοÏοιήÏει αÏ
ÏÏμαÏα Ïη λειÏοÏ
Ïγία "
+"διÏÎ»Î®Ï Î¿Î¸ÏνηÏ.\n"
+"Îν η καÏάλληλη ανάλÏ
Ïη δεν είναι διαθÎÏιμη μÏοÏείÏε να Ïην οÏίÏεÏε με Ïο "
+"ÏÎÏι ÏÏη\n"
+"λειÏοÏ
Ïγία για ÏÏοÏÏÏημÎνοÏ
Ï. Σ'αÏ
Ïή Ïην ÏεÏίÏÏÏÏη ÏαÏÎ±ÎºÎ±Î»Ï ÎµÏικοινÏνήÏÏε με "
+"Ïον\n"
+"δημιοÏ
ÏÎ³Ï ÏοÏ
ÏÏογÏάμμαÏÎ¿Ï ÏÏÏε αÏ
Ïή να ÏÏοÏÏεθεί Ïε μελλονÏικÎÏ ÎµÎºÎ´ÏÏειÏ."
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "ΠληÏοÏοÏίεÏ"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+"ÎÎÏονÏÎ±Ï Ïη μÏάÏα ÏÏο 0 θα εξαιÏÎÏει αÏ
Ïή Ïη\n"
+"λειÏοÏ
Ïγία αÏÏ ÏÎ¹Ï ÎµÎ½Î±Î»Î»Î±Î³ÎÏ ÎµÎ½ÏÏÏ ÏοÏ
ÏαιÏνιδιοÏ."
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "ΤαÏÏÏηÏÎµÏ ÎÏλιÏÎ·Ï (ÏονÏίκι & ÏληκÏÏολÏγιο)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "ÎÏÏική ÎειÏοÏ
Ïγία ÎάμεÏαÏ"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "ÎÎ»Î»ÎµÏ ÎµÏιλογÎÏ Î´Î¹ÎµÏαÏήÏ"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "ÎεγÎθÏ
νÏη"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+"ÎÏοÏείÏε να ÏÏÏεÏε Ïο εικονίδιο ήλιοÏ
/bot για να οÏίÏεÏε Ïην αÏÏική θÎÏη.\n"
+" ΠηγαίνεÏε Ïο ÏονÏίκι ÏÎ¬Î½Ï Î±ÏÏ Ïο εικονίδιο για να αλλάξεÏε μεÏιά, ÏÏ
μμαÏία "
+"και εÏίδομα."
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "Î ÏοÏθήκη bot..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "ÎεαÏήÏ"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "ΤÏ
ÏÎ±Î¯ÎµÏ Î±ÏÏικÎÏ Î¸ÎÏειÏ"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- ÎÏιλÎξÏε κάÏοιο --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "ΣÏάλμα ÏÏθμιÏÎ·Ï ÏαιÏνιδιοÏ"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Î ÏÎÏει να εÏιλÎξεÏε Îναν ÏάÏÏη ÏÏÏÏα."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+"ΣÏ
νÎÏιÏη ÏÏÏÎ¯Ï ÏÏοÏθήκη bot ÏÏÏÏα;\n"
+" Το ÏαιÏνίδι θα ÏελειÏÏει εξαιÏεÏικά γÏήγοÏα.\n"
+" "
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "Îεν ÏÏοÏÏÎθηκε Bot"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "Îεν μÏοÏείÏε να εκκινήÏεÏε ξανά Ïο Spring ÏÏο αÏ
ÏÏ Î®Î´Î· ÏÏÎÏει."
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Îεια "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+".\n"
+"ΦαίνεÏαι ÏÏÏ ÏÏηÏιμοÏοιείÏε για ÏÏÏÏη ÏοÏά Ïο SpringLobby. ÎÏÏ Î¼Î±Î½ÏÎÏει "
+"κάÏÎ¿Î¹ÎµÏ Î±ÏÏικÎÏ ÏÏ
θμίÏÎµÎ¹Ï ÏοÏ
ÏιÏÏÎÏ
Ï ÏÏÏ Î¸Î± δοÏ
λÎÏοÏ
ν για ÏαÏ, αλλά ÎºÎ±Î»Ï Î¸Î± "
+"ήÏαν να ÏÎ¹Ï ÎµÎ»ÎγξεÏε, είδικα ÏÎ¹Ï ÏÏ
θμίÏÎµÎ¹Ï ÏοÏ
Spring.\n"
+"\n"
+"ÎÏαν είÏÏε ÎÏοιμοι, εÏιλÎξÏε ΣÏνδεÏη Ïε ÎξÏ
ÏηÏεÏηÏή αÏÏ Ïο Î¼ÎµÎ½Î¿Ï ÎÏÏείο και "
+"αÏολαÏÏÏε Ïο Spring :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "ÎαλÏÏ ÎλθαÏε"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "ÎαθÏλοÏ
"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "ΡÏ
θμίÏÎµÎ¹Ï Î´Î¹Î±Î´ÏομήÏ"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+"ΠεÏαÏμογή ÏÏοκάλεÏε Îνα μοιÏαίο ÏÏάλμα και θα ÏεÏμαÏιÏÏεί\n"
+"ΠδημιοÏ
Ïγία αναÏοÏÎ¬Ï ÏÏοβλήμαÏÎ¿Ï Î´ÎµÎ½ είναι δÏ
ναÏή\n"
+"\n"
+"ÏαÏÎ±ÎºÎ±Î»Ï ÏÏηÏιμοÏοιήÏÏε μια ÎκδοÏη ÏÎ·Ï Î¼Î¿Î½Î¬Î´Î±Ï wxWidgets\n"
+"ÏοÏ
να Ï
ÏοÏÏηÏίζει Ïο wxUSE_DEBUGREPORT"
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "ÎνοιÏÏή ΣÏ
νομιλία"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "ÎίÏÏα μαÏÏν"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "ÎναζήÏηÏη"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "ÎκÏελÎÏιμο ÏοÏ
Spring"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "ΤοÏοθεÏία"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "ÎναζήÏηÏη"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "Îονάδα UnitSync"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "ÎÏ
ÏÏμαÏη ΡÏθμιÏη"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "ÎÏιλÎξÏε Ïο εκÏελÎÏιμο ÏοÏ
Spring"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Îονάδα"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr "ÎÏιλÎξÏε Ïη μονάδα UnitSync"
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+"ÎÏοÏÏ
Ïία ÏÏÏÏÏÏÎ·Ï Î¼Î¿Î½Î¬Î´Î±Ï UnitSync.\n"
+"\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÎµÏιβεβαιÏÏÏε Ïη ÏÏθμιÏη UnitSync."
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr "Îαμία ενÎÏγεια (ÏÏηÏιμοÏοιήÏÏε Ïο μÏνο αν είÏÏε αÏÏλÏ
Ïα ÏίγοÏ
Ïοι)"
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid "Data dir wizard"
+msgstr "ÎδηγÏÏ ÏÏÏÏÎ·Ï ÏοÏάÏ"
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "ÎÏιλογή ÏακÎλοÏ
"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+"ÎάÏι Ïήγε ÏÏÏαβά καÏά Ïη δημιοÏ
Ïγία ÏÏν ÏακÎλÏν\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï Î´Î·Î¼Î¹Î¿Ï
ÏγήÏÏε με Ïο ÏÎÏι ÏοÏ
Ï ÏαÏακάÏÏ ÏάκελοÏ
Ï:"
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Îήξη ÏÏÏνοÏ
ÏÏνδεÏηÏ"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "ÎγνÏÏÏη αÏάνÏηÏη αÏÏ Ïον εξÏ
ÏηÏεÏηÏή"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+"ÎÏοÏÏ
Ïία ÎιάÏÏηÏÎ·Ï NAT, αÏ
Ïή η μάÏη μÏοÏεί να μην δοÏ
λÎÏει για ÎÏÎ±Ï Î® άλλοÏ
Ï "
+"ÏαίκÏεÏ."
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "ÎÏιθμοί"
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "MB ÏÏάλθηκαν"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "MB ÏÏάλθηκαν"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "ÎαÏάÏÏαÏη:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s αÏοÏÏÎλονÏαι"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s λαμβάνονÏαι"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "ΧÏÏÎ½Î¿Ï (δεÏ
.)"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "μÎÎ³ÎµÎ¸Î¿Ï (MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "ÎÏ
ÏÏμαÏη εκκίνηÏη ÏÏ
ÏÏήμαÏÎ¿Ï Î»Î®ÏεÏν"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr "καÏά Ïη ÏÏνδεÏη ÏÏο lobby (εξ οÏιÏμοÏ)"
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr "καÏά Ïην εκκίνηÏη"
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "ÏειÏοκίνηÏα"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr "ÎναÏÏολή ÏÏην εκκίνηÏη ÏαιÏνιδιοÏ"
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "ΠαÏÏη ÏλÏν ÏÏν λήÏεÏν"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr "ΠεÏιοÏιÏμÏÏ ÏαÏÏ
ÏήÏÏν:"
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "ÎÏοÏÏολή (KB/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "ÎήÏη (KB/s)"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "ÎÏιθμοί"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "ÎÎγιÏÏη ÏαÏÏÏηÏα αÏοÏÏÎ¿Î»Î®Ï Ïε KB/sec(-1 για άÏειÏο)"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "ÎÎγιÏÏη ÏαÏÏÏηÏα λήÏÎ·Ï Ïε KB/sec(-1 για άÏειÏο)"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "ΧÏήÏη θÏÏÎ±Ï Î³Î¹Î± ÏÏ
νδÎÏÎµÎ¹Ï torrent"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "ÎÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ ÏαÏ
ÏÏÏÏονÏν ÏÏ
νδÎÏεÏν"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+#, fuzzy
+msgid "Torrent system failure"
+msgstr "ÎÏ
ÏÏμαÏη εκκίνηÏη ÏÏ
ÏÏήμαÏÎ¿Ï Î»Î®ÏεÏν"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "ÎÏδικÏÏ ÎµÎ¾Ï
ÏηÏεÏηÏή"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr "ÎÏιÏÏ
ÏÎ®Ï ÎµÎ³Î³ÏαÏή."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "ÎÏιÏÏ
ÏÎ®Ï ÎµÎ³Î³ÏαÏή"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "ΠεγγÏαÏή αÏÎÏÏ
Ïε, ο λÏÎ³Î¿Ï Î®Ïαν:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"ÎιαδÏομή ÏεÏιηγηÏή είναι: "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "ΣÏάλμα βοήθειαÏ"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "ΠληκÏÏολογήÏÏε /help Ïε Îνα ÏαÏάθÏ
Ïο ÏÏ
νομιλίαÏ"
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "Îοήθεια ενÏολÏν SpringLobby."
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "ÎενικÎÏ ÎµÎ½ÏολÎÏ:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - ÎÏίζει Ïην καÏάÏÏαÏη ÏÎ±Ï ÏÏ Î¼Î±ÎºÏÏ
ά αÏÏ Ïον Ï
ÏολογιÏÏή."
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - ÎÏίζει Ïην καÏάÏÏαÏη ÏÎ±Ï ÏÏ ÎºÎ¿Î½Ïά ÏÏον Ï
ÏολογιÏÏή."
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+" \"/changepassword ÏαλιÏÏκÏδικÏÏ Î½ÎοÏκÏδικÏÏ\" - Îλλάζει Ïον κÏÎ´Î¹ÎºÏ ÏοÏ
"
+"ÏÏÎÏονÏÎ¿Ï Î»Î¿Î³Î±ÏιαÏμοÏ."
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - ÎμÏανίζει μια λίÏÏα ÏÏν ενεÏγÏν καναλιÏν."
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+" \"/help [θÎμα]\" - ÎάλÏε θÎμα αν θÎλεÏε Ïιο ÏÏ
γκεκÏιμÎÎ½ÎµÏ ÏληÏοÏοÏÎ¯ÎµÏ Î³Î¹Î± "
+"μια ενÏολή."
+
+#: src/ui.cpp:495
+#, fuzzy
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+" \"/join κανάλι [κÏδικÏÏ] [,κανάλι2 [κÏδικÏÏ2]]\" - ÎίÏÎ¿Î´Î¿Ï Ïε κανάλι."
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - ΣÏ
νÏνÏ
μο ÏοÏ
/join."
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" - ÎμÏανίζει ÏÏÏο ÏÏÏνο ÎÏεÏε ÏεÏάÏει μÎÏα Ïε ÏαιÏνίδια."
+
+#: src/ui.cpp:498
+#, fuzzy
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+" \"/msg ÏνομαÏÏήÏÏη [κείμενο]\" - ÏÏÎλνει Îνα prive μήνÏ
μα Ïε κάÏοιον "
+"ÏÏήÏÏη."
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - ÎμÏανίζει μια λίÏÏα ÏÏν ενεÏγÏν καναλιÏν."
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - ΣÏ
νÏνÏ
μο ÏοÏ
/join."
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename νÎοÏεÏ
δÏνÏ
μο\" - Îλλάζει Ïο ÏεÏ
δÏνÏ
μο ÏÎ±Ï Ïε νÎοÏεÏ
δÏνÏ
μο."
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+" \"/sayver\" - ÎναÏÎÏει Ïην ÎκδοÏη ÏοÏ
SpringLobby ÏοÏ
ÏÏηÏιμοÏοιείÏε ÏÏην "
+"ÏÏ
νομιλία."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr " \"/testmd5 κείμενο\" - ÎÏιÏÏÏÎÏει Îνα md5-b64 hash ÏοÏ
κειμÎνοÏ
."
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - ÎμÏάνιÏη ÏÎ·Ï ÎκδοÏÎ·Ï SpringLobby ÏοÏ
ÏÏηÏιμοÏοιείÏε."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "ÎνÏολÎÏ ÏÏ
νομιλίαÏ:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+" \"/me δÏαÏÏηÏιÏÏηÏα\" - ΣÏÎλνει Îνα μήνÏ
μα δÏαÏÏηÏιÏÏηÏÎ±Ï Ïε ÏÏÏ
λ IRC (/e)."
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+"Îν δεν μÏοÏείÏε να θÏ
μηθείÏε κάÏοια ενÏολή, ÏηγαίνεÏε ÏÏο #springlobby και "
+"δοκιμάÏÏε να Ïην ÏληκÏÏολογήÏεÏε εκεί :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "ÎανÎνα θÎμα δεν ÎÏει γÏαÏÏεί ακÏμα."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Το θÎμα \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+"\" δεν βÏÎθηκε. ΠληκÏÏολογήÏÏε \"/help topics\" για μια λίÏÏα ÏÏν διαθÎÏιμÏν "
+"θεμάÏÏν."
+
+#: src/ui.cpp:609
+#, fuzzy
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Îεν βÏÎθηκε η ÎκδοÏη ÏοÏ
Spring αÏÏ Ïη μονάδα UnitSync.\n"
+"\n"
+"Τα δικÏÏ
ακά ÏαιÏνίδια θα αÏενεÏγοÏοιηθοÏν."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Τα δικÏÏ
ακά ÏαιÏνίδια θα αÏενεÏγοÏοιηθοÏν."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "ÎγνÏÏÏη αÏάνÏηÏη αÏÏ Ïον εξÏ
ÏηÏεÏηÏή"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Îήξη ÏÏÏνοÏ
ÏÏνδεÏηÏ"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "καμία ενεÏγή ÏÏ
νομιλία ανοιÏÏή."
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d ÏÏήÏÏεÏ)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "ÎήνÏ
μα εξÏ
ÏηÏεÏηÏή"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "Î ÏÏÎÏοÏ
Ïα μάÏη ÎκλειÏε αÏÏ Ïον οικοδεÏÏÏÏη."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "ΠμάÏη ÎκλειÏε"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Îι ÏÏ
θμίÏÎµÎ¹Ï ÏοÏ
Spring μάλλον δεν είναι ÏÏÏÏÎÏ.\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÎµÏιβεβαιÏÏÏε ÏÎ¹Ï ÏÏιν ÏÏοÏÏαθήÏεÏε\n"
+"να ÏαίξεÏε δικÏÏ
ακά."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "ΣÏάλμα ÏÏ
θμίÏεÏν Spring"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"ΠαÏοÏ
ÏιάÏÏηκε ÏÏÏβλημα καÏά Ïον ÎλεγÏο για νÎα ÎκδοÏη.\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÏÏοÏÏαθήÏÏε αÏγÏÏεÏα.\n"
+"Îν Ïο ÏÏÏβλημα ÏαÏαμÎνει, ÏαÏÎ±ÎºÎ±Î»Ï ÏÏηÏιμοÏοιήÏÏε Ïο Îοηθεία -> ÎναÏοÏά "
+"Î ÏοβλήμαÏÎ¿Ï Î³Î¹Î± να αναÏÎÏεÏε αÏ
ÏÏ Ïο ÏÏÏβλημα."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Î ÎκδοÏή ÏαÏ: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "ΤελεÏ
Ïαία ÎκδοÏη: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"Î ÎκδοÏη ÏοÏ
SpringLobby δεν είναι ενημεÏÏμÎνη.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Îη ÎνημεÏÏμÎνο"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Îη ÎνημεÏÏμÎνο"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+#, fuzzy
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"ΠαÏοÏ
ÏιάÏÏηκε ÏÏÏβλημα καÏά Ïον ÎλεγÏο για νÎα ÎκδοÏη.\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÏÏοÏÏαθήÏÏε αÏγÏÏεÏα.\n"
+"Îν Ïο ÏÏÏβλημα ÏαÏαμÎνει, ÏαÏÎ±ÎºÎ±Î»Ï ÏÏηÏιμοÏοιήÏÏε Ïο Îοηθεία -> ÎναÏοÏά "
+"Î ÏοβλήμαÏÎ¿Ï Î³Î¹Î± να αναÏÎÏεÏε αÏ
ÏÏ Ïο ÏÏÏβλημα."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, fuzzy, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"ΠαÏοÏ
ÏιάÏÏηκε ÏÏÏβλημα καÏά Ïον ÎλεγÏο για νÎα ÎκδοÏη.\n"
+"ΠαÏÎ±ÎºÎ±Î»Ï ÏÏοÏÏαθήÏÏε αÏγÏÏεÏα.\n"
+"Îν Ïο ÏÏÏβλημα ÏαÏαμÎνει, ÏαÏÎ±ÎºÎ±Î»Ï ÏÏηÏιμοÏοιήÏÏε Ïο Îοηθεία -> ÎναÏοÏά "
+"Î ÏοβλήμαÏÎ¿Ï Î³Î¹Î± να αναÏÎÏεÏε αÏ
ÏÏ Ïο ÏÏÏβλημα."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "ÎαθÏλοÏ
"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "ÎÏιÏήμανÏη"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "ΣÏνδεÏη ÏÏην ίδια μάÏη"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+#, fuzzy
+msgid "no action at all"
+msgstr "καμία ενεÏγή ÏÏ
νομιλία ανοιÏÏή."
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "ΠάνÏα"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "ΨεÏ
δÏνÏ
μο"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "ÎÎοÏ"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "ÎÏÏάÏιοÏ"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "ÎÎÏοÏ"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Î Î¬Î½Ï ÏοÏ
μÎÏοÏ
"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "ΠεÏειÏαμÎνοÏ"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "ÎδιαίÏεÏα ÏεÏειÏαμÎνοÏ"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "ÎεÏεÏάνοÏ"
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "άγνÏÏÏο"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "Î ÏοÏθήκη Bot..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "ÎιαγÏαÏή ÎογαÏιαÏÎ¼Î¿Ï Î§ÏήÏÏη"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "ÎÏ
ÏÏÏία"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Î ÎκδοÏη Spring ÏαÏ"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "MB ÏÏάλθηκαν"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "ÎκδοÏη νÎοÏ
αÏÏείοÏ
"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "ÎκÏÏÏÏη"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "ÎνάλÏ
Ïη ÎθÏνηÏ"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "ÎεαÏÎÏ:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "ΠαίκÏεÏ:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Îμάδα"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "ΣÏ
μμαÏία"
+
+#~ msgid "cpu"
+#~ msgstr "ÎÏεξεÏγαÏÏήÏ"
+
+#~ msgid "Test firewall"
+#~ msgstr "ÎλεγÏÎ¿Ï ÏείÏοÏ
Ï ÏÏοÏÏαÏίαÏ"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Î ÏÏ
νομιλία ÎκλειÏε."
+
+#, fuzzy
+#~ msgid "Game is in progress."
+#~ msgstr "ÎήÏÎµÎ¹Ï Ïε εξÎλιξη: "
+
+#, fuzzy
+#~ msgid "Game is in progress and full."
+#~ msgstr "ÎήÏÎµÎ¹Ï Ïε εξÎλιξη: "
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "ÎÏιλογÎÏ Î§Î¬ÏÏη"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "ÎÏιλ. ÏÏο ÏαιÏνίδι"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "ÎήÏη ολοκληÏÏθηκε"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "ÎÏοÏÏνδεÏη"
+
+#~ msgid "Debug"
+#~ msgstr "ÎκÏÏαλμάÏÏÏη"
+
+#~ msgid "Debug Options"
+#~ msgstr "ÎÏιλογÎÏ ÎκÏÏαλμάÏÏÏηÏ"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "ΠαίκÏεÏ:"
+
+#~ msgid "status"
+#~ msgstr "ÎαÏάÏÏαÏη"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "ÎÏιλογή ÏακÎλοÏ
"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "ÎνÎÏγεια"
+
+#~ msgid "a"
+#~ msgstr "θ"
+
+#~ msgid "p"
+#~ msgstr "Ï"
+
+#~ msgid "m"
+#~ msgstr "μ"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "ο"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "Τιμή εκÏÏÏ Î¿ÏίÏν.\n"
+#~ " ΠαÏÎ±ÎºÎ±Î»Ï ÎµÎ¹ÏάγεÏε Îναν ακÎÏαιο αÏÏ 0 εÏÏ 100."
+
+#~ msgid ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+#~ msgstr ""
+#~ "Î¥ÏάÏÏοÏ
ν δÏο ή ÏεÏιÏÏÏÏεÏα bot ÏÏην ίδια ομάδα. ÎÏειδή δεν ξÎÏοÏ
ν να "
+#~ "μοιÏάζονÏαι, αÏ
ÏÏ Î´ÎµÎ½ θα λειÏοÏ
ÏγήÏει."
+
+#~ msgid "Bot team sharing."
+#~ msgstr "ÎιαμοιÏαÏμÏÏ Î¿Î¼Î¬Î´Î±Ï bot."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "ÎÏιθμÏÏ ÏαικÏÏν"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "ΠληÏοÏοÏÎ¯ÎµÏ ÎºÎ±Î½Î±Î»Î¹Î¿Ï"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Το θÎμα \""
+
+#~ msgid "Use smart scrolling"
+#~ msgstr "ΧÏήÏη ÎξÏ
ÏÎ½Î·Ï ÎºÏλιÏηÏ"
+
+#~ msgid "_SERVER"
+#~ msgstr "_ÎÎΥΠÎΡÎΤÎΤÎΣ"
+
+#~ msgid "Download failed"
+#~ msgstr "ÎÏοÏÏ
Ïία λήÏηÏ"
+
+#, fuzzy
+#~ msgid ""
+#~ "You need to download the map to be able to watch this replay.\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Î ÏÎÏει να καÏεβάÏεÏε Ïον ÏάÏÏη ÏÏιν να ÏÏ
μμεÏάÏÏεÏε Ïε αÏ
ÏÏ Ïο ÏαιÏνίδι.\n"
+#~ "\n"
+
+#~ msgid "Unit detail"
+#~ msgstr "ÎεÏÏομÎÏÎµÎ¹ÎµÏ Î¼Î¿Î½Î¬Î´Ïν"
+
+#~ msgid "only on/off available at this time"
+#~ msgstr "μÏνο ενεÏγÏ/ανενεÏÎ³Ï Î³Î¹Î± Ïην ÏÏα"
+
+#~ msgid "Global sound volume"
+#~ msgstr "Îενική ÎνÏαÏη ήÏοÏ
"
+
+#~ msgid "mark to be able to use"
+#~ msgstr "εÏιλÎξÏε για να μÏοÏείÏε να Ïα ÏÏηÏιμοÏοιείÏε"
+
+#~ msgid "Send debug info to console"
+#~ msgstr "ÎÏοÏÏολή ÏληÏοÏοÏιÏν εκÏÏαλμάÏÏÏÎ·Ï ÏÏην κονÏÏλα"
+
+#~ msgid "if disabled these will only be logged"
+#~ msgstr "αν αÏενεÏγοÏοιηθεί θα καÏαγÏάÏονÏαι μονάÏα"
+
+#~ msgid ""
+#~ "You're using a wxwidgets library of the 2.6.x series\n"
+#~ " battle filtering, advanced gui and joining/hosting games using nat "
+#~ "traversal\n"
+#~ " won't be available"
+#~ msgstr ""
+#~ "ΧÏηÏιμοÏοιείÏε wxWidgets ÏÎ·Ï ÏειÏÎ¬Ï 2.6.\n"
+#~ " Το ÏιλÏÏάÏιÏμα μαÏÏν, η ÏÏοÏÏÏημÎνη διεÏαÏή και η ÏÏ
μμεÏοÏή/Ïιλοξενία "
+#~ "ÏαιÏνιδιÏν\n"
+#~ " με ÏÏήÏη ÎιάÏÏηÏÎ·Ï Nat δεν θα είναι διαθÎÏιμεÏ."
+
+#~ msgid "Missing Functionality"
+#~ msgstr "ÎλλιÏÎ®Ï ÎειÏοÏ
ÏγικÏÏηÏα"
+
+#, fuzzy
+#~ msgid ""
+#~ "Do you want to download OTA content?\n"
+#~ "You need this to be able to play TA based mods.\n"
+#~ "You need to own a copy of Total Annihilation do legally download it."
+#~ msgstr ""
+#~ "ÎÎλεÏε να καÏεβάÏÏ Ïα βαÏικά αÏÏεία ÏοÏ
OTA (Original Total "
+#~ "Annihilation);\n"
+#~ "Îα ÏÏειαÏÏοÏν αν θελήÏεÏε να ÏαίξεÏε mod ÏοÏ
βαÏίζονÏαι Ï'αÏ
ÏÏ.\n"
+#~ "ΧÏειάζεÏε να είÏÏε νÏÎ¼Î¹Î¼Î¿Ï ÎºÎ¬ÏοÏÎ¿Ï ÏοÏ
Total Annihilation για να είναι "
+#~ "νÏμιμη η λήÏη ÏοÏ
Ï."
+
+#~ msgid "Download OTA content?"
+#~ msgstr "ÎήÏη βαÏικÏν αÏÏείÏν OTA;"
+
+#, fuzzy
+#~ msgid "Create a spring directory in my documents folder"
+#~ msgstr ""
+#~ "ÎημιοÏ
Ïγία ÏοÏ
ÏακÎλοÏ
.spring ÏÏον αÏÏÎ¹ÎºÏ ÎºÎ±Ïάλογο ÏÎ±Ï (ÏÏ
νιÏÏάÏαι)"
+
+#, fuzzy
+#~ msgid "Do nothing"
+#~ msgstr "ÎιάÏÏηÏη"
+
+#~ msgid "Create a folder in a custom path (you'll get prompted for the path)"
+#~ msgstr "ÎημιοÏ
Ïγία ÏακÎλοÏ
Ïε άλλη διαδÏομή (θα εÏÏÏηθείÏε για Ïη διαδÏομή)"
+
+#~ msgid "I have already a SpringData folder, i want to browse manually for it"
+#~ msgstr ""
+#~ "ÎÏÏ Î®Î´Î· Îναν Ïάκελο δεδομÎνÏν ÏοÏ
Spring, θÎÎ»Ï Î½Î± Ïον αναζηÏήÏÏ Î¼Îµ Ïο ÏÎÏι"
+
+#, fuzzy
+#~ msgid ""
+#~ "Looks like you don't have yet a user SpringData folder structure\n"
+#~ "What would you like to do? (leave default choice if you don't know what "
+#~ "this is for)"
+#~ msgstr ""
+#~ "ΦαίνεÏαι ÏÏÏ Î´ÎµÎ½ ÎÏεÏε Ïάκελο δεδομÎνÏν ÏοÏ
Spring\n"
+#~ "Τι θα θÎλαÏε να κάνÏ; (αÏήÏÏε Ïην αÏÏική εÏιλογή αν δεν γνÏÏίζεÏε ÏεÏί "
+#~ "ÏÎ¯Î½Î¿Ï ÏÏÏκειÏαι αÏ
ÏÏ)"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "ÎγνÏÏÏη αÏάνÏηÏη αÏÏ Ïον εξÏ
ÏηÏεÏηÏή"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "ÎκÏÏÏ Î£ÏνδεÏηÏ."
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "ÎÏ
ÏÏ Ïο ÏαιÏνίδι ÏÏηÏιμοÏοιεί ÎιάÏÏηÏη NAT ÏοÏ
ÏμÏÏ Î´ÎµÎ½ Ï
ÏοÏÏηÏίζεÏαι αÏÏ "
+#~ "Ïη ÏειÏά 2.6 ÏοÏ
WxWidgets.\n"
+#~ "\n"
+#~ "Îεν θα μÏοÏÎÏεÏε να ÏÏ
μμεÏάÏÏεÏε Ïε αÏ
Ïή Ïην μάÏη.\n"
+#~ "ΠαÏÎ±ÎºÎ±Î»Ï ÎµÎ½Î·Î¼ÎµÏÏÏÏε Ïο wxWidgets ÏÏη ÏειÏά 2.8 ή νεÏÏεÏη για να "
+#~ "ενεÏγοÏοιηθεί η ÎιάÏÏηÏη NAT."
+
+#, fuzzy
+#~ msgid "Only the host can change the game options"
+#~ msgstr "ÎÏνο ο οικοδεÏÏÏÏÎ·Ï Î¼ÏοÏεί να κλειδÏÏει Ïο ÏαιÏνίδι."
+
+#~ msgid "Only the host can start the battle."
+#~ msgstr "ÎÏνο ο οικοδεÏÏÏÏÎ·Ï Î¼ÏοÏεί να εκκινήÏει Ïη μάÏη."
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "ÎÏνο ο οικοδεÏÏÏÏÎ·Ï Î¼ÏοÏεί να κλειδÏÏει Ïο ÏαιÏνίδι."
+
+#~ msgid "Only the host can lock the game."
+#~ msgstr "ÎÏνο ο οικοδεÏÏÏÏÎ·Ï Î¼ÏοÏεί να κλειδÏÏει Ïο ÏαιÏνίδι."
+
+#, fuzzy
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "ÎÏνο ο οικοδεÏÏÏÏÎ·Ï Î¼ÏοÏεί να κλειδÏÏει Ïο ÏαιÏνίδι."
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Îη ÎγκÏ
ÏÎ¿Ï ÎµÎ¾Ï
ÏηÏεÏηÏήÏ/θÏÏα ή Ïνομα εξÏ
ÏηÏεÏηÏή."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "ÎνεÏγά κανάλια ÏÏ
νομιλίαÏ:"
+
+#~ msgid "no rank"
+#~ msgstr "ÏÏÏÎ¯Ï Î²Î±Î¸Î¼Ï"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "ÎίÏÏα μαÏÏν"
+
+#~ msgid "Only the host can fix player colours."
+#~ msgstr "ÎÏνο ο οικοδεÏÏÏÏÎ·Ï Î¼ÏοÏεί να διοÏθÏÏει Ïα ÏÏÏμαÏα ÏÏν ÏαιÏÏÏν."
+
+#~ msgid "Select all"
+#~ msgstr "ÎÏιλογή ÏλÏν"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d ÏÏήÏÏεÏ)"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Îεν εÏιλÎÏθηκε mod."
+
+#, fuzzy
+#~ msgid "you can also enter a ';' seperated list of usernames:"
+#~ msgstr "ÎιÏάγεÏε λίÏÏα ÏÏÏιÏμÎνη με \";\""
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Îη ÎγκÏ
ÏÎ¿Ï Î±ÏιθμÏÏ"
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "ΣÏνÏομη ÏεÏιγÏαÏή ÏοÏ
ÏαιÏνιδιοÏ, θα εμÏανιÏÏεί ÏÏη λίÏÏα μαÏÏν."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "ÎÏιλÎξÏε Ïο mod ÏοÏ
θÎλεÏε να ÏαίξεÏε."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "ÎανονικÏ"
+
+#~ msgid "NAT traversal to use. Experimental support."
+#~ msgstr "ΤÏÏÎ¿Ï ÎιάÏÏηÏÎ·Ï NAT ÏÏÎ¿Ï ÏÏήÏη. ΠειÏαμαÏική Ï
ÏοÏÏήÏιξη."
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "ΣÏάλμα UnitSync"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "ΣÏ
νεÏίÏÏε αν Ïεθάνει ο ÎιοικηÏήÏ"
+
+#~ msgid "End if commander dies"
+#~ msgstr "ΤεÏμαÏιÏμÏÏ Î±Î½ Ïεθάνει ο ÎιοικηÏήÏ"
+
+#~ msgid "Lineage mode"
+#~ msgstr "ÎειÏοÏ
Ïγία καÏαγÏγήÏ"
+
+#~ msgid "End condition"
+#~ msgstr "ΣÏ
νθήκη ÏεÏμαÏιÏμοÏ"
+
+#~ msgid "Resources"
+#~ msgstr "Î ÏÏοι"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Î ÏοÏÏÏηÏα μεÏάλλοÏ
με Ïην οÏοία ξεκινάει ο κάθε ÏαίκÏηÏ."
+
+#~ msgid "Start Energy"
+#~ msgstr "ÎÏÏική ÎνÎÏγεια"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Î ÏοÏÏÏηÏα ενÎÏÎ³ÎµÎ¹Î±Ï Î¼Îµ Ïην οÏοία ξεκινάει ο κάθε ÏαίκÏηÏ."
+
+#~ msgid "Max units"
+#~ msgstr "ÎÏιο μονάδÏν"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "Το μÎγιÏÏο ÏÎ»Î®Î¸Î¿Ï Î¼Î¿Î½Î¬Î´Ïν ανά ÏαίκÏη."
+
+#~ msgid "Limit d-gun"
+#~ msgstr "ΠεÏιοÏιÏμÏÏ D-Gun"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "ΦανÏάÏμαÏα κÏιÏίÏν"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "ΣÏαδιακά μειοÏμενη ÏαÏαγÏγή μεÏάλλοÏ
"
+
+#~ msgid "This chat is exclusively for participants of this battle."
+#~ msgstr "Î ÏÏ
ζήÏηÏη είναι αÏοκλειÏÏικά για ÏοÏ
Ï ÏÏ
μμεÏÎÏονÏÎµÏ ÏÏη μάÏη."
+
+#~ msgid "Cannot add bot, maximum number of players already reached."
+#~ msgstr "ÎδÏναÏη η ÏÏοÏθήκη bot, ο μÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ ÏαιÏÏÏν ÎÏει ÏÏαÏθεί."
+
+#~ msgid "Max players reached"
+#~ msgstr "ΠμÎγιÏÏÎ¿Ï Î±ÏιθμÏÏ ÏαιÏÏÏν ÎÏει ÏÏαÏθεί"
+
+#~ msgid "Autoconnect last server"
+#~ msgstr "ÎÏ
ÏÏμαÏη ÏÏνδεÏη ÏÏον ÏελεÏ
Ïαίο εξÏ
ÏηÏεÏηÏή"
+
+#~ msgid "Save to:"
+#~ msgstr "ÎÏοθήκεÏ
Ïη Ïε:"
+
+#~ msgid "Browse..."
+#~ msgstr "ÎναζήÏηÏη..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "ÎÏιλÎξÏε Îναν Ïάκελο"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "ÎÏιλογÎÏ Î§Î¬ÏÏη/Mod"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "H ÎκδοÏη ÏοÏ
SpringLobby είναι ενημεÏÏμÎνη!\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "ÎνημεÏÏμÎνο"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "ÎÎλεÏε να εÏιÏκεÏθείÏε μια Ïελίδα με Î¿Î´Î·Î³Î¯ÎµÏ ÏÏεÏικά με Ïο ÏÏÏ Î½Î± "
+#~ "καÏεβάÏεÏε Ïην ÏελεÏ
Ïαία ÎκδοÏη;"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "ΠεÏιοÏιÏμÏÏ D-Gun"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr ""
+#~ "ÎÏενεÏγοÏοιεί Ïο D-Gun ÏοÏ
ÎιοικηÏή ÏÏαν βÏίÏκεÏÏε μακÏÏ
ά αÏÏ Ïην αÏÏική "
+#~ "θÎÏη ÏαÏ"
+
+#~ msgid "Ghosted Buildings"
+#~ msgstr "ΦανÏάÏμαÏα ÎÏιÏίÏν"
+
+#~ msgid ""
+#~ "Enemy buildings will leave a ghost image on the map after losing LoS on "
+#~ "them"
+#~ msgstr ""
+#~ "Τα εÏθÏικά κÏίÏια θα αÏήνοÏ
ν αÏοÏÏÏÏμα ÏÏον ÏάÏÏη αÏÎ¿Ï ÏάÏεÏε οÏÏική "
+#~ "εÏαÏή μαζί ÏοÏ
Ï"
+
+#~ msgid "Diminishing MM"
+#~ msgstr "ÎειοÏμενοι MM"
+
+#~ msgid ""
+#~ "Efficiency of MetalMakers will progressively reduce as much as you build "
+#~ "them"
+#~ msgstr ""
+#~ "ΠαÏοÏελεÏμαÏικÏÏηÏα ÏÏν ÎαÏαÏκεÏ
αÏÏÏν ÎεÏάλλοÏ
θα μειÏνεÏαι ÏÏοοδεÏ
Ïικά "
+#~ "καθÏÏ ÏοÏ
Ï ÏÏίζεÏε"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "ΣÏ
νθήκη ΤÎλοÏ
Ï Î Î±Î¹ÏνιδιοÏ"
+
+#~ msgid ""
+#~ "The condition that will end the game\n"
+#~ "0: when all units will be destroyed\n"
+#~ "1: when the commander will be destroyed\n"
+#~ "2: lineage mode (see option 1, but given away units will still die"
+#~ msgstr ""
+#~ "Î ÏÏ
νθήκη ÏοÏ
θα ÏεÏμαÏίÏει Ïο ÏαιÏνίδι\n"
+#~ "0: ÏÏαν καÏαÏÏÏαÏοÏν ÏÎ»ÎµÏ Î¿Î¹ μονάδεÏ\n"
+#~ "1: ÏÏαν καÏαÏÏÏαÏεί ο ÎιοικηÏήÏ\n"
+#~ "2: λειÏοÏ
Ïγία καÏαγÏÎ³Î®Ï (ÏÏÏÏ Ïο 1, αλλά ο δÏÏιÏμÎÎ½ÎµÏ Î¼Î¿Î½Î¬Î´ÎµÏ Î¸Î± "
+#~ "ÏεθαίνοÏ
ν)"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "ÎÏίζει Ïην ÏοÏÏÏηÏα μεÏάλλοÏ
με Ïην οÏοία θα αÏÏίζοÏ
ν οι ÏαίκÏεÏ"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "ÎÏίζει Ïην ÏοÏÏÏηÏα ενÎÏÎ³ÎµÎ¹Î±Ï Î¼Îµ Ïην οÏοία θα αÏÏίζοÏ
ν οι ÏαίκÏεÏ"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "ÎÎγιÏÏÎ¿Ï ÎÏιθμÏÏ ÎονάδÏν"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "ÎÏίζει Ïον μÎγιÏÏο αÏÎ¹Î¸Î¼Ï Î¼Î¿Î½Î¬Î´Ïν ÏοÏ
μÏοÏοÏν να ÏÏίζοÏ
ν οι ÏαίκÏεÏ"
+
+#~ msgid "Reset"
+#~ msgstr "ÎÏαναÏοÏά"
+
+#~ msgid ""
+#~ "You have bots that are not assingled to startpositions. In the current "
+#~ "version of spring you are only allowed to use start positions positioning "
+#~ "them freely is not allowed.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "Îεν οÏίÏÏηκαν αÏÏικÎÏ Î¸ÎÏÎµÎ¹Ï Î³Î¹Î± κάÏοια bot. ΣÏην ÏÏÎÏοÏ
Ïα ÎκδοÏη ÏοÏ
"
+#~ "Spring εÏιÏÏÎÏεÏαι μÏνο η ÏÏήÏη ÏÏν αÏÏικÏν ÏεÏιοÏÏν και ÏÏι η ελεÏθεÏη "
+#~ "ÏοÏοθÎÏηÏη ÏοÏ
Ï.\n"
+#~ "\n"
+#~ "ÎÏ
ÏÏ Î¸Î± διοÏθÏθεί Ïε εÏÏμενη ÎκδοÏη ÏοÏ
Spring."
+
+#~ msgid ""
+#~ "You are not using consecutive start position numbers.\n"
+#~ "\n"
+#~ "In the current version of spring you are not allowed to skip any "
+#~ "startpositions. You have to use all consecutive position.\n"
+#~ "\n"
+#~ "Example: if you have 2 bots + yourself you have to use start positions "
+#~ "1,2,3 not 1,3,4 or 2,3,4.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "Îεν ÏÏηÏιμοÏοιείÏε διαδοÏικοÏÏ Î±ÏιθμοÏÏ Î±ÏÏικÏν θÎÏεÏν.\n"
+#~ "\n"
+#~ "ΣÏην ÏÏÎÏοÏ
Ïα ÎκδοÏη ÏοÏ
Spring δεν εÏιÏÏÎÏεÏαι η ÏαÏάκαμÏη οÏοιÏνδήÏοÏε "
+#~ "αÏÏικÏν θÎÏεÏν. Îα ÏÏειαÏÏεί να ÏÎ¹Ï ÏÏηÏιμοÏοιήÏεÏε διαδοÏικά.\n"
+#~ "\n"
+#~ "ΠαÏάδειγμα: αν ÎÏεÏε 2 bot & Ïον εαÏ
ÏÏ ÏαÏ, θα ÏÏÎÏει να ÏÏηÏιμοÏοιήÏεÏε "
+#~ "ÏÎ¹Ï Î±ÏÏικÎÏ Î¸ÎÏÎµÎ¹Ï 1, 2, 3 και ÏÏι ÏÎ¹Ï 1, 3, 4 ή 2, 3, 4.\n"
+#~ "\n"
+#~ "ÎÏ
ÏÏ Î¸Î± διοÏθÏθεί Ïε εÏÏμενη ÎκδοÏη ÏοÏ
Spring."
+
+#~ msgid "Spring directory"
+#~ msgstr "ÎαÏÎ¬Î»Î¿Î³Î¿Ï Spring"
+
+#~ msgid "Default location."
+#~ msgstr "Îξ οÏιÏμοÏ"
+
+#~ msgid "The Spring executable is installed in the default location"
+#~ msgstr "Το εκÏελÎÏιμο ÏοÏ
Spring είναι εγκαÏεÏÏημÎνο ÏÏην εξ οÏιÏÎ¼Î¿Ï Î¸ÎÏη"
+
+#~ msgid "Specify the location of the Spring executable"
+#~ msgstr "Î ÏοÏδιοÏίÏÏε Ïη θÎÏη ÏοÏ
εκÏελÎÏιμοÏ
ÏοÏ
Spring"
+
+#~ msgid "The UnitSync library is installed in the default location"
+#~ msgstr "Πμονάδα UnitSync είναι εγκαÏεÏÏημÎνη ÏÏην εξ οÏιÏÎ¼Î¿Ï Î¸ÎÏη"
+
+#~ msgid ""
+#~ "SpringLobby is unable to determine your Spring version from the UnitSync "
+#~ "library.\n"
+#~ "\n"
+#~ "You might want to take another look at your settings."
+#~ msgstr ""
+#~ "Το SpringLobby δεν μÏÏÏεÏε να ÏÏοÏδιοÏίÏει Ïην ÎκδοÏη ÏοÏ
Spring μÎÏÏ ÏÎ·Ï "
+#~ "Î¼Î¿Î½Î¬Î´Î±Ï UnitSync.\n"
+#~ "\n"
+#~ "ΠαÏÎ±ÎºÎ±Î»Ï ÎµÏιβεβαιÏÏÏε Ïη ÏÏθμιÏη UnitSync."
+
+#~ msgid ""
+#~ "Unitsync loading was aborted because your spring data directory is not "
+#~ "writable. Please check."
+#~ msgstr ""
+#~ "Î ÏÏÏÏÏÏη ÏοÏ
Unitsync διακÏÏηκε εÏειδή ο ÏÎ¬ÎºÎµÎ»Î¿Ï Î´ÎµÎ´Î¿Î¼ÎνÏν ÏοÏ
Spring "
+#~ "δεν ειναι εγγÏάξιμοÏ. ΠαÏÎ±ÎºÎ±Î»Ï ÎµÏιβεβαιÏÏÏε."
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "δεν Ï
ÏοÏÏηÏίζεÏαι αÏÏ Ïον εξÏ
ÏηÏεÏηÏή lobby ο οÏÎ¿Î¹Ï Î±ÏαιÏεί ÎκδοÏη"
+
+#~ msgid ""
+#~ "This is the SpringLobby channel, please report any problems you are "
+#~ "having with SpringLobby here and the friendly developers will help you."
+#~ msgstr ""
+#~ "ÎÏ
ÏÏ ÎµÎ¯Î½Î±Î¹ Ïο κανάλι ÏοÏ
SpringLobby, ÏαÏÎ±ÎºÎ±Î»Ï Î±Î½Î±ÏÎÏεÏε ÏÏ
ÏÏν ÏÏοβλήμαÏα "
+#~ "ÏοÏ
ÎÏεÏε με Ïο SpringLobby ÎµÎ´Ï ÎºÎ±Î¹ οι δημιοÏ
Ïγοί θα ÏÎ±Ï Î²Î¿Î·Î¸Î®ÏοÏ
ν "
+#~ "ÏÏÏθÏ
μα. ΣημείÏÏη: Το κανάλι είναι αγγλÏÏÏνο!"
diff --git a/po/en at boldquot.header b/po/en at boldquot.header
new file mode 100644
index 0000000..fedb6a0
--- /dev/null
+++ b/po/en at boldquot.header
@@ -0,0 +1,25 @@
+# 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.
+#
diff --git a/po/en at quot.header b/po/en at quot.header
new file mode 100644
index 0000000..a9647fc
--- /dev/null
+++ b/po/en at quot.header
@@ -0,0 +1,22 @@
+# 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.
+#
diff --git a/po/en_US.gmo b/po/en_US.gmo
new file mode 100644
index 0000000..2f3f44e
Binary files /dev/null and b/po/en_US.gmo differ
diff --git a/po/en_US.po b/po/en_US.po
new file mode 100644
index 0000000..29929fe
--- /dev/null
+++ b/po/en_US.po
@@ -0,0 +1,6405 @@
+# English translations for SpringLobby package.
+# Copyright (C) 2009 The SpringLobby team
+# This file is distributed under the same license as the SpringLobby package.
+# René Milk <koshi at springlobby.info>, 2009.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby 0.0.1.10393-170-g3bd11a5\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2009-02-18 13:57+0100\n"
+"Last-Translator: Ren Milk <koshi at springlobby.info>\n"
+"Language-Team: English\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ASCII\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Add bot"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Nickname:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "AI:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Choose the AI library to use with this bot."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr "property"
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+msgid "value"
+msgstr "value"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Cancel"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Add Bot"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "No AI bots found in your Spring installation."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "No bot-libs found"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Accept Agreement"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Do you accept the terms of this agreement?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Yes"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "No"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "Autobalance players into teams"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "Method"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "Divide ranks evenly"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Random"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Clans"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "None"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Fair"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Always"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Number of players"
+
+#: src/autobalancedialog.cpp:56
+msgid "Auto select"
+msgstr "Auto select"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Description"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Map"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Host"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Spectators:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+msgid "Players"
+msgstr "Players"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Map"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Download &map"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "Download m&od"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Spectators:"
+
+#: src/battlelistctrl.cpp:361
+msgid "Active Players:"
+msgstr "Active Players:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Host:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Status:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Locked"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Passworded"
+
+#: src/battlelistfilter.cpp:122
+msgid "Highlighted only"
+msgstr "Highlighted only"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Rank Limit:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Description:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Started"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Full"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Open"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Player:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "All"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Map:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Only maps i have"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Max.Player:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Only mods i have"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Spectator:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Players:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+msgid " Filter "
+msgstr " Filter "
+
+#: src/battlelisttab.cpp:142
+msgid "Activated"
+msgstr "Activated"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+msgid " Battle infos "
+msgstr " Battle infos "
+
+#: src/battlelisttab.cpp:152
+#, fuzzy
+msgid "0 battles displayed"
+msgstr "Files displayed"
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Host new..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "Join"
+
+#: src/battlelisttab.cpp:182
+#, fuzzy, c-format
+msgid "%d battles displayed"
+msgstr "%u files displayed"
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Not Online."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "Hosting is disabled due to the incompatible version you're using"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Spring error"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Already in a battle"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "Battle not started beacuse the mod you selected could not be found. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Error starting battle."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "No maps found"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Already in a battle"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Already in a battle"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to and join this one?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "Do you want me to take you to the download page?"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Mod not available"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Map not available"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Battle password"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Enter password"
+
+#: src/battlemaptab.cpp:69
+msgid "Select"
+msgstr "Select"
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Option"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Value"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Size"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Windspeed"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Tidal strength"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravity"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Extractor radius"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Max metal"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Fixed"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Choose in game"
+
+#: src/battlemaptab.cpp:103
+msgid "Chose before game"
+msgstr "Chose before game"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Startpositions"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Unit restrictions"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Allowed units"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Units in this list will be available in the game."
+
+#: src/battleoptionstab.cpp:76
+msgid "Disable selected units."
+msgstr "Disable selected units."
+
+#: src/battleoptionstab.cpp:80
+msgid "Re-enable selected units."
+msgstr "Re-enable selected units."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr "<<"
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Enable all units."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Restricted units"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Units in this list will not be available in the game."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Unit restrictions"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Nickname"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Team"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Ally"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Resource Bonus"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Side"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Set color"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Set Resource Bonus"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Spectator"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Kick"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Ring"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Please enter a value between 0 and 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Add bot"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Oman"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Spectator"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Player:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Host"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Client"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Replays"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Not ready"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "Enable v-sync"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr "Enter name"
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr "Manage Presets"
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Rename.."
+
+#: src/battleroommmoptionstab.cpp:62
+#, fuzzy
+msgid "Load..."
+msgstr "Lock..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Save a set of options."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Save"
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+msgid "Save a set of options."
+msgstr "Save a set of options."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Delete"
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+msgid "Delete a set of options."
+msgstr "Delete a set of options."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "Set default"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr "Use the current set of options as mod's default."
+
+#: src/battleroommmoptionstab.cpp:86
+#, fuzzy
+msgid "Mod Options"
+msgstr "Options"
+
+#: src/battleroommmoptionstab.cpp:91
+#, fuzzy
+msgid "Map Options"
+msgstr "Options"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "not available"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+#, fuzzy
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr "Cannot save an options set without a name."
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "error"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr "Enter preset name"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr "Cannot save an options set without a name."
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr "Pick an existing option set from the list"
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Set delete preset"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+msgid "Set mod default preset"
+msgstr "Set mod default preset"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr "Players with the same team number share control of their units."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr "Players with the same ally number work together to achieve victory."
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "Select a color to identify your units in-game"
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "Select your faction"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "Spectate (watch) the battle instead of playing"
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "I'm ready"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "Click this if you are content with the battle settings."
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Color"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Leave"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "Leave the battle and return to the battle list"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "Start the battle"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr "Player Management"
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr "Various functions to make team games simplers to setup"
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Add Bot..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "Add a computer-controlled player to the game"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr "Autolock on start"
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "Prevent additional players from joining the battle"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr "Autohost"
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Auto select"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr "Lock Balance"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr "When activated, prevents anyone but the host to change team and ally"
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "Enable v-sync"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Ring"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Not ready"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "Force start?"
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr "Balance alliances"
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr "Automatically balance players into two or more alliances"
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "Fix colours"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "Make player colors unique"
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr "Balance teams"
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr "Load battle preset"
+
+#: src/battleroomtab.cpp:259
+msgid "Save"
+msgstr "Save"
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr "Delete"
+
+#: src/battleroomtab.cpp:269
+msgid "Set default"
+msgstr "Set default"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr "Activate an element to quickly change it"
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "Boxes"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr "Pick"
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "Continue"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "End"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr "Lineage"
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "Map does not exist."
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Some players are not ready yet.\n"
+"Ring these players?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Not ready"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "Set default"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr "Edit auto-joined channels"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr "Double click to join"
+
+#: src/channel/channelchooser.cpp:30
+msgid "Find channel:"
+msgstr "Find channel:"
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr "Choose channels to join"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "channel"
+
+#: src/channel/channellistctrl.cpp:29
+msgid "# users"
+msgstr "# users"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr "Displaying %d out of %d channels"
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Session Closed at ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "Log function is disabled until restart SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Log Warning"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Colors and font"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Use system colors"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Background"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Action"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Highlight"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Join/Leave"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "My messages"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Server"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Client"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Error"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Timestamp"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Notification"
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Font:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "default"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Select..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Behavior"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr "Play notification sounds"
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Chat logs"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Save chat logs"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Highlight words"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Words to highlight in chat:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "enter a ; seperated list"
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr "Additionally play sound/flash titlebar "
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr "channel_"
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d users)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "right click for options (like autojoin)"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Send"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr "Disable text appending (workaround for autoscroll)"
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr ""
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+#, fuzzy
+msgid "Clear"
+msgstr "Clans"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "Auto join this channel"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "Display Join/Leave Messages"
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr "Show mute list"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Channel info"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Set topic..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Channel message..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Lock..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Unlock"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Register..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Unregister"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "On"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Off"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "Is on?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Spam protection"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Disconnect"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Reconnect"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Remove..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Change password..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Set access..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Accounts"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "Broadcast..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Admin"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Mute User"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Open Chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "Join same battle"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Ingame time"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "Retrieve IP and Smurfs"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Mute..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Mute for 5 minutes"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Mute for 10 minutes"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Mute for 30 minutes"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Mute for 2 hours"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Mute for 1 day"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Unmute"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Mute"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Kick..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Ban..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Unban"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "Slap!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Op"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "DeOp"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Command: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" params: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "channel"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "battle"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "server"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " joined the "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " left the "
+
+#: src/chatpanel.cpp:1029
+msgid " ** Channel topic:"
+msgstr " ** Channel topic:"
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr " ** Set by "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat closed."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Are you sure you want to paste %d lines?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Flood warning"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " You have SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " You are not in channel or channel does not exist."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " User is offline."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Sent: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ChanServ error"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ is not in this channel."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "What should be the new topic?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Message:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "Lock channel..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "What should the new password be?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "Unlock Channel"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Are you sure you want to unlock this channel?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ is not on this server."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Register Channel"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Who should be appointed founder of this channel?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "Unregister Channel"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "Are you sure you want to unregister this channel?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Remove User Acount"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "What user account do you want to remove today?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Remove Account"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Are you sure you want to remove the account "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Change User Acount Password"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "What user account do you want to change the password for?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "What would be the new password?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Not Implemented"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "Broadcast Message"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "Message to be broadcasted:"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "You don't have the mod "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . Please download it first"
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr "Mod unavailable"
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "This battle is password protected, enter the password."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Mute User"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "For how many minutes should the user be muted?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Kick User"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Reason:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Kick user"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "Mute user"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Duration:"
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr "couldn't add user"
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Connect to lobby server"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Password"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "Remember password"
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "Autoconnect next time"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Login"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Register"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Nick"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Invalid port."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Invalid port"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Invalid host/port."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Invalid host"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+
+#: src/connectwindow.cpp:293
+msgid "Invalid nickname"
+msgstr "Invalid nickname"
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Registration failed."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "United Arab Emirates"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afghanistan"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua and Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albania"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Armenia"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Netherlands Antilles"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antarctica"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentina"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "American Samoa"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Austria"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Australia"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azerbaijan"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosnia and Herzegovina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladesh"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgium"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgaria"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahrain"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermuda"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunei Darussalam"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Bolivia"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brazil"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamas"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhutan"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Bouvet Island"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Belarus"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Canada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "Cocos (Keeling Islands)"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "Central African Republic"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Congo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Switzerland"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Cote D'Ivoire (Ivory Coast)"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Cook Islands"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Cameroon"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "China"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Colombia"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Cuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Cape Verde"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Christmas Island"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Cyprus"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "Czech Republic"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Germany"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Djibouti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Denmark"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominica"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Dominican Republic"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Algeria"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ecuador"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estonia"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Egypt"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Western Sahara"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritrea"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Spain"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Ethiopia"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finland"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fiji"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Falkland Islands (Malvinas)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Micronesia"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Faroe Islands"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "France"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "France, Metropolitan"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Georgia"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "French Guiana"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Greenland"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambia"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guinea"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadeloupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Equatorial Guinea"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Greece"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "S. Georgia and S. Sandwich Isls."
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guinea-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guyana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Heard and McDonald Islands"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Croatia (Hrvatska)"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Hungary"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonesia"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Ireland"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israel"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "India"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "British Indian Ocean Territory"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Iraq"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Iran"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Iceland"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Italy"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamaica"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Jordan"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japan"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Kenya"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "Kyrgyzstan (Kyrgyz Republic)"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Cambodia"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Comoros"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "Saint Kitts and Nevis"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Korea (North) (People's Republic)"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Korea (South) (Republic)"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuwait"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Cayman Islands"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kazakhstan"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Lebanon"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Saint Lucia"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Liberia"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Lithuania"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Luxembourg"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Latvia"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Libya"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Morocco"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldova"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Montenegro"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagascar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Marshall Islands"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Macedonia"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Myanmar"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongolia"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macau"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Northern Mariana Islands"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinique"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauritania"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Mauritius"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Maldives"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Mexico"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malaysia"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mozambique"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "Namibia"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "New Caledonia"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Niger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Norfolk Island"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigeria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nicaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Netherlands"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norway"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Neutral Zone (Saudia Arabia/Iraq)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "New Zealand"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Oman"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panama"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Peru"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "French Polynesia"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua New Guinea"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Philippines"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pakistan"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Poland"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "St. Pierre and Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Pitcairn"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Puerto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugal"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palau"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Qatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Reunion"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Romania"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Serbia"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Russian Federation"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Rwanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Saudi Arabia"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Solomon Islands"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychelles"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Sudan"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Sweden"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapore"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "St. Helena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slovenia"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Svalbard and Jan Mayen Islands"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Slovakia (Slovak Republic)"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Leone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somalia"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Suriname"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "Sao Tome and Principe"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "Soviet Union (former)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "El Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Syria"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Swaziland"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Turks and Caicos Islands"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Chad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "French Southern Territories"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Thailand"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tajikistan"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Tokelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistan"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunisia"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "East Timor"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Turkey"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad and Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Taiwan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tanzania"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ukraine"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "United Kingdom (Great Britain)"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "US Minor Outlying Islands"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "United States"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Uzbekistan"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Vatican City State (Holy See)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "Saint Vincent and The Grenadines"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Virgin Islands (British)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Virgin Islands (US)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Viet Nam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Wallis and Futuna Islands"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Yemen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Yugoslavia"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "South Africa"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Zambia"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zaire"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Full country name not found)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "System informations"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "Application verbose log"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Last generated spring launching script"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+msgid "Name"
+msgstr "Name"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr "Type"
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr "Hash"
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr "Search and download files"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr "Files displayed"
+
+#: src/filelister/filelistdialog.cpp:58
+msgid "Download selected"
+msgstr "Download selected"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr "%u files displayed"
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr "unknown hash "
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+msgid "Remove"
+msgstr "Remove"
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr "Remove an existing group"
+
+#: src/groupoptionspanel.cpp:61
+msgid "Rename.."
+msgstr "Rename.."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr "Rename an existing group"
+
+#: src/groupoptionspanel.cpp:70
+msgid "Add New.."
+msgstr "Add New.."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr "Add new group"
+
+#: src/groupoptionspanel.cpp:84
+msgid "Group Actions"
+msgstr "Group Actions"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr "Notify login/logout"
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr "Notify when users of this group go online or offline"
+
+#: src/groupoptionspanel.cpp:95
+msgid "Ignore Chat"
+msgstr "Ignore Chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr "Ignore anything said in channel by any of the users in this group"
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr "Notify Hosted Battles"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr "Notify when users of this group hosts a battle"
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr "Ignore PM"
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr "Ignore anything said in private chat by any of the users in this group"
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr "Notify Status Change"
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr "Notify when the status of a users in this group changes"
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr "Autokick"
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr "Auto kick any of the users in this group from battles hosted"
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr "Highlight battles and the names of users in this group"
+
+#: src/groupoptionspanel.cpp:134
+msgid "Highlight Color"
+msgstr "Highlight Color"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr "Select highlight color"
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr "Users in group"
+
+#: src/groupoptionspanel.cpp:163
+msgid "Add.."
+msgstr "Add.."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr "Add users to group"
+
+#: src/groupoptionspanel.cpp:170
+msgid "Remove users from group"
+msgstr "Remove users from group"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr "Name of new group:"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr "Add New Group"
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Delete"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Choose in game"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"successfully saved to:\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr "Success"
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "Could not save\n"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+msgid "Default"
+msgstr "Default"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "&Change language"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+#, fuzzy
+msgid "Language"
+msgstr "Lineage"
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Host new battle"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "A short description of the game, this will show up in the battle list."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Description"
+
+#: src/hostbattledialog.cpp:83
+#, fuzzy
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Select the mod to play with."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr "Password needed to join game. Keep empty for no password"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Port"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "UDP port to host game on. Default is 8452."
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "not available"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Number of players"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "The maximum number of players to allow in the battle."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "Hole punching"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "NAT traversal"
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr "NAT traversal to use."
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Minimum Rank needed"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Start hosting the battle."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "You have to select a mod first."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "No mod selected."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"successfully saved to:\n"
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"successfully unzipped in:\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+"\n"
+" unzipping failed, please correct manually"
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr "Could not save\n"
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"to:\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+"\n"
+"Error number: "
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Web Browser"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Default Browser."
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr "Use your system-wide browser preference"
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Specify:"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr "Specify the web browser you want to use"
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Browse"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr "Use a file dialog to find the web browser"
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+#, fuzzy
+msgid "Path"
+msgstr "Watch"
+
+#: src/lobbyoptionstab.cpp:79
+#, fuzzy
+msgid "Use a file dialog to find the editor binary"
+msgstr "Use a file dialog to find the web browser"
+
+#: src/lobbyoptionstab.cpp:90
+msgid "Autoconnect"
+msgstr "Autoconnect"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+"If checked, SpringLobby will automatically log on to the last used server"
+
+#: src/lobbyoptionstab.cpp:92
+msgid "Autoconnect on lobby start"
+msgstr "Autoconnect on lobby start"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr "Report statistics"
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr "report statistics"
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr "Automatic updates"
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr "automatically check for updates"
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr "Tooltips"
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr "Show Tooltips?"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr "Requires SpringLobby restart to take effect."
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr "Tab completion method"
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr "Match exact"
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr "Match nearest"
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Start"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "Choose a web browser executable"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "Choose a web browser executable"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Disconnected from server."
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "Battle list"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "Battleroom"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Options"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+msgid "Unit Restrictions"
+msgstr "Unit Restrictions"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "P2P"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+msgid "General"
+msgstr "General"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr "Groups"
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Restore"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "Apply"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Game"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr "Transfers in progress: "
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "Total Outgoing: "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "Total Incoming: "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "unknown"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "Cancel Download"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "Publish new file"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "Search file"
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Enable LuaUI widgets"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "not available"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "seeding"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr "leeching"
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr "queued"
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "Status: not connected"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "Status: connected"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr "Status: throttled or paused (ingame)"
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "Status: unknown"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "Total Outgoing: %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "Total Incoming: %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Connect..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&Disconnect"
+
+#: src/mainwindow.cpp:133
+msgid "&Save options"
+msgstr "&Save options"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Quit"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "&Join channel..."
+
+#: src/mainwindow.cpp:151
+msgid "Channel &list"
+msgstr "Channel &list"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Open private &chat..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr "&Autojoin channels..."
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&Reload maps/mods"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "Check for new Version"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "SpringSettings"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&About"
+
+#: src/mainwindow.cpp:168
+msgid "&Change language"
+msgstr "&Change language"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&Report a bug..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Documentation"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&File"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Tools"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Help"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr "You need to be connected to server to view channel list"
+
+#: src/mainwindow.cpp:450
+msgid "Not connected"
+msgstr "Not connected"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "Join channel..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Name of channel to join"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Open Private Chat..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Name of user"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+"SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "No maps found"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "Manually &Start Torrent System"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "Manually &Stop Torrent System"
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+"You need to restart SpringLobby for the language change to take effect."
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr "Restart required"
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr "Layout manager"
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr "Enter a profile name"
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr "Which profile fo you want to load?"
+
+#: src/mainwindow.cpp:678
+msgid "Which profile do you want to be default?"
+msgstr "Which profile do you want to be default?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr "Multiplayer"
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr "Singleplayer"
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Save"
+
+#: src/mainwindow.h:184
+msgid "Replays"
+msgstr "Replays"
+
+#: src/mainwindow.h:186
+msgid "Downloads"
+msgstr "Downloads"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr "Metal: %.1f%%"
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Refresh"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Download"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "side:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "ally: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr " Filter "
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Max metal"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Startpositions"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Minimum Rank needed"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "Average"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Spectator"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Random start positions"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Start Position Type"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: chose in game\n"
+"3: chose in the lobby before starting"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Choose in game"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Chose before game"
+
+#: src/mmoptionswrapper.cpp:131
+msgid "List of restricted units"
+msgstr "List of restricted units"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr "Map name"
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "&Save options"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "c"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Any file (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr "Filter settings"
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr "Filesize in KB:"
+
+#: src/playback/playbackfilter.cpp:190
+msgid "Duration (hh:mm:ss):"
+msgstr "Duration (hh:mm:ss):"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Delete"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Mode"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Map name"
+
+#: src/playback/playbacklistctrl.cpp:45
+msgid "Duration"
+msgstr "Duration"
+
+#: src/playback/playbacklistctrl.cpp:46
+msgid "Spring Version"
+msgstr "Spring Version"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize"
+msgstr "Filesize"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "Filesize in KB:"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "File"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr "Watch"
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Lock..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr "Reload list"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Replays"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Save"
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr "Couldn't get your spring versions from any unitsync library."
+
+#: src/playback/playbacktab.cpp:304
+#, fuzzy, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr "Your current installed versions are:"
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Invalid port"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr "Could not delete Replay: "
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr "Filter names"
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr "Enter text filter to filter the online users list"
+
+#: src/selectusersdialog.h:67
+msgid "Select Users"
+msgstr "Select Users"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+msgid " is online"
+msgstr " is online"
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr " is now "
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() failed ! (exception)"
+
+#: src/serverevents.cpp:225
+msgid " just went offline"
+msgstr " just went offline"
+
+#: src/serverevents.cpp:260
+msgid " opened battle "
+msgstr " opened battle "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "Join channel failed"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Could not join channel "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " because: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Server Message"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " has ip=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " does not really support nat traversal"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "You were kicked from the battle!"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "Kicked by Host"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr "Begin mutelist for "
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr " mutelist"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr " indefinite time remaining"
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr " %d minutes remaining"
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr "End mutelist for "
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Download complete"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Notification"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Invalid number"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Not a number"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "Map does not exist."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Activated"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Reconnect"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "Unknown"
+
+#: src/serverevents.cpp:1009
+#, fuzzy
+msgid "Download complete, location is: "
+msgstr "Download complete"
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Download complete"
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "Couldn't launch browser. URL is: "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "Couldn't launch browser."
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr "Scrollwheel speed"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr "Shadow-map size"
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr "Tree view-distance"
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr "sets the maximum distance at which trees will still be rendered"
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr "Terrain detail"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr "higher value = more terrain details"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "Unit LOD distance"
+msgstr "Unit icon distance"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr "higher value = more detailed units"
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr "Grass detail"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr "higher value = more detailed grass"
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr "Ground decals"
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr "Unit icon distance"
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr "Max simultaneous particles"
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "limits how many particles are displayed at the same time"
+
+#: src/settings++/Defs.hpp:233
+#, fuzzy
+msgid "Max nano simultaneous particles"
+msgstr "Max simultaneous particles"
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr "Run full-screen"
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr "run fullscreen or in a window?"
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "Dual-screen mode"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "if you have two monitors you can use both"
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "Enable v-sync"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr "V-Sync on/off"
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr "16-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr "placeholder"
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr "24-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr "Full-scene anti-aliasing samples"
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr "how much anti-aliasing should be applied"
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr "Maximum simultaneous sounds"
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "Master sound volume"
+msgstr "overall sound volume"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "master sound volume"
+msgstr "overall sound volume"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "General sound volume"
+msgstr "overall sound volume"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "general volume relative to master volume"
+msgstr "reply volume relative to global volume"
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr "Unit reply volume"
+
+#: src/settings++/Defs.hpp:273
+#, fuzzy
+msgid "reply volume relative to master volume"
+msgstr "reply volume relative to global volume"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Battleroom"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "battle volume relative to global volume"
+msgstr "reply volume relative to global volume"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "User interface volume"
+msgstr "Unit reply volume"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "ui volume relative to global volume"
+msgstr "reply volume relative to global volume"
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "Shadows (slow)"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr "enable shadows?"
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr "3D trees"
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr "High-resolution clouds"
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr "Dynamic clouds (slow)"
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr "want moving clouds in the sky?"
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr "Reflective units"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr "Never use shaders when rendering SM3 maps"
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr "problems with sm3 maps? enable this"
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr "Enable LuaShaders support"
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr "makes for some cool effects"
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr "Use Pixelbuffer objects"
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr "Compress textures"
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr "High-resolution LOS textures"
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr "smoother Line of Sight overlays"
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr "Draw smooth points"
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr "should points be anti-aliased"
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr "Draw smooth lines"
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr "should lines be anti-aliased"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr "Issue commands on mini-map"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr "Issue orders on the mini-map like you would "
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "Show commands on mini-map"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr "default value is \"on\""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr "Draw icons on mini-map"
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr "Draw markers on mini-map"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr "Mini-map on left (single screen)"
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "left is the default"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr "Mini-map on left (dual screen)"
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr "Simplified mini-map colors"
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "Use less colors"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr "Team-colored nanospray"
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr "Should nano particels be the color of your team?"
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr "Colorized elevation map"
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr "makes differences in height clearer"
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "Show in-game clock"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr "Show in-game player information"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr "Show in-game framerate"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr "Fix rendering on alt-tab"
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr "Do not change if not needed"
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr "Disallow helper AI's"
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr "Enable scroll on window edge"
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr "Scroll the screen when mouse reaches the screen's edge."
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr "Invert Mouse"
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "Inverts the Mouse Y-axis in FPS mode"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr "Use Hardware Cursor"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr "Use native OS mouse cursor (hardware accelerated)"
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr "Overhead camera"
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "set the scroll speed (mouse + keyboard) for this mode"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr "Rotatable overhead camera"
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr "Total war camera"
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr "First person camera"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr "Free camera"
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr "Console verbose level (0=min,10=max)"
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr "How much information should be outputted?"
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr "Catch AI exceptions"
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr "disable for AI debugging"
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "Basic"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr "Reflective"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "Reflective + refractive"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "Dynamic"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr "Bump-mapped"
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr "Invert mouse y-axis"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr "swap up/down with down/up"
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr "Mini-map 3-button mouse support"
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr "if you don't want to able to use that button, disable it here"
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr "Overhead"
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr "Static bird's eye view"
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr "Rotatable overhead"
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr "Same as overhead, but you can rotate around the z-axis"
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr "Total war"
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr "top-view camera, which can be tilted on the X axis"
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "First person"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr "Camera from unit's point of view"
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr "Modify the view anyway you want"
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "screen width"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "screen height"
+
+#: src/settings++/Defs.hpp:413
+msgid "Blur reflection"
+msgstr "Blur reflection"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr "Use depth texture"
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr "enables smoother blending on coastlines"
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr "Shore waves"
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr "Enables shorewaves"
+
+#: src/settings++/Defs.hpp:416
+msgid "Reflection"
+msgstr "Reflection"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr "Turn on water reflections"
+
+#: src/settings++/Defs.hpp:418
+msgid "Reflection texture size"
+msgstr "Reflection texture size"
+
+#: src/settings++/Defs.hpp:419
+msgid "Refraction"
+msgstr "Refraction"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr "Anisotropy"
+
+#: src/settings++/Defs.hpp:429
+msgid "off"
+msgstr "off"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr "screencopy(fast)"
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr "own rendering pass(slow)"
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr "128"
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr "256"
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr "512"
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "Combined Options"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "Render quality / Video mode"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "Render detail"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "UI options"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Audio"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "Error!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "Save Spring settings before exiting?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "Confirmation needed"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "SpringSettings (expert mode)"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "SpringSettings (simple mode)"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "Save settings"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "Reset settings to default values"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "Disable expert mode warning"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "Quit"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "Simple (few options)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "Expert (all options"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "About"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Contact"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "Credits"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "Report a bug"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Mode"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Info/Help"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "Reset ALL settings to default values?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Hint"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr "Kloot"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "The SpringLobby team"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr "everyone reporting bugs/suggestions"
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Critical error"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "Path to unitsync shared library"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "Use this path"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "unitsync.so on linux, unitsync.dll on windows"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "Path settings"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "Choose an unitsync library"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Any File"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "low"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "medium"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "high"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "very low"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "very high"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "can't launch default browser"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "Couldn't launch browser. URL is: "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "Couldn't launch browser."
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "Could not access your settings.\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "Could not save, unitsync not properly loaded"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "SpringSettings Error"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Audio Options"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Screen Resolution"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Water Quality"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "Resolution in bit"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "Render Quality Options"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "Video Mode Options"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "Anti-Aliasing Options"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr "Z-/Depth-Buffer"
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr "Bump-mapped Water"
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "Rendering detail levels"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "Graphics quality"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Graphics detail"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Screen resolution"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "Switch to expert mode"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (current)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+"Sets all quality options to predefined values according to your choice."
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr "Sets all detail options to predefined values according to your choice."
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Info"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "Scroll Speeds (mouse + keyboard)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "Default Camera Mode"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "Misc. UI Options"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "Zoom"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "Add bot..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Spectator"
+
+#: src/singleplayertab.cpp:103
+msgid "Random start positions"
+msgstr "Random start positions"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- Select one --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "Gamesetup error"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "You have to select a map first."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "No Bot added"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "You cannot start a spring instance while another is already running"
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Hi "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Welcome"
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+"By default SpringLobby reports some statistics.\n"
+"You can disable that on options tab --> General."
+
+#: src/springlobbyapp.cpp:172
+msgid "Notice"
+msgstr "Notice"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "Path settings"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Ignore Chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "Autokick"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Find"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "Spring executable"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Location"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Find"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "UnitSync library"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Auto Configure"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "Choose a Spring executable"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Library"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr "Choose UnitSync library"
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid "Data dir wizard"
+msgstr "First time wizard"
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "Choose a folder"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Connection timed out"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Unknown answer from server"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr "line "
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr " , column "
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "numcopies"
+
+#: src/torrentlistctrl.cpp:48
+msgid "MB downloaded"
+msgstr "MB downloaded"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "MB uploaded"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Status:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr "% complete"
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s up"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s down"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "ETA (s)"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "Filesize (MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "Torrent system autostart"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr "at lobby connection (default)"
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr "at lobby start"
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "manual"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr "At game start suspend mode"
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "Pause all torrents"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr "Throttle speeds:"
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "upload (KB/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "download (KB/s)"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "Numbers"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "maximum upload speed in KB/sec(-1 for infinite)"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "maximum download speed in KB/sec (-1 for infinite)"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "port used for torrent connections"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "maximum number of concurrent connections"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr "Torrent system failure"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Server password"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Registration successful,\n"
+"you should now be able to login."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Registration successful"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "Registration failed, the reason was:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"Broser path is: "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "Help error"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "Type /help in a chat box."
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "SpringLobby commands help."
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Global commands:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - Sets your status to away."
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - Resets your away status."
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - Lists currently active channels."
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+
+#: src/ui.cpp:495
+#, fuzzy
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+" \"/join channel [password] [,channel2 [password2]]\" - Join a channel."
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Alias to /join."
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" - Show how much time you have in game."
+
+#: src/ui.cpp:498
+#, fuzzy
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+" \"/msg username [text]\" - sends a private message containing text to "
+"username."
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - Lists currently active channels."
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - Alias to /join."
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename newalias\" - Changes your nickname to newalias."
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " \"/sayver\" - Say what version of springlobby you have in chat."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - Display what version of SpringLobby you have."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Chat commands:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me action\" - Say IRC style action message."
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "No topics written yet."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "The topic \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr "\" was not found. Type \"/help topics\" only for available topics."
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr "Online play is currently disabled."
+
+#: src/ui.cpp:661
+msgid "Disconnected from server."
+msgstr "Disconnected from server."
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Connection timed out"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "no active chat panels open."
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d users)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Server message"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "The current battle was closed by the host."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "Battle closed"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Spring settings error"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr "The selected preset requires the map "
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr "Map missing"
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Your Version: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Latest Version: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? It will be "
+"automatically used next time you launch the lobby again."
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Not up to Date"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Not up to Date"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr "Update complete. The changes will be available next lobby start."
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr "Partial success"
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr "Cannot add user to group"
+
+#: src/useractions.h:11
+msgid "none"
+msgstr "none"
+
+#: src/useractions.h:11
+msgid "highlight"
+msgstr "highlight"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr "notify login/out"
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr "ignore chat"
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr "ignore pm"
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr "autokick"
+
+#: src/useractions.h:12
+msgid "notify hosted battle"
+msgstr "notify hosted battle"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr "notify status change"
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr "no action at all"
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr "highlight user in nick list and battles he participates in"
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr "popup a message box when user logs in/out from the server"
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr "popup a message box when user hosts a new battle"
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr "popup a message box when user changes away status"
+
+#: src/user.cpp:77
+msgid "away"
+msgstr "away"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr "back"
+
+#: src/user.cpp:79
+msgid "ingame"
+msgstr "ingame"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr "back from game"
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "Newbie"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "Beginner"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "Average"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Above average"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "Experienced"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "Highly experienced"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Veteran"
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr "Unknown"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr "Create new group..."
+
+#: src/usermenu.h:29
+msgid "Add to group..."
+msgstr "Add to group..."
+
+#: src/usermenu.h:30
+msgid "Remove from group"
+msgstr "Remove from group"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Autohost"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Spring Version"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "MB downloaded"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "Publish new file"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Cancel"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "Screen Resolution"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Spectators:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "Players"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Team"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Ally"
+
+#~ msgid "cpu"
+#~ msgstr "cpu"
+
+#~ msgid "Test firewall"
+#~ msgstr "Test firewall"
+
+#~ msgid "Relay battle to an Autohost"
+#~ msgstr "Relay battle to an Autohost"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat closed."
+
+#, fuzzy
+#~ msgid "Game is in progress."
+#~ msgstr "Transfers in progress: "
+
+#, fuzzy
+#~ msgid "Game is in progress and full."
+#~ msgstr "Transfers in progress: "
+
+#~ msgid "Chose in game"
+#~ msgstr "Chose in game"
+
+#~ msgid ""
+#~ "No compatible installed spring version has been found, this replay "
+#~ "requires version: %s\n"
+#~ msgstr ""
+#~ "No compatible installed spring version has been found, this replay "
+#~ "requires version: %s\n"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Download selected"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Disconnect"
+
+#~ msgid "Debug"
+#~ msgstr "Debug"
+
+#~ msgid "Debug Options"
+#~ msgstr "Debug Options"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Player:"
+
+#~ msgid "status"
+#~ msgstr "status"
+
+#~ msgid "Choose color"
+#~ msgstr "Choose color"
+
+#~ msgid "Choose color (only first 16 will be saved)"
+#~ msgstr "Choose color (only first 16 will be saved)"
+
+#~ msgid "Grouping size"
+#~ msgstr "Grouping size"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "p"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+
+#~ msgid ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+#~ msgstr ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+
+#~ msgid "Bot team sharing."
+#~ msgstr "Bot team sharing."
+
+#~ msgid ""
+#~ "You have more than 32 players (including spectators) in your battle\n"
+#~ "Spring supports maximum 32"
+#~ msgstr ""
+#~ "You have more than 32 players (including spectators) in your battle\n"
+#~ "Spring supports maximum 32"
+
+#~ msgid "Num players error"
+#~ msgstr "Num players error"
+
+#~ msgid "Channel name"
+#~ msgstr "Channel name"
+
+#~ msgid "topic"
+#~ msgstr "topic"
+
+#~ msgid "Use smart scrolling"
+#~ msgstr "Use smart scrolling"
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Download failed"
+#~ msgstr "Download failed"
+
+#~ msgid ""
+#~ "You need to download the map to be able to watch this replay.\n"
+#~ "\n"
+#~ msgstr ""
+#~ "You need to download the map to be able to watch this replay.\n"
+#~ "\n"
+
+#~ msgid "Unit detail"
+#~ msgstr "Unit detail"
+
+#~ msgid "only on/off available at this time"
+#~ msgstr "only on/off available at this time"
+
+#~ msgid "Global sound volume"
+#~ msgstr "Global sound volume"
+
+#~ msgid "mark to be able to use"
+#~ msgstr "mark to be able to use"
+
+#~ msgid "Send debug info to console"
+#~ msgstr "Send debug info to console"
+
+#~ msgid "if disabled these will only be logged"
+#~ msgstr "if disabled these will only be logged"
+
+#~ msgid "Spring only supports up to 16 different teams"
+#~ msgstr "Spring only supports up to 16 different teams"
+
+#~ msgid ""
+#~ "You're using a wxwidgets library of the 2.6.x series\n"
+#~ " battle filtering, advanced gui and joining/hosting games using nat "
+#~ "traversal\n"
+#~ " won't be available"
+#~ msgstr ""
+#~ "You're using a wxwidgets library of the 2.6.x series\n"
+#~ " battle filtering, advanced gui and joining/hosting games using nat "
+#~ "traversal\n"
+#~ " won't be available"
+
+#~ msgid "Missing Functionality"
+#~ msgstr "Missing Functionality"
+
+#~ msgid ""
+#~ "Do you want to download OTA content?\n"
+#~ "You need this to be able to play TA based mods.\n"
+#~ "You need to own a copy of Total Annihilation do legally download it."
+#~ msgstr ""
+#~ "Do you want to download OTA content?\n"
+#~ "You need this to be able to play TA based mods.\n"
+#~ "You need to own a copy of Total Annihilation do legally download it."
+
+#~ msgid "Download OTA content?"
+#~ msgstr "Download OTA content?"
+
+#~ msgid "Create a spring directory in my documents folder"
+#~ msgstr "Create a spring directory in my documents folder"
+
+#~ msgid "Do nothing"
+#~ msgstr "Do nothing"
+
+#~ msgid "Create a folder in a custom path (you'll get prompted for the path)"
+#~ msgstr "Create a folder in a custom path (you'll get prompted for the path)"
+
+#~ msgid "I have already a SpringData folder, i want to browse manually for it"
+#~ msgstr ""
+#~ "I have already a SpringData folder, i want to browse manually for it"
+
+#~ msgid ""
+#~ "Looks like you don't have yet a user SpringData folder structure\n"
+#~ "What would you like to do? (leave default choice if you don't know what "
+#~ "this is for)"
+#~ msgstr ""
+#~ "Looks like you don't have yet a user SpringData folder structure\n"
+#~ "What would you like to do? (leave default choice if you don't know what "
+#~ "this is for)"
+
+#~ msgid "Disconnected from server"
+#~ msgstr "Disconnected from server"
+
+#~ msgid "Not online"
+#~ msgstr "Not online"
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
diff --git a/po/es.gmo b/po/es.gmo
new file mode 100644
index 0000000..2369510
Binary files /dev/null and b/po/es.gmo differ
diff --git a/po/es.po b/po/es.po
new file mode 100644
index 0000000..89478c2
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,6104 @@
+# Spanish translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-07-30 23:41+0000\n"
+"Last-Translator: SpringLobby_Buildbot <Unknown>\n"
+"Language-Team: Spanish <es at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Añadir robot"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Apodo:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "IA"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr ""
+"Elige la librerÃa IA (Inteligencia Artificial) para usar con los robots."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Valor"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Añadir robot"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "No se han encontrado robots con IA en tu instalación Spring"
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "No se han encontrado librerÃas de robots."
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Aceptar los términos del acuerdo"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "¿Aceptas los términos del acuerdo?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "SÃ"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "No"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "Método"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "Dividir rangos uniformemente"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Aleatorio"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Clanes"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Ninguno"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Limpio"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Siempre"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"Poner los miembros del mismo clan (usuarios con la msima etiqueta de clan, "
+"como '[ibericos]Alice' y '[ibericos]Bob' ) dentro de la misma alianza.\n"
+"None: nada especial para los clanes.\n"
+"Limpio: poner los miembros del clan en la alianza, almenos que haga la "
+"alianza injusta.\n"
+"Siempre: poner siempre los miembros del clan en la alianza, siempre que la "
+"alianza no sea injusta."
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Números"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Remover Cuenta de Usuario"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Descripción"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Host"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Espectadores:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Jugadores:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Descargar &map"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "Descargar m&od"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Espectadores:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Jugadores:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Servidor:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Estado:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Bloqueado"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Con contraseña"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Highlight"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "LÃmite de rango"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Descripción:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Iniciado"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Lleno"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Abierto"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Jugador:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Todo"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Mapa:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Sólo mapas que tengo"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Máx. Jugadores:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Sólo mods que tengo"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Espectador:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Jugadores:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "Archivo"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Iniciado"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "Batalla cerrada"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Nuevo servidor..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "Unirse"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"No puedes ser servidor de un juego mientras continues en NO CONECTADO. Por "
+"favor favor, conéctate a un servidor."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "No estás en lÃnea"
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+"No puedes ser servidor, lo tienes desactivado debido a que estás usando una "
+"versión incompatible"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Error de Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Ya estás corriendo un Spring, cierra este primero para poder ser servidor en "
+"juego nuevo"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Ya estás en una batalla"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr "¿Quieres abandonar la batalla y empezar una nueva?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "La batalla no comenzará porque no se encuentra el mod seleccionado. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Error empezando batalla."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "No se encontraron mapas"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"Unirse a las batallas está desactivado debido a que la versión que usas de "
+"Spring es incompatible."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Ya estás en una batalla"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr "¿Quieres abandonar la batalla y empezar una nueva?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Ya estás en una batalla"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Ya estás en una batalla.\n"
+"\n"
+"¿Quieres abandonar la batalla y unirte a ésta?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Ya estás ejecutando un Spring, cierra primero éste para poder unirte a otra "
+"batalla."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Mot no disponible"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Mapa no avalible"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Password de batalla"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Introduzca la contraseña"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Seleccionar..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Opción"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Valor"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Tamaño"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Windspeed"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr ""
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravedad"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr ""
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Max metal"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Arreglado"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr ""
+
+#: src/battlemaptab.cpp:103
+msgid "Chose before game"
+msgstr ""
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "POsiciones iniciales"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Restricciones de unidad"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Unidades permitidas"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Las unidades de esta lista estarán disponibles en el juego."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Activar todas las unidades"
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Activar todas las unidades"
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Activar todas las unidades"
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Unidades restringidas."
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Las unidades de esta lista no estarán disponibles en el juego."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Restricciones de unidad"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Apodo"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Equipo"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Aliado"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Lado"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Escoger color"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Espectador"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Expulsar"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Anillo"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Por favor, introduzca un valor entre 0 y 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Añadir robot"
+
+#: src/battleroomlistctrl.cpp:719
+msgid "Human\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Espectador"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Jugador:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Host"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Cliente"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Siempre"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "No está listo"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+msgid "Set name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Cargar..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Cargar una configuración de restricciones."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Guardar..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Guardar configuración de restricciones."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Seleccionar..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Guardar configuración de restricciones."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "predeterminado"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Opciones de Mod"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Opciones de mapa"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "Mot no disponible"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "error"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "predeterminado"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Estoy listo"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Color"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Abandonar"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Comenzar"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Añadir robot"
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Remover Cuenta de Usuario"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Comenzar"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+#, fuzzy
+msgid "Lock Balance"
+msgstr "Balance"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Anillo"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "No está listo"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+msgid "Force spectate ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "Fijar colores"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid "Balance teams"
+msgstr "Balance"
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Guardar..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr ""
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "predeterminado"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr ""
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr ""
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "No está listo"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "predeterminado"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+msgid "Find channel:"
+msgstr ""
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "Cancelar"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d usuarios)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Sesión Cerrada ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"No se pudo crear la carpeta. \n"
+"Asegúrate de que no esté protegida contra escritura.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Colores y fuentes"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Utilice los colores del sistema"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Fondo"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Acción"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Highlight"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Unir/Abanadonar"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Mis mensajes"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Servidor"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Cliente"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Error"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Timestamp"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Notificación"
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "TipografÃa"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "predeterminado"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Seleccionar..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Comportamiento"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr ""
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d usuarios)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr ""
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr ""
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Limpiar"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr ""
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr ""
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Información del canal"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr ""
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Mensaje del canal..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr ""
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr ""
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr ""
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr ""
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr ""
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr ""
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr ""
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr ""
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr ""
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr ""
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr ""
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr ""
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr ""
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr ""
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr ""
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr ""
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Usuario Mudo"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Abrir Chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr ""
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr ""
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Mudo..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Mudo por 5 minutos"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Mudo por 10 minutos"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Mudo por 30 minutos"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Mudo por 5 horas"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Mudo por 1 dÃa"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr ""
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr ""
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr ""
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Ban..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr ""
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr ""
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr ""
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Comando: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" params: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr ""
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "batalla"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr ""
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr ""
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr ""
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Información del canal"
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr ""
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat cerrado"
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr ""
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr ""
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "error de ChanServ"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr ""
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr ""
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Registrar Canal"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Remover Cuenta de Usuario"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr ""
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr ""
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr ""
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr ""
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Usuario Mudo"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr ""
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Patear Usuario"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr ""
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Patear usuario"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr ""
+
+#: src/chatpanel.cpp:1797
+#, fuzzy
+msgid "couldn't add user"
+msgstr "No se pudo lanzar el explorador."
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr ""
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr ""
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr ""
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr ""
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr ""
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "puerto inválido."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "puerto inválido"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "host inválido"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Número inválido"
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr ""
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr ""
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr ""
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr ""
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr ""
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr ""
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr ""
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr ""
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr ""
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr ""
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr ""
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr ""
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr ""
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr ""
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr ""
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr ""
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr ""
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr ""
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr ""
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr ""
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr ""
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr ""
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr ""
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr ""
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr ""
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr ""
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr ""
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr ""
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr ""
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr ""
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr ""
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr ""
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr ""
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr ""
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr ""
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr ""
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr ""
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr ""
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr ""
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr ""
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr ""
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr ""
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr ""
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr ""
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr ""
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr ""
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr ""
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr ""
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr ""
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr ""
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr ""
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr ""
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr ""
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr ""
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr ""
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr ""
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr ""
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr ""
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr ""
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr ""
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr ""
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr ""
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr ""
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr ""
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr ""
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr ""
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr ""
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr ""
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr ""
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr ""
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr ""
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr ""
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr ""
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr ""
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr ""
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr ""
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr ""
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr ""
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr ""
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr ""
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr ""
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr ""
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr ""
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr ""
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr ""
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr ""
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr ""
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr ""
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr ""
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr ""
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr ""
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr ""
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr ""
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr ""
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr ""
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr ""
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr ""
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr ""
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr ""
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr ""
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr ""
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr ""
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr ""
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr ""
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr ""
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr ""
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr ""
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr ""
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr ""
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr ""
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr ""
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr ""
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr ""
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr ""
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr ""
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr ""
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr ""
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr ""
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr ""
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr ""
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr ""
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr ""
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr ""
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr ""
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr ""
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr ""
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr ""
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr ""
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr ""
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr ""
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr ""
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr ""
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr ""
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr ""
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr ""
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr ""
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr ""
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr ""
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr ""
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr ""
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr ""
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr ""
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr ""
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr ""
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr ""
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr ""
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr ""
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr ""
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr ""
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr ""
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr ""
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr ""
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr ""
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr ""
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr ""
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr ""
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr ""
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr ""
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr ""
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr ""
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr ""
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr ""
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr ""
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr ""
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr ""
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr ""
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr ""
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr ""
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr ""
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr ""
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr ""
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr ""
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr ""
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr ""
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr ""
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr ""
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr ""
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr ""
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr ""
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr ""
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr ""
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr ""
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr ""
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr ""
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr ""
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr ""
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr ""
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr ""
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr ""
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr ""
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr ""
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr ""
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr ""
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr ""
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr ""
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr ""
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr ""
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr ""
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr ""
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr ""
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr ""
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr ""
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr ""
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr ""
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr ""
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr ""
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr ""
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr ""
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr ""
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr ""
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr ""
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr ""
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr ""
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr ""
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr ""
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr ""
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr ""
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr ""
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr ""
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr ""
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Apodo"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Descargar m&od"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+#, fuzzy
+msgid "unknown hash "
+msgstr "desconocido"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+msgid "Remove"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+msgid "Rename.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "Añadir robot"
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Acción"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Abrir Chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Highlight"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "Añadir robot"
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Remover Cuenta de Usuario"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Seleccionar..."
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Elegir carpeta"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "No se pudo lanzar el explorador."
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "predeterminado"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Información del canal"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr ""
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Descripción"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr ""
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr ""
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "Mot no disponible"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr ""
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr ""
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Navegador web"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Buscador predeterminado"
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Especificar:"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Explorar"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+msgid "Autoconnect"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+msgid "Autoconnect on lobby start"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Comenzar"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "Elegir una navegador web ejecutable"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "Elegir una navegador web ejecutable"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Respuesta desconocida del servidor"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Opciones"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Restricciones de unidad"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr ""
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr ""
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Detalle de renderizado"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr ""
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr ""
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr ""
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "desconocido"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Descargar &map"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "enviando"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "Estado: no conectado"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "Estado: conectado"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "Estado: desconocido"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr ""
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr ""
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Opciones de mapa"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr ""
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Información del canal"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr ""
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr ""
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr ""
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr ""
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Información del canal"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr ""
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr ""
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr ""
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr ""
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Estado: conectado"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr ""
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "No se encontraron mapas"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+msgid "Which profile do you want to be default?"
+msgstr ""
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Guardar..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "Siempre"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Descargar &map"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr ""
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr ""
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr ""
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr ""
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "Archivo"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Max metal"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "POsiciones iniciales"
+
+#: src/mapselectdialog.cpp:265
+msgid "Minimum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "Avanzado"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Espectador"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "POsiciones iniciales"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Información del canal"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Información del canal"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Unidades restringidas."
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Opciones de mapa"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr ""
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr ""
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr ""
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr ""
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+#, fuzzy
+msgid "Filesize in KB:"
+msgstr "Tamaño (MB)"
+
+#: src/playback/playbackfilter.cpp:190
+msgid "Duration (hh:mm:ss):"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "batalla"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Modo"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Apodo"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Descripción"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Error de Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "Tamaño (MB)"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "Tamaño (MB)"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "Archivo"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Cargar..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Siempre"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Guardar..."
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "puerto inválido"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+msgid "Select Users"
+msgstr ""
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+msgid " is online"
+msgstr ""
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+msgid " just went offline"
+msgstr ""
+
+#: src/serverevents.cpp:260
+msgid " opened battle "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr ""
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr ""
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Descargar &map"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Notificación"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Número inválido"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "No un número"
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Iniciado"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Expiró la conexión"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "desconocido"
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Descargar m&od"
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "No se pudo lanzar el explorador. URL is: "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "No se pudo lanzar el explorador."
+
+#: src/settings++/Defs.hpp:212
+#, fuzzy
+msgid "Scrollwheel speed"
+msgstr "Regular velocidad:"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Detalle de gráficos"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Detalle de gráficos"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Batalla cerrada"
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "Acción"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "predeterminado"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+#, fuzzy
+msgid "Use less colors"
+msgstr "Utilice los colores del sistema"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr ""
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+#, fuzzy
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "Velocidad de scroll (ratón + teclado)"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Acción"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Acción"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Acción"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Acción"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Acción"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "Calidad de renderizado / Modo de VÃdeo"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "Detalle de renderizado"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Audio"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "¡Error!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "Se necesita confirmación"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "Resetear valores a valores predeterminados"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "Desactivar advertencias en modo experto"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "Salir"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "Simple (pocas opciones)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "EXperto (todas las opciones)"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "Acerca de"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Contacto"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "Créditos"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "Informar sobre un error"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Modo"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Info/Ayuda"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "¿Resetear todos los valores a valores predeterminados?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Sugerencia"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Error crÃtico"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "Usar esta ruta"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Cualquier archivo"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "bajo"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "medio"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "alto"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "muy bajo"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "muy alto"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "No se puede lanzar el explorador predeterminado"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "No se pudo lanzar el explorador. URL is: "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "No se pudo lanzar el explorador."
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "No se pudo acceder a tu configuración.\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Opciones de Audio"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Resolución de pantalla"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+"Si una opción necesita hardware especial para funcionar\n"
+"se mencionará en la herramienta de consejos."
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Calidad del agua"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "Resolución en bit"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "Opciones de calidad de renderizado"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "Opciones de modos de vÃdeo"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "Opciones de Anti-Aliasing"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "Detalle de niveles de renderizado"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "Calidad de gráficos"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Detalle de gráficos"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Resolución de pantalla"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "Activar modo experto"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (actual)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+"Fijar todos los valores de calidad de las opciones predefinidas de acuerdo a "
+"tus cambios."
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+"Fijar todos los valores de detgalle de las opciones predefinidas de acuerdo "
+"a tus cambios."
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Info"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "Velocidad de scroll (ratón + teclado)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "Modo de cámara predeterminado"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "Misc. UI Opciones"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "Zoom"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "Añadir robor..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Espectador"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "POsiciones iniciales"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- Seleccionar una --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "Error de la configuración del juego"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Tú has seleccionado un mapa primero."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "No hay robots añadidos"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "No puedes comenzar un spring mientras ya esté otro en ejecución"
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Hola "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Bienvenido"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Ninguno"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+msgid "Import settings?"
+msgstr ""
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Abrir Chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr ""
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Buscar"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "Ejecutable Spring"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Ubicación"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Buscar"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "LibrerÃa UnitSync"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Configurar automáticamente"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "Elegir un ejecutable Spring"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "LibrerÃa"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr "No hacer nada (usar ésto sólo si sabes lo que haces)"
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid "Data dir wizard"
+msgstr "Primer turno hechicero"
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "Elegir carpeta"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Expiró la conexión"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Respuesta desconocida del servidor"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "Números"
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "MB subidos"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "MB subidos"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Estado:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr "% completado"
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s subiendo"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s bajando"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "ETA (s)"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "Tamaño (MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "Autocomenzar sistema de torrent"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "manual"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "Detener todos los torrents"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr "Regular velocidad:"
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "subida (KB/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "bajada (KB/s)"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "Números"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "velocidad de subida máxima en KB/sec (-1 para infinito)"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "velocidad de descarga máxima en KB/sec (-1 para infinito)"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "Puertos usados para las conexiones de los torrents"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "Número máximo de conexiones simultaneas"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+#, fuzzy
+msgid "Torrent system failure"
+msgstr "Autocomenzar sistema de torrent"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Contraseña de servidor"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr ""
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr ""
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "Error en ayuda"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "Escribir /help en una ventana de chat"
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Comandos globales:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Alias to /join."
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" - Te ensela cuanto tiempo llevas en el juego."
+
+#: src/ui.cpp:498
+#, fuzzy
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+" \"/msg username [text]\" - envÃa un mensaje privado, sustituir: username "
+"por el destinatario y text por el mensaje."
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - Alias to /join."
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename newalias\" - Cambiar tu alias actual por otro."
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " \"/sayver\" - Decir tu versión actual de springlobby en el chat."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - Visualizar tu versión actual de springlobby."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Comandos de chat:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "No hay temas escritos aún."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "El tema \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Jugar Online será desactivado."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "Respuesta desconocida del servidor"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Expiró la conexión"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "no hay abiertos paneles de chat activos"
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d usuarios)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "La batalla actual fue cerrada por el servidor."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "Batalla cerrada"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Error en la configuración de Spring"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid "Not up to date"
+msgstr ""
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr ""
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Ninguno"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Highlight"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify hosted battle"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+#, fuzzy
+msgid "no action at all"
+msgstr "no hay abiertos paneles de chat activos"
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Siempre"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Apodo"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "Novato en canzoncillos"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "Principiante"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "Avanzado"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Muy avanzado"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "Experimentado"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "Altamente experimentado"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Veterano"
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "desconocido"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "Añadir robot"
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Remover Cuenta de Usuario"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+msgid "Author"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Tú versión de primavera"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "MB subidos"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Cancelar"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "Resolución de pantalla"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Espectadores:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "Jugadores:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Equipo"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Aliado"
+
+#~ msgid "cpu"
+#~ msgstr "cpu"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat cerrado"
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Opciones de mapa"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Descargar m&od"
+
+#~ msgid "Debug"
+#~ msgstr "Depuración"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Jugador:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Elegir carpeta"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Acción"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "p"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Información del canal"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "El tema \""
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Missing Functionality"
+#~ msgstr "Funcionalidad perdida"
+
+#~ msgid "Download OTA content?"
+#~ msgstr "¿Descargar contenido OTA?"
+
+#, fuzzy
+#~ msgid "Create a spring directory in my documents folder"
+#~ msgstr "Crear una carpeta .spring en el directorio inicial (recomendado)"
+
+#~ msgid "Create a folder in a custom path (you'll get prompted for the path)"
+#~ msgstr ""
+#~ "Crear una carpeta en la ruta definida (tendrás que escribir la ruta)"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "Respuesta desconocida del servidor"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "No estás en lÃnea"
+
+#~ msgid "Active chat channels:"
+#~ msgstr "Activar canales de chat:"
+
+#~ msgid "no rank"
+#~ msgstr "Sin rango"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d usuarios)"
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Número inválido"
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normal"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "Problema con Unitsync"
+
+#~ msgid "You have one or more bots sharing team, this is not possible."
+#~ msgstr "Tienes uno o más robots compatiendo equipo, esto no es posible."
+
+#~ msgid "/.spring"
+#~ msgstr "/.spring"
+
+#~ msgid "Start system"
+#~ msgstr "Comenzar sistema"
+
+#~ msgid "Stop system"
+#~ msgstr "Parar sistema"
+
+#~ msgid "End condition"
+#~ msgstr "Fin de condición"
+
+#~ msgid "Resources"
+#~ msgstr "Recursos"
+
+#~ msgid "Max units"
+#~ msgstr "Unidades máximas"
+
+#~ msgid "Limit d-gun"
+#~ msgstr "LÃmite d-gun"
+
+#~ msgid "Reset"
+#~ msgstr "Restablecer"
+
+#~ msgid "Spring directory"
+#~ msgstr "Directorio Spring"
+
+#~ msgid "Default location."
+#~ msgstr "Localización predefinida"
diff --git a/po/fi.gmo b/po/fi.gmo
new file mode 100644
index 0000000..b8f2102
Binary files /dev/null and b/po/fi.gmo differ
diff --git a/po/fi.po b/po/fi.po
new file mode 100644
index 0000000..db2a005
--- /dev/null
+++ b/po/fi.po
@@ -0,0 +1,6317 @@
+# Finnish translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-07-30 23:31+0000\n"
+"Last-Translator: SpringLobby_Buildbot <Unknown>\n"
+"Language-Team: Finnish <fi at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Lisää tietokonepelaaja"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Nimimerkki:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "Tekoäly"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Valitse tämän tietokonepelaajan ohjaukseen käytettävä AI-kirjasto"
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Arvo"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Peruuta"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Lisää botti"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Tekoälykirjasto(ja) ei löytynyt."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Tekoälykirjasto(ja) ei löytynyt"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Hyväksy sopimus"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Haluatko hyväksyä tämän sopimuksen ehdot?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Kyllä"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Ei"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr ""
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr ""
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Sattumanvarainen"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr ""
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Ei mitään"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr ""
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr ""
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Pelaajien määrä"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Yhdistä uudelleen"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Kuvaus"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Kenttä"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Modi"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Palvelin"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Katsojat:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Pelaajat:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Kenttä"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Lataa &map"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "Lataa m&od"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Katsojat:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Pelaajat:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Palvelin:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Tila:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Lukittu"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Salasanasuojattu"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Korostus"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Tasorajoitus"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Kuvaus:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Aloitettu"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Täysi"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Avaa"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Pelaaja:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Kaikki"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Kartta:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Vain asennetut kartat"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Maksimi määrä pelaajia:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Modi:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Vain asennetut modit"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Katsoja:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Pelaajat:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "&Tiedosto"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Aloitettu"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "Pelilistaus"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Isännöi uusi..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "liity"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Et voi isännöidä peliä ellet ole yhdistyneenä. Ole hyvä ja yhdistä "
+"palvelimeen."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Ei kirjautuneena."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "Pelien isännöinti estetty väärän ohjelmistoversion vuoksi."
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Spring virhe"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr "Spring on jo käynnissä. Sulje se jotta voit isännöidä uuden pelin"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Olet jo mukana pelissä"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Olet jo mukana pelissä.\n"
+"\n"
+"Haluatko poistua nykyisestä pelistä käynnistääksesi uuden?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "Peli ei käynnistynyt koska valitsemasi modi ei löytynyt. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Virhe käynnistäessä peliä."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Karttatiedostoja ei voitu löytää. Tämä tapahtuu kun et ole säätänyt Spring:"
+"in asetuksia oikein."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Yhtään karttaa ei löytynyt."
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr "Peleihin liittyminen on estetty johtuen väärästä Spring-versiosta."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Olet jo mukana pelissä"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Olet jo mukana pelissä.\n"
+"\n"
+"Haluatko poistua nykyisestä pelistä käynnistääksesi uuden?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Olet jo mukana pelissä"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Olet jo mukana pelissä.\n"
+"\n"
+"Haluatko poistua nykyisestä pelistä liittyäksesi tähän?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr "Spring on jo käynnissä. Sulje se pystyäksesi liittymään peliin."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Modia ei ole saatavilla"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Karttatiedostoa ei saatavilla"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Pelin salasana"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Syötä salasana"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Valitse..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Asetus"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Arvo"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Koko"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Tuulen nopeus"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Merivirtauksen voimakkuus"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Painovoima"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Metallinlouhijan säde"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Maksimi metalli"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Ennalta määrätty"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Valitse pelissä"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "Valitse pelissä"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Aloituskohdat"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Yksikköjen rajoitukset"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Sallitut yksiköt"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Tässä listassa näkyvät yksiköt ovat sallittuja pelissä."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Salli kaikki yksiköt."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Salli kaikki yksiköt."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Salli kaikki yksiköt."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Kielletyt yksiköt"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Tässä listassa näkyvät yksiköt ovat kiellettyjä pelissä."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Yksikköjen rajoitukset"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Nimimerkki"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Joukkue"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Liittolainen"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Resurssilisä"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Puoli"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Aseta väri"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Aseta resurssilisä"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Katsoja"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Potkaise"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Heräte"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Anna arvo väliltä 0 - 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Lisää tietokonepelaaja"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Oman"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Katsoja"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Pelaaja:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Palvelin"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Asiakasohjelma"
+
+#: src/battleroomlistctrl.cpp:732
+msgid "Ready\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Ei valmiina"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Aseta oikeudet..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Lataa..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Lataa tallennettu rajoitustiedosto"
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Tallenna..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Tallenna rajoitukset tiedostoon."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Valitse..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Tallenna rajoitukset tiedostoon."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "oletus"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Modin asetukset"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Kartan asetukset"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "Modia ei ole saatavilla"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "virhe"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Valitse"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "oletus"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Valmis"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Väri"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Poistu"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Käynnistä"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Lisää tietokonepelaaja"
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Yhdistä uudelleen"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Käynnistä"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Heräte"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Ei valmiina"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "Pakota pelin alkaminen?"
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Tallenna..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "Valitse"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "oletus"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr ""
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr ""
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Jotkut pelaajat eivät ole valmiita vielä.\n"
+"Lähetetäänkö heille heräte?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Ei valmiina"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "Ping kutsun aikavirhe!"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "Liity tähän kanavaan automaattisesti"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "Liity kanavalle..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "Kanavan nimi"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "kanava"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d käyttäjät)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Yhteys suljettu ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Kansiota ei pystytty luomaan. \n"
+"Varmista että kirjoitus ei ole estettynä.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "Loki -toiminto on estetty kunnes käynnistät ohjelman uudelleen."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Varoitus lokissa."
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"Viestiä ei pystytty tallentamaan lokiin.\n"
+"Loki -toiminto poissa käytössä tässä pelissä. "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"Liity peliin uudelleen käynnistääksesi loki -toiminnon."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Lokitiedostoa ei voitu avata. \n"
+"Varmistu että kirjoittaminen on sallittu.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Värit ja kirjasintyyli"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Käytä järjestelmän värejä"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Tavallinen"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Tausta"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Toiminto"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Korostus"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Liity/Poistu"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Minun viestit"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Palvelin"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Asiakasohjelma"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Virhe"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Aikaleima"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Ilmoitus"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Connected to TAS Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Kirjasin:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "oletus"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Valitse..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr ""
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Keskustelujen lokit"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Tallenna keskustelujen lokit"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Korostetut sanat"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Sanat jotka korostetaan keskusteluissa:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d käyttäjät)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Lähetä"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Kopioi"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Tyhjennä"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "Liity tähän kanavaan automaattisesti"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "Näytä Liity/Poistu -ilmoitukset"
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Kanavan tiedot"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Aseta kanavan ostikko..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Kanavan viesti..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Lukitse..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Poista lukitus"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Rekisteröidy..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Rekisteröinnin poisto"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Päällä"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Pois päältä"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "On päällä?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Spammin esto"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Katkaise yhteys"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Yhdistä uudelleen"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Poista..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Vaihda salasana..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Aseta oikeudet..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Tilit"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "Kuulutus..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Ylläpitäjä"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Hiljennä käyttäjä"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Avoin keskustelu"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "Liity samaan keskusteluun"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Pelissä vietetty aika"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "Etsi IP sekä smurffipelaajat"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Hiljennä..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Hiljennä 5 minuutiksi"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Hiljennä 10 minuutiksi"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Hiljennä 30 minuutiksi"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Hiljennä 2 tunniksi"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Hiljennä 1 päiväksi"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Poista hiljennys"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Hiljennä"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Potkaise..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Banni..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Poista banni"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "Läimäytä!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Anna opit"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "Poista opit"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Komento: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" parametrit: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "kanava"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "peli"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "palvelin"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " liityit peliin "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " poistuit pelistä "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Kanavan tiedot"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * Asettaja "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Keskustelu suljettu."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Oletko varma että haluat liittää %d riviä?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Floodaus varoitus"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Sinulla on käytössä SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Et ole kanavalla tai kanavaa ei ole olemassa."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Käyttäjä ei ole yhdistyneenä."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Lähetetty: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ChanServ virhe"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ ei ole tällä kanavalla."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Anna uusi kanavan otsikko?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Viesti:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "Lukitse kanava..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Anna uusi salasana?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "Poista lukitus"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Oletko varma että haluat poistaa lukituksen tältä kanavalta?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ ei ole tällä palvelimella."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Rekisteröi kanava"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Kuka nimetään tämän kanavan perustajaksi?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "Poista rekisteröinti tältä kanavalta"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "Oletko varma että haluat poistaa rekisteröinnin tältä kanavalta?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Käyttäjätili poistettu"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Minkä käyttäjätilin haluat poistaa tänään?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Poista käyttäjätili"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Oletko varma että haluat poistaa käyttäjätilin? "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Vaihda käyttäjätilin salasana"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Minkä käyttäjätilin salasanan haluat vaihtaa?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Anna uusi salasana?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Ei toteutettu"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "Kuuluta viesti"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "Kuulutettava viesti:"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "Tämä peli on suojattu, anna salasana."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Hiljennä käyttäjä"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Miten moneksi minuutiksi käyttäjä hiljennetään?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Potkaise käyttäjä"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Syy:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Potkaise käyttäjä"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "Hiljennä käyttäjä"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Kesto:"
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Yhdistä palvelimeen"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr "Yhdistä palvelimeen. Anna palvelimen osoita muodossa osoite:portti"
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Salasana"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"Huomio: Jos sinulla ei ole käyttäjätiliä, voit rekisteröityä\n"
+" siirtymällä rekisteröitymis välilehdelle"
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Kirjaudu"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Rekisteröidy"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Nimimerkki"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Epäkelpo portti."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Virheellinen portti"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Porttinumero väärä.\n"
+"\n"
+"Oltava väliltä 1 - 633535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Epäkelpo palvelin ja/tai portti."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Epäkelpo palvelin"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Virheellinen numero"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr "Rekisteröityminen epäonnistui."
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Rekisteröinti epäonnistui."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Yhdistyneet Arabiemiirikunnat"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afganistan"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua ja Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albania"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Armenia"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Alankomaiden Antillit"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Etelänapamanner"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentiina"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Amerikan Samoa"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Itävalta"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Australia"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azerbaidžan"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosnia-Hertsegovina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladesh"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgia"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgaria"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahrain"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermuda"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunei Darussalamin sulttaanikunta"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Bolivia"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brasilia"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamasaaret"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhutan"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Bouvet'n saari"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Valko-Venäjä"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Kanada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "Cocos (Keelingin saaret)"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "Keski-Afrikan tasavalta"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Kongo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Sveitsi"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Norsunluunrannikko"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Cook-saaret"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Kamerun"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "Kiina"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Kolumbia"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Kuuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Kap Verde"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Joulusaari"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Kypros"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "TÅ¡ekin tasavalta"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Saksa"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Djibouti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Tanska"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominica"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Dominikaaninen tasavalta"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Algeria"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ecuador"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Viro"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Egypti"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Länsi-Sahara"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritrea"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Espanja"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Etiopia"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Suomi"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fidzi"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Falkland-saaret (Malvinas-saaret)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Micronesia"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Färsaaret"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "Ranska"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "Manner-Ranska"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Georgia"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Ranskan Guinea"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Grönlanti"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambia"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guinea"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadeloupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Päiväntasaajan Guinea"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Kreikka"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "S. Gregoria ja S. Sandwich saaret."
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guinea-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guyana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Heard ja McDonaldinsaaret"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Kroatia"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Unkari"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonesia"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irlanti"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israel"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "Intia"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Brittiläinen Intian valtameren alue"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Irak"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Iran"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Islanti"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Italia"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamaika"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Jordania"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japani"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Kenia"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "Krygyz Republikaaninen"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Kambodža"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Komorit"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "Saint Kitts ja Nevis"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Korea"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Eteläkorea"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuwait"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Caymansaaret"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kazakstan"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Libanon"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Saint Lucia"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Liberia"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Liettua"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Luxemburg"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Latvia"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Libya"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Marokko"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldova"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Montenegro"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagascar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Marshallinsaaret"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Makedonia"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Myanmar"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongolia"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macau"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Pohjois-Mariaanit"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinique"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauritania"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Mauritius"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Malediivit"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Meksiko"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malesia"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mosambik"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "Namibia"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Uusi-Kaledonia"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Niger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Norfolkinsaaret"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigeria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nicaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Alankomaat"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norja"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Neutraali alue (Saudi Arabia/Iraq)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "Uusi-Seelanti"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Oman"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panama"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Peru"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Ranskan Polynesia"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua Uusi-Guinea"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Filippiinit"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pakistan"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Puola"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "Saint-Pierre ja Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Pitcairn"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Puerto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugali"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palau"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Qatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Reunion"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Romania"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Serbia"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Venäjä"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Ruanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Saudi-Arabia"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Salomonsaaret"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychellit"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Sudan"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Ruotsi"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapore"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "Saint Helena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slovenia"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Svalbard- ja Jan Mayen -saaret"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Slovakia"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Leone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somalia"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Surinam"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "São Tomé ja PrÃncipe"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "Neuvostoliitto"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "El Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Syyria"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Swazimaa"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Turks- ja Caicossaaret"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "TÅ¡ad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Ranskan eteläiset alueet"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Thaimaa"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tadzikistan"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Tokelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistan"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunisia"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Itä-Timor"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Turkki"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad ja Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Taiwan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tansania"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ukraina"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "Iso-Britannia"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "Yhdysvaltojen pienet syrjäiset saaret"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "Yhdysvallat"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Uzbekistan"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Vatikaanivaltio"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "ST. Vincent"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Neitsytsaaret (Englanti)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Neitsytsaaret (USA)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vietnam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Wallis- ja Futunasaaret"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Jemen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Jugoslavia"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Etelä-Afrikka"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Sambia"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zaire"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Täyttä maan nimeä ei löytynyt)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "Järjestelmän tiedot"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "Ohjelman loki"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Edellinen Spring -ohjelman tekemä käynnistysskripti"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Peli"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Ei modia valittuna."
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Poista..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Poista..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "Lisää tietokonepelaaja"
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Toiminto"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Avoin keskustelu"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "Isännöi uusi peli"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Korostetut sanat"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "Lisää tietokonepelaaja"
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Käyttäjätili poistettu"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Käyttäjän nimi"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Valitse"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Valitse pelissä"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "Aseta oikeudet..."
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "oletus"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Kanavan tiedot"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Isännöi uusi peli"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "Pelin lyhyt kuvaus. Tämä näkyy pelilistauksessa muille pelaajille."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Kuvaus"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Valitse modi."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr "Salasana vaadittu liittyäksesi peliin."
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Portti"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "Käynnistä pelipalvelin tässä UDP portissa. Oletus on 8452."
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "Modia ei ole saatavilla"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Pelaajien määrä"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "Maksimi määrä pelaajia sallittu pelissä."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "\"Hole Punching\" tekniikka"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "\"NAT traversal\" tekniikka"
+
+#: src/hostbattledialog.cpp:177
+#, fuzzy
+msgid "NAT traversal to use."
+msgstr "\"NAT traversal\" tekniikka"
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Minimi arvomerkkivaatimus"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Aloita pelin isännöiminen."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "Sinun on vlaittava modiu ensin."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Ei modia valittuna."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "Yhdistä uudelleen"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "Yhdistä palvelimeen"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "&Työkalut"
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Metallimäärä pelin alkaessa"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Tuntematon vastaus palvelimelta"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "Pelilistaus"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "Pelihuone"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Asetukset"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Yksikköjen rajoitukset"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Keskustelu"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Senegal"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Palauta"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "Käytä"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Peli"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Lataa"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Yhdistä..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&Katkaise yhteys"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Kartan asetukset"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Poistu"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "&Liity kanavalle..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Kanavan tiedot"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Avaa yksityinen &keskustelu..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&Lataa uudelleen kartat/modit"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "Tarkista onko uusi versio saatavilla"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "Spring asetukset"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&Tietoja"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Kanavan tiedot"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&Ilmoita bugista..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Dokumentointi"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&Tiedosto"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Työkalut"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Ohje"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Yhdistä uudelleen"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "Liity kanavalle..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Kanavan nimi"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Avaa yksityinen keskusteluikkuna..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Käyttäjän nimi"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Yhtään karttaa ei löytynyt."
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Minkä käyttäjätilin haluat poistaa tänään?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Tallenna..."
+
+#: src/mainwindow.h:184
+msgid "Replays"
+msgstr ""
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Lataa"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Päivitä"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Lataa"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "Puoli:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "liitto: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+#, fuzzy
+msgid "Show"
+msgstr "Näytä kaikki"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "&Tiedosto"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Maksimi metalli"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Aloituskohdat"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Minimi arvomerkkivaatimus"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Katsoja"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Aloituskohdat"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Aloituskohtien tyyppi"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Aloituskohtien valinta\n"
+"0: ennalta määrätyt kohdat\n"
+"1: sattumanvaraiset kohdat\n"
+"2: valitse pelissä\n"
+"3: valitse ennen pelin alkua"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Valitse pelissä"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Valitse pelissä"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Kielletyt yksiköt"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Kartan asetukset"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "c"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Suoritettavat tiedostot (*.exe)|*.exe|Any File (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Mikä tahansa tiedosto (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr "Ohjelmistopaketit (*.app)|*.app|Any File (*.*)|*.*"
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Kesto:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Valitse"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Monaco"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Panama"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Kesto:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Spring virhe"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "&Tiedosto"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Lataa..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Pelaajat:"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Tallenna..."
+
+#: src/playback/playbacktab.cpp:286
+#, fuzzy
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"Ei pystynyt lukemaan Spring versiotasi unitsync -kirjastosta.\n"
+"\n"
+"Verkkopeli tulee olemaan estetty."
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Virheellinen portti"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Valitse"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Käyttäjä ei ole yhdistyneenä."
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() epäonnistui ! (exception)"
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Käyttäjä ei ole yhdistyneenä."
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " liityit peliin "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr ""
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "Pelilistaus"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Lataa &map"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"Versiontarkistuksessa tapahtui virhe.\n"
+"Kokeile myöhemmin uudelleen.\n"
+"Jos ongelma pysyy, voit tehdä siitä ilmoituksen springlobby:n kehittäjille."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Ilmoitus"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Virheellinen numero"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Ei ole numero"
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Aloitettu"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Yhdistä uudelleen"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "Tuntematon vastaus palvelimelta"
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Ei modia valittuna."
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Maksimi metalli"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Maksimi metalli"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Pelihuone"
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "Valitse"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "oletus"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+#, fuzzy
+msgid "Use less colors"
+msgstr "Käytä järjestelmän värejä"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+#, fuzzy
+msgid "Show in-game player information"
+msgstr "Järjestelmän tiedot"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Valitse"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Valitse"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Valitse"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Valitse"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Kesto:"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Pois päältä"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr ""
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr ""
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr ""
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr ""
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr ""
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr ""
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr ""
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr ""
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Katsoja"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Aloituskohdat"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr ""
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr ""
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Ei mitään"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "Spring asetukset"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Avoin keskustelu"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "Pelilistaus"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Ennalta määrätty"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr ""
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr ""
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr ""
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr ""
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr ""
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Tuntematon vastaus palvelimelta"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "Lataa"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Tila:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Plavelimen salasana"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Rekisteröityminen onnistui\n"
+"Voit kirjautua sisään."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Rekisteröityminen onnistui"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "Rekisteröityminen epäonnistui, syy:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"Selaimen polku on: "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "Aputiedoston virhe"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "Kirjoita \"/help\" viestiikkunaan."
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "SpringLobby:n komennot."
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Globaalit komennot:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - Asettaa tilasi poissaolevaksi."
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - Poistaa poissaolevan tilan."
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - Näyttää aktiiviset kanavat."
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Sama kuin \"/join\""
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" näyttää montako minuuttia olet pelannut."
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - Näyttää aktiiviset kanavat."
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - Sama kuin \"/join\""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename uusinimi\" - Muuttaa nimimerkkisi uusinimi:ksi"
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " \"/sayver\" - Sanoo SpringLobby -versiosi keskusteluikkunassa."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - Näyttää SpringLobby versiosi."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Keskustelun komennot:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me action\" - sanoo IRC tyylisen toimintoviestin."
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Ei viestiketjuja."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Viestiketjua \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr "\" ei löytynyt. Kirjoita \"/help topics\" listataksesi viestiketjut."
+
+#: src/ui.cpp:609
+#, fuzzy
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Ei pystynyt lukemaan Spring versiotasi unitsync -kirjastosta.\n"
+"\n"
+"Verkkopeli tulee olemaan estetty."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Verkkopeli tulee olemaan estetty."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "Tuntematon vastaus palvelimelta"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+msgid "Connection failure"
+msgstr ""
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "Ei aktiivisia keskusteluikkunoita auki."
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d käyttäjät)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Palvelin viesti"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "Nykyinen peli suljettiin isännän toimesta."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "Peli suljettu"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Sinun Spring -asetukset eivät ole kunnossa. Tarkasta asetukset ennen kuin "
+"yrität\n"
+"pelata verkossa."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Spring -asetuksissa virhe"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Versiontarkistuksessa tapahtui virhe.\n"
+"Kokeile myöhemmin uudelleen.\n"
+"Jos ongelma pysyy, voit tehdä siitä ilmoituksen springlobby:n kehittäjille."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Sinun versio: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Viimeisin versio: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"SpringLobby versiosi on vanha.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Ei ajan tasalla"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Ei ajan tasalla"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+#, fuzzy
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Versiontarkistuksessa tapahtui virhe.\n"
+"Kokeile myöhemmin uudelleen.\n"
+"Jos ongelma pysyy, voit tehdä siitä ilmoituksen springlobby:n kehittäjille."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, fuzzy, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"Versiontarkistuksessa tapahtui virhe.\n"
+"Kokeile myöhemmin uudelleen.\n"
+"Jos ongelma pysyy, voit tehdä siitä ilmoituksen springlobby:n kehittäjille."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Ei mitään"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Korostus"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "Liity samaan keskusteluun"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+#, fuzzy
+msgid "no action at all"
+msgstr "Ei aktiivisia keskusteluikkunoita auki."
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Norja"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Nimimerkki"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr ""
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr ""
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr ""
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr ""
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr ""
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr ""
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr ""
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "Lisää tietokonepelaaja"
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Käyttäjätili poistettu"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Itävalta"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Sinun Spring versio"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "Lataa"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Peruuta"
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Katsojat:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Joukkue"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Liittolainen"
+
+#~ msgid "cpu"
+#~ msgstr "suoritin"
+
+#~ msgid "Test firewall"
+#~ msgstr "Kokeile palomuurin toimivuus"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Keskustelu suljettu."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Kartan asetukset"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "Valitse pelissä"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Ei modia valittuna."
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Katkaise yhteys"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Pelaaja:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Aseta väri"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Toiminto"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "p"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "Annettu arvo virheellinen\n"
+#~ " Anna kokonaisluku väliltä 0 - 100"
+
+#~ msgid "Bot team sharing."
+#~ msgstr "Tietokonepelaaja jaetussa joukkueessa."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "Pelaajien määrä"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Kanavan tiedot"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Viestiketjua \""
+
+#~ msgid "_SERVER"
+#~ msgstr "_PALVELIN"
+
+#, fuzzy
+#~ msgid "Do nothing"
+#~ msgstr "\"Hole Punching\" tekniikka"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "Tuntematon vastaus palvelimelta"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Ei kirjautuneena."
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "Tämä peli käyttää \"NAT traversal\" menetelmää.\n"
+#~ "Päivitä wxwidgets versioon 2.8 tai uudempaan saadaksesi ominaisuuden "
+#~ "käyttöön."
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Väärä palvelimen osoite tai portti."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "Aktiiviset keskusteluikkunat:"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "Pelilistaus"
+
+#~ msgid "Select all"
+#~ msgstr "Valitse kaikki"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d käyttäjät)"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Ei modia valittuna."
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Virheellinen numero"
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "Pelin lyhyt kuvaus. Tämä näkyy pelilistauksessa muille pelaajille."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "Valitse modi."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Tavallinen"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "Spring virhe"
+
+#~ msgid "You have one or more bots sharing team, this is not possible."
+#~ msgstr ""
+#~ "Yksi tai useampi tietokonepelaaja on samassa joukkueessa, mikä ei ole "
+#~ "mahdollista."
+
+#~ msgid ""
+#~ "Please enter password needed to join this channel, leave blank for no "
+#~ "passwrd."
+#~ msgstr "Anna salasana, jätä tyhjäksi jos salasana on tyhjä."
+
+#~ msgid "Fixed source ports"
+#~ msgstr "\"Fixed source ports\" tekniikka"
+
+#~ msgid ""
+#~ "NAT traversal to use, currently this feature is not supported by "
+#~ "SpringLobby."
+#~ msgstr "Valitsemasi tekniikka ei valitettavasti ole vielä tuettu."
+
+#~ msgid "&Edit"
+#~ msgstr "&Muokkaa"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "Jatkuu kun komentaja kuolee"
+
+#~ msgid "End if commander dies"
+#~ msgstr "Päättyy kun komentaja kuolee"
+
+#~ msgid "End condition"
+#~ msgstr "Päättymisehdot"
+
+#~ msgid "Resources"
+#~ msgstr "Resurssit"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Metallimäärä pelaajalla pelin alkaessa."
+
+#~ msgid "Start Energy"
+#~ msgstr "Energiamäärä pelin alkaessa"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Energiamäärä pelaajalla pelin alkaessa."
+
+#~ msgid "Max units"
+#~ msgstr "Maksimi määrä yksikköjä"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "Maksimi määrä sallittuja yksikköjä pelaajaa kohden."
+
+#~ msgid "Limit d-gun"
+#~ msgstr "D-Gun etäisyys rajoitettu"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "Haamukuvat taloista"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "Metallinmuuntimien vähentyvä hyötysuhde"
+
+#~ msgid "Save to:"
+#~ msgstr "Tallenna tiedostoon:"
+
+#~ msgid "Browse..."
+#~ msgstr "Selaa..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Valitse hakemisto"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "Kartta/Modi Asetukset"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "SpringLobby versio on ajan tasalla!\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "Ajan tasalla"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "Haluatko siirtyä sivulle jolta voit ladata uusimman version?"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "D-Gun rajoitus"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr "D-Gun käytössä vain aloituskohdan lähettyvillä."
+
+#~ msgid "Ghosted Buildings"
+#~ msgstr "Haamukuvat taloista"
+
+#~ msgid ""
+#~ "Enemy buildings will leave a ghost image on the map after losing LoS on "
+#~ "them"
+#~ msgstr ""
+#~ "Vihollisen talot jäävät näkyviin haamukuvina kun näköyhteys menetetään."
+
+#~ msgid "Diminishing MM"
+#~ msgstr "Vähentyvä metallintekijöiden tehokkuus"
+
+#~ msgid ""
+#~ "Efficiency of MetalMakers will progressively reduce as much as you build "
+#~ "them"
+#~ msgstr "Metallintekijöiden hyötysuhde pienenee määrän lisääntyessä"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "Pelin päättymisen ehdot"
+
+#~ msgid ""
+#~ "The condition that will end the game\n"
+#~ "0: when all units will be destroyed\n"
+#~ "1: when the commander will be destroyed\n"
+#~ "2: lineage mode (see option 1, but given away units will still die"
+#~ msgstr ""
+#~ "Peli päättyy kun\n"
+#~ "0: kaikki yksiköt ovat kuolleet\n"
+#~ "1: kun komentaja kuolee\n"
+#~ "2: turnajais moodi (myös pois annetut yksiköt kuolevat pelaajan kuollessa)"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "Asettaa kunkin pelaajan pelin alussa saaman metallimäärän"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "Aseta pelaajan aloituksessa saama energiamäärä"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "Maksimi määrä yksiköitä"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "Asettaa maksimi määrän yksiköitä per pelaaja"
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "ei ole ruettu palvelimen puolelta."
+
+#~ msgid ""
+#~ "This is the SpringLobby channel, please report any problems you are "
+#~ "having with SpringLobby here and the friendly developers will help you."
+#~ msgstr ""
+#~ "Tämä on SpringLobby:n kanava. Ole hyvä ja ilmoita havaitsemasi ongelmat "
+#~ "koskien SpringLobby:a täällä niin ystävälliset ohjelman kehittäjät voivat "
+#~ "auttaa sinua."
diff --git a/po/fr.gmo b/po/fr.gmo
new file mode 100644
index 0000000..815ea6a
Binary files /dev/null and b/po/fr.gmo differ
diff --git a/po/fr.po b/po/fr.po
new file mode 100644
index 0000000..d3dd84f
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,6262 @@
+# French translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# Remi RAMPIN <remirampin at gmail.com>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: fr\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2009-06-29 15:08+0100\n"
+"Last-Translator: remram44 <remirampin at gmail.com>\n"
+"Language-Team: french\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Ajouter un bot"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Pseudo :"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "IA"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Choisissez l'IA du bot."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr "propriété"
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+msgid "value"
+msgstr "valeur"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Annuler"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Ajouter un bot"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Aucune bibliothèque d'IA trouvée dans votre installation de Spring."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Aucune bibliothèque d'IA trouvée."
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Accepter le contrat"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Acceptez-vous les termes de cette licence ?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Oui"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Non"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "Equilibrer les équipes"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "Méthode"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "Répartir uniformément les grades"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Aléatoire"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Clans"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Aucun"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Equilibré"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Toujours"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"Mettre les membres d'un même clan (en utilisant les tags d'alliance, "
+"comme )'[smurfzor]Alice' and '[smurfzor]Bob' dans la même alliance.\n"
+"Aucun : Ne tient pas compte des clans pour équilibrer.\n"
+"Equilibré : Met les membres d'un clan dans la même alliance, sauf si cela "
+"rend les alliances déséquilibrées.\n"
+"Toujours : Met toujours les membres d'un clan dans la même alliance, même si "
+"les alliances sont déséquilibrées."
+
+#: src/autobalancedialog.cpp:53
+msgid "Number of allies"
+msgstr "Nombre d'alliances"
+
+#: src/autobalancedialog.cpp:56
+msgid "Auto select"
+msgstr "Sélection automatique"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Description"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Carte"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Héberger"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Spectateurs :"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+msgid "Players"
+msgstr "Joueurs"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Carte"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Télécharger la &carte"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "Télécharger le m&od"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Spectateurs :"
+
+#: src/battlelistctrl.cpp:361
+msgid "Active Players:"
+msgstr "Joueurs :"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Hôte :"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Etat :"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Verrouillé"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Protégé par un mot de passe"
+
+#: src/battlelistfilter.cpp:122
+msgid "Highlighted only"
+msgstr "Surlignées seulement"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Grade minimum :"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Description :"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Démarré"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Complet"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Ouvert"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Joueur :"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Tous"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Carte :"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Uniquement les cartes que j'ai"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Maximum de joueurs"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod :"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Uniquement les mods que j'ai"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Spectateurs :"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Joueurs :"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+msgid " Filter "
+msgstr " Filtre "
+
+#: src/battlelisttab.cpp:142
+msgid "Activated"
+msgstr "Activé"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+msgid " Battle infos "
+msgstr " Informations "
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr "0 bataille affichée"
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Héberger ..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "Rejoindre"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr "%d batailles affichées"
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Vous ne pouvez pas héberger une partie en étant déconnecté. Merci de vous "
+"connecter à un serveur lobby"
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Hors-ligne."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "Vous ne pouvez pas héberger avec une version incompatible."
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Erreur de Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Spring est déjà lancé, fermez-le afin de pouvoir héberger une nouvelle "
+"partie."
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Déjà dans une bataille"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Vous êtes déjà dans une bataille\n"
+"Voulez-vous quitter la bataille actuelle pour commencer une nouvelle ?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"Vous utilisez une version de wxWidgets antérieure à la version 2.8.\n"
+"Le test de port n'est pas pris en charge.\n"
+"L'hébergement peut fonctionner ou non."
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"Le serveur utilisé pour tester votre port %d est inaccessible.\n"
+"L'hébergement peut fonctionner ou non avec ces paramètres."
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"La bataille n'a pas été ouverte car le port que vous avez choisi (%d) ne "
+"peut pas recevoir les paquets entrants.\n"
+"Vérifiez la configuration de vos pare-feu/routeur à nouveau ou changez le "
+"port dans la fenêtre.\n"
+"\n"
+"Si tout le reste échoue, activez \"Hole punching\" dans les options "
+"d'hébergement."
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+"La bataille n'a pas commencé car le mod sélectionné n'est pas installé. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Erreur au démarrage de la bataille."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Aucune carte dans votre installation de Spring. Ceci peut arriver si vous "
+"avez mal réglé les paramètres de Spring."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Aucune carte trouvée."
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"La version de spring est incompatible et ne permet pas de rejoindre une "
+"bataille."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Déjà dans une bataille"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Vous êtes déjà dans une bataille\n"
+"Voulez-vous quitter la bataille actuelle pour commencer une nouvelle ?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Déjà dans une bataille"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Vous êtes déjà dans une bataille\n"
+"Voulez vous quitter cette bataille et rejoindre celle-ci ?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Une instance de Spring est déjà en cours d'exécution, arrêtez-la avant de "
+"rejoindre une autre bataille."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "Souhaitez-vous que je vous mène sur la page de téléchargement ?"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+"Voulez-vous que j'essaye de le télécharger pour vous ?\n"
+"Vous pourrez voir la progression dans l'onglet \"Download Manager\"."
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+"Vous devez télécharger la mod avant de pouvoir rejoindre cette bataille.\n"
+"\n"
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Mod non disponible."
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+"Vous devez télécharger la carte avant de pouvoir rejoindre cette bataille.\n"
+"\n"
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Carte non-disponible"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Mot de passe de la partie"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Saisir un mot de passe"
+
+#: src/battlemaptab.cpp:69
+msgid "Select"
+msgstr "Sélectionner..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Option"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Valeur"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Taille"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Vitesse du vent"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Force du courant"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravité"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Rayon des extracteurs"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Métal max."
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Fixes"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Choisies en jeu"
+
+#: src/battlemaptab.cpp:103
+msgid "Chose before game"
+msgstr "Choisies avant la partie"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Positions de départ"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Unités interdites"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Unités autorisées"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Les unités dans cette liste seront accessibles pendant la partie."
+
+#: src/battleoptionstab.cpp:76
+msgid "Disable selected units."
+msgstr "Désactiver les unités sélectionnées."
+
+#: src/battleoptionstab.cpp:80
+msgid "Re-enable selected units."
+msgstr "Réactiver les unités sélectionnées."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr "<<"
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Autorise toutes les unités."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Unités interdites"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr ""
+"Les unités dans cette liste ne seront pas utilisables pendant la partie."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr "Combien d'unités de ce type souhaitez-vous autoriser ?"
+
+#: src/battleoptionstab.cpp:238
+msgid "Unit restriction"
+msgstr "Unités interdites"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Surnom"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Ãquipe"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Alliance"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Bonus de ressources"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Faction"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Choisir la couleur"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Choisir le bonus de ressources"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Spectateur"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Expulser"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Biper"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Veuillez entrer une valeur entre 0 et 100"
+
+#: src/battleroomlistctrl.cpp:717
+msgid "AI (bot)\n"
+msgstr "IA (bot)\n"
+
+#: src/battleroomlistctrl.cpp:719
+msgid "Human\n"
+msgstr "Humain\n"
+
+#: src/battleroomlistctrl.cpp:722
+msgid "Spectator\n"
+msgstr "Spectateur\n"
+
+#: src/battleroomlistctrl.cpp:724
+msgid "Player\n"
+msgstr "Joueur\n"
+
+#: src/battleroomlistctrl.cpp:727
+msgid "Host\n"
+msgstr "Hôte\n"
+
+#: src/battleroomlistctrl.cpp:729
+msgid "Client\n"
+msgstr "Client\n"
+
+#: src/battleroomlistctrl.cpp:732
+msgid "Ready\n"
+msgstr "Prêt\n"
+
+#: src/battleroomlistctrl.cpp:734
+msgid "Not ready\n"
+msgstr "Pas prêt\n"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr "Synchronisé"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr "Non-synchronisé"
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr "Entrez le nom"
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+"Merci d'entrer le nom du nouveau groupe.\n"
+"Après avoir cliqué sur ok vous pourrez modifier ses paramètres."
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr "Jeux d'options"
+
+#: src/battleroommmoptionstab.cpp:58
+msgid "Set name."
+msgstr "Définissez le nom."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Chargement ..."
+
+#: src/battleroommmoptionstab.cpp:63
+msgid "Load a saved set of options."
+msgstr "Charger des options prédéfinies."
+
+#: src/battleroommmoptionstab.cpp:67
+msgid "Save..."
+msgstr "Sauvegarder..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+msgid "Save a set of options."
+msgstr "Sauvegarder ce jeu d'options."
+
+#: src/battleroommmoptionstab.cpp:72
+msgid "Delete..."
+msgstr "Effacer..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+msgid "Delete a set of options."
+msgstr "Effacer ce jeu d'options."
+
+#: src/battleroommmoptionstab.cpp:77
+msgid "Set default..."
+msgstr "Définir comme options par défaut..."
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr "Utiliser les options actuelles comme options par défaut de la mod."
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Options du Mod"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Options de la carte"
+
+#: src/battleroommmoptionstab.cpp:152
+msgid "no options available"
+msgstr "pas d'options disponibles"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+"Impossible d'effacer un jeu d'options sans son nom.\n"
+"Merci d'en sélectionner un parmi ceux de la liste et de réessayer."
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "erreur"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr "Entrez le nom du jeu d'options"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+"Entrez un nom pour le jeu d'options actuel\n"
+"Si un jeu d'options avec le même nom existe déjà , il sera écrasé."
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+"Impossible de charger un jeu d'options sans un nom.\n"
+"Merci d'en sélectionner un dans la liste et de réessayer."
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr "Choisissez un jeu d'options existant dans la liste"
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr "Effacer le jeu d'options"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+msgid "Set mod default preset"
+msgstr "Définir options de la mod par défaut"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+"Les joueurs avec le même numéro d'équipe partage le contrôle de leurs unités."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+"Les joueurs avec le même numéro d'alliance jouerons ensemble pour atteindre "
+"la victoire."
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "Selectionnez une couleur pour identifier vos unités dans le jeu"
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "Selectionnez votre faction"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "Regarder la bataille au lieu de jouer"
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Je suis prêt"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "Cliquez si vous êtes satisfait des paramètres de la bataille."
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Couleur"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"Un aperçu de la carte sélectionnée. Vous pouvez voir les positions de "
+"départ, ou (le cas échéant) les zones de départ."
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Quitter"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "Quitter la bataille et revenir à la liste des parties"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Démarrer"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "Lancer la bataille"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr "Organisation des joueurs"
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr "Diverses fonctions pour simplifier la mise en place de jeux en équipe"
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Ajouter bot"
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "Ajouter un joueur contrôlé par l'ordinateur à la partie"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr "Verrouiller au lancement"
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+"Verrouille automatiquement la bataille quand le jeu commence et la "
+"déverrouille quand il est terminé."
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "Prévenir d'autres joueurs de se joindre à la bataille"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr "Hébergement automatique"
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+"Active le mode d'hébergement automatisé. Ceci permet aux joueurs de "
+"contrôler votre bataille en utilisant des commandes comme \"!balance\" et \"!"
+"start\"."
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Sélection automatique"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Démarrer"
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+"Verrouille automatiquement la bataille quand le jeu commence et la "
+"déverrouille quand il est terminé."
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr "Verrouiller les alliances"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr "Quand activé, seul l'hôte peut changer les équipes et les alliances"
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "Synchronisé"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Biper"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Non prêt"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+msgid "Force spectate ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr "Equilibrer les alliances"
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr "Répartie automatiquement les joueurs en deux alliances ou plus."
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "Arranger les couleurs"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "Rend les couleurs des joueurs différentes"
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr "Définir les équipes"
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+"Répartit automatiquement en équipes, par défaut sans partage de contrôle"
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr "Charge un jeu d'options"
+
+#: src/battleroomtab.cpp:259
+msgid "Save"
+msgstr "Sauvegarder..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr "Effacer"
+
+#: src/battleroomtab.cpp:269
+msgid "Set default"
+msgstr "Définir par défaut..."
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr "Choisissez un jeu d'options enregistré pour les définir rapidement"
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "Boîtes"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr "Choisir"
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "Continuer"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "Terminer"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr "Lignée"
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "La carte n'existe pas."
+
+#: src/battleroomtab.cpp:593
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Certains joueurs ne sont pas encore prêts.\n"
+"Voulez-vous forcer le lancement ?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Non prêt"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "Définir par défaut..."
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr "Choisir les canaux rejoints automatiquement"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+"Ajoutez une salle par ligne comme ceci :\n"
+"nomdelasalle motdepasse\n"
+"(les mots de passe des salles existantes ne sont pas affichés)"
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr "Double-cliquez pour rejoindre"
+
+#: src/channel/channelchooser.cpp:30
+msgid "Find channel:"
+msgstr "Rejoindre une salle..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr "Nom de la salle à rejoindre"
+
+#: src/channel/channellistctrl.cpp:28
+msgid "Channel"
+msgstr "Salle"
+
+#: src/channel/channellistctrl.cpp:29
+msgid "# users"
+msgstr "nb. d'utilisateurs"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr "%d canaux sur %d sont affichés"
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Session terminée à ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Impossible de créer le dossier.\n"
+"Vérifiez qu'il n'y a pas de protection en écriture.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+"La fonction d'enregistrement est désactivée jusqu'au redémarrage de "
+"SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Journaliser les avertissements"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"Impossible d'écrire le message dans le journal.\n"
+"La journalisation sera désactivée pour la salle "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr "Rejoignez cette salle pour réactiver la journalisation."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Impossible d'ouvrir le fichier journal.\n"
+"Vérifiez qu'il n'y a pas de protection en écriture.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Couleurs et police"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Utilisez les couleurs du système"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Arrière-plan"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Action"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Surligner"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Rejoindre/Quitter"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Mes messages"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Serveur"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Client"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Erreur"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Horodatage"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Notification"
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Serveur ** Connecté au serveur TAS.\n"
+"[22:30] <Dude> bonjour tout le monde\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 pense que ses couleurs sont belles\n"
+"[22:45] <Dude> Dude2: vraiment ?\n"
+"[22:46] <Dude2> Mais elles pourraient être mieux, je vais les peaufiner "
+"encore un peu...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Police :"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "Par défaut"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Sélectionner..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Comportement des zones de texte"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr "Active les couleurs IRC dans les messages du chat"
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr "Jouer les sons de notification"
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Journalisation du chat"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Enregistrer les journaux du chat"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Mots surlignés"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Mots à surligner dans le chat"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "entre une liste séparée par des ;"
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr "Optionnellement, jouer un son/faire clignoter la barre de titre "
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr "salle_"
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, c-format
+msgid "%d users"
+msgstr "%d utilisateurs"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "clic droit pour les options (comme autojoin)"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Envoyer"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr "Désactiver l'ajout de texte (workaround pour le scrolling)"
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Copier"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr "Copier le lien dans le presse-papier"
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Effacer"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "Rejoindre automatiquement cette salle"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "Afficher les messages d'arrivée/de départ"
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr "Affiche la liste des muets"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Information de la salle"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Changer le sujet..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Message dans la salle..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Verrouiller..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Déverrouiller"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Inscription ..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Se désinscrire"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Activée"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Désactivée"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "Est activé ?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Protection contre le Spam"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Déconnecter"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Reconnecter"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Supprimer..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Changer de mot de passe..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Changer l'accès..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Comptes"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "Transmission"
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Admin"
+
+#: src/chatpanel.cpp:510
+msgid "User"
+msgstr "Utilisateur"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Ouvrir Chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "Rejoindre la même partie"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Temps passé en jeu"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "Récupérer l'IP, etc"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Rendre muet..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Rendre muet pour 5 minutes"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Rendre muet pour 10 minutes"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Rendre muet pour 30 minutes"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Rendre muet pour 2 heures"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Rendre muet pour 1 jour"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Rendre la parole"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Rendre muet"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Expulser"
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Bannir..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Débannir"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "Baffer !"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Donner les droits d'opérateur"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "Prendre les droits d'opérateur"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Commande : \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" paramètres : \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "salle"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "bataille"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "serveur"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " a rejoint la "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " a quitté la "
+
+#: src/chatpanel.cpp:1029
+msgid " ** Channel topic:"
+msgstr " ** Sujet de la salle :"
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr " ** Défini par "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat fermé."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Ãtes-vous sûr de vouloir coller %d lignes ?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Attention Flood !"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Vous avez SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Vous n'êtes pas dans cette salle ou elle n'existe pas."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" Erreur: La commande (%s) n'existe pas, tapez /help pour afficher la liste "
+"des commandes disponibles."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+" Vous n'êtes pas dans une bataille ou la bataille n'existe pas, utilisez /"
+"help pour une liste des commandes."
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Utilisateur est Hors Ligne"
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Envoyé : \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "Erreur ChanServ"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ n'est pas dans cette salle."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Que devrait être le nouveau sujet ?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Message :"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "Verrouiller la salle..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Que devrait être le nouveau mot de passe ?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "Déverrouiller la salle"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Etes vous sur de vouloir déverrouiller cette salle ?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ n'est pas sur ce serveur."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Enregistrer la salle"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Qui devra être le fondateur de cette salle ?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "Désinscrire la salle"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "Etes vous sur de vouloir désinscrire cette salle ?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Supprimer le compte utilisateur"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Quel compte utilisateur voulez vous supprimer aujourd'hui ?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Supprimer compte"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Etes vous sur de vouloir supprimer ce compte ? "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Changer le mot de passe du compte utilisateur"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "De quel compte utilisateur voulez-vous changer le mot de passe ?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Quel devrait être le nouveau mot de passe ?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Non implémenté"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "Transmettre le Message"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "Message à transmettre"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "Mod non installé : "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . Veuillez le télécharger."
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr "Mod inaccessible"
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr ""
+"Cette bataille est protéger par un mot de passe, entrer le mot de passe."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Rendre l'utilisateur muet"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Pour combien de minutes l'utilisateur sera-t'il muet ?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Expluser l'utilisateur"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Raison:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Expluser l'Utilisateur"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "Rendre muet l'utilisateur"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Durée :"
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr "impossible d'ajouter le joueur"
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Se connecter au serveur lobby"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Server auquel se connecter. Vous pouvez vous connecter au serveur que vous "
+"voulez en l'entrant sous la forme adresse:port."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Mot de passe"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "Se souvenir du mot de passe"
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "Connection automatique la prochaine fois"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"se souvenir des détails de connexion et se connecter automatiquement au "
+"serveur au prochain démarrage du lobby"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"Si vous n'avez pas de compte, vous\n"
+" pouvez vous inscrire gratuitement dans l'onglet \"S'inscrire\"."
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Connexion"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "S'inscrire"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Pseudo"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Port invalide."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Port invalide"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Numéro de port en dehors des limites.\n"
+"\n"
+"Il doit être un entier entre 1 et 65535."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Hote/port invalide."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "hote invalide"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+"Le pseudonyme entré contient des caractères invalides comme )?&%.\n"
+" Merci de réessayer."
+
+#: src/connectwindow.cpp:293
+msgid "Invalid nickname"
+msgstr "Pseudonyme invalide"
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"L'inscription a échoué, la raison était :\n"
+"Mot de passe / confirmation différents (ou mot de passe vide)"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Ãchec de l'inscription."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorre"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Ãmirats Arabes Unis"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afghanistan"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua et Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albanie"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Arménie"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Antilles néerlandaises"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antarctique"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentine"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Samoa américaines"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Autriche"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Australie"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azérbaïdjan"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosnie-herzégovine"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "La Barbade"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladesh"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgique"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina-Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgarie"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahreïn"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Bénin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermudes"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunéi Darussalam"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Bolivie"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brésil"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamas"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhoutan"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Ãle Bouvet"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Biélorussie"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Bélize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Canada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "Ãles Cocos"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "République Centre-Africaine"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Congo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Suisse"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Cote D'Ivoire"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Ãles de Cook"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chili"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Cameroun"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "Chine"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Colombie"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Cuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Cap Vert"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Ãle Christmas"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Chypre"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "République Tchèque"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Allemagne"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Djibouti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Danemark"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominique"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Republique Dominicaine"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Algérie"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ãquateur"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estonie"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Ãgypte"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Sahara occidental"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Erythrée"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Espagne"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Ãthiopie"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finlande"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Les Ãles Fidji"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Ãles Malouines"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Micronésie"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Les Iles Féroé"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "France"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "France, Métropolitaine"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenade"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Géorgie"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Guyane française"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Groënland"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambie"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guinée"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadeloupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Guinée équatoriale"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Grèce"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "Géorgie du Sud et les Ãles Sandwich du Sud"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guinée-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guyana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Ãles Head et McDonald"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "République de Croatie"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haïti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Hongrie"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonésie"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irlande"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israël"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "Inde"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Territoires britanniques de l'Océan Indien"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Irak"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Iran"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Islande"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Italie"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamaïque"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Jordanie"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japon"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Kenya"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "Kirghizistan"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Cambodge"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Comores"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "Saint Christophe et Niévès"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Corée du Nord"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Corée du Sud"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Koweït"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Ãles Caïman"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kazakstan"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Lao, Rpublique Démocratique Populaire"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Liban"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Sainte-Lucie"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Liberia"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Lituanie"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Luxembourg"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Lettonie"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Lybie"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Maroc"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldova, république de"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Le Monténégro"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagascar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Ãles Marshall"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "La Macédoine"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Birmanie"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongolie"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macau"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Ãles Mariannes du Nord"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinique"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauritanie"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malte"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Maurice"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Maldives"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Mexique"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malaisie"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mozambique"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "Namibie"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Nouvelle Calédonie"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Niger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Ãle Norfolk"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigeria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nicaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Pays-Bas"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norvège"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Népal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Zone Neutre (Arabie Saoudite / Irak)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niué"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "Nouvelle-Zélande"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Oman"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panamá"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Pérou"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Polynésie française"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papouasie-Nouvelle-Guinée"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Philippines"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pakistan"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Pologne"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "Saint-Pierre-et-Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Ãles Pitcairn"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Puerto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugal"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palaos"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Qatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Réunion, île de la"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Roumanie"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "La Serbie"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Russie"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Rwanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Arabie Saoudite"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Ãles Salomon"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychelles"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Soudan"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Suède"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapour"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "St Hélène"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slovénie"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Svalbard et île Jan Mayen"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Slovaquie"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Léone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "Saint-Marin"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Sénégal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somalie"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Suriname"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "Sao Tomé-et-Principe"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "Union Soviétique (Ex-URSS)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Syrie"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Swaziland"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Ãles Turques et Caïques"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Tchad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Terres australes françaises"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Thaïlande"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tadjikistan"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Tokelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistan"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunisie"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Timor oriental"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Turquie"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad et Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Taïwan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tanzanie, République-Unie de"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ukraine"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Ouganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "Royaume-Uni (Grande-Bretagne)"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "Ãles mineures éloignées des Ãtats-Unis"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "Ãtats-Unis"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Ouzbékistan"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Cité du Vatican (Saint-Siège)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "Saint-Vincent et Les Grenadines"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Ãles Vierges (Anglaises)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Ãles Vierges (Américaines)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vit Nam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Wallis et Futuna"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Yémen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Yougoslavie"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Afrique du Sud"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Zambie"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zaïre"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(nom complet du pays non trouvé)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "Information sur le système"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "Journal de l'application"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Dernier script de lancement de Spring généré"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+msgid "Name"
+msgstr "Nom"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr "Type"
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr "Empreinte"
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr "Chercher et télécharger les fichiers"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr "Fichiers affichés"
+
+#: src/filelister/filelistdialog.cpp:58
+msgid "Download selected"
+msgstr "Télécharger la sélection"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr "%u fichiers affichés"
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr "empreinte inconnue "
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+msgid "Remove"
+msgstr "Effacer"
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr "Efface le groupe sélectionné"
+
+#: src/groupoptionspanel.cpp:61
+msgid "Rename.."
+msgstr "Renommer..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr "Renomme le groupe sélectionné"
+
+#: src/groupoptionspanel.cpp:70
+msgid "Add New.."
+msgstr "Ajouter un nouveau..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr "Ajoute un nouveau groupe"
+
+#: src/groupoptionspanel.cpp:84
+msgid "Group Actions"
+msgstr "Actions pour ce groupe"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr "Avertir de la connexion/déconnexion"
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+"Vous serez averti quand les utilisateurs de ce groupe se connecteront ou se "
+"déconnecteront."
+
+#: src/groupoptionspanel.cpp:95
+msgid "Ignore Chat"
+msgstr "Ignorer le chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+"Ignore tout ce qui est dit sur une salle par un utilisateur de ce groupe."
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr "Avertir d'une partie hébergée"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+"Vous serez averti lorsqu'un utilisateur de ce groupe héberge une bataille."
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr "Ignorer les messages privés"
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr "Ignorer tout ce qui est dit en privé par un utilisateur de ce groupe."
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr "Avertir du changement d'état"
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr "Vous serez averti lorsque l'état d'un utilisateur de ce groupe change."
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr "Expulsion automatique"
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+"Expulse automatiquement les utilisateurs de ce groupe des batailles que vous "
+"hébergez."
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr "Surligner les batailles et les noms des utilisateurs de ce groupe."
+
+#: src/groupoptionspanel.cpp:134
+msgid "Highlight Color"
+msgstr "Couleur de surlignage"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr "Choisissez la couleur du surlignage"
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr "Utilisateur dans ce groupe"
+
+#: src/groupoptionspanel.cpp:163
+msgid "Add.."
+msgstr "Ajouter..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr "Ajouter des utilisateurs au groupe"
+
+#: src/groupoptionspanel.cpp:170
+msgid "Remove users from group"
+msgstr "Retirer des utilisateurs de ce groupe"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr "Nom du nouveau groupe :"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr "Ajouter un nouveau groupe"
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr "précédente"
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr "suivante"
+
+#: src/Helper/imageviewer.cpp:92
+msgid "delete"
+msgstr "effacer"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr "enregistrer sous"
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr "impossible de supprimer le fichier"
+
+#: src/Helper/imageviewer.cpp:160
+msgid "Choose a filename"
+msgstr "Choisissez le fichier"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr "Fichier enregistré"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr "Réussite"
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr "Impossible de sauvegarder"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+msgid "Default"
+msgstr "Par défaut"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr "RECHERCHE DE %s"
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+"Les tableaux de nom de langues et d'identifieurs doivent avoir la même "
+"taille."
+
+#: src/Helper/wxTranslationHelper.cpp:145
+msgid "Select the language"
+msgstr "Choisissez une langue"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr "Langue"
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr "wxTranslationHelper: Préfixe du répertoire = \"%s\""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr "wxTranslationHelper: Nom du catalogue = \"%s\""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Heberger un nouvelle bataille"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+"Une petite description de cette partie, elle apparaîtra dans la liste de "
+"bataille."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Description"
+
+#: src/hostbattledialog.cpp:83
+#, fuzzy
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+"Verrouille automatiquement la bataille quand le jeu commence et la "
+"déverrouille quand il est terminé."
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Selectionnez le mod avec le quel vous voulez jouer."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+"Mot de passe requis pour rejoindre la partie. Laissez vide si sans mot de "
+"passe"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Port"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "Port UDP pour héberger une partie. Par défaut 8452"
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+"héberge et contrôle la partie sur une autre machine, utile si vous ne "
+"parvenez pas à héberger"
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "pas d'options disponibles"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Nombre de joueurs"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "Le nombre maximum de joueurs autorisés à rejoindre la partie."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "Hole punching"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "Traversée du NAT"
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr "Méthode de traversée de NAT à utiliser."
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Grade minimum requis"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Démarrer l'hébergement de la bataille."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "Vous devez choisir un mod d'abord."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Pas de mod séléctionner."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"enregistré dans :\n"
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"décompressé avec succès dans :\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+"\n"
+" échec de la décompression, merci de corriger manuellement"
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr "Impossible de sauvegarder\n"
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"dans :\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+"\n"
+"Erreur numéro : "
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Navigateur web"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Navigateur par défaut."
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr "Utilisez le navigateur par défaut de votre système"
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Spécifiez :"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr "Indiquez le navigateur internet que vous souhaitez utiliser"
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Parcourir"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr "Choisir le chemin du navigateur web"
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+#, fuzzy
+msgid "Path"
+msgstr "Regarder"
+
+#: src/lobbyoptionstab.cpp:79
+#, fuzzy
+msgid "Use a file dialog to find the editor binary"
+msgstr "Choisir le chemin du navigateur web"
+
+#: src/lobbyoptionstab.cpp:90
+msgid "Autoconnect"
+msgstr "Connexion automatique"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+"Si coché, SpringLobby se connectera automatiquement au dernier serveur "
+"utilisé"
+
+#: src/lobbyoptionstab.cpp:92
+msgid "Autoconnect on lobby start"
+msgstr "Connexion automatique au lancement"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr "Envoyer les statistiques"
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+"Par défaut, SpringLobby enverra des statistiques (OS, version de "
+"SpringLobby) au serveur,\n"
+"pour vous aider plus facilement en cas de problème et pour vous prévenir des "
+"mises à jour.\n"
+"Décochez pour désactiver."
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr "Envoyer les statistiques"
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr "Mises à jour automatiques"
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+"SpringLobby peut vérifier à son lancement si une version plus récente est "
+"disponible et la télécharger automatiquement pour vous."
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr "Vérifier automatiquement les mises à jour"
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr "Infobulles"
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr "Afficher des infobulles ?"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr "Nécessite le redémarrage de SpringLobby pour prendre effet."
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr "Méthode d'auto-complétion"
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+"\"Exacte\" complètera un mot si il n'y a qu'une seule possibilité.\n"
+"\"Plus proche\" sélectionnera la possibilité qui a la plus faible distance "
+"de Levenshtein."
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr "Exacte"
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr "Plus proche"
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+"Afficher des grosses icônes pour les onglets de la fenêtre principale ?"
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+msgid "Start tab"
+msgstr "Onglet de démarrage"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr "Sélectionnez quel onglet afficher au démarrage"
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "Choisissez un exécutable de navigateur web"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "Choisissez un exécutable de navigateur web"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+msgid "Disconnected from server, chat closed."
+msgstr "Déconnecté du serveur, fermeture du chat."
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "Liste de bataille"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "Salle de bataille"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Options"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+msgid "Unit Restrictions"
+msgstr "Unités interdites"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "Téléchargement mutualisé"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+msgid "General"
+msgstr "Générales"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr "Groupes"
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Restaurer"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "Appliquer"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Jeu"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr "Transferts en cours : "
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "Total sortant : "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "Total entrant : "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "inconnu"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "Annuler le téléchargement"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "Publier un fichier"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "Chercher le fichier"
+
+#: src/maintorrenttab.cpp:79
+msgid "Download Lua widgets"
+msgstr "Télécharger des widgets Lua"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr "Téléchargement de widgets Lua"
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "non disponible"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "en partage"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr "télécharge"
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr "en attente"
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "non connecté"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "connecté"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr "Etat : ralenti ou pausé (en jeu)"
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "Etat : inconnu"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "Total sortant : %.2f ko/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "Total entrant : %.2f ko/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Connexion..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&Déconnecter"
+
+#: src/mainwindow.cpp:133
+msgid "&Save options"
+msgstr "&Enregistrer les options"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Quitter"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "Rejoindre la &salle..."
+
+#: src/mainwindow.cpp:151
+msgid "Channel &list"
+msgstr "&Liste des salles"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Ouvrir un chat &privé"
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr "Canaux rejoints &automatiquement..."
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr "&Captures d'écran"
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&Recharger Cartes/Mods"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "Chercher une &mise à jour"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "&Options de Spring"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&A propos"
+
+#: src/mainwindow.cpp:168
+msgid "&Change language"
+msgstr "&Changer de langue"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&Signaler un bogue"
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Documentation"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&Fichier"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Outils"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Aide"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr "Vous devez être connecté au serveur pour voir la liste des canaux"
+
+#: src/mainwindow.cpp:450
+msgid "Not connected"
+msgstr "Non connecté"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "Rejoindre la salle..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Nom de la salle à rejoindre"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Ouvrir un chat privé..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Nom de l'utilisateur"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+"SpringLobby est un client lobby multiplateforme pour le moteur de RTS Spring."
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr "Il n'y a pas de captures d'écran dans le dossier data de spring."
+
+#: src/mainwindow.cpp:544
+msgid "No files found"
+msgstr "Aucun fichier"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "Démarrer manuellement le système de &torrents"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "Arrêter manuellement le système de &torrent"
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+"Vous devez redémarrer SpringLobby pour prendre en compte le changement de "
+"langue."
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr "Redémarrage requis"
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr "Entrez un nom pour ce profil"
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr "Quel profil voulez-vous charger ?"
+
+#: src/mainwindow.cpp:678
+msgid "Which profile do you want to be default?"
+msgstr "Quel profil voulez-vous sélectionner par défaut ?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr "Multijoueur"
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr "Solo"
+
+#: src/mainwindow.h:183
+msgid "Savegames"
+msgstr "Sauvegardes"
+
+#: src/mainwindow.h:184
+msgid "Replays"
+msgstr "Replays"
+
+#: src/mainwindow.h:186
+msgid "Downloads"
+msgstr "Téléchargements"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr "Métal: %.1f%%"
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Actualiser"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Télécharger"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "faction :"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "allié: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr "Sélectionnez une carte (cliquez-glissez pour faire défiler)"
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr "Trier verticalement selon"
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr "Trier horizontalement selon"
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr "Afficher"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr "Toutes les cartes"
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr "Affiche toutes les cartes disponibles"
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr "Cartes populaires"
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+"Affiche uniquement les cartes qui sont actuellement jouées sur le serveur. "
+"Vous devez être connecté pour utiliser ceci."
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr "Cartes jouées récemment."
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+"Affiche uniquement les cartes sur lesquelles vous avez joué récemment (en se "
+"basant sur vos replays)."
+
+#: src/mapselectdialog.cpp:94
+msgid "Filter"
+msgstr "Filtrer"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+"Affiche uniquement les cartes qui contiennent ce texte dans leur nom ou leur "
+"description."
+
+#: src/mapselectdialog.cpp:99
+msgid "Map details"
+msgstr "Détails de la carte"
+
+#: src/mapselectdialog.cpp:162
+msgid "Start positions"
+msgstr "Positions de départ"
+
+#: src/mapselectdialog.cpp:265
+msgid "Minimum wind"
+msgstr "Vent minimum"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr "Vent maximum"
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr "Vent moyen"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr "Taille (map area)"
+
+#: src/mapselectdialog.cpp:269
+msgid "Aspect ratio"
+msgstr "Rapport des dimensions"
+
+#: src/mapselectdialog.cpp:270
+msgid "Number of start positions"
+msgstr "Nombre de positions de départ"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Type de position de départ"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Comment les joueurs sélectionneront où ils commencent sur la carte\n"
+"0 : positions fixes de la carte\n"
+"1 : positions aléatoires\n"
+"2 : choisie en jeu\n"
+"3 : choisie dans le lobby avant de lancer"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Choisies en jeu"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Choisies avant la partie"
+
+#: src/mmoptionswrapper.cpp:131
+msgid "List of restricted units"
+msgstr "Liste des unités interdites"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr "Nom de la carte"
+
+#: src/mmoptionwindows.cpp:39
+msgid "Change option"
+msgstr "Modifier l'option"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "c"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Exécutables (*.exe)|*.exe|Tous les fichiers (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Tous les fichiers (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr "Paramètres de filtrage"
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr "Taille du fichier en ko :"
+
+#: src/playback/playbackfilter.cpp:190
+msgid "Duration (hh:mm:ss):"
+msgstr "Durée (hh:mm:ss)"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date"
+msgstr "Date"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr "Date d'enregistrement"
+
+#: src/playback/playbacklistctrl.cpp:42
+msgid "Modname"
+msgstr "Mod"
+
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Mapname"
+msgstr "Carte"
+
+#: src/playback/playbacklistctrl.cpp:45
+msgid "Duration"
+msgstr "Durée"
+
+#: src/playback/playbacklistctrl.cpp:46
+msgid "Spring Version"
+msgstr "Version de Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize"
+msgstr "Taille du fichier"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr "Taille du fichier en ko"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "Fichier"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr "Regarder"
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Chargement ..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr "Rafraîchir la liste"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Replays"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Sauvegardes"
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"Impossible de récupérer votre version de Spring depuis une bibliothèque "
+"unitsync."
+
+#: src/playback/playbacktab.cpp:304
+#, fuzzy, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+"Aucune version installée et compatible de spring n'a été trouvée, ce serveur "
+"nécessite la version : %s\n"
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr "Vos versions actuellement installées sont :"
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+"Vous devez télécharger la mod avant de pouvoir regarder ce replay.\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+" Je n'ai pas pu trouver la carte utilisée sur ce replay.\n"
+"Ceci peut être provoqué par tasclient qui écrit de mauvaises valeurs du hash "
+"de la carte.\n"
+"Si vous êtes sûr de posséder la carte, cliquez sur non.\n"
+"Vous devez télécharger la carte pour pouvoir visualiser ce replay.\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+"Je ne pense pas que vous pourrez visualiser ce replay.\n"
+"Essayer quand même ? (PEUT PLANTER !)"
+
+#: src/playback/playbacktab.cpp:359
+msgid "Invalid replay"
+msgstr "Replay invalide"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr "Impossible d'effacer le replay : "
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr "Filtrer les noms"
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr "Entrez un filtre pour filtrer les noms des utilisateurs en ligne"
+
+#: src/selectusersdialog.h:67
+msgid "Select Users"
+msgstr "Sélectionner des utilisateurs"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr "réponse au ping après %s ms"
+
+#: src/serverevents.cpp:144
+msgid " is online"
+msgstr " est en ligne"
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr " est maintenant "
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() a échoué ! (exception)"
+
+#: src/serverevents.cpp:225
+msgid " just went offline"
+msgstr " vient de se déconnecter"
+
+#: src/serverevents.cpp:260
+msgid " opened battle "
+msgstr " a ouvert la bataille "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "Impossible de rejoindre la salle"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Impossible de rejoindre la salle "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " car : "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Message du serveur"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " détient l'ip : %s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " ne supporte pas vraiment la traversée de NAT"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "Vous avez été expulsé de la partie !"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "Expulsé par l'hôte"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr "Début de la liste des muets pour "
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr "Muets sur %s"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr " aucune limite de durée"
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr " %d minutes restantes"
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr "Fin de la liste des muets pour "
+
+#: src/serverevents.cpp:950
+msgid "Download update"
+msgstr "Téléchargement d'une mise à jour"
+
+#: src/serverevents.cpp:950
+#, fuzzy, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+"Voulez-vous télécharger %s ? Le fichier apporte les mises à jour "
+"suivantes :\n"
+"%s"
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"Il y a eu une erreur pendant le téléchargement de la dernière version.\n"
+"Merci de vous mettre à jour manuellement depuis http://springrts.com"
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Notification"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Pseudonyme invalide"
+
+#: src/serverevents.cpp:987
+msgid "No Handler"
+msgstr ""
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "La carte n'existe pas."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Activé"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Reconnecter"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "Inconnu"
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr "Téléchargement terminé, l'emplacement est : "
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+msgid "Download complete."
+msgstr "Téléchargement terminé."
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr "Impossible de lancer l'installeur. L'emplacement du fichier est : "
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr "Impossible de lancer l'installeur."
+
+#: src/settings++/Defs.hpp:212
+#, fuzzy
+msgid "Scrollwheel speed"
+msgstr "Limiter les vitesses :"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Détail graphique"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Détail graphique"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "Synchronisé"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Salle de bataille"
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "Unités interdites"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "Définir par défaut..."
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+#, fuzzy
+msgid "Use less colors"
+msgstr "Utilisez les couleurs du système"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+#, fuzzy
+msgid "Show in-game player information"
+msgstr "Information sur le système"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+#, fuzzy
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "Vitesse de défilement (clavier et souris)"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+#, fuzzy
+msgid "Catch AI exceptions"
+msgstr "Exacte"
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Sélectionner..."
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Bump-mapped"
+msgstr "Eau bump-mappée"
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+msgid "Blur reflection"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Sélectionner..."
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+msgid "Reflection texture size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Durée"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Désactivée"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "Options combinées"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "Qualité d'affichage / Mode vidéo"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "Détail du rendu"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "Options de l'interface"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Audio"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+"Les changements faits dans l'onglet Qualité/Détail\n"
+"en mode expert seront perdus si vous changez les\n"
+"options simples à nouveau.\n"
+"Egalement, ces changements NE SERONT PAS visibles\n"
+"dans les choix de l'onglet Options combinées (ce\n"
+"message peut être désactivé dans le meni \"Fichier\")"
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "Erreur !"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "Sauvegarder les paramètres de Spring avant de sortir ?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "Confirmation nécessaire"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "SpringSettings (mode expert)"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "SpringSettings (mode simple)"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "Sauvegarder les paramètres"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "Réinitialiser les paramètres aux valeurs par défaut"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "Désactiver l'avertissement du mode expert"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "Quitter"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "Simple (peu d'options)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "Expert (toutes les options)"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "A propos"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Contact"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "Crédits"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "Signaler un bug"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Mode"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Info/Aide"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "Rétablier TOUS les paramètres aux valeurs par défaut ?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Astuce"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+"SpringSettings est une interface graphique pour le réglage du Spring engine"
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr "Kloot"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "L'équipe de SpringLobby"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+"merci de m'avoir invité, code à réutiliser, infrastructure et aide en général"
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr "tous ceux qui rapportent des bogues/des suggestions"
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+"Cette application a généré une erreur fatale et va se terminer.\n"
+"La génération d'un rapport de bogue n'est pas possible.\n"
+"Merci d'activer wxUSE_DEBUGREPORT"
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Erreur critique"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr "affiche ce message d'aide"
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr "ne pas utiliser le gestionnaire de crashs (utile pour le débogage)"
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr "écrire le journal de l'application dans la console (si possible)"
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr "active l'affichage du journal de l'application dans une fenêtre"
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+"force la verbosité par défaut du journal, peut être :\n"
+" 0: pas de journal\n"
+" 1: erreurs critiques\n"
+" 2: erreurs\n"
+" 3: avertissements (par défaut)\n"
+" 4: messages\n"
+" 5: appels de fonction"
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "Chemin vers la bibliothèque unitsync"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+"Il y a eu un problème en récupérant vos paramètres.\n"
+"Merci de vérifier que le chemin ci-dessous est correct.\n"
+"Quand vous l'aurez corrigé, cliquez sur le bouton\n"
+"\"Utiliser ce chemin\" à nouveau pour réessayer."
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "Utiliser ce chemin"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "unitsync.so sous Linux, unitsync.dll sous Windows"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "Réglage des chemins"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "Choisissez une bibliothèque unitsync"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Tous les fichiers"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+"SpringSettings ne peut pas charger votre bibliothèque\n"
+" unitsync.\n"
+"Vous devriez vérifier les paramètres d'unitsync.\n"
+"Votre version de Spring doit être 0.76 ou plus récent,\n"
+"sinon ceci échouera à chaque fois."
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "basse"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "moyenne"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "haute"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "très basse"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "très haute"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "Impossible de lancer le navigateur par défaut"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "Impossible de lancer le navigateur. L'URL est : "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "Impossible de lancer le navigateur."
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "Impossible d'accéder à vos paramètres.\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "Impossible de sauvegarder, unitsync n'est pas chargée correctement"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "Erreur de SpringSettings"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Options audio"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Résolution de l'écran"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+"Si une option nécessite du matériel spécial pour\n"
+"fonctionner, ce sera mentionné dans l'infobulle."
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Qualité de l'eau"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "Résolution en bits"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "Options de qualité du rendu"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "Options du mode vidéo"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "Options d'anti-aliasing"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr "Z-Buffer (tampon de profondeur)"
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr "Eau bump-mappée"
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "Niveau de détail du rendu"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+"Ces options vous permettent de contrôler le rendu de Spring.\n"
+"Pour plus de vitesse, essayez de diminuer ces réglages.\n"
+"Un contrôle total sur tous les paramètres est accessible dans\n"
+"le \"Mode expert\", soit en cliquant sur le bouton à droite\n"
+"soit en utilisant le menu \"Mode\" dans la barre d'outils du\n"
+"haut. Vous pouvez revenir dans ce mode à n'importe quel\n"
+"moment en choisissant \"Mode simple\" dans le menu \"Mode\".\n"
+"Si vous rencontre des messages d'erreur concernant les\n"
+"graphismes dans Spring, il pourrait être nécessaire de\n"
+"désactiver certaines options en mode expert.\n"
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "Qualité graphique"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Détail graphique"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Résolution de l'écran"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "Passer en mode expert"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (actuel)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+"Définit toutes les options de qualité à des valeurs prédéfinies en fonction "
+"de votre choix."
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+"Définit toutes les options de détail à des valeurs prédéfinies en fonction "
+"de votre choix."
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+"Choisissez la résolution qui convient pour votre écran(s).\n"
+"Choisir une résolution pour deux écran activera automatiquement le mode deux "
+"écrans.\n"
+"Si la résolution appropriée n'est pas accessible vous pouvez la définir "
+"manuellement en mode expert.\n"
+"Veuillez aussi contacter l'auteur afin qu'elle soit ajoutée dans les futures "
+"versions."
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Info"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+"Placer une barre à 0 empêchera cette caméra\n"
+"d'être sélectionnée pendant le jeu"
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "Vitesse de défilement (clavier et souris)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "Mode de caméra par défaut"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "Options diverse de l'interface"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "Zoom"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+"Vous pouvez déplacer le soleil/ordinateur sur la carte pour choisir la "
+"position de départ.\n"
+" Passer la souris sur l'icône permet de changer la faction, l'alliance et le "
+"bonus."
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "Ajouter un bot..."
+
+#: src/singleplayertab.cpp:100
+msgid "Spectate only"
+msgstr "Observer seulement"
+
+#: src/singleplayertab.cpp:103
+msgid "Random start positions"
+msgstr "Positions de départ aléatoires"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- Faites un choix --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "Paramètres de jeu invalides"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Vous devez d'abord sélectionner une carte."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+"Continuer sans ajouter un bot ?\n"
+" La partie sera terminée plutôt vite.\n"
+" "
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "Aucun bot ajouté"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "Vous ne pouvez pas lancer Spring alors qu'il est déjà lancé"
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Salut "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+",\n"
+"Apparemment c'est la première fois que tu utilises SpringLobby. J'ai deviné "
+"une configuration qui je pense fonctionnera pour toi mais tu devrais la "
+"vérifier, particulièrement la configuration de Spring.\n"
+"\n"
+"Quand tu auras fini tu pourras aller dans la menu Fichier, se connecter à un "
+"serveur, et apprécier une bonne partie de Spring :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Bienvenue"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+"Par défaut SpringLobby envoie certaines statistiques.\n"
+"Vous pouvez le désactiver dans les options, onglet \"Générales\"."
+
+#: src/springlobbyapp.cpp:172
+msgid "Notice"
+msgstr "Remarque"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr "Dois-je essayer d'importer (quelques) réglages de TASClient ?\n"
+
+#: src/springlobbyapp.cpp:188
+msgid "Import settings?"
+msgstr "Importer les paramètres ?"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+"Cette application a généré une erreur fatale et va être terminée\n"
+"La génération d'un rapport de bogue n'est pas possible\n"
+"\n"
+"Merci de récupérer une bibliothèque wxWidgets qui supporte wxUSE_DEBUGREPORT"
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr "seulement effectuer la mise à jour, quitter immédiatement ensuite"
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+msgid "Ignore chat"
+msgstr "Ignorer le chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr "Expulsion automatique d'une bataille"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+msgid "Friends"
+msgstr "Amis"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr "Chercher uniquement dans le répertoire d'installation"
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "Exécutables de Spring"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Emplacement"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Chercher"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "Bibliothèque unitsync"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Configuration automatique"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "Choisissez un exécutable de Spring"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Bibliothèque"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr "Choisir la bibliothèque UnitSync"
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+"SpringLobby ne parvient pas à charger votre bibliothèque UnitSync.\n"
+"\n"
+"Vous devriez vérifier vos paramètres concernant UnitSync."
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "Choisir un dossier"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+"La création des répertoires a échoué\n"
+"Veuillez créer manuellement les dossiers suivants :"
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Délai de connexion expiré"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Réponse inconnue du serveur"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+"Echec de la traversée du NAT, cette bataille risque de ne pas fonctionner "
+"pour vous ou d'autres joueurs."
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr "ligne "
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ", colonne "
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "nb. copies"
+
+#: src/torrentlistctrl.cpp:48
+msgid "MB downloaded"
+msgstr "Mo téléchargés"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "Mo envoyés"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Etat :"
+
+#: src/torrentlistctrl.cpp:60
+#, fuzzy, c-format
+msgid "% complete"
+msgstr "% effectués"
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "ko/s sortant"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "ko/s entrant"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "temps restant estimé (s)"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "Taille (Mo)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "Démarrer le torrent automatiquement"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr "lors de la connexion"
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr "lors du lancement"
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "manuel"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr "Suspendre au lancement d'une partie"
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "Suspendre les torrents"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr "Limiter les vitesses :"
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "envoi (ko/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "téléchargement (ko/s)"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "Chiffres"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "vitesse d'envoi maximum en ko/s (-1 > sans limite)"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "vitesse de réception maximum en ko/s (-1 > sans limite)"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "port utilisé pour les connexions torrent"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "connexions parallèles maximum"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+"Tous les trackers ont été testés. Aucune connexion au système de torrents "
+"n'a pu être établie."
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr "Echec du système de torrents"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Mot de passe du serveur"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Réussite de l'inscription,\n"
+"vous devriez maintenant pouvoir vous connecter."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Inscription réussie"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "Echec de l'inscription, la raison était :\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"Le chemin d'accès du navigateur est : "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "Erreur d'aide"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "Tapez /help dans une fenêtre de chat."
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "Aide sur les commandes de SpringLobby."
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Commandes globales :"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - Définit votre état comme absent."
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - Retire votre état absent."
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+" \"/changepassword oldpassword newpassword\" - Change le mot de passe du "
+"compte actuellement actif."
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - Liste les salles actuellement actives."
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+" \"/help [sujet]\" - Ajoutez \"sujet\" si vous voulez obtenir des "
+"informations plus spécifiques sur une commande."
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+" \"/join salle [mot de passe] [,salle2 [mot de passe2]]\" - Rejoint une "
+"salle."
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Raccourcis pour /join."
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" - Affiche combien de temps vous avez en jeu."
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+" \"/msg pseudo [texte]\" - Envoie un message privé contenant texte à pseudo."
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/part\" - Quitte la salle actuelle."
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/p\" - Raccourci pour /part."
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename nouveaunom\" - Change votre pseudo en nouveaunom."
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+" \"/sayver\" - Dit quelle version de SpringLobby vous utilisez dans le chat."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr " \"/testmd5 text\" - Retourne le hash md5-b64 du texte donné."
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - Affiche quelle version de SpringLobby vous utilisez."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr " \"/clear\" - Efface tout le texte de la fenêtre actuelle"
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Commandes de chat :"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me action\" - Fait une action dans le style d'IRC."
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+"Si vous ne comprenez pas une commande, allez sur #springlobby et essayez de "
+"la taper ici :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Pas de sujets écrits pour le moment."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Le sujet \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+"\" n'a pas été trouvé. Tapez \"/help sujets\" seulement pour des sujets "
+"disponibles."
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Impossible de récupérer votre version de Spring depuis la bibliothèque "
+"unitsync.\n"
+"\n"
+"Le jeu en ligne est actuellement désactivé."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+"Aucune version installée et compatible de spring n'a été trouvée, ce serveur "
+"nécessite la version : %s\n"
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr "Le jeu en ligne est actuellement désactivé."
+
+#: src/ui.cpp:661
+msgid "Disconnected from server."
+msgstr "Déconnecté du serveur."
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+"Une connexion au serveur n'a pas pu être établie\n"
+"Voulez-vous essayer à nouveau avec le même serveur ?\n"
+"Non pour passer au prochain serveur dans la liste"
+
+#: src/ui.cpp:673
+msgid "Connection failure"
+msgstr "Echec de la connexion"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "aucun onglet de chat ouvert."
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d utilisateurs)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Message du serveur"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "La partie actuelle a été fermée par l'hôte."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "Partie fermée"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Vos paramètres de Spring ne sont probablement pas réglés\n"
+"correctement, vous devriez les vérifier avant de tenter\n"
+"de jouer en ligne."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Erreur de configuration de Spring"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr "Le jeu d'options sélectionné nécessite la carte "
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+". Faut-il la télécharger ? Choisir \"non\" retirera la carte manquante du "
+"jeu d'options\n"
+"Merci de resélectionner le jeu d'options après la fin du téléchargement."
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr "Carte manquante"
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Il y a eu une erreur pendant la recherche d'une nouvelle version.\n"
+"Merci de réessayer plus tard.\n"
+"Si le problème persiste, merci d'utiliser Aide->Signaler un bogue pour "
+"rapporter ce bogue."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Votre Version: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Dernière Version: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"Votre version de SpringLobby n'est pas à jour.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+"\n"
+"\n"
+"Dois-je télécharger la dernière version ? Les changements prendront effet la "
+"prochaine fois que vous lancerez le lobby."
+
+#: src/updater/updater.cpp:55
+msgid "Not up to date"
+msgstr "Pas à jour"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr "SpringLobby -- télécharge une mise à jour"
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Non à jours"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+"Impossible d'écrire dans le répertoire d'installation.\n"
+"Vérifiez manuellement ou donnez à l'utilisateur actuel la permission "
+"d'écrire."
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Il y a eu une erreur pendant le téléchargement de la dernière version.\n"
+"Merci de réessayer plus tard.\n"
+"Si le problème persiste, merci d'utiliser Aide->Signaler un bogue."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"Il y a eu une erreur en tentant de remplacer la version actuelle de "
+"l'exécutable.\n"
+" une copie manuelle est nécessaire depuis : %s\n"
+" vers : %s\n"
+"Merci d'utiliser Aide->Signaler un bogue pour rapporter ce bogue."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+"Mise à jour effectuée. Les modifications seront accessibles au prochain "
+"lancement."
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+"Exécutable mis à jour.\n"
+"Certains fichiers de traduction n'ont pas pu être mis à jour.\n"
+"Merci de le signaler sur #springlobby après avoir redémarré."
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr "Succès partiel"
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+"Pour prévenir les problèmes logiques, il n'est pas permis d'ajouter un "
+"utilisateur à plus d'un seul groupe."
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr "Impossible d'ajouter l'utilisateur au groupe."
+
+#: src/useractions.h:11
+msgid "none"
+msgstr "aucune"
+
+#: src/useractions.h:11
+msgid "highlight"
+msgstr "surligner"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr "avertir de la connexion/déconnexion"
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr "ignorer le chat"
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr "ignorer les messages privés"
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr "expulsion automatique"
+
+#: src/useractions.h:12
+msgid "notify hosted battle"
+msgstr "avertir d'une partie hébergée"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr "avertir du changement d'état"
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr "aucune action"
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+"surligne l'utilisateur dans les listes d'utilisateur et les batailles "
+"auxquelles il participe"
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+"affiche une popup quand l'utilisateur se connecte ou se déconnecte du serveur"
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+"ignore les messages privés de ces utilisateurs, aucune fenêtre ne s'ouvrira "
+"si l'un d'eux tente de vous contacter en privé"
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr "affiche une popup quand l'utilisateur héberge une nouvelle partie"
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr "affiche une popup quand l'utilisateur change son statut d'absence"
+
+#: src/user.cpp:77
+msgid "away"
+msgstr "absent"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr "de retour"
+
+#: src/user.cpp:79
+msgid "ingame"
+msgstr "en jeu"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr "de retour du jeu"
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "Débutant"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "Débutant"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "Normal"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Au dessus de la moyenne"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "Vétéran"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "Très expérimenté"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Vétéran"
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr "Inconnu"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr "Créer un nouveau groupe..."
+
+#: src/usermenu.h:29
+msgid "Add to group..."
+msgstr "Ajouter à un groupe..."
+
+#: src/usermenu.h:30
+msgid "Remove from group"
+msgstr "Retirer du groupe"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr "widgets"
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr "récupère les infos"
+
+#: src/widgets/infopanel.cpp:64
+msgid "Author"
+msgstr "Auteur"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr "Mods adaptées"
+
+#: src/widgets/infopanel.cpp:74
+msgid "Current version"
+msgstr "Version actuelle"
+
+#: src/widgets/infopanel.cpp:79
+msgid "# downloaded"
+msgstr "Nb. de téléchargements"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr "Publié le"
+
+#: src/widgets/infopanel.cpp:121
+msgid "Changelog"
+msgstr "Changelog"
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr "Captures d'écran"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr "Le widget a été installé."
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr "Le widget n'a pas été installé."
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr "Le widget a été supprimé."
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr "Le widget n'a pas été supprimé."
+
+#~ msgid "spectators"
+#~ msgstr "Spectateurs"
+
+#~ msgid "players"
+#~ msgstr "joueurs"
+
+#~ msgid "max"
+#~ msgstr "max"
+
+#~ msgid "team"
+#~ msgstr "Ãquipe"
+
+#~ msgid "ally"
+#~ msgstr "Alliance"
+
+#~ msgid "cpu"
+#~ msgstr "CPU"
+
+#~ msgid "Test firewall"
+#~ msgstr "Tester le pare-feu"
+
+#~ msgid "Relay battle to an Autohost"
+#~ msgstr "Relayer la bataille à un Autohost"
+
+#~ msgid "Game is open."
+#~ msgstr "La partie est ouverte."
+
+#~ msgid "Game is password-protected."
+#~ msgstr "La partie est protégée par un mot de passe."
+
+#~ msgid "Game is full."
+#~ msgstr "La partie est pleine."
+
+#~ msgid "Game is full and password-protected."
+#~ msgstr "La partie est pleine et protégée par un mot de passe."
+
+#~ msgid "Game is closed."
+#~ msgstr "La partie est fermée."
+
+#~ msgid "Game is closed and password-protected."
+#~ msgstr "La partie est fermée et protégée par un mot de passe."
+
+#~ msgid "Game is closed and full."
+#~ msgstr "La partie est fermée et pleine."
+
+#~ msgid "Game is closed, full and password-protected."
+#~ msgstr "La partie est fermée, plein et protégée par un mot de passe."
+
+#~ msgid "Game is in progress."
+#~ msgstr "La partie est en cours."
+
+#~ msgid "Game is in progress and password-protected."
+#~ msgstr "La partie est en cours et protégée par un mot de passe."
+
+#~ msgid "Game is in progress and full."
+#~ msgstr "La partie est en cours et pleine."
+
+#~ msgid "Game is in progress, full and password-protected."
+#~ msgstr "La partie est en cours, pleine et protégée par un mot de passe."
+
+#~ msgid "Game is in progress and closed."
+#~ msgstr "La partie est en cours et fermée."
+
+#~ msgid "Game is in progress, closed and password-protected."
+#~ msgstr "La partie est en cours, fermée et protégée par un mot de passe."
+
+#~ msgid "Game is in progress, closed and full."
+#~ msgstr "La partie est en cours, fermée et pleine."
+
+#~ msgid "Game is in progress, closed, full and password-protected."
+#~ msgstr ""
+#~ "La partie est en cours, fermée, pleine et protégée par un mot de passe."
+
+#~ msgid "Tab icons"
+#~ msgstr "Icônes des onglets"
+
+#~ msgid "Chose in game"
+#~ msgstr "Choisies en jeu"
+
+#~ msgid ""
+#~ "No compatible installed spring version has been found, this replay "
+#~ "requires version: %s\n"
+#~ msgstr ""
+#~ "Aucune version installée et compatible de spring n'a été trouvée, ce "
+#~ "replay nécessite la version : %s\n"
+
+#~ msgid ""
+#~ "Download started in the background, please be patient\n"
+#~ "you will be notified on operation completed."
+#~ msgstr ""
+#~ "Téléchargement lancé en tâche de fond, merci de patienter\n"
+#~ "vous serez averti à la fin de l'opération."
+
+#~ msgid "Download started"
+#~ msgstr "Téléchargement en cours"
+
+#~ msgid "You refused a mandatory update, you will be disconnected now."
+#~ msgstr ""
+#~ "Vous avez refusé une mise à jour obligatoire, vous allez maintenant être "
+#~ "déconnecté."
+
+#~ msgid "Disconnecting"
+#~ msgstr "Déconnexion"
+
+#~ msgid "Debug"
+#~ msgstr "Débogage"
+
+#~ msgid "Debug Options"
+#~ msgstr "Options de débogage"
+
+#~ msgid "Player"
+#~ msgstr "Joueur"
+
+#~ msgid "Timeout assumed, disconnecting"
+#~ msgstr "Timeout de la connexion détecté, déconnexion"
+
+#~ msgid "status"
+#~ msgstr "état"
+
+#~ msgid "Choose color"
+#~ msgstr "Choisissez une couleur"
+
+#~ msgid "Choose color (only first 16 will be saved)"
+#~ msgstr ""
+#~ "Choisissez une couleur (seulement les 16 premiers seront sauvegardées)"
diff --git a/po/insert-header.sin b/po/insert-header.sin
new file mode 100644
index 0000000..b26de01
--- /dev/null
+++ b/po/insert-header.sin
@@ -0,0 +1,23 @@
+# 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
+}
diff --git a/po/it.gmo b/po/it.gmo
new file mode 100644
index 0000000..e336d41
Binary files /dev/null and b/po/it.gmo differ
diff --git a/po/it.po b/po/it.po
new file mode 100644
index 0000000..94c2f55
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,6378 @@
+# Italian translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-07-30 23:29+0000\n"
+"Last-Translator: Daedalus <osd_daedalus at hotmail.com>\n"
+"Language-Team: Italian <it at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Aggiungi bot"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Nickname:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "IA"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Scegli la libreria IA da utilizzare con questo bot"
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Valore"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Annulla"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Aggiungi Bot"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Nessuna IA trovata nella tua installazione di Spring"
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Nessuna libreria bot è stata trovata"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Accetta i termini"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Accetti i termini di questa licenza?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Sì"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "No"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "Bilancia automaticamente le squadre"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr ""
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "Dividi equamente i ranghi"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Casuale"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr ""
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Nessuno"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr ""
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr ""
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"Colloca membri dello stesso clan (utenti che hanno lo stesso tag, come "
+"'[smurfzor]Alice' and '[smurfzor]Bob') nella stessa alleanza insieme. \n"
+"Nessuno: Niente di speciale per i clan.\n"
+"Leale: colloca i membri di un clan come alleati, a meno che questo non "
+"squilibri le squadre.\n"
+"Sempre: colloca sempre i membri di un clan nella stessa alleanza, anche se "
+"dovesse squilibrare le squadre."
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Numero di giocatori"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Riconnetti"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Descrizione"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Mappa"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Host"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Spettatori:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Giocatori"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Mappa"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Scarica &mappa"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "Scarica m&od"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Spettatori:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Giocatori"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Host:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Stato:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Bloccata"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Privata con password"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Evidenzia"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Limite di grado"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Descrizione:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Avviata"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Piena"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Aperta"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Giocatore:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Tutte"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Mappa:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Solo mappe che possiedo"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Solo mod che possiedo"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Spettatore:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Giocatori"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "File"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Avviata"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "Battaglia chiusa"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Nuova partita"
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "Partecipa"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Tu non puoi hostare una partita mentre sei offline. Connettiti prima a una "
+"lobby server."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Non online"
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+"L'host e' disabilitato a causa dell'icompatibilità della versione di Spring "
+"che stai usando"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Spring error"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Già in battaglia"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Sei già in battaglia.\n"
+"Vuoi lasciare la partita corrente per far partire una nuova?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+"La battaglia non è iniziata perchè il mod che hai selezionato non e' stato "
+"rilevato "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Errore all'apertura della partita."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Non posso trovare nessuna mappa nella directory di Spring. Questo puo' "
+"succedere se Spring non è settato correttamente."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Nessuna mappa trovata"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"La partecipazione alla battaglia è disabilitato a causa dell'incopatibilità "
+"della versione di spring che stai usando."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Già in battaglia"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Sei già in battaglia.\n"
+"Vuoi lasciare la partita corrente per far partire una nuova?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Già in battaglia"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Tu sei già in battaglia.\n"
+"Vuoi lasciare la battaglia corrente e partecipare ad un'altra?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Sei già all'interno di una stanza, chiudila prima di essere in grado di "
+"unirti a un'altra partita."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Nessun mod disponibile"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Mappa non disponibile"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Password della partita"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Inserire password"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Seleziona..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Opzione"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Valore"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Dimensione"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Velocità del vento"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Forza delle maree"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravità "
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Raggio degli estrattori"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Metallo massimo"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Fisso"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Scegli in gioco"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "Scegli in gioco"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Posizioni di partenza"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Restrizioni unità "
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Unità permesse"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Le unità in questa lista saranno disponibili in gioco."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Abilita tutte le unità ."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Abilita tutte le unità ."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Abilita tutte le unità ."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Restrizioni unità "
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Le unità in questa lista non saranno disponibili in gioco."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Restrizioni unità "
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Nickname"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Squadra"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Allineamento"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Bonus risorse"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Fazione"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Settaggio colori"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Settaggio Risorse Bonus"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Spettatore"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Kick"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Fai uno squillo"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Inserisci a valore tra 0 e 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Aggiungi bot"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Oman"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Spettatore"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Giocatore:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Host"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Client"
+
+#: src/battleroomlistctrl.cpp:732
+msgid "Ready\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Non pronto"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "Abilita V-Sync"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Setta l'accesso..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Caricamento..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Carica un set di restrizioni."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Salva..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Salva un set di restrizioni."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Seleziona..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Salva un set di restrizioni."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "default"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Opzioni del mod"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Opzioni della mappa"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "Nessun mod disponibile"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "errore"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Seleziona"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "default"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Sono pronto"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Colore"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Esci"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Avvio"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Aggiungi bot..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Riconnetti"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Avvio"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "Abilita V-Sync"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Fai uno squillo"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Non pronto"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+msgid "Force spectate ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Salva..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "Seleziona"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "default"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr ""
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr ""
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Alcuni giocatori non sono pronti.\n"
+"Vuoi fare uno squillo a questi giocatori."
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Non pronto"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "default"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "Non è stato possibile entrare nel canale "
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "&Entra nel canale..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "Nome del canale in cui entrare"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "canale"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "Kick l'utente"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Sessione chiusa a ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Avvertimento Log"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Non posso aprire il file di log.\n"
+"Assicurati che non ci sia una protezione in scrittura.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Colori e fonts"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Usa colori di sistema"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normale"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Sfondo"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Azione"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Evidenzia"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Partecipa/Lascia"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "I miei messaggi"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Server"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Client"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Errore"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Marcatempo"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Notifica"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Connected to TAS Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Font:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "default"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Seleziona..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Comportamento"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Chat logs"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Salva i chat logs"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Evidenzia parole"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Parole da evidenziare nella chat:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "Kick l'utente"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Invia"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Copia"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Pulisci"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr ""
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr ""
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Informazioni del canale"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Setta il topic..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Messaggio sul canale..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Chiudi..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Sblocca"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Registra..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Annulla registrazione"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Acceso"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Disattivato"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "è attivato?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Protezione contro lo spam"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Disconnetti"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Riconnetti"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Rimuovi..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Cambia password..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Setta l'accesso..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Accounts"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr ""
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Amministratore"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Zittisci utente"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Chat aperta"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "Partecipa alla stessa battaglia"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Tempo all'interno del gioco"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "Recupera IP e Smurfs"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Zittisci..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Zittisci per 5 minuti"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Zittisci per 10minuti"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Zittisci per 30 minuti"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Zittisci per 2 ore"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Zittisci per 1 giorno"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Togli il mute"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Mute"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Kick..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Banna..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Togli il ban"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr ""
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Op"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "DeOp"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Comando: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" parametri: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "canale"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "battaglia"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "server"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " partecipa alla "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " lasciato il "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Informazioni del canale"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * Settato da "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat chiusa."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Sei sicuro di voler incollare %d linee?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Tu hai springlobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Tu non sei nel canale o il canale non esiste."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" Errore: Il comando (%s) non esiste. Usa /help per una lista dei comandi "
+"disponibili."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Utente non in linea."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Inviato: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ChanServ error"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ non è in questo canale."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Cosa dovrebbe essere il nuovo topic?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Messaggio:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "Chiudi il canale..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Quale dovrebbe essere la nuova password?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "Sblocca il canale"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Sei sicuro di voler sbloccare questo canale?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ non è su questo server."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Registra il canale"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Chi dovrebbe essere considerato fondatore di questo canale?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "Sei sicuro di volere eliminare la registrazione di questo canale?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Rimuovi l'account dell'utente"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Quale user accaunt vuoi rimuovere?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Rimuovi account"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Sei sicuro di rimuovere l'accaunt "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Cambia la password"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Di quale account utente vuoi cambiare la password?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr ""
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Non Implementato"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "Messaggio trasmesso in broadcast"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "Messaggio da trasmettere in broadcast"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "Non possiedi il mod "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . Per favore scaricalo prima."
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "La partita è protetta da password, per entrare inseriscila."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Zittisci utente"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Per quanti minuti questo utente deve essere zittito?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr ""
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Motivo:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Kick l'utente"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "Mute l'utente"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Durata:"
+
+#: src/chatpanel.cpp:1797
+#, fuzzy
+msgid "couldn't add user"
+msgstr "Non posso lanciare il browser"
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Connesso a lobby server"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Server al quale connettersi. Puoi connetterti a qualsiasi server indicato "
+"nel formato indirizzo:porta"
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Password"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"Nota: se non hai un account,\n"
+" puoi crearne uno gratuitamente nella\n"
+"scheda \"Registrati\"."
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Accesso"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Registrati"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Nick"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Porta non valida."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Porta non valida"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Numero di porta fuori limite.\n"
+"\n"
+"Deve essere un numero intero tra 1 e 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Indirizzo non valido"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Numero non valido."
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"Registrazione non riuscita. Il motivo è stato:\n"
+"Le password non coincidono tra loro"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Registrazione non riuscita."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Emirati Arabi Uniti"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afghanistan"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua e Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albania"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Armenia"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Antille Olandesi"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antartide"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentina"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Samoa Americane"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Austria"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Australia"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azerbaijan"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosnia-Herzegovina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladesh"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgio"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgaria"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahrain"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermuda"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunei"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Bolivia"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brasile"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamas"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhutan"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Isole Bouvet"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Bielorussia"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Canada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "Repubblica Centroafricana"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Congo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Svizzera"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Costa D'Avorio"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Isole Cook"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Cile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Camerun"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "Cina"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Colombia"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Cuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Capo Verde"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Isola di Natale"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Cipro"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "Repubblica Ceca"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Germania"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Gibuti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Danimarca"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominica"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Repubblica Dominicana"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Algeria"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ecuador"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estonia"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Egitto"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Sahara occidentale"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritrea"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Spagna"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Etiopia"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finlandia"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fiji"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Isole Falkland (Malvine)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Micronesia"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Isole Fær Ãer"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "Francia"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "Francia Metropolitana"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Georgia"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Guiana Francese"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibilterra"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Groenlandia"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambia"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guinea"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadalupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Guinea Equatoriale"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Grecia"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guinea Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guyana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Isole Heard e McDonald"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Croazia (Hrvatska)"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Ungheria"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonesia"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irlanda"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israele"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "India"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Territorio Britannico dell'Oceano Indiano"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Iraq"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Iran"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Islanda"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Italia"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Giamaica"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Giordania"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Giappone"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Kenya"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Cambogia"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr ""
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "San Kitts e Nevis"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Corea del Nord (Repubblica Popolare)"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Corea del Sud (Repubblica)"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuwait"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Isole Cayman"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kazakistan"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Libano"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Santa Lucia"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Liberia"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Lituania"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Lussemburgo"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Lettonia"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Libia"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Marocco"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldavia"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Montenegro"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagascar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Isole Marshall"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Macedonia"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr ""
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongolia"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macao"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Isole Marianne Settentrionali"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinica"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauritania"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Mauritius"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Maldive"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Messico"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malesia"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mozambico"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "Namibia"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Nuova Caledonia"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Niger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Isole Norfolk"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigeria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nicaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Olanda"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norvegia"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Zona Neutrale (Arabia Saudita/Iraq)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "Nuova Zelanda"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Oman"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panama"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Perù"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Polinesia francese"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua Nuova Guinea"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Filippine"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pakistan"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Polonia"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "St. Pierre e Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Isole Pitcairn"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Porto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portogallo"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palau"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Qatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr ""
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Romania"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Serbia"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Federazione Russa"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Ruanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Arabia Saudita"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Isole Solomon"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychelles"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Sudan"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Svezia"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapore"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "Sant'Elena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slovenia"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Isole Svalbard e Jan Mayen"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Slovacchia"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Leone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somalia"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Suriname"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr ""
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr ""
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "El Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Siria"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Swaziland"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Ciad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Territori Francesi Meridionali"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Thailandia"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tagikistan"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Tokelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistan"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunisia"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Timor Est"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Turchia"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad e Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Taiwan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tanzania"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ucraina"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "Regno Unito (Gran Bretagna)"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "Isole esterne minori americane"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "Stati Uniti"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Uzbekistan"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Stato della Città del Vaticano (Santa Sede)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Isole Vergini (UK)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Isole Vergini (US)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vietnam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Isole Wallis e Fortuna"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Yemen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Yugoslavia"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Sud Africa"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Zambia"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zaire"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Nome completo della nazione non trovato)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "Informazioni di sistema"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "Log esteso dell'applicazione"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Ultimo script di avvio di spring generato"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Partita"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Nessun mod selezionato."
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+#, fuzzy
+msgid "unknown hash "
+msgstr "sconosciuto"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Rimuovi..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Rimuovi..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "Aggiungi bot..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Azione"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Chat aperta"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "Crea nuova battaglia"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Evidenzia parole"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "Aggiungi bot..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Rimuovi l'account dell'utente"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Nome dell'utente"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Seleziona"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Scegli in gioco"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"salvato correttamente in:\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "Setta l'accesso..."
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "Non posso lanciare il browser"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "default"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Informazioni del canale"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Crea nuova battaglia"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+"Una breve descrizione della partita, che comparirà nella lista battaglie."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Descrizione"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Seleziona il mod con il quale giocare."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+"E' richiesta una password per partecipare. Lascia vuoto per non inserire "
+"password."
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Porta"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "Porta UDP sulla quale ospitare la partita. La predefinita è 8452."
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "Nessun mod disponibile"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Numero di giocatori"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "Il numero massimo di giocatori permessi in battaglia."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "NAT traversal"
+
+#: src/hostbattledialog.cpp:177
+#, fuzzy
+msgid "NAT traversal to use."
+msgstr "NAT traversal"
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Grado minimo richiesto"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Comincia ad ospitare la battaglia."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "Devi prima selezionare un mod."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Nessun mod selezionato."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"salvato correttamente in:\n"
+
+#: src/httpdownloader.cpp:78
+#, fuzzy
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"salvato correttamente in:\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"a:\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Browser web"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Browser predefinito."
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Sfoglia"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "Riconnetti"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "Connesso a lobby server"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "&Strumenti"
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Metallo di partenza"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Risposta sconosciuta dal server"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Opzioni"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Restrizioni unità "
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "P2P"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Senegal"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Ripristina"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "Applica"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Partita"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "Inviati in totale: "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "Ricevuti in totale: "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "sconosciuto"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "Pubblica nuovo file"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Attiva widgets LuaUI"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "Inviati in totale: %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "Ricevuti in totale: %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Connetti..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&Disconnetti"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Opzioni interfaccia utente"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Esci"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "&Entra nel canale..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Informazioni del canale"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Apri &chat privata"
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&Ricarica mappe/mods"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "Controlla nuove Versioni"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr ""
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&Informazioni su"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Informazioni del canale"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&Segnala Bug..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Documentazione"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&File"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Strumenti"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Aiuto"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Riconnetti"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "&Entra nel canale..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Nome del canale in cui entrare"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Apri Chat Privata..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Nome dell'utente"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+"SpringLobby è un lobby client multipiattaforma per il motore RTS Spring"
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Nessuna mappa trovata"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Quale user accaunt vuoi rimuovere?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Salva..."
+
+#: src/mainwindow.h:184
+msgid "Replays"
+msgstr ""
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Scarica"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Aggiorna"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Scarica"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "Fazione:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "alleato: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+#, fuzzy
+msgid "Show"
+msgstr "Mostra tutto"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "File"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Metallo massimo"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Posizioni di partenza"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Grado minimo richiesto"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Spettatore"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Posizioni di partenza"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Scegli in gioco"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Scegli in gioco"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Restrizioni unità "
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Opzioni interfaccia utente"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr ""
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr ""
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Eseguibile (*.exe)|*.exe|Tutti i Files (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Tutti i Files (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+#, fuzzy
+msgid "Filter settings"
+msgstr "Salva impostazioni"
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Durata:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Seleziona"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Modalità "
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Panama"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Durata:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Spring error"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "File"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "File"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Caricamento..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Giocatori"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Salva..."
+
+#: src/playback/playbacktab.cpp:286
+#, fuzzy
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"Non posso prendere dalla tua versione di spring la libreria unitssync.\n"
+"Il gioco online sarà disabilitato."
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Porta non valida"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Seleziona"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Utente non in linea."
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Utente non in linea."
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " partecipa alla "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "Ingresso nel canale fallito"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Non è stato possibile entrare nel canale "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " poiché: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Messaggio del Server"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " ha ip:=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " in realtà non supporta NAT traversal"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "Sei stato allontanato dalla battaglia!"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "Espulso dall'host"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr ""
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Scarica &mappa"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"C'è stato un errore nel cercare l'ultima versione.\n"
+"Per favore riprova più tardi.\n"
+"Se il problema persiste, vai su Aiuto->Segnala Bug per segnalare questo bug."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Notifica"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Numero non valido."
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Non è un numero"
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Avviata"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Riconnetti"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "sconosciuto"
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Nessun mod selezionato."
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "Non posso lanciare il browser"
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"Valori alti = ombre graficamente migliori\n"
+"valori possibili: 1024, 2048, 4096, 8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr "Dettaglio del terreno"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr "Valori alti = maggiori dettagli del terreno"
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr "Valori alti = maggiori dettagli delle unità "
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr "Dettaglio erba"
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "higher value = more detailed grass"
+msgstr "Valori alti = maggiori dettagli dell'erba"
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr "Numero massimo di particelle simultanee"
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "Limita il numero di particelle visibili nello stesso tempo"
+
+#: src/settings++/Defs.hpp:233
+#, fuzzy
+msgid "Max nano simultaneous particles"
+msgstr "Numero massimo di particelle simultanee"
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr "Schermo intero"
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "Modalità Dual-screen"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "Sei hai due monitors puoi usarli entrambi"
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "Abilita V-Sync"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr "alloggiamento"
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+#, fuzzy
+msgid "Full-scene anti-aliasing samples"
+msgstr "quanto antialias dov"
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr "quanto antialias dov"
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr "Numero massimo suoni simultanei"
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+"Numero massimo di suoni differenti riprodotti simultaneamente\n"
+"Imposta questo valore a 0 per disabilitare completamente il suono."
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "Master sound volume"
+msgstr "Volume del suono globale"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "master sound volume"
+msgstr "Volume del suono globale"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "General sound volume"
+msgstr "Volume del suono globale"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "general volume relative to master volume"
+msgstr "Volume delle risposte relativo al volume globale"
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr "Volume delle risposte delle unità "
+
+#: src/settings++/Defs.hpp:273
+#, fuzzy
+msgid "reply volume relative to master volume"
+msgstr "Volume delle risposte relativo al volume globale"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Battaglia chiusa"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "battle volume relative to global volume"
+msgstr "Volume delle risposte relativo al volume globale"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "User interface volume"
+msgstr "Volume delle risposte delle unità "
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "ui volume relative to global volume"
+msgstr "Volume delle risposte relativo al volume globale"
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "Ombre (lento)"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr "Vuoi abilitare le ombre?"
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr "Alberi 3D"
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+"Vuoi alberi graficamente migliori?\n"
+"Richiede una scheda video della serie Geforce 2/Radeon 8500/Intel 830 o più "
+"recente"
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr "Nuvole ad alta risoluzione"
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"Vuoi un cielo graficamente migliore?\n"
+"Richiede una scheda video della serie Geforce 5/Radeon 9500/Intel 915 o più "
+"recente"
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr "Ombre dinamiche (lento)"
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr "vuoi nuvole mobili nel cielo?"
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr "Unità riflettenti"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"Unità splendenti?\n"
+"Richiede una scheda video di classe Geforce 5/Radeon 9500/Intel 915 o "
+"superiore"
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr "Problemi con mappe in formato sm3? Attiva questo."
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr "Attiva supporto LuaShaders"
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+#, fuzzy
+msgid "High-resolution LOS textures"
+msgstr "Nuvole ad alta risoluzione"
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+#, fuzzy
+msgid "Issue commands on mini-map"
+msgstr "Mostra comandi sulla minimappa"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "Mostra comandi sulla minimappa"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr "Il valore predefinito è \"sì\""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr "Disegna icone sulla minimappa"
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr "Disegna marcatori sulla minimappa"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr "Minimappa a sinistra (schermo singolo)"
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "La posizione predefinita è a sinistra"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr "Minimappa a sinistra (doppio schermo)"
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr "Colori mini-mappa semplificati"
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "Usa meno colori"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr "Nanospray colore squadra"
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr "Le nanoparticelle dovrebbero avere il colore della tua squadra?"
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "Mostra orologio nel gioco"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+"richiede \"Attiva LuaWidgets\" per funzionare.\n"
+"Comparirà nell'angolo in basso a destra."
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr "Mostra informazioni sul giocatore nel gioco"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr "Mostra FPS nel gioco"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr "Correggi il rendering quando si preme ALT+TAB"
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr "Non cambiare a meno che non sia necessario"
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr "Non consentire aiuto dell'IA"
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+"Disattiva Economy AI, ecc.\n"
+"Se attivato potrebbe entrare in conflitto con LuaUI."
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr "Attiva scorrimento sui bordi della finestra"
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr "Scorri lo schermo quando il mouse raggiunge il bordo della finestra."
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr "Inverti Mouse"
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "Inverti l'asse Y del mouse quando si è in modalità FPS"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr "Telecamera dall'alto"
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr "Telecamera dall'alto roteabile."
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr "Telecamera Total War"
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr "Telecamera in prima persona"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr "Telecamera libera"
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+"Rendi la visuale predefinita quando viene avviato Spring.\n"
+"Può essere cambiata durante il gioco."
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+#, fuzzy
+msgid "How much information should be outputted?"
+msgstr "quanto antialias dov"
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "Base"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+"A seconda della potenza della tua scheda video,\n"
+"la scelta di una qualità più alta di quella base può\n"
+"avere un impatto pesante sulle prestazioni di Spring.\n"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr "Riflettente"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "Riflettente + rifrangente"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "Dinamico"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr "Inverti l'asse Y del mouse"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr "Supporto mouse a 3 tasti nella mini-mappa"
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr "Dall'alto"
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr "Telecamera fissa a vista d'uccello"
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr "Dall'alto roteabile"
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr "Come la telecamera dall'alto, ma si può ruotare sull'asse Z"
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr "Total War"
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr "Telecamera dall'alto, che può essere ruotata sull'asse X"
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "Prima persona"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr "Telecamera dal punto di vista dell'unità "
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "larghezza dello schermo"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "altezza dello schermo"
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Riflettente"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Shore waves"
+msgstr "Vuoi abilitare le ombre?"
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Enables shorewaves"
+msgstr "Vuoi abilitare le ombre?"
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Riflettente"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Riflettente"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Durata:"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Disattivato"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "Opzioni combinate"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "Opzioni interfaccia utente"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Audio"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "Errore!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "Salvare le impostazioni di Spring prima di uscire?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "Conferma necessaria"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "Salva impostazioni"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "Esci"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "Semplice (poche opzioni)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "Esperto (tutte le opzioni)"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "Informazioni su"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Contatta"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "Riconoscimenti"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "Segnala un bug"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Modalità "
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Informazioni/Aiuto"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "Vuoi reimpostare TUTTE le impostazioni al loro valore predefinito?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Suggerimento"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "Il team SpringLobby"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Errore critico"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "Percorso per la libreria condivisa unitsync"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "Usa questo percorso"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "\"unitsync.so\" su Linux, \"unitsync.dll\" su Windows"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "Impostazioni percorsi"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "Scegli una libreria unitsync"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Qualsiasi file"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "basso"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "Medio"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "alto"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "molto basso"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "molto alto"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "Non posso lanciare il browser predefinito"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "Non posso lanciare il browser"
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "Non posso salvare, unitsync non è stato caricato correttamente"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Opzioni Audio"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Risoluzione dello Schermo"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Qualità dell'Acqua"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "Risoluzione in bit"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "Opzioni Modalità Video"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "Opzioni di Anti-Aliasing"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "Qualità grafica"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Dettagli grafici"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Risoluzione schermo"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "Passa alla modalità esperto"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (attuale)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Informazioni"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "Ingrandimento"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "Aggiungi bot..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Spettatore"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Posizioni di partenza"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- Seleziona --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "Errore nella configurazione del gioco"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Devi prima selezionare una mappa."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "Nessun bot aggiunto"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+"Non puoi avviare una istanza di Spring mentre ce n'è un'altra già in "
+"esecuzione."
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Ciao "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Benvenuto"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Nessuno"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "Impostazioni percorsi"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Chat aperta"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr ""
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Cerca"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "Eseguibile Spring"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Posizione"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Cerca"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "libreria UnitSync"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Configurazione automatica"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Libreria"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Connessione scaduta"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "Risposta sconosciuta dal server"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "Scarica"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Stato:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "Ferma tutti i torrents"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Password del server"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Registrazione avvenuta con successo,\n"
+"ora dovresti riuscire ad autenticarti."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Registrazione avvenuta con successo."
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "Registrazione non riuscita. Il motivo è stato:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr ""
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - Imposta il tuo stato come \"non al computer\"."
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - Elenca i canali al momento attivi"
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+" \"/help [comando]\" - Scrivi un comando se vuoi avere informazioni più "
+"specifiche su di esso."
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Sinonimo di /join"
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - Elenca i canali al momento attivi"
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - Sinonimo di /join"
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+" \"/sayver\" - Comunica in chat la versione di springlobby che stai usando."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - Mostra la versione di SpringLobby in uso"
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Comandi di chat:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me azione\" - Manda un messaggio di azione in stile IRC"
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Nessun topic scritto finora."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "il topic \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+"\" non è stato trovato. Digita \"/help topics\" solo per i topic disponibili"
+
+#: src/ui.cpp:609
+#, fuzzy
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Non posso prendere dalla tua versione di spring la libreria unitssync.\n"
+"Il gioco online sarà disabilitato."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Il gioco onlie sarà disabilitato."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "Risposta sconosciuta dal server"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Connessione scaduta"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr ""
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Messaggio del server"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "La battaglia attuale è stata chiusa dall'host."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "Battaglia chiusa"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Probabilmente le tue impostazioni di Spring non sono configurate "
+"correttamente,\n"
+"dovresti controllare meglio le tue impostazioni prima di provare\n"
+"a giocare online."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Errore nelle impostazioni di Spring"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"C'è stato un errore nel cercare l'ultima versione.\n"
+"Per favore riprova più tardi.\n"
+"Se il problema persiste, vai su Aiuto->Segnala Bug per segnalare questo bug."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "La tua versione: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Ultima Versione: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"La tua versione di SpringLobby non è aggiornata.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Non aggiornato"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Non aggiornato"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+#, fuzzy
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"C'è stato un errore nel cercare l'ultima versione.\n"
+"Per favore riprova più tardi.\n"
+"Se il problema persiste, vai su Aiuto->Segnala Bug per segnalare questo bug."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, fuzzy, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"C'è stato un errore nel cercare l'ultima versione.\n"
+"Per favore riprova più tardi.\n"
+"Se il problema persiste, vai su Aiuto->Segnala Bug per segnalare questo bug."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Nessuno"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Evidenzia"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "Partecipa alla stessa battaglia"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Norvegia"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Nickname"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr ""
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr ""
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr ""
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr ""
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr ""
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr ""
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr ""
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "sconosciuto"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "Aggiungi bot..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Rimuovi l'account dell'utente"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Austria"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "La tua versione di Spring"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "Scarica"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "Pubblica nuovo file"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Annulla"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "Risoluzione dello Schermo"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Spettatori:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Squadra"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Allineamento"
+
+#~ msgid "cpu"
+#~ msgstr "cpu"
+
+#~ msgid "Test firewall"
+#~ msgstr "Prova firewall"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat chiusa."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Opzioni della mappa"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "Scegli in gioco"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Nessun mod selezionato."
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Disconnetti"
+
+#~ msgid "Debug"
+#~ msgstr "Debug"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Giocatore:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Settaggio colori"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Azione"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "g"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "Valore fuori dal range.\n"
+#~ "Inserisci un valore intero tra 0 e 100."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "Numero di giocatori"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Informazioni del canale"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "il topic \""
+
+#~ msgid "Use smart scrolling"
+#~ msgstr "usa scorrimento intelligente"
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Unit detail"
+#~ msgstr "Dettaglio delle unità "
+
+#~ msgid "Send debug info to console"
+#~ msgstr "Manda informazioni di debug nella console"
+
+#~ msgid "if disabled these will only be logged"
+#~ msgstr "Se disattivato, queste saranno soltanto raccolte in un log."
+
+#~ msgid "Missing Functionality"
+#~ msgstr "Funzionalità Mancanti"
+
+#~ msgid "Download OTA content?"
+#~ msgstr "Vuoi scaricare i dati OTA? (Original Total Annihilation)"
+
+#, fuzzy
+#~ msgid "Create a spring directory in my documents folder"
+#~ msgstr "Crea una cartella .spring nella cartella home (raccomandato)"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "Risposta sconosciuta dal server"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Non online"
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Indirizzo/porta o nome del server non valido."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "Canali di chat attivi:"
+
+#~ msgid "Select all"
+#~ msgstr "Seleziona tutto"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Nessun mod selezionato."
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Numero non valido."
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr ""
+#~ "Una breve descrizione della partita, che comparirà nella lista battaglie."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "Seleziona il mod con il quale giocare."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normale"
+
+#~ msgid "NAT traversal to use. Experimental support."
+#~ msgstr "Usa protocollo NAT Traversal. Supporto sperimentale."
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "libreria UnitSync"
+
+#~ msgid ""
+#~ "Please enter password needed to join this channel, leave blank for no "
+#~ "passwrd."
+#~ msgstr ""
+#~ "Inserisci una password necessaria per questo canale, lascia in bianco se "
+#~ "non esiste."
+
+#~ msgid "&Edit"
+#~ msgstr "&Modifica"
+
+#~ msgid "LuaAI"
+#~ msgstr "LuaAI"
+
+#~ msgid "no"
+#~ msgstr "no"
+
+#~ msgid "/.spring"
+#~ msgstr "/.spring"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "Continua se il commander muore"
+
+#~ msgid "End if commander dies"
+#~ msgstr "Termina se il commander muore"
+
+#~ msgid "End condition"
+#~ msgstr "Condizioni finali"
+
+#~ msgid "Resources"
+#~ msgstr "Risorse"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Ammontare di metallo per ogni giocatore alla partenza."
+
+#~ msgid "Start Energy"
+#~ msgstr "Energia di partenza"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Ammontare di energia per ogni giocatore alla partenza."
+
+#~ msgid "Max units"
+#~ msgstr "Unità massime"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "Numero massimo di unità permesse per giocatore."
+
+#~ msgid "Limit d-gun"
+#~ msgstr "D-gun limitato"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "Edifici fantasma"
+
+#~ msgid "Save to:"
+#~ msgstr "Salva in:"
+
+#~ msgid "Browse..."
+#~ msgstr "Sfoglia..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Scegli una directory"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "Opzioni mappa/mod"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "La tua versione di SpringLobby è aggiornata!\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "Aggiornato"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "Vorresti visitare una pagina Internet con le istruzioni per scaricare la "
+#~ "versione più recente?"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "Limita D-Gun"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr ""
+#~ "Disabilita il D-Gun del comandante quando si allontana troppo dal punto "
+#~ "di partenza"
+
+#~ msgid "Ghosted Buildings"
+#~ msgstr "Costruzioni Fantasma"
+
+#~ msgid ""
+#~ "Enemy buildings will leave a ghost image on the map after losing LoS on "
+#~ "them"
+#~ msgstr ""
+#~ "Le costruzioni nemiche lasceranno un'immagine fantasma sulla mappa quando "
+#~ "si perderà il contatto visivo su di esse"
+
+#~ msgid ""
+#~ "Efficiency of MetalMakers will progressively reduce as much as you build "
+#~ "them"
+#~ msgstr ""
+#~ "L'efficienza dei Metal Makers si ridurrà progressivamente man mano che li "
+#~ "costruisci"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "Condizioni di Fine Partita"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "Imposta la quantità di metallo con la quale i giocatori inizieranno"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "Imposta la quantità di energia con la quale i giocatori inizieranno"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "Numero massimo di unità consentite"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "Imposta il numero massimo di unità che un giocatore può costruire"
+
+#~ msgid "Reset"
+#~ msgstr "Ripristina"
+
+#~ msgid "Spring directory"
+#~ msgstr "Directory Spring"
+
+#~ msgid "Default location."
+#~ msgstr "Posizione predefinita."
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "non e' supportata dalla lobby server."
+
+#~ msgid ""
+#~ "This is the SpringLobby channel, please report any problems you are "
+#~ "having with SpringLobby here and the friendly developers will help you."
+#~ msgstr ""
+#~ "Questo è il canale di Springlobby, riportaci qualsiasi problema che hai "
+#~ "avuto e i tuoi amici sviluppatori ti daranno un aiuto."
diff --git a/po/pl.gmo b/po/pl.gmo
new file mode 100644
index 0000000..d77b97c
Binary files /dev/null and b/po/pl.gmo differ
diff --git a/po/pl.po b/po/pl.po
new file mode 100644
index 0000000..4829bc0
--- /dev/null
+++ b/po/pl.po
@@ -0,0 +1,5983 @@
+# Polish translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-08-22 06:20+0000\n"
+"Last-Translator: Roman SkrzypiÅski <romano473 at gmail.com>\n"
+"Language-Team: Polish <pl at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Dodaj bota"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Pseudonim:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr ""
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr ""
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "WartoÅÄ"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Anuluj"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Dodaj bota"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr ""
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr ""
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Zaakceptuj umowÄ"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Czy akceptujesz warunki tej umowy?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Tak"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Nie"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "Metoda"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr ""
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Losowo"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Klany"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Brak"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr ""
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Zawsze"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+msgid "Number of allies"
+msgstr ""
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "PoÅÄ
cz ponownie"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Opis"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Host"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Obserwatorzy:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Gracze:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "ÅciÄ
gnij &mape"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr ""
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Obserwatorzy:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Gracze:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Host:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Status:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Zablokowany"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr ""
+
+#: src/battlelistfilter.cpp:122
+msgid "Highlighted only"
+msgstr ""
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Opis:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "RozpoczÄta"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "PeÅny"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Otwarte"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Gracz"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Wszystko"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Mapa"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Tylko mapy które mam"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Max. Graczy:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Tylko mody które mam"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Obserwator:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Gracze:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+msgid " Filter "
+msgstr ""
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "RozpoczÄta"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+msgid " Battle infos "
+msgstr ""
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr ""
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "DoÅÄ
cz"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr ""
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr ""
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Nie znaleziono żadnych map"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+msgid "Already in this battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+
+#: src/battlelisttab.cpp:523
+msgid "Already in another battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:523
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Mod niedostÄpny"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Mapa niedostÄpna"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr ""
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Wprowadź hasÅo"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Wybierz..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Opcje"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "WartoÅÄ"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Rozmiar"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "PrÄdkoÅÄ wiatru"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "SiÅa pÅywów"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Grawitacja"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr ""
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Maksimum metalu"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr ""
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr ""
+
+#: src/battlemaptab.cpp:103
+msgid "Chose before game"
+msgstr ""
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Pozycja startowa"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr ""
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Dozwolone jednostki"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "UdostÄpniÄ wszystkie jednostki."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "UdostÄpniÄ wszystkie jednostki."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "UdostÄpniÄ wszystkie jednostki."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "NiedostÄpne jednostki"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "NiedostÄpne jednostki"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Pseudonim"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Drużyna"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Sojusznik"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Strona"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Wybierz kolor"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Obserwator"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "UsuÅ"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Dodaj bota"
+
+#: src/battleroomlistctrl.cpp:719
+msgid "Human\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Obserwator"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Gracz"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Host"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Klient"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Zawsze"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Niegotowy"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "UsuÅ..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Wczytaj..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Zapisz zbiór ograniczeÅ"
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Zapisz..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Zapisz zbiór ograniczeÅ"
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Wybierz..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Zapisz zbiór ograniczeÅ"
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "domyÅlny"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Opcje Mod'u"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Opcje Mapy"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "Mod niedostÄpny"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "bÅÄ
d"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "domyÅlny"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Jestem gotowy"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Kolor"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "OpuÅÄ"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Rozpocznij"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "Rozpocznij bitwe"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr ""
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "PoÅÄ
cz ponownie"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Rozpocznij"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+msgid "Ring ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Niegotowy"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "Wymuszony start?"
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Zapisz..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr ""
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "domyÅlny"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "Kontynuuj"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "Koniec"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "Mapa nie istnieje"
+
+#: src/battleroomtab.cpp:593
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Niegotowy"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "domyÅlny"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "kanaÅ"
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "kanaÅ"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d użytkowników)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr ""
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr ""
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normalny"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "TÅo"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr ""
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr ""
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr ""
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Moje wiadomoÅci"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Serwer"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Klient"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "BÅÄ
d"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr ""
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Powiadomienie"
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Czcionka:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "domyÅlny"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Wybierz..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Zachowanie"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr ""
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr "kanaÅ_"
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d użytkowników)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "WyÅlij"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Kopiuj"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "WyczyÅÄ"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr ""
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr ""
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr ""
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr ""
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr ""
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Zablokuj..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "Odblokuj"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Zarejestruj..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Wyrejestruj"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "WÅÄ
cz"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "WyÅÄ
cz"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr ""
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr ""
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr ""
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "RozÅÄ
cz"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "PoÅÄ
cz ponownie"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "UsuÅ..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Zmiana hasÅa..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr ""
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Konta"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr ""
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Admin"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "serwer"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr ""
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr ""
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr ""
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr ""
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr ""
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr ""
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr ""
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr ""
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr ""
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr ""
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr ""
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr ""
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr ""
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr ""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "kanaÅ"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "bitwa"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "serwer"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr ""
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr ""
+
+#: src/chatpanel.cpp:1029
+msgid " ** Channel topic:"
+msgstr ""
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr ""
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr ""
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr ""
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr ""
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr ""
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr ""
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr ""
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr ""
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr ""
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr ""
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr ""
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr ""
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr ""
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr ""
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr ""
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr ""
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr ""
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr ""
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr ""
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr ""
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "NieprawidÅowa liczba"
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr ""
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr ""
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr ""
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr ""
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr ""
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr ""
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr ""
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr ""
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr ""
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr ""
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr ""
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr ""
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr ""
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr ""
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr ""
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr ""
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr ""
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr ""
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr ""
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr ""
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr ""
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr ""
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr ""
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr ""
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr ""
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr ""
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr ""
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr ""
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr ""
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr ""
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr ""
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr ""
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr ""
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr ""
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr ""
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr ""
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr ""
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr ""
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr ""
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr ""
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr ""
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr ""
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr ""
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr ""
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr ""
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr ""
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr ""
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr ""
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr ""
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr ""
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr ""
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr ""
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr ""
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr ""
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr ""
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr ""
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr ""
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr ""
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr ""
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr ""
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr ""
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr ""
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr ""
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr ""
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr ""
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr ""
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr ""
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr ""
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr ""
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr ""
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr ""
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr ""
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr ""
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr ""
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr ""
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr ""
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr ""
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr ""
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr ""
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr ""
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr ""
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr ""
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr ""
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr ""
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr ""
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr ""
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr ""
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr ""
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr ""
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr ""
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr ""
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr ""
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr ""
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr ""
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr ""
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr ""
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr ""
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr ""
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr ""
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr ""
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr ""
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr ""
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr ""
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr ""
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr ""
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr ""
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr ""
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr ""
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr ""
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr ""
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr ""
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr ""
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr ""
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr ""
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr ""
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr ""
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr ""
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr ""
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr ""
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr ""
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr ""
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr ""
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr ""
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr ""
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr ""
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr ""
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr ""
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr ""
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr ""
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr ""
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr ""
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr ""
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr ""
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr ""
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr ""
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr ""
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr ""
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr ""
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr ""
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr ""
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr ""
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr ""
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr ""
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr ""
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr ""
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr ""
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr ""
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr ""
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr ""
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr ""
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr ""
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr ""
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr ""
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr ""
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr ""
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr ""
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr ""
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr ""
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr ""
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr ""
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr ""
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr ""
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr ""
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr ""
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr ""
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr ""
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr ""
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr ""
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr ""
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr ""
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr ""
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr ""
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr ""
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr ""
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr ""
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr ""
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr ""
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr ""
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr ""
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr ""
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr ""
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr ""
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr ""
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr ""
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr ""
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr ""
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr ""
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr ""
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr ""
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr ""
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr ""
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr ""
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr ""
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr ""
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr ""
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr ""
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr ""
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr ""
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr ""
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr ""
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr ""
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr ""
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr ""
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr ""
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr ""
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr ""
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr ""
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr ""
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr ""
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr ""
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr ""
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr ""
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr ""
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr ""
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr ""
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr ""
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr ""
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr ""
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr ""
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr ""
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Pseudonim"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "ÅciÄ
gnij &mape"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "UsuÅ..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "UsuÅ..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+msgid "Add New.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Opcje"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+msgid "Ignore Chat"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+msgid "Highlight Color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+msgid "Add.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+msgid "Remove users from group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Wybierz..."
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "kanaÅ"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "domyÅlny"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "kanaÅ"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr ""
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Opis"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr ""
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr ""
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "Mod niedostÄpny"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr ""
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr ""
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "PoÅÄ
cz ponownie"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+msgid "Autoconnect on lobby start"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "PoczÄ
tkowy Metal"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+msgid "Disconnected from server, chat closed."
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Opcje"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "NiedostÄpne jednostki"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr ""
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr ""
+
+#: src/mainoptionstab.cpp:75
+msgid "General"
+msgstr ""
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr ""
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr ""
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr ""
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "ÅciÄ
gnij &mape"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr ""
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr ""
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr ""
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Opcje Mapy"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr ""
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "kanaÅ"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr ""
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr ""
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr ""
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr ""
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "kanaÅ"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr ""
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr ""
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr ""
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr ""
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "PoÅÄ
cz ponownie"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr ""
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Nie znaleziono żadnych map"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+msgid "Which profile do you want to be default?"
+msgstr ""
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Zapisz..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "Zawsze"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "ÅciÄ
gnij &mape"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr ""
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr ""
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr ""
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr ""
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+msgid "Filter"
+msgstr ""
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Maksimum metalu"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Pozycja startowa"
+
+#: src/mapselectdialog.cpp:265
+msgid "Minimum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "PrzeciÄtny"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Obserwator"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Losowe pozycje startowe"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "kanaÅ"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "kanaÅ"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "NiedostÄpne jednostki"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Opcje Mapy"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr ""
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr ""
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr ""
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr ""
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+msgid "Duration (hh:mm:ss):"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "bitwa"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Pseudonim"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Pseudonim"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Opis"
+
+#: src/playback/playbacklistctrl.cpp:46
+msgid "Spring Version"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Wczytaj..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Zawsze"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Zapisz..."
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "NieprawidÅowa liczba"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Zaznacz wszystko"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr "RozÅÄ
cz"
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+msgid " just went offline"
+msgstr ""
+
+#: src/serverevents.cpp:260
+msgid " opened battle "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr ""
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr ""
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "ÅciÄ
gnij &mape"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Powiadomienie"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "NieprawidÅowa liczba"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "RozÅÄ
cz"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "Mapa nie istnieje"
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "RozpoczÄta"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "PoÅÄ
cz ponownie"
+
+#: src/serverevents.cpp:999
+msgid "Unknown Error"
+msgstr ""
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "ÅciÄ
gnij &mape"
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Maksimum metalu"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Maksimum metalu"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "Battle volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "NiedostÄpne jednostki"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "domyÅlny"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr ""
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Wybierz..."
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+msgid "Blur reflection"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Wybierz..."
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+msgid "Reflection texture size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Opis"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "WyÅÄ
cz"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr ""
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr ""
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr ""
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr ""
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr ""
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr ""
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr ""
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr ""
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Obserwator"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Losowe pozycje startowe"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr ""
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr ""
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Brak"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+msgid "Import settings?"
+msgstr ""
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+msgid "Ignore chat"
+msgstr ""
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr ""
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+msgid "Friends"
+msgstr ""
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr ""
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr ""
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr ""
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr ""
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr ""
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr ""
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+msgid "MB downloaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Status:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "HasÅo serwera"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr ""
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr ""
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr ""
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr ""
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr ""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr ""
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr ""
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:661
+msgid "Disconnected from server."
+msgstr ""
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Kontynuuj"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d użytkowników)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid "Not up to date"
+msgstr ""
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr ""
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Brak"
+
+#: src/useractions.h:11
+msgid "highlight"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "Rozpocznij bitwe"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Zawsze"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Pseudonim"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "Nowicjusz"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "PoczÄ
tkujÄ
cy"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "PrzeciÄtny"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Ponad przeciÄtny"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "DoÅwiadczony"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "Bardzo doÅwiadczony"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Weteran"
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+msgid "Add to group..."
+msgstr ""
+
+#: src/usermenu.h:30
+msgid "Remove from group"
+msgstr ""
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+msgid "Author"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+msgid "Current version"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "ÅciÄ
gnij &mape"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Anuluj"
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Obserwatorzy:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "Gracze:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Drużyna"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Sojusznik"
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Opcje Mapy"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "ÅciÄ
gnij &mape"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "RozÅÄ
cz"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Gracz"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Wybierz kolor"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Opcje"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "p"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "kanaÅ"
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERWER"
+
+#, fuzzy
+#~ msgid "Only the host can change the game options"
+#~ msgstr "Tylko host może rozpoczÄ
Ä bitwe"
+
+#~ msgid "Only the host can start the battle."
+#~ msgstr "Tylko host może rozpoczÄ
Ä bitwe"
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "Tylko host może rozpoczÄ
Ä bitwe"
+
+#, fuzzy
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "Tylko host może rozpoczÄ
Ä bitwe"
+
+#~ msgid "Select all"
+#~ msgstr "Zaznacz wszystko"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d użytkowników)"
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normalny"
+
+#~ msgid "Resources"
+#~ msgstr "Zasoby"
+
+#~ msgid "Start Energy"
+#~ msgstr "PoczÄ
tkowa Energia"
+
+#~ msgid "Max units"
+#~ msgstr "Maksimum jednostek"
+
+#~ msgid "Save to:"
+#~ msgstr "Zapisz w:"
+
+#~ msgid "Browse..."
+#~ msgstr "PrzeglÄ
daj..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Wybierz folder"
diff --git a/po/pt.gmo b/po/pt.gmo
new file mode 100644
index 0000000..87fd78e
Binary files /dev/null and b/po/pt.gmo differ
diff --git a/po/pt.po b/po/pt.po
new file mode 100644
index 0000000..fc7ae3c
--- /dev/null
+++ b/po/pt.po
@@ -0,0 +1,6192 @@
+# Portuguese translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-08-17 14:38+0000\n"
+"Last-Translator: fastfox <Unknown>\n"
+"Language-Team: Portuguese <pt at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Adicionar robô"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Alcunha:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "IA:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Escolha uma biblioteca de IA para o robô."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Valor"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Adicionar robô"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Não foram encontrados robôs com IA na sua instalação do Spring."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Não foram encontradas bibliotecas de IA"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Aceitar a Licença"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Aceita os termos desta licença?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Sim"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Não"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "Método"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "Dividir patentes uniformemente"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Aleatório"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Clãs"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Nenhum"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Justo"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Sempre"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"Colocar membros do mesmo Clã (utilizadores com o mesmo tag de Clã, como "
+"'[smurfzor]Alice' e '[smurfzor]Bob') juntos na mesma aliança. \n"
+"Nenhum: nenhum tratamento especial para clãs.\n"
+"Justo: colocar membros do mesmo clã numa aliança caso a aliança não seja "
+"injusta.\n"
+"Sempre: colocar sempre os membros do mesmo clã numa aliança, mesmo se a "
+"aliança se tornar injusta."
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Número de jogadores"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Reconectar automaticamente"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "OK"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Descrição"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Anfitrião"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Espectadores:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Jogadores:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Mapa"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr ""
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr ""
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Espectadores:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Jogadores:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Anfitrião:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Estado:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Fechado"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Com senha"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Realçar"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Descrição:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Iniciado"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Cheio"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr ""
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Jogador:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Todos"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Mapa:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Apenas mapas que possuo"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Max. de jogadores:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Apenas mods que possuo"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Espectador:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Jogadores:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+msgid " Filter "
+msgstr ""
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Iniciado"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+msgid " Battle infos "
+msgstr ""
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr ""
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "Entrar"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Não pode hospedar um jogo enquanto estiver offline. Por favor ligue-se a um "
+"servidor."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr ""
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+"Hospedar jogos está desactivado devido à versão incompatÃvel que está a usar"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Erro do Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Já se encontra a correr uma instância do Spring, feche-a primeiro de modo a "
+"poder hospedar um novo jogo"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Numa batalha"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Já se encontra numa batalha.\n"
+"Deseja sair da batalha actual e começar uma nova?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"Está a usar uma versão do wxWidgets anterior à 2.8.\n"
+" O teste de portas não é possÃvel.\n"
+" A criação de novos jogos poderá não funcionar."
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"O servidor usado para testar a sua porta %d está inacessÃvel.\n"
+"A criação de novos jogos poderá não funcionar com esta opção"
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+"A batalha não começou porque o mod que escolheu não pôde ser encontrado. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Erro ao iniciar a batalha."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Não foi possÃvel encontrar mapas na sua instalação do Spring. Isto pode "
+"ocorrer quando as opções do Spring estão incorrectas."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Nenhum mapa encontrado"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"Entrar em batalhas está desactivado devido à versão do Spring que está a "
+"usar ser incompatÃvel."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Numa batalha"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Já se encontra numa batalha.\n"
+"Deseja sair da batalha actual e começar uma nova?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Numa batalha"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Já se encontra numa batalha.\n"
+"\n"
+"Deseja deixar a batalha actual e entrar nesta?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Já se encontra a correr uma instância do Spring, feche-a de modo a poder "
+"entrar noutra batalha."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "Deseja que o leve à página de downloads?"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+"Precisa de descarregar o mod antes de entrar neste jogo.\n"
+"\n"
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "O mod não está disponÃvel"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+"Precisa de descarregar o mapa para poder jogar nesta batalha.\n"
+"\n"
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Mapa não disponÃvel"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Palavra chave da batalha"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Introduza a palavra chave"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Seleccionar..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Opção"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Valor"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Tamanho"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Velocidade do vento"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Força das marés"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravidade"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Raio de extração"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr ""
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Fixo"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Escolher durante o jogo"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "Escolher durante o jogo"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Posições iniciais"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Restrições de unidades"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Unidades permitidas"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "As unidades nesta lista estarão disponÃveis durante o jogo."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Permitir todas as unidades."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Permitir todas as unidades."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Permitir todas as unidades."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Unidades proibidas"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "As unidades nesta lista não estarão disponÃveis durante o jogo."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Restrições de unidades"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Alcunha"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Equipa"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Aliado"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Bonus de Recursos"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Facção"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Definir cor"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Definir Bónus de Recusos"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Espectador"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Expulsar"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Por favor introduza um valor entre 0 e 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Adicionar robô"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Omã"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Espectador"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Jogador:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Anfitrião"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Cliente"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Sempre"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Não pronto"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Definir acesso..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Carregar..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Carregar um conjunto de restrições salvas."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Guardar..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Guardar um conjunto de restrições."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Seleccionar..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Guardar um conjunto de restrições."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "pré-definido"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Opções do Mod"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Opções do Mapa"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "O mod não está disponÃvel"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "pré-definido"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+"Jogadores com o mesmo número de equipa partilham o controlo das suas "
+"unidades."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+"Jogadores como mesmo número de aliança trabalham juntos para alcançar a "
+"vitória."
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "Selecione uma cor para identificar as suas unidades durante o jogo"
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "Espectar (observar) a batalha em vez de jogar"
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Estou pronto"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "Pressione aqui se estiver satisfeito com as opções da batalha."
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Cor"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Sair"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "Deixar a batalha e voltar à lista de batalhas"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Começar"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "Começar a batalha"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Adicionar Robô"
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "Adicionar um jogador controlado pelo computador ao jogo"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "Impedir novos jogadores de entrarem na batalha"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Reconectar automaticamente"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Começar"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+msgid "Ring ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Não pronto"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "Forçar o inÃcio?"
+
+#: src/battleroomtab.cpp:239
+#, fuzzy
+msgid "Balance alliances"
+msgstr "Apenas o anfitrião pode equilibrar as equipas."
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr "Equilibrar automaticamente os jogadores em duas ou mais alianças"
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "Corrigir cores"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "Tornas as cores dos jogadores únicas"
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr "Equilibrar automaticamente os jogadores em duas ou mais alianças"
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Guardar..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr ""
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "pré-definido"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "Ãreas"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr "Escolher"
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "Continuar"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "Terminar"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "O mapa não existe."
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Alguns dos jogadores ainda não estão prontos.\n"
+"Tocar a campainha destes jogadores?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Não pronto"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "pré-definido"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "Entrar automaticamente neste canal"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "canal"
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "canal"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "Expulsar utilizador"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Sessão Fechada a ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Não foi possÃvel criar a pasta.\n"
+"Verifique que não existe protecção contra a escrita.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "Função de registo desactivada até reiniciar o SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Resgisto de Aviso"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"Volte a entrar na sala para reactivar os registos."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Não é possÃvel abrir os ficheiros de registo.\n"
+"Verifique se não existe protecção contra a escrita.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Cores e tipos de letra"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Usar as cores do sistema"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Fundo"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Acção"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Realçar"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Entrar/Sair"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "As minhas mensagens"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Servidor"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Cliente"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Erro"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr ""
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Notificação"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Connected to TAS Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Tipo de Letra:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "pré-definido"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Seleccionar..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Comportamento"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Realçar palavras"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Palavras a realçar nas conversas:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "introduza uma lista separada por ;"
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "Expulsar utilizador"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Enviar"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Copiar"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Limpar"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "Entrar automaticamente neste canal"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "Mostrar Mensagens de Entrada/SaÃda"
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Informação do canal"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Definir tópico..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Menssagem do canal..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "Trancar..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr ""
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Registar..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Remover o Registo"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Ligado"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Desligado"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr ""
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Protecção de spam"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Desligar"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Reconectar automaticamente"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Remover..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Alterar senha..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Definir acesso..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Contas"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr ""
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Admin"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Silenciar Utilizador"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Abrir canal"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "Entrar na mesma batalha"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Tempo de jogo"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Silenciar..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Silenciar durante 5 minutos"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Silenciar durante 10 minutos"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Silenciar durante 30 minutos"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Silenciar durante 2 horas"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Silenciar durante 1 dia"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr ""
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Silenciar"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Expulsar..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Banir..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Desbanir"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr ""
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr ""
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Comando: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" params: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "canal"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "batalha"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "servidor"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr ""
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr ""
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Informação do canal"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * Definido por "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Conversa fechada."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Tem a certeza de que pretende colar %d linhas?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Tem o SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Não está num canal ou o canal não existe."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" Erro: O comando (%s) não existe, use /help para obter uma lista dos "
+"comandos disponÃveis."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+" Não está numa batalha ou a batalha não existe, use /help para obter uma "
+"lista dos comandos disponÃveis."
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " O utilizador está offline"
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Enviado: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "Erro do ChanServ"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "O ChanServ não está neste canal"
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Qual deve ser o novo tópico?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Mensagem:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "Trancar canal..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Qual deverá ser a nova senha?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "Destrancar canal"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Tem a certeza de que pretende destrancar este canal?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "O ChanServ não está neste servidor."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Quem deve ser indicado como fundador deste canal?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Remover Conta de Utilizador"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Que conta de utilizador pretende remover hoje?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Remover Conta"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Tem a certeza que pretende remover a conta "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr ""
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "De que conta de utilizador pretende mudar a senha?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Qual deverá ser a nova senha?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Não Implementado"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "Não possui o mod "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . Por favor descarregue-o primeiro"
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr "Mod não disponÃvel"
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "Esta batalha está protegida com palavra-chave, introduza-a."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Silenciar Utilizador"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Por quantos minutos deverá o utilizador ser silenciado?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Expulsar Utilizador"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Razão:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Expulsar utilizador"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "Silenciar utilizador"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Duração:"
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr ""
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Servidor a ligar. Pode ligar a qualquer servidor introduzindo-o no formato "
+"endereçoDoServidor:porta."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Senha"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "Lembrar senha"
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "Ligar automaticamente da próxima vez"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"lembrar os detalhes da ligação e ligar automaticamente ao servidor da "
+"próxima vez que iniciar o lobby"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Autentificação"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Registar"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Alcunha"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Porta inválida."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Porta inválida"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Número da porta fora dos limites.\n"
+"\n"
+"Tem de ser um inteiro entre 1 e 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Máquina/porta inválida."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Máquina inválida"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Número inválido"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"O registo falhou, a razão foi:\n"
+"Senha / confirmação não idênticas"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "O registo falhou."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Emiratos Ãrabes Unidos"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afeganistão"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "AntÃgua e Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albânia"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Arménia"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Antilhas Holandesas"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antárctica"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentina"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Samoa Americana"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Ãustria"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Austrália"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azerbaijão"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bósnia Herzegovina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "Bangladesh"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Bélgica"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burquina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgária"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Barém"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benim"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermudas"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Darussalam do Brunei"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "BolÃvia"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brasil"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamas"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Butão"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Ilha Bouvet"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Bielorrússia"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Canadá"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "Ilhas Cocos (Keeling)"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "República Centro-Africana"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Congo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "SuÃça"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Costa do Marfim"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Ilhas Cook"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "República dos Camarões"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "China"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Colômbia"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Cuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Cabo Verde"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Ilha Natal"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Chipre"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "República Checa"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Alemanha"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Djibuti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Dinamarca"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominica"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "República Dominicana"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Argélia"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Equador"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estónia"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Egipto"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Saara Ocidental"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritreia"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Espanha"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Etiópia"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finlândia"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fiji"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Ilhas Falkland (Malvinas)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Micronésia"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Ilhas Feroé"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "França"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "França, Metropolitana"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabão"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Granada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Geórgia"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Guiana Francesa"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Gana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Gronelândia"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gâmbia"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guiné-Conacri"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadalupe"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Guiné Equatorial"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Grécia"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "Ilhas Geórgia do Sul e Sandwich do Sul"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guiné-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guiana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Ilha Heard e McDonald"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Croácia"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Hungria"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonésia"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irlanda"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israel"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "Ãndia"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Território Britânico do Oceano Ãndico"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Iraque"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Irão"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Islândia"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Itália"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamaica"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Jordânia"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japão"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Quénia"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "Quirguistão"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Camboja"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Comoros"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "São Cristóvão e Neves"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "República Democrática Popular da Coreia"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "República da Coreia (Coreia do Sul)"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuwait"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Ilhas Caimão"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Cazaquistão"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "LÃbano"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Santa Lúcia"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Libéria"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesoto"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Lituânia"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Luxemburgo"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Letónia"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "LÃbia"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Marrocos"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Mónaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Moldávia"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Montenegro"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagáscar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Ilhas Marshall"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Macedónia"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Mianmar"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongólia"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macau"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Ilhas Marianas do Norte"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinica"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauritânia"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "MaurÃcias"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Maldivas"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "México"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malásia"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Moçambique"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "NamÃbia"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Nova Caledónia"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "NÃger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Ilha Norfolk"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigéria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nicarágua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Holanda"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Noruega"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "Zona Neutra (Arábia Saudita/Iraque)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "Nova Zelândia"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Omã"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panamá"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Perú"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Polinésia Francesa"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua Nova Guiné"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Filipinas"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Paquistão"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Polónia"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "São Pedro e Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Pitcairn"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Porto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugal"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "República de Palau"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguai"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Qatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Reunião"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Roménia"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Sérvia"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "Federação Russa"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Ruanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Arábia Saudita"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Ilhas Salomão"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seicheles"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Sudão"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Suécia"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapura"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "Santa Helena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Eslovénia"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Ilhas Svalbard e Jan Mayen"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "República Eslovaca"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Serra Leoa"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somália"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Suriname"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "São Tomé e PrÃncipe"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "União Soviética (Antiga)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "El Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "SÃria"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Suazilândia"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Ilhas Turks e Caicos"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Chade"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Terras Austrais e Antárcticas Francesas"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Tailândia"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tajiquistão"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Toquelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turquemenistão"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "TunÃsia"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Timor Leste"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Turquia"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trindade e Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Formosa"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tanzânia"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ucrânia"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "Reino Unido"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "Ilhas Menores Distantes dos Estados Unidos"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "Estados Unidos da América"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguai"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Uzbequistão"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Estado Cidade do Vaticano (Santa Sé)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "São Vicente e Granadinas"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Ilhas Virgens Britânicas"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Ilhas Virgens Americanas"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vietname"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Ilhas Wallis e Futuna"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Iémen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Jugoslávia"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Ãfrica do Sul"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Zâmbia"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zaire"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbábue"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Nome do paÃs não encontrado)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "Informações do sistema"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Ãltimo script de lançamento gerado pelo Spring"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Alcunha"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+#, fuzzy
+msgid "Search and download files"
+msgstr "Descarga falhada"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Descarga completa"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Remover..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Remover..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "Adicionar Robô"
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Acção"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Abrir canal"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "Criar nova batalha"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Realçar palavras"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "Adicionar Robô"
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Remover Conta de Utilizador"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Seleccionar..."
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Escolher durante o jogo"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "Definir acesso..."
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "pré-definido"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Informação do canal"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Criar nova batalha"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "Uma descrição curta do jogo que irá aparecer na lista das batalhas."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Descrição"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Escolha o mod com que pretende jogar."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+"A senha necessária para participar neste jogo. Mantenha vazio para não haver "
+"senha"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Porta"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "O mod não está disponÃvel"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Número de jogadores"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "O número máximo de jogadores permitidos na batalha"
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Patente MÃnima Necessária"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "Reconectar automaticamente"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "Ligar automaticamente ao último servidor"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Metal inicial"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+msgid "Disconnected from server, chat closed."
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Opções"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Restrições de unidades"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr ""
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr ""
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Senegal"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr ""
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr ""
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr ""
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Descarga falhada"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr ""
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr ""
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr ""
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Opções do Mapa"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr ""
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Informação do canal"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr ""
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr ""
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr ""
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr ""
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Informação do canal"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr ""
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr ""
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr ""
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr ""
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Reconectar automaticamente"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr ""
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Nenhum mapa encontrado"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Que conta de utilizador pretende remover hoje?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Guardar..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "Sempre"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Descarga falhada"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr ""
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr ""
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr ""
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr ""
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "Justo"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Opções do Mapa"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Posições iniciais"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Patente MÃnima Necessária"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Espectador"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Posições iniciais aleatórias"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Escolher durante o jogo"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Escolher durante o jogo"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Unidades proibidas"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Opções do Mapa"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr ""
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr ""
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr ""
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr ""
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Duração:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "batalha"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Mónaco"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Panamá"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Duração:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Erro do Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Carregar..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Sempre"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Guardar..."
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+#, fuzzy
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+"Precisa de descarregar o mod antes de entrar neste jogo.\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Porta inválida"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Seleccionar tudo"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " O utilizador está offline"
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " O utilizador está offline"
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr "Criar nova batalha"
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr ""
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr ""
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Descarga completa"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Notificação"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Número inválido"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Não é um número"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "O mapa não existe."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Iniciado"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Reconectar automaticamente"
+
+#: src/serverevents.cpp:999
+msgid "Unknown Error"
+msgstr ""
+
+#: src/serverevents.cpp:1009
+#, fuzzy
+msgid "Download complete, location is: "
+msgstr "Descarga completa"
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Descarga completa"
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Opções do Mapa"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Opções do Mapa"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "Battle volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "Acção"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "pré-definido"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+#, fuzzy
+msgid "Use less colors"
+msgstr "Usar as cores do sistema"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+#, fuzzy
+msgid "Show in-game player information"
+msgstr "Informações do sistema"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Acção"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Acção"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Acção"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Acção"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Duração:"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Desligado"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr ""
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr ""
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr ""
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr ""
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr ""
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr ""
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr ""
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr ""
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Espectador"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Posições iniciais aleatórias"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr ""
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr ""
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Nenhum"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+msgid "Import settings?"
+msgstr ""
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Abrir canal"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr ""
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Fixo"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr ""
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr ""
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr ""
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr ""
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr ""
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr ""
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "Descarga falhada"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Estado:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr ""
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Registo com sucesso,\n"
+"agora deverá conseguir iniciar a sessão."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Registo com sucesso"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "O registo falhou, a razão foi:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr ""
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr ""
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr ""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr ""
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr ""
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:661
+msgid "Disconnected from server."
+msgstr ""
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Continuar"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr ""
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid "Not up to date"
+msgstr ""
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr ""
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Nenhum"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Realçar"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "Entrar na mesma batalha"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Sempre"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Alcunha"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr ""
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr ""
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr ""
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr ""
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr ""
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr ""
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr ""
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "Adicionar Robô"
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Remover Conta de Utilizador"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Ãustria"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Erro do Spring"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "Descarga falhada"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Cancelar"
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Espectadores:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "Jogadores:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Equipa"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Aliado"
+
+#~ msgid "cpu"
+#~ msgstr "cpu"
+
+#~ msgid "Test firewall"
+#~ msgstr "Testar a firewall"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Conversa fechada."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Opções do Mapa"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "Escolher durante o jogo"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Descarga completa"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Desligar"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Jogador:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Definir cor"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Acção"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#~ msgid ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+#~ msgstr ""
+#~ "Existem dois ou mais robôs na mesma equipa. Isto não irá funcionar porque "
+#~ "os robôs não sabem partilhar."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "Número de jogadores"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Informação do canal"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Etiópia"
+
+#, fuzzy
+#~ msgid ""
+#~ "You need to download the map to be able to watch this replay.\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Precisa de descarregar o mapa para poder jogar nesta batalha.\n"
+#~ "\n"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr " O utilizador está offline"
+
+#, fuzzy
+#~ msgid "Only the host can change the game options"
+#~ msgstr "Apenas o anfitrião pode trancar o jogo."
+
+#~ msgid "Only the host can start the battle."
+#~ msgstr "Apenas o anfitrião pode iniciar a batalha."
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "Apenas o anfitrião pode trancar o jogo."
+
+#~ msgid "Only the host can lock the game."
+#~ msgstr "Apenas o anfitrião pode trancar o jogo."
+
+#, fuzzy
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "Apenas o anfitrião pode trancar o jogo."
+
+#~ msgid "Only the host can fix player colours."
+#~ msgstr "Apenas o anfitrião pode corrigir as cores."
+
+#~ msgid "Select all"
+#~ msgstr "Seleccionar tudo"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Remover Conta de Utilizador"
+
+#, fuzzy
+#~ msgid "you can also enter a ';' seperated list of usernames:"
+#~ msgstr "introduza uma lista separada por ;"
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Número inválido"
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "Uma descrição curta do jogo que irá aparecer na lista das batalhas."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "Escolha o mod com que pretende jogar."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normal"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "Erro do Spring"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "Continuar se o comandante morrer"
+
+#~ msgid "End if commander dies"
+#~ msgstr "Terminar se o comandante morrer"
+
+#~ msgid "End condition"
+#~ msgstr "Condição do fim do jogo"
+
+#~ msgid "Resources"
+#~ msgstr "Recursos"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "A quantidade de metal com que cada jogador começa."
+
+#~ msgid "Start Energy"
+#~ msgstr "Energia inicial"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "A quantidade de energia com que cada jogador começa."
+
+#~ msgid "Max units"
+#~ msgstr "Max. de unidades"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "O número máximo de unidades permitidas por jogador."
+
+#~ msgid "Limit d-gun"
+#~ msgstr "Limitar o d-gun"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "EdifÃcios camuflados"
+
+#~ msgid "This chat is exclusively for participants of this battle."
+#~ msgstr "Esta conversa é exclusivamente para participantes nesta batalha."
+
+#~ msgid "Cannot add bot, maximum number of players already reached."
+#~ msgstr ""
+#~ "Não é possÃvel adicionar robô, o número máximo de jogadores foi atingido."
+
+#~ msgid "Max players reached"
+#~ msgstr "Número máximo de jogadores atingido"
+
+#~ msgid "Save to:"
+#~ msgstr "Guardar em:"
+
+#~ msgid "Browse..."
+#~ msgstr "Navegar..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Escolha um directório"
diff --git a/po/quot.sed b/po/quot.sed
new file mode 100644
index 0000000..0122c46
--- /dev/null
+++ b/po/quot.sed
@@ -0,0 +1,6 @@
+s/"\([^"]*\)"/â\1â/g
+s/`\([^`']*\)'/â\1â/g
+s/ '\([^`']*\)' / â\1â /g
+s/ '\([^`']*\)'$/ â\1â/g
+s/^'\([^`']*\)' /â\1â /g
+s/ââ/""/g
diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin
new file mode 100644
index 0000000..2436c49
--- /dev/null
+++ b/po/remove-potcdate.sin
@@ -0,0 +1,19 @@
+# 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
+}
diff --git a/po/ro.gmo b/po/ro.gmo
new file mode 100644
index 0000000..a7e56a4
Binary files /dev/null and b/po/ro.gmo differ
diff --git a/po/ro.po b/po/ro.po
new file mode 100644
index 0000000..40955fd
--- /dev/null
+++ b/po/ro.po
@@ -0,0 +1,6722 @@
+# Romanian translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-09-07 20:22+0000\n"
+"Last-Translator: Danut Haiduc <danuthaiduc at gmail.com>\n"
+"Language-Team: Romanian <ro at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "AdaugÄ bot"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "PoreclÄ:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "AI:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Alege biblioteca AI pentru acest bot."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Valoare"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "AnuleazÄ"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "AdaugÄ Bot"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Nu au fost gÄsiÅ£i boÅ£i în instalaÅ£ia dvs. Spring."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Nu au fost gÄsite biblioteci AI."
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "AcceptÄ acordul"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Acceptaţi termenii acestui acord?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Da"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Nu"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "Auto-echilibreazÄ jucÄtorii în echipe"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "MetodÄ"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "Ãmparte rangurile în mod egal"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Aleatoare"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Clanuri"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Niciunul"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Echitabil"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Ãntotdeauna"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"Pune membrii aceluiaÅi clan (utilizatori cu acelaÅi titlu de clan, de ex. "
+"[smurf]Alice Åi [smurf]Bob) împreunÄ. \n"
+"Nimic: nimic special pentru clanuri.\n"
+"Echitabil: membrii unui clan sunt puÅi în aceeaÅi echipÄ, cu excepÅ£ia "
+"alianţei nedrepte.\n"
+"Totdeauna: membrii unui clan sunt puÅi întotdeauna în aceeaÅi echipÄ, "
+"indiferent de rang."
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "NumÄrul jucÄtorilor"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "ReconecteazÄ"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "OK"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Descriere"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "HartÄ"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "GazdÄ"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Spectatori:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "JucÄtori:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "HartÄ"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "DescarcÄ &harta"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "DescarcÄ &mod-ul"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Spectatori:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "JucÄtori:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "GazdÄ:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Stare:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Blocat"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Parolat"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Evidenţiere"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "LimitÄ de rang:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Descriere:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Ãnceput"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Plin"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Deschide"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "JucÄtor:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Tot"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "HartÄ:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Doar hÄrÅ£i pe care le am"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Max. JucÄtori:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Doar mod-uri pe care le am"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Spectator:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "JucÄtori:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "FiÅier"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Ãnceput"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "ListÄ de lupte"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "GÄzduieÅte nou..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "AlÄturÄ-te"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Nu puteÅ£i gÄzdui un joc cât timp sunteÅ£i deconectat. VÄ rog sÄ vÄ conectaÅ£i "
+"la un server."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Nu este conectat."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+"GÄzduirea e dezactivatÄ ca urmare a versiunii incompatibile de Spring "
+"folositÄ."
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Eroare Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"RulaÅ£i deja o instanÅ£Ä de Spring; închideÅ£i-o pentru a putea gÄzdui un nou "
+"joc"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "SunteÅ£i deja într-o luptÄ"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"SunteÅ£i deja într-o luptÄ.\n"
+"\n"
+"DoriÅ£i sÄ o pÄrÄsiÅ£i Åi sÄ deschideÅ£i una?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"Versiunea dvs. de wxWidgets este sub 2.8.\n"
+" Testarea porturilor nu va funcţiona.\n"
+" GÄzduirea poate sÄ eÅueze."
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"Server-ul folosit pentru testarea portului %d este inaccesibil. \n"
+"GÄzduirea poate sÄ nu funcÅ£ioneze cu aceastÄ setare."
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"Lupta nu a fost pornitÄ pentru cÄ portul selectat (%d) nu este capabil de a "
+"primi pachete.\n"
+"VerificaÅ£i configuraÅ£ia router-ului Åi firewall-ului sau alegeÅ£i alt port.\n"
+"\n"
+"DacÄ totul eÅueazÄ, activaÅ£i opÅ£iunea Hole Punching NAT Traversal\n"
+" din setÄrile pentru gÄzduire."
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+"Lupta nu a fost pornitÄ pentru cÄ mod-ul pe care l-aÅ£i ales nu poate fi "
+"gÄsit. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Eroare la pornirea luptei."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Nu pot gÄsi hÄrÅ£i în instalaÅ£ia dvs. Spring. Acest lucru se poate întâmpla "
+"Åi dacÄ nu aÅ£i setat corect Spring."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Nici o hartÄ gÄsitÄ"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"AlÄturarea la lupte e dezactivatÄ deoarece aveÅ£i o versiune incompatibilÄ de "
+"Spring."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "SunteÅ£i deja într-o luptÄ"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"SunteÅ£i deja într-o luptÄ.\n"
+"\n"
+"DoriÅ£i sÄ o pÄrÄsiÅ£i Åi sÄ deschideÅ£i una?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "SunteÅ£i deja într-o luptÄ"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"SunteÅ£i deja într-o luptÄ.\n"
+"\n"
+"DoriÅ£i sÄ o pÄrÄsiÅ£i Åi sÄ vÄ alÄturaÅ£i acesteia?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"RulaÅ£i deja o instanÅ£Ä de Spring; închideÅ£i-o pentru a vÄ putea alÄtura "
+"altei lupte."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+#, fuzzy
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+"SÄ Ã®ncerc sÄ descarc pentru dvs?\n"
+"Puteţi vedea progresul sub tab-ul \"Download Manager\""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Mod indisponibil"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "HartÄ indisponibilÄ"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Parola luptei"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Introduceţi parola"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Alege..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Opţiune"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Valoare"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Dimensiune"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Viteza vântului"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Puterea valurilor"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravitaţie"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Raza extractoarelor"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Maxim de metal"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "FixatÄ"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "AleasÄ Ã®n joc"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "AleasÄ Ã®n joc"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Poziţii de început"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "UnitÄÅ£i restricÅ£ionate"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "UnitÄÅ£i permise"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "UnitÄÅ£ile din aceastÄ listÄ vor fi disponibile în joc."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "ActiveazÄ toate unitÄÅ£ile"
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "ActiveazÄ toate unitÄÅ£ile"
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "ActiveazÄ toate unitÄÅ£ile"
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "UnitÄÅ£i restricÅ£ionate"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "UnitÄÅ£ile din aceastÄ listÄ nu vor fi disponibile în joc."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "UnitÄÅ£i restricÅ£ionate"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Porecla"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "EchipÄ"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Aliat"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Bonus de resurse"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Parte"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "SeteazÄ culoarea"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "SeteazÄ bonusul de resurse"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Spectator"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Kick"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "SunÄ"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "VÄ rog introduceÅ£i o valoare între 0 Åi 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "AdaugÄ bot"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Oman"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Spectator"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "JucÄtor:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "GazdÄ"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Client"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Ãntotdeauna"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Nu sunt gata"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "ActiveazÄ v-sync"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "SeteazÄ acces..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "ÃncarcÄ..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "ÃncarcÄ un set salvat de restricÅ£ii."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "SalveazÄ..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "SalveazÄ un set de restricÅ£ii"
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Alege..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "SalveazÄ un set de restricÅ£ii"
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "implicit"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Opţiuni mod"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "OpÅ£iuni hartÄ"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "indisponibil"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "eroare"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Selectaţi"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "implicit"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr "JucÄtorii cu acelaÅi numÄr de echipÄ controleazÄ unitÄÅ£ile în comun."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+"JucÄtorii cu acelaÅi numÄr de aliat lucreazÄ Ã®mpreunÄ pentru a atinge "
+"victoria."
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "AlegeÅ£i o culoare pentru a vÄ identifica unitÄÅ£ile în joc."
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "AlegeÅ£i-vÄ rasa"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "IntraÅ£i ca spectator în loc sÄ jucaÅ£i"
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Sunt gata"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "ApÄsaÅ£i aici dacÄ ÅtiÅ£i setÄrile luptei Åi sunteÅ£i gata."
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Culoare"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"O previzualizare a hÄrÅ£ii selectate. PuteÅ£i vedea poziÅ£iile de start, sau "
+"(dacÄ puse) zonele de start."
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "PÄrÄseÅte"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "PÄrÄseÅte lupta Åi întoarce-te la lista de lupte"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "AdaugÄ Bot..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "AdaugÄ un jucÄtor controlat de calculator"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "Previne alÄturarea altor jucÄtori"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "ReconecteazÄ"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Start"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+#, fuzzy
+msgid "Lock Balance"
+msgstr "BalanÅ£Ä"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "ActiveazÄ v-sync"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "SunÄ"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Nu sunt gata"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "PorneÅte cu forÅ£a?"
+
+#: src/battleroomtab.cpp:239
+#, fuzzy
+msgid "Balance alliances"
+msgstr "Doar gazda poate echilibra alianţele."
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "SeteazÄ culoarea"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "Face culorile jucÄtorilor mai uÅor de distins."
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid "Balance teams"
+msgstr "BalanÅ£Ä"
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "SalveazÄ..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "Selectaţi"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "implicit"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "Zone de start"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "ContinuÄ"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "SfârÅit"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "Harta nu existÄ."
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Unii jucÄtori nu sunt gata încÄ.\n"
+"SÄ Ã®i sun?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Nu sunt gata"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "Ping Timeout!"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "IntrÄ automat în acest canal"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "IntrÄ pe canal..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "Numele canalului"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "canal"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d utilizatori)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Sesiune ÃnchisÄ la ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Nu am putut crea folder. \n"
+"AsiguraÅ£i-vÄ cÄ nu este protecÅ£ie la scriere.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "FuncÅ£ia de jurnal este dezactivatÄ pânÄ la repornirea SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Avertizare de jurnal"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"Nu pot trece mesajul în jurnal.\n"
+"Scrierea va fi dezactivatÄ pentru camera "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"IntraÅ£i din nou în camerÄ pentru a reactiva jurnalul."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Nu pot deschide fiÅierul jurnal. \n"
+"AsiguraÅ£i-vÄ cÄ nu existÄ protecÅ£ie la scriere.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Culori Åi font"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "FoloseÅte culorile sistemului"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Fundal"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Acţiune"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Evidenţiere"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "IntrÄ/pÄrÄseÅte"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Mesajele mele"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Server"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Client"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Eroare"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Marcaj de timp"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Notificare"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Conectat la TAS Server.\n"
+"[22:30] <Tip> salut lume\n"
+"[22:30] ** Tip2 a intrat pe canal.\n"
+"[22:30] * Tip2 crede ca is fain culorile lui\n"
+"[22:45] <Tip> o serios?\n"
+"[22:46] <Tip2> Poate ar fi mai bine altcumva, le mai editez io...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Font"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "implicit"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Alege..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Comportament"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Jurnale de chat"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "SalveazÄ jurnalele de chat"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "EvidenÈiazÄ cuvinte"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Cuvinte de evidenÈiat în chat:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "introduceÅ£i o listÄ separatÄ prin \";\""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr "Ãn plus, sunÄ avertizare/pâlpâie bara de titlu "
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d utilizatori)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "click dreapta pentru opţiuni chat"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Trimite"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "CopiazÄ"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "CurÄÅ£Ä"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "IntrÄ automat în acest canal"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "AratÄ mesaje de ieÅire/intrare"
+
+#: src/chatpanel.cpp:433
+#, fuzzy
+msgid "Show mute list"
+msgstr "AratÄ ponturi"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Informaţii canal"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "SeteazÄ subiect..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Mesajul canalului..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "BlocheazÄ..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "DeblocheazÄ"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "ÃnregistreazÄ..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Återgere înregistrare"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Pornit"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Oprit"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "E pornit?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Protecţie spam"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "DeconecteazÄ"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "ReconecteazÄ"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Återge..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "SchimbÄ parola..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "SeteazÄ acces..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Conturi"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "Emite..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Administrator"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "MuÅ£eÅte utilizator"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Deschide chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "IntrÄ Ã®n aceeaÅi luptÄ"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Timp în joc"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "FÄ rost de IP Åi Pitici"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "MuÅ£eÅte.."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "MuÅ£eÅte pentru 5 minute"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "MuÅ£eÅte pentru 10 minute"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "MuÅ£eÅte pentru 30 de minute"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "MuÅ£eÅte pentru 2 ore"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "MuÅ£eÅte pentru 1 zi"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Dez-muÅ£eÅte"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "MuÅ£eÅte"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Kick..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Ban..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Unban"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "DÄ-i palmÄ!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Op"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "DeOp"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! ComandÄ: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" parametri: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "canal"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "luptÄ"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "server"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " a intrat în "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " a pÄrÄsit "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Informaţii canal"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * SetatÄ de "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat închis."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "SunteÅ£i sigur cÄ vreÅ£i sÄ introduceÅ£i %d rânduri?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Atenţie: exces de mesaje"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Aveţi SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Nu sunteÅ£i în canal sau canalul nu existÄ."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" Eroare: comanda (%s) nu existÄ, folosiÅ£i /help pentru o listÄ de comenzi "
+"disponibile."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr " Nu sunteÅ£i în luptÄ sau lupta nu existÄ."
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Utilizatorul e deconectat."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Trimis: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "Eroare ChanServ"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ nu e în acest canal."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Care va fi subiectul nou?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Mesaj:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "BlocheazÄ canalul..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Care va fi parola nouÄ?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "DeblocheazÄ canalul"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "SunteÅ£i sigur cÄ doriÅ£i sÄ deblocaÅ£i acest canal?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ nu e pe acest server."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "ÃnregistreazÄ canal"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Cine va fi numit fondatorul canalului?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "Canal neînregistrat"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "SunteÅ£i sigur cÄ doriÅ£i sÄ dez-înregistraÅ£i acest canal?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Återge cont utilizator"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Ce cont de utilizator doreÅti sÄ Återgi în aceastÄ zi minunatÄ?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Återge cont"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "SunteÅ£i sigur cÄ doriÅ£i sÄ ÅtergeÅ£i contul "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "SchimbÄ parola contului de utilizator"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Pentru ce cont doriÅ£i sÄ schimbaÅ£i parola?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Care va fi noua parolÄ?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Nu a fost implementat"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "Emite mesaj"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "Mesajul de emis:"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "Nu aveţi modul "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . VÄ rugÄm descÄrcaÅ£i-l mai întâi."
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr "Mod indisponibil"
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "AceastÄ luptÄ e parolatÄ; introduceÅ£i parola."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "MuÅ£eÅte utilizator"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Pentru câte minute sÄ fie muÅ£it utilizatorul?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Kick Utilizator"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Motiv:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Kick utilizator"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "MuÅ£eÅte utilizator"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Durata:"
+
+#: src/chatpanel.cpp:1797
+#, fuzzy
+msgid "couldn't add user"
+msgstr "Nu pot lansa browser."
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Conectare la serverul lobby"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Serverul la care sÄ vÄ conectaÅ£i. PuteÅ£i sÄ vÄ conectaÅ£i la orice server "
+"doriţi scriind în formatul \"adresa:portul\"."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Parola"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "Auto-conectare data viitoare"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"Å£ine minte detaliile conexiunii Åi se conecteazÄ automat la urmÄtoarea "
+"pornire a lobby-ului"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"NotÄ: DacÄ nu aveÅ£i cont, vÄ\n"
+" puteţi înregistra pe gratis la\n"
+"tab-ul \"Ãnregistrare\""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Conectare"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Ãnregistrare"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "PoreclÄ"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Port invalid."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Port invalid"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Port ieÅit din interval.\n"
+"\n"
+"Trebuie sÄ fie un întreg între 1 Åi 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "GazdÄ/port invalidÄ."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "GazdÄ invalidÄ"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "NumÄr invalid"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"Ãnregistrare nereuÅitÄ, motiv:\n"
+"ParolÄ / confirmare non-identice"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Ãnregistrare nereuÅitÄ."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " Andorra"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "Emiratele Arabe Unite"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "Afganistan"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "Antigua Åi Barbuda"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Anguilla"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "Albania"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "Armenia"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "Antilele Olandeze"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Angola"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "Antarctica"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "Argentina"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "Samoa AmericanÄ"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "Austria"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "Australia"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "Aruba"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "Azerbaijan"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "Bosnia Åi HerÅ£egovina"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "Barbados"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "BangladeÅ"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "Belgia"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "Burkina Faso"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "Bulgaria"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "Bahrain"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "Burundi"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Benin"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "Bermude"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "Brunei"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "Bolivia"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "Brazilia"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "Bahamas"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "Bhutan"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "Insula Bouvet"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "Botswana"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "Bielorusia"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Belize"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Canada"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "Cocos (Insulele Keeling)"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "Republica CentrafricanÄ"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Congo"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "Elveţia"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "Coasta de FildeÅ"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "Insulele Cook"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Chile"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "Camerun"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "China"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "Columbia"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "Costa Rica"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "Cuba"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Capul Verde"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "Insula Christmas"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "Cipru"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "Republica CehÄ"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "Germania"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "Djibouti"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "Danemarca"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Dominica"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "Republica DominicanÄ"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "Algeria"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "Ecuador"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "Estonia"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "Egipt"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "Sahara de Vest"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "Eritreea"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "Spania"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "Etiopia"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "Finlanda"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Fiji"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "Insulele Falkland"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "Micronezia"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "Insulele Feroe"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "Franţa"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "FranÈa, Metropolitan"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Gabon"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "Grenada"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "Georgia"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "Guiana FrancezÄ"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ghana"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "Gibraltar"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "Groenlanda"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "Gambia"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "Guineea"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "Guadalupa"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "Guineea EcuatorialÄ"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "Grecia"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "Georgia de Sud Åi Insulele Sandwich de Sud"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "Guatemala"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "Guam"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "Guineea-Bissau"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "Guiana"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Hong Kong"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "Heard Åi Insulele McDonald"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "Honduras"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "Croaţia"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "Haiti"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "Ungaria"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "Indonezia"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "Irlanda"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "Israel"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "India"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "Teritoriul Britanic din Oceanul Indian"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "Irak"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "Iran"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "Islanda"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "Italia"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Jamaica"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "Iordan"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "Japonia"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "Kenya"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "Kârgâzstan"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Cambogia"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "Kiribati"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "Comoros"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "Saint Kitts si Nevis"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "Coreea de Nord"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Coreea de Sud"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "Kuweit"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "Insulele Caiman"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "Kazahstan"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "Laos"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Liban"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "Saint Lucia"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "Liechtenstein"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "Sri Lanka"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "Liberia"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "Lesotho"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "Lituania"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "Luxemburg"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "Letonia"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "Libia"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "Maroc"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Monaco"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "Rep. Moldova"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "Muntenegru"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "Madagascar"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "Insulele Marshall"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "Macedonia"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Mali"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "Myanmar"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "Mongolia"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Macao"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "Insulele Mariane de Nord"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "Martinica"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "Mauritania"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "Montserrat"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "Malta"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "Mauritania"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "Maldive"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Malawi"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "Mexic"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "Malaezia"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Mozambic"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "Namibia"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "Noua Caledonie"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "Niger"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "Insula Norfolk"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "Nigeria"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "Nicaragua"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "Olanda"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "Norvegia"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Nepal"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "Nauru"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "ZonÄ NeutrÄ (Arabia SauditÄ/Irak)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "Niue"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "Noua ZeelandÄ"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Oman"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Panama"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "Peru"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "Polinezia FrancezÄ"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "Papua Noua Guinee"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "Filipine"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "Pakistan"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "Polonia"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "Sf. Pierre Åi Miquelon"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "Pitcairn"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "Puerto Rico"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "Portugalia"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "Palau"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "Paraguay"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "Qatar"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "Reunion"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "România"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "Serbia"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "FederaÈia RusÄ"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Rwanda"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "Arabia SauditÄ"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Insulele Solomon"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "Seychelles"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "Sudan"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "Suedia"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "Singapore"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "Sfânta Elena"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "Slovenia"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "Svalbard Åi Jan Mayen"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Slovacia (Republica SlovacÄ)"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "Sierra Leone"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "San Marino"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Senegal"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Somalia"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "Suriname"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "Sao Tome Åi Principe"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "Uniunea SovieticÄ (fosta)"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "El Salvador"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "Siria"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Swaziland"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "Insulele Turks Åi Caicos"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Ciad"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "Teritoriile Franceze de Sud"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Togo"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Tailanda"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "Tajikistan"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "Tokelau"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "Turkmenistan"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "Tunisia"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Tonga"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "Timorul de Est"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "Turcia"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "Trinidad Åi Tobago"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "Tuvalu"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "Taiwan"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "Tanzania"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "Ucraina"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Uganda"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "Regatul Unit (Marea Britanie)"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "Insulele Minore Externe ale Statelor Unite"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "Statele Unite"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "Uruguay"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "Uzbekistan"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "Vatican"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "Sfântul Vincent Åi Grenadine"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "Venezuela"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "Insulele Virgine (Britanice)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "Insulele Virgine (SUA)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "Vietnam"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "Vanuatu"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "Wallis Åi Futuna"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Samoa"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Yemen"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "Mayotte"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "Iugoslavia"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Africa de Sud"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "Zambia"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "Zair"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Zimbabwe"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Numele complet al Å£Ärii nu a fost gÄsit)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "Informaţii de sistem"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "Jurnal extins al aplicaţiei"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Ultimul script pentru Spring lansat"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Joc"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+#, fuzzy
+msgid "Search and download files"
+msgstr "CautÄ fiÅier"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "DescÄrcare completÄ"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+#, fuzzy
+msgid "unknown hash "
+msgstr "necunoscut"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Återge..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Återge..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "AdaugÄ Bot..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Acţiune"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Deschide chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "GÄzduieÅte luptÄ nouÄ"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "EvidenÈiazÄ cuvinte"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "AdaugÄ Bot..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Återge cont utilizator"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Nume de utilizator"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Selectaţi"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "AleasÄ Ã®n joc"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"salvat cu sicces în:\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "SeteazÄ acces..."
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "Nu pot salva\n"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "implicit"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Informaţii canal"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "GÄzduieÅte luptÄ nouÄ"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "O descriere scurtÄ a jocului, aceasta va apÄrea în lista de lupte."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Descriere"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "AlegeÅ£i mod-ul cu care sÄ jucaÅ£i."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+"Parola necesarÄ pentru joc. LÄsaÅ£i necompletat pentru a nu avea parolÄ."
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Port"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "Portul de ascultare UDP pentru gÄzduire. Implicit: 8452"
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "indisponibil"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "NumÄrul jucÄtorilor"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "NumÄrul maxim de jucÄtori permis în aceastÄ luptÄ."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "Hole punching"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "Traversare NAT"
+
+#: src/hostbattledialog.cpp:177
+#, fuzzy
+msgid "NAT traversal to use."
+msgstr "Traversare NAT"
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Rang minim necesar"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Ãncepe gÄzduirea luptei."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "Trebuie sÄ alegeÅ£i un mod prima datÄ."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Nici un mod ales."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"salvat cu sicces în:\n"
+
+#: src/httpdownloader.cpp:78
+#, fuzzy
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"salvat cu sicces în:\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr "Nu pot salva\n"
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"la:\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Navigator web"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Navigator implicit"
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr "FoloseÅte preferinÅ£a de sistem pentru browser"
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Specificaţi:"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr "SpecificÄ browser-ul preferat"
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "RÄsfoieÈte"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr "FoloseÅte un dialog de cÄutare pentru a gÄsi executabilul"
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+#, fuzzy
+msgid "Use a file dialog to find the editor binary"
+msgstr "FoloseÅte un dialog de cÄutare pentru a gÄsi executabilul"
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "ReconecteazÄ"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "Conectare la serverul lobby"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "&Unelte"
+
+#: src/lobbyoptionstab.cpp:121
+#, fuzzy
+msgid "Show Tooltips?"
+msgstr "AratÄ ponturi"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+#, fuzzy
+msgid "Match exact"
+msgstr "Prinde exceptii AI"
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Metal de început"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "Alegeţi executabilul unui navigator"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "Alegeţi executabilul unui navigator"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "RÄspuns necunoscut de la server"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "ListÄ de lupte"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "CamerÄ de luptÄ"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "OpÈiuni"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "UnitÄÅ£i restricÅ£ionate"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "P2P"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Senegal"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "RestaureazÄ"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "AplicÄ"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Joc"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "Total IeÅire: "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "Total Intrare: "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "necunoscut"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "AnuleazÄ DescÄrcarea"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "PublicaÅ£i fiÅier nou"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "CautÄ fiÅier"
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "ActiveazÄ unelte LuaUI"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "indisponibil"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "seeding"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr "la rând"
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "Statut: deconectat"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "Statut: conectat"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "Statut: necunoscut"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "Total IeÅire: %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "Total Intrare: %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Conectare..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&Deconectare"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Opţiuni UI"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&TerminÄ"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "&Intrare pe canal..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Informaţii canal"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Deschide chat &privat"
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&ReîncarcÄ hÄrÅ£i/mod-uri"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "VerificÄ pentru Versiune nouÄ"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "SpringSettings"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&Despre"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Informaţii canal"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&RaporteazÄ o problemÄ..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Documentare"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&FiÅier"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Unelte"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Ajutor"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Statut: conectat"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "IntrÄ pe canal..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Numele canalului"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Deschide chat privat..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Nume de utilizator"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+"SpringLobby este un client independent de platformÄ pentru motorul RTS "
+"Spring."
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Nici o hartÄ gÄsitÄ"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "PorneÅte manual sistemul de torente"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "OpreÅte manual sistemul de torente"
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Ce cont de utilizator doreÅti sÄ Återgi în aceastÄ zi minunatÄ?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "SalveazÄ..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "Ãntotdeauna"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "DescarcÄ"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "ReincarcÄ"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "DescarcÄ"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "parte:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "aliat: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+#, fuzzy
+msgid "Show"
+msgstr "AratÄ totul"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "FiÅier"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Maxim de metal"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Poziţii de început"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Rang minim necesar"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "Mediu"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Spectator"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Poziţii de început"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Tipul poziţiei de început"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Cum vor selecta jucÄtorii unde sÄ Ã®nceapÄ:\n"
+"0: poziÅ£ie fixÄ pe hartÄ\n"
+"1: poziÅ£ie aleatorie pe hartÄ\n"
+"2: alegere în joc\n"
+"3: alegere în lobby înaintea începerii"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "AleasÄ Ã®n joc"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "AleasÄ Ã®n joc"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "UnitÄÅ£i restricÅ£ionate"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Opţiuni UI"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "Å£"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Executabile (*.exe)|*.exe|Orice fiÅier (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Orice fiÅier (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr "App Bundles (*.app)|*.app|Orice fiÅier (*.*)|*.*"
+
+#: src/playback/playbackfilter.cpp:60
+#, fuzzy
+msgid "Filter settings"
+msgstr "Salvare setÄri"
+
+#: src/playback/playbackfilter.cpp:164
+#, fuzzy
+msgid "Filesize in KB:"
+msgstr "MÄrime fiÅier (MB)"
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Durata:"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Selectaţi"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Mod"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Panama"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Durata:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Eroare Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "MÄrime fiÅier (MB)"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "MÄrime fiÅier (MB)"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "FiÅier"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "ÃncarcÄ..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Ãntotdeauna"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "SalveazÄ..."
+
+#: src/playback/playbacktab.cpp:286
+#, fuzzy
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"Nu pot gÄsi versiunea dvs. Spring din biblioteca UnitSync.\n"
+"\n"
+"Jocul online va fi dezactivat."
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Port invalid"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Selectaţi"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Utilizatorul e deconectat."
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() eÅuat ! (excepÅ£ie)"
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Utilizatorul e deconectat."
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " a intrat în "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "Intrare pe canal eÅuatÄ"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Nu pot intra pe canalul "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " deoarece: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Mesaj de la Server"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " are ip=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " nu suportÄ, de fapt, nat traversal"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "Ai fost dat afarÄ din luptÄ!"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "Dat afarÄ de cÄtre gazdÄ"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "ListÄ de lupte"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "DescÄrcare completÄ"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"S-a produs o eroare la verificarea versiunii.\n"
+"VÄ rugÄm încercaÅ£i din nou mai târziu.\n"
+"DacÄ problema persistÄ, vÄ rugÄm sÄ o raportaÅ£i folosind Ajutor -> Raportare "
+"problemÄ."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Notificare"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "NumÄr invalid"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Nu e numÄr"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "Harta nu existÄ."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Ãnceput"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "ReconecteazÄ"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "necunoscut"
+
+#: src/serverevents.cpp:1009
+#, fuzzy
+msgid "Download complete, location is: "
+msgstr "DescÄrcare completÄ"
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "DescÄrcare completÄ"
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "Nu pot lansa browser. URL-ul este: "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "Nu pot lansa browser."
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr "Viteza rotiţei de scroll"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+"Valorile mai mari înseamnÄ zoom mai rapid cu rotiÅ£a.\n"
+"Valorile negative vor inversa direcţia zoom-ului.\n"
+"Rezultatele pot depinde de modul camerei!"
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr "MÄrimea shadow-map"
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"valori mai mari = umbre care aratÄ mai bine\n"
+"valori posibile: 1024, 2048, 4096, 8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr "Distanţa vederii copacilor"
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr "seteazÄ distanÅ£a maximÄ la care pomii vor fi afiÅaÅ£i"
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr "Detaliul reliefului"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr "valoare mai mare = relief mai detaliat"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "Unit LOD distance"
+msgstr "DistanÅ£a pictogramelor pt. unitÄÅ£i"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr "valoare mai mare = unitÄÅ£i mai detaliate"
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr "Detaliile vegetaţiei"
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "higher value = more detailed grass"
+msgstr "valoare mai mare = iarbÄ mai detaliatÄ"
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr "ProiecÅ£ii pe pÄmânt [decals]"
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr "DistanÅ£a pictogramelor pt. unitÄÅ£i"
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+"hotÄrÄÅte la ce distanÅ£Ä unitÄÅ£ile sunt afiÅate complet; nu pictograme\n"
+"valoare mai mare = distanÅ£Ä mai mare = unitÄÅ£i mai multe afiÅate"
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr "Maxim de particule simultane"
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "limiteazÄ câte particule sunt afiÅate în acelaÅi timp"
+
+#: src/settings++/Defs.hpp:233
+#, fuzzy
+msgid "Max nano simultaneous particles"
+msgstr "Maxim de particule simultane"
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr "RuleazÄ full-screen"
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr "ruleazÄ pe tot ecranul sau într-o fereastrÄ?"
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "Mod dual-screen"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "dacÄ aveÅ£i douÄ monitoare le puteÅ£i folosi pe ambele"
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "ActiveazÄ v-sync"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr "Sincronizare verticalÄ pornit/oprit"
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr "16-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr "umpluturÄ"
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr "24-bit Z-buffer"
+
+#: src/settings++/Defs.hpp:257
+#, fuzzy
+msgid "Full-scene anti-aliasing samples"
+msgstr "Full-screen anti-aliasing samples"
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr "cât de mult anti-aliasing sÄ fie folosit"
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr "Maxim de sunete simultane"
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+"numÄrul maxim de sunete care sÄ fie redate în acelaÅi timp\n"
+"Setaţi ca zero pentru a dezactiva sunetul de tot."
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "Master sound volume"
+msgstr "volumul de sunet total"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "master sound volume"
+msgstr "volumul de sunet total"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "General sound volume"
+msgstr "volumul de sunet total"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "general volume relative to master volume"
+msgstr "volumul cu care unitÄÅ£ile rÄspund - afectat de volumul global"
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr "Volum de sunet de rÄspuns"
+
+#: src/settings++/Defs.hpp:273
+#, fuzzy
+msgid "reply volume relative to master volume"
+msgstr "volumul cu care unitÄÅ£ile rÄspund - afectat de volumul global"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "CamerÄ de luptÄ"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "battle volume relative to global volume"
+msgstr "volumul cu care unitÄÅ£ile rÄspund - afectat de volumul global"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "User interface volume"
+msgstr "Volum de sunet de rÄspuns"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "ui volume relative to global volume"
+msgstr "volumul cu care unitÄÅ£ile rÄspund - afectat de volumul global"
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "Umbre (încet)"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr "activeazÄ umbre?"
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr "Copaci 3D"
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+"doriÅ£i copaci care aratÄ mai bine?\n"
+"necesitÄ placÄ video Geforce 2/Radeon 8500/Intel 830 sau mai bunÄ"
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr "Nori cu rezoluÅ£ie înaltÄ"
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"doriţi un cer mai frumos?\n"
+"necesitÄ placÄ video Geforce 5/Radeon 9500/Intel 915 sau mai bunÄ"
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr "Nori dinamici (încet)"
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr "doriÅ£i nori care se miÅcÄ?"
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr "Reflexii pe unitÄÅ£i"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"unitÄÅ£i strÄlucitoare\n"
+"necesitÄ placÄ video Geforce 5/Radeon 9500/Intel 915 sau mai bunÄ"
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr "Nu folosi shader-e pentru hÄrÅ£i SM3"
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr "aveÅ£i probleme cu hÄrÅ£i SM3? activaÅ£i asta"
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr "ActiveazÄ suport pentru LuaShaders"
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr "face niÅte efecte ca lumea"
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr "Texturi LOS de rezoluÅ£ie înaltÄ"
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr "Line of Sight (câmp vizual) mai clar"
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr "Puncte fine"
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr "aplicare anti-aliasing pe puncte?"
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr "Linii fine"
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr "aplicare anti-aliasing pe linii?"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr "AratÄ comenzi pe mini-hartÄ"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr "DaÅ£i ordine pe mini-hartÄ cum aÅ£i face "
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "AratÄ comenzi pe mini-hartÄ"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr "valoarea implicitÄ e \"pornit\""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr "AratÄ pictograme pe mini-hartÄ"
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr "AratÄ marcaje pe mini-hartÄ"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr "Mini-hartÄ pe stânga (un singur ecran)"
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "pe stânga e implicit"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr "Mini-hartÄ pe stânga (dual screen)"
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr "Culori de pe mini-hartÄ simplificate"
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "FoloseÅte mai puÅ£ine culori"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr "Nanospray colorat ca echipele"
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr "SÄ fie nano-particulele de culoarea echipelor?"
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr "HartÄ de înÄlÅ£ime colorizatÄ"
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr "face diferenÅ£ele în înÄlÅ£ime mai evidente"
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "AratÄ ceas în joc"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+"necesitÄ LuaWidgets (unelte Lua).\n"
+"Va fi arÄtat în colÅ£ul din dreapta-jos."
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr "AratÄ informaÅ£ii despre jucÄtori în joc"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr "AratÄ numÄrul de cadre/secundÄ (FPS) în joc"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr "RegleazÄ afiÅajul la alt-tab"
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr "Nu schimbaÅ£i dacÄ nu este necesar."
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr "Interzi ajutoare AI"
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+"DezactiveazÄ Economy AI etc,\n"
+"Poate afecta LuaUI."
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr "ActivezÄ deplasarea la margine"
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr "MutÄ ecranul dacÄ sÄgeata se mutÄ pe margine."
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr "InverseazÄ Mouse"
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "InverseazÄ axa Y a mouse-ului în modul FPS"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr "CamerÄ de deasupra"
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "seteazÄ viteza de mutare (mouse Åi tastaturÄ) pentru acest mod"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr "CamerÄ de deasupra rotativÄ"
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr "CamerÄ de gen \"Total War\""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr "CamerÄ persoana I (FPS)"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr "CamerÄ liberÄ"
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+"FÄ acesta tipul de camerÄ implicit în Spring.\n"
+"Poate fi schimbat în joc."
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr "Nivel de verbozitate în consolÄ (0=min, 10=max)"
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr "CâtÄ informaÅ£ie sÄ iasÄ?"
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr "Prinde exceptii AI"
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr "dezactiveazÄ pentru depanare AI"
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "De bazÄ"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+"Depinzând de puterea plÄcii dvs. video,\n"
+"setarea calitÄÅ£ii poate avea influenÅ£e mari\n"
+"pentru performanţa Spring.\n"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr "Cu reflexie"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "Cu reflexie + refracţie"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "DinamicÄ"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr "InverseazÄ axa y a mouse-ului"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr "interschimbÄ sus/jos cu jos/sus"
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr "Suport pentru mouse cu 3 butoane pe mini-hartÄ"
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr "dacÄ nu doriÅ£i sÄ folosiÅ£i acel buton, dezactivaÅ£i-l"
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr "De deasupra"
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr "Vedere de sus staticÄ"
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr "Vedere de sus rotativÄ"
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+"Ca vederea de sus staticÄ, dar cu posibilitatea rotaÅ£iei în jurul axei Z"
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr "\"Total War\""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr "Vedere de sus, cu rotaţie pe axa X"
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "Persoana I (FPS)"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr "Camera din punctul de vedere al unitÄÅ£ii"
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr "ModificÄ vederea în orice mod"
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "dimensiune orizontalÄ ecran"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "dimensiune verticalÄ ecran"
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Cu reflexie"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Shore waves"
+msgstr "activeazÄ umbre?"
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Enables shorewaves"
+msgstr "activeazÄ umbre?"
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Cu reflexie"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Cu reflexie"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Durata:"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Oprit"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "Opţiuni combinate"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "Calitate video"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "Detaliere"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "Opţiuni UI"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "Audio"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+"SchimbÄrile efectuate în tab-urile Calitate Åi Detalii în modul expert\n"
+" vor fi pierdute la alegerea din nou a opÅ£iunilor de bazÄ.\n"
+"Aceste setÄri nu vor fi afiÅate în tab-ul de OpÅ£iuni combinate.\n"
+"(acest mesaj poate fi dezactivat din meniul \"FiÅier\")"
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "Eroare!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "Salvez setÄrile Spring înainte de a ieÅi?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "Confirmare necesarÄ"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "SpringSettings (mod expert)"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "SpringSettings (mod simplu)"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "Salvare setÄri"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "Restaurare setÄri la valori implicite"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "DezactiveazÄ avertizare pt. mod expert"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "IeÅire"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "Simplu (puţine opţiuni)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "Expert (toate opţiunile)"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "Despre"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "Contact"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "Autori"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "RaporteazÄ o problemÄ"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Mod"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "Info/Ajutor"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "RestaureazÄ TOATE setÄrile la valori implicite?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "Sugestie"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr "SpringSettings e o interfaÅ£Ä graficÄ pentru setÄrile motorului Spring."
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr "Kloot"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "Echipa SpringLobby"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+"mulÅ£umiri pentru invitaÅ£ie, cod pentru refolosit, infrastructurÄ, Åi ajutor "
+"în general"
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr "toatÄ lumea care a contribuit sugestii / gÄsit probleme"
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+"AplicaÅ£ia a generat o eroare fatalÄ Åi va fi închisÄ.\n"
+"Nu este posibilÄ crearea unui raport.\n"
+"\n"
+"vÄ rugÄm sÄ activaÅ£i wxUSE_DEBUGREPORT"
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Eroare criticÄ"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "Cale cÄtre bibliotecÄ unitsync"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+"A fost o problemÄ la citirea setÄrilor.\n"
+"VÄ rugÄm verificaÅ£i dacÄ aceastÄ cale e corectÄ.\n"
+"DupÄ corectare, apÄsaÅ£i\n"
+"butonul \"FoloseÅte calea\"."
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "FoloseÅte calea"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "unitsync.so pe linux, unitsync.dll pe windows"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "SetÄri de cale"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "AlegeÅ£i o cale cÄtre unitsync"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Orice fiÅier"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+"SpringSettings nu poate sÄ Ã®ncarce biblioteca unitsync.\n"
+"AtenÅ£ie la setÄrile unitsync.\n"
+"Versiunea dvs. Spring trebuie sÄ fie 0.76 sau mai nouÄ, altfel \n"
+"va eÅua în orice caz."
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "scÄzut"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "mediu"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "ridicat"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "foarte scÄzut"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "foarte ridicat"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "nu pot lansa browser-ul implicit"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "Nu pot lansa browser. URL-ul este: "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "Nu pot lansa browser."
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "Nu pot accesa setÄrile.\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "Nu pot salva, unitsync nu este încÄrcat complet."
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "Eroare SpringSettings"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "Opţiuni audio"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "Rezoluţie ecran"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+"DacÄ este necesarÄ o placÄ video specialÄ,\n"
+"va fi menÅ£ionatÄ Ã®n indicaÅ£ie."
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "Calitatea apei"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "Rezoluţia în bit"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "OpÅ£iuni ale calitÄÅ£ii de afiÅare"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "Opţiuni ale modului video"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "Opţiuni Anti-Aliasing"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr "Z-/Depth-Buffer"
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "Nivel de afiÅare detalii"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+"Aceste opÅ£iuni vÄ permite sÄ controlaÅ£i afiÅarea (rendering) Spring.\n"
+"Pentru mai multÄ performanÅ£Ä, reduceÅ£i-le.\n"
+"Controlul complet e disponibil sub 'Mod expert' - \n"
+"apÄsaÅ£i meniul 'Mod' sau pe butonul din dreapta.\n"
+"Pentru a reveni în acest mod, alegeţi 'Mod simplu' din meniu.\n"
+"DacÄ Ã®ntâmpinaÅ£i erori legate de graficÄ Ã®n timp ce rulaÅ£i Spring\n"
+"s-ar putea sÄ fie necesar sÄ dezactivaÅ£i unele setÄri din \n"
+" modul expert.\n"
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "Calitate graficÄ"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "Detalii graficÄ"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "Rezoluţie ecran"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "SchimbÄ Ã®n modul expert"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (actual)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+"SeteazÄ toate opÅ£iunile de calitate la valori predefinite, dupÄ alegere."
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+"SeteazÄ toate opÅ£iunile de detalii la valori predefinite, dupÄ alegere."
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr "Alegeţi rezoluţia pentru monitorul/arele dvs."
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "Info"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+"Setarea unui slider la 0 va exclude acel\n"
+"element din modificarea în joc."
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "Viteze de derulare (mouse + tastaturÄ)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "Mod predefinit pt. camerÄ"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "Alte opÅ£iuni interfaÅ£Ä"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "Zoom"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+"Puteţi trage pictograma bot/soare pentru a defini poziţia de start.\n"
+" TreceÅ£i cu mouse-ul peste ea pentru a putea schimba partea, alianÅ£a Åi "
+"bonusul."
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "AdaugÄ bot..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Spectator"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Poziţii de început"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- Alegeţi unul --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "Eroare la setarea jocului"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Trebuie sÄ alegeÅ£i întâi o hartÄ."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+"ContinuÄ fÄrÄ a adÄuga bot?\n"
+" Jocul se va termina repede.\n"
+" "
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "Nici un bot adÄugat"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "Nu puteÅ£i porni altÄ instanÅ£Ä de Spring cât timp alta este pornitÄ."
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Salut, "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+".\n"
+"Se pare cÄ aceasta este prima datÄ când folosiÅ£i SpringLobby. Am gÄsit o "
+"configuraÅ£ie care ar trebui sÄ funcÅ£ioneze, dar ar trebui verificatÄ, în "
+"special configuraţia Spring. \n"
+"\n"
+"Când aÅ£i terminat, conectaÅ£i-vÄ la un server prin meniul FiÅier, Åi bucuraÅ£i-"
+"vÄ de un joc bun de Spring :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Bine aÈi venit"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Niciunul"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "SetÄri de cale"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+"AceastÄ aplicaÅ£ie a generat o eroare fatalÄ Åi va fi terminatÄ.\n"
+"Generarea unui raport nu este posibilÄ.\n"
+"\n"
+"VÄ rugÄm obÅ£ineÅ£i o bibliotecÄ wxWidgets care suportÄ wxUSE_DEBUGREPORT"
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Deschide chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "ListÄ de lupte"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "GÄseÅte"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "Executabilul Spring"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Loc"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "GÄseÅte"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "Biblioteca UnitSync"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Configurare automatÄ"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "Alegeţi un executabil Spring"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "BibliotecÄ"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr "Nu fÄ nimic (folosiÅ£i în cazul în care ÅtiÅ£i ce faceÅ£i)"
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid "Data dir wizard"
+msgstr "Wizard pentru început"
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "Alegeţi un director"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+"Ceva a eÅuat în crearea directoarelor\n"
+"VÄ rog creaÅ£i manual urmÄtoarele foldere:"
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "Timp de conectare expirat"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "RÄspuns necunoscut de la server"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+"Intrarea forÅ£atÄ prin NAT a eÅuat, s-ar putea ca aceastÄ luptÄ sÄ nu "
+"funcţioneze."
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "Numere"
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "MB trimiÅi"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "MB trimiÅi"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Stare:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr "% complet"
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s sus"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s jos"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "Timp estimat (s)"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "MÄrime fiÅier (MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "Auto porneÅte sistemul Torrent"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr "la conectarea lobby-ului"
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr "la pornirea lobby-ului"
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "manual"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr "La pornirea jocului opreÅte modul"
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "PauzÄ toate torrent-ele"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr "Limite de vitezÄ:"
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "upload (KB/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "descÄrcare (KB/s)"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "Numere"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "vitezÄ maximÄ upload în KB/s (-1 pt infinit)"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "vitezÄ maximÄ download în KB/s (-1 pt infinit)"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "port folosit pentru conexiuni torrent"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "numÄr maxim de conexiuni simultane"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+#, fuzzy
+msgid "Torrent system failure"
+msgstr "Auto porneÅte sistemul Torrent"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Parola server-ului"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Ãnregistrare cu succes.\n"
+"Ar trebui sÄ vÄ puteÅ£i conecta."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Ãnregistrare cu succes."
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "Ãnregistrare nereuÅitÄ, motivul a fost:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"Calea navigatorului: "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "Eroare de help"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "ScrieÅ£i /help într-o cÄsuÅ£Ä de chat."
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "Ajutor comenzi SpringLobby"
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Comenzi globale:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - SeteazÄ statutul dvs. la \"away\" - absent"
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - Revenire la normal (din \"away\")"
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+" \"/changepassword parolÄveche parolÄnouÄ\" - SchimbÄ parola contului."
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - AratÄ canalele active"
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr " \"/help [subiect]\" - AratÄ informaÅ£ii despre o comandÄ."
+
+#: src/ui.cpp:495
+#, fuzzy
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+" \"/join channel [password] [,channel2 [password2]]\" - IntrÄ Ã®ntr-un canal"
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - la fel ca \"/join\""
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" - AratÄ cât timp aÅ£i petrecut în joc."
+
+#: src/ui.cpp:498
+#, fuzzy
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+" \"/msg utilizator [text]\" - Trimite un mesaj privat cu textul text cÄtre "
+"utilizator."
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - AratÄ canalele active"
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - la fel ca \"/join\""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename newalias\" - VÄ schimbÄ pseudonimul în newalias."
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " \"/sayver\" - Spune ce versiune de SpringLobby aveţi în chat."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr " \"/testmd5 text\" - DÄ hash md5-b64 pentru textul dat."
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - AratÄ ce versiune de SpringLobby aveÅ£i."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Comenzi chat:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me acţiune\" - Spune mesaj de acţiune în stil IRC"
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+"DacÄ vÄ lipsesc unele comenzi, duceÅ£i-vÄ Ã®n #springlobby Åi încercaÅ£i "
+"acolo :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Nu au fost scrise subiectele încÄ."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Subiectul \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+"\" nu a fost gÄsit. ÃncercaÅ£i \"/help topics\" numai pentru subiectele "
+"existente."
+
+#: src/ui.cpp:609
+#, fuzzy
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Nu pot gÄsi versiunea dvs. Spring din biblioteca UnitSync.\n"
+"\n"
+"Jocul online va fi dezactivat."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Jocul online va fi dezactivat."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "RÄspuns necunoscut de la server"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "Timp de conectare expirat"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "nu sunt deschise panouri chat active."
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d utilizatori)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Mesaj server"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "Lupta a fost închisÄ de gazdÄ."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "LuptÄ Ã®nchisÄ"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Este probabil cÄ setÄrile dvs. Spring nu sunt corecte.\n"
+"Ar trebui sÄ le verificaÅ£i înainte de a juca online."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Eroare setÄri Spring"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"S-a produs o eroare la verificarea versiunii.\n"
+"VÄ rugÄm încercaÅ£i din nou mai târziu.\n"
+"DacÄ problema persistÄ, vÄ rugÄm sÄ o raportaÅ£i folosind Ajutor -> Raportare "
+"problemÄ."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Versiunea dvs.: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Ultima versiune: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"Versiunea dvs. SpringLobby nu e actualizatÄ.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Neactualizat"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Neactualizat"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+#, fuzzy
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"S-a produs o eroare la verificarea versiunii.\n"
+"VÄ rugÄm încercaÅ£i din nou mai târziu.\n"
+"DacÄ problema persistÄ, vÄ rugÄm sÄ o raportaÅ£i folosind Ajutor -> Raportare "
+"problemÄ."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, fuzzy, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"S-a produs o eroare la verificarea versiunii.\n"
+"VÄ rugÄm încercaÅ£i din nou mai târziu.\n"
+"DacÄ problema persistÄ, vÄ rugÄm sÄ o raportaÅ£i folosind Ajutor -> Raportare "
+"problemÄ."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Niciunul"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Evidenţiere"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "IntrÄ Ã®n aceeaÅi luptÄ"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+#, fuzzy
+msgid "no action at all"
+msgstr "nu sunt deschise panouri chat active."
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Ãntotdeauna"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Porecla"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "Nou-venit"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "ÃncepÄtor"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "Mediu"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Deasupra mediei"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "Cu experienÅ£Ä"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "Cu multÄ experienÅ£Ä"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Veteran"
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "necunoscut"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "AdaugÄ Bot..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Återge cont utilizator"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "Austria"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Versiunea dvs. Spring"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "MB trimiÅi"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "PublicaÅ£i fiÅier nou"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "AnuleazÄ"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "Rezoluţie ecran"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Spectatori:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "JucÄtori:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "EchipÄ"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Aliat"
+
+#~ msgid "cpu"
+#~ msgstr "cpu"
+
+#~ msgid "Test firewall"
+#~ msgstr "Testare firewall"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat închis."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "OpÅ£iuni hartÄ"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "AleasÄ Ã®n joc"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "DescÄrcare completÄ"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "DeconecteazÄ"
+
+#~ msgid "Debug"
+#~ msgstr "Depanare"
+
+#~ msgid "Debug Options"
+#~ msgstr "Opţiuni depanare"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "JucÄtor:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Alegeţi un director"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Acţiune"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "j"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "%d%"
+#~ msgstr "%d"
+
+#~ msgid "t"
+#~ msgstr "e"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "Valoare în afara intervalului.\n"
+#~ " IntroduceÅ£i un întreg între 0 Åi 100."
+
+#~ msgid ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+#~ msgstr ""
+#~ "ExistÄ doi sau mai mulÅ£i boÅ£i în aceeaÅi echipÄ. Pentru cÄ boÅ£ii nu Åtiu "
+#~ "cum sÄ joace împreunÄ, aceasta nu va funcÅ£iona."
+
+#~ msgid "Bot team sharing."
+#~ msgstr "BoÅ£i în aceeaÅi echipÄ."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "NumÄrul jucÄtorilor"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Informaţii canal"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Subiectul \""
+
+#~ msgid "Use smart scrolling"
+#~ msgstr "FoloseÅte derulare inteligentÄ"
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Download failed"
+#~ msgstr "DescÄrcare eÅuatÄ"
+
+#~ msgid "Unit detail"
+#~ msgstr "Detaliile unitÄÅ£ilor"
+
+#~ msgid "only on/off available at this time"
+#~ msgstr "numai pornit/oprit disponibil acum"
+
+#~ msgid "Global sound volume"
+#~ msgstr "Volum de sunet global"
+
+#~ msgid "mark to be able to use"
+#~ msgstr "activeazÄ pentru a le putea folosi"
+
+#~ msgid "Send debug info to console"
+#~ msgstr "Trimite info pt. depanare la consolÄ"
+
+#~ msgid "if disabled these will only be logged"
+#~ msgstr "dacÄ e dezactivat, acestea vor fi trecute numai în jurnal"
+
+#~ msgid ""
+#~ "You're using a wxwidgets library of the 2.6.x series\n"
+#~ " battle filtering, advanced gui and joining/hosting games using nat "
+#~ "traversal\n"
+#~ " won't be available"
+#~ msgstr ""
+#~ "Folosiţi biblioteca wxWidgets versiunea 2.6.x.\n"
+#~ " Filtrarea luptelor, interfaÅ£a avansatÄ Åi jocurile cu traversare nat\n"
+#~ " nu vor fi disponibile."
+
+#~ msgid "Missing Functionality"
+#~ msgstr "LipseÅte funcÅ£ionalitate"
+
+#, fuzzy
+#~ msgid ""
+#~ "Do you want to download OTA content?\n"
+#~ "You need this to be able to play TA based mods.\n"
+#~ "You need to own a copy of Total Annihilation do legally download it."
+#~ msgstr ""
+#~ "DoriÅ£i sÄ descÄrcaÅ£i conÅ£inutul OTA?\n"
+#~ "Acesta este necesar pentru a juca modurile bazate pe TA.\n"
+#~ "AveÅ£i nevoie de o copie legalÄ a Total Annihilation pentru a-l obÅ£ine "
+#~ "legal."
+
+#~ msgid "Download OTA content?"
+#~ msgstr "Descarc conţinut OTA?"
+
+#, fuzzy
+#~ msgid "Create a spring directory in my documents folder"
+#~ msgstr "CreeazÄ un folder .spring în directorul home. (recomandat)"
+
+#, fuzzy
+#~ msgid "Do nothing"
+#~ msgstr "Hole punching"
+
+#~ msgid "Create a folder in a custom path (you'll get prompted for the path)"
+#~ msgstr "CreeazÄ un folder într-o altÄ cale (veÅ£i fi întrebat)"
+
+#~ msgid "I have already a SpringData folder, i want to browse manually for it"
+#~ msgstr "Am deja un folder SpringData, îl voi cÄuta manual"
+
+#, fuzzy
+#~ msgid ""
+#~ "Looks like you don't have yet a user SpringData folder structure\n"
+#~ "What would you like to do? (leave default choice if you don't know what "
+#~ "this is for)"
+#~ msgstr ""
+#~ "Se pare cÄ nu aveÅ£i o structurÄ de foldere SpringData.\n"
+#~ "Ce doriÅ£i sÄ fac? (lÄsaÅ£i varianta implicitÄ dacÄ nu ÅtiÅ£i pentru ce e "
+#~ "asta)"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "RÄspuns necunoscut de la server"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Nu este conectat."
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "AceastÄ luptÄ foloseÅte NAT traversal care nu este suportatÄ de build-ul "
+#~ "cu wx 2.6 SpringLobby.\n"
+#~ "\n"
+#~ "Nu veÅ£i putea juca în aceastÄ luptÄ. \n"
+#~ "ActualizaÅ£i-vÄ biblioteca wxWidgets la 2.8 sau mai nou pentru NAT "
+#~ "traversal."
+
+#, fuzzy
+#~ msgid "Only the host can change the game options"
+#~ msgstr "Doar gazda poate bloca lupta."
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "Doar gazda poate bloca lupta."
+
+#~ msgid "Only the host can lock the game."
+#~ msgstr "Doar gazda poate bloca lupta."
+
+#, fuzzy
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "Doar gazda poate bloca lupta."
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Nume de server sau server/port invalid."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "Canale de chat active:"
+
+#~ msgid "no rank"
+#~ msgstr "fÄrÄ rang"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "ListÄ de lupte"
+
+#~ msgid "Only the host can fix player colours."
+#~ msgstr "Doar gazda poate regla culorile."
+
+#~ msgid "Select all"
+#~ msgstr "SelecteazÄ tot"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d utilizatori)"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Nici un mod ales."
+
+#, fuzzy
+#~ msgid "you can also enter a ';' seperated list of usernames:"
+#~ msgstr "introduceÅ£i o listÄ separatÄ prin \";\""
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "NumÄr invalid"
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "O descriere scurtÄ a jocului, aceasta va apÄrea în lista de lupte."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "AlegeÅ£i mod-ul cu care sÄ jucaÅ£i."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normal"
+
+#~ msgid "NAT traversal to use. Experimental support."
+#~ msgstr "NAT traversal. Suport experimental."
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "ProblemÄ Unitsync"
+
+#~ msgid "You have one or more bots sharing team, this is not possible."
+#~ msgstr "Ai unul sau mai mulÅ£i boÅ£i în aceeaÅi echipÄ, nu pot porni."
+
+#~ msgid ""
+#~ "Please enter password needed to join this channel, leave blank for no "
+#~ "passwrd."
+#~ msgstr ""
+#~ "VÄ rog introduceÅ£i parola necesarÄ pentru a intra în acest canal; lÄsaÅ£i "
+#~ "liber dacÄ nu a fost nevoie."
+
+#~ msgid "Fixed source ports"
+#~ msgstr "Porturi sursÄ fixe"
+
+#~ msgid ""
+#~ "NAT traversal to use, currently this feature is not supported by "
+#~ "SpringLobby."
+#~ msgstr ""
+#~ "Modul de traversare a NAT-ului; funcÅ£ia nu este suportatÄ de SpringLobby."
+
+#~ msgid "&Edit"
+#~ msgstr "&Editare"
+
+#~ msgid "Failed to punch through NAT"
+#~ msgstr "EÅuare la NAT-punching"
+
+#~ msgid "no"
+#~ msgstr "nu"
+
+#~ msgid "yes"
+#~ msgstr "da"
+
+#~ msgid ""
+#~ "You should add a bot before starting a game.\n"
+#~ "If you don't want an opponent add TestGlobalAi"
+#~ msgstr ""
+#~ "Ar trebui sÄ adÄugaÅ£i un bot înainte de a începe un joc.\n"
+#~ "DacÄ nu doriÅ£i un oponent, adÄugaÅ£i TestGlobalAI."
+
+#~ msgid "/.spring"
+#~ msgstr "/.spring"
+
+#~ msgid "Start system"
+#~ msgstr "Ãnceput"
+
+#~ msgid "Stop system"
+#~ msgstr "OpreÅte sistem"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "ContinuÄ dacÄ commander-ul moare"
+
+#~ msgid "End if commander dies"
+#~ msgstr "TerminÄ dacÄ commander-ul moare"
+
+#~ msgid "End condition"
+#~ msgstr "CondiÅ£ie de sfârÅit"
+
+#~ msgid "Resources"
+#~ msgstr "Resurse"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Cantitatea de metal cu care fiecare jucÄtor începe"
+
+#~ msgid "Start Energy"
+#~ msgstr "Energie de început"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Cantitatea de energie cu care fiecare jucÄtor începe"
+
+#~ msgid "Max units"
+#~ msgstr "Maxim de unitÄÅ£i"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "NumÄrul maxim permis per jucÄtor"
+
+#~ msgid "Limit d-gun"
+#~ msgstr "LimiteazÄ D-Gun"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "ClÄdiri fantomatice"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "Reducerea producţiei metal maker"
+
+#~ msgid "This chat is exclusively for participants of this battle."
+#~ msgstr "Acest chat este exclusiv pentru participanţii acestei lupte."
+
+#~ msgid "Max players reached"
+#~ msgstr "NumÄrul maxim de jucÄtori a fost atins."
+
+#~ msgid "Save to:"
+#~ msgstr "SalveazÄ Ã®n:"
+
+#~ msgid "Browse..."
+#~ msgstr "CautÄ..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Alegeţi un director"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "OpÅ£iuni hartÄ/mod"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Versiunea dvs. de SpringLobby e actualÄ!\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "Actualizat"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "AÅ£i dori sÄ vizitaÅ£i o paginÄ cu instrucÅ£iuni cum sÄ descÄrcaÅ£i ultima "
+#~ "versiune?"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "LimiteazÄ D-Gun"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr ""
+#~ "DezactiveazÄ D-Gun-ul commander-ului la distanÅ£e prea mari de punctul de "
+#~ "pornire"
+
+#~ msgid "Ghosted Buildings"
+#~ msgstr "ClÄdiri fantomatice"
+
+#~ msgid ""
+#~ "Enemy buildings will leave a ghost image on the map after losing LoS on "
+#~ "them"
+#~ msgstr ""
+#~ "ClÄdirile inamice vor lÄsa o imagine fantomaticÄ pe hartÄ, dupÄ pierderea "
+#~ "contactului vizual."
+
+#~ msgid "Diminishing MM"
+#~ msgstr "ProdcÅ£ie redusÄ pt. Metal Maker-e"
+
+#~ msgid ""
+#~ "Efficiency of MetalMakers will progressively reduce as much as you build "
+#~ "them"
+#~ msgstr ""
+#~ "EficienÅ£a Metal Maker-elor va scÄdea progresiv pe mÄsurÄ ce construiÅ£i un "
+#~ "numÄr mai mare"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "CondiÅ£ia sfârÅirii jocului"
+
+#~ msgid ""
+#~ "The condition that will end the game\n"
+#~ "0: when all units will be destroyed\n"
+#~ "1: when the commander will be destroyed\n"
+#~ "2: lineage mode (see option 1, but given away units will still die"
+#~ msgstr ""
+#~ "CondiÅ£ia care va cauza sfârÅitul jocului\n"
+#~ "0: când toate unitÄÅ£ile sunt distruse\n"
+#~ "1: când commander-ul este distrus\n"
+#~ "2: mod \"lineage\" (vezi opÅ£. 1, dar Åi celelalte unitÄÅ£i vor fi distruse"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "SeteazÄ cantitatea de metal cu care se va începe"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "SeteazÄ cantitatea de energie cu care se va începe"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "Maxim de unitÄÅ£i permise"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr ""
+#~ "SeteazÄ numÄrul maxim de unitÄÅ£i pe care un jucÄtor are voie sÄ "
+#~ "construiascÄ"
+
+#~ msgid "Reset"
+#~ msgstr "ReseteazÄ"
+
+#~ msgid ""
+#~ "You have bots that are not assingled to startpositions. In the current "
+#~ "version of spring you are only allowed to use start positions positioning "
+#~ "them freely is not allowed.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "AveÅ£i boÅ£i care nu au poziÅ£ii iniÅ£iale. Ãn versiunea curentÄ Spring nu "
+#~ "aveÅ£i voie sÄ Ã®i poziÅ£ionaÅ£i manual, ci doar prin punctele de pe hartÄ.\n"
+#~ "\n"
+#~ "AceastÄ problemÄ va fi rezolvatÄ Ã®n urmÄtoarea versiune de Spring."
+
+#~ msgid ""
+#~ "You are not using consecutive start position numbers.\n"
+#~ "\n"
+#~ "In the current version of spring you are not allowed to skip any "
+#~ "startpositions. You have to use all consecutive position.\n"
+#~ "\n"
+#~ "Example: if you have 2 bots + yourself you have to use start positions "
+#~ "1,2,3 not 1,3,4 or 2,3,4.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "Nu folosiţi poziţii iniţiale consecutive.\n"
+#~ "\n"
+#~ "Ãn versiunea curentÄ de Spring, nu aveÅ£i voie sÄ sÄriÅ£i peste poziÅ£ii. "
+#~ "Trebuie sÄ folosiÅ£i toate poziÅ£iile marcate consecutiv.\n"
+#~ "\n"
+#~ "Exemplu: dacÄ aveÅ£i 2 boÅ£i + dvs. trebuie sÄ folosiÅ£i poziÅ£iile 1,2,3 Åi "
+#~ "nu 1,3,4 sau 2,3,4.\n"
+#~ "\n"
+#~ "AceastÄ problemÄ va fi rezolvatÄ Ã®n urmÄtoarea versiune de Spring."
+
+#~ msgid "Spring directory"
+#~ msgstr "Directorul Spring"
+
+#~ msgid "Default location."
+#~ msgstr "Locul implicit"
+
+#~ msgid "The Spring executable is installed in the default location"
+#~ msgstr "Executabilul Spring este instalat în locul implicit"
+
+#~ msgid "The UnitSync library is installed in the default location"
+#~ msgstr "Biblioteca UnitSync e instalatÄ Ã®n locul implicit"
+
+#~ msgid ""
+#~ "Unitsync loading was aborted because your spring data directory is not "
+#~ "writable. Please check."
+#~ msgstr ""
+#~ "ÃncÄrcarea Unitsync a fost anulatÄ deoarece directorul de date Spring nu "
+#~ "poate fi scris. VÄ rugÄm verificaÅ£i."
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "nu este suportat de serverul lobby care cere versiunea"
+
+#~ msgid ""
+#~ "This is the SpringLobby channel, please report any problems you are "
+#~ "having with SpringLobby here and the friendly developers will help you."
+#~ msgstr ""
+#~ "Acesta este canalul SpringLobby, vÄ rugÄm raportaÅ£i orice problemÄ aveÅ£i "
+#~ "cu SpringLobby aici Åi programatorii prietenoÅi vÄ vor ajuta."
diff --git a/po/ru.gmo b/po/ru.gmo
new file mode 100644
index 0000000..46eb423
Binary files /dev/null and b/po/ru.gmo differ
diff --git a/po/ru.po b/po/ru.po
new file mode 100644
index 0000000..e78d17d
--- /dev/null
+++ b/po/ru.po
@@ -0,0 +1,6688 @@
+# Russian translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-09-14 02:04+0000\n"
+"Last-Translator: Keldar <cryptbeast at gmail.com>\n"
+"Language-Team: Russian <ru at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "ÐобавиÑÑ Ð±Ð¾Ñа"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "ÐÑевдоним:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "ÐÐ:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "ÐÑбеÑиÑе ÐÐ Ð´Ð»Ñ ÑÑого боÑа."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "ÐнаÑение"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "ÐÑмена"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "ÐобавиÑÑ Ð±Ð¾Ñа"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Ðе бÑли Ð½Ð°Ð¹Ð´ÐµÐ½Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñеки ÐРв ÐаÑем Spring'е"
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Ðе Ð½Ð°Ð¹Ð´ÐµÐ½Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñеки ÐÐ"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "ÐÑинÑÑÑ Ð¡Ð¾Ð³Ð»Ð°Ñение"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "ÐÑ Ð¿ÑинимаеÑе ÑÑÐ»Ð¾Ð²Ð¸Ñ ÑÑого СоглаÑениÑ?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Ðа"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "ÐеÑ"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "ÐвÑомаÑиÑеÑки ÑаÑпÑеделиÑÑ Ð¸Ð³Ñоков по командам"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "ÐеÑод"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "РазделиÑÑ Ñанги ÑавномеÑно"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "СлÑÑайнÑе"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "ÐланÑ"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "ÐÑÑÑÑÑÑвÑеÑ"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "ЧеÑÑно"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "ÐÑегда"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"ÐбÑединÑÑÑ Ñленов одного клана (полÑзоваÑелей Ñ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ñми клан-ÑÑгами, "
+"напÑ. '[smurfzor]Alice' и '[smurfzor]Bob') в ÑоÑз.\n"
+"ÐеÑ: Ð½ÐµÑ Ð¾ÑобÑÑ
дейÑÑвий Ð´Ð»Ñ ÐºÐ»Ð°Ð½Ð¾Ð².\n"
+"РавномеÑно: обÑединÑÑÑ Ñленов клана в ÑоÑз, не наÑÑÑÐ°Ñ Ð±Ð°Ð»Ð°Ð½Ñа Ð¼ÐµÐ¶Ð´Ñ "
+"ÑоÑзами.\n"
+"ÐÑегда: вÑегда обÑединÑÑÑ Ñленов клана в ÑоÑз, даже, еÑли наÑÑÑиÑÑÑ Ð±Ð°Ð»Ð°Ð½Ñ."
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "ЧиÑло игÑоков"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "ÐвÑоÑоединение"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ðа"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "ÐпиÑание"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "ÐаÑÑа"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Ðод"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "СеÑвеÑ"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "ÐÑиÑели:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "ÐгÑоки:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "ÐаÑÑа"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "СкаÑаÑÑ &каÑÑÑ"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "СкаÑаÑÑ Ð¼&од"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "ÐÑиÑели:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "ÐгÑоки:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "СеÑвеÑ:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "СÑаÑÑÑ:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "ÐапеÑÑо"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "ÐÑжен паÑолÑ"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "ТолÑко подÑвеÑеное"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "ТÑебÑемÑй ÑÑовенÑ:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "ÐпиÑание:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "ÐапÑÑено"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "ÐолнÑй"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "ÐÑкÑÑÑо"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "ÐгÑок:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "ÐÑе"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "ÐаÑÑа:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "ТолÑко имеÑÑиеÑÑ Ñ Ð¼ÐµÐ½Ñ ÐºÐ°ÑÑÑ"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "ÐакÑ. колиÑеÑÑво игÑоков:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Ðод:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "ТолÑко имеÑÑиеÑÑ Ñ Ð¼ÐµÐ½Ñ Ð¼Ð¾Ð´Ñ"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " ÐÑиÑелÑ:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "ÐгÑоки:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr " ÐÑÑеивание "
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "ÐклÑÑено"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr " ÐнÑо. ÑÑажений "
+
+#: src/battlelisttab.cpp:152
+#, fuzzy
+msgid "0 battles displayed"
+msgstr "ÐоказаннÑе ÑайлÑ"
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "СоздаÑÑ Ð¸Ð³ÑÑ..."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "ÐойÑи"
+
+#: src/battlelisttab.cpp:182
+#, fuzzy, c-format
+msgid "%d battles displayed"
+msgstr "%u Ñайлов показано"
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"ÐÑ Ð½Ðµ можеÑе ÑоздаÑÑ Ð¸Ð³ÑÑ Ð±ÐµÐ· подлÑÑÐµÐ½Ð¸Ñ Ðº ÑеÑвеÑÑ. ÐожалÑйÑÑа подлÑÑиÑеÑÑ "
+"ÑнаÑала."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Ðе подлÑÑенÑ."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "ÐаÑа веÑÑÐ¸Ñ Ð¸Ð³ÑÑ Ð½Ðµ подÑ
одиÑ, и ÐÑ Ð½Ðµ можеÑе ÑоздаваÑÑ Ð¸Ð³ÑÑ."
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "ÐÑибка в Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Spring Ñже запÑÑен, пожалÑйÑÑа закÑойÑе его пеÑед Ñем как ÑоздаваÑÑ Ð½Ð¾Ð²ÑÑ "
+"игÑÑ"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Уже в игÑе"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"ÐÑ Ñже в ÑÑажении.\n"
+"\n"
+"ХоÑиÑе покинÑÑÑ ÑекÑÑее ÑÑажение и наÑаÑÑ Ð½Ð¾Ð²Ð¾Ðµ?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"ÐÑ Ð¸ÑполÑзÑеÑе веÑÑÐ¸Ñ wxWidgets Ñанее 2.8,\n"
+" ÑеÑÑиÑование поÑÑов не поддеÑживаеÑÑÑ.\n"
+" СеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ ÑабоÑаÑÑ."
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"СеÑвеÑ, иÑполÑзÑемÑй Ð´Ð»Ñ ÑеÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ ÐаÑего поÑÑа %d недоÑÑÑпен. \n"
+"СеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ ÑабоÑаÑÑ Ñ ÑÑой ÑÑÑановкой."
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"СÑажение не наÑаÑо, поÑÐ¾Ð¼Ñ ÑÑо вÑбÑаннÑй поÑÑ (%d) не Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑинимаÑÑ "
+"вÑ
одÑÑиÑ
даннÑÑ
.\n"
+"ÐÑовеÑÑÑе Ð²Ð°Ñ ÑоÑÑÐµÑ Ð¸Ð»Ð¸ ÑаиÑволл или поменÑйÑе поÑÑ Ð¿Ñи Ñоздании игÑÑ.\n"
+"\n"
+"ÐÑли ниÑего не помогаеÑ, вклÑÑиÑе Hole Punching NAT Traversal опÑÐ¸Ñ Ð¿Ñи "
+"Ñоздании игÑÑ."
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "УгÑа не могла бÑÑÑ Ð½Ð°ÑаÑой, поÑÐ¾Ð¼Ñ ÑÑо вÑбÑаннÑй мод небÑл найден. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "ÐÑибка пÑи наÑаÑии игÑÑ."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Ðе найдено каÑÑ Ð² ÐаÑем Spring'е. Ðозможно, пÑиÑина в невеÑной наÑÑÑойке "
+"Spring'а."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "ÐÐµÑ ÐºÐ°ÑÑ"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"Ðевозможен вÑ
од в ÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð·-за неÑовмеÑÑимоÑÑи ÐаÑей веÑÑии Spring'а."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Уже в игÑе"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"ÐÑ Ñже в ÑÑажении.\n"
+"\n"
+"ХоÑиÑе покинÑÑÑ ÑекÑÑее ÑÑажение и наÑаÑÑ Ð½Ð¾Ð²Ð¾Ðµ?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Уже в игÑе"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"ÐÑ Ñже в ÑÑажении.\n"
+"\n"
+"ХоÑиÑе вÑйÑи из ÑекÑÑего ÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¸ войÑи в ÑÑо?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+"Spring Ñже запÑÑен, Ñак ÑÑо ÑнаÑала закÑойÑе его пеÑед Ñем, как "
+"пÑиÑоединÑÑÑÑ Ðº дÑÑгим ÑÑажениÑм."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "ХоÑиÑе ли поÑеÑиÑÑ ÑÑÑаниÑÑ Ð·Ð°ÐºÐ°Ñек?"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+#, fuzzy
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+"ХоÑиÑе попÑобоваÑÑ ÑкаÑаÑÑ ÑÑо?\n"
+"ÐÑ Ð¼Ð¾Ð¶ÐµÑе ÑледиÑÑ Ð·Ð° пÑоÑеÑÑом на вкладке \"ÐакаÑки\"."
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+"ÐеобÑ
одимо ÑÑÑановиÑÑ Ð¼Ð¾Ð´ Ð´Ð»Ñ Ð²Ñ
ода в ÑÑÑ Ð¸Ð³ÑÑ.\n"
+"\n"
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Ðод не доÑÑÑпен"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+"ÐеобÑ
одимо ÑÑÑановиÑÑ ÐºÐ°ÑÑÑ Ð´Ð»Ñ Ð²Ñ
ода в ÑÑÑ Ð¸Ð³ÑÑ.\n"
+"\n"
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "ÐаÑÑа не доÑÑÑпна"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "ÐаÑÐ¾Ð»Ñ ÑÑажениÑ"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "ÐведиÑе паÑолÑ"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "ÐÑбÑаÑÑ..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "ÐаÑамеÑÑ"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "ÐнаÑение"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "РазмеÑ"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "СкоÑоÑÑÑ Ð²ÐµÑÑа"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "ÐÑÐ¸Ð»Ð¸Ð²Ð½Ð°Ñ Ñила"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "ÐÑавиÑаÑиÑ"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "РадиÑÑ ÑаÑ
ÑÑ"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "ÐакÑ. колиÑеÑÑво меÑалла"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "ФикÑиÑованнÑе"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "ÐÑÐ±Ð¾Ñ Ð² Ñамой игÑе"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "ÐÑÐ±Ð¾Ñ Ð² Ñамой игÑе"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "ÐаÑинаÑÑие позиÑии"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "ÐгÑаниÑÐµÐ½Ð¸Ñ Ð½Ð° войÑка"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "РазÑеÑеннÑе войÑка"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "ÐойÑка в ÑÑом ÑпиÑке бÑдÑÑ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð² игÑе."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "ÐÑклÑÑиÑÑ Ð²ÑбÑаннÑе войÑка."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "ÐклÑÑиÑÑ Ð·Ð°Ð½Ð¾Ð²Ð¾ вÑбÑаннÑе войÑка."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr "<<"
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "РазÑеÑиÑÑ Ð²Ñе войÑка."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "ÐапÑеÑÑннÑе войÑка"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "ÐойÑка в ÑÑом ÑпиÑке бÑдÑÑ Ð·Ð°Ð¿ÑеÑÐµÐ½Ñ Ð² игÑе."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "ÐгÑаниÑÐµÐ½Ð¸Ñ Ð½Ð° войÑка"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "ÐÑевдоним"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Ðоманда"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "СоÑзник"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "ÐонÑÑ ÑеÑÑÑÑов"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "СÑоÑона"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "ÐÑбÑаÑÑ ÑвеÑ"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "УÑÑановиÑÑ Ð±Ð¾Ð½ÑÑ Ð´Ð»Ñ ÑеÑÑÑÑов"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "ÐаблÑдаÑелÑ"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "ÐÑгнаÑÑ"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "ÐозвониÑÑ"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "ÐожалÑйÑÑа, введиÑе знаÑение Ð¼ÐµÐ¶Ð´Ñ 0 и 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "ÐобавиÑÑ Ð±Ð¾Ñа"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "Ðман"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "ÐаблÑдаÑелÑ"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "ÐгÑок:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "СеÑвеÑ"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "ÐлиенÑ"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "ÐÑегда"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Ðе гоÑов"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "ÐклÑÑиÑÑ Ð²ÐµÑÑ. ÑинÑ
Ñ."
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr "ÐведиÑе имÑ"
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+"ÐожалÑйÑÑа, введиÑе Ð¸Ð¼Ñ Ð½Ð¾Ð²Ð¾Ð¹ гÑÑппÑ.\n"
+"ÐоÑле нажаÑÐ¸Ñ \"Ðа\" Ðам надо бÑÐ´ÐµÑ Ð½Ð°ÑÑÑоиÑÑ."
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr "СоÑ
ÑанÑннÑе наÑÑÑойки"
+
+#: src/battleroommmoptionstab.cpp:58
+msgid "Set name."
+msgstr "УÑÑановиÑÑ Ð¸Ð¼Ñ."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "ÐагÑÑзка..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "ÐагÑÑзиÑÑ ÑоÑ
ÑанÑннÑе наÑÑÑойки."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "СоÑ
ÑаниÑÑ..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "СоÑ
ÑаниÑÑ Ð½Ð°ÑÑÑойки"
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "УдалиÑÑ..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "УдалиÑÑ Ð½Ð°ÑÑÑойки"
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "СделаÑÑ Ð¿Ð¾ ÑмолÑаниÑ..."
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr "ÐÑполÑзоваÑÑ ÑекÑÑие наÑÑÑойки, как по ÑмолÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ Ð¼Ð¾Ð´Ð°."
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "ÐаÑÑÑойки мода"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "ÐаÑÑÑойки каÑÑÑ"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "недоÑÑÑпно"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+#, fuzzy
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+"Ðевозможно ÑдалиÑÑ Ð½Ð°ÑÑÑойки без имени\n"
+"ÐожалÑйÑÑа, вÑбеÑиÑе наÑÑÑойки из ÑпиÑка и попÑобÑйÑе Ñнова."
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "оÑибка"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+#, fuzzy
+msgid "Enter preset name"
+msgstr "ÐведиÑе имÑ"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+#, fuzzy
+msgid "Cannot save an options set without a name."
+msgstr ""
+"Ðевозможно загÑÑзиÑÑ Ð½Ð°ÑÑÑойки без имени\n"
+"ÐожалÑйÑÑа, вÑбеÑиÑе наÑÑÑойки из ÑпиÑка и попÑобÑйÑе Ñнова."
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "УдалиÑÑ"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "СделаÑÑ Ð¿Ð¾ ÑмолÑаниÑ..."
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+"ÐгÑоки Ñ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ñм номеÑом ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¼Ð¾Ð³ÑÑ ÑпÑавлÑÑÑ Ñвоими войÑками "
+"ÑовмеÑÑно."
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+"ÐгÑоки Ñ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ñм номеÑом ÑоÑза ÑабоÑаÑÑ Ð´Ð»Ñ Ð´Ð¾ÑÑÐ¸Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð±ÐµÐ´Ñ ÑовмеÑÑно."
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "ÐÑбеÑиÑе ÑÐ²ÐµÑ ÐаÑиÑ
войÑк в игÑе"
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "ÐÑбеÑиÑе ÐаÑÑ ÑÑоÑонÑ"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "ÐаблÑдаÑÑ Ð·Ð° ÑÑажением, не ÑÑаÑÑвÑÑ"
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Я гоÑов"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "ÐажмиÑе, еÑли ÐÐ°Ñ ÑдовлеÑвоÑÑÑÑ ÑÑÐ»Ð¾Ð²Ð¸Ñ ÑÑажениÑ."
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "ЦвеÑ"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"ÐÑедпÑоÑмоÑÑ Ð²ÑбÑанной каÑÑÑ. ÐÑ Ð¼Ð¾Ð¶ÐµÑе ÑвидеÑÑ Ð½Ð°ÑалÑнÑе позиÑии или (еÑли "
+"вклÑÑено) или наÑалÑнÑе зонÑ."
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "ÐокинÑÑÑ"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "ÐокинÑÑÑ ÑÑажение и веÑнÑÑÑÑÑ Ðº ÑпиÑÐºÑ ÑÑажений"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "ÐаÑаÑÑ"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "ÐаÑаÑÑ ÑÑажение"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "ÐобавиÑÑ Ð±Ð¾Ñа..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "ÐобавиÑÑ Ð¸Ð³Ñока, ÑпÑавлÑемого компÑÑÑеÑом"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr "ÐапиÑаÑÑ Ð¿Ñи запÑÑке"
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr "ÐапиÑаÑÑ ÑÑажение, когда оно наÑаÑо, и оÑпиÑаÑÑ, когда законÑено."
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "ÐапÑеÑиÑÑ Ð½Ð¾Ð²Ñм игÑокам пÑиÑоединÑÑÑÑÑ Ðº ÑÑÐ¾Ð¼Ñ ÑÑажениÑ"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr "ÐвÑоÑеÑвеÑ"
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+"ÐклÑÑение Ñежима авÑоÑеÑвеÑа. ÐаÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ ÑпÑавлÑÑÑ ÑÑажением Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ "
+"команд '!balance' and '!start' и Ñ.д."
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "ÐвÑоÑоединение"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "ÐаÑаÑÑ"
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr "ÐапиÑаÑÑ ÑÑажение, когда оно наÑаÑо, и оÑпиÑаÑÑ, когда законÑено."
+
+#: src/battleroomtab.cpp:217
+#, fuzzy
+msgid "Lock Balance"
+msgstr "СоÑÐ·Ñ Ð¿Ð¾ÑовнÑ"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "ÐклÑÑиÑÑ Ð²ÐµÑÑ. ÑинÑ
Ñ."
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "ÐозвониÑÑ"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Ðе гоÑов"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "ÐаÑаÑÑ Ð¸Ð³ÑÑ Ð²ÑÑ Ñавно?"
+
+#: src/battleroomtab.cpp:239
+#, fuzzy
+msgid "Balance alliances"
+msgstr "ТолÑко ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ ÑÑавниваÑÑ ÑоÑзÑ."
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr "РазделиÑÑ Ð¸Ð³Ñоков на два или более ÑоÑза"
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "ÐÑпÑавиÑÑ ÑвеÑа"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "СделаÑÑ ÑвеÑа игÑоков ÑазнÑми"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid "Balance teams"
+msgstr "СоÑÐ·Ñ Ð¿Ð¾ÑовнÑ"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr "РазделиÑÑ Ð¸Ð³Ñоков на два или более ÑоÑза"
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr "ÐагÑÑзиÑÑ Ð½Ð°ÑÑÑойки ÑÑажениÑ"
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "СоÑ
ÑаниÑÑ..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "УдалиÑÑ"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "СделаÑÑ Ð¿Ð¾ ÑмолÑаниÑ..."
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "ÐонÑ"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr "ÐзÑÑÑ"
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "ÐÑодолжиÑÑ"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "ÐонеÑ"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr "ÐÐ¸Ð½Ð¸Ñ Ð¶Ð¸Ð·Ð½Ð¸"
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "ÐÐµÑ Ñакой каÑÑÑ."
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"ÐекоÑоÑÑе игÑоки еÑÑ Ð½Ðµ гоÑовÑ.\n"
+"ÐозвониÑÑ Ð¸Ð¼?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Ðе гоÑов"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "ÐÑÑло вÑÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ!"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "ÐаÑÑÑоиÑÑ ÐºÐ°Ð½Ð°Ð»Ñ Ð´Ð»Ñ Ð°Ð²ÑомаÑиÑеÑкого вÑ
ода"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+"ÐобвÑÑе канал в Ð»Ð¸Ð½Ð¸Ñ Ð²Ð¾Ñ Ñак:\n"
+"имÑканала паÑолÑ\n"
+"(паÑоли Ð´Ð»Ñ ÑÑÑеÑÑвÑÑÑиÑ
каналов не оÑобÑаженÑ)"
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr "Ðвойное нажаÑие Ð´Ð»Ñ Ð²Ñ
ода"
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "ÐайÑи канал:"
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "ÐÑбеÑиÑе канал Ð´Ð»Ñ Ð²Ñ
ода"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "канал"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d игÑоков)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr "Ðоказ %d вне %d каналов"
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### СеÑÑÐ¸Ñ Ð·Ð°ÐºÑÑÑа в ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Ðевозможно ÑоздаÑÑ Ð¿Ð°Ð¿ÐºÑ. \n"
+"УбедиÑеÑÑ, ÑÑо она не заÑиÑена Ð¾Ñ Ð·Ð°Ð¿Ð¸Ñи.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "ФÑнкÑÐ¸Ñ Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¶ÑÑнала оÑклÑÑена до пеÑезапÑÑка SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Уведомлнение"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"ÐÑибка запиÑи в жÑÑнал.\n"
+"ÐÑÑнал Ð´Ð»Ñ ÐºÐ¾Ð¼Ð½Ð°ÑÑ Ð±ÑÐ´ÐµÑ Ð¾ÑклÑÑен "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"ÐеÑезайдиÑе в комнаÑÑ Ð´Ð»Ñ Ð²ÐºÐ»ÑÑÐµÐ½Ð¸Ñ Ð¶ÑÑнала."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"ÐÑибка оÑкÑÑÑÐ¸Ñ Ñайла жÑÑнала. \n"
+"УбедиÑеÑÑ, ÑÑо он не заÑиÑен Ð¾Ñ Ð·Ð°Ð¿Ð¸Ñи.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "ЦвеÑа и ÑÑиÑÑ"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "ÐÑполÑзоваÑÑ ÑиÑÑемнÑе ÑвеÑа"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "ÐоÑмалÑнаÑ"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Фон"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "ÐейÑÑвие"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "ÐодÑвеÑка"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "ÐойÑи/УйÑи"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Ðои ÑообÑениÑ"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "СеÑвеÑ"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "ÐлиенÑ"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "ÐÑибка"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "ÐÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¼ÐµÑка"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "Уведомление"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Соединено Ñ TAS Server.\n"
+"[22:30] <Dude> ÐÑÐ¸Ð²ÐµÑ Ð²Ñем\n"
+"[22:30] ** Dude2 воÑÑл на канал.\n"
+"[22:30] * Dude2 дÑмаеÑ, его ÑÐ²ÐµÑ ÐºÐ»Ð°ÑÑно ÑмоÑÑиÑÑÑ\n"
+"[22:45] <Dude> Dude2: ÑÑ Ñак дÑмаеÑÑ?\n"
+"[22:46] <Dude2> ÐÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ бÑÑÑ Ð»ÑдÑе, надо измениÑÑ ÐµÐ³Ð¾ болÑÑе...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "ШÑиÑÑ:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "по ÑмолÑаниÑ"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "ÐÑбÑаÑÑ..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "Ðоведение"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr "ÐгÑаÑÑ Ð·Ð²Ñки Ñведомлений"
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "ÐÑÑÐ½Ð°Ð»Ñ ÑазговоÑов"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "СоÑ
ÑаниÑÑ Ð¶ÑÑÐ½Ð°Ð»Ñ ÑазговоÑов"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "ÐодÑвеÑиваÑÑ Ñлова"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Слова Ð´Ð»Ñ Ð¿Ð¾Ð´ÑвеÑки в ÑазговоÑе:"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "введиÑе ; ÑазделÑннÑй ÑпиÑок"
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr "ÐополниÑелÑно игÑаÑÑ Ð·Ð²Ñк/меÑÑаÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð¼"
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr "канал_"
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d игÑоков)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "пÑавое нажаÑие Ð´Ð»Ñ Ð½Ð°ÑÑÑоек (напÑ., авÑовÑ
од)"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "СказаÑÑ"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "ÐопиÑоваÑÑ"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "ÐÑиÑÑиÑÑ"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "ÐвÑомаÑиÑеÑки пÑиÑоединÑÑÑÑÑ Ðº каналÑ"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "ÐоказÑваÑÑ ÑообÑÐµÐ½Ð¸Ñ Ð¿ÑиÑ
ода/ÑÑ
ода"
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr "ÐоказаÑÑ ÑпиÑок молÑаниÑ"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "ÐнÑоÑмаÑÐ¸Ñ ÐºÐ°Ð½Ð°Ð»Ð°"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "ÐоÑÑавиÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "СообÑение каналÑ..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "ÐапеÑеÑÑ..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "ÐÑпеÑеÑÑ"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "ÐаÑегиÑÑÑиÑоваÑÑ..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "ÐÑмениÑÑ ÑегиÑÑÑаÑиÑ"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "Ðкл."
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "ÐÑкл."
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "ÐклÑÑено?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "ÐаÑиÑа Ð¾Ñ Ñпама"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "ÐÑÑоединиÑÑÑÑ"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "ÐеÑеÑоединиÑÑÑÑ"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "УдалиÑÑ..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "ÐзмениÑÑ Ð¿Ð°ÑолÑ..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "УÑÑановиÑÑ Ð´Ð¾ÑÑÑп..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "ÐккаÑнÑÑ"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "СказаÑÑ Ð²Ñем..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "ÐдминиÑÑÑаÑоÑ"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "ÐавÑÑавиÑÑ Ð¼Ð¾Ð»ÑаÑÑ Ð¿Ð¾Ð»Ñзов."
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "ÐÑкÑÑÑÑ ÑазговоÑ"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "ÐÑиÑоединиÑÑÑ Ðº ÑÐ¾Ð¼Ñ Ð¶Ðµ ÑÑажениÑ"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "ÐÑемÑ, пÑоведенное в игÑе"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "УзнаÑÑ IP адÑеÑа и не наÑÑоÑÑиÑ
новиÑков"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "ÐаÑÑавиÑÑ Ð¼Ð¾Ð»ÑаÑÑ..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "ÐолÑание на 5 минÑÑ"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "ÐолÑание на 10 минÑÑ"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "ÐолÑание на 30 минÑÑ"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "ÐолÑание на 2 ÑаÑа"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "ÐолÑание на 1 денÑ"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "СнÑÑÑ Ð¼Ð¾Ð»Ñание"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "ÐаÑÑавиÑÑ Ð¼Ð¾Ð»ÑаÑÑ"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "ÐÑгнаÑÑ..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "ÐапÑеÑиÑÑ..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "СнÑÑÑ Ð·Ð°Ð¿ÑеÑ"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "ШлÑпнÑÑÑ!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "ÐпеÑаÑоÑ"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "СнÑÑÑ Ð¾Ð¿ÐµÑаÑоÑа"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! Ðомманда: \""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "\" паÑамеÑÑÑ: \""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "канал"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "ÑÑажение"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "ÑеÑвеÑ"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " пÑиÑоединилÑÑ Ðº "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " ÑÑел из "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "ÐнÑоÑмаÑÐ¸Ñ ÐºÐ°Ð½Ð°Ð»Ð°"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * УÑÑановлено "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Ð Ð°Ð·Ð³Ð¾Ð²Ð¾Ñ Ð·Ð°ÐºÑÑÑ."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "ÐÑ ÑвеÑенÑ, ÑÑо Ñ
оÑиÑе вÑÑавиÑÑ %d ÑÑÑок?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "ÐÑедÑпÑеждение ÑлÑда"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " ÐÐ°Ñ SpringLobby веÑÑии v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " ÐÑ Ð½Ðµ в канале, или еÑÐ¾Ñ ÐºÐ°Ð½Ð°Ð» не ÑÑÑеÑÑвÑеÑ"
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+" ÐÑибка: Ðоманда (%s) не ÑÑÑеÑÑвÑеÑ, иÑполÑзÑйÑе /help Ð´Ð»Ñ Ð¾ÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ "
+"ÑпиÑка доÑÑÑпнÑÑ
команд."
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+" ÐÑ Ð½Ðµ в ÑÑажении, или Ñакого ÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ ÑÑÑеÑÑвÑеÑ, иÑполÑзÑиÑе /help ÑÑоб "
+"ÑвидеÑÑ ÑпиÑок возможнÑÑ
комманд"
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " ÐолÑзоваÑÐµÐ»Ñ Ð¾ÑклÑÑен."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " ÐоÑлано: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ÐÑибка ChanServ"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ не пÑиÑÑÑÑÑвÑÐµÑ Ð² ÑÑом канале."
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Ðакой должен бÑÑÑ Ð½Ð¾Ð²Ñй заголовок?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "СообÑение:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "ÐапеÑеÑÑ ÐºÐ°Ð½Ð°Ð»..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Ðакой новÑй паÑÐ¾Ð»Ñ Ð¿Ð¾ÑÑавиÑÑ?"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "ÐÑпеÑеÑÑ ÐºÐ°Ð½Ð°Ð»..."
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "ÐÑ ÑвеÑенÑ, ÑÑо Ñ
оÑиÑе оÑкÑÑÑÑ ÑÑÐ¾Ñ ÐºÐ°Ð½Ð°Ð»?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ не на ÑеÑвеÑе."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "ÐаÑегеÑÑÑиÑоваÑÑ ÐºÐ°Ð½Ð°Ð»"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "ÐÑо должен бÑÑÑ Ð¾ÑноваÑелем ÑÑого канала?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "ÐÑмена ÑегиÑÑÑаÑии канала"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "ÐÑ ÑвеÑенÑ, ÑÑо Ñ
оÑиÑе оÑмениÑÑ ÑегиÑÑÑаÑÐ¸Ñ ÑÑого канала?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "УдалиÑÑ ÑÑеÑнÑÑ Ð·Ð°Ð¿Ð¸ÑÑ"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "ÐакÑÑ ÑÑеÑнÑÑ Ð·Ð°Ð¿Ð¸ÑÑ ÐÑ Ñ
оÑиÑе ÑдалиÑÑ?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "УдалиÑÑ Ð°ÐºÐºÐ°ÑнÑ"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "ÐÑ ÑвеÑÐµÐ½Ñ Ð²Ñ Ñ
оÑиÑе ÑдалиÑÑ Ð°ÐºÐºÐ°ÑнÑ? "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "ÐзмениÑÑ Ð¿Ð°ÑолÑ"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "ÐаÑÐ¾Ð»Ñ ÐºÐ°ÐºÐ¾Ð¹ ÑÑеÑной запиÑи Ð²Ñ Ñ
оÑиÑе измениÑÑ?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Ðакой новÑй паÑолÑ?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Ðе Ñеализовано"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "СообÑение вÑем"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "СообÑение вÑем:"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "У ÐÐ°Ñ Ð½ÐµÑ Ð¼Ð¾Ð´Ð°"
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " . ÐожалÑйÑÑа, ÑÑÑановиÑе ÑнаÑала"
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr "Ðод не доÑÑÑпен"
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "СÑажение под паÑолем, введиÑе паÑолÑ:"
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "ÐавÑÑавиÑÑ Ð¼Ð¾Ð»ÑаÑÑ Ð¿Ð¾Ð»Ñзов."
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "Ðа ÑколÑко минÑÑ Ð½Ð°Ð´Ð¾ заÑÑавиÑÑ Ð¼Ð¾Ð»ÑаÑÑ Ð¿Ð¾Ð»Ñзов.?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "ÐÑгнаÑÑ Ð¿Ð¾Ð»Ñзов."
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "ÐÑиÑина:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "ÐÑгнаÑÑ Ð¿Ð¾Ð»Ñзов."
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "ÐаÑÑавиÑÑ Ð¼Ð¾Ð»ÑаÑÑ Ð¿Ð¾Ð»Ñзов."
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "ÐÑодолжиÑелÑноÑÑÑ:"
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr "невозможно добавиÑÑ Ð¿Ð¾Ð»Ñзов."
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "ÐодлÑÑиÑÑÑ Ðº ÑеÑвеÑÑ"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"ÐодклÑÑиÑÑÑÑ Ðº ÑеÑвеÑÑ. ÐÑ Ð¼Ð¾Ð¶ÐµÑе ввеÑÑи адÑеÑ:поÑÑ ÑеÑвеÑа к коÑоÑÐ¾Ð¼Ñ "
+"Ñ
оÑиÑе подклÑÑиÑÑÑÑ."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "ÐаÑолÑ"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "ÐапомниÑÑ Ð¿Ð°ÑолÑ"
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "ÐодклÑÑаÑÑÑÑ Ð°Ð²ÑомаÑиÑеÑки"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+"запомниÑÑ ÑÑÑановки подклÑÑÐµÐ½Ð¸Ñ Ð¸ подклÑÑиÑÑÑÑ Ðº ÑÑÐ¾Ð¼Ñ ÑеÑвеÑÑ Ð°Ð²ÑомаÑиÑеÑки "
+"пÑи ÑледÑÑÑей загÑÑзке лобби"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"ÐÑимеÑание: еÑли Ð²Ñ Ð½Ðµ заÑегеÑÑÑиÑованÑ, Ñо можеÑе\n"
+" заÑегеÑÑÑиÑоваÑÑÑÑ Ð±ÐµÑплаÑно на \n"
+"вкладке \"РегиÑÑÑаÑиÑ\"."
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "ÐойÑи"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "ÐаÑегиÑÑÑиÑоваÑÑÑÑ"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "ÐÑевдоним"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "ÐевеÑнÑй поÑÑ."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "ÐевеÑнÑй поÑÑ"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"ÐевеÑнÑй Ð½Ð¾Ð¼ÐµÑ Ð¿Ð¾ÑÑа.\n"
+"\n"
+"Ðн должен бÑÑÑ ÑелÑм ÑиÑлом Ð¼ÐµÐ¶Ð´Ñ 1 и 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "ÐевеÑнÑй адÑеÑ/поÑÑ."
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "ÐевеÑнÑй адÑеÑ"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+"ÐведÑннÑй пÑевдоним ÑодеÑÐ¶Ð¸Ñ Ð½ÐµÑазÑеÑÑннÑе ÑимволÑ: )? &%.\n"
+" ÐожалÑйÑÑа, попÑобÑйÑе Ñнова"
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "ÐепÑавилÑнÑй пÑевдоним"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"РегиÑÑÑаÑÐ¸Ñ Ð½Ðµ ÑдалаÑÑ, пÑиÑина:\n"
+"ÐаÑÐ¾Ð»Ñ / подÑвеÑждение не ÑовпадаÑÑ (или пÑÑÑой паÑолÑ)"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "ÐÑибка ÑегиÑÑÑаÑии."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " ÐндоÑÑа"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "ÐбÑединеннÑе ÐÑабÑкие ÐмиÑаÑÑ"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "ÐÑганиÑÑан"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "ÐнÑигÑа и ÐаÑбÑда"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "Ðнгила"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "ÐлбаниÑ"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "ÐÑмениÑ"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "ÐидеÑландÑкие ÐнÑиллÑ"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "Ðнгола"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "ÐнÑаÑкÑика"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "ÐÑгенÑина"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "ÐмеÑиканÑкое Самоа"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "ÐвÑÑÑиÑ"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "ÐвÑÑÑалиÑ"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "ÐÑÑба"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "ÐзеÑбайджан"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "ÐоÑÐ½Ð¸Ñ Ð¸ ÐеÑÑеговина"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "ÐаÑбадоÑ"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "ÐангладеÑ"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "ÐелÑгиÑ"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "ÐÑÑкина ФаÑо"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "ÐолгаÑиÑ"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "ÐаÑ
Ñейн"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "ÐÑÑÑнди"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "Ðенин"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "ÐеÑмÑдÑ"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "ÐÑÑней ÐаÑÑÑÑалам"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "ÐоливиÑ"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "ÐÑазилиÑ"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "ÐагамÑ"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "ÐÑÑан"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "ÐÑÑÑов ÐÑвеÑ"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "ÐоÑÑвана"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "ÐелоÑÑÑÑиÑ"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "Ðелизе"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "Ðанада"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "ÐÐ¾ÐºÐ¾Ñ (ÐÑÑÑова Ðеелинг)"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "ЦенÑÑалÑно-ÐÑÑиканÑÐºÐ°Ñ Ð ÐµÑпÑблика"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "Ðонго"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "ШвейÑаÑиÑ"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "ÐоÑ-д'ÐвÑÐ°Ñ (ÐеÑег Слоновой ÐоÑÑи)"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "ÐÑÑÑова ÐÑка"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "Чили"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "ÐамеÑÑн"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "ÐиÑай"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "ÐолÑмбиÑ"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "ÐоÑÑа Рика"
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "ÐÑба"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "Ðапе ÐеÑде"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "ÐÑÑÑов РождеÑÑва"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "ÐипÑ"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "ЧеÑÑÐºÐ°Ñ Ð ÐµÑпÑблика"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "ÐеÑманиÑ"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "ÐжибÑÑи"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "ÐаниÑ"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "Ðоминика"
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "ÐоминиканÑÐºÐ°Ñ Ð ÐµÑпÑблика"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "ÐлжиÑ"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "ÐквадоÑ"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "ÐÑÑониÑ"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "ÐгипеÑ"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "ÐÐ°Ð¿Ð°Ð´Ð½Ð°Ñ Ð¡Ð°Ñ
аÑа"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "ÐÑиÑÑеÑ"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "ÐÑпаниÑ"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "ÐÑиопиÑ"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "ФинлÑндиÑ"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "Фиджи"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "ФолклендÑкие оÑÑÑова (ÐалÑвинÑ)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "ÐикÑонезиÑ"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "ÐÑÑÑова ФаÑое"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "ФÑанÑиÑ"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "ФÑанÑиÑ, ÐеÑÑополиÑ"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "Ðабон"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "ÐÑенада"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "ÐÑÑзиÑ"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "ФÑанÑÑзÑÐºÐ°Ñ Ðвиана"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "Ðана"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "ÐибÑалÑаÑ"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "ÐÑенландиÑ"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "ÐамбиÑ"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "ÐвинеÑ"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "ÐваделÑпа"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "ÐкваÑоÑиалÑÐ½Ð°Ñ ÐвинеÑ"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "ÐÑеÑиÑ"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "ÐÑÑÑова Южной ÐÐµÐ¾Ð³Ð¸Ñ Ð¸ Южной СандвиÑ"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "ÐваÑемала"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "ÐÑам"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "ÐвинеÑ-ÐиÑÑаÑ"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "ÐÑÑна"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "Ðонконг"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "ÐÑÑÑова ХеÑд и ÐакдоналÑд"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "ÐондÑÑаÑ"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "ХоÑваÑиÑ"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "ÐаиÑи"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "ÐенгÑиÑ"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "ÐндонезиÑ"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "ÐÑландиÑ"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "ÐзÑаилÑ"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "ÐндиÑ"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "ÐÑиÑанÑÐºÐ°Ñ ÑеÑÑиÑоÑÐ¸Ñ Ð² ÐндийÑком океане"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "ÐÑак"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "ÐÑан"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "ÐÑландиÑ"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "ÐÑалиÑ"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "Ямайка"
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "ÐоÑданиÑ"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "ЯпониÑ"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "ÐениÑ"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "ÐÑÑгÑзÑÑан"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "Ðамбоджа"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "ÐиÑибаÑи"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "ÐомоÑÑкие оÑÑÑова"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "Сен-ÐиÑÑ Ð¸ ÐевиÑ"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "СевеÑÐ½Ð°Ñ ÐоÑеÑ"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "Ð®Ð¶Ð½Ð°Ñ ÐоÑеÑ"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "ÐÑвейÑ"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "ÐÑÑÑова Ðайман"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "ÐазаÑ
ÑÑан"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "ÐаоÑ"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "Ðебанон"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "СенÑ-ÐÑÑиÑ"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "ÐиÑ
ÑенÑнейн"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "ШÑи Ðанка"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "ÐибеÑиÑ"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "ÐеÑоÑо"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "ÐиÑва"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "ÐÑкÑембÑÑг"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "ÐаÑвиÑ"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "ÐивиÑ"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "ÐаÑокко"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "Ðонако"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "ÐолдавиÑ"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "ЧеÑногоÑиÑ"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "ÐадагаÑкаÑ"
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "ÐаÑÑÐ°Ð»Ð¾Ð²Ñ Ð¾-ва"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "ÐакедониÑ"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "Ðали"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "ÐÑÑнма (ÐиÑма)"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "ÐонголиÑ"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "Ðакао"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "СевеÑнÑе ÐаÑианÑкие ÐÑÑÑова"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "ÐаÑÑиника"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "ÐавÑиÑаниÑ"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "ÐонÑÑеÑÑаÑ"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "ÐалÑÑа"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "ÐавÑÑиÑиÑ"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "ÐалÑдивÑкие оÑÑÑова"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "Ðалави"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "ÐекÑика"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "ÐалайзиÑ"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "Ðозамбик"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "ÐамибиÑ"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "ÐÐ¾Ð²Ð°Ñ ÐаледониÑ"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "ÐигеÑ"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "ÐоÑÑолкÑкие оÑÑÑова"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "ÐигеÑиÑ"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "ÐикаÑагÑа"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "ÐидеÑландÑ"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "ÐоÑвегиÑ"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "Ðепал"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "ÐаÑÑÑ"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "ÐейÑалÑÐ½Ð°Ñ Ðона (СаÑди ÐÑабиÑ/ÐÑак)"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "ÐиÑ"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "ÐÐ¾Ð²Ð°Ñ ÐеландиÑ"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "Ðман"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "Ðанама"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "ÐеÑÑ"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "ФÑанÑÑзÑÐºÐ°Ñ ÐолинезиÑ"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "ÐапÑа ÐÐ¾Ð²Ð°Ñ ÐвинеÑ"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "ФилиппинÑ"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "ÐакиÑÑан"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "ÐолÑÑа"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "Сен-ÐÑÐµÑ Ð¸ Ðикелон"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "ÐиÑкаиÑн"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "ÐÑÑÑÑо Рико"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "ÐоÑÑÑгалиÑ"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "ÐалаÑ"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "ÐаÑагвай"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "ÐаÑаÑ"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "РеÑнÑон"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "Ð ÑмÑниÑ"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "СеÑбиÑ"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "РоÑÑийÑÐºÐ°Ñ Ð¤ÐµÐ´ÐµÑаÑиÑ"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "Ð Ñанда"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "СаÑдовÑÐºÐ°Ñ ÐÑавиÑ"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "Ð¡Ð¾Ð»Ð¾Ð¼Ð¾Ð½Ð¾Ð²Ñ Ð¾ÑÑÑова"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "СейÑелÑÑкие оÑÑÑова"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "СÑдан"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "ШвеÑиÑ"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "СингапÑÑ"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "ÐÑÑÑов СвÑÑой ÐленÑ"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "СловениÑ"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "ÐÑÑÑова СвалбаÑд и Ðан Ðаен"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "Ð¡Ð»Ð¾Ð²Ð°ÐºÐ¸Ñ (СловаÑÐºÐ°Ñ Ð ÐµÑпÑблика)"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "СÑеÑÑа-Ðеоне"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "Сан ÐаÑино"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "Сенегал"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "Сомали"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "СÑÑинам"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "Сен-Томе и ÐÑинÑипи"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "екÑ-СССР"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "ÐÐ»Ñ Ð¡Ð°Ð»ÑвадоÑ"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "СиÑиÑ"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "Свазиленд"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "ÐÑÑÑова ТеÑÐºÑ Ð¸ ÐайкоÑ"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "Чад"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "ФÑанÑÑзÑкие ЮжнÑе ТеÑÑиÑоÑии"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "Того"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "Таиланд"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "ТаджикиÑÑан"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "ТокелаÑ"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "ТÑÑкмениÑÑан"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "ТÑниÑ"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "Тонга"
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "ÐоÑÑоÑнÑй ТимоÑ"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "ТÑÑÑиÑ"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "ТÑинидад и Тобаго"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "ТÑвалÑ"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "ТайванÑ"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "ТанзаниÑ"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "УкÑаина"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "Уганда"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "ÐнглиÑ"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "ÐнеÑние земли СШÐ"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "СШÐ"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "УÑÑгвай"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "УзбекиÑÑан"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "ÐоÑÑдаÑÑÑво ÐаÑикан (ÐапÑкий ÐÑеÑÑол)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "СенÑ-ÐинÑÐµÐ½Ñ Ð¸ ÐÑенадинÑ"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "ÐенеÑÑÑла"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "ÐиÑгинÑкие оÑÑÑова (ÐеликобÑиÑаниÑ)"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "ÐиÑгинÑкие оÑÑÑова (СШÐ)"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "ÐÑеÑнам"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "ÐанÑаÑÑ"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "ÐÑÑÑова ÐÐ°Ð»Ð»Ð¸Ñ Ð¸ ФÑÑÑна"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "Самоа"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "Ðемен"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "ÐайоÑ"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "ЮгоÑлавиÑ"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "Ð®Ð¶Ð½Ð°Ñ ÐÑÑика"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "ÐамбиÑ"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "ÐаиÑ"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "Ðимбабве"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(ÐÐ¼Ñ ÑÑÑÐ°Ð½Ñ Ð½Ðµ найдено)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "ÐнÑоÑмаÑÐ¸Ñ Ð¾Ð± ÑиÑÑеме"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "УÑÐ¾Ð²ÐµÐ½Ñ ÑообÑений в жÑÑнале"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "ÐоÑледний ÑозданнÑй script Ð´Ð»Ñ Ð·Ð°Ð¿ÑÑка Spring'а"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "ÐмÑ"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr "Тип"
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr "ÑодеÑжание"
+
+#: src/filelister/filelistdialog.cpp:30
+#, fuzzy
+msgid "Search and download files"
+msgstr "ÐайÑи и ÑкаÑаÑÑ ÑайлÑ"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr "ÐоказаннÑе ÑайлÑ"
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "ÐакаÑка завеÑÑена"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr "%u Ñайлов показано"
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr "неизвеÑÑное ÑодеÑжимое"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "УдалиÑÑ"
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr "УдалиÑÑ Ð³ÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "ÐеÑеименоваÑÑ..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr "ÐеÑеименоваÑÑ Ð³ÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "ÐобавиÑÑ..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr "ÐобавиÑÑ Ð³ÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "ÐейÑÑÐ²Ð¸Ñ Ñ Ð³ÑÑппами"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr "Уведомление о вÑ
оде/вÑÑ
оде"
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr "УведомлÑÑÑ, когда полÑзоваÑели из гÑÑÐ¿Ð¿Ñ Ð¿ÑиÑ
одÑÑ Ð¸Ð»Ð¸ ÑÑ
одÑÑ"
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "ÐÑопÑÑкаÑÑ ÑазговоÑ"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr "ÐÑопÑÑкаÑÑ Ð²ÑÑ Ñказанное в канале полÑзоваÑелÑми из ÑÑой гÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "УведомлÑÑÑ Ð¾ Ñоздании ÑÑажений"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr "УведомлÑÑÑ, когда полÑзоваÑели ÑÑой гÑÑÐ¿Ð¿Ñ ÑоздаÑÑ ÑÑажениÑ"
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr "ÐÑопÑÑкаÑÑ Ð»Ð¸Ñное"
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+"ÐÑопÑÑкаÑÑ Ð²ÑÑ Ñказанное в лиÑном ÑазговоÑе полÑзоваÑелÑми из ÑÑой игÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr "УведомлÑÑÑ Ð¾ Ñмене ÑоÑÑоÑниÑ"
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr "УведомлÑÑÑ, когда ÑоÑÑоÑние полÑзоваÑелей из ÑÑой гÑÑÐ¿Ð¿Ñ Ð¼ÐµÐ½ÑеÑÑÑ"
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr "СÑÐ°Ð·Ñ Ð²ÑгнаÑÑ"
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr "СÑÐ°Ð·Ñ Ð²ÑгонÑÑÑ Ð²ÑеÑ
полÑзоваÑелей из ÑÑой гÑÑÐ¿Ð¿Ñ Ð¸Ð· ÑÑажений"
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr "ÐодÑвеÑиваÑÑ ÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¸ имена полÑзоваÑелей из ÑÑой гÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Ð¦Ð²ÐµÑ Ð¿Ð¾Ð´ÑвеÑки"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr "ÐÑбеÑиÑе ÑÐ²ÐµÑ Ð¿Ð¾Ð´ÑвеÑки"
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr "ÐолÑзоваÑели в гÑÑппе"
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "ÐобавиÑÑ..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr "ÐобавиÑÑ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ð² гÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "УдалиÑÑ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ð¸Ð· гÑÑппÑ"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "ÐÐ¼Ñ Ð½Ð¾Ð²Ð¾Ð¹ гÑÑппÑ:"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr "ÐобавиÑÑ Ð½Ð¾Ð²ÑÑ Ð³ÑÑппÑ"
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "УдалиÑÑ"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "ÐÑÐ±Ð¾Ñ Ð² Ñамой игÑе"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"ÑÑпеÑно ÑоÑ
Ñанено в:\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr "УÑпеÑно"
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "Ðевозможно ÑоÑ
ÑаниÑÑ\n"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "Ðо ÑмолÑаниÑ"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "ÐÐ¼Ñ ÐºÐ°Ð½Ð°Ð»Ð°"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+#, fuzzy
+msgid "Language"
+msgstr "ÐÐ¸Ð½Ð¸Ñ Ð¶Ð¸Ð·Ð½Ð¸"
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "СоздаÑÑ Ð½Ð¾Ð²Ð¾Ðµ ÑÑажение"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "ÐÑаÑкое опиÑание игÑÑ, коÑоÑое бÑÐ´ÐµÑ Ð¾ÑобÑажаÑÑÑÑ Ð² ÑпиÑке ÑÑажений."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "ÐпиÑание"
+
+#: src/hostbattledialog.cpp:83
+#, fuzzy
+msgid "Automatically write the battle description when a user joins."
+msgstr "ÐапиÑаÑÑ ÑÑажение, когда оно наÑаÑо, и оÑпиÑаÑÑ, когда законÑено."
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "ÐÑбеÑиÑе мод Ð´Ð»Ñ Ð¸Ð³ÑÑ."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr "ÐаÑолÑ, необÑ
одимÑй Ð´Ð»Ñ Ð²Ñ
ода. ÐÑÑавÑÑе пÑÑÑÑм, еÑли неÑ"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "ÐоÑÑ"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "UDP поÑÑ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð³ÑÑ. Ðо ÑмолÑÐ°Ð½Ð¸Ñ 8452."
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "недоÑÑÑпно"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "ЧиÑло игÑоков"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "ÐакÑималÑное ÑазÑеÑÑнно колиÑеÑÑво игÑоков в ÑÑажении."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "ÐÑобиÑÑ Ð´ÑÑÑ"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "NAT обÑ
од"
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr "ÐÑполÑзоваÑÑ NAT обÑ
од."
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "ÐинималÑнÑй ÑÑебÑемÑй ÑÑовенÑ"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "СоздаÑÑ ÐºÐ¾Ð¼Ð½Ð°ÑÑ ÑÑажениÑ"
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "СнаÑала вÑбеÑиÑе мод."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Ðе вÑбÑан мод."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"ÑÑпеÑно ÑоÑ
Ñанено в:\n"
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"ÑÑпеÑно ÑаÑпаковано в:\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+"\n"
+" оÑибка ÑаÑпаковки, пожалÑйÑÑа, иÑпÑавÑÑе вÑÑÑнÑÑ"
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr "Ðевозможно ÑоÑ
ÑаниÑÑ\n"
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"в:\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+"\n"
+"ÐÑибка номеÑ: "
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Ðеб бÑаÑзеÑ"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "ÐÑаÑÐ·ÐµÑ Ð¿Ð¾ ÑмолÑаниÑ"
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr "ÐÑп. ваÑи ÑиÑÑемнÑе наÑÑÑойки бÑаÑзеÑа"
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "ТоÑно"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr "ÐпÑеделиÑе ÑоÑно ÐÐ°Ñ Ð±ÑаÑÐ·ÐµÑ Ð´Ð»Ñ Ð¸ÑполÑзованиÑ"
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "ÐÑоÑмоÑÑеÑÑ"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr "ÐÑп. ÑайловÑй диалог Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка веб бÑаÑзеÑа"
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+#, fuzzy
+msgid "Path"
+msgstr "СмоÑÑеÑÑ"
+
+#: src/lobbyoptionstab.cpp:79
+#, fuzzy
+msgid "Use a file dialog to find the editor binary"
+msgstr "ÐÑп. ÑайловÑй диалог Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка веб бÑаÑзеÑа"
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "ÐвÑоÑоединение"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+"ÐÑли ÑÑÑановлено, SpringLobby бÑÐ´ÐµÑ ÑÑÐ°Ð·Ñ Ð·Ð°Ñ
одиÑÑ Ð½Ð° поÑледний "
+"иÑполÑзовавÑийÑÑ ÑеÑвеÑ"
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "ÐодлÑÑиÑÑÑ Ðº ÑеÑвеÑÑ"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr "СообÑиÑÑ ÑÑаÑиÑÑикÑ"
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+"Ðо ÑмолÑÐ°Ð½Ð¸Ñ SpringLobby бÑÐ´ÐµÑ ÑообÑаÑÑ Ð½ÐµÐºÐ¾ÑоÑÑÑ ÑÑаÑиÑÑÐ¸ÐºÑ (ÑиÑÑема, "
+"веÑÑÐ¸Ñ SpringLobby) на ÑеÑвеÑ,\n"
+"ÑÑÐ¾Ð±Ñ Ð¾Ð´Ð½Ð¾Ð²Ñеменно ÑделаÑÑ Ð¿Ð¾Ð¼Ð¾ÑÑ Ðам в ÑеÑении пÑоблем пÑоÑе и ÑообÑиÑÑ Ð¾ "
+"важнÑÑ
обновлениÑÑ
.\n"
+"УбеÑиÑе оÑмеÑÐºÑ Ð´Ð»Ñ Ð¾ÑклÑÑениÑ."
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr "ÑообÑиÑÑ ÑÑаÑиÑÑикÑ"
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr "ÐвÑомаÑиÑеÑкие обновлениÑ"
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+"SpringLobby пÑи запÑÑке Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑовеÑиÑÑ Ð´Ð¾ÑÑÑпноÑÑÑ Ð½Ð¾Ð²Ð¾Ð¹ веÑÑииd и "
+"авÑомаÑиÑеÑки ÑкаÑаÑÑ ÐµÐ³Ð¾ Ð´Ð»Ñ ÐаÑ."
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr "авÑомаÑиÑеÑки пÑовеÑиÑÑ Ð½Ð° обновлениÑ"
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "ÐодÑказки"
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr "ÐоказÑваÑÑ Ð¿Ð¾Ð´Ñказки?"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr "ÐеобÑ
одим пеÑезапÑÑк SpringLobby Ð´Ð»Ñ ÑабоÑÑ Ð½Ð°ÑÑÑоек."
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr "ÐавеÑÑение ÑеÑез Tab"
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+"\"ТоÑное Ñовпадение\" бÑÐ´ÐµÑ Ð·Ð°ÐºÐ°Ð½ÑиваÑÑ Ñлово, ÑолÑко еÑли Ð½ÐµÑ Ð²Ð°ÑианÑов.\n"
+"\"ÐÑиблизиÑелÑное Ñовпадение\" бÑÐ´ÐµÑ Ð²ÑбиÑаÑÑ Ð±Ð»Ð¸Ð¶Ð°Ð¹Ñее Ñовпадение"
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr "ТоÑное Ñовпадение"
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr "ÐÑиблизиÑелÑное Ñовпадение"
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "ÐаÑинаÑÑие колиÑеÑÑво меÑалла"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "ÐÑбÑаÑÑ Ð¸ÑполнÑемÑй Ñайл бÑаÑзеÑа"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "ÐÑбÑаÑÑ Ð¸ÑполнÑемÑй Ñайл бÑаÑзеÑа"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "ÐеизвеÑÑнÑй оÑÐ²ÐµÑ Ð¾Ñ ÑеÑвеÑа"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "СпиÑок ÑÑажений"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "ÐомнаÑа ÑÑажениÑ"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "ÐаÑÑÑойки"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "ÐгÑаниÑÐµÐ½Ð¸Ñ Ð½Ð° войÑка"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "P2P"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "РазговоÑ"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "Ðлавное"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr "ÐÑÑппÑ"
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "ÐоÑÑÑановиÑÑ"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "ÐÑимениÑÑ"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "ÐгÑа"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr "ÐеÑедаÑа: "
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "ÐÑего иÑÑ
одÑÑиÑ
: "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "ÐÑего вÑ
одÑÑиÑ
: "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "неизвеÑÑно"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "ÐÑмена загÑÑзки"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "РазмеÑÑиÑÑ Ñайл"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "ÐоиÑк Ñайла"
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "ÐклÑÑиÑÑ LuaUI ÑиÑки"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "недоÑÑÑпно"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "ÑаздаÑа"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr "полÑÑение"
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr "запÑоÑено"
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "СоÑÑоÑние: не подклÑÑен"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "СоÑÑоÑние: подклÑÑен"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr "СÑаÑÑÑ: на паÑзе (в игÑе)"
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "СÑаÑÑÑ: неизвеÑÑно"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "ÐÑÑ
одÑÑий вÑего: %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "ÐÑ
одÑÑиÑ
вÑего: %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Соединение"
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "&ÐÑÑоединение"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "&СоÑ
ÑаниÑÑ Ð½Ð°ÑÑÑойки"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&ÐÑйÑи"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "&ÐÑиÑоединиÑÑÑ..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "ÐнÑоÑмаÑÐ¸Ñ Ð¾ канале"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "ÐÑкÑÑÑ Ð»Ð¸ÑнÑй &ÑазговоÑ..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr "ÐвÑовÑ
од на каналÑ..."
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&ÐеÑезагÑÑзиÑÑ ÐºÐ°ÑÑÑ/модÑ"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "ÐайÑи новÑÑ Ð²ÐµÑÑÐ¸Ñ SpringLobby"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "ÐаÑÑÑойка Spring"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&РпÑогÑамме"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "ÐÐ¼Ñ ÐºÐ°Ð½Ð°Ð»Ð°"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&СообÑиÑÑ Ð¾Ð± оÑибке..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&ÐокÑменÑаÑиÑ"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&Файл"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&СеÑвиÑ"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&СпÑавка"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr "Ðам нÑжно пÑиÑоединиÑÑÑÑ Ðº ÑеÑвеÑÑ Ð´Ð»Ñ Ð¿ÑоÑмоÑÑа ÑпиÑка каналов"
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Ðе подклÑÑено"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "ÐÑиÑоединиÑÑÑ Ðº каналÑ..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "ÐÐ¼Ñ ÐºÐ°Ð½Ð°Ð»Ð° Ð´Ð»Ñ Ð¿ÑиÑоединениÑ"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "ÐаÑаÑÑ Ð»Ð¸ÑнÑй ÑазговоÑ..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "ÐÐ¼Ñ Ð¿Ð¾Ð»ÑзоваÑелÑ"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "ÐÐµÑ ÐºÐ°ÑÑ"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "&ÐапÑÑÑиÑÑ ÑиÑÑÐµÐ¼Ñ Ð¿Ð¾Ñоков (torrents)"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "&ÐÑÑановиÑÑ ÑиÑÑÐµÐ¼Ñ Ð¿Ð¾Ñоков (torrents)"
+
+#: src/mainwindow.cpp:638
+#, fuzzy
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr "ÐеобÑ
одим пеÑезапÑÑк SpringLobby Ð´Ð»Ñ ÑабоÑÑ Ð½Ð°ÑÑÑоек."
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+#, fuzzy
+msgid "Enter a profile name"
+msgstr "ÐведиÑе имÑ"
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "ÐакÑÑ ÑÑеÑнÑÑ Ð·Ð°Ð¿Ð¸ÑÑ ÐÑ Ñ
оÑиÑе ÑдалиÑÑ?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr "ÐногополÑзов. игÑа"
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr "ÐдиноÑÐ½Ð°Ñ Ð¸Ð³Ñа"
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "СоÑ
ÑаниÑÑ..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "ÐÑегда"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "СкаÑаÑÑ"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr "ÐеÑалл: %.1f%%"
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "ÐбновиÑÑ"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "СкаÑаÑÑ"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "ÑÑоÑона:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "ÑоÑз: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "бонÑÑ: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+#, fuzzy
+msgid "Show"
+msgstr "ÐоказаÑÑ Ð²ÑÑ"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr " ÐÑÑеивание "
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "ÐакÑ. колиÑеÑÑво меÑалла"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "ÐаÑинаÑÑие позиÑии"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "ÐинималÑнÑй ÑÑебÑемÑй ÑÑовенÑ"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "СÑедний"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "ÐаблÑдаÑелÑ"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "СлÑÑайнÑе ÑÑаÑÑовÑе позиÑии"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Тип ÑÑаÑÑовой позиÑии"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Ðак игÑоки бÑдÑÑ Ð²ÑбÑаÑÑ, где им наÑинаÑÑ ÑÑажение на каÑÑе\n"
+"0: обÑÑнÑе позиÑии\n"
+"1: ÑлÑÑайнÑе позиÑии\n"
+"2: вÑÐ±Ð¾Ñ Ð² игÑе\n"
+"3: вÑÐ±Ð¾Ñ Ð¿ÐµÑед ÑÑажением"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "ÐÑÐ±Ð¾Ñ Ð² Ñамой игÑе"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "ÐÑÐ±Ð¾Ñ Ð² Ñамой игÑе"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "СпиÑок огÑаниÑений на войÑка"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr "ÐÐ¼Ñ ÐºÐ°ÑÑÑ"
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "&СоÑ
ÑаниÑÑ Ð½Ð°ÑÑÑойки"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "Ñ"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "Ñ"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "Ñ"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "ÐÑполнÑемÑе (*.exe)|*.exe|ÐÑбой Ñайл (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "ÐÑбой Ñайл (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr "Ð£Ð·Ð»Ñ Ð¿ÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (*.app)|*.app|ÐÑбой Ñайл (*.*)|*.*"
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr "ÐаÑÑÑойки оÑÑеиваниÑ"
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr "Ð Ð°Ð·Ð¼ÐµÑ Ñайла в KB:"
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "ÐÑодолжиÑелÑноÑÑÑ (ÑÑ:мм:ÑÑ):"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "УдалиÑÑ"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Режим"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "ÐÐ¼Ñ ÐºÐ°ÑÑÑ"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "ÐÑодолжиÑелÑноÑÑÑ:"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "ÐеÑÑÐ¸Ñ Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "Ð Ð°Ð·Ð¼ÐµÑ Ñайла"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "Ð Ð°Ð·Ð¼ÐµÑ Ñайла в KB:"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "Файл"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr "СмоÑÑеÑÑ"
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "ÐагÑÑзка..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr "ÐбновиÑÑ ÑпиÑок"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "ÐÑегда"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "СоÑ
ÑаниÑÑ..."
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr "Ðевозможно пÑовеÑиÑÑ Ð²ÐµÑÑÐ¸Ñ Spring'а ÑеÑез unitsync библиоÑекÑ."
+
+#: src/playback/playbacktab.cpp:304
+#, fuzzy, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+"Ðе найдено ÑовмеÑÑимÑÑ
веÑÑий Spring'а, ÑÑÐ¾Ñ ÑеÑÐ²ÐµÑ ÑÑебÑÐµÑ Ð²ÐµÑÑиÑ: %s\n"
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr "ÐаÑи ÑекÑÑие веÑÑии:"
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+"Ðам необÑ
одимо имеÑÑ Ð¼Ð¾Ð´ Ð´Ð»Ñ Ð¿ÑоÑмоÑÑа ÑÑого повÑоÑа.\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "ÐевеÑнÑй поÑÑ"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr "Ðевозможно ÑдалиÑÑ Ð¿Ð¾Ð²ÑоÑ: "
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr "ÐÑÑеивание имÑн"
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr "ÐведиÑе ÑекÑÑ Ð´Ð»Ñ Ð¾ÑÑÐµÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ð»ÑзоваÑелей в ÑпиÑке"
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "ÐÑбеÑиÑе полÑзоваÑелей"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " в ÑеÑи"
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr " ÑейÑÐ°Ñ "
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() failed ! (exception)"
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " ÑолÑко ÑÑо ÑÑÑл"
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " пÑиÑоединилÑÑ Ðº "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "ÐеÑдаÑнÑй вÑ
од на канал"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Ðевозможно войÑи на канал"
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " ,поÑÐ¾Ð¼Ñ ÑÑо: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "СообÑение ÑеÑвеÑа"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " имел ip=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " не поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ NAT обÑ
од"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "ÐÐ°Ñ Ð²Ñгнали из ÑÑажениÑ!"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "ÐÑл вÑгнан ÑеÑвеÑом"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr "ÐаÑаÑÑ ÑпиÑок молÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ "
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "ÑпиÑок молÑаниÑ"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr " оÑÑалоÑÑ Ð½ÐµÐ¸Ð·Ð²ÐµÑÑно вÑемени"
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr " %d минÑÑ Ð¾ÑÑалоÑÑ"
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr "ÐавеÑÑиÑÑ ÑпиÑок молÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ "
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "ÐакаÑка завеÑÑена"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"ÐÑла оÑибка пÑи ÑкаÑивании поÑледней веÑÑии.\n"
+"ÐожалÑйÑÑа, попÑобÑйÑе Ñнова позже.\n"
+"ÐÑли пÑоблема повÑоÑиÑÑÑ, пожалÑйÑÑа, возполÑзÑйÑеÑÑ Ð¼ÐµÐ½Ñ ÐомоÑÑ->СообÑиÑÑ "
+"об оÑибке Ð´Ð»Ñ ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± ÑÑой оÑибке."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "Уведомление"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "ÐепÑавилÑное ÑиÑло"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "ÐÑо не ÑиÑло"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "ÐÐµÑ Ñакой каÑÑÑ."
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "ÐклÑÑено"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "ÐеÑеÑоединиÑÑÑÑ"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "неизвеÑÑно"
+
+#: src/serverevents.cpp:1009
+#, fuzzy
+msgid "Download complete, location is: "
+msgstr "ÐакаÑка завеÑÑена"
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "ÐакаÑка завеÑÑена"
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "Ðевозможно запÑÑÑиÑÑ Ð±ÑаÑзеÑ. URL адÑеÑ: "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "Ðевозможно запÑÑÑиÑÑ Ð±ÑаÑзеÑ"
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr "СкоÑоÑÑÑ ÐºÐ¾Ð»ÐµÑа мÑÑи"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+"ÐÑÑокие знаÑÐµÐ½Ð¸Ñ Ð¾Ð·Ð½Ð°ÑаÑÑ Ð±ÑÑÑÑое пÑиближение колеÑом мÑÑи.\n"
+"ÐÑÑиÑаÑелÑнÑе знаÑÐµÐ½Ð¸Ñ ÑазвоÑаÑиваÑÑ Ð½Ð°Ð¿Ñавление пÑиближениÑ.\n"
+"РезÑлÑÑÐ°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑенÑÑ Ð·Ð°Ð²Ð¸ÑеÑÑ Ð¾Ñ Ñежима камеÑÑ!"
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr "Ð Ð°Ð·Ð¼ÐµÑ ÐºÐ°ÑÑÑ Ñени"
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"вÑÑокое знаÑение = более ÑÑÑкие Ñени\n"
+"возможнÑе знаÑениÑ: 1024, 2048, 4096, 8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr "РаÑÑÑоÑние видимоÑÑи деÑевÑев"
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+"ÑÑÑановка макÑималÑного ÑаÑÑÑоÑниÑ, на коÑоÑом бÑдÑÑ Ð¾ÑÑаваÑÑÑÑ Ð²Ð¸Ð´Ð½Ñ Ð´ÐµÑевÑÑ"
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr "ÐеÑали повеÑÑ
ноÑÑи"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr "вÑÑе знаÑение = более ÑоÑÐ½Ð°Ñ Ð·ÐµÐ¼Ð»Ñ"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "Unit LOD distance"
+msgstr "РаÑÑÑоÑние знаÑков войÑк"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr "вÑÑе знаÑение = более ÑоÑнÑе войÑка"
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr "ÐеÑали ÑÑавÑ"
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "higher value = more detailed grass"
+msgstr "вÑÑе знаÑение = более ÑоÑÐ½Ð°Ñ ÑÑава"
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr "ÐеÑали земли"
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr "РаÑÑÑоÑние знаÑков войÑк"
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+"опÑеделÑÐµÑ Ð·Ð½Ð°Ñение, на коÑоÑом войÑка бÑдÑÑ Ð¿Ð¾Ð»Ð½Ð¾ÑÑÑÑ ÑиÑоваÑÑÑÑ\n"
+"вÑÑе знаÑение = болÑÑе ÑаÑÑÑоÑние = болÑÑе одновÑеменно наÑиÑованнÑÑ
войÑк"
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr "ÐакÑимÑм единовÑеменнÑÑ
ÑаÑÑиÑ"
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "опÑеделÑÐµÑ ÑколÑко ÑаÑÑÐ¸Ñ Ð±ÑÐ´ÐµÑ Ð¾ÑобÑажено в одно вÑемÑ"
+
+#: src/settings++/Defs.hpp:233
+#, fuzzy
+msgid "Max nano simultaneous particles"
+msgstr "ÐакÑимÑм единовÑеменнÑÑ
ÑаÑÑиÑ"
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr "ÐапÑÑк в полнÑй ÑкÑан"
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr "запÑÑкаÑÑ Ð² полнÑй ÑкÑан или в окне?"
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "Режим двÑÑ
ÑкÑанов"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "еÑли Ñ ÐÐ°Ñ ÐµÑÑÑ Ð´Ð²Ð° мониÑоÑа, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе иÑп. оба"
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "ÐклÑÑиÑÑ Ð²ÐµÑÑ. ÑинÑ
Ñ."
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr "ÐеÑÑикалÑÐ½Ð°Ñ ÑинÑ
ÑонизаÑÐ¸Ñ Ð²ÐºÐ»./вÑкл."
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr "16-bit Z-бÑÑеÑ"
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr "меÑка"
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr "24-bit Z-бÑÑеÑ"
+
+#: src/settings++/Defs.hpp:257
+#, fuzzy
+msgid "Full-scene anti-aliasing samples"
+msgstr "УÑовни anti-alieasing полного ÑкÑана"
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr "как много Ñаз anti-aliasing должен бÑÑÑ Ð½Ð°Ð»Ð¾Ð¶ÐµÐ½"
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr "ÐакÑимÑм единовÑеменнÑÑ
звÑков"
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "Master sound volume"
+msgstr "обÑÐ°Ñ Ð³ÑомкоÑÑÑ Ð·Ð²Ñка"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "master sound volume"
+msgstr "обÑÐ°Ñ Ð³ÑомкоÑÑÑ Ð·Ð²Ñка"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "General sound volume"
+msgstr "обÑÐ°Ñ Ð³ÑомкоÑÑÑ Ð·Ð²Ñка"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "general volume relative to master volume"
+msgstr "гÑомкоÑÑÑ Ð¾ÑвеÑа завиÑÐ¸Ñ Ð¾Ñ Ð¾Ð±Ñей гÑомкоÑÑи"
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr "ÐÑомкоÑÑÑ Ð¾ÑвеÑа войÑк"
+
+#: src/settings++/Defs.hpp:273
+#, fuzzy
+msgid "reply volume relative to master volume"
+msgstr "гÑомкоÑÑÑ Ð¾ÑвеÑа завиÑÐ¸Ñ Ð¾Ñ Ð¾Ð±Ñей гÑомкоÑÑи"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "ÐомнаÑа ÑÑажениÑ"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "battle volume relative to global volume"
+msgstr "гÑомкоÑÑÑ Ð¾ÑвеÑа завиÑÐ¸Ñ Ð¾Ñ Ð¾Ð±Ñей гÑомкоÑÑи"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "User interface volume"
+msgstr "ÐÑомкоÑÑÑ Ð¾ÑвеÑа войÑк"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "ui volume relative to global volume"
+msgstr "гÑомкоÑÑÑ Ð¾ÑвеÑа завиÑÐ¸Ñ Ð¾Ñ Ð¾Ð±Ñей гÑомкоÑÑи"
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "Тени"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr "вклÑÑиÑÑ Ñени? (Ð¼Ð¾Ð¶ÐµÑ ÑменÑÑиÑÑ Ð¿ÑоизводиÑелÑноÑÑÑ)"
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr "3D деÑевÑÑ"
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+"Ñ
оÑеÑÑ Ð±Ð¾Ð»ÐµÐµ кÑаÑивÑе деÑевÑÑ?\n"
+"надо Geforce 2/Radeon 8500/Intel 830 или видеокаÑÑа более позднего клаÑÑа"
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr "Ðблака Ñ Ð²ÑÑоким ÑазÑеÑением"
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"Ñ
оÑеÑÑ Ð±Ð¾Ð»ÐµÐµ кÑаÑивое небо?\n"
+"надо Geforce 5/Radeon 9500/Intel 915 или видеокаÑÑа более позднего клаÑÑа"
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr "ÐвижÑÑиеÑÑ Ð¾Ð±Ð»Ð°ÐºÐ°"
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr "Ñ
оÑеÑÑ Ð´Ð²Ð¸Ð¶ÑÑиеÑÑ Ð¾Ð±Ð»Ð°ÐºÐ° в небе"
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr "ÐлеÑÑÑÑие войÑка"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"войÑка блеÑÑÑÑ?\n"
+"надо Geforce 5/Radeon 9500/Intel 915 или видеокаÑÑа более позднего клаÑÑа"
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr "Ðе иÑполÑзоваÑÑ ÐÐТ (shaders) на каÑÑаÑ
SM3"
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr "пÑÐ¾Ð±Ð»ÐµÐ¼Ñ Ñ ÐºÐ°ÑÑами sm3? вклÑÑиÑе ÑÑо"
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr "ÐклÑÑиÑÑ Ð¿Ð¾Ð´Ð´ÐµÑÐ¶ÐºÑ LuaShaders"
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr "Ð´Ð»Ñ Ð½ÐµÐºÐ¾ÑоÑÑÑ
клаÑÑнÑÑ
ÑÑÑекÑов"
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr "ÐÑп. Pixelbuffer objects"
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+"ÐÑли еÑÑÑ Ð¿Ð¾Ð´Ð´ÐµÑжка ÑÑого, Ñо ÑÑкоÑиÑÑÑ Ð·Ð°Ð³ÑÑзка изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð²ÐµÑÑ
ноÑÑи -> "
+"более гладкое движение камеÑÑ"
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr "СжаÑие ÑекÑÑÑÑ"
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+"СжаÑие ÑекÑÑÑÑ Ð² пÑоÑеÑÑе. (ÐдеалÑно Ð´Ð»Ñ Ð²Ð¸Ð´ÐµÐ¾ÐºÐ°ÑÑ Ñ Ð¼Ð°Ð»ÐµÐ½Ñким ÑазмеÑом "
+"виÑÑÑалÑной памÑÑи)"
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr "ÐÑÑокое ÑазÑеÑение LOS"
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr "более Ð³Ð»Ð°Ð´ÐºÐ°Ñ Line of Sight (Ð»Ð¸Ð½Ð¸Ñ Ð²Ð¸Ð´Ð¸Ð¼Ð¾ÑÑи)"
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr "Ðладкие ÑоÑки"
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr "пÑименÑÑÑ Ð»Ð¸ на ÑоÑки anti-aliasing"
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr "Ðладкие линии"
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr "пÑименÑÑÑ Ð»Ð¸ на линии anti-aliasing"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr "ÐбознаÑаÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° миникаÑÑе"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr "ÐбознаÑение пÑиказов на миникаÑÑе, еÑли Ñ
оÑиÑе"
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "ÐоказÑваÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° миникаÑÑе"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr "наÑалÑное знаÑение \"вкл.\""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr "ÐÑобÑажаÑÑ Ð·Ð½Ð°Ñки на миникаÑÑе"
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr "ÐÑобÑажаÑÑ Ð¿Ð¾Ð¼ÐµÑки на миникаÑÑе"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr "ÐиникаÑÑа Ñлева (один мониÑоÑ)"
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "Ñлева, по-обÑÑномÑ"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr "ÐиникаÑÑа Ñлева (два мониÑоÑа)"
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr "ÐÑоÑÑÑе ÑвеÑа на миникаÑÑе"
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "ÐÑполÑзоваÑÑ Ð¼ÐµÐ½ÑÑе ÑвеÑа"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr "ЦвеÑной наноÑпÑей"
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr "ÐкÑаÑиваÑÑ Ð»Ð¸ нано ÑаÑÑиÑÑ Ð² ÑÐ²ÐµÑ ÐаÑей командÑ?"
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr "ЦвеÑÐ½Ð°Ñ ÐºÐ°ÑÑа вÑÑоÑ"
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr "Ð´ÐµÐ»Ð°ÐµÑ ÑазлиÑÐ¸Ñ Ð² вÑÑоÑаÑ
ÑÑÑÑе"
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "ÐоказÑваÑÑ ÑаÑÑ Ð² игÑе"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+"ÑÑебÑÐµÑ \"ÐклÑÑиÑÑ LuaWidgets\"\n"
+"ÐÑдÑÑ Ð¿Ð¾ÐºÐ°Ð·ÑваÑÑÑÑ Ð²Ð½Ð¸Ð·Ñ ÑпÑава"
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr "ÐоказÑваÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¸Ð³Ñока в игÑе"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr "ÐоказÑваÑÑ FPS в игÑе"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr "ÐÑпÑавлÑÑÑ Ð¾ÑÑиÑÐ¾Ð²ÐºÑ Ð¿Ñи Alt+Tab"
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr "Ðе изменÑйÑе, еÑли ненÑжно"
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr "ÐапÑеÑиÑÑ Ð¿Ð¾Ð¼Ð¾Ñников"
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+"ÐÑклÑÑение, напÑимеÑ, Economy AI.\n"
+"ÐÑли вклÑÑено, Ð¼Ð¾Ð¶ÐµÑ Ð¾Ð±ÑезаÑÑÑÑ LuaUI."
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr "ÐклÑÑиÑÑ ÑмеÑение камеÑÑ Ð¿Ð¾ кÑÐ°Ñ ÑкÑана"
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr "ÐвигаÑÑ ÐºÐ°Ð¼ÐµÑÑ, пÑи доÑÑижении мÑÑкой кÑÐ°Ñ ÑкÑана."
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr "РазвеÑнÑÑÑ Ð¼ÑÑÑ"
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "РазвоÑаÑÐ¸Ð²Ð°ÐµÑ Y-оÑÑ Ð² Ñежиме FPS"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr "ÐÑп. ÑиÑÑемнÑй ÑказаÑелÑ"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr "ÐÑполÑзоваÑÑ ÑказаÑÐµÐ»Ñ Ð¼ÑÑи из ÐС (аппаÑаÑно ÑÑкоÑено)"
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr "ÐамеÑа над головой"
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "ÑÑÑановиÑÑ ÑкоÑоÑÑÑ Ð¿ÑокÑÑÑки (мÑÑÑ + клавиаÑÑÑа) Ð´Ð»Ñ ÑÑого Ñежима"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr "ÐÑаÑÐ°ÐµÐ¼Ð°Ñ ÐºÐ°Ð¼ÐµÑа"
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr "ÐамеÑа обÑего вида"
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr "ÐамеÑа Ð¾Ñ Ð¿ÐµÑвого лиÑа"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr "Ð¡Ð²Ð¾Ð±Ð¾Ð´Ð½Ð°Ñ ÐºÐ°Ð¼ÐµÑа"
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+"СделаÑÑ ÑÑÐ¾Ñ Ñежим по ÑмолÑÐ°Ð½Ð¸Ñ Ð¿Ñи запÑÑке Spring'а.\n"
+"ÐÐ¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¾ в игÑе."
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr "УÑÐ¾Ð²ÐµÐ½Ñ ÑообÑений (0=мин,10=макÑ)"
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr "Ðак много инÑоÑмаÑии должно бÑÑÑ Ð²Ñведено?"
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr "ÐÑлавливаÑÑ ÐРиÑклÑÑениÑ"
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr "оÑклÑÑиÑе Ð´Ð»Ñ Ð¾Ñладки ÐÐ"
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "ÐÑновное"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+"РзавиÑимоÑÑи Ð¾Ñ Ð¼Ð¾ÑноÑÑи ÐаÑей видеокаÑÑÑ,\n"
+"вÑÐ±Ð¾Ñ Ð±Ð¾Ð»ÐµÐµ вÑÑокого каÑеÑÑва, Ñем оÑновное можеÑ\n"
+"оÑноваÑелÑно повлиÑÑÑ Ð½Ð° пÑоизводиÑелÑноÑÑÑ Spring'а.\n"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr "ÐлеÑÑÑÑий"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "ÐлеÑк + пÑеломление"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "Ðвижение"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr "Bump-mapped"
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr "РазвеÑнÑÑÑ y-оÑÑ Ð¼ÑÑи"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr "менÑÐµÑ Ð²ÐµÑÑ
/низ на низ/веÑÑ
"
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr "ÐоддеÑжка 3Ñ
кнопоÑной мÑÑи в миникаÑÑе"
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr "еÑли Ð²Ñ Ð½Ðµ Ñ
оÑиÑе иÑполÑзоваÑÑ ÑÑÑ ÐºÐ½Ð¾Ð¿ÐºÑ, Ñо оÑклÑÑиÑе ÑÑо"
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr "Ðад головой"
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr "ÐоÑÑоÑннÑй вид из глаза пÑиÑÑ"
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr "ÐÑаÑаемÑй вид"
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr "Тоже ÑÑо и над головой, но ÐÑ Ð¼Ð¾Ð¶ÐµÑе вÑаÑаÑÑÑ Ð¿Ð¾ z-оÑи"
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr "ÐбÑий вид"
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr "камеÑа ÑвеÑÑ
Ñ, коÑоÑÐ°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑазвÑÑнÑÑа по X оÑи"
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "ÐÑ Ð¿ÐµÑвого лиÑа"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr "ÐамеÑа Ñ Ð¿Ð¾Ð·Ð¸Ñии взглÑда войÑк"
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr "ÐенÑйÑе вид как Ðам заÑ
оÑеÑÑÑ"
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "ÑиÑина ÑкÑана"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "вÑÑоÑа ÑкÑана"
+
+#: src/settings++/Defs.hpp:413
+msgid "Blur reflection"
+msgstr "ÐÑÑноÑÑÑ"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr "ÐÑп. глÑÐ±Ð¸Ð½Ñ ÐºÐ°ÑÑинок"
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr "вклÑÑÐ°ÐµÑ Ð±Ð¾Ð»ÐµÐµ гладкое ÑазмÑÑие на линии беÑега"
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr "ÐÑибÑежнÑе волнÑ"
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr "ÐклÑÑиÑÑ Ð¿ÑибÑежнÑе волнÑ"
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "ÐлеÑк"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr "ÐклÑÑÐ°ÐµÑ Ð¾ÑÑажение на воде"
+
+#: src/settings++/Defs.hpp:418
+msgid "Reflection texture size"
+msgstr "Ð Ð°Ð·Ð¼ÐµÑ ÐºÐ°ÑÑинки оÑÑажений"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "ÐÑеломление"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+"ÐклÑÑÐ°ÐµÑ Ð¿Ñеломление на воде.\n"
+"(0:=вÑкл., 1:=ÐºÐ¾Ð¿Ð¸Ñ ÑкÑана(бÑÑÑÑо), 2:=ÑобÑÑÐ²ÐµÐ½Ð½Ð°Ñ Ð¾ÑÑиÑовка(медленно))."
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr "Anisotropy"
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "вÑкл."
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr "ÐºÐ¾Ð¿Ð¸Ñ ÑкÑана(бÑÑÑÑо)"
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr "ÑобÑÑÐ²ÐµÐ½Ð½Ð°Ñ Ð¾ÑÑиÑовка(медленно)"
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr "128"
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr "256"
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr "512"
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "ÐбÑие наÑÑÑойки"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "ÐаÑеÑÑво оÑÑиÑовки / Режим видео"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "ÐеÑалÑноÑÑÑ Ð¾ÑÑиÑовки"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "UI наÑÑÑойки"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "ÐвÑк"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+"ÐзменениÑ, ÑделаннÑе на вкладке ÐаÑеÑÑво/ÐеÑали в Ñежиме ÑкÑпеÑÑа\n"
+" бÑдÑÑ Ð¿Ð¾ÑеÑÑнÑ, еÑли ÐÑ Ð¿Ð¾Ð¼ÐµÐ½ÑеÑе пÑоÑÑÑе наÑÑÑойки опÑÑÑ.\n"
+"Также ÑÑи Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÐÐ ÐУÐУТ оÑÑÐ°Ð¶ÐµÐ½Ñ Ð² \n"
+"вÑбÑаннÑÑ
наÑÑÑойка на вкладке ÐбÑие наÑÑÑойки.\n"
+"(ÑÑо ÑообÑение Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¾ÑклÑÑено в Ð¼ÐµÐ½Ñ \"Файл\")"
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "ÐÑибка!"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "СоÑ
ÑаниÑÑ Ð½Ð°ÑÑÑойки Spring'а пеÑед вÑÑ
одом?"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "ÐеобÑ
одимо подÑвеÑждение"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "ÐаÑÑÑойки Spring'а (Ñежим ÑкÑпеÑÑа)"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "ÐаÑÑÑойки Spring'а (пÑоÑÑой Ñежим)"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "СозÑаниÑÑ Ð½Ð°ÑÑÑойки"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "СбÑоÑиÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð½Ð°ÑÑÑоек"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "ÐÑклÑÑиÑÑ Ð¿ÑедÑпÑеждение Ñежима ÑкÑпеÑÑа"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "ÐÑÑ
од"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "ÐÑоÑÑо (мало опÑий)"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "ÐкÑпеÑÑ (вÑе опÑии"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "РпÑогÑамме"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "СвÑзÑ"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "ÐвÑоÑÑ"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "СообÑиÑÑ Ð¾Ð± оÑибке"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "Режим"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "ÐнÑо/ÐомоÑÑ"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "СбÑоÑиÑÑ Ð²Ñе наÑÑÑойки?"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "ÐодÑказка"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr "SpringSettings гÑаÑиÑеÑкое пÑиложение Ð´Ð»Ñ Ð½Ð°ÑÑÑоек движка Spring"
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr "Kloot"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "Ðоманда SpringLobby"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr "ÑпаÑибо за пÑиглаÑение, иÑполÑзование кода, помоÑÑ Ð² Ñелом"
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr "вÑе ÑообÑÐ°Ñ Ð¾Ñибки/пÑедложениÑ"
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+"ÐÑиложение ÑообÑило о главной оÑибке и бÑÐ´ÐµÑ Ð·Ð°Ð²ÐµÑÑено\n"
+"Создание ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± оÑибке невозможно\n"
+"\n"
+"пожалÑйÑÑа, вклÑÑиÑе wxUSE_DEBUGREPORT"
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "ÐÐ»Ð°Ð²Ð½Ð°Ñ Ð¾Ñибка"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "ÐÑÑÑ Ðº библиоÑеке unitsync"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+"ÐÑибка в ÐаÑиÑ
наÑÑÑойкаÑ
.\n"
+"ÐожалÑйÑÑа, пÑовеÑÑÑе пÑÑÑ Ð½Ð° пÑавилÑноÑÑÑ.\n"
+"ÐоÑле иÑпÑавление, нажмиÑе\n"
+"\"ÐÑп. ÑÑÐ¾Ñ Ð¿ÑÑÑ\" ÐºÐ½Ð¾Ð¿ÐºÑ Ð¸ попÑобÑйÑе Ñнова."
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "ÐÑп. ÑÑÐ¾Ñ Ð¿ÑÑÑ"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "unitsync.so в linux, unitsync.dll в windows"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "ÐаÑÑÑойка пÑÑи"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "ÐÑбеÑиÑе библиоÑÐµÐºÑ unitsync"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "ÐÑбой Ñайл"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+"SpringSettings не Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð³ÑÑзиÑÑ ÐаÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾ÑÐµÐºÑ unitsync.\n"
+"Ðам можеÑе взглÑнÑÑÑ Ð½Ð° наÑÑÑойки.\n"
+"ÐеÑÑÐ¸Ñ ÐаÑего Spring'а должна бÑÑÑ 0.76 или новее, инаÑе \n"
+"ÑÑо бÑÐ´ÐµÑ ÑлÑÑаÑÑÑÑ Ð²Ñегда."
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "низко"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "ÑÑедне"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "вÑÑоко"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "оÑÐµÐ½Ñ Ð½Ð¸Ð·ÐºÐ¾"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "оÑÐµÐ½Ñ Ð²ÑÑоко"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "невозможно запÑÑÑиÑÑ ÑÑандаÑÑнÑй бÑаÑзеÑ"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "Ðевозможно запÑÑÑиÑÑ Ð±ÑаÑзеÑ. URL адÑеÑ: "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "Ðевозможно запÑÑÑиÑÑ Ð±ÑаÑзеÑ"
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "Ðевозможно полÑÑиÑÑ Ð´Ð¾ÑÑÑп к ÐаÑим наÑÑÑойкам.\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "Ðевозможно ÑоÑ
ÑаниÑÑ, Ñ.к. unitsync не загÑÑжен"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "ÐÑибка наÑÑÑоек Spring'а"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "ÐаÑÑÑойки звÑка"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "РазÑеÑение ÑкÑана"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "ÐаÑеÑÑво водÑ"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "РазÑеÑение"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "ÐаÑÑÑойки каÑеÑÑво оÑобÑажениÑ"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "ÐаÑÑÑойки Ñежима видео"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "ÐаÑÑÑойки Anti-Aliasing"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr "Z-/ÐлÑбина-ÐÑÑеÑ"
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr "Bump-mapped вода"
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "УÑовни оÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð´ÐµÑалей"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+"ÐÑи наÑÑÑойки даÑÑ Ðам пÑимеÑно наÑÑÑоиÑÑ Ð¾ÑобÑажение Spring's.\n"
+"ÐÐ»Ñ Ð±Ð¾Ð»ÑÑей ÑкоÑоÑÑи попÑобÑйÑе низкие наÑÑÑойки.\n"
+"ÐолнÑй конÑÑÐ¾Ð»Ñ Ð½Ð°Ð´ вÑеми наÑÑÑойками доÑÑÑпен в\n"
+"\"EРежиме ÑкÑпеÑÑа\", Ð´Ð»Ñ Ñего нажмиÑе на кнопкÑ\n"
+"ÑпÑава или иÑполÑзÑйÑе Ð¼ÐµÐ½Ñ \"Режим\" ввеÑÑ
Ñ.\n"
+"ÐÑ Ð¼Ð¾Ð¶ÐµÑе веÑнÑÑÑÑÑ Ðº ÑÑÐ¾Ð¼Ñ ÑÐµÐ¶Ð¸Ð¼Ñ Ð² лÑбое вÑемÑ, вÑбÑав\n"
+"\"ÐÑоÑÑой Ñеим\" из Ð¼ÐµÐ½Ñ \"Режим\".\n"
+"ÐÑли ÐÑ ÑÑалкиваеÑеÑÑ Ñ ÑообÑениÑми об оÑибкаÑ
о гÑаÑике\n"
+"пÑи запÑÑке Spring'а, ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð¾Ð·Ð½Ð°ÑаÑÑ Ð½ÐµÐ¾Ð±Ñ
одимоÑÑÑ Ð² оÑклÑÑении\n"
+" некоÑоÑÑÑ
наÑÑÑоек в Ñежиме ÑкÑпеÑÑа.\n"
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "ÐаÑеÑÑво гÑаÑики"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "ÐеÑали гÑаÑики"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "РазÑеÑение ÑкÑана"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "ÐеÑейÑи в Ñежим ÑкÑпеÑÑа"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (ÑекÑÑее)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+"УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð²Ñе наÑÑÑойки каÑеÑÑво на знаÑÐµÐ½Ð¸Ñ Ð¾ÑноÑиÑелÑно ÐаÑего вÑбоÑа"
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+"УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð²Ñе наÑÑÑойки деÑалей на знаÑÐµÐ½Ð¸Ñ Ð¾ÑноÑиÑелÑно ÐаÑего вÑбоÑа"
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+"ÐÑбеÑиÑе ÑазÑеÑение ÑкÑана под ÐаÑ(и) мониÑоÑ(Ñ).\n"
+"ÐÑÐ±Ð¾Ñ ÑазÑеÑÐµÐ½Ð¸Ñ Ð½Ð° два мониÑоÑа авÑомаÑиÑеÑки вклÑÑÐ¸Ñ Ñежим двÑÑ
ÑкÑанов.\n"
+"ÐÑли ÑооÑеÑÑÑвÑÑÑее ÑазÑеÑение недоÑÑÑпно, оно Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑÑÑановлено "
+"вÑÑÑнÑÑ Ð² Ñежиме ÑкÑпеÑÑа.\n"
+"ÐожалÑйÑÑÑ, ÑвÑжиÑеÑÑ Ñ Ð°Ð²ÑоÑом, Ñак как ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¾ в бÑдÑÑиÑ
"
+"вÑпÑÑкаÑ
."
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "ÐнÑо"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+"УÑÑановка ползÑнка на 0 иÑклÑÑиÑ\n"
+"Ñежим из вÑбоÑа в игÑе."
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "СкоÑоÑÑÑ Ð¿ÑокÑÑÑки (мÑÑÑ + клавиаÑÑÑа)"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "Режим камеÑа по ÑмолÑаниÑ"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "Разное. UI наÑÑÑойки"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "ÐÑиближение"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+"ÐÑ Ð¼Ð¾Ð¶ÐµÑе ÑазмеÑÑиÑÑ Ð·Ð½Ð°Ñок ÑолнÑе/боÑа на опÑеделÑнном меÑÑе поÑвлениÑ.\n"
+" ÐаведиÑе на знаÑок Ð´Ð»Ñ Ð¿Ð¾ÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð¾ÐºÐ½Ð° и наÑÑÑойки ÑÑоÑонÑ, ÑоÑза и бонÑÑа."
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "ÐобавиÑÑ Ð±Ð¾Ñа"
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "ÐаблÑдаÑелÑ"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "СлÑÑайнÑе ÑÑаÑÑовÑе позиÑии"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- ÐÑбеÑиÑе --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "ÐÑибка наÑÑÑоек игÑÑ"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "СнаÑала вÑбеÑиÑе каÑÑÑ."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+"ÐÑодолжиÑÑ Ð±ÐµÐ· Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð¾Ñа?.\n"
+" ÐгÑа завеÑÑиÑÑÑ Ð¾ÑÐµÐ½Ñ Ð±ÑÑÑÑо.\n"
+" "
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "ÐÐµÑ Ð±Ð¾Ñов"
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "ÐÑ Ð½Ðµ можеÑе запÑÑÑиÑÑ Spring, пока запÑÑен дÑÑгой"
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "ÐÑÐ¸Ð²ÐµÑ "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+",\n"
+"ÐоÑ
оже ÑÑо ÐаÑе пеÑвое вÑÐµÐ¼Ñ Ñо SpringLobby. Я Ð¿Ð¾Ð»Ð°Ð³Ð°Ñ Ð½Ð°ÑÑÑойки, коÑоÑÑе, "
+"как мне кажеÑÑÑ, бÑдÑÑ ÑабоÑаÑÑ Ñ ÐаÑ, но ÐÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÑовеÑиÑÑ Ð¸Ñ
, оÑобенно "
+"наÑÑÑоки Spring'а. \n"
+"\n"
+"Ðогда ÐÑ Ð·Ð°Ð²ÐµÑÑиÑе, ÐÑ Ð¼Ð¾Ð¶ÐµÑе идÑи в Ð¼ÐµÐ½Ñ Ð¤Ð°Ð¹Ð», ÑоединиÑÑÑÑ Ñ ÑеÑвеÑом и "
+"полÑÑаÑÑ ÑдоволÑÑÑвие Ð¾Ñ ÐºÐ»Ð°ÑÑной игÑÑ Ð² Spring :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "ÐобÑо пожаловаÑÑ"
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+"Ðо ÑмолÑÐ°Ð½Ð¸Ñ SpringLobby ÑообÑÐ°ÐµÑ Ð½ÐµÐºÐ¾ÑоÑÑÑ ÑÑаÑиÑÑикÑ.?\n"
+"ÐÑ Ð¼Ð¾Ð¶ÐµÑе оÑклÑÑиÑÑ ÑÑо в закладке наÑÑÑоек --> ÐлавнÑе."
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "ÐамеÑание"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "ÐаÑÑÑойка пÑÑи"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+"ÐÑиложение ÑообÑило о главной оÑибке и бÑÐ´ÐµÑ Ð·Ð°Ð²ÐµÑÑено\n"
+"Создание ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± оÑибке невозможно\n"
+"\n"
+"пожалÑйÑÑа, возÑмиÑе wxWidgets библиоÑекÑ, коÑоÑÐ°Ñ Ð¿Ð¾Ð´Ð´ÐµÑÐ¶Ð¸Ð²Ð°ÐµÑ "
+"wxUSE_DEBUGREPORT"
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "ÐÑопÑÑкаÑÑ ÑазговоÑ"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "СÑÐ°Ð·Ñ Ð²ÑгнаÑÑ"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "ÐайÑи"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "ÐÑполнÑемÑе Spring'а"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "ÐеÑÑоположение"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "ÐайÑи"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "UnitSync библиоÑека"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "ÐвÑо наÑÑÑойка"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "ÐÑбÑаÑÑ Ð¸ÑполнÑемÑй Spring'а"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "ÐиблиоÑека"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr "ÐÑбÑаÑÑ UnitSync библиоÑекÑ"
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+"SpringLobby не Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð³ÑÑзиÑÑ ÐаÑÑ UnitSync библиоÑекÑ.\n"
+"\n"
+"ÐÑ Ð¼Ð¾Ð¶ÐµÑ Ñ
оÑиÑе пÑовеÑиÑÑ ÐаÑи наÑÑÑоки unitsync."
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid "Data dir wizard"
+msgstr "ÐомоÑник Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñков"
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "ÐÑбеÑиÑе папкÑ"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+"ЧÑо-Ñо пÑоиÑзоÑло не Ñак пÑи Ñоздании папок\n"
+"ÐожалÑйÑÑа, ÑоздайÑе вÑÑÑнÑÑ ÑледÑÑÑие папки:"
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "ÐÑÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð´Ð»Ñ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð¸ÑÑекло"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "ÐеизвеÑÑнÑй оÑÐ²ÐµÑ Ð¾Ñ ÑеÑвеÑа"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+"ÐÑибка пÑоÑ
ода ÑеÑез NAT, игÑа в ÑÑом ÑÑажении Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ ÑабоÑаÑÑ Ð´Ð»Ñ ÐÐ°Ñ Ð¸Ð»Ð¸ "
+"Ð´Ð»Ñ Ð´ÑгиÑ
игÑоков."
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr "линиÑ"
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr " , ÑÑÐ¾Ð»Ð±ÐµÑ "
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "ÑиÑло копий"
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "MB ÑкаÑано"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "MB загÑÑжено"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "СÑаÑÑÑ:"
+
+#: src/torrentlistctrl.cpp:60
+#, fuzzy, c-format
+msgid "% complete"
+msgstr "ÐакаÑка завеÑÑена"
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s ÑÑло"
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s пÑиÑло"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "оÑÑалоÑÑ (Ñек.)"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "Ð Ð°Ð·Ð¼ÐµÑ Ñайла (MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "ÐвÑозапÑÑк ÑиÑÑÐµÐ¼Ñ Ð¿Ð¾Ñоков (torrents)"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr "ÐÑи Ñоединении Ñ ÑеÑвеÑом (по ÑмолÑаниÑ)"
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr "пÑи запÑÑке ÑеÑвеÑа"
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "ÑÑÑнаÑ"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr "Режим заÑÑÐ¿Ð°Ð½Ð¸Ñ Ð¿Ñи запÑÑке игÑÑ"
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "ÐÑÑановиÑÑ Ð²Ñе поÑоки"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr "ÐонизиÑÑ ÑкоÑоÑÑÑ:"
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "загÑÑзка (KB/s)"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "ÑкаÑаÑÑ (KB/s)"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "ÐомеÑа"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "макÑималÑÐ½Ð°Ñ ÑкоÑоÑÑÑ Ð·Ð°Ð³ÑÑзки KB/Ñек(-1 Ð´Ð»Ñ Ð±ÐµÑконеÑной)"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "макÑималÑÐ½Ð°Ñ ÑкоÑоÑÑÑ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ KB/Ñек(-1 Ð´Ð»Ñ Ð±ÐµÑконеÑной)"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "поÑÑ Ð´Ð»Ñ Ñоединений поÑоков"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "макÑимÑм одновÑеменнÑÑ
Ñоединений"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+"ÐпÑÐ¾Ð±Ð¾Ð²Ð°Ð½Ñ Ð²Ñе \"оÑ
оÑники\" Ð´Ð»Ñ ÑиÑÑÐµÐ¼Ñ Ð¿Ð¾Ñоков. Ðе найдено ÑÑабилÑного "
+"ÑоединениÑ"
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr "ÐÑибка ÑиÑÑÐµÐ¼Ñ Ð¿Ð¾Ñоков"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "ÐаÑÐ¾Ð»Ñ ÑеÑвеÑа"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"РегиÑÑÑаÑÐ¸Ñ Ð¿ÑоÑла ÑÑпеÑно,\n"
+"ÑепеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе подклÑÑиÑÑÑÑ."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "РегиÑÑÑаÑÐ¸Ñ Ð¿ÑоÑла ÑÑпеÑно!"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "РегиÑÑÑаÑÐ¸Ñ Ð½Ðµ ÑдалаÑÑ, пÑиÑина:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"ÐÑÑÑÑ Ð¿ÑоÑмоÑÑа: "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "ÐÑибка помоÑи"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "ÐведиÑе /help в ÑÑÑоке ÑазговоÑа."
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "SpringLobby помоÑÑ Ð¿Ð¾ командам."
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "ÐбÑие командÑ:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - СÑÐ°Ð²Ð¸Ñ ÐÐ°Ñ ÑÑаÑÑÑ ÐºÐ°Ðº \"оÑоÑÑл\","
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - ÐÑменÑÐµÑ ÑÑаÑÑÑ \"оÑоÑÑл\","
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+" \"/changepassword oldpassword newpassword\" - ÐенÑÐµÑ ÑекÑÑий паÑÐ¾Ð»Ñ "
+"аккаÑнÑа."
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - ÐоказÑÐ²Ð°ÐµÑ Ð²Ñе каналÑ."
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+" \"/help [topic]\" - ÐÑÑавÑÑе заголовок (topic), еÑли ÐÑ Ñ
оÑиÑе более "
+"деÑалÑнÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾Ð± ÑÑой команде."
+
+#: src/ui.cpp:495
+#, fuzzy
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+" \"/join channel [password] [,channel2 [password2]]\" - ÐайÑи на канал."
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Тоже, ÑÑо и /join."
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" - ÐоказÑваеÑ, как много ÑаÑов ÐÑ Ð±Ñли в игÑе."
+
+#: src/ui.cpp:498
+#, fuzzy
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+" \"/msg username [text]\" - поÑлаÑÑ Ð»Ð¸Ñное ÑообÑение, ÑодеÑжаÑее ÑекÑÑ "
+"(text) Ð´Ð»Ñ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ (username)."
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - ÐоказÑÐ²Ð°ÐµÑ Ð²Ñе каналÑ."
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - Тоже, ÑÑо и /join."
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+" \"/rename newalias\" - ÐенÑÐµÑ ÐÐ°Ñ ÑекÑÑий пÑевдоним (nickname) на новÑй "
+"(newalias)."
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " \"/sayver\" - СказаÑÑ Ð²ÐµÑÑÐ¸Ñ ÐаÑего springlobby в ÑазговоÑе."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+" \"/testmd5 text\" - СообÑÐ°ÐµÑ md5-b64 ÑодеÑжимое введÑнного ÑекÑÑа (text)."
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - ÐоказÑÐ²Ð°ÐµÑ Ð²ÐµÑÑÐ¸Ñ ÐаÑего SpringLobby."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "ÐÐ¾Ð¼Ð°Ð½Ð´Ñ ÑазговоÑа:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me action\" - СказаÑÑ Ð¾ дейÑÑвии в ÑÑиле IRC."
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+"ÐÑли ÐÑ Ð¿Ð¾ÑеÑÑли какие-Ñо командÑ, идиÑе на #springlobby и попÑобÑйÑе ввеÑи "
+"иÑ
Ñам :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Ðе введÑн заголовок."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Ðаголовок \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+"\" не бÑл найден. ÐводиÑе \"/help topics\" ÑолÑко Ð´Ð»Ñ Ð´Ð¾ÑÑÑпнÑÑ
заголовков."
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Ðевозможно полÑÑиÑÑ Ð²ÐµÑÑÐ¸Ñ ÐаÑего Spring'а из unitsync библиоÑеки.\n"
+"\n"
+"ÐгÑа Ñ Ð´ÑÑгими бÑÐ´ÐµÑ Ð½ÐµÐ´Ð¾ÑÑÑпна."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+"Ðе найдено ÑовмеÑÑимÑÑ
веÑÑий Spring'а, ÑÑÐ¾Ñ ÑеÑÐ²ÐµÑ ÑÑебÑÐµÑ Ð²ÐµÑÑиÑ: %s\n"
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "ÐгÑа в инÑеÑÐ½ÐµÑ Ð¾ÑклÑÑена."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "ÐеизвеÑÑнÑй оÑÐ²ÐµÑ Ð¾Ñ ÑеÑвеÑа"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "ÐÑÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð´Ð»Ñ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð¸ÑÑекло"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "Ð½ÐµÑ Ð¾ÑкÑÑÑÑÑ
ÑабоÑаÑÑиÑ
вкладок ÑазговоÑа"
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d игÑоков)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "СообÑение ÑеÑвеÑа"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "СÑажение бÑло закÑÑÑо ÑеÑвеÑом."
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "СÑажение закÑÑÑо"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"ÐаÑÑÑойка ÐаÑего Spring'а, возможно, не наÑÑÑÐ¾ÐµÐ½Ñ Ð²ÐµÑно,\n"
+"ÐÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÑовеÑиÑÑ ÐаÑи наÑÑÑойки пеÑÐµÑ Ñем, как попÑобоваÑÑ\n"
+"игÑаÑÑ Ñ Ð´ÑÑгими."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "ÐÑибка в наÑÑÑойкаÑ
Spring'а"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"ÐÑоизоÑла оÑибка пÑи пÑовеÑке налиÑÐ¸Ñ Ð¿Ð¾Ñледней веÑÑии.\n"
+"ÐожалÑйÑÑа, попÑобÑйÑе Ñнова позже.\n"
+"ÐÑли пÑоблема повÑоÑиÑÑÑ, пожалÑйÑÑа, возполÑзÑйÑеÑÑ Ð¼ÐµÐ½Ñ ÐомоÑÑ->СообÑиÑÑ "
+"об оÑибке Ð´Ð»Ñ ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± ÑÑой оÑибке."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "ÐаÑа веÑÑиÑ: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "ÐовейÑÐ°Ñ Ð²ÐµÑÑиÑ: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"ÐеÑÑÐ¸Ñ ÐаÑего SpringLobby не обновлена.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+"\n"
+"\n"
+"ХоÑиÑе ÑкаÑаÑÑ Ð½Ð¾Ð²ÑÑ Ð²ÐµÑÑиÑ? ÐÑо бÑÐ´ÐµÑ Ð°Ð²ÑомаÑиÑеÑки Ñделано пÑи ÑледÑÑÑем "
+"запÑÑке SpringLobby."
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Ðе обновлено"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Ðе обновлено"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+"Ðевозможна запиÑÑ Ð² Ð¿Ð°Ð¿ÐºÑ SpringLobby.\n"
+"ÐожалÑйÑÑа обновиÑе вÑÑÑнÑÑ Ð¸Ð»Ð¸ вклÑÑиÑе ÑазÑеÑение к запиÑи Ð´Ð»Ñ ÑекÑÑего "
+"полÑзоваÑелÑ."
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"ÐÑла оÑибка пÑи ÑкаÑивании поÑледней веÑÑии.\n"
+"ÐожалÑйÑÑа, попÑобÑйÑе Ñнова позже.\n"
+"ÐÑли пÑоблема повÑоÑиÑÑÑ, пожалÑйÑÑа, возполÑзÑйÑеÑÑ Ð¼ÐµÐ½Ñ ÐомоÑÑ->СообÑиÑÑ "
+"об оÑибке Ð´Ð»Ñ ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± ÑÑой оÑибке."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"ÐÑла оÑибка пÑи пеÑезапиÑи ÑекÑÑего иÑполнÑемого\n"
+" необÑ
одимо вÑÑÑнÑÑ ÑкопиÑоваÑÑ: %s\n"
+" в: %s\n"
+"ÐожалÑйÑÑа, возполÑзÑйÑеÑÑ Ð¼ÐµÐ½Ñ ÐомоÑÑ->СообÑиÑÑ Ð¾Ð± оÑибке Ð´Ð»Ñ ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± "
+"ÑÑой оÑибке."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr "Ðбновление завеÑÑено. ÐÐ·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²ÑÑÑпÑÑ Ð² ÑÐ¸Ð»Ñ Ð¿Ð¾Ñле пеÑезапÑÑка."
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+"Ðо ÑазлиÑнÑм пÑиÑинам добавление полÑзоваÑÐµÐ»Ñ Ð² более, Ñем Ð¾Ð´Ð½Ñ Ð³ÑÑппÑ, "
+"запÑеÑено"
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr "Ðевозможно добавиÑÑ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ð² гÑÑппÑ"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "неÑ"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "подÑвеÑка"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr "напоминаÑÑ Ð¾ вÑ
оде/вÑÑ
оде"
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr "не обÑаÑаÑÑ Ð²Ð½Ð¸Ð¼Ð°Ð½Ð¸Ñ Ð² ÑазговоÑе"
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr "не обÑаÑаÑÑ Ð²Ð½Ð¸Ð¼Ð°Ð½Ð¸Ñ"
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr "авÑомаÑиÑеÑки вÑгнаÑÑ"
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "ÑведомлÑÑÑ Ð¾ Ñозданном ÑÑажении"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr "ÑведомлÑÑÑ Ð¾ Ñмене ÑоÑÑоÑниÑ"
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr "Ð½ÐµÑ Ð´ÐµÐ¹ÑÑвий Ð´Ð»Ñ Ð²ÑеÑ
"
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr "подÑвеÑиваÑÑ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ð² ÑпиÑке и ÑÑажениÑÑ
, в коÑоÑÑÑ
он еÑÑÑ"
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr "ÑообÑиÑÑ Ð² окне, когда полÑзоваÑÐµÐ»Ñ Ð²Ñ
одиÑ/вÑÑ
Ð¾Ð´Ð¸Ñ Ñ ÑеÑвеÑа"
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+"пÑопÑÑкаÑÑ ÑообÑÐµÐ½Ð¸Ñ Ð¾Ñ ÑÑиÑ
полÑзоваÑелей, лиÑнÑе ÑазговоÑÑ Ð½Ðµ бÑдÑÑ "
+"поÑвлÑÑÑÑÑ, еÑли кÑо-Ñо из ниÑ
бÑÐ´ÐµÑ Ð¿ÑÑаÑÑÑÑ ÑвÑзаÑÑÑÑ Ñ Ðами лиÑно"
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr "ÑообÑиÑÑ Ð² окне, еÑли полÑзоваÑÐµÐ»Ñ ÑоздаÑÑ Ð½Ð¾Ð²Ð¾Ðµ ÑÑажение"
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr "ÑообÑиÑÑ Ð² окне, еÑли полÑзоваÑÐµÐ»Ñ ÑмеÑÐ¸Ñ ÑоÑÑоÑние \"ÑÑÑл\""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "ÑÑÑл"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr "веÑнÑлÑÑ"
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "в игÑе"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr "веÑнÑлÑÑ Ð¸Ð· игÑÑ"
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "ÐаÑинаÑÑий"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "ÐовиÑок"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "СÑедний"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "ÐÑÑе ÑÑеднего"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "С навÑком"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "С болÑÑим навÑком"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "ÐеÑеÑан"
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "неизвеÑÑно"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr "СоздаÑÑ Ð³ÑÑппÑ..."
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "ÐобавиÑÑ Ð² гÑÑппÑ..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "УдалиÑÑ Ð¸Ð· гÑÑппÑ"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "ÐвÑоÑеÑвеÑ"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "ÐаÑа веÑÑÐ¸Ñ Ð¡Ð¿Ñинг"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "MB ÑкаÑано"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "РазмеÑÑиÑÑ Ñайл"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "ÐÑмена"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "РазÑеÑение ÑкÑана"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "ÐÑиÑели:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "ÐгÑоки:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Ðоманда"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "СоÑзник"
+
+#~ msgid "cpu"
+#~ msgstr "ЦÐ"
+
+#~ msgid "Test firewall"
+#~ msgstr "ÐÑовеÑиÑÑ ÑаиÑволл"
+
+#~ msgid "Relay battle to an Autohost"
+#~ msgstr "СмениÑÑ ÑÑажение на авÑоÑеÑвеÑ"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Ð Ð°Ð·Ð³Ð¾Ð²Ð¾Ñ Ð·Ð°ÐºÑÑÑ."
+
+#, fuzzy
+#~ msgid "Game is in progress."
+#~ msgstr "ÐеÑедаÑа: "
+
+#, fuzzy
+#~ msgid "Game is in progress and full."
+#~ msgstr "ÐеÑедаÑа: "
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "ÐаÑÑÑойки каÑÑÑ"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "ÐÑÐ±Ð¾Ñ Ð² Ñамой игÑе"
+
+#~ msgid ""
+#~ "No compatible installed spring version has been found, this replay "
+#~ "requires version: %s\n"
+#~ msgstr ""
+#~ "Ðе найдено ÑовмеÑÑимÑÑ
веÑÑий Spring'а, Ñ.к. повÑÐ¾Ñ ÑÑебÑÐµÑ Ð²ÐµÑÑиÑ: %s\n"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "ÐакаÑка завеÑÑена"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "ÐÑÑоединиÑÑÑÑ"
+
+#~ msgid "Debug"
+#~ msgstr "ÐÑладка"
+
+#~ msgid "Debug Options"
+#~ msgstr "ÐаÑÑÑойки оÑладки"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "ÐгÑок:"
+
+#~ msgid "status"
+#~ msgstr "ÑоÑÑоÑние"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "ÐÑбеÑиÑе ÑвеÑ"
+
+#~ msgid "Choose color (only first 16 will be saved)"
+#~ msgstr "ÐÑбеÑиÑе ÑÐ²ÐµÑ (пеÑвÑÑ
19 ÑвеÑов могÑÑ Ð±ÑÑÑ ÑоÑ
ÑаненÑ)"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "ÐÑÑппÑ"
+
+#~ msgid "a"
+#~ msgstr "Ñ"
+
+#~ msgid "p"
+#~ msgstr "и"
+
+#~ msgid "m"
+#~ msgstr "м"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "к"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "ÐнаÑение вне пÑедела.\n"
+#~ "ÐожалÑйÑÑа, введиÑе Ð¼ÐµÐ¶Ð´Ñ 0 и 100."
+
+#~ msgid ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+#~ msgstr ""
+#~ "Ðва или более боÑов в одной команде. Так как боÑÑ Ð½Ðµ ÑмеÑÑ Ð¾Ð±Ð¼ÐµÐ½Ð¸Ð²Ð°ÑÑÑÑ, "
+#~ "ÑÑого не бÑÐ´ÐµÑ Ð¿ÑоиÑÑ
одиÑÑ."
+
+#~ msgid "Bot team sharing."
+#~ msgstr "СовмеÑÑно Ñ Ð±Ð¾Ñом."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "ЧиÑло игÑоков"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "ÐÐ¼Ñ ÐºÐ°Ð½Ð°Ð»Ð°"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Ðаголовок"
+
+#~ msgid "Use smart scrolling"
+#~ msgstr "ÐÑп. ÑезкÑÑ Ð¿ÑокÑÑÑкÑ"
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Download failed"
+#~ msgstr "ÐÑибка ÑкаÑиваниÑ"
+
+#~ msgid ""
+#~ "You need to download the map to be able to watch this replay.\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Ðам необÑ
одимо имеÑÑ ÐºÐ°ÑÑÑ Ð´Ð»Ñ Ð¿ÑоÑмоÑÑа ÑÑого повÑоÑа.\n"
+#~ "\n"
+
+#~ msgid "Unit detail"
+#~ msgstr "ÐеÑали войÑк"
+
+#~ msgid "only on/off available at this time"
+#~ msgstr "возможнÑе знаÑÐµÐ½Ð¸Ñ Ð²ÐºÐ». и вÑкл."
+
+#~ msgid "Global sound volume"
+#~ msgstr "ÐбÑÐ°Ñ Ð³ÑомкоÑÑÑ Ð·Ð²Ñка"
+
+#~ msgid "mark to be able to use"
+#~ msgstr "ÑделаÑÑ Ð´Ð¾ÑÑÑпнÑми"
+
+#~ msgid "Send debug info to console"
+#~ msgstr "ÐоÑÑлаÑÑ Ð¾ÑладоÑнÑÑ Ð¸Ð½ÑÑ Ð² конÑолÑ"
+
+#~ msgid "if disabled these will only be logged"
+#~ msgstr "еÑли оÑклÑÑено, Ñо бÑÐ´ÐµÑ ÑолÑко запиÑÑ Ð² жÑÑнал"
+
+#~ msgid ""
+#~ "You're using a wxwidgets library of the 2.6.x series\n"
+#~ " battle filtering, advanced gui and joining/hosting games using nat "
+#~ "traversal\n"
+#~ " won't be available"
+#~ msgstr ""
+#~ "ÐÑ Ð¸ÑполÑзÑеÑе библиоÑÐµÐºÑ wxwidgets ÑеÑии 2.6.x\n"
+#~ " оÑÑеивание ÑÑажений, ÑлÑдÑеннÑй инÑеÑÑÐµÐ¹Ñ Ð¸ вÑ
од/Ñоздание Ð¸Ð³Ñ Ñ NAT "
+#~ "обÑ
одом\n"
+#~ " не бÑдÑÑ Ð´Ð¾ÑÑÑпнÑ"
+
+#~ msgid "Missing Functionality"
+#~ msgstr "УÑÑаÑена ÑÑнкÑионалÑноÑÑÑ"
+
+#~ msgid ""
+#~ "Do you want to download OTA content?\n"
+#~ "You need this to be able to play TA based mods.\n"
+#~ "You need to own a copy of Total Annihilation do legally download it."
+#~ msgstr ""
+#~ "ХоÑиÑе ли ÐÑ ÑкаÑаÑÑ OTA даннÑе?\n"
+#~ "Ðам нÑжно ÑÑо Ð´Ð»Ñ Ð¸Ð³ÑÑ Ð² TA модÑ.\n"
+#~ "Ðам нÑжна ÑобÑÑÐ²ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Total Annihilation Ð´Ð»Ñ ÑазÑеÑÑнного "
+#~ "ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ ÑÑого."
+
+#~ msgid "Download OTA content?"
+#~ msgstr "ÐагÑÑзиÑÑ OTA даннÑе?"
+
+#~ msgid "Do nothing"
+#~ msgstr "ÐиÑего не делаÑÑ"
+
+#~ msgid "Create a folder in a custom path (you'll get prompted for the path)"
+#~ msgstr "СоздаÑÑ Ð¿Ð°Ð¿ÐºÑ Ð² пÑоизволÑном пÑÑи (Ñ ÐÐ°Ñ ÑпÑоÑÑÑ Ð¿ÑÑÑ)"
+
+#~ msgid "I have already a SpringData folder, i want to browse manually for it"
+#~ msgstr "У Ð¼ÐµÐ½Ñ Ñже еÑÑÑ Ð¿Ð°Ð¿ÐºÐ° Spring'а, Ñ Ñ
оÑÑ ÑказаÑÑ Ð²ÑÑÑнÑÑ ÐµÑ"
+
+#, fuzzy
+#~ msgid ""
+#~ "Looks like you don't have yet a user SpringData folder structure\n"
+#~ "What would you like to do? (leave default choice if you don't know what "
+#~ "this is for)"
+#~ msgstr ""
+#~ "ÐоÑ
оже Ñ ÐÐ°Ñ Ð½ÐµÑÑ Ð¿Ð°Ð¿ÐºÐ¸ Spring'а\n"
+#~ "ЧÑо Ð²Ñ Ñ
оÑиÑе ÑделаÑÑ? (оÑÑавÑÑе вÑÐ±Ð¾Ñ Ð¿Ð¾ ÑмолÑаниÑ, ÑÑо ÑÑо Ñакое)"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "ÐеизвеÑÑнÑй оÑÐ²ÐµÑ Ð¾Ñ ÑеÑвеÑа"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Ðе подлÑÑенÑ."
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "ÐÑа игÑа иÑполÑзÑÐµÑ NAT обÑ
од, ÑÑо не поддеÑживаеÑÑÑ Ð² wx 2.6 ÑбоÑке "
+#~ "SpringLobby. \n"
+#~ "\n"
+#~ "ÐÑ Ð½Ðµ ÑможеÑе игÑаÑÑ Ð² ÑÑом ÑÑажении. \n"
+#~ "ÐбновиÑе ÐÐ°Ñ wxwidgets до 2.8 или новее Ð´Ð»Ñ Ð²ÐºÐ»ÑÑÐµÐ½Ð¸Ñ Ð¿Ð¾Ð´Ð´ÐµÑжки NAT "
+#~ "обÑ
ода."
+
+#~ msgid ""
+#~ "Cannot save an options set without a name\n"
+#~ "Please write one in the list or chose an existing to overwrite and try "
+#~ "again."
+#~ msgstr ""
+#~ "Ðевозможно ÑоÑ
ÑаниÑÑ Ð½Ð°ÑÑÑойки без имени\n"
+#~ "ÐожалÑйÑÑа, введиÑе Ð¸Ð¼Ñ Ð¸Ð»Ð¸ вÑбеÑиÑе из ÑпиÑка Ð´Ð»Ñ Ð¿ÐµÑезапиÑи и "
+#~ "попÑобÑйÑе Ñнова."
+
+#~ msgid ""
+#~ "No options set is selected to set as default\n"
+#~ "Please select one from the list and try again."
+#~ msgstr ""
+#~ "Ðе вÑбÑÐ°Ð½Ñ Ð½Ð°ÑÑÑоки Ð´Ð»Ñ ÑÑÑановки по ÑмолÑаниÑ\n"
+#~ "ÐожалÑйÑÑа, вÑбеÑиÑе наÑÑÑойки из ÑпиÑка и попÑобÑйÑе Ñнова."
+
+#~ msgid "Only the host can change the game options"
+#~ msgstr "ТолÑко ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð¼ÐµÐ½ÑÑÑ Ð½Ð°ÑÑÑоки игÑÑ"
+
+#~ msgid "Only the host can start the battle."
+#~ msgstr "ТолÑко ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð½Ð°ÑинаÑÑ ÑÑажение."
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "ТолÑко ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð¼ÐµÐ½ÑÑÑ Ð½Ð°ÑÑÑоки игÑÑ"
+
+#~ msgid "Only the host can lock the game."
+#~ msgstr "ТолÑко ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð¿Ð¸ÑаÑÑ Ð¸Ð³ÑÑ."
+
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "ТолÑко ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð²ÐºÐ»ÑÑаÑÑ Ñежим авÑоÑеÑвеÑа."
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Ðе пÑавилÑнÑй поÑÑ/адÑÐµÑ Ð¸Ð»Ð¸ Ð¸Ð¼Ñ ÑеÑвеÑа."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "РабоÑаÑÑие ÐºÐ°Ð½Ð°Ð»Ñ ÑазговоÑа:"
+
+#~ msgid "no rank"
+#~ msgstr "неÑÑ ÑÑовнÑ"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "ÐÑÑеивание ÑÑажений вклÑÑено"
+
+#~ msgid "Only the host can fix player colours."
+#~ msgstr "ТолÑко ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð¸ÑпÑавлÑÑÑ ÑвеÑа игÑоков."
+
+#~ msgid "Select all"
+#~ msgstr "ÐÑделиÑÑ Ð²ÑÑ"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "ÐобавиÑÑ Ð¿Ð¾Ð»Ñзов."
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "УдалиÑÑ Ð²ÑбÑанное"
+
+#, fuzzy
+#~ msgid "you can also enter a ';' seperated list of usernames:"
+#~ msgstr "введиÑе ÑпиÑок, иÑполÑзÑÑ ; Ð´Ð»Ñ ÑÐ°Ð·Ð´ÐµÐ»ÐµÐ½Ð¸Ñ ÑлеменÑов"
+
+#~ msgid "not connected to server, no user to display"
+#~ msgstr "Ð½ÐµÑ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ ÑеÑвеÑом, некого оÑобÑажаÑÑ"
+
+#~ msgid ""
+#~ "At least one username contained non-ascii or whitespace character.\n"
+#~ "Please correct and try again."
+#~ msgstr ""
+#~ "Ðак минимÑм одно Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ ÑодеÑÐ¶Ð¸Ñ Ð½Ðµ ascii или пÑобел.\n"
+#~ "ÐожалÑйÑÑа, иÑпÑавÑÑе и попÑобÑйÑе Ñнова."
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "ÐевеÑное Ð¸Ð¼Ñ Ð¿Ð¾Ð»Ñзов."
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "ÐÑаÑкое опиÑание игÑÑ, оно бÑÐ´ÐµÑ Ð¾ÑобÑажаÑÑÑÑ Ð² ÑпиÑке ÑÑажений."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "ÐÑбеÑиÑе мод Ð´Ð»Ñ Ð¸Ð³ÑÑ"
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "ÐоÑмалÑнаÑ"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "ÐÑибка в СпÑинг"
+
+#~ msgid "You have one or more bots sharing team, this is not possible."
+#~ msgstr "Ðва и болÑÑе компÑÑеÑа на одной команде, и ÑÑо не ÑÑабоÑаеÑ."
+
+#~ msgid ""
+#~ "Please enter password needed to join this channel, leave blank for no "
+#~ "passwrd."
+#~ msgstr ""
+#~ "ÐожалÑйÑÑа дайÑе паÑÐ¾Ð»Ñ Ð´Ð»Ñ ÐºÐ°Ð½Ð°Ð»Ð°, или оÑÑавÑе меÑÑо еÑли паÑÐ¾Ð»Ñ Ð½Ðµ "
+#~ "нÑжен."
+
+#~ msgid "&Edit"
+#~ msgstr "&ÐзмениÑÑ"
+
+#~ msgid "LuaAI"
+#~ msgstr "LuaAI"
+
+#~ msgid "yes"
+#~ msgstr "Ðа"
+
+#~ msgid "/.spring"
+#~ msgstr "/.spring"
+
+#~ msgid "Start system"
+#~ msgstr "ÐаÑаÑÑ ÑиÑÑемÑ"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "ÐÑодолжаÑÑ Ð¸Ð³ÑÑ ÐµÑли ÐºÐ¾Ð¼Ð¼Ð°Ð½Ð´Ð¸Ñ ÑмеÑ"
+
+#~ msgid "End if commander dies"
+#~ msgstr "ÐÑодолжаÑÑ ÐµÑли ÐºÐ¾Ð¼Ð¼Ð°Ð½Ð´Ð¸Ñ ÑмеÑ"
+
+#~ msgid "End condition"
+#~ msgstr "УÑÐ»Ð¾Ð²Ð¸Ñ ÐºÐ¾Ð½Ñа"
+
+#~ msgid "Resources"
+#~ msgstr "РеÑÑÑÑÑ"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "ÐолиÑеÑÑво меÑалла Ñ ÐºÐ¾ÑоÑÑм каждÑй игÑок наÑинаеÑ"
+
+#~ msgid "Start Energy"
+#~ msgstr "ÐаÑинаÑÑие колиÑеÑÑво енеÑгии"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "ÐолиÑеÑÑво енеÑгии Ñ ÐºÐ¾ÑоÑÑм каждÑй игÑок наÑинаеÑ"
+
+#~ msgid "Max units"
+#~ msgstr "ÐакÑ. колиÑеÑÑво единиÑ"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "ÐакÑ. колиÑеÑÑво ÐµÐ´Ð¸Ð½Ð¸Ñ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ игÑока"
+
+#~ msgid "Limit d-gun"
+#~ msgstr "ÐÐ¸Ð¼Ð¸Ñ Ð´Ð»Ñ Ð-пÑÑки"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "ÐÑизÑаки зданий"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "УменÑÑаÑÑиеÑÑ Ð²ÑÑабаÑÑваÑели меÑалла"
+
+#~ msgid "This chat is exclusively for participants of this battle."
+#~ msgstr "ÐÑÐ¾Ñ ÑÐ°Ñ Ð´Ð¾ÑÑÑпен ÑолÑко ÑÑаÑÑникам ÑÑой биÑвÑ."
+
+#~ msgid "Cannot add bot, maximum number of players already reached."
+#~ msgstr "Ðевозможно добавиÑÑ Ð±Ð¾Ñа, доÑÑигнÑÑо макÑмималÑное ÑиÑло игÑоков."
+
+#~ msgid "Max players reached"
+#~ msgstr "ÐоÑÑигнÑÑо макÑималÑное ÑиÑло игÑоков"
+
+#~ msgid "Save to:"
+#~ msgstr "СоÑ
ÑаниÑÑ Ð²:"
+
+#~ msgid "Browse..."
+#~ msgstr "ÐÑбÑаÑÑ..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "ÐÑбеÑиÑе папкÑ"
+
+#~ msgid "Up to Date"
+#~ msgstr "Ðбновление не нÑжно"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "ÐÑ Ñ
оÑиÑе поÑеÑиÑÑ ÑÑÑаниÑÑ Ñ Ð¸Ð½ÑÑÑÑкÑиÑми по загÑÑзке поÑледней веÑÑии?"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð½Ð°ÑалÑное колиÑеÑÑво меÑала Ñ Ð¸Ð³Ñоков"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð½Ð°ÑалÑное колиÑеÑÑво ÑнеÑгии Ñ Ð¸Ð³Ñоков"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "ÐакÑималÑное ÑиÑло ÑниÑов"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr ""
+#~ "УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð¼Ð°ÐºÑималÑное ÑиÑло ÑниÑов, коÑоÑÑе Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑÑÑоиÑÑ Ð¸Ð³Ñок"
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "не поддеÑживаеÑÑÑ ÑеÑвеÑом, коÑоÑÐ¾Ð¼Ñ Ð½Ñжна веÑÑиÑ"
diff --git a/po/springlobby.pot b/po/springlobby.pot
new file mode 100644
index 0000000..9e3d873
--- /dev/null
+++ b/po/springlobby.pot
@@ -0,0 +1,5768 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR The SpringLobby team
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby 0.29\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr ""
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr ""
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr ""
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr ""
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+msgid "value"
+msgstr ""
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr ""
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr ""
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr ""
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr ""
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr ""
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr ""
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr ""
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr ""
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr ""
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr ""
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr ""
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr ""
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr ""
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr ""
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr ""
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+msgid "Number of allies"
+msgstr ""
+
+#: src/autobalancedialog.cpp:56
+msgid "Auto select"
+msgstr ""
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr ""
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr ""
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr ""
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr ""
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr ""
+
+#: src/battlelistctrl.cpp:61
+msgid "Spectators"
+msgstr ""
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+msgid "Players"
+msgstr ""
+
+#: src/battlelistctrl.cpp:63
+msgid "Max"
+msgstr ""
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr ""
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr ""
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr ""
+
+#: src/battlelistctrl.cpp:361
+msgid "Active Players:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr ""
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr ""
+
+#: src/battlelistfilter.cpp:122
+msgid "Highlighted only"
+msgstr ""
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr ""
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr ""
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr ""
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr ""
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr ""
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr ""
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr ""
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr ""
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+msgid " Filter "
+msgstr ""
+
+#: src/battlelisttab.cpp:142
+msgid "Activated"
+msgstr ""
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+msgid " Battle infos "
+msgstr ""
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr ""
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr ""
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr ""
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr ""
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr ""
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+msgid "Already in this battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+
+#: src/battlelisttab.cpp:523
+msgid "Already in another battle"
+msgstr ""
+
+#: src/battlelisttab.cpp:523
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr ""
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr ""
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr ""
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr ""
+
+#: src/battlemaptab.cpp:69
+msgid "Select"
+msgstr ""
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr ""
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr ""
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr ""
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr ""
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr ""
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr ""
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr ""
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr ""
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr ""
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr ""
+
+#: src/battlemaptab.cpp:103
+msgid "Chose before game"
+msgstr ""
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr ""
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr ""
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr ""
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:76
+msgid "Disable selected units."
+msgstr ""
+
+#: src/battleoptionstab.cpp:80
+msgid "Re-enable selected units."
+msgstr ""
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr ""
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr ""
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+msgid "Unit restriction"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:717
+msgid "AI (bot)\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:719
+msgid "Human\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:722
+msgid "Spectator\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:724
+msgid "Player\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:727
+msgid "Host\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:729
+msgid "Client\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:732
+msgid "Ready\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:734
+msgid "Not ready\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+msgid "Set name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:63
+msgid "Load a saved set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:67
+msgid "Save..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+msgid "Save a set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:72
+msgid "Delete..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+msgid "Delete a set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:77
+msgid "Set default..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:152
+msgid "no options available"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+msgid "Set mod default preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr ""
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr ""
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr ""
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr ""
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr ""
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+msgid "AutoSpect"
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+msgid "AutoStart"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+msgid "Ring ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:231
+msgid "Spect unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+msgid "Force spectate ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+msgid "Save"
+msgstr ""
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr ""
+
+#: src/battleroomtab.cpp:269
+msgid "Set default"
+msgstr ""
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr ""
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr ""
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+msgid "Set Timeout"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+msgid "Find channel:"
+msgstr ""
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:28
+msgid "Channel"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:29
+msgid "# users"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr ""
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr ""
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr ""
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr ""
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr ""
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr ""
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr ""
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr ""
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr ""
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr ""
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr ""
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr ""
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr ""
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr ""
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr ""
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr ""
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, c-format
+msgid "%d users"
+msgstr ""
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr ""
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr ""
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr ""
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr ""
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr ""
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr ""
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr ""
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr ""
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr ""
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr ""
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr ""
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr ""
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr ""
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr ""
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr ""
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr ""
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr ""
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr ""
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr ""
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr ""
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr ""
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr ""
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr ""
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr ""
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr ""
+
+#: src/chatpanel.cpp:510
+msgid "User"
+msgstr ""
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr ""
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr ""
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr ""
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr ""
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr ""
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr ""
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr ""
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr ""
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr ""
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr ""
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr ""
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr ""
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr ""
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr ""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr ""
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr ""
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr ""
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr ""
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr ""
+
+#: src/chatpanel.cpp:1029
+msgid " ** Channel topic:"
+msgstr ""
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr ""
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr ""
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr ""
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr ""
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr ""
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr ""
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr ""
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr ""
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr ""
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr ""
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr ""
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr ""
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr ""
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr ""
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr ""
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr ""
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr ""
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr ""
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr ""
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr ""
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+msgid "Invalid nickname"
+msgstr ""
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr ""
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr ""
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr ""
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr ""
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr ""
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr ""
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr ""
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr ""
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr ""
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr ""
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr ""
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr ""
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr ""
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr ""
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr ""
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr ""
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr ""
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr ""
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr ""
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr ""
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr ""
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr ""
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr ""
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr ""
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr ""
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr ""
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr ""
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr ""
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr ""
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr ""
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr ""
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr ""
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr ""
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr ""
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr ""
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr ""
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr ""
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr ""
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr ""
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr ""
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr ""
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr ""
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr ""
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr ""
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr ""
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr ""
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr ""
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr ""
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr ""
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr ""
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr ""
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr ""
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr ""
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr ""
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr ""
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr ""
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr ""
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr ""
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr ""
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr ""
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr ""
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr ""
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr ""
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr ""
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr ""
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr ""
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr ""
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr ""
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr ""
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr ""
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr ""
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr ""
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr ""
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr ""
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr ""
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr ""
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr ""
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr ""
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr ""
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr ""
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr ""
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr ""
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr ""
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr ""
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr ""
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr ""
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr ""
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr ""
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr ""
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr ""
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr ""
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr ""
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr ""
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr ""
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr ""
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr ""
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr ""
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr ""
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr ""
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr ""
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr ""
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr ""
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr ""
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr ""
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr ""
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr ""
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr ""
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr ""
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr ""
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr ""
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr ""
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr ""
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr ""
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr ""
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr ""
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr ""
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr ""
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr ""
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr ""
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr ""
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr ""
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr ""
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr ""
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr ""
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr ""
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr ""
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr ""
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr ""
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr ""
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr ""
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr ""
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr ""
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr ""
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr ""
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr ""
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr ""
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr ""
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr ""
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr ""
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr ""
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr ""
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr ""
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr ""
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr ""
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr ""
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr ""
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr ""
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr ""
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr ""
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr ""
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr ""
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr ""
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr ""
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr ""
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr ""
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr ""
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr ""
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr ""
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr ""
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr ""
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr ""
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr ""
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr ""
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr ""
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr ""
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr ""
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr ""
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr ""
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr ""
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr ""
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr ""
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr ""
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr ""
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr ""
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr ""
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr ""
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr ""
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr ""
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr ""
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr ""
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr ""
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr ""
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr ""
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr ""
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr ""
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr ""
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr ""
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr ""
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr ""
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr ""
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr ""
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr ""
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr ""
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr ""
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr ""
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr ""
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr ""
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr ""
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr ""
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr ""
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr ""
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr ""
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr ""
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr ""
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr ""
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr ""
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr ""
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr ""
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr ""
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr ""
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr ""
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr ""
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr ""
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr ""
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr ""
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr ""
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr ""
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr ""
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr ""
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr ""
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+msgid "Name"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+msgid "Download selected"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+msgid "Remove"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+msgid "Rename.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+msgid "Add New.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+msgid "Group Actions"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+msgid "Ignore Chat"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+msgid "Highlight Color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+msgid "Add.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+msgid "Remove users from group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+msgid "delete"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+msgid "Choose a filename"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+msgid "Default"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+msgid "Select the language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr ""
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+
+#: src/hostbattledialog.cpp:81
+msgid "Autopaste description"
+msgstr ""
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr ""
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr ""
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Randomly picks an available one"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr ""
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr ""
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+msgid "Autoconnect"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+msgid "Autoconnect on lobby start"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+msgid "Start tab"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+msgid "Disconnected from server, chat closed."
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+msgid "Unit Restrictions"
+msgstr ""
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr ""
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr ""
+
+#: src/mainoptionstab.cpp:75
+msgid "General"
+msgstr ""
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr ""
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr ""
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr ""
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+msgid "Download Lua widgets"
+msgstr ""
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr ""
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr ""
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr ""
+
+#: src/mainwindow.cpp:133
+msgid "&Save options"
+msgstr ""
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr ""
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+msgid "Channel &list"
+msgstr ""
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr ""
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr ""
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr ""
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr ""
+
+#: src/mainwindow.cpp:168
+msgid "&Change language"
+msgstr ""
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr ""
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr ""
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr ""
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr ""
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "Not connected"
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr ""
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "No files found"
+msgstr ""
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+msgid "Which profile do you want to be default?"
+msgstr ""
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+msgid "Savegames"
+msgstr ""
+
+#: src/mainwindow.h:184
+msgid "Replays"
+msgstr ""
+
+#: src/mainwindow.h:186
+msgid "Downloads"
+msgstr ""
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr ""
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr ""
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr ""
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr ""
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+msgid "Filter"
+msgstr ""
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+msgid "Map details"
+msgstr ""
+
+#: src/mapselectdialog.cpp:162
+msgid "Start positions"
+msgstr ""
+
+#: src/mapselectdialog.cpp:265
+msgid "Minimum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+msgid "Aspect ratio"
+msgstr ""
+
+#: src/mapselectdialog.cpp:270
+msgid "Number of start positions"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+msgid "Choose in-game"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:125
+msgid "Choose before game"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:131
+msgid "List of restricted units"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+msgid "Change option"
+msgstr ""
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr ""
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr ""
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr ""
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr ""
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+msgid "Duration (hh:mm:ss):"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+msgid "Modname"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Mapname"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:45
+msgid "Duration"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:46
+msgid "Spring Version"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Load"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+msgid "replay"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+msgid "savegame"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid "Invalid replay"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+msgid "Select Users"
+msgstr ""
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+msgid " is online"
+msgstr ""
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+msgid " just went offline"
+msgstr ""
+
+#: src/serverevents.cpp:260
+msgid " opened battle "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr ""
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr ""
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+msgid "Download update"
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+msgid "Negotiation error"
+msgstr ""
+
+#: src/serverevents.cpp:984
+msgid "Invalid Value"
+msgstr ""
+
+#: src/serverevents.cpp:987
+msgid "No Handler"
+msgstr ""
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+msgid "Action Aborted"
+msgstr ""
+
+#: src/serverevents.cpp:996
+msgid "Reconnection Error"
+msgstr ""
+
+#: src/serverevents.cpp:999
+msgid "Unknown Error"
+msgstr ""
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+msgid "Download complete."
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "Battle volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr ""
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr ""
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+msgid "Blur reflection"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+msgid "Reflection"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+msgid "Reflection texture size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:419
+msgid "Refraction"
+msgstr ""
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr ""
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr ""
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr ""
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr ""
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr ""
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr ""
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr ""
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr ""
+
+#: src/singleplayertab.cpp:100
+msgid "Spectate only"
+msgstr ""
+
+#: src/singleplayertab.cpp:103
+msgid "Random start positions"
+msgstr ""
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr ""
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr ""
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+msgid "Notice"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+msgid "Import settings?"
+msgstr ""
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+msgid "Ignore chat"
+msgstr ""
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr ""
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+msgid "Friends"
+msgstr ""
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr ""
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr ""
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr ""
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr ""
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr ""
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr ""
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+msgid "MB downloaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+msgid "Status"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr ""
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr ""
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr ""
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr ""
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr ""
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr ""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr ""
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr ""
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:661
+msgid "Disconnected from server."
+msgstr ""
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+msgid "Connection failure"
+msgstr ""
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr ""
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid "Not up to date"
+msgstr ""
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr ""
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "none"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "highlight"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify hosted battle"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+msgid "away"
+msgstr ""
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+msgid "ingame"
+msgstr ""
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr ""
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr ""
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr ""
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr ""
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr ""
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr ""
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr ""
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+msgid "Add to group..."
+msgstr ""
+
+#: src/usermenu.h:30
+msgid "Remove from group"
+msgstr ""
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+msgid "Author"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+msgid "Current version"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:79
+msgid "# downloaded"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+msgid "Changelog"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
diff --git a/po/stamp-po b/po/stamp-po
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/po/stamp-po
@@ -0,0 +1 @@
+timestamp
diff --git a/po/sv.gmo b/po/sv.gmo
new file mode 100644
index 0000000..9093c47
Binary files /dev/null and b/po/sv.gmo differ
diff --git a/po/sv.po b/po/sv.po
new file mode 100644
index 0000000..41b87f4
--- /dev/null
+++ b/po/sv.po
@@ -0,0 +1,6398 @@
+# Swedish translations for SpringLobby package.
+# Copyright (C) 2008 The SpringLobby team
+# This file is distributed under the same license as the SpringLobby package.
+# Tommy Carlsson <tc at springlobby.info>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: SpringLobby 0.0.1-svn\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-08-02 17:18+0000\n"
+"Last-Translator: nanker <Unknown>\n"
+"Language-Team: Swedish\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+"X-Poedit-Country: SWEDEN\n"
+"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-Basepath: ..\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "Lägg till bot"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "Smeknamn:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "AI:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "Välj vilket AI du vill använda med den här boten."
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "Värde"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "Avbryt"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "Lägg till bot"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "Hittade inga AI bibliotek i din Spring installation."
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Inga AI bibliotek funna"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "Acceptera avtal"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Accepterar du avtalet?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Ja"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "Nej"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr ""
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr ""
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr ""
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Slumpmässiga"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr ""
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "Ingen"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "Acceptabel"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr ""
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "Antal spelare"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "Ã
teranslut"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "Ok"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "Beskrivning"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Karta"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "Mod"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "Värd"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "Spektatorer:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "Spelare:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Karta"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "Ladda ner &karta"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "Ladda ner &mod"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "Spektatorer:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "Spelare:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "Värd:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "Status:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "LÃ¥st"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "Lösenords skyddade"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "Markering"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "Rang begränsning:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "Beskrivning:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "Startade"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "Fulla"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "Ãppna"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "Spelare:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "Alla"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Karta:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "Enbart kartor som jag har"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "Max.Spelare:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "Mod:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "Bara moddar som jag har"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " Spektator:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "Spelare:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "Alla filer"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "Startade"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "Spel lista"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "Hosta nytt.."
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "GÃ¥ med"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Du kan inte skapa ett spel när du är nerkopplad. Var god koppla upp dig mot "
+"lobby serven."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Inte uppkopplad."
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr ""
+"Du kan inte skapa spel eftersom din version av Spring inte är kompatibel."
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Spring fel"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr "Spring körs redan, stäng det innan du försöker starta ett nytt spel."
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Du är redan inne i ett spel"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Du är redan inne i ett spel.\n"
+"\n"
+"Vill du gå ur detta och starta ett nytt?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "Spelet kunde inte startas eftersom modden du valt inte kunde hittas. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Kunde inte starta spel."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Inga kartor funna"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+"Du kan inte gå med i nätverks spel eftersom din Spring version är "
+"inkompatibel."
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Du är redan inne i ett spel"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Du är redan inne i ett spel.\n"
+"\n"
+"Vill du gå ur detta och starta ett nytt?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Du är redan inne i ett spel"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Du är redan inne i ett spel.\n"
+"\n"
+"Vill du gå ur detta och starta ett nytt?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr "Spring körs redan, stäng det innan du försöker starta ett nytt spel."
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "Modden inte tillgänlig"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "Kartan inte tillgänglig"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "Spelets lösenord"
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "Skriv in lösenord"
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "Välj..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "Alternativ"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "Värde"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "Storlek"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "Vindhastighet"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "Strömstyrka"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "Gravitation"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "Extractor radie"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "Max metal"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "Fasta"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "Välj i spelet"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "Välj i spelet"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "Start positioner"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "Enhets begränsningar"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "Tillåtna enheter"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "Enheter i den här listan kan användas i spelet."
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "Tillåt alla enheter."
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "Tillåt alla enheter."
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "Tillåt alla enheter."
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "Begränsade enheter"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "Enheter i den här listan kan inte användas i spelet."
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "Enhets begränsningar"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "Smeknamn"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "Team"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "Allians"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "Resurs bonus"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "Sida"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "Välj färg"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "Sätt resurs bonus"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "Spektator"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "Släng ut"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "Ring"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "Var god välj ett nummer mellan 0 och 100"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "Lägg till bot"
+
+#: src/battleroomlistctrl.cpp:719
+msgid "Human\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "Spektator"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "Spelare:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "Värd"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "Klient"
+
+#: src/battleroomlistctrl.cpp:732
+msgid "Ready\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "Inte redo"
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "Sätt åtkomst..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "Ladda..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "Ladda lista från fil."
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "Spara..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "Spara lista till fil."
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "Välj..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "Spara lista till fil."
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "standard"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "Mod alternativ"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "Kart alternativ"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "Modden inte tillgänlig"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "fel"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "Välj"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "standard"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "Redo"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "Färg"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "Lämna"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "Starta"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "Lägg till bot..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "Ã
teranslut"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "Starta"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "Ring"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "Inte redo"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "PÃ¥tvinga start?"
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "Spara..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "Välj"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "standard"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr ""
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr ""
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"Några av spelarna är inte redo.\n"
+"Ska jag ringa dessa?"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "Inte redo"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "standard"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "GÃ¥ med denna kanalen automatiskt"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "GÃ¥ med i kanal..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "Namn på kanalen"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "kanal"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d användare)"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### Sessionen avslutad ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "]"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Kunde inte skapa katalog.\n"
+"Kontrollera att den inte är skrivskyddad.\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "Log funktionen är avstängd tills du startar om SpringLobby."
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "Log varning"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"Kunde inte skriva log meddelandet till loggen.\n"
+"Loggningen kommer att stängas av för kanalen "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+".\n"
+"\n"
+"Gå in i kanalen igen för att aktivera loggning."
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"Kunde inte skapa log filen.\n"
+"Kontrollera att den inte är skrivskyddad.\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "Färger och font"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "Använd systemfärger"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "Normal"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "Bakgrund"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "Händelse"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "Markering"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "Gå med/Lämna"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "Mina medelanden"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "Server"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "Klient"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "Felmedelanden"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "Tids stämpel"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "PÃ¥minnelse"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Ansluten till TAS Server.\n"
+"[22:30] <Kompis> hi everyone\n"
+"[22:30] ** Kompis2 kom in i kanalen.\n"
+"[22:30] * Kompis2 thinks his colors looks nice\n"
+"[22:45] <Kompis> Kompis2: orl?\n"
+"[22:46] <Kompis2> But could be better, should tweak them some more...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "Font:"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "standard"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "Välj..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr ""
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "Chat loggar"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "Spara chat loggar"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "Markera ord"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "Ord som ska bli markerade"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d användare)"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "Skicka"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "Kopiera"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "Rensa"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "GÃ¥ med denna kanalen automatiskt"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "Visa gå med/lämna medelanden"
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "Kanal information"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "Sätt ämne..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "Kanal medelande..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "LÃ¥s..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "LÃ¥s upp..."
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "Registrera..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "Avregistrera"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "PÃ¥"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "Av"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "Ãr pÃ¥?"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "Spam skydd"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "ChanServ"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "Koppla ned"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "Ã
teranslut"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "Ta bort..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "Ãndra lösenord..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "Sätt åtkomst..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "Konton"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "Broadcasta..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "Administrering"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "Tysta användare"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "Ãppna chat"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "GÃ¥ med samma spel"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "Spel tid"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "Tysta..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "Tysta i 5 minuter"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "Tysta i 10 minuter"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "Tysta i 30 minuter"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "Tysta i 2 timmar"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "Tysta i en dag"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "Avtysta"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "Tysta"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "Sparka..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "Banna..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "Avbanna"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "Slap!"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "Op"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "DeOp"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr ""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "kanal"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "spel"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "server"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " gick med i "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " gick ur "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "Kanal information"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * Satt av "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "Chat stängd."
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "Ãr du säker pÃ¥ att du vill klistra in %d rader?"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Flood varning"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " Du har SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " Du är inte i kanalen eller så finns den inte."
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " Användaren är ner kopplad."
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " Skickade: \""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "\""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "ChanServ fel"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "ChanServ är inte i kanalen"
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "Vad ska det nya ämnet vara?"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "Medelande:"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "LÃ¥s kanalen..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "Ange lösenord"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "LÃ¥s upp kanalen"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "Ãr du säker pÃ¥ att du vill lÃ¥sa kanalen?"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "ChanServ finns inte på servern."
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "Registrera kanalen"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "Vem skall vara grundare till den här kanalen?"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "Avregistrera kanalen"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "Ãr du säker pÃ¥ att du vill avregistrera kanalen?"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "Ta bort användarkonto"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "Vilket användar konto vill du ta bort idag?"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "Ta bort konto"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "Ãr du säker pÃ¥ att du vill ta bort kontot "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "Ãndra användar lösenord"
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "Vilken användare vill du byta lösenord för?"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "Vad ska det nya lösenordet bli?"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "Inte implementerad"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "Broadcasta medelande"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "Medelande att broadcasta:"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "Detta spelet är lösenords skyddat skriv in lösenordet."
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "Tysta användare"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "I hur många minuter skall han bli tystad?"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "Sparka ut användare"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "Anledning:"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "Sparka ut användare"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "Tysta användare"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "Hur länge?"
+
+#: src/chatpanel.cpp:1797
+#, fuzzy
+msgid "couldn't add user"
+msgstr "Kunde inte starta webbläsaren."
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "Anslut till lobby server"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+"Servern du vill ansluta till. Du kan skriva in vilken adress du vill med "
+"formatet host:port."
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "Lösenord"
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"Notera: Om du inte har något konto\n"
+"ännu kan du skapa ett under \"Registrering\"\n"
+"fliken."
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "Login"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "Registrering"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "Smeknamn"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "Felaktig port."
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "Felaktig port"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"Portnumret är utanför tillåtet intervall.\n"
+"\n"
+"Det måste liga inom 1 till 65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "Felaktig host/port"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "Felaktig host"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "Felaktigt nummer"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr "Registreringen misslyckades på grund av att lösenorden inte matchade."
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "Registreringen misslyckades."
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr ""
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr ""
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr ""
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr ""
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr ""
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr ""
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr ""
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr ""
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr ""
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr ""
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr ""
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr ""
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr ""
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr ""
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr ""
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr ""
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr ""
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr ""
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr ""
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr ""
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr ""
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr ""
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr ""
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr ""
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr ""
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr ""
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr ""
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr ""
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr ""
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr ""
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr ""
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr ""
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr ""
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr ""
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr ""
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr ""
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr ""
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr ""
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr ""
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr ""
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr ""
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr ""
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr ""
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr ""
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr ""
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr ""
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr ""
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr ""
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr ""
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr ""
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr ""
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr ""
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr ""
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr ""
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr ""
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr ""
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr ""
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr ""
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr ""
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr ""
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr ""
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr ""
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr ""
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr ""
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr ""
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr ""
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr ""
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr ""
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr ""
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr ""
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr ""
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr ""
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr ""
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr ""
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr ""
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr ""
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr ""
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr ""
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr ""
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr ""
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr ""
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr ""
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr ""
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr ""
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr ""
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr ""
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr ""
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr ""
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr ""
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr ""
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr ""
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr ""
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr ""
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr ""
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr ""
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr ""
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr ""
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr ""
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr ""
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr ""
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr ""
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr ""
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr ""
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr ""
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr ""
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr ""
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr ""
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr ""
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr ""
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr ""
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr ""
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr ""
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr ""
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr ""
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr ""
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr ""
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr ""
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr ""
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr ""
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr ""
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr ""
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr ""
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr ""
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr ""
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr ""
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr ""
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr ""
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr ""
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr ""
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr ""
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr ""
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr ""
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr ""
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr ""
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr ""
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr ""
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr ""
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr ""
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr ""
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr ""
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr ""
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr ""
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr ""
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr ""
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr ""
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr ""
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr ""
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr ""
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr ""
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr ""
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr ""
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr ""
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr ""
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr ""
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr ""
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr ""
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr ""
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr ""
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr ""
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr ""
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr ""
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr ""
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr ""
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr ""
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr ""
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr ""
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr ""
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr ""
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr ""
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr ""
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr ""
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr ""
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr ""
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr ""
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr ""
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr ""
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr ""
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr ""
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr ""
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr ""
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr ""
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr ""
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr ""
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr ""
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr ""
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr ""
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr ""
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr ""
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr ""
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr ""
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr ""
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr ""
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr ""
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr ""
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr ""
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr ""
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr ""
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr ""
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr ""
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr ""
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr ""
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr ""
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr ""
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr ""
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr ""
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr ""
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr ""
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr ""
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr ""
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr ""
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr ""
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr ""
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr ""
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr ""
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr ""
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr ""
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr ""
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "(Helt landsnamn ej funnet)"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "System information"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "Programmets utförliga logg"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "Det senast skapade start skriptet"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "Spel"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "Ingen mod vald."
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "Ta bort..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "Ta bort..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "Lägg till bot..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "Händelse"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "Ãppna chat"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "Starta nytt spel"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "Markera ord"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "Lägg till bot..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "Ta bort användarkonto"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "Namn på användaren"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "Välj"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "Välj i spelet"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "Sätt åtkomst..."
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "Kunde inte starta webbläsaren."
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "standard"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "Kanal information"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "Starta nytt spel"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "En kort beskrivning, denna kommer visas i spel listan."
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "Beskrivning"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "Välj den mod som ska användas."
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr "Lösenordet som behövs för spelet. Behåll tomt för att inte ha lösenord"
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "Port"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "UDP porten att spela spelet på. Standard är 8452."
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "Modden inte tillgänlig"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "Antal spelare"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "Maximala antalet spelare tillåtna i spelet."
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "Hole punching"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "NAT traversal"
+
+#: src/hostbattledialog.cpp:177
+#, fuzzy
+msgid "NAT traversal to use."
+msgstr "NAT traversal"
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "Minsta rang som behövs"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "Starta spel lobbyn."
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "Du måste välja en mod först."
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "Ingen mod vald."
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "Webbläsare"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "Standard webbläsare"
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "Ange:"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "Bläddra"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "Ã
teranslut"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "Anslut till lobby server"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "&Verktyg"
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "Start metall"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "Ange en webbläsar exekverbar"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "Ange en webbläsar exekverbar"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "Anslut till lobby server"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "Spel lista"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "Spel lobby"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "Alternativ"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "Enhets begränsningar"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "Chat"
+
+#: src/mainoptionstab.cpp:75
+msgid "General"
+msgstr ""
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "Ã
terställ"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "Spara"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "Spel"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "Ladda ner"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "SpringLobby"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "&Koppla upp..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "Koppla &ner..."
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "Kart alternativ"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "&Avsluta"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "&GÃ¥ med kanal..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "Kanal information"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "Ãppna privat &chat fönster..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "&Ladda om kartor/moddar"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "Kolla efter ny &version"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "Spring inställningar"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "&Om"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "Kanal information"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "&Rapportera bugg..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "&Dokumentation"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "&Arkiv"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "&Verktyg"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "&Hjälp"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "Ã
teranslut"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "GÃ¥ med i kanal..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "Namn på kanalen"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "Ãppna privat chat..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "Namn på användaren"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Inga kartor funna"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "Vilket användar konto vill du ta bort idag?"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "Spara..."
+
+#: src/mainwindow.h:184
+msgid "Replays"
+msgstr ""
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "Ladda ner"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "Läs om"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "Ladda ner"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "sida:"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "ally: %d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "bonus: %d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+#, fuzzy
+msgid "Show"
+msgstr "Visa alla"
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "Alla filer"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "Max metal"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "Start positioner"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "Minsta rang som behövs"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "Medelmåttig"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "Spektator"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "Start positioner"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "Start positioner"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"Hur spelare väljer vart de vill starta på kartan\n"
+"0: fixerade kart positioner\n"
+"1: Slumpmässiga kart positioner\n"
+"2: Välja inne i spelet\n"
+"3: Välja i spel lobbyn"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "Välj i spelet"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "Välj i spelet"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "Begränsade enheter"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "Kart alternativ"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "s"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "c"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "r"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "Exekverbara filer (*.exe)|*.exe|Any File (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "Alla filer (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr "Program paket (*.app)|*.app|Alla filer (*.*)|*.*"
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "Hur länge?"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "Välj"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "Smeknamn"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "Smeknamn"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "Hur länge?"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Spring fel"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "&Arkiv"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Ladda..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Spelare:"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "Spara..."
+
+#: src/playback/playbacktab.cpp:286
+#, fuzzy
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"Kunde inte läsa din Spring version från unitsync biblioteket.\n"
+"\n"
+"Multiplayer spel kommer att inaktiveras."
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "Felaktig port"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "Välj"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " Användaren är ner kopplad."
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " Användaren är ner kopplad."
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " gick med i "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "Kunde inte gå med kanal"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "Kunde inte gå med i kanal "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " anledning: "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "Server medelande"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "Du blev ut sparkad från spelet."
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "Ut sparkad ur spelet"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "Spel lista"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "Ladda ner &karta"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"Ett fel uppstod under kontrollen för ny version.\n"
+"Försök igen senare.\n"
+"Om problemet kvarstår var god rapportera detta."
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "PÃ¥minnelse"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "Felaktigt nummer"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Inget nummer"
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "Startade"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "Ã
teranslut"
+
+#: src/serverevents.cpp:999
+msgid "Unknown Error"
+msgstr ""
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "Ingen mod vald."
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "Kunde inte starta webläsaren. URL: "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "Kunde inte starta webbläsaren."
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+#, fuzzy
+msgid "Terrain detail"
+msgstr "Max metal"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "Grass detail"
+msgstr "Max metal"
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "Spel lobby"
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+#, fuzzy
+msgid "Reflective units"
+msgstr "Välj"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+#, fuzzy
+msgid "left is the default"
+msgstr "standard"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+#, fuzzy
+msgid "Use less colors"
+msgstr "Använd systemfärger"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+#, fuzzy
+msgid "Show in-game player information"
+msgstr "System information"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+#, fuzzy
+msgid "Reflective"
+msgstr "Välj"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "Välj"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "Välj"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "Välj"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "Hur länge?"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "Av"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr ""
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr ""
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr ""
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr ""
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr ""
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "Kritiskt fel"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "Ange unitsync bibliotek"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "Alla filer"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "Kunde inte starta webläsaren. URL: "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "Kunde inte starta webbläsaren."
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr ""
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "Lägg till bot..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "Spektator"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "Start positioner"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- Välj en --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "Kunde inte start spel"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "Du måste välja en karta först."
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "Spring körs redan stäng av det innan du startar ett nytt spel"
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "Hej "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+"Det ser ut som om detta är den första gången du använder SpringLobby. Jag "
+"har gissat mig till en konfiguration som jag tror skall fungera men du borde "
+"kolla igenom den för säkerhets skull.\n"
+"När du är klar är det bara att börja spel Spring :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "Välkommen"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "Ingen"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "Spring inställningar"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+"Programmet har genererat ett allvarligt fel och kommer att avslutas.\n"
+"Kan inte generera en bugg rapport.\n"
+"\n"
+"Var god fixa en wxWidgets version som har stöd för wxUSE_DEBUGREPORT"
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "Ãppna chat"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "Spel lista"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "Hitta"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "Spring exekverbar"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "Plats"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "Hitta"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "Unitsync bibliotek"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "Automatisk konfiguration"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "Ange Spring exekverbar"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "Bibliotek"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr ""
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr ""
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "Ladda ner"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "Status:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "Lösenord"
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"Registreringen lyckades,\n"
+"du ska nu kunna logga in."
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "Registreringen lyckades"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "Registreringen misslyckades med meddelandet:\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"Webbläsarens plats är: "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "Hjälp fel"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "Skriv /help i chatten."
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "SpringLobby kommando hjälp."
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "Globala kommandon:"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " \"/away\" - Sätter din status till borta."
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " \"/back\" - Sätter din status till närvarande."
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " \"/channels\" - Listar alla aktiva kanaler."
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr " \"/help [ämne]\" - Visar hjälp om ett visst ämne."
+
+#: src/ui.cpp:495
+#, fuzzy
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+" \"/join kanal [lösenord] [,kanal2 [lösenord22]]\" - Gå med i en kanal "
+"eller flera."
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " \"/j\" - Alias till /join."
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " \"/ingame\" - Visar hur mycket spel tid du har."
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " \"/channels\" - Listar alla aktiva kanaler."
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " \"/j\" - Alias till /join."
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " \"/rename nyttsmeknamn\" - Ãndrar ditt smeknamn."
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " \"/sayver\" - Säger vilken version av SpringLobby du har i chatten."
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " \"/ver\" - Visar vilken version av SpringLobby du har."
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "Chat kommandon:"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " \"/me action\" - Aktions medelande a la IRC."
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr "Om du saknar något kommando, gå till #springlobby och skriv det där :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "Det finns inga ämnen ännu."
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "Ãmnet \""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr "\" hittades inte. Skriv \"/help\" för att se vilka som finns."
+
+#: src/ui.cpp:609
+#, fuzzy
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"Kunde inte läsa din Spring version från unitsync biblioteket.\n"
+"\n"
+"Multiplayer spel kommer att inaktiveras."
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "Multiplayer spel kommer att inaktiveras."
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "Anslut till lobby server"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+msgid "Connection failure"
+msgstr ""
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "inga aktiva chat paneler öppna."
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d användare)"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "Server medelanden"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+"Dina Spring inställningar är förmodligen inte korrekt inställda,\n"
+"du bör ta en titt på dem innan du spelar multiplayer."
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Spring inställnings fel"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Ett fel uppstod under kontrollen för ny version.\n"
+"Försök igen senare.\n"
+"Om problemet kvarstår var god rapportera detta."
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "Er version: "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "Senaste versionen: "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"Du har en äldre version av SpringLobby.\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "Inte uppdaterad"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "Inte uppdaterad"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+#, fuzzy
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"Ett fel uppstod under kontrollen för ny version.\n"
+"Försök igen senare.\n"
+"Om problemet kvarstår var god rapportera detta."
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, fuzzy, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"Ett fel uppstod under kontrollen för ny version.\n"
+"Försök igen senare.\n"
+"Om problemet kvarstår var god rapportera detta."
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "Ingen"
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "Markering"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "GÃ¥ med samma spel"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+#, fuzzy
+msgid "no action at all"
+msgstr "inga aktiva chat paneler öppna."
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+msgid "away"
+msgstr ""
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "Smeknamn"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "Ny nybörjare"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "Nybörjare"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "Medelmåttig"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "Duktig"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "Erfaren"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "Mycket erfaren"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "Veteran"
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "Lägg till bot..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "Ta bort användarkonto"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+msgid "Author"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Din Spring version"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "Ladda ner"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "Avbryt"
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "Spektatorer:"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "Team"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "Allians"
+
+#~ msgid "cpu"
+#~ msgstr "cpu"
+
+#~ msgid "Test firewall"
+#~ msgstr "Testa firewallen"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "Chat stängd."
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "Kart alternativ"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "Välj i spelet"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "Ingen mod vald."
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "Koppla ned"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "Spelare:"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "Välj färg"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "Händelse"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "p"
+
+#~ msgid "m"
+#~ msgstr "m"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "t"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr "Numret ligger utanför intervallet 0 och 100."
+
+#~ msgid "Bot team sharing."
+#~ msgstr "Bot team delning."
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "Antal spelare"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "Kanal information"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "Ãmnet \""
+
+#~ msgid ""
+#~ "You're using a wxwidgets library of the 2.6.x series\n"
+#~ " battle filtering, advanced gui and joining/hosting games using nat "
+#~ "traversal\n"
+#~ " won't be available"
+#~ msgstr ""
+#~ "Du använder en wxWidgets version i 2.6.x serien\n"
+#~ "vissa funktioner kommer att bli avstängda. Skaffa\n"
+#~ "en nyare version för att få full funktionalitet."
+
+#~ msgid "Missing Functionality"
+#~ msgstr "Saknad funktionalitet"
+
+#, fuzzy
+#~ msgid "Do nothing"
+#~ msgstr "Hole punching"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "Anslut till lobby server"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "Inte uppkopplad."
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "Det här spelet använder NAT traversal som inte stödjs för wxWidgets 2.6.x."
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "Felaktigt host/port eller servernamn."
+
+#~ msgid "Active chat channels:"
+#~ msgstr "Aktiva chat kanaler:"
+
+#~ msgid "no rank"
+#~ msgstr "ingen rank"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "Spel lista"
+
+#~ msgid "Select all"
+#~ msgstr "Markera allt"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d användare)"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "Ingen mod vald."
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "Felaktigt nummer"
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "En kort beskrivning, denna kommer visas i spel listan."
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "Välj den mod som ska användas."
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "Normal"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "Unitsync bibliotek"
+
+#~ msgid ""
+#~ "Please enter password needed to join this channel, leave blank for no "
+#~ "passwrd."
+#~ msgstr ""
+#~ "Var vänlig skriv in kanalen lösenord om detta behövs, annars lämnar du "
+#~ "det tomt."
+
+#~ msgid "Fixed source ports"
+#~ msgstr "Fixed source ports"
+
+#~ msgid ""
+#~ "NAT traversal to use, currently this feature is not supported by "
+#~ "SpringLobby."
+#~ msgstr ""
+#~ "NAT traversal att använda, detta stöds för tillfället inte av SpringLobby."
+
+#~ msgid "&Edit"
+#~ msgstr "&Redigera"
+
+#~ msgid "LuaAI"
+#~ msgstr "LuaAI"
+
+#~ msgid "Bot%d"
+#~ msgstr "Bot%d"
+
+#~ msgid "%Y-%m-%d %H:%M"
+#~ msgstr "%Y-%m-%d %H:%M"
+
+#~ msgid "["
+#~ msgstr "["
+
+#~ msgid "%H:%M"
+#~ msgstr "%H:%M"
+
+#~ msgid "?"
+#~ msgstr "?"
+
+#~ msgid "..."
+#~ msgstr "..."
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "Fortsätt on din commander dör"
+
+#~ msgid "End if commander dies"
+#~ msgstr "Avsluta don din commander dör"
+
+#~ msgid "End condition"
+#~ msgstr "Spelets avslutning"
+
+#~ msgid "Resources"
+#~ msgstr "Resurser"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "Hur mycket metall varje spelare startar med."
+
+#~ msgid "Start Energy"
+#~ msgstr "Start energi"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "Hur mycket energi varje spelare startar med."
+
+#~ msgid "Max units"
+#~ msgstr "Max enheter"
+
+#~ msgid "Limit d-gun"
+#~ msgstr "Begränsa d-gun"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "Spök byggnader"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "Av tagande metall skapare"
+
+#~ msgid "Save to:"
+#~ msgstr "Spara till:"
+
+#~ msgid "Browse..."
+#~ msgstr "Bläddra..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "Välj en katalog"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "Kart/mod alternativ"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "Din SpringLobby version är redan uppdaterad.\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "Uppdaterad"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "Vill du gå till sidan som beskriver hur du uppdaterar?"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "Begränsa d-gun"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr ""
+#~ "Stänger av en commanders D-gun nät han går för långt från sin start "
+#~ "position"
+
+#~ msgid "Ghosted Buildings"
+#~ msgstr "Spök byggnader"
+
+#~ msgid ""
+#~ "Enemy buildings will leave a ghost image on the map after losing LoS on "
+#~ "them"
+#~ msgstr ""
+#~ "Fientliga byggnader lämna en spökbild på kartan efter att de kommit utom "
+#~ "synhåll"
+
+#~ msgid "Diminishing MM"
+#~ msgstr "Avtagande MM"
+
+#~ msgid ""
+#~ "Efficiency of MetalMakers will progressively reduce as much as you build "
+#~ "them"
+#~ msgstr "Effektiviteten av dina metall skapare sjunker ju fler du bygger"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "Spelets avslutning"
+
+#~ msgid ""
+#~ "The condition that will end the game\n"
+#~ "0: when all units will be destroyed\n"
+#~ "1: when the commander will be destroyed\n"
+#~ "2: lineage mode (see option 1, but given away units will still die"
+#~ msgstr ""
+#~ "Spelet avlutnings villkor\n"
+#~ "0: Alla enheter döda\n"
+#~ "1: När commandern dör\n"
+#~ "2: lineage mode"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "Hur mycket metall en spelare startar med"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "Hur mycket energi en spelare startar med"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "Max antal enheter"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "Maximalt antal enheter en spelare kan ha"
+
+#~ msgid "Reset"
+#~ msgstr "Ã
terställ"
+
+#~ msgid ""
+#~ "You have bots that are not assingled to startpositions. In the current "
+#~ "version of spring you are only allowed to use start positions positioning "
+#~ "them freely is not allowed.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "Du har botar som inte är knutna till någon startposition. I denna "
+#~ "versionen av Spring är detta inte tillåtet."
+
+#~ msgid ""
+#~ "You are not using consecutive start position numbers.\n"
+#~ "\n"
+#~ "In the current version of spring you are not allowed to skip any "
+#~ "startpositions. You have to use all consecutive position.\n"
+#~ "\n"
+#~ "Example: if you have 2 bots + yourself you have to use start positions "
+#~ "1,2,3 not 1,3,4 or 2,3,4.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "Du använder inte konsekutiva startpositions nummer, detta krävs i den här "
+#~ "versionen av Spring."
+
+#~ msgid "Spring directory"
+#~ msgstr "Spring katalogen"
+
+#~ msgid "Default location."
+#~ msgstr "Standard plats"
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "supportras inte av lobby servern som kräver version"
+
+#~ msgid ""
+#~ "This is the SpringLobby channel, please report any problems you are "
+#~ "having with SpringLobby here and the friendly developers will help you."
+#~ msgstr ""
+#~ "Det här är SpringLobby kanalen, var god rapportera alla problem du har i "
+#~ "denna kanalen, så hjälper de välliga utvecklarna dig."
diff --git a/po/uk.gmo b/po/uk.gmo
new file mode 100644
index 0000000..9ebe976
Binary files /dev/null and b/po/uk.gmo differ
diff --git a/po/uk.po b/po/uk.po
new file mode 100644
index 0000000..6aa7e9c
--- /dev/null
+++ b/po/uk.po
@@ -0,0 +1,5856 @@
+# Ukrainian translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-07-30 23:43+0000\n"
+"Last-Translator: SpringLobby_Buildbot <Unknown>\n"
+"Language-Team: Ukrainian <uk at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "ÐодаÑи боÑа"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "ШÐ:"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "ÐбеÑÑÑÑ Ð±ÑблÑоÑÐµÐºÑ ÑÑÑÑного ÑнÑелекÑÑ Ð´Ð»Ñ ÑÑого боÑа"
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+msgid "value"
+msgstr ""
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "СкаÑÑваÑи"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "ÐодаÑи боÑа"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "У ваÑÐ¾Ð¼Ñ Spring Ð½ÐµÐ¼Ð°Ñ Ð¶Ð¾Ð´Ð½Ð¾Ð³Ð¾ боÑа"
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "Ðе знайдено бÑблÑоÑек боÑÑв"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "ÐÑийнÑÑи ÑгодÑ"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "Ðи пÑиймаÑÑе Ñмови ÑÑÑÑ Ñгоди?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "Так"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "ÐÑ"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "ÐвÑомаÑиÑне баланÑÑÐ²Ð°Ð½Ð½Ñ Ð³ÑавÑÑв по командам"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr ""
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "РозподÑлиÑи Ñанги ÑÑвно"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "Ðипадково"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "Ðлани"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "ÐемаÑ"
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "ЧеÑно"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "Ðавжди"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+
+#: src/autobalancedialog.cpp:53
+msgid "Number of allies"
+msgstr ""
+
+#: src/autobalancedialog.cpp:56
+msgid "Auto select"
+msgstr ""
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "ÐаÑазд"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "ÐпиÑ"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "Ðапа"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "ÐодиÑÑкаÑÑÑ"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "ХоÑÑ"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "СпоÑÑеÑÑгаÑÑ:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "ÐÑавÑÑ:"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "Ðапа"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "СкаÑаÑи &мапÑ"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr ""
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "СпоÑÑеÑÑгаÑÑ:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "ÐÑавÑÑ:"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "ХоÑÑ:"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "СÑан:"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "Ðаблоковано"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "ÐаÑ
иÑено паÑолем"
+
+#: src/battlelistfilter.cpp:122
+msgid "Highlighted only"
+msgstr ""
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "ÐÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾ ÑангÑ:"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "ÐпиÑ:"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "РозпоÑаÑо"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "ÐоÑÑгнÑÑо макÑ. кÑлÑкÑÑÑÑ Ð³ÑавÑÑв"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "ÐÑдкÑиÑо"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "ÐÑавеÑÑ:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "УÑÑ"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "Ðапа:"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "ТÑлÑки мапи, Ñо Ñ Ñ Ð¼ÐµÐ½Ðµ"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "ÐакÑ.гÑавÑÑв:"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "ÐодиÑÑкаÑÑÑ:"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "ТÑлÑки модиÑÑкаÑÑÑ, Ñо Ñ Ñ Ð¼ÐµÐ½Ðµ"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " СпоÑÑеÑÑгаÑ:"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr ""
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "ÐÑавÑÑ:"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+msgid " Filter "
+msgstr ""
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "РозпоÑаÑо"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+msgid " Battle infos "
+msgstr ""
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "СÑвоÑиÑи Ð½Ð¾Ð²Ñ Ð³ÑÑ"
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "ÐÑиÑднаÑиÑÑ"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr ""
+"Ðи не можеÑе ÑÑвоÑиÑи Ð½Ð¾Ð²Ñ Ð³ÑÑ, не пÑд'ÑднавÑиÑÑ Ð´Ð¾ ÑеÑвеÑÑ. ÐÑÐ´Ñ Ð»Ð°Ñка, "
+"зайдÑÑÑ Ð½Ð° ÑеÑвеÑ."
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "Ðе ÐÑдклÑÑено"
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "Ðи не можеÑе ÑÑвоÑиÑи гÑÑ ÑеÑез неÑÑмÑÑнÑÑÑÑ ÐаÑÐ¾Ñ Ð²ÐµÑÑÑÑ"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Ðомилка Spring"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr ""
+"Ðи вже маÑÑе копÑÑ Spring Ñ Ð·Ð°Ð¿ÑÑÐµÐ½Ð½Ð¾Ð¼Ñ ÑÑанÑ, Ð´Ð»Ñ ÑÑвоÑÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ Ð³Ñи ÑÑ "
+"ÑÑеба закÑиÑи"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "Ðже Ñ Ð±Ð¸ÑвÑ"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"Ðи вже Ñ Ð±Ð¸ÑвÑ.\n"
+"Ðи дÑйÑно бажаÑÑе залиÑиÑи поÑоÑÐ½Ñ Ð±Ð¸ÑÐ²Ñ Ñа ÑÑвоÑиÑи новÑ?"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"ÐиÑÐ²Ñ Ð½Ðµ ÑозпоÑаÑо ÑеÑез неможливÑÑÑÑ Ð¾Ð±Ñаного (%d) поÑÑÑ Ð¿ÑиймаÑи пакеÑи. "
+"ÐеÑевÑÑÑе налаÑÑÑÐ²Ð°Ð½Ð½Ñ Ð¼ÐµÑежевого екÑÐ°Ð½Ñ Ñа ÑлÑÐ·Ñ Ð°Ð±Ð¾ змÑнÑÑÑ Ð¿Ð¾ÑÑ. ЯкÑо "
+"нÑÑого не допомогло, задÑйÑе Ñ Ð½Ð°Ð»Ð°ÑÑÑваннÑÑ
опÑÑÑ \"Hole Punching NAT "
+"Traversal\"."
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "ÐиÑÐ²Ñ Ð½Ðµ ÑозпоÑаÑо ÑеÑез неможливÑÑÑÑ Ð·Ð½Ð°Ð¹Ñи обÑÐ°Ð½Ñ Ð¼Ð¾Ð´Ð¸ÑÑкаÑÑÑ. "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "Ðомилка пÑи запÑÑÐºÑ Ð±Ð¸Ñви."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr ""
+"Ðе Ð¼Ð¾Ð¶Ñ Ð·Ð½Ð°Ð¹Ñи Ð¶Ð¾Ð´Ð½Ð¾Ñ ÐºÐ°ÑÑи Ñ Ð²Ð°ÑÐ¾Ð¼Ñ Spring. Ðожливо ви вказали невÑÑний "
+"ÑлÑÑ
до диÑекÑоÑÑÑ Spring."
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "Ðе знайдено Ð¶Ð¾Ð´Ð½Ð¾Ñ Ð¼Ð°Ð¿Ð¸"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr ""
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "Ðже Ñ Ð±Ð¸ÑвÑ"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"Ðи вже Ñ Ð±Ð¸ÑвÑ.\n"
+"Ðи дÑйÑно бажаÑÑе залиÑиÑи поÑоÑÐ½Ñ Ð±Ð¸ÑÐ²Ñ Ñа ÑÑвоÑиÑи новÑ?"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "Ðже Ñ Ð±Ð¸ÑвÑ"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"Ðи вже Ñ Ð±Ð¸ÑвÑ.\n"
+"Ðи дÑйÑно бажаÑÑе залиÑиÑи поÑоÑÐ½Ñ Ð±Ð¸ÑÐ²Ñ Ñа ÑÑвоÑиÑи новÑ?"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr ""
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr ""
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr ""
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr ""
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr ""
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr ""
+
+#: src/battlemaptab.cpp:69
+msgid "Select"
+msgstr ""
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr ""
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr ""
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr ""
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr ""
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr ""
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr ""
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr ""
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr ""
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr ""
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr ""
+
+#: src/battlemaptab.cpp:103
+msgid "Chose before game"
+msgstr ""
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr ""
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr ""
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr ""
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:76
+msgid "Disable selected units."
+msgstr ""
+
+#: src/battleoptionstab.cpp:80
+msgid "Re-enable selected units."
+msgstr ""
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr ""
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr ""
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+msgid "Unit restriction"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "ÐодаÑи боÑа"
+
+#: src/battleroomlistctrl.cpp:719
+msgid "Human\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "СпоÑÑеÑÑгаÑÑ:"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "ÐÑавеÑÑ:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "ХоÑÑ"
+
+#: src/battleroomlistctrl.cpp:729
+msgid "Client\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "Ðавжди"
+
+#: src/battleroomlistctrl.cpp:734
+msgid "Not ready\n"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:737
+msgid "In sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+msgid "Set name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:63
+msgid "Load a saved set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:67
+msgid "Save..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+msgid "Save a set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:72
+msgid "Delete..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+msgid "Delete a set of options."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:77
+msgid "Set default..."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:152
+msgid "no options available"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+msgid "Delete preset"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+msgid "Set mod default preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr ""
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr ""
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr ""
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr ""
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr ""
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr ""
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr ""
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr ""
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr ""
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr ""
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr ""
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr ""
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr ""
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+msgid "AutoSpect"
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "РозпоÑаÑо"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "Lock Balance"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Ring unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+msgid "Ring ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "СпоÑÑеÑÑгаÑÑ:"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+msgid "Force spectate ..."
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Balance alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr ""
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid "Balance teams"
+msgstr ""
+
+#: src/battleroomtab.cpp:245
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr ""
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+msgid "Save"
+msgstr ""
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+msgid "Delete"
+msgstr ""
+
+#: src/battleroomtab.cpp:269
+msgid "Set default"
+msgstr ""
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr ""
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr ""
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr ""
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr ""
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr ""
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+msgid "Set Timeout"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:25
+msgid "Edit auto-joined channels"
+msgstr ""
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+msgid "Find channel:"
+msgstr ""
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+msgid "Choose channels to join"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "СкаÑÑваÑи"
+
+#: src/channel/channellistctrl.cpp:29
+msgid "# users"
+msgstr ""
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr ""
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr ""
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr ""
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr ""
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr ""
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr ""
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr ""
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr ""
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr ""
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr ""
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr ""
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr ""
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr ""
+
+#: src/chatoptionstab.cpp:259
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr ""
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr ""
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr ""
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr ""
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr ""
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr ""
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr ""
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr ""
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr ""
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr ""
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr ""
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, c-format
+msgid "%d users"
+msgstr ""
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr ""
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr ""
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr ""
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+#, fuzzy
+msgid "Clear"
+msgstr "Ðлани"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr ""
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr ""
+
+#: src/chatpanel.cpp:433
+msgid "Show mute list"
+msgstr ""
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr ""
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr ""
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr ""
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr ""
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr ""
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr ""
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr ""
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr ""
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr ""
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr ""
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr ""
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr ""
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr ""
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr ""
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr ""
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr ""
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr ""
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr ""
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr ""
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr ""
+
+#: src/chatpanel.cpp:510
+msgid "User"
+msgstr ""
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr ""
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr ""
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr ""
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr ""
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr ""
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr ""
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr ""
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr ""
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr ""
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr ""
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr ""
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr ""
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr ""
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr ""
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr ""
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr ""
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr ""
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr ""
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr ""
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr ""
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr ""
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr ""
+
+#: src/chatpanel.cpp:1029
+msgid " ** Channel topic:"
+msgstr ""
+
+#: src/chatpanel.cpp:1036
+msgid " ** Set by "
+msgstr ""
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr ""
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr ""
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr ""
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr ""
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr ""
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr ""
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr ""
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr ""
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr ""
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr ""
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr ""
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr ""
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr ""
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr ""
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr ""
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr ""
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr ""
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr ""
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr ""
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr ""
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr ""
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr ""
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr ""
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr ""
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr ""
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr ""
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr ""
+
+#: src/chatpanel.cpp:1797
+msgid "couldn't add user"
+msgstr ""
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr ""
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr ""
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr ""
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr ""
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr ""
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr ""
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr ""
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr ""
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr ""
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr ""
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr ""
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr ""
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+msgid "Invalid nickname"
+msgstr ""
+
+#: src/connectwindow.cpp:300
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr ""
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr ""
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr ""
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr ""
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr ""
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr ""
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr ""
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr ""
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr ""
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr ""
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr ""
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr ""
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr ""
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr ""
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr ""
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr ""
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr ""
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr ""
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr ""
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr ""
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr ""
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr ""
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr ""
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr ""
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr ""
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr ""
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr ""
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr ""
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr ""
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr ""
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr ""
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr ""
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr ""
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr ""
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr ""
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr ""
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr ""
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr ""
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr ""
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr ""
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr ""
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr ""
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr ""
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr ""
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr ""
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr ""
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr ""
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr ""
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr ""
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr ""
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr ""
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr ""
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr ""
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr ""
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr ""
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr ""
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr ""
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr ""
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr ""
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr ""
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr ""
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr ""
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr ""
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr ""
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr ""
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr ""
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr ""
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr ""
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr ""
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr ""
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr ""
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr ""
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr ""
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr ""
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr ""
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr ""
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr ""
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr ""
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr ""
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr ""
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr ""
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr ""
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr ""
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr ""
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr ""
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr ""
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr ""
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr ""
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr ""
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr ""
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr ""
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr ""
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr ""
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr ""
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr ""
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr ""
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr ""
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr ""
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr ""
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr ""
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr ""
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr ""
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr ""
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr ""
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr ""
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr ""
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr ""
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr ""
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr ""
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr ""
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr ""
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr ""
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr ""
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr ""
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr ""
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr ""
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr ""
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr ""
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr ""
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr ""
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr ""
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr ""
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr ""
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr ""
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr ""
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr ""
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr ""
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr ""
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr ""
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr ""
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr ""
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr ""
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr ""
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr ""
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr ""
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr ""
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr ""
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr ""
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr ""
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr ""
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr ""
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr ""
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr ""
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr ""
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr ""
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr ""
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr ""
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr ""
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr ""
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr ""
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr ""
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr ""
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr ""
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr ""
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr ""
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr ""
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr ""
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr ""
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr ""
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr ""
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr ""
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr ""
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr ""
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr ""
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr ""
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr ""
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr ""
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr ""
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr ""
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr ""
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr ""
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr ""
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr ""
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr ""
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr ""
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr ""
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr ""
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr ""
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr ""
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr ""
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr ""
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr ""
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr ""
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr ""
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr ""
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr ""
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr ""
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr ""
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr ""
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr ""
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr ""
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr ""
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr ""
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr ""
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr ""
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr ""
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr ""
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr ""
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr ""
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr ""
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr ""
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr ""
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr ""
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr ""
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr ""
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr ""
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr ""
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr ""
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr ""
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr ""
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr ""
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr ""
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr ""
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr ""
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr ""
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr ""
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr ""
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr ""
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr ""
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr ""
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr ""
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr ""
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr ""
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr ""
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr ""
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr ""
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr ""
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr ""
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr ""
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+msgid "Search and download files"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "СкаÑаÑи &мапÑ"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+msgid "unknown hash "
+msgstr ""
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+msgid "Remove"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+msgid "Rename.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+msgid "Add New.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+msgid "Group Actions"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+msgid "Ignore Chat"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+msgid "Notify Hosted Battles"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+msgid "Highlight Color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+msgid "Add.."
+msgstr ""
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+msgid "Remove users from group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Name of new group:"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+msgid "delete"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/Helper/imageviewer.cpp:167
+msgid "File successfully saved"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+msgid "Success"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:170
+msgid "Couldn't save file"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+msgid "Default"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+msgid "Select the language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:146
+msgid "Language"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr ""
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr ""
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "ÐпиÑ"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr ""
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr ""
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr ""
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr ""
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Randomly picks an available one"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr ""
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr ""
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr ""
+
+#: src/hostbattledialog.cpp:177
+msgid "NAT traversal to use."
+msgstr ""
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr ""
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr ""
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:78
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+msgid "Use a file dialog to find the editor binary"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:90
+msgid "Autoconnect"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+msgid "Autoconnect on lobby start"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+msgid "Tooltips"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:121
+msgid "Show Tooltips?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+msgid "Match exact"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "РозпоÑаÑо"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:247
+msgid "Choose a editor browser executable"
+msgstr ""
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+msgid "Disconnected from server, chat closed."
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr ""
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+msgid "Unit Restrictions"
+msgstr ""
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr ""
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr ""
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr ""
+
+#: src/mainoptionstab.cpp:75
+msgid "General"
+msgstr ""
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr ""
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr ""
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr ""
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr ""
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr ""
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr ""
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "СкаÑаÑи &мапÑ"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr ""
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr ""
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr ""
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr ""
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr ""
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr ""
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr ""
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr ""
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr ""
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr ""
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr ""
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr ""
+
+#: src/mainwindow.cpp:133
+msgid "&Save options"
+msgstr ""
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr ""
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:151
+msgid "Channel &list"
+msgstr ""
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr ""
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr ""
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr ""
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr ""
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr ""
+
+#: src/mainwindow.cpp:168
+msgid "&Change language"
+msgstr ""
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr ""
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr ""
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr ""
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr ""
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+msgid "Not connected"
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr ""
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr ""
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr ""
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr ""
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "Ðе знайдено Ð¶Ð¾Ð´Ð½Ð¾Ñ Ð¼Ð°Ð¿Ð¸"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr ""
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+msgid "Which profile do you want to be default?"
+msgstr ""
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+msgid "Savegames"
+msgstr ""
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "Ðавжди"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "СкаÑаÑи &мапÑ"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr ""
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr ""
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr ""
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr ""
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr ""
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "ЧеÑно"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+msgid "Map details"
+msgstr ""
+
+#: src/mapselectdialog.cpp:162
+msgid "Start positions"
+msgstr ""
+
+#: src/mapselectdialog.cpp:265
+msgid "Minimum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+msgid "Average wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "СпоÑÑеÑÑгаÑÑ:"
+
+#: src/mapselectdialog.cpp:270
+msgid "Number of start positions"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:121
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/mmoptionswrapper.cpp:131
+msgid "List of restricted units"
+msgstr ""
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+msgid "Change option"
+msgstr ""
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr ""
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr ""
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr ""
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr ""
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:60
+msgid "Filter settings"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:164
+msgid "Filesize in KB:"
+msgstr ""
+
+#: src/playback/playbackfilter.cpp:190
+msgid "Duration (hh:mm:ss):"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "ÐпиÑ"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Ðомилка Spring"
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:47
+msgid "Filesize in kilobyte"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "Ðаблоковано"
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "Ðавжди"
+
+#: src/playback/playbacktab.cpp:278
+msgid "savegame"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:286
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid "Invalid replay"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+msgid "Select Users"
+msgstr ""
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+msgid " is online"
+msgstr ""
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr ""
+
+#: src/serverevents.cpp:225
+msgid " just went offline"
+msgstr ""
+
+#: src/serverevents.cpp:260
+msgid " opened battle "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr ""
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr ""
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr ""
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr ""
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr ""
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr ""
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, c-format
+msgid "%s mutelist"
+msgstr ""
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "СкаÑаÑи &мапÑ"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+msgid "Negotiation error"
+msgstr ""
+
+#: src/serverevents.cpp:984
+msgid "Invalid Value"
+msgstr ""
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "Ðе ÐÑдклÑÑено"
+
+#: src/serverevents.cpp:990
+msgid "File doesn't exit"
+msgstr ""
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "РозпоÑаÑо"
+
+#: src/serverevents.cpp:996
+msgid "Reconnection Error"
+msgstr ""
+
+#: src/serverevents.cpp:999
+msgid "Unknown Error"
+msgstr ""
+
+#: src/serverevents.cpp:1009
+msgid "Download complete, location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "СкаÑаÑи &мапÑ"
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer. File location is: "
+msgstr ""
+
+#: src/serverevents.cpp:1016
+msgid "Couldn't launch installer."
+msgstr ""
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr ""
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "Unit LOD distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:227
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr ""
+
+#: src/settings++/Defs.hpp:228
+msgid "higher value = more detailed grass"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr ""
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr ""
+
+#: src/settings++/Defs.hpp:233
+msgid "Max nano simultaneous particles"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr ""
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "Enable v-sync"
+msgstr ""
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr ""
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "Full-scene anti-aliasing samples"
+msgstr ""
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "Master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:271
+msgid "master sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "General sound volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:272
+msgid "general volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:273
+msgid "reply volume relative to master volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "Battle volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:274
+msgid "battle volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "User interface volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:275
+msgid "ui volume relative to global volume"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr ""
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr ""
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr ""
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr ""
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr ""
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr ""
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr ""
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr ""
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr ""
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr ""
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr ""
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr ""
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr ""
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr ""
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr ""
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr ""
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr ""
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr ""
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr ""
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr ""
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr ""
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr ""
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr ""
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr ""
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr ""
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr ""
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr ""
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr ""
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr ""
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr ""
+
+#: src/settings++/Defs.hpp:413
+msgid "Blur reflection"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Shore waves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+msgid "Enables shorewaves"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+msgid "Reflection"
+msgstr ""
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+msgid "Reflection texture size"
+msgstr ""
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "ÐпиÑ"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "off"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr ""
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr ""
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr ""
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr ""
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr ""
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr ""
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr ""
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr ""
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr ""
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr ""
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr ""
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr ""
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr ""
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr ""
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr ""
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr ""
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr ""
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr ""
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr ""
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr ""
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr ""
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr ""
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr ""
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr ""
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr ""
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr ""
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr ""
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr ""
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr ""
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr ""
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr ""
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr ""
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "СпоÑÑеÑÑгаÑÑ:"
+
+#: src/singleplayertab.cpp:103
+msgid "Random start positions"
+msgstr ""
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr ""
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr ""
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr ""
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr ""
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "ÐемаÑ"
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+msgid "Import settings?"
+msgstr ""
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+msgid "Ignore chat"
+msgstr ""
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+msgid "Battle Autokick"
+msgstr ""
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+msgid "Friends"
+msgstr ""
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr ""
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr ""
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr ""
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr ""
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr ""
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr ""
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr ""
+
+#: src/springoptionstab.cpp:277
+msgid "Data dir wizard"
+msgstr ""
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr ""
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr ""
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr ""
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+msgid "Numcopies"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:48
+msgid "MB downloaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "СÑан:"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr ""
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr ""
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr ""
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+msgid "Torrent system failure"
+msgstr ""
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr ""
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr ""
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr ""
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr ""
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr ""
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr ""
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr ""
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr ""
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr ""
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr ""
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr ""
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr ""
+
+#: src/ui.cpp:495
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr ""
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr ""
+
+#: src/ui.cpp:497
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr ""
+
+#: src/ui.cpp:498
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr ""
+
+#: src/ui.cpp:499
+msgid " \"/part\" - Leaves current channel."
+msgstr ""
+
+#: src/ui.cpp:500
+msgid " \"/p\" - Alias to /part."
+msgstr ""
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr ""
+
+#: src/ui.cpp:502
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr ""
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr ""
+
+#: src/ui.cpp:504
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr ""
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr ""
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr ""
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr ""
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr ""
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr ""
+
+#: src/ui.cpp:609
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+msgid "Online play is currently disabled."
+msgstr ""
+
+#: src/ui.cpp:661
+msgid "Disconnected from server."
+msgstr ""
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+msgid "Connection failure"
+msgstr ""
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr ""
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr ""
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr ""
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr ""
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr ""
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+msgid "Not up to date"
+msgstr ""
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr ""
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "ÐемаÑ"
+
+#: src/useractions.h:11
+msgid "highlight"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify hosted battle"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "no action at all"
+msgstr ""
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "Ðавжди"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "ÐÑÑзвиÑÑко:"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr ""
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr ""
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr ""
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr ""
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr ""
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr ""
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr ""
+
+#: src/user.cpp:195
+msgid "Unknown"
+msgstr ""
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+msgid "Add to group..."
+msgstr ""
+
+#: src/usermenu.h:30
+msgid "Remove from group"
+msgstr ""
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+msgid "Author"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "Ðомилка Spring"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "СкаÑаÑи &мапÑ"
+
+#: src/widgets/infopanel.cpp:84
+msgid "Published on"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "СкаÑÑваÑи"
+
+#: src/widgets/infopanel.cpp:126
+msgid "Screenshots"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "СпоÑÑеÑÑгаÑÑ:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "ÐÑавÑÑ:"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "СкаÑаÑи &мапÑ"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "ÐÑавеÑÑ:"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "Ðомилка Spring"
diff --git a/po/zh_CN.gmo b/po/zh_CN.gmo
new file mode 100644
index 0000000..ec835ad
Binary files /dev/null and b/po/zh_CN.gmo differ
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644
index 0000000..73c69be
--- /dev/null
+++ b/po/zh_CN.po
@@ -0,0 +1,6669 @@
+# Simplified Chinese translation for springlobby
+# Copyright (c) 2008 Rosetta Contributors and Canonical Ltd 2008
+# This file is distributed under the same license as the springlobby package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, 2008.
+#
+#: src/battleroomlistctrl.cpp:714 src/hostbattledialog.cpp:129
+#: src/settings++/Defs.hpp:263 src/settings++/Defs.hpp:345
+#: src/settings++/Defs.hpp:347 src/settings++/Defs.hpp:349
+#: src/settings++/Defs.hpp:351 src/settings++/Defs.hpp:353
+#: src/settings++/Defs.hpp:404 src/settings++/Defs.hpp:405
+#: src/settings++/Defs.hpp:413 src/settings++/Defs.hpp:418
+#: src/settings++/Defs.hpp:421
+msgid ""
+msgstr ""
+"Project-Id-Version: springlobby\n"
+"Report-Msgid-Bugs-To: devel at www.springlobby.info\n"
+"POT-Creation-Date: 2009-10-23 16:45+0200\n"
+"PO-Revision-Date: 2008-09-15 13:38+0000\n"
+"Last-Translator: rainofchaos <rainofchaos at gmail.com>\n"
+"Language-Team: Simplified Chinese <zh_CN at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2008-09-20 21:32+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#: src/addbotdialog.cpp:32
+msgid "Add bot"
+msgstr "æ·»å AI"
+
+#: src/addbotdialog.cpp:44
+msgid "Nickname:"
+msgstr "æµç§°ï¼"
+
+#: src/addbotdialog.cpp:57
+msgid "AI:"
+msgstr "AIï¼"
+
+#: src/addbotdialog.cpp:61
+msgid "Choose the AI library to use with this bot."
+msgstr "éæ©è¯¥AIæ使ç¨çåºæ件ã"
+
+#: src/addbotdialog.cpp:71 src/addbotdialog.cpp:81
+msgid "property"
+msgstr ""
+
+#: src/addbotdialog.cpp:75 src/addbotdialog.cpp:85
+#, fuzzy
+msgid "value"
+msgstr "å¼"
+
+#: src/addbotdialog.cpp:108 src/autobalancedialog.cpp:65
+#: src/connectwindow.cpp:87 src/hostbattledialog.cpp:243
+#: src/mmoptionwindows.cpp:106
+msgid "Cancel"
+msgstr "åæ¶"
+
+#: src/addbotdialog.cpp:113
+msgid "Add Bot"
+msgstr "æ·»å AI"
+
+#: src/addbotdialog.cpp:191
+msgid "No AI bots found in your Spring installation."
+msgstr "ä½ å½åçSpringä¸æ²¡æAI"
+
+#: src/addbotdialog.cpp:191
+msgid "No bot-libs found"
+msgstr "AIåºæ件æªæ¾å°"
+
+#: src/agreementdialog.cpp:24
+msgid "Accept Agreement"
+msgstr "æ¥ååè®®"
+
+#: src/agreementdialog.cpp:33
+msgid "Do you accept the terms of this agreement?"
+msgstr "ä½ æ¥ååè®®ä¸çæ¡æ¬¾å?"
+
+#: src/agreementdialog.cpp:41
+msgid "Yes"
+msgstr "æ¯"
+
+#: src/agreementdialog.cpp:46
+msgid "No"
+msgstr "å¦"
+
+#: src/autobalancedialog.cpp:36
+msgid "Autobalance players into teams"
+msgstr "èªå¨å¹³è¡¡éä¼"
+
+#: src/autobalancedialog.cpp:39
+msgid "Method"
+msgstr "æ¹æ³"
+
+#: src/autobalancedialog.cpp:42
+msgid "Divide ranks evenly"
+msgstr "æç©å®¶çº§å«å¹³å"
+
+#: src/autobalancedialog.cpp:43 src/battlemaptab.cpp:103
+#: src/battleroomtab.cpp:436 src/mmoptionswrapper.cpp:123
+msgid "Random"
+msgstr "éæº"
+
+#: src/autobalancedialog.cpp:45
+msgid "Clans"
+msgstr "æ´¾å«"
+
+#: src/autobalancedialog.cpp:48 src/hostbattledialog.cpp:169
+msgid "None"
+msgstr "æ "
+
+#: src/autobalancedialog.cpp:49
+msgid "Fair"
+msgstr "ä¸è¬"
+
+#: src/autobalancedialog.cpp:50
+msgid "Always"
+msgstr "æ»æ¯"
+
+#: src/autobalancedialog.cpp:51
+msgid ""
+"Put members of same clan ( users having same clantag, like '[smurfzor]Alice' "
+"and '[smurfzor]Bob' ) together into same alliance. \n"
+"None: nothing special for clans.\n"
+"Fair: put clanmembers into alliance, unless this makes alliances unfair.\n"
+"Always: always put clanmembers into alliance, even if that alliance is "
+"unfair."
+msgstr ""
+"å°åä¸ä¸ªæ´¾å«çæåï¼ä¾å¦â[smurfzor]Aliceâåâ[smurfzor]Bobâï¼å½å
¥åä¸èçã \n"
+"æ ï¼åæ´¾å«æåä¸åå½±åã\n"
+"ä¸è¬ï¼å°åæ´¾å«æåå å
¥èçï¼é¤éèçå®åæ¬æ®ã\n"
+"æ»æ¯ï¼æ»æ¯å°åæ´¾å«æåå½å
¥åä¸èçï¼æ 论èçå®åæ¬æ®ä¸å¦ã"
+
+#: src/autobalancedialog.cpp:53
+#, fuzzy
+msgid "Number of allies"
+msgstr "ç©å®¶æ°é"
+
+#: src/autobalancedialog.cpp:56
+#, fuzzy
+msgid "Auto select"
+msgstr "éæ°è¿æ¥"
+
+#: src/autobalancedialog.cpp:68 src/connectwindow.cpp:86
+#: src/mmoptionwindows.cpp:109
+msgid "Ok"
+msgstr "ç¡®å®"
+
+#: src/battlelistctrl.cpp:57 src/hostbattledialog.cpp:72
+#: src/widgets/infopanel.cpp:120
+msgid "Description"
+msgstr "æè¿°"
+
+#: src/battlelistctrl.cpp:58 src/battleroomtab.cpp:172
+#: src/filelister/filelistctrl.cpp:183 src/filelister/filelistctrl.cpp:184
+#: src/filelister/filelistctrl.cpp:195 src/filelister/filelistctrl.cpp:196
+#: src/filelister/filelistdialog.cpp:130 src/mainjoinbattletab.cpp:143
+#: src/playback/playbacklistctrl.cpp:43
+msgid "Map"
+msgstr "å°å¾"
+
+#: src/battlelistctrl.cpp:59 src/filelister/filelistctrl.cpp:183
+#: src/filelister/filelistctrl.cpp:184 src/filelister/filelistctrl.cpp:195
+#: src/filelister/filelistctrl.cpp:196 src/filelister/filelistdialog.cpp:130
+#: src/hostbattledialog.cpp:89 src/playback/playbacklistctrl.cpp:42
+msgid "Mod"
+msgstr "模ç»"
+
+#: src/battlelistctrl.cpp:60 src/hostbattledialog.cpp:247
+msgid "Host"
+msgstr "主æº"
+
+#: src/battlelistctrl.cpp:61
+#, fuzzy
+msgid "Spectators"
+msgstr "æè§è
:"
+
+#: src/battlelistctrl.cpp:62 src/playback/playbacklistctrl.cpp:44
+#, fuzzy
+msgid "Players"
+msgstr "ç©å®¶ï¼"
+
+#: src/battlelistctrl.cpp:63
+#, fuzzy
+msgid "Max"
+msgstr "å°å¾"
+
+#: src/battlelistctrl.cpp:203 src/playback/playbacklistctrl.cpp:65
+msgid "Download &map"
+msgstr "ä¸è½½å°å¾"
+
+#: src/battlelistctrl.cpp:206 src/playback/playbacklistctrl.cpp:66
+msgid "Download m&od"
+msgstr "ä¸è½½æ¨¡ç»"
+
+#: src/battlelistctrl.cpp:354 src/battlelisttab.cpp:108
+msgid "Spectators:"
+msgstr "æè§è
:"
+
+#: src/battlelistctrl.cpp:361
+#, fuzzy
+msgid "Active Players:"
+msgstr "ç©å®¶ï¼"
+
+#: src/battlelistfilter.cpp:89
+msgid "Host:"
+msgstr "主æºï¼"
+
+#: src/battlelistfilter.cpp:108 src/battlelistfilter.cpp:183
+msgid "Status:"
+msgstr "ç¶æï¼"
+
+#: src/battlelistfilter.cpp:112 src/battleroomtab.cpp:198
+msgid "Locked"
+msgstr "å·²éå®"
+
+#: src/battlelistfilter.cpp:117
+msgid "Passworded"
+msgstr "æå¯ç ç"
+
+#: src/battlelistfilter.cpp:122
+#, fuzzy
+msgid "Highlighted only"
+msgstr "é«äº®æ¾ç¤º"
+
+#: src/battlelistfilter.cpp:132
+msgid "Rank Limit:"
+msgstr "ç级éå¶"
+
+#: src/battlelistfilter.cpp:166
+msgid "Description:"
+msgstr "æè¿°ï¼"
+
+#: src/battlelistfilter.cpp:187
+msgid "Started"
+msgstr "å·²å¼å§"
+
+#: src/battlelistfilter.cpp:192
+msgid "Full"
+msgstr "人æ°å·²æ»¡"
+
+#: src/battlelistfilter.cpp:197
+msgid "Open"
+msgstr "å¼æ¾ç"
+
+#: src/battlelistfilter.cpp:207 src/playback/playbackfilter.cpp:68
+msgid "Player:"
+msgstr "ç©å®¶:"
+
+#: src/battlelistfilter.cpp:216 src/playback/playbackfilter.cpp:75
+msgid "All"
+msgstr "å
¨é¨"
+
+#: src/battlelistfilter.cpp:235 src/battlelisttab.cpp:90
+#: src/playback/playbackfilter.cpp:96 src/playback/playbacktab.cpp:84
+#: src/singleplayertab.cpp:63
+msgid "Map:"
+msgstr "å°å¾ï¼"
+
+#: src/battlelistfilter.cpp:252 src/playback/playbackfilter.cpp:113
+msgid "Only maps i have"
+msgstr "ä»
ååºææ¥æå°å¾ç游æ"
+
+#: src/battlelistfilter.cpp:263
+msgid "Max.Player:"
+msgstr "æ大ç©å®¶æ°"
+
+#: src/battlelistfilter.cpp:290 src/battlelisttab.cpp:96
+#: src/playback/playbackfilter.cpp:129 src/playback/playbacktab.cpp:90
+#: src/singleplayertab.cpp:72
+msgid "Mod:"
+msgstr "模ç»ï¼"
+
+#: src/battlelistfilter.cpp:307 src/playback/playbackfilter.cpp:146
+msgid "Only mods i have"
+msgstr "ä»
ååºææ¥æ模ç»ç游æ"
+
+#: src/battlelistfilter.cpp:318
+msgid " Spectator:"
+msgstr " è§ä¼æ°ï¼"
+
+#: src/battlelistfilter.cpp:650 src/battlelistfilter.cpp:655
+#: src/battlelistfilter.cpp:656 src/battlelistfilter.cpp:658
+#: src/playback/playbackfilter.cpp:414 src/settings++/tab_quality_video.cpp:87
+#: src/settings++/tab_quality_video.cpp:88
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/battlelisttab.cpp:102 src/playback/playbacktab.cpp:96
+msgid "Players:"
+msgstr "ç©å®¶ï¼"
+
+#: src/battlelisttab.cpp:136 src/battlelisttab.cpp:138
+#, fuzzy
+msgid " Filter "
+msgstr "æ件"
+
+#: src/battlelisttab.cpp:142
+#, fuzzy
+msgid "Activated"
+msgstr "å·²å¼å§"
+
+#: src/battlelisttab.cpp:146 src/battlelisttab.cpp:148
+#, fuzzy
+msgid " Battle infos "
+msgstr "游æå表"
+
+#: src/battlelisttab.cpp:152
+msgid "0 battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:156
+msgid "Host new..."
+msgstr "主建æ°æ¸¸æ"
+
+#: src/battlelisttab.cpp:159
+msgid "Join"
+msgstr "å å
¥"
+
+#: src/battlelisttab.cpp:182
+#, c-format
+msgid "%d battles displayed"
+msgstr ""
+
+#: src/battlelisttab.cpp:306
+msgid ""
+"You cannot host a game while being offline. Please connect to a lobby server."
+msgstr "离线æ¶ä½ ä¸è½ä¸»å»ºæ¸¸æã请è¿æ¥å°æå¡å¨ã"
+
+#: src/battlelisttab.cpp:306
+msgid "Not Online."
+msgstr "ä¸å¨çº¿"
+
+#: src/battlelisttab.cpp:313
+msgid "Hosting is disabled due to the incompatible version you're using"
+msgstr "å ä¸ºä½ ä½¿ç¨äºä¸å¹é
ççæ¬ï¼ä½ å°ä¸è½ä¸»å»ºæ¸¸æ"
+
+#: src/battlelisttab.cpp:313 src/battlelisttab.cpp:319
+#: src/battlelisttab.cpp:501 src/battlelisttab.cpp:536
+#: src/playback/playbacktab.cpp:286 src/playback/playbacktab.cpp:307
+#: src/settings++/panel_pathoption.cpp:93 src/singleplayertab.cpp:313
+#: src/springoptionstab.cpp:219 src/ui.cpp:609 src/ui.cpp:629
+msgid "Spring error"
+msgstr "Springè¿è¡é误"
+
+#: src/battlelisttab.cpp:319
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to host a new game"
+msgstr "ä½ å·²ç»å¨è¿è¡ä¸ä¸ªSpringç¨åºäºï¼è¯·å¨ä¸»å»ºæ°æ¸¸æåå°å®å
³éã"
+
+#: src/battlelisttab.cpp:325
+msgid "Already in a battle"
+msgstr "å·²ç»å¨ææä¸"
+
+#: src/battlelisttab.cpp:325
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave current battle to start a new?"
+msgstr ""
+"ä½ å·²ç»å¨ææä¸ã\n"
+"ä½ æ³ç¦»å¼ç°å¨çææ以å¼å§æ°çææåï¼"
+
+#: src/battlelisttab.cpp:351
+msgid ""
+"Your using wxWidgets prior to version 2.8,\n"
+" port testing is not supported.\n"
+" Hosting may or may not work."
+msgstr ""
+"ä½ ä½¿ç¨çwxWidgetçæ¬æ¯2.8æ©ï¼\n"
+" 端å£æµè¯ä¸æ¯æã\n"
+" å¯è½æ æ³ä¸»å»ºæ°æ¸¸æã"
+
+#: src/battlelisttab.cpp:358
+#, c-format
+msgid ""
+"The server used for testing your port %d is unreachable. \n"
+"Hosting may or may not work with this setting."
+msgstr ""
+"æ æ³è¿æ¥å°ç¨æ¥æµè¯ç«¯å£ %d çæå¡å¨ã \n"
+"使ç¨è¯¥è®¾ç½®å¯è½æ æ³ä¸»å»ºæ¸¸æã"
+
+#: src/battlelisttab.cpp:366 src/battlelisttab.cpp:379
+#, c-format
+msgid ""
+"Battle not started because the port you selected (%d) is unable to recieve "
+"incoming packets\n"
+" checks your router & firewall configuration again or change port in the "
+"dialog.\n"
+"\n"
+"If everything else fails, enable the Hole Punching NAT Traversal\n"
+" option in the hosting settings."
+msgstr ""
+"å ä¸ºä½ éæ©çç«¯å£ %d æ æ³æ¥æ¶ä¼ éæ¥çæ°æ®å
ï¼å æ¤æææ æ³å¼å§ã\n"
+" 请å次æ£æ¥ä½ çè·¯ç±åé²ç«å¢è®¾ç½®ï¼æè
å¨å¯¹è¯æ¡ä¸ä¿®æ¹ç«¯å£å·ã\n"
+"\n"
+"å¦æä¸è¿°æ¹æ³ä¾ç¶å¤±è´¥ï¼è¯·å¨ä¸»å»ºè®¾ç½®ä¸å¯ç¨ ç©¿è¶NATé»æ¡ é项ã"
+
+#: src/battlelisttab.cpp:395
+msgid "Battle not started beacuse the mod you selected could not be found. "
+msgstr "å ä¸ºä½ éæ©ç模ç»æ æ³è¢«æ¾å°ï¼å æ¤æææ æ³å¼å§ã "
+
+#: src/battlelisttab.cpp:395
+msgid "Error starting battle."
+msgstr "å¯å¨æææ¶åºéã"
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid ""
+"Couldn't find any maps in your spring installation. This could happen when "
+"you set the Spring settings incorrectly."
+msgstr "æ æ³æ¾å°ä»»ä½å°å¾ãå¯è½æ¯å 为æ¨é误ç设置äºSpring导è´çã"
+
+#: src/battlelisttab.cpp:407 src/battlelisttab.cpp:418
+msgid "No maps found"
+msgstr "没ææ¾å°å°å¾"
+
+#: src/battlelisttab.cpp:501
+msgid ""
+"Joining battles is disabled due to the incompatible spring version you're "
+"using."
+msgstr "å 为æ¨çSpringçæ¬ä¸å
¼å®¹ï¼å æ¤æ æ³å å
¥ææã"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid "Already in this battle"
+msgstr "å·²ç»å¨ææä¸"
+
+#: src/battlelisttab.cpp:509
+#, fuzzy
+msgid ""
+"You are already in this battle.\n"
+"\n"
+"Do you want to leave it?"
+msgstr ""
+"ä½ å·²ç»å¨ææä¸ã\n"
+"ä½ æ³ç¦»å¼ç°å¨çææ以å¼å§æ°çææåï¼"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid "Already in another battle"
+msgstr "å·²ç»å¨ææä¸"
+
+#: src/battlelisttab.cpp:523
+#, fuzzy
+msgid ""
+"You are already in a battle.\n"
+"\n"
+"Do you want to leave your current battle and join this one?"
+msgstr ""
+"ä½ å·²ç»å¨ä¸å±ææä¸äºã\n"
+"\n"
+"ä½ æ³è¦ç¦»å¼å½åææ并å å
¥è¿ä¸ä¸ªåï¼"
+
+#: src/battlelisttab.cpp:536
+msgid ""
+"You already are running a Spring instance, close it first in order to be "
+"able to join another battle."
+msgstr "ä½ å·²ç»è¿è¡äºä¸ä¸ªSpringï¼è¯·å
å
³éSpringåå å
¥å
¶ä»ææã"
+
+#: src/battlelisttab.cpp:541 src/playback/playbacktab.cpp:318
+msgid "Do you want me to take you to the download page?"
+msgstr "ä½ æ³è¦åå¾ä¸è½½é¡µé¢åï¼"
+
+#: src/battlelisttab.cpp:543 src/playback/playbacktab.cpp:320
+#, fuzzy
+msgid ""
+"Should i try to download it for you?\n"
+"You can see the progress in the \"Download Manager\" tab."
+msgstr ""
+"æ¯å¦è¦ä¸è½½å®ï¼\n"
+"ä½ å¯ä»¥å¨âä¸è½½ç®¡çå¨âé项å¡ä¸çå°å
¶è¿åº¦ã"
+
+#: src/battlelisttab.cpp:548
+msgid ""
+"You need to download the mod before you can join this game.\n"
+"\n"
+msgstr ""
+"å¨ä½ è½å¤å å
¥è¯¥æ¸¸æåï¼ä½ éè¦ä¸è½½æ¨¡ç»ã\n"
+"\n"
+
+#: src/battlelisttab.cpp:548 src/playback/playbacktab.cpp:326
+msgid "Mod not available"
+msgstr "模ç»ä¸å¯ç¨"
+
+#: src/battlelisttab.cpp:558
+msgid ""
+"You need to download the map to be able to play in this game.\n"
+"\n"
+msgstr ""
+"å¨ç©æ¤æ¸¸æåä½ éè¦ä¸è½½å°å¾ã\n"
+"\n"
+
+#: src/battlelisttab.cpp:558 src/playback/playbacktab.cpp:338
+msgid "Map not available"
+msgstr "å°å¾ä¸å¯ç¨"
+
+#: src/battlelisttab.cpp:567 src/chatpanel.cpp:1560
+msgid "Battle password"
+msgstr "游æå¯ç "
+
+#: src/battlelisttab.cpp:567
+msgid "Enter password"
+msgstr "è¾å
¥å¯ç "
+
+#: src/battlemaptab.cpp:69
+#, fuzzy
+msgid "Select"
+msgstr "éæ©..."
+
+#: src/battlemaptab.cpp:86 src/battleroomtab.cpp:283
+#: src/mapselectdialog.cpp:149
+msgid "Option"
+msgstr "é项"
+
+#: src/battlemaptab.cpp:88 src/battleroomtab.cpp:285
+#: src/mapselectdialog.cpp:151
+msgid "Value"
+msgstr "å¼"
+
+#: src/battlemaptab.cpp:93 src/battleroomtab.cpp:290 src/battleroomtab.cpp:291
+#: src/battleroomtab.cpp:500 src/battleroomtab.cpp:507
+#: src/mapselectdialog.cpp:156
+msgid "Size"
+msgstr "大å°"
+
+#: src/battlemaptab.cpp:94 src/battleroomtab.cpp:292 src/battleroomtab.cpp:293
+#: src/battleroomtab.cpp:501 src/battleroomtab.cpp:508
+#: src/mapselectdialog.cpp:157
+msgid "Windspeed"
+msgstr "é£é"
+
+#: src/battlemaptab.cpp:95 src/battleroomtab.cpp:294 src/battleroomtab.cpp:295
+#: src/battleroomtab.cpp:502 src/battleroomtab.cpp:509
+#: src/mapselectdialog.cpp:158 src/mapselectdialog.cpp:261
+msgid "Tidal strength"
+msgstr "æ½®æ±å¼ºåº¦"
+
+#: src/battlemaptab.cpp:96 src/mapselectdialog.cpp:159
+#: src/mapselectdialog.cpp:262
+msgid "Gravity"
+msgstr "éå"
+
+#: src/battlemaptab.cpp:97 src/mapselectdialog.cpp:160
+#: src/mapselectdialog.cpp:264
+msgid "Extractor radius"
+msgstr "éå±ééåå¾"
+
+#: src/battlemaptab.cpp:98 src/mapselectdialog.cpp:161
+#: src/mapselectdialog.cpp:263
+msgid "Max metal"
+msgstr "éå±å«é"
+
+#: src/battlemaptab.cpp:103 src/battleroomtab.cpp:434
+#: src/mmoptionswrapper.cpp:122
+msgid "Fixed"
+msgstr "åºå®ä½ç½®"
+
+#: src/battlemaptab.cpp:103
+msgid "Choose in game"
+msgstr "å¨æ¸¸æä¸éæ©"
+
+#: src/battlemaptab.cpp:103
+#, fuzzy
+msgid "Chose before game"
+msgstr "å¨æ¸¸æä¸éæ©"
+
+#: src/battlemaptab.cpp:106
+msgid "Startpositions"
+msgstr "åºçä½ç½®"
+
+#: src/battleoptionstab.cpp:52
+msgid "Unit restrictions"
+msgstr "åä½éå¶"
+
+#: src/battleoptionstab.cpp:60
+msgid "Allowed units"
+msgstr "å
许åä½"
+
+#: src/battleoptionstab.cpp:64
+msgid "Units in this list will be available in the game."
+msgstr "å¨è¿ä¸ªæ¸
åä¸çåä½å°å¨æ¸¸æä¸å¯ç¨"
+
+#: src/battleoptionstab.cpp:76
+#, fuzzy
+msgid "Disable selected units."
+msgstr "å
许ææåä½ã"
+
+#: src/battleoptionstab.cpp:80
+#, fuzzy
+msgid "Re-enable selected units."
+msgstr "å
许ææåä½ã"
+
+#: src/battleoptionstab.cpp:83
+msgid "<<"
+msgstr ""
+
+#: src/battleoptionstab.cpp:84
+msgid "Enable all units."
+msgstr "å
许ææåä½ã"
+
+#: src/battleoptionstab.cpp:93
+msgid "Restricted units"
+msgstr "éå¶åä½"
+
+#: src/battleoptionstab.cpp:97
+msgid "Units in this list will not be available in the game."
+msgstr "该å表ä¸çåä½å°ä¸è½å¨æ¸¸æä¸ä½¿ç¨"
+
+#: src/battleoptionstab.cpp:238
+msgid "How many units of this type do you wish to allow?"
+msgstr ""
+
+#: src/battleoptionstab.cpp:238
+#, fuzzy
+msgid "Unit restriction"
+msgstr "åä½éå¶"
+
+#: src/battleroomlistctrl.cpp:88 src/connectwindow.cpp:70
+#: src/nicklistctrl.cpp:61 src/selectusersdialog.cpp:106
+#: src/userlistctrl.cpp:20
+msgid "Nickname"
+msgstr "æµç§°"
+
+#: src/battleroomlistctrl.cpp:89 src/battleroomlistctrl.cpp:115
+#: src/battleroomtab.cpp:158
+msgid "Team"
+msgstr "éä¼"
+
+#: src/battleroomlistctrl.cpp:90 src/battleroomlistctrl.cpp:124
+#: src/battleroomtab.cpp:159
+msgid "Ally"
+msgstr "èç"
+
+#: src/battleroomlistctrl.cpp:91
+msgid "CPU"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:92
+msgid "Resource Bonus"
+msgstr "èµæºå æ"
+
+#: src/battleroomlistctrl.cpp:137 src/battleroomtab.cpp:161
+msgid "Side"
+msgstr "éµè¥"
+
+#: src/battleroomlistctrl.cpp:141
+msgid "Set color"
+msgstr "设置é¢è²"
+
+#: src/battleroomlistctrl.cpp:146 src/battleroomlistctrl.cpp:398
+msgid "Set Resource Bonus"
+msgstr "设置èµæºå æ"
+
+#: src/battleroomlistctrl.cpp:151 src/battleroomlistctrl.cpp:334
+#: src/battleroomlistctrl.cpp:343 src/battleroomtab.cpp:143
+msgid "Spectator"
+msgstr "è§çè
"
+
+#: src/battleroomlistctrl.cpp:156 src/battleroomlistctrl.cpp:338
+#: src/battleroomlistctrl.cpp:348
+msgid "Kick"
+msgstr "踢åº"
+
+#: src/battleroomlistctrl.cpp:158 src/battleroomlistctrl.cpp:337
+#: src/battleroomlistctrl.cpp:346 src/chatpanel.cpp:570
+msgid "Ring"
+msgstr "é¹éæ示"
+
+#: src/battleroomlistctrl.cpp:398
+msgid "Please enter a value between 0 and 100"
+msgstr "请è¾å
¥ä»äº0ä¸100ä¹é´çä¸ä¸ªå¼"
+
+#: src/battleroomlistctrl.cpp:717
+#, fuzzy
+msgid "AI (bot)\n"
+msgstr "æ·»å AI"
+
+#: src/battleroomlistctrl.cpp:719
+#, fuzzy
+msgid "Human\n"
+msgstr "é¿æ¼"
+
+#: src/battleroomlistctrl.cpp:722
+#, fuzzy
+msgid "Spectator\n"
+msgstr "è§çè
"
+
+#: src/battleroomlistctrl.cpp:724
+#, fuzzy
+msgid "Player\n"
+msgstr "ç©å®¶:"
+
+#: src/battleroomlistctrl.cpp:727
+#, fuzzy
+msgid "Host\n"
+msgstr "主æº"
+
+#: src/battleroomlistctrl.cpp:729
+#, fuzzy
+msgid "Client\n"
+msgstr "客æ·ç«¯"
+
+#: src/battleroomlistctrl.cpp:732
+#, fuzzy
+msgid "Ready\n"
+msgstr "æ»æ¯"
+
+#: src/battleroomlistctrl.cpp:734
+#, fuzzy
+msgid "Not ready\n"
+msgstr "æªå°±ç»ª"
+
+#: src/battleroomlistctrl.cpp:737
+#, fuzzy
+msgid "In sync"
+msgstr "å¯ç¨ åç´åæ¥"
+
+#: src/battleroomlistctrl.cpp:739
+msgid "Not in sync"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:791 src/chatpanel.cpp:1787
+msgid "Enter name"
+msgstr ""
+
+#: src/battleroomlistctrl.cpp:792 src/chatpanel.cpp:1788
+msgid ""
+"Please enter the name for the new group.\n"
+"After clicking ok you will be taken to adjust its settings."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:55 src/battleroomtab.cpp:249
+msgid "Manage Presets"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:58
+#, fuzzy
+msgid "Set name."
+msgstr "设置æé..."
+
+#: src/battleroommmoptionstab.cpp:62
+msgid "Load..."
+msgstr "è½½å
¥..."
+
+#: src/battleroommmoptionstab.cpp:63
+#, fuzzy
+msgid "Load a saved set of options."
+msgstr "è½½å
¥å·²å¨åçåä½éå¶é
ç½®"
+
+#: src/battleroommmoptionstab.cpp:67
+#, fuzzy
+msgid "Save..."
+msgstr "ä¿å..."
+
+#: src/battleroommmoptionstab.cpp:68 src/battleroomtab.cpp:260
+#, fuzzy
+msgid "Save a set of options."
+msgstr "ä¿ååä½éå¶é
ç½®"
+
+#: src/battleroommmoptionstab.cpp:72
+#, fuzzy
+msgid "Delete..."
+msgstr "éæ©..."
+
+#: src/battleroommmoptionstab.cpp:73 src/battleroomtab.cpp:265
+#, fuzzy
+msgid "Delete a set of options."
+msgstr "ä¿ååä½éå¶é
ç½®"
+
+#: src/battleroommmoptionstab.cpp:77
+#, fuzzy
+msgid "Set default..."
+msgstr "é»è®¤"
+
+#: src/battleroommmoptionstab.cpp:78 src/battleroomtab.cpp:270
+msgid "Use the current set of options as mod's default."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:86
+msgid "Mod Options"
+msgstr "模ç»é项"
+
+#: src/battleroommmoptionstab.cpp:91
+msgid "Map Options"
+msgstr "å°å¾é项"
+
+#: src/battleroommmoptionstab.cpp:152
+#, fuzzy
+msgid "no options available"
+msgstr "ä¸å¯ç¨"
+
+#: src/battleroommmoptionstab.cpp:159
+msgid "other"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497
+msgid ""
+"Cannot load an options set without a name\n"
+"Please select one from the list and try again."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:497 src/battleroommmoptionstab.cpp:514
+#: src/battleroomtab.cpp:884 src/ui.cpp:835
+msgid "error"
+msgstr "é误"
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid "Enter preset name"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:510 src/battleroomtab.cpp:880
+msgid ""
+"Enter a name to save the current set of options\n"
+"If a preset with the same name already exist, it will be overwritten"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:514 src/battleroomtab.cpp:884
+msgid "Cannot save an options set without a name."
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroommmoptionstab.cpp:534
+#: src/battleroomtab.cpp:894 src/battleroomtab.cpp:902
+msgid "Pick an existing option set from the list"
+msgstr ""
+
+#: src/battleroommmoptionstab.cpp:525 src/battleroomtab.cpp:894
+#, fuzzy
+msgid "Delete preset"
+msgstr "åå°ç"
+
+#: src/battleroommmoptionstab.cpp:534 src/battleroomtab.cpp:902
+#, fuzzy
+msgid "Set mod default preset"
+msgstr "é»è®¤"
+
+#: src/battleroomtab.cpp:136
+msgid "Players with the same team number share control of their units."
+msgstr "æ¥æç¸åéä¼ç¼å·çç©å®¶å
±åæ§å¶ä»ä»¬çåä½ã"
+
+#: src/battleroomtab.cpp:138
+msgid "Players with the same ally number work together to achieve victory."
+msgstr "æ¥æç¸åèçç¼å·çç©å®¶å
±ååä½ä»¥è¾¾å°èå©ã"
+
+#: src/battleroomtab.cpp:140
+msgid "Select a color to identify your units in-game"
+msgstr "éæ©ä¸ä¸ªç¨æ¥å¨æ¸¸æä¸è¯å«ä½ çåä½çé¢è²"
+
+#: src/battleroomtab.cpp:142
+msgid "Select your faction"
+msgstr "éæ©ä½ çéµè¥"
+
+#: src/battleroomtab.cpp:144
+msgid "Spectate (watch) the battle instead of playing"
+msgstr "è§çæ¤åºææï¼èä¸æ¯åä¸ææ"
+
+#: src/battleroomtab.cpp:145
+msgid "I'm ready"
+msgstr "æåå¤å¥½äº"
+
+#: src/battleroomtab.cpp:146
+msgid "Click this if you are content with the battle settings."
+msgstr "å¦æä½ æ»¡æææç设置ï¼è¯·ç¹å»æ¤å¤ã"
+
+#: src/battleroomtab.cpp:160
+msgid "Color"
+msgstr "é¢è²"
+
+#: src/battleroomtab.cpp:170
+msgid ""
+"A preview of the selected map. You can see the starting positions, or (if "
+"set) starting boxes."
+msgstr ""
+"éä¸å°å¾çé¢è§å¾ãä½ å¯ä»¥çå°åºçä½ç½®ï¼æè
ï¼å¦æ已设置好çè¯ï¼åºçåºåã"
+
+#: src/battleroomtab.cpp:180 src/chatpanel.cpp:424
+msgid "Leave"
+msgstr "离å¼"
+
+#: src/battleroomtab.cpp:181
+msgid "Leave the battle and return to the battle list"
+msgstr "离å¼ææ并è¿å大å
"
+
+#: src/battleroomtab.cpp:182 src/singleplayertab.cpp:106
+msgid "Start"
+msgstr "å¼å§"
+
+#: src/battleroomtab.cpp:183
+msgid "Start the battle"
+msgstr "å¼å§ææ"
+
+#: src/battleroomtab.cpp:185
+msgid "Player Management"
+msgstr ""
+
+#: src/battleroomtab.cpp:186
+msgid "Various functions to make team games simplers to setup"
+msgstr ""
+
+#: src/battleroomtab.cpp:188
+msgid "Add Bot..."
+msgstr "æ·»å AI..."
+
+#: src/battleroomtab.cpp:189
+msgid "Add a computer-controlled player to the game"
+msgstr "å¢å ä¸ä¸ªçµèæ§å¶çç©å®¶è¿å
¥æ¸¸æ"
+
+#: src/battleroomtab.cpp:191 src/battleroomtab.cpp:193
+msgid "Autolock on start"
+msgstr ""
+
+#: src/battleroomtab.cpp:195
+msgid ""
+"Automatically locks the battle when the game starts and unlock when it's "
+"finished."
+msgstr ""
+
+#: src/battleroomtab.cpp:199
+msgid "Prevent additional players from joining the battle"
+msgstr "é»æ¢æ´å¤å
¶ä»ç©å®¶è¿å
¥è¯¥ææ"
+
+#: src/battleroomtab.cpp:203
+msgid "Autohost"
+msgstr ""
+
+#: src/battleroomtab.cpp:203
+msgid ""
+"Toggle autohost mode. This allows players to control your battle using "
+"commands like '!balance' and '!start'."
+msgstr ""
+
+#: src/battleroomtab.cpp:207
+#, fuzzy
+msgid "AutoSpect"
+msgstr "éæ°è¿æ¥"
+
+#: src/battleroomtab.cpp:207
+msgid ""
+"Automatically spectate players that don't ready up or become synced within x "
+"seconds."
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid "AutoControlBalance"
+msgstr ""
+
+#: src/battleroomtab.cpp:210
+msgid ""
+"Automatically balance teams and allies and fix colors when all players are "
+"ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:213
+#, fuzzy
+msgid "AutoStart"
+msgstr "å¼å§"
+
+#: src/battleroomtab.cpp:213
+msgid "Automatically start the battle when all players are ready and synced"
+msgstr ""
+
+#: src/battleroomtab.cpp:217
+#, fuzzy
+msgid "Lock Balance"
+msgstr "平衡"
+
+#: src/battleroomtab.cpp:217
+msgid "When activated, prevents anyone but the host to change team and ally"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Ring unready"
+msgstr ""
+
+#: src/battleroomtab.cpp:222
+msgid "Rings all players that don't have ready status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:224
+#, fuzzy
+msgid "Ring unsynced"
+msgstr "å¯ç¨ åç´åæ¥"
+
+#: src/battleroomtab.cpp:224
+msgid "Rings all players that don't have sync status and aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid "Ring unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:226
+msgid ""
+"Rings all players that don't have sync status or don't have ready status and "
+"aren't spectators"
+msgstr ""
+
+#: src/battleroomtab.cpp:228
+#, fuzzy
+msgid "Ring ..."
+msgstr "é¹éæ示"
+
+#: src/battleroomtab.cpp:231
+#, fuzzy
+msgid "Spect unready"
+msgstr "æªå°±ç»ª"
+
+#: src/battleroomtab.cpp:231
+msgid "Force to spectate all players that don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Spect unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:233
+msgid "Force to spectate all players that don't have sync status"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid "Force to spectate unready and unsynced"
+msgstr ""
+
+#: src/battleroomtab.cpp:235
+msgid ""
+"Rings all players that don't have sync status or don't have ready status"
+msgstr ""
+
+#: src/battleroomtab.cpp:237
+#, fuzzy
+msgid "Force spectate ..."
+msgstr "强å¶å¼å§ï¼"
+
+#: src/battleroomtab.cpp:239
+#, fuzzy
+msgid "Balance alliances"
+msgstr "åªæ主æºå¯ä»¥å¹³è¡¡èçå®åã"
+
+#: src/battleroomtab.cpp:239
+msgid "Automatically balance players into two or more alliances"
+msgstr "èªå¨å¹³è¡¡åé
å°ä¸¤ä¸ªæå¤ä¸ªèç"
+
+#: src/battleroomtab.cpp:242
+msgid "Fix colours"
+msgstr "ä¿®æ¹é¢è²"
+
+#: src/battleroomtab.cpp:242
+msgid "Make player colors unique"
+msgstr "使ç©å®¶çé¢è²ä¸éå¤"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid "Balance teams"
+msgstr "平衡"
+
+#: src/battleroomtab.cpp:245
+#, fuzzy
+msgid ""
+"Automatically balance players into control teams, by default none shares "
+"control"
+msgstr "èªå¨å¹³è¡¡åé
å°ä¸¤ä¸ªæå¤ä¸ªèç"
+
+#: src/battleroomtab.cpp:255
+msgid "Load battle preset"
+msgstr ""
+
+#: src/battleroomtab.cpp:259
+#, fuzzy
+msgid "Save"
+msgstr "ä¿å..."
+
+#: src/battleroomtab.cpp:264 src/playback/playbacktab.cpp:137
+#, fuzzy
+msgid "Delete"
+msgstr "åå°ç"
+
+#: src/battleroomtab.cpp:269
+#, fuzzy
+msgid "Set default"
+msgstr "é»è®¤"
+
+#: src/battleroomtab.cpp:280
+msgid "Activate an element to quickly change it"
+msgstr ""
+
+#: src/battleroomtab.cpp:438
+msgid "Boxes"
+msgstr "åºçåºåæ¡ä¸ªæ°"
+
+#: src/battleroomtab.cpp:440
+msgid "Pick"
+msgstr "æé"
+
+#: src/battleroomtab.cpp:452
+msgid "Continue"
+msgstr "继ç»"
+
+#: src/battleroomtab.cpp:454
+msgid "End"
+msgstr "ç»æ"
+
+#: src/battleroomtab.cpp:456
+msgid "Lineage"
+msgstr "è¡ç»æ¨¡å¼"
+
+#: src/battleroomtab.cpp:498
+msgid "Map does not exist."
+msgstr "å°å¾ä¸åå¨ã"
+
+#: src/battleroomtab.cpp:593
+#, fuzzy
+msgid ""
+"Some Players are not ready yet\n"
+"Do you want to force start?"
+msgstr ""
+"æäºç©å®¶è¿æ²¡åå¤å¥½ã\n"
+"é¹éæ示è¿äºç©å®¶ï¼"
+
+#: src/battleroomtab.cpp:593
+msgid "Not ready"
+msgstr "æªå°±ç»ª"
+
+#: src/battleroomtab.cpp:718
+msgid "Enter timeout before autospeccing a player in minutes"
+msgstr ""
+
+#: src/battleroomtab.cpp:718
+#, fuzzy
+msgid "Set Timeout"
+msgstr "Pingè¶
æ¶ï¼"
+
+#: src/channel/autojoinchanneldialog.cpp:25
+#, fuzzy
+msgid "Edit auto-joined channels"
+msgstr "(&A) èªå¨å å
¥é¢é"
+
+#: src/channel/autojoinchanneldialog.cpp:34
+msgid ""
+"Add one channel per line like this:\n"
+"channelname password\n"
+"(passwords for existing channels are not displayed)"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:23
+msgid "Double click to join"
+msgstr ""
+
+#: src/channel/channelchooser.cpp:30
+#, fuzzy
+msgid "Find channel:"
+msgstr "å å
¥é¢é..."
+
+#: src/channel/channelchooserdialog.cpp:13 src/mainwindow.cpp:226
+#, fuzzy
+msgid "Choose channels to join"
+msgstr "å å
¥é¢éçå称"
+
+#: src/channel/channellistctrl.cpp:28
+#, fuzzy
+msgid "Channel"
+msgstr "é¢é"
+
+#: src/channel/channellistctrl.cpp:29
+#, fuzzy
+msgid "# users"
+msgstr "(%d åç¨æ·ï¼"
+
+#: src/channel/channellistctrl.cpp:116
+#, c-format
+msgid "Displaying %d out of %d channels"
+msgstr ""
+
+#: src/chatlog.cpp:45
+msgid "### Session Closed at ["
+msgstr "### ä¼è¯äº ["
+
+#: src/chatlog.cpp:45
+msgid "]"
+msgstr "] ç»æ"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid ""
+"Couldn't create folder. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"æ æ³å建ç®å½ã \n"
+"请确认åä¿æ¤æ¯å¦è¢«æå¼ã\n"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:104
+msgid "Log function is disabled until restart SpringLobby."
+msgstr "æ¥å¿åè½å°å¨SpringLobbyéæ°å¯å¨åå¯ç¨ã"
+
+#: src/chatlog.cpp:98 src/chatlog.cpp:121 src/chatlog.cpp:143
+msgid "Log Warning"
+msgstr "æ¥å¿è¦æ¥"
+
+#: src/chatlog.cpp:121
+msgid ""
+"Couldn't write message to log.\n"
+"Logging will be disabled for room "
+msgstr ""
+"æ æ³å°ä¿¡æ¯åå
¥æ¥å¿ã\n"
+"æ¥å¿å°å¨è¯¥æ¿é´è¢«ç¦ç¨ "
+
+#: src/chatlog.cpp:121
+msgid ""
+".\n"
+"\n"
+"Rejoin room to reactivate logging."
+msgstr ""
+"ã\n"
+"\n"
+"éæ°è¿å
¥æ¿é´æ¥éæ°å¯ç¨æ¥å¿åè½ã"
+
+#: src/chatlog.cpp:143
+msgid ""
+"Can't open log file. \n"
+"Be sure that there isn't a write protection.\n"
+msgstr ""
+"æ æ³æå¼æ¥å¿æ件ã \n"
+"请确认åä¿æ¤æ¯å¦è¢«æå¼ã\n"
+
+#: src/chatoptionstab.cpp:73
+msgid "Colors and font"
+msgstr "é¢è²ä¸åä½"
+
+#: src/chatoptionstab.cpp:78
+msgid "Use system colors"
+msgstr "使ç¨ç³»ç»é¢è²"
+
+#: src/chatoptionstab.cpp:104
+msgid "Normal"
+msgstr "æ®é"
+
+#: src/chatoptionstab.cpp:118
+msgid "Background"
+msgstr "èæ¯"
+
+#: src/chatoptionstab.cpp:132
+msgid "Action"
+msgstr "å¨ä½"
+
+#: src/chatoptionstab.cpp:146 src/groupoptionspanel.cpp:125
+msgid "Highlight"
+msgstr "é«äº®æ¾ç¤º"
+
+#: src/chatoptionstab.cpp:160
+msgid "Join/Leave"
+msgstr "å å
¥/离å¼"
+
+#: src/chatoptionstab.cpp:174
+msgid "My messages"
+msgstr "æçæ¶æ¯"
+
+#: src/chatoptionstab.cpp:193 src/connectwindow.cpp:64
+msgid "Server"
+msgstr "æå¡å¨"
+
+#: src/chatoptionstab.cpp:207
+msgid "Client"
+msgstr "客æ·ç«¯"
+
+#: src/chatoptionstab.cpp:221 src/chatpanel.cpp:1524 src/chatpanel.cpp:1698
+#: src/chatpanel.cpp:1704 src/chatpanel.cpp:1797
+#: src/Helper/imageviewer.cpp:146 src/Helper/imageviewer.cpp:170
+#: src/playback/playbacktab.cpp:377 src/serverevents.cpp:970
+#: src/settings++/tab_abstract.cpp:129 src/tasserver.cpp:517
+#: src/updater/updater.cpp:46 src/updater/updater.cpp:82
+#: src/updater/updater.cpp:97 src/updater/updater.cpp:102
+#: src/updater/updater.cpp:105 src/widgets/infopanel.cpp:161
+#: src/widgets/infopanel.cpp:173
+msgid "Error"
+msgstr "é误"
+
+#: src/chatoptionstab.cpp:235
+msgid "Timestamp"
+msgstr "æ¶é´æ³"
+
+#: src/chatoptionstab.cpp:249
+msgid "Notification"
+msgstr "éç¥"
+
+#: src/chatoptionstab.cpp:259
+#, fuzzy
+msgid ""
+"[19:35] ** Server ** Connected to Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+msgstr ""
+"[19:35] ** Server ** Connected to TAS Server.\n"
+"[22:30] <Dude> hi everyone\n"
+"[22:30] ** Dude2 joined the channel.\n"
+"[22:30] * Dude2 thinks his colors looks nice\n"
+"[22:45] <Dude> Dude2: orl?\n"
+"[22:46] <Dude2> But could be better, should tweak them some more...\n"
+
+#: src/chatoptionstab.cpp:270
+msgid "Font:"
+msgstr "åä½ï¼"
+
+#: src/chatoptionstab.cpp:274
+msgid "default"
+msgstr "é»è®¤"
+
+#: src/chatoptionstab.cpp:278
+msgid "Select..."
+msgstr "éæ©..."
+
+#: src/chatoptionstab.cpp:289
+msgid "Behavior"
+msgstr "è¡ä¸º"
+
+#: src/chatoptionstab.cpp:291
+msgid "Enable Irc colors in chat messages"
+msgstr ""
+
+#: src/chatoptionstab.cpp:296
+msgid "Play notification sounds"
+msgstr "ææ¾éç¥å£°é³"
+
+#: src/chatoptionstab.cpp:307
+msgid "Chat logs"
+msgstr "è天æ¥å¿"
+
+#: src/chatoptionstab.cpp:310
+msgid "Save chat logs"
+msgstr "ä¿åè天记å½"
+
+#: src/chatoptionstab.cpp:318
+msgid "Highlight words"
+msgstr "é«äº®ææ¬"
+
+#: src/chatoptionstab.cpp:320
+msgid "Words to highlight in chat:"
+msgstr "è天ä¸é«äº®æ¾ç¤ºåï¼"
+
+#: src/chatoptionstab.cpp:329
+msgid "enter a ; seperated list"
+msgstr "è¾å
¥ä¸ä¸ªç± ; åéå¼çå表"
+
+#: src/chatoptionstab.cpp:333
+msgid "Additionally play sound/flash titlebar "
+msgstr "é¢å¤çææ¾å£°é³/éªçæ é¢æ "
+
+#: src/chatpanel.cpp:124
+msgid "channel_"
+msgstr "é¢é_"
+
+#: src/chatpanel.cpp:126
+msgid "#"
+msgstr "#"
+
+#: src/chatpanel.cpp:307 src/chatpanel.cpp:960 src/chatpanel.cpp:976
+#: src/chatpanel.cpp:1001
+#, fuzzy, c-format
+msgid "%d users"
+msgstr "(%d åç¨æ·ï¼"
+
+#: src/chatpanel.cpp:335
+msgid "right click for options (like autojoin)"
+msgstr "å³é®é项ï¼å¦èªå¨å å
¥ï¼"
+
+#: src/chatpanel.cpp:343
+msgid "Send"
+msgstr "åé"
+
+#: src/chatpanel.cpp:397
+msgid "Disable text appending (workaround for autoscroll)"
+msgstr ""
+
+#: src/chatpanel.cpp:401
+msgid "Copy"
+msgstr "å¤å¶"
+
+#: src/chatpanel.cpp:407
+msgid "Copy link location"
+msgstr ""
+
+#: src/chatpanel.cpp:411
+msgid "Clear"
+msgstr "æ¸
é¤"
+
+#: src/chatpanel.cpp:417
+msgid "Auto join this channel"
+msgstr "èªå¨å å
¥è¯¥é¢é"
+
+#: src/chatpanel.cpp:427
+msgid "Display Join/Leave Messages"
+msgstr "æ¾ç¤º å å
¥/ç¦»å¼ ä¿¡æ¯"
+
+#: src/chatpanel.cpp:433
+#, fuzzy
+msgid "Show mute list"
+msgstr "æ¾ç¤ºå·¥å
·æ示"
+
+#: src/chatpanel.cpp:439
+msgid "Channel info"
+msgstr "é¢éä¿¡æ¯"
+
+#: src/chatpanel.cpp:443 src/chatpanel.cpp:1360
+msgid "Set topic..."
+msgstr "设置è¯é¢..."
+
+#: src/chatpanel.cpp:445 src/chatpanel.cpp:1377
+msgid "Channel message..."
+msgstr "é¢éæ¶æ¯..."
+
+#: src/chatpanel.cpp:449
+msgid "Lock..."
+msgstr "éå®..."
+
+#: src/chatpanel.cpp:451
+msgid "Unlock"
+msgstr "解é"
+
+#: src/chatpanel.cpp:455
+msgid "Register..."
+msgstr "注å..."
+
+#: src/chatpanel.cpp:457
+msgid "Unregister"
+msgstr "注é"
+
+#: src/chatpanel.cpp:463
+msgid "On"
+msgstr "æå¼"
+
+#: src/chatpanel.cpp:465
+msgid "Off"
+msgstr "å
³é"
+
+#: src/chatpanel.cpp:469
+msgid "Is on?"
+msgstr "æ¯å¦å¼å¯"
+
+#: src/chatpanel.cpp:471
+msgid "Spam protection"
+msgstr "åå¾æ¶æ¯ä¿æ¤"
+
+#: src/chatpanel.cpp:472 src/chatpanel.cpp:595
+msgid "ChanServ"
+msgstr "é¢éæå¡å¨"
+
+#: src/chatpanel.cpp:479
+msgid "Disconnect"
+msgstr "æå¼è¿æ¥"
+
+#: src/chatpanel.cpp:481
+msgid "Reconnect"
+msgstr "éæ°è¿æ¥"
+
+#: src/chatpanel.cpp:490
+msgid "Remove..."
+msgstr "移é¤..."
+
+#: src/chatpanel.cpp:492
+msgid "Change password..."
+msgstr "æ´æ¹å¯ç ..."
+
+#: src/chatpanel.cpp:494
+msgid "Set access..."
+msgstr "设置æé..."
+
+#: src/chatpanel.cpp:496
+msgid "Accounts"
+msgstr "å¸æ·"
+
+#: src/chatpanel.cpp:499
+msgid "Broadcast..."
+msgstr "广æ..."
+
+#: src/chatpanel.cpp:501
+msgid "Admin"
+msgstr "管çå"
+
+#: src/chatpanel.cpp:510
+#, fuzzy
+msgid "User"
+msgstr "ç¦è¨ç¨æ·"
+
+#: src/chatpanel.cpp:514
+msgid "Open log in editor"
+msgstr ""
+
+#: src/chatpanel.cpp:525
+msgid "Open Chat"
+msgstr "å
¬ä¼è天"
+
+#: src/chatpanel.cpp:528
+msgid "Join same battle"
+msgstr "å å
¥åä¸ææ"
+
+#: src/chatpanel.cpp:534
+msgid "Ingame time"
+msgstr "游ææç»æ¶é´"
+
+#: src/chatpanel.cpp:536
+msgid "Retrieve IP and Smurfs"
+msgstr "è¿åIPä¸Smurf"
+
+#: src/chatpanel.cpp:543 src/chatpanel.cpp:582
+msgid "Mute..."
+msgstr "ç¦è¨..."
+
+#: src/chatpanel.cpp:545
+msgid "Mute for 5 minutes"
+msgstr "ç¦è¨5åé"
+
+#: src/chatpanel.cpp:547
+msgid "Mute for 10 minutes"
+msgstr "ç¦è¨10åé"
+
+#: src/chatpanel.cpp:549
+msgid "Mute for 30 minutes"
+msgstr "ç¦è¨30åé"
+
+#: src/chatpanel.cpp:551
+msgid "Mute for 2 hours"
+msgstr "ç¦è¨2å°æ¶"
+
+#: src/chatpanel.cpp:553
+msgid "Mute for 1 day"
+msgstr "ç¦è¨1天"
+
+#: src/chatpanel.cpp:556 src/chatpanel.cpp:584
+msgid "Unmute"
+msgstr "åæ¶ç¦è¨"
+
+#: src/chatpanel.cpp:558
+msgid "Mute"
+msgstr "ç¦è¨"
+
+#: src/chatpanel.cpp:560 src/chatpanel.cpp:587
+msgid "Kick..."
+msgstr "踢åº..."
+
+#: src/chatpanel.cpp:564
+msgid "Ban..."
+msgstr "ç¦é..."
+
+#: src/chatpanel.cpp:566
+msgid "Unban"
+msgstr "解ç¦"
+
+#: src/chatpanel.cpp:574
+msgid "Slap!"
+msgstr "æè³å
ï¼"
+
+#: src/chatpanel.cpp:591
+msgid "Op"
+msgstr "ç»ç®¡çåæé"
+
+#: src/chatpanel.cpp:593
+msgid "DeOp"
+msgstr "åæ¶ç®¡çåæé"
+
+#: src/chatpanel.cpp:936
+msgid " !! Command: \""
+msgstr " !! æ令ï¼â"
+
+#: src/chatpanel.cpp:936
+msgid "\" params: \""
+msgstr "â åæ°ï¼â"
+
+#: src/chatpanel.cpp:942
+msgid "channel"
+msgstr "é¢é"
+
+#: src/chatpanel.cpp:943
+msgid "battle"
+msgstr "ææ"
+
+#: src/chatpanel.cpp:944
+msgid "server"
+msgstr "æå¡å¨"
+
+#: src/chatpanel.cpp:956 src/chatpanel.cpp:964
+msgid " joined the "
+msgstr " å å
¥ "
+
+#: src/chatpanel.cpp:997 src/chatpanel.cpp:1006
+msgid " left the "
+msgstr " ç¦»å¼ "
+
+#: src/chatpanel.cpp:1029
+#, fuzzy
+msgid " ** Channel topic:"
+msgstr "é¢éä¿¡æ¯"
+
+#: src/chatpanel.cpp:1036
+#, fuzzy
+msgid " ** Set by "
+msgstr ""
+"\n"
+" * è®¾ç½®ç± "
+
+#: src/chatpanel.cpp:1063 src/chatpanel.cpp:1088 src/chatpanel.cpp:1114
+msgid "Chat closed."
+msgstr "è天被å
³éã"
+
+#: src/chatpanel.cpp:1161
+#, c-format
+msgid "Are you sure you want to paste %d lines?"
+msgstr "ä½ ç¡®è®¤ä½ è¦ç²è´´ %d è¡åï¼"
+
+#: src/chatpanel.cpp:1161
+msgid "Flood warning"
+msgstr "Floodè¦æ¥"
+
+#: src/chatpanel.cpp:1173
+msgid " You have SpringLobby v"
+msgstr " æ¨ä½¿ç¨ SpringLobby v"
+
+#: src/chatpanel.cpp:1186
+msgid " You are not in channel or channel does not exist."
+msgstr " ä½ è¿æ²¡æå å
¥é¢éæè
é¢éä¸åå¨ã"
+
+#: src/chatpanel.cpp:1192 src/chatpanel.cpp:1206 src/chatpanel.cpp:1220
+#: src/chatpanel.cpp:1230
+#, c-format
+msgid ""
+" Error: Command (%s) does not exist, use /help for a list of available "
+"commands."
+msgstr " éè¯¯ï¼ æ令 %s ä¸åå¨ï¼è¯·ä½¿ç¨ /help è·å¾æ令å表ã"
+
+#: src/chatpanel.cpp:1200
+msgid ""
+" You are not in battle or battle does not exist, use /help for a list of "
+"available commands."
+msgstr " ä½ ä¸å¨ææä¸æè
ææä¸åå¨ï¼ä½¿ç¨ /help è·å¾æ令å表ã"
+
+#: src/chatpanel.cpp:1214
+msgid " User is offline."
+msgstr " ç¨æ·ä¸å¨çº¿ã"
+
+#: src/chatpanel.cpp:1248
+msgid " Sent: \""
+msgstr " å·²åéï¼ â"
+
+#: src/chatpanel.cpp:1248
+msgid "\""
+msgstr "â"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1421
+#: src/chatpanel.cpp:1438 src/chatpanel.cpp:1454 src/chatpanel.cpp:1468
+#: src/chatpanel.cpp:1482 src/chatpanel.cpp:1585 src/chatpanel.cpp:1607
+#: src/chatpanel.cpp:1624 src/chatpanel.cpp:1646 src/chatpanel.cpp:1663
+msgid "ChanServ error"
+msgstr "é¢éæå¡å¨é误"
+
+#: src/chatpanel.cpp:1340 src/chatpanel.cpp:1354 src/chatpanel.cpp:1371
+#: src/chatpanel.cpp:1388 src/chatpanel.cpp:1405 src/chatpanel.cpp:1454
+#: src/chatpanel.cpp:1468 src/chatpanel.cpp:1482 src/chatpanel.cpp:1585
+#: src/chatpanel.cpp:1607 src/chatpanel.cpp:1624 src/chatpanel.cpp:1646
+#: src/chatpanel.cpp:1663
+msgid "ChanServ is not in this channel."
+msgstr "é¢éæå¡å¨ä¸å¨è¯¥é¢éã"
+
+#: src/chatpanel.cpp:1360
+msgid "What should be the new topic?"
+msgstr "æ°è¯é¢åºè¯¥æ¯ä»ä¹ï¼"
+
+#: src/chatpanel.cpp:1377
+msgid "Message:"
+msgstr "æ¶æ¯ï¼"
+
+#: src/chatpanel.cpp:1394
+msgid "Lock channel..."
+msgstr "éå®é¢é..."
+
+#: src/chatpanel.cpp:1394
+msgid "What should the new password be?"
+msgstr "æ°å¯ç åºè¯¥æ¯ä»ä¹ï¼"
+
+#: src/chatpanel.cpp:1410
+msgid "Unlock Channel"
+msgstr "解éé¢é"
+
+#: src/chatpanel.cpp:1410
+msgid "Are you sure you want to unlock this channel?"
+msgstr "ä½ ç¡®è®¤ä½ è¦è§£é该é¢éï¼"
+
+#: src/chatpanel.cpp:1421 src/chatpanel.cpp:1438
+msgid "ChanServ is not on this server."
+msgstr "é¢éæå¡å¨ä¸å¨è¯¥æå¡å¨ã"
+
+#: src/chatpanel.cpp:1427
+msgid "Register Channel"
+msgstr "注åé¢é"
+
+#: src/chatpanel.cpp:1427
+msgid "Who should be appointed founder of this channel?"
+msgstr "è°åºè¯¥è¢«æ派为该é¢éçå建è
ï¼"
+
+#: src/chatpanel.cpp:1443
+msgid "Unregister Channel"
+msgstr "注éé¢é"
+
+#: src/chatpanel.cpp:1443
+msgid "Are you sure you want to unregister this channel?"
+msgstr "ä½ ç¡®è®¤ä½ è¦æ³¨éæ¤é¢éï¼"
+
+#: src/chatpanel.cpp:1507
+msgid "Remove User Acount"
+msgstr "移é¤ç¨æ·å¸æ·"
+
+#: src/chatpanel.cpp:1507
+msgid "What user account do you want to remove today?"
+msgstr "ä½ æ³è¦ç§»é¤åªä¸ªç¨æ·å¸æ·ï¼"
+
+#: src/chatpanel.cpp:1508
+msgid "Remove Account"
+msgstr "å é¤è´¦æ·"
+
+#: src/chatpanel.cpp:1508
+msgid "Are you sure you want to remove the account "
+msgstr "ä½ ç¡®è®¤ä½ è¦ç§»é¤å¸æ· "
+
+#: src/chatpanel.cpp:1516 src/chatpanel.cpp:1517
+msgid "Change User Acount Password"
+msgstr "ä¿®æ¹ç¨æ·å¸æ·å¯ç "
+
+#: src/chatpanel.cpp:1516
+msgid "What user account do you want to change the password for?"
+msgstr "ä½ æ³ä¸ºåªä½ç¨æ·ä¿®æ¹å¯ç ï¼"
+
+#: src/chatpanel.cpp:1517
+msgid "What would be the new password?"
+msgstr "æ°å¯ç åºè¯¥æ¯ä»ä¹ï¼"
+
+#: src/chatpanel.cpp:1524 src/chatpanel.cpp:1698 src/chatpanel.cpp:1704
+msgid "Not Implemented"
+msgstr "å°æªå®ç°"
+
+#: src/chatpanel.cpp:1531
+msgid "Broadcast Message"
+msgstr "广ææ¶æ¯"
+
+#: src/chatpanel.cpp:1531
+msgid "Message to be broadcasted:"
+msgstr "è¦å¹¿æçæ¶æ¯ï¼"
+
+#: src/chatpanel.cpp:1553
+msgid "You don't have the mod "
+msgstr "ä½ æ²¡æ "
+
+#: src/chatpanel.cpp:1554
+msgid " . Please download it first"
+msgstr " 模ç»ã请å
ä¸è½½"
+
+#: src/chatpanel.cpp:1554
+msgid "Mod unavailable"
+msgstr "模ç»ä¸å¯ç¨"
+
+#: src/chatpanel.cpp:1560
+msgid "This battle is password protected, enter the password."
+msgstr "è¿ä¸ªæææå¯ç ä¿æ¤ï¼è¯·è¾å
¥å¯ç ã"
+
+#: src/chatpanel.cpp:1590
+msgid "Mute User"
+msgstr "ç¦è¨ç¨æ·"
+
+#: src/chatpanel.cpp:1590
+msgid "For how many minutes should the user be muted?"
+msgstr "该ç¨æ·å°è¢«ç¦è¨å åéï¼"
+
+#: src/chatpanel.cpp:1632
+msgid "Kick User"
+msgstr "踢åºç¨æ·"
+
+#: src/chatpanel.cpp:1632 src/chatpanel.cpp:1691
+msgid "Reason:"
+msgstr "åå ï¼"
+
+#: src/chatpanel.cpp:1691
+msgid "Kick user"
+msgstr "踢åºç¨æ·"
+
+#: src/chatpanel.cpp:1711
+msgid "Mute user"
+msgstr "ç¦è¨ç¨æ·"
+
+#: src/chatpanel.cpp:1711
+msgid "Duration:"
+msgstr "æç»æ¶é´ï¼"
+
+#: src/chatpanel.cpp:1797
+#, fuzzy
+msgid "couldn't add user"
+msgstr "æ æ³å¯å¨æµè§å¨ã"
+
+#: src/connectwindow.cpp:43
+msgid "Connect to lobby server"
+msgstr "è¿æ¥å°å¯¹æ大å
æå¡å¨"
+
+#: src/connectwindow.cpp:66
+msgid ""
+"Server to connect to. You can connect to any server you like by typing in "
+"hostaddress:port format."
+msgstr "æå¡å¨è¿æ¥è³ã ä½ å¯ä»¥ä»¥ 主æºå°å:端å£å· çæ ¼å¼è¾å
¥å¹¶è¿æ¥å°ä»»ä½æå¡å¨ã"
+
+#: src/connectwindow.cpp:72 src/connectwindow.cpp:159
+#: src/hostbattledialog.cpp:105 src/ui.cpp:165
+msgid "Password"
+msgstr "å¯ç "
+
+#: src/connectwindow.cpp:74
+msgid "Remember password"
+msgstr "è®°ä½å¯ç "
+
+#: src/connectwindow.cpp:75
+msgid "Autoconnect next time"
+msgstr "ä¸æ¬¡èªå¨è¿æ¥"
+
+#: src/connectwindow.cpp:76
+msgid ""
+"remember connection details and automatically connect to server on next "
+"lobby startup"
+msgstr "è®°ä½è¿æ¥è¯¦ç»è®¾ç½®å¹¶å¨ä¸æ¬¡æ¸¸æ大å
å¯å¨æ¶èªå¨è¿æ¥å°æå¡å¨"
+
+#: src/connectwindow.cpp:84
+msgid ""
+"Note: If you do not have an account, you\n"
+" can register one for free under the\n"
+"\"Register\" tab."
+msgstr ""
+"æ示ï¼å¦æä½ è¿æ²¡æä¸ä¸ªè´¦æ·ï¼ä½ \n"
+"å¯ä»¥å¨â注åâé项å¡å
å
费注å\n"
+"ä¸ä¸ªã"
+
+#: src/connectwindow.cpp:90
+msgid "Login"
+msgstr "ç»é"
+
+#: src/connectwindow.cpp:91
+msgid "Register"
+msgstr "注å"
+
+#: src/connectwindow.cpp:146
+msgid "Nick"
+msgstr "æµç§°"
+
+#: src/connectwindow.cpp:260
+msgid "Invalid port."
+msgstr "æ æç端å£ã"
+
+#: src/connectwindow.cpp:260 src/connectwindow.cpp:266
+msgid "Invalid port"
+msgstr "æ æç端å£"
+
+#: src/connectwindow.cpp:266
+msgid ""
+"Port number out of range.\n"
+"\n"
+"It must be an integer between 1 and 65535"
+msgstr ""
+"端å£å·è¶
åºèå´ã\n"
+"\n"
+"端å£å·å¿
é¡»ä»äº1å°65535"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host/port."
+msgstr "æ æç主æº/端å£ã"
+
+#: src/connectwindow.cpp:275
+msgid "Invalid host"
+msgstr "æ æç主æº"
+
+#: src/connectwindow.cpp:293
+msgid ""
+"The entered nickname contains invalid characters like )? &%.\n"
+" Please try again"
+msgstr ""
+
+#: src/connectwindow.cpp:293
+#, fuzzy
+msgid "Invalid nickname"
+msgstr "æ æçæ°å"
+
+#: src/connectwindow.cpp:300
+#, fuzzy
+msgid ""
+"Registration failed, the reason was:\n"
+"Password / confirmation mismatch (or empty passwort)"
+msgstr ""
+"注å失败ï¼åå æ¯ï¼\n"
+"å¯ç ä¸ç¡®è®¤ä¸å¹é
"
+
+#: src/connectwindow.cpp:300 src/ui.cpp:247
+msgid "Registration failed."
+msgstr "注å失败ã"
+
+#: src/countrycodes.cpp:11
+msgid " Andorra"
+msgstr " å®éå°å
񆆫"
+
+#: src/countrycodes.cpp:12
+msgid "United Arab Emirates"
+msgstr "é¿æ伯èåé
é¿å½"
+
+#: src/countrycodes.cpp:13
+msgid "Afghanistan"
+msgstr "é¿å¯æ±"
+
+#: src/countrycodes.cpp:14
+msgid "Antigua and Barbuda"
+msgstr "å®æçåå·´å¸è¾¾"
+
+#: src/countrycodes.cpp:15
+msgid "Anguilla"
+msgstr "å®åæ"
+
+#: src/countrycodes.cpp:16
+msgid "Albania"
+msgstr "é¿å°å·´å°¼äº"
+
+#: src/countrycodes.cpp:17
+msgid "Armenia"
+msgstr "äºç¾å°¼äº"
+
+#: src/countrycodes.cpp:18
+msgid "Netherlands Antilles"
+msgstr "è·å±å®çåæ¯"
+
+#: src/countrycodes.cpp:19
+msgid "Angola"
+msgstr "å®å¥æ"
+
+#: src/countrycodes.cpp:20
+msgid "Antarctica"
+msgstr "åææ´²"
+
+#: src/countrycodes.cpp:21
+msgid "Argentina"
+msgstr "é¿æ ¹å»·"
+
+#: src/countrycodes.cpp:22
+msgid "American Samoa"
+msgstr "ç¾æ´²è¨æ©äº"
+
+#: src/countrycodes.cpp:23
+msgid "Austria"
+msgstr "奥å°å©"
+
+#: src/countrycodes.cpp:24
+msgid "Australia"
+msgstr "澳大å©äº"
+
+#: src/countrycodes.cpp:25
+msgid "Aruba"
+msgstr "é¿é²å·´"
+
+#: src/countrycodes.cpp:26
+msgid "Azerbaijan"
+msgstr "é¿å¡æç"
+
+#: src/countrycodes.cpp:27
+msgid "Bosnia and Herzegovina"
+msgstr "æ³¢æ¯å°¼äºåé»å¡å¥ç»´é£"
+
+#: src/countrycodes.cpp:28
+msgid "Barbados"
+msgstr "å·´å·´å¤æ¯"
+
+#: src/countrycodes.cpp:29
+msgid "Bangladesh"
+msgstr "åå æå½"
+
+#: src/countrycodes.cpp:30
+msgid "Belgium"
+msgstr "æ¯å©æ¶"
+
+#: src/countrycodes.cpp:31
+msgid "Burkina Faso"
+msgstr "å¸åºçº³æ³ç´¢"
+
+#: src/countrycodes.cpp:32
+msgid "Bulgaria"
+msgstr "ä¿å å©äº"
+
+#: src/countrycodes.cpp:33
+msgid "Bahrain"
+msgstr "å·´æ"
+
+#: src/countrycodes.cpp:34
+msgid "Burundi"
+msgstr "å¸é迪"
+
+#: src/countrycodes.cpp:35
+msgid "Benin"
+msgstr "è´å®"
+
+#: src/countrycodes.cpp:36
+msgid "Bermuda"
+msgstr "ç¾æ
大"
+
+#: src/countrycodes.cpp:37
+msgid "Brunei Darussalam"
+msgstr "æè±å¾·é²è¨å
°"
+
+#: src/countrycodes.cpp:38
+msgid "Bolivia"
+msgstr "ç»å©ç»´äº"
+
+#: src/countrycodes.cpp:39
+msgid "Brazil"
+msgstr "巴西"
+
+#: src/countrycodes.cpp:40
+msgid "Bahamas"
+msgstr "å·´å马"
+
+#: src/countrycodes.cpp:41
+msgid "Bhutan"
+msgstr "ä¸ä¸¹"
+
+#: src/countrycodes.cpp:42
+msgid "Bouvet Island"
+msgstr "å¸ç»´ç¾¤å²"
+
+#: src/countrycodes.cpp:43
+msgid "Botswana"
+msgstr "åè¨ç¦çº³"
+
+#: src/countrycodes.cpp:44
+msgid "Belarus"
+msgstr "ç½ä¿ç½æ¯"
+
+#: src/countrycodes.cpp:45
+msgid "Belize"
+msgstr "伯å©å
¹"
+
+#: src/countrycodes.cpp:46
+msgid "Canada"
+msgstr "å æ¿å¤§"
+
+#: src/countrycodes.cpp:47
+msgid "Cocos (Keeling Islands)"
+msgstr "æ¯ææ¯ç¾¤å²"
+
+#: src/countrycodes.cpp:48
+msgid "Central African Republic"
+msgstr "ä¸éå
񆆫"
+
+#: src/countrycodes.cpp:49
+msgid "Congo"
+msgstr "åæ"
+
+#: src/countrycodes.cpp:50
+msgid "Switzerland"
+msgstr "ç士"
+
+#: src/countrycodes.cpp:51
+msgid "Cote D'Ivoire (Ivory Coast)"
+msgstr "象ç海岸"
+
+#: src/countrycodes.cpp:52
+msgid "Cook Islands"
+msgstr "åºå
群å²"
+
+#: src/countrycodes.cpp:53
+msgid "Chile"
+msgstr "æºå©"
+
+#: src/countrycodes.cpp:54
+msgid "Cameroon"
+msgstr "å麦é"
+
+#: src/countrycodes.cpp:55
+msgid "China"
+msgstr "ä¸å½"
+
+#: src/countrycodes.cpp:56
+msgid "Colombia"
+msgstr "å¥ä¼¦æ¯äº"
+
+#: src/countrycodes.cpp:57
+msgid "Costa Rica"
+msgstr "å¥æ¯è¾¾é»å "
+
+#: src/countrycodes.cpp:58
+msgid "Cuba"
+msgstr "å¤å·´"
+
+#: src/countrycodes.cpp:59
+msgid "Cape Verde"
+msgstr "ä½å¾è§"
+
+#: src/countrycodes.cpp:60
+msgid "Christmas Island"
+msgstr "å£è¯å²"
+
+#: src/countrycodes.cpp:61
+msgid "Cyprus"
+msgstr "å¡æ®åæ¯"
+
+#: src/countrycodes.cpp:62
+msgid "Czech Republic"
+msgstr "æ·å
å
񆆫"
+
+#: src/countrycodes.cpp:63
+msgid "Germany"
+msgstr "å¾·å½"
+
+#: src/countrycodes.cpp:64
+msgid "Djibouti"
+msgstr "åå¸æ"
+
+#: src/countrycodes.cpp:65
+msgid "Denmark"
+msgstr "丹麦"
+
+#: src/countrycodes.cpp:66
+msgid "Dominica"
+msgstr "å¤ç±³å°¼å "
+
+#: src/countrycodes.cpp:67
+msgid "Dominican Republic"
+msgstr "å¤ç±³å°¼å å
񆆫"
+
+#: src/countrycodes.cpp:68
+msgid "Algeria"
+msgstr "é¿å°åå©äº"
+
+#: src/countrycodes.cpp:69
+msgid "Ecuador"
+msgstr "åçå¤å°"
+
+#: src/countrycodes.cpp:70
+msgid "Estonia"
+msgstr "ç±æ²å°¼äº"
+
+#: src/countrycodes.cpp:71
+msgid "Egypt"
+msgstr "åå"
+
+#: src/countrycodes.cpp:72
+msgid "Western Sahara"
+msgstr "西æåæ"
+
+#: src/countrycodes.cpp:73
+msgid "Eritrea"
+msgstr "åç«ç¹éäº"
+
+#: src/countrycodes.cpp:74
+msgid "Spain"
+msgstr "西çç"
+
+#: src/countrycodes.cpp:75
+msgid "Ethiopia"
+msgstr "åå¡ä¿æ¯äº"
+
+#: src/countrycodes.cpp:76
+msgid "Finland"
+msgstr "è¬å
°"
+
+#: src/countrycodes.cpp:77
+msgid "Fiji"
+msgstr "ææµ"
+
+#: src/countrycodes.cpp:78
+msgid "Falkland Islands (Malvinas)"
+msgstr "ç¦å
å
°ç¾¤å²(马å°ç»´çº³æ¯)"
+
+#: src/countrycodes.cpp:79
+msgid "Micronesia"
+msgstr "å¯å
ç½å°¼è¥¿äº"
+
+#: src/countrycodes.cpp:80
+msgid "Faroe Islands"
+msgstr "æ³ç½ç¾¤å²"
+
+#: src/countrycodes.cpp:81
+msgid "France"
+msgstr "æ³å½"
+
+#: src/countrycodes.cpp:82
+msgid "France, Metropolitan"
+msgstr "æ³å½ï¼æ¬§æ´²æ¬å"
+
+#: src/countrycodes.cpp:83
+msgid "Gabon"
+msgstr "å è¬"
+
+#: src/countrycodes.cpp:84
+msgid "Grenada"
+msgstr "æ ¼æ纳达"
+
+#: src/countrycodes.cpp:85
+msgid "Georgia"
+msgstr "æ ¼é²åäº"
+
+#: src/countrycodes.cpp:86
+msgid "French Guiana"
+msgstr "æ³å±åäºé£"
+
+#: src/countrycodes.cpp:87
+msgid "Ghana"
+msgstr "å 纳"
+
+#: src/countrycodes.cpp:88
+msgid "Gibraltar"
+msgstr "ç´å¸ç½é"
+
+#: src/countrycodes.cpp:89
+msgid "Greenland"
+msgstr "æ ¼éµå
°"
+
+#: src/countrycodes.cpp:90
+msgid "Gambia"
+msgstr "åæ¯äº"
+
+#: src/countrycodes.cpp:91
+msgid "Guinea"
+msgstr "å å
äº"
+
+#: src/countrycodes.cpp:92
+msgid "Guadeloupe"
+msgstr "çå¾·ç½æ®"
+
+#: src/countrycodes.cpp:93
+msgid "Equatorial Guinea"
+msgstr "赤éå å
äº"
+
+#: src/countrycodes.cpp:94
+msgid "Greece"
+msgstr "å¸è
"
+
+#: src/countrycodes.cpp:95
+msgid "S. Georgia and S. Sandwich Isls."
+msgstr "åä¹æ²»äºä¸åä¸æ治群å²"
+
+#: src/countrycodes.cpp:96
+msgid "Guatemala"
+msgstr "å±å°é©¬æ"
+
+#: src/countrycodes.cpp:97
+msgid "Guam"
+msgstr "å
³å²"
+
+#: src/countrycodes.cpp:98
+msgid "Guinea-Bissau"
+msgstr "å å
äºæ¯ç»"
+
+#: src/countrycodes.cpp:99
+msgid "Guyana"
+msgstr "åäºé£"
+
+#: src/countrycodes.cpp:100
+msgid "Hong Kong"
+msgstr "é¦æ¸¯ç¹å«è¡æ¿åº"
+
+#: src/countrycodes.cpp:101
+msgid "Heard and McDonald Islands"
+msgstr "赫德ä¸éº¦å
å纳群å²"
+
+#: src/countrycodes.cpp:102
+msgid "Honduras"
+msgstr "æ´ªé½ææ¯"
+
+#: src/countrycodes.cpp:103
+msgid "Croatia (Hrvatska)"
+msgstr "å
ç½å°äº"
+
+#: src/countrycodes.cpp:104
+msgid "Haiti"
+msgstr "æµ·å°"
+
+#: src/countrycodes.cpp:105
+msgid "Hungary"
+msgstr "åçå©"
+
+#: src/countrycodes.cpp:106
+msgid "Indonesia"
+msgstr "å°åº¦å°¼è¥¿äº"
+
+#: src/countrycodes.cpp:107
+msgid "Ireland"
+msgstr "ç±å°å
°"
+
+#: src/countrycodes.cpp:108
+msgid "Israel"
+msgstr "以è²å"
+
+#: src/countrycodes.cpp:109
+msgid "India"
+msgstr "å°åº¦"
+
+#: src/countrycodes.cpp:110
+msgid "British Indian Ocean Territory"
+msgstr "è±å±å°åº¦æ´å°åº"
+
+#: src/countrycodes.cpp:111
+msgid "Iraq"
+msgstr "ä¼æå
"
+
+#: src/countrycodes.cpp:112
+msgid "Iran"
+msgstr "ä¼æ"
+
+#: src/countrycodes.cpp:113
+msgid "Iceland"
+msgstr "å°å²"
+
+#: src/countrycodes.cpp:114
+msgid "Italy"
+msgstr "æ大å©"
+
+#: src/countrycodes.cpp:115
+msgid "Jamaica"
+msgstr "çä¹°å "
+
+#: src/countrycodes.cpp:116
+msgid "Jordan"
+msgstr "约æ¦"
+
+#: src/countrycodes.cpp:117
+msgid "Japan"
+msgstr "æ¥æ¬"
+
+#: src/countrycodes.cpp:118
+msgid "Kenya"
+msgstr "è¯å°¼äº"
+
+#: src/countrycodes.cpp:119
+msgid "Kyrgyzstan (Kyrgyz Republic)"
+msgstr "åå°åæ¯æ¯å¦"
+
+#: src/countrycodes.cpp:120
+msgid "Cambodia"
+msgstr "æ¬å寨"
+
+#: src/countrycodes.cpp:121
+msgid "Kiribati"
+msgstr "åºéå·´æ¯"
+
+#: src/countrycodes.cpp:122
+msgid "Comoros"
+msgstr "ç§æ©ç½"
+
+#: src/countrycodes.cpp:123
+msgid "Saint Kitts and Nevis"
+msgstr "å£åºè¨å尼维æ¯"
+
+#: src/countrycodes.cpp:124
+msgid "Korea (North) (People's Republic)"
+msgstr "æé²"
+
+#: src/countrycodes.cpp:125
+msgid "Korea (South) (Republic)"
+msgstr "é©å½"
+
+#: src/countrycodes.cpp:126
+msgid "Kuwait"
+msgstr "ç§å¨ç¹"
+
+#: src/countrycodes.cpp:127
+msgid "Cayman Islands"
+msgstr "å¼æ¼ç¾¤å²"
+
+#: src/countrycodes.cpp:128
+msgid "Kazakhstan"
+msgstr "åè¨å
æ¯å¦"
+
+#: src/countrycodes.cpp:129
+msgid "Laos"
+msgstr "èæ"
+
+#: src/countrycodes.cpp:130
+msgid "Lebanon"
+msgstr "é»å·´å«©"
+
+#: src/countrycodes.cpp:131
+msgid "Saint Lucia"
+msgstr "å£è·¯è¥¿äº"
+
+#: src/countrycodes.cpp:132
+msgid "Liechtenstein"
+msgstr "åæ¯æ¦å£«ç»"
+
+#: src/countrycodes.cpp:133
+msgid "Sri Lanka"
+msgstr "æ¯éå
°å¡"
+
+#: src/countrycodes.cpp:134
+msgid "Liberia"
+msgstr "å©æ¯éäº"
+
+#: src/countrycodes.cpp:135
+msgid "Lesotho"
+msgstr "è±ç´¢æ"
+
+#: src/countrycodes.cpp:136
+msgid "Lithuania"
+msgstr "ç«é¶å®"
+
+#: src/countrycodes.cpp:137
+msgid "Luxembourg"
+msgstr "å¢æ£®å ¡"
+
+#: src/countrycodes.cpp:138
+msgid "Latvia"
+msgstr "æè±ç»´äº"
+
+#: src/countrycodes.cpp:139
+msgid "Libya"
+msgstr "å©æ¯äº"
+
+#: src/countrycodes.cpp:140
+msgid "Morocco"
+msgstr "æ©æ´å¥"
+
+#: src/countrycodes.cpp:141
+msgid "Monaco"
+msgstr "æ©çº³å¥"
+
+#: src/countrycodes.cpp:142
+msgid "Moldova"
+msgstr "æ©å°å¤ç¦"
+
+#: src/countrycodes.cpp:143
+msgid "Montenegro"
+msgstr "èç¹å°¼æ ¼ç½å
񆆫"
+
+#: src/countrycodes.cpp:144
+msgid "Madagascar"
+msgstr "马达å æ¯å "
+
+#: src/countrycodes.cpp:145
+msgid "Marshall Islands"
+msgstr "马ç»å°ç¾¤å²"
+
+#: src/countrycodes.cpp:146
+msgid "Macedonia"
+msgstr "马å
¶é¡¿"
+
+#: src/countrycodes.cpp:147
+msgid "Mali"
+msgstr "马é"
+
+#: src/countrycodes.cpp:148
+msgid "Myanmar"
+msgstr "ç¼
ç¸"
+
+#: src/countrycodes.cpp:149
+msgid "Mongolia"
+msgstr "èå¤"
+
+#: src/countrycodes.cpp:150
+msgid "Macau"
+msgstr "æ¾³é¨ç¹å«è¡æ¿åº"
+
+#: src/countrycodes.cpp:151
+msgid "Northern Mariana Islands"
+msgstr "å马éäºçº³ç¾¤å²"
+
+#: src/countrycodes.cpp:152
+msgid "Martinique"
+msgstr "马æå°¼å
"
+
+#: src/countrycodes.cpp:153
+msgid "Mauritania"
+msgstr "æ¯éå¡å°¼äº"
+
+#: src/countrycodes.cpp:154
+msgid "Montserrat"
+msgstr "èç¹å¡æç¹"
+
+#: src/countrycodes.cpp:155
+msgid "Malta"
+msgstr "马è³ä»"
+
+#: src/countrycodes.cpp:156
+msgid "Mauritius"
+msgstr "æ¯éæ±æ¯"
+
+#: src/countrycodes.cpp:157
+msgid "Maldives"
+msgstr "马å°ä»£å¤«"
+
+#: src/countrycodes.cpp:158
+msgid "Malawi"
+msgstr "马æç»´"
+
+#: src/countrycodes.cpp:159
+msgid "Mexico"
+msgstr "墨西å¥"
+
+#: src/countrycodes.cpp:160
+msgid "Malaysia"
+msgstr "马æ¥è¥¿äº"
+
+#: src/countrycodes.cpp:161
+msgid "Mozambique"
+msgstr "è«æ¡æ¯å
"
+
+#: src/countrycodes.cpp:162
+msgid "Namibia"
+msgstr "纳米æ¯äº"
+
+#: src/countrycodes.cpp:163
+msgid "New Caledonia"
+msgstr "æ°åéå¤å°¼äº"
+
+#: src/countrycodes.cpp:164
+msgid "Niger"
+msgstr "å°¼æ¥å°"
+
+#: src/countrycodes.cpp:165
+msgid "Norfolk Island"
+msgstr "诺ç¦å
å²"
+
+#: src/countrycodes.cpp:166
+msgid "Nigeria"
+msgstr "å°¼æ¥å©äº"
+
+#: src/countrycodes.cpp:167
+msgid "Nicaragua"
+msgstr "å°¼å æç"
+
+#: src/countrycodes.cpp:168
+msgid "Netherlands"
+msgstr "è·å
°"
+
+#: src/countrycodes.cpp:169
+msgid "Norway"
+msgstr "æªå¨"
+
+#: src/countrycodes.cpp:170
+msgid "Nepal"
+msgstr "å°¼æ³å°"
+
+#: src/countrycodes.cpp:171
+msgid "Nauru"
+msgstr "çé²"
+
+#: src/countrycodes.cpp:172
+msgid "Neutral Zone (Saudia Arabia/Iraq)"
+msgstr "ä¸ç«åºï¼æ²ç¹é¿æ伯/ä¼æå
ï¼"
+
+#: src/countrycodes.cpp:173
+msgid "Niue"
+msgstr "纽å"
+
+#: src/countrycodes.cpp:174
+msgid "New Zealand"
+msgstr "æ°è¥¿å
°"
+
+#: src/countrycodes.cpp:175
+msgid "Oman"
+msgstr "é¿æ¼"
+
+#: src/countrycodes.cpp:176
+msgid "Panama"
+msgstr "å·´æ¿é©¬"
+
+#: src/countrycodes.cpp:177
+msgid "Peru"
+msgstr "ç§é²"
+
+#: src/countrycodes.cpp:178
+msgid "French Polynesia"
+msgstr "æ³å±æ³¢å©å°¼è¥¿äº"
+
+#: src/countrycodes.cpp:179
+msgid "Papua New Guinea"
+msgstr "å·´å¸äºæ°å å
äº"
+
+#: src/countrycodes.cpp:180
+msgid "Philippines"
+msgstr "è²å¾å®¾"
+
+#: src/countrycodes.cpp:181
+msgid "Pakistan"
+msgstr "å·´åºæ¯å¦"
+
+#: src/countrycodes.cpp:182
+msgid "Poland"
+msgstr "æ³¢å
°"
+
+#: src/countrycodes.cpp:183
+msgid "St. Pierre and Miquelon"
+msgstr "å£ç®åå°å麦å
伦群å²"
+
+#: src/countrycodes.cpp:184
+msgid "Pitcairn"
+msgstr "ç®ç¹å
æ©"
+
+#: src/countrycodes.cpp:185
+msgid "Puerto Rico"
+msgstr "æ³¢å¤é»å"
+
+#: src/countrycodes.cpp:186
+msgid "Portugal"
+msgstr "è¡èç"
+
+#: src/countrycodes.cpp:187
+msgid "Palau"
+msgstr "å¸å³"
+
+#: src/countrycodes.cpp:188
+msgid "Paraguay"
+msgstr "å·´æå"
+
+#: src/countrycodes.cpp:189
+msgid "Qatar"
+msgstr "å¡å¡å°"
+
+#: src/countrycodes.cpp:190
+msgid "Reunion"
+msgstr "ç尼汪"
+
+#: src/countrycodes.cpp:191
+msgid "Romania"
+msgstr "ç½é©¬å°¼äº"
+
+#: src/countrycodes.cpp:192
+msgid "Serbia"
+msgstr "å¡å°ç»´äº"
+
+#: src/countrycodes.cpp:193
+msgid "Russian Federation"
+msgstr "ä¿ç½æ¯"
+
+#: src/countrycodes.cpp:194
+msgid "Rwanda"
+msgstr "å¢æºè¾¾"
+
+#: src/countrycodes.cpp:195
+msgid "Saudi Arabia"
+msgstr "æ²ç¹é¿æ伯"
+
+#: src/countrycodes.cpp:196
+msgid "Solomon Islands"
+msgstr "æç½é¨ç¾¤å²"
+
+#: src/countrycodes.cpp:197
+msgid "Seychelles"
+msgstr "å¡èå°"
+
+#: src/countrycodes.cpp:198
+msgid "Sudan"
+msgstr "è丹"
+
+#: src/countrycodes.cpp:199
+msgid "Sweden"
+msgstr "çå
¸"
+
+#: src/countrycodes.cpp:200
+msgid "Singapore"
+msgstr "æ°å å¡"
+
+#: src/countrycodes.cpp:201
+msgid "St. Helena"
+msgstr "å£èµ«åæ¿å²"
+
+#: src/countrycodes.cpp:202
+msgid "Slovenia"
+msgstr "æ¯æ´æå°¼äº"
+
+#: src/countrycodes.cpp:203
+msgid "Svalbard and Jan Mayen Islands"
+msgstr "æ¯ç¦å°å·´ç¹åæ¬é©¬å»¶å²"
+
+#: src/countrycodes.cpp:204
+msgid "Slovakia (Slovak Republic)"
+msgstr "æ¯æ´ä¼å
"
+
+#: src/countrycodes.cpp:205
+msgid "Sierra Leone"
+msgstr "å¡æå©æ"
+
+#: src/countrycodes.cpp:206
+msgid "San Marino"
+msgstr "å£é©¬å诺"
+
+#: src/countrycodes.cpp:207
+msgid "Senegal"
+msgstr "å¡å
å å°"
+
+#: src/countrycodes.cpp:208
+msgid "Somalia"
+msgstr "索马é"
+
+#: src/countrycodes.cpp:209
+msgid "Suriname"
+msgstr "èéå"
+
+#: src/countrycodes.cpp:210
+msgid "Sao Tome and Principe"
+msgstr "å£å¤ç¾åæ®æ西æ¯"
+
+#: src/countrycodes.cpp:211
+msgid "Soviet Union (former)"
+msgstr "åèè"
+
+#: src/countrycodes.cpp:212
+msgid "El Salvador"
+msgstr "è¨å°ç¦å¤"
+
+#: src/countrycodes.cpp:213
+msgid "Syria"
+msgstr "åå©äº"
+
+#: src/countrycodes.cpp:214
+msgid "Swaziland"
+msgstr "å²ç¦æµå
°"
+
+#: src/countrycodes.cpp:215
+msgid "Turks and Caicos Islands"
+msgstr "ç¹å
æ¯åå¯ç§æ¯ç¾¤å²"
+
+#: src/countrycodes.cpp:216
+msgid "Chad"
+msgstr "ä¹å¾"
+
+#: src/countrycodes.cpp:217
+msgid "French Southern Territories"
+msgstr "æ³å±ååçé¢å°"
+
+#: src/countrycodes.cpp:218
+msgid "Togo"
+msgstr "å¤å¥"
+
+#: src/countrycodes.cpp:219
+msgid "Thailand"
+msgstr "æ³°å½"
+
+#: src/countrycodes.cpp:220
+msgid "Tajikistan"
+msgstr "å¡åå
æ¯å¦"
+
+#: src/countrycodes.cpp:221
+msgid "Tokelau"
+msgstr "æå
å³ç¾¤å²"
+
+#: src/countrycodes.cpp:222
+msgid "Turkmenistan"
+msgstr "ååºæ¼æ¯å¦"
+
+#: src/countrycodes.cpp:223
+msgid "Tunisia"
+msgstr "çªå°¼æ¯"
+
+#: src/countrycodes.cpp:224
+msgid "Tonga"
+msgstr "汤å "
+
+#: src/countrycodes.cpp:225
+msgid "East Timor"
+msgstr "ä¸å¸æ±¶"
+
+#: src/countrycodes.cpp:226
+msgid "Turkey"
+msgstr "åè³å
¶"
+
+#: src/countrycodes.cpp:227
+msgid "Trinidad and Tobago"
+msgstr "ç¹é尼达åå¤å·´å¥"
+
+#: src/countrycodes.cpp:228
+msgid "Tuvalu"
+msgstr "å¾ç¦å¢"
+
+#: src/countrycodes.cpp:229
+msgid "Taiwan"
+msgstr "ä¸å½å°æ¹¾"
+
+#: src/countrycodes.cpp:230
+msgid "Tanzania"
+msgstr "å¦æ¡å°¼äº"
+
+#: src/countrycodes.cpp:231
+msgid "Ukraine"
+msgstr "ä¹å
å
°"
+
+#: src/countrycodes.cpp:232
+msgid "Uganda"
+msgstr "ä¹å¹²è¾¾"
+
+#: src/countrycodes.cpp:233
+msgid "United Kingdom (Great Britain)"
+msgstr "è±å½"
+
+#: src/countrycodes.cpp:234
+msgid "US Minor Outlying Islands"
+msgstr "ç¾å½å¨è¾¹å²å±¿"
+
+#: src/countrycodes.cpp:235
+msgid "United States"
+msgstr "ç¾å½"
+
+#: src/countrycodes.cpp:236
+msgid "Uruguay"
+msgstr "ä¹æå"
+
+#: src/countrycodes.cpp:237
+msgid "Uzbekistan"
+msgstr "ä¹å
¹å«å
æ¯å¦"
+
+#: src/countrycodes.cpp:238
+msgid "Vatican City State (Holy See)"
+msgstr "梵èååå½ (æå»·)"
+
+#: src/countrycodes.cpp:239
+msgid "Saint Vincent and The Grenadines"
+msgstr "å£æ森ç¹åæ ¼æ纳ä¸æ¯"
+
+#: src/countrycodes.cpp:240
+msgid "Venezuela"
+msgstr "å§å
çæ"
+
+#: src/countrycodes.cpp:241
+msgid "Virgin Islands (British)"
+msgstr "è±å±ç»´äº¬ç¾¤å²"
+
+#: src/countrycodes.cpp:242
+msgid "Virgin Islands (US)"
+msgstr "ç¾å±ç»´äº¬ç¾¤å²"
+
+#: src/countrycodes.cpp:243
+msgid "Viet Nam"
+msgstr "è¶å"
+
+#: src/countrycodes.cpp:244
+msgid "Vanuatu"
+msgstr "ç¦åªé¿å¾"
+
+#: src/countrycodes.cpp:245
+msgid "Wallis and Futuna Islands"
+msgstr "ç¦å©æ¯åå¯å¾ç¾¤å²"
+
+#: src/countrycodes.cpp:246
+msgid "Samoa"
+msgstr "è¨æ©äº"
+
+#: src/countrycodes.cpp:247
+msgid "Yemen"
+msgstr "ä¹é¨"
+
+#: src/countrycodes.cpp:248
+msgid "Mayotte"
+msgstr "马约ç¹"
+
+#: src/countrycodes.cpp:249
+msgid "Yugoslavia"
+msgstr "åæ¯æ夫"
+
+#: src/countrycodes.cpp:250
+msgid "South Africa"
+msgstr "åé"
+
+#: src/countrycodes.cpp:251
+msgid "Zambia"
+msgstr "èµæ¯äº"
+
+#: src/countrycodes.cpp:252
+msgid "Zaire"
+msgstr "æä¼å°"
+
+#: src/countrycodes.cpp:253
+msgid "Zimbabwe"
+msgstr "津巴å¸é¦"
+
+#: src/countrycodes.cpp:260
+msgid "(Full country name not found)"
+msgstr "ï¼å½å®¶å称æªæ¾å°ï¼"
+
+#: src/crashreport.cpp:66
+msgid "System informations"
+msgstr "ç³»ç»ä¿¡æ¯"
+
+#: src/crashreport.cpp:68
+msgid "Application verbose log"
+msgstr "åºç¨ç¨åºè¯¦ç»æ¥å¿"
+
+#: src/crashreport.cpp:70
+msgid "Last generated spring launching script"
+msgstr "ä¸ä¸æ¬¡çæçSpringå¯å¨èæ¬"
+
+#: src/filelister/filelistctrl.cpp:43 src/filelister/filelistctrl.cpp:45
+#: src/mapselectdialog.cpp:260 src/selectusersdialog.cpp:73
+#: src/torrentlistctrl.cpp:40 src/widgets/downloadlistctrl.cpp:28
+#: src/widgets/infopanel.cpp:59
+#, fuzzy
+msgid "Name"
+msgstr "游æ"
+
+#: src/filelister/filelistctrl.cpp:47 src/filelister/filelistctrl.cpp:49
+msgid "Type"
+msgstr ""
+
+#: src/filelister/filelistctrl.cpp:51 src/filelister/filelistctrl.cpp:53
+msgid "Hash"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:30
+#, fuzzy
+msgid "Search and download files"
+msgstr "æç´¢æ件"
+
+#: src/filelister/filelistdialog.cpp:33
+msgid "Files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:58
+#, fuzzy
+msgid "Download selected"
+msgstr "ä¸è½½å®æ¯"
+
+#: src/filelister/filelistdialog.cpp:104
+#, c-format
+msgid "%u files displayed"
+msgstr ""
+
+#: src/filelister/filelistdialog.cpp:146
+#, fuzzy
+msgid "unknown hash "
+msgstr "æªç¥"
+
+#: src/groupoptionspanel.cpp:55 src/groupoptionspanel.cpp:168
+#: src/widgets/infopanel.cpp:93
+#, fuzzy
+msgid "Remove"
+msgstr "移é¤..."
+
+#: src/groupoptionspanel.cpp:57
+msgid "Remove an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:61
+#, fuzzy
+msgid "Rename.."
+msgstr "移é¤..."
+
+#: src/groupoptionspanel.cpp:63
+msgid "Rename an existing group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:70
+#, fuzzy
+msgid "Add New.."
+msgstr "æ·»å AI..."
+
+#: src/groupoptionspanel.cpp:71
+msgid "Add new group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:84
+#, fuzzy
+msgid "Group Actions"
+msgstr "å¨ä½"
+
+#: src/groupoptionspanel.cpp:89
+msgid "Notify login/logout"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:91
+msgid "Notify when users of this group go online or offline"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:95
+#, fuzzy
+msgid "Ignore Chat"
+msgstr "å
¬ä¼è天"
+
+#: src/groupoptionspanel.cpp:97
+msgid "Ignore anything said in channel by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:101
+#, fuzzy
+msgid "Notify Hosted Battles"
+msgstr "主建æ°ææ"
+
+#: src/groupoptionspanel.cpp:103
+msgid "Notify when users of this group hosts a battle"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:107 src/springlobbyapp.cpp:449
+#: src/springlobbyapp.cpp:450
+msgid "Ignore PM"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:109
+msgid "Ignore anything said in private chat by any of the users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:113
+msgid "Notify Status Change"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:115
+msgid "Notify when the status of a users in this group changes"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:119
+msgid "Autokick"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:121
+msgid "Auto kick any of the users in this group from battles hosted"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:127
+msgid "Highlight battles and the names of users in this group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:134
+#, fuzzy
+msgid "Highlight Color"
+msgstr "é«äº®ææ¬"
+
+#: src/groupoptionspanel.cpp:139 src/groupoptionspanel.cpp:141
+msgid "Select highlight color"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:152
+msgid "Users in group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:163
+#, fuzzy
+msgid "Add.."
+msgstr "æ·»å AI..."
+
+#: src/groupoptionspanel.cpp:164
+msgid "Add users to group"
+msgstr ""
+
+#: src/groupoptionspanel.cpp:170
+#, fuzzy
+msgid "Remove users from group"
+msgstr "移é¤ç¨æ·å¸æ·"
+
+#: src/groupoptionspanel.cpp:264
+#, fuzzy
+msgid "Name of new group:"
+msgstr "ç¨æ·å"
+
+#: src/groupoptionspanel.cpp:264
+msgid "Add New Group"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:85
+msgid "previous"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:88
+msgid "next"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:92
+#, fuzzy
+msgid "delete"
+msgstr "åå°ç"
+
+#: src/Helper/imageviewer.cpp:96
+msgid "save as"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:146
+msgid "couldn't remove file"
+msgstr ""
+
+#: src/Helper/imageviewer.cpp:160
+#, fuzzy
+msgid "Choose a filename"
+msgstr "å¨æ¸¸æä¸éæ©"
+
+#: src/Helper/imageviewer.cpp:167
+#, fuzzy
+msgid "File successfully saved"
+msgstr ""
+"\n"
+"æåç被ä¿åå°ï¼\n"
+
+#: src/Helper/imageviewer.cpp:167 src/updater/updater.cpp:113
+#: src/updater/updater.cpp:116 src/widgets/infopanel.cpp:158
+#: src/widgets/infopanel.cpp:170
+#, fuzzy
+msgid "Success"
+msgstr "设置æé..."
+
+#: src/Helper/imageviewer.cpp:170
+#, fuzzy
+msgid "Couldn't save file"
+msgstr "æ æ³ä¿å\n"
+
+#: src/Helper/wxTranslationHelper.cpp:96 src/springlobbyapp.cpp:448
+#, fuzzy
+msgid "Default"
+msgstr "é»è®¤"
+
+#: src/Helper/wxTranslationHelper.cpp:127
+#, c-format
+msgid "SEARCHING FOR %s"
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:144
+msgid "Array of language names and identifiers should have the same size."
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:145
+#, fuzzy
+msgid "Select the language"
+msgstr "é¢éä¿¡æ¯"
+
+#: src/Helper/wxTranslationHelper.cpp:146
+#, fuzzy
+msgid "Language"
+msgstr "è¡ç»æ¨¡å¼"
+
+#: src/Helper/wxTranslationHelper.cpp:156
+#, c-format
+msgid "wxTranslationHelper: Path Prefix = \"%s\""
+msgstr ""
+
+#: src/Helper/wxTranslationHelper.cpp:159
+#, c-format
+msgid "wxTranslationHelper: Catalog Name = \"%s\""
+msgstr ""
+
+#: src/hostbattledialog.cpp:60
+msgid "Host new battle"
+msgstr "主建æ°ææ"
+
+#: src/hostbattledialog.cpp:78
+msgid "A short description of the game, this will show up in the battle list."
+msgstr "游æçç®çæè¿°ï¼è¿å°ä¼æ¾ç¤ºå¨å¤§å
ä¸ç游æå表ä¸ã"
+
+#: src/hostbattledialog.cpp:81
+#, fuzzy
+msgid "Autopaste description"
+msgstr "æè¿°"
+
+#: src/hostbattledialog.cpp:83
+msgid "Automatically write the battle description when a user joins."
+msgstr ""
+
+#: src/hostbattledialog.cpp:96
+msgid "Select the mod to play with."
+msgstr "éæ©æ¸¸æ使ç¨ç模ç»ã"
+
+#: src/hostbattledialog.cpp:110
+msgid "Password needed to join game. Keep empty for no password"
+msgstr "å å
¥è¯¥æ¸¸ææéè¦å¯ç ãä¿æ空ç½è¡¨ç¤ºæ²¡æå¯ç "
+
+#: src/hostbattledialog.cpp:113
+msgid "Port"
+msgstr "端å£"
+
+#: src/hostbattledialog.cpp:118
+msgid "UDP port to host game on. Default is 8452."
+msgstr "主建游ææ使ç¨çUDP端å£ãé»è®¤ä¸º8452ã"
+
+#: src/hostbattledialog.cpp:127
+msgid "Use relayhost"
+msgstr ""
+
+#: src/hostbattledialog.cpp:128
+msgid ""
+"host and control game on remote server, helps if you have trouble hosting"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+msgid "Chose automatically"
+msgstr ""
+
+#: src/hostbattledialog.cpp:133
+#, fuzzy
+msgid "Randomly picks an available one"
+msgstr "ä¸å¯ç¨"
+
+#: src/hostbattledialog.cpp:137
+msgid "Manually enter the manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:137
+msgid "You'll get prompted for the exact manager name"
+msgstr ""
+
+#: src/hostbattledialog.cpp:157 src/playback/playbacklistctrl.cpp:44
+msgid "Number of players"
+msgstr "ç©å®¶æ°é"
+
+#: src/hostbattledialog.cpp:161
+msgid "The maximum number of players to allow in the battle."
+msgstr "ææä¸å
许çæ大ç©å®¶æ°éã"
+
+#: src/hostbattledialog.cpp:169
+msgid "Hole punching"
+msgstr "ç©¿å"
+
+#: src/hostbattledialog.cpp:171
+msgid "NAT traversal"
+msgstr "NATç©¿è¶é»æ¡"
+
+#: src/hostbattledialog.cpp:177
+#, fuzzy
+msgid "NAT traversal to use."
+msgstr "NATç©¿è¶é»æ¡"
+
+#: src/hostbattledialog.cpp:182
+msgid "Minimum Rank needed"
+msgstr "æä½éæ±çº§å«"
+
+#: src/hostbattledialog.cpp:248
+msgid "Start hosting the battle."
+msgstr "å¼å§ä¸»å»ºæ¸¸æã"
+
+#: src/hostbattledialog.cpp:286 src/singleplayertab.cpp:235
+msgid "You have to select a mod first."
+msgstr "ä½ å¿
é¡»å
éæ©ä¸ä¸ªæ¨¡ç»ã"
+
+#: src/hostbattledialog.cpp:286
+msgid "No mod selected."
+msgstr "模ç»æªéæ©ã"
+
+#: src/hostbattledialog.cpp:344
+msgid "Manually chose a manager"
+msgstr ""
+
+#: src/hostbattledialog.cpp:344
+msgid "Please type the nick of the manager you want to use ( case sensitive )"
+msgstr ""
+
+#: src/httpdownloader.cpp:72
+msgid ""
+"\n"
+"successfully saved to:\n"
+msgstr ""
+"\n"
+"æåç被ä¿åå°ï¼\n"
+
+#: src/httpdownloader.cpp:78
+#, fuzzy
+msgid ""
+"\n"
+"successfully unzipped in:\n"
+msgstr ""
+"\n"
+"æåç被ä¿åå°ï¼\n"
+
+#: src/httpdownloader.cpp:79
+msgid ""
+"\n"
+" unzipping failed, please correct manually"
+msgstr ""
+
+#: src/httpdownloader.cpp:99
+msgid "Could not save\n"
+msgstr "æ æ³ä¿å\n"
+
+#: src/httpdownloader.cpp:99
+msgid ""
+"\n"
+"to:\n"
+msgstr ""
+"\n"
+"å°ï¼\n"
+
+#: src/httpdownloader.cpp:102
+msgid ""
+"\n"
+"Error number: "
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:44 src/lobbyoptionstab.cpp:45
+msgid "Web Browser"
+msgstr "ç½ç»æµè§å¨"
+
+#: src/lobbyoptionstab.cpp:47
+msgid "Default Browser."
+msgstr "é»è®¤æµè§å¨ã"
+
+#: src/lobbyoptionstab.cpp:49
+msgid "Use your system-wide browser preference"
+msgstr "使ç¨ä½ çç³»ç»æµè§å¨è®¾ç½®"
+
+#: src/lobbyoptionstab.cpp:51
+msgid "Specify:"
+msgstr "èªå®ä¹ï¼"
+
+#: src/lobbyoptionstab.cpp:52
+msgid "Specify the web browser you want to use"
+msgstr "èªå®ä¹ä½ æ³è¦ä½¿ç¨çæµè§å¨"
+
+#: src/lobbyoptionstab.cpp:56 src/lobbyoptionstab.cpp:78
+#: src/settings++/panel_pathoption.cpp:42 src/springoptionstab.cpp:69
+#: src/springoptionstab.cpp:79
+msgid "Browse"
+msgstr "æµè§"
+
+#: src/lobbyoptionstab.cpp:57
+msgid "Use a file dialog to find the web browser"
+msgstr "使ç¨ä¸ä¸ªæ件对è¯æ¡æ¥æ¥æ¾ç½ç»æµè§å¨"
+
+#: src/lobbyoptionstab.cpp:73
+msgid "External text editor"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:74
+msgid "Path"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:79
+#, fuzzy
+msgid "Use a file dialog to find the editor binary"
+msgstr "使ç¨ä¸ä¸ªæ件对è¯æ¡æ¥æ¥æ¾ç½ç»æµè§å¨"
+
+#: src/lobbyoptionstab.cpp:90
+#, fuzzy
+msgid "Autoconnect"
+msgstr "éæ°è¿æ¥"
+
+#: src/lobbyoptionstab.cpp:91
+msgid ""
+"If checked, SpringLobby will automatically log on to the last used server"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:92
+#, fuzzy
+msgid "Autoconnect on lobby start"
+msgstr "è¿æ¥å°å¯¹æ大å
æå¡å¨"
+
+#: src/lobbyoptionstab.cpp:97
+msgid "Report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:98
+msgid ""
+"By default SpringLobby will send some statistics (OS,SpringLobby version) to "
+"server,\n"
+"to both make helping you in case of problems easier and inform of critical "
+"updates.\n"
+"Uncheck to disable."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:99
+msgid "report statistics"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:110
+msgid "Automatic updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:111
+msgid ""
+"SpringLobby can check at startup if a newer version is available and "
+"automatically download it for you."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:112
+msgid "automatically check for updates"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:120
+#, fuzzy
+msgid "Tooltips"
+msgstr "å·¥å
·(&T)"
+
+#: src/lobbyoptionstab.cpp:121
+#, fuzzy
+msgid "Show Tooltips?"
+msgstr "æ¾ç¤ºå·¥å
·æ示"
+
+#: src/lobbyoptionstab.cpp:124
+msgid "Requires SpringLobby restart to take effect."
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:131
+msgid "Tab completion method"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:132
+msgid ""
+"\"Match exact\" will complete a word if there is one and only one match.\n"
+"\"Match nearest\" will select the (first) match that has closest Levenshtein "
+"distance"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:134
+#, fuzzy
+msgid "Match exact"
+msgstr "ææAIå¼å¸¸"
+
+#: src/lobbyoptionstab.cpp:135
+msgid "Match nearest"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:144
+msgid "Misc GUI"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:145
+msgid "Show big icons in mainwindow tabs?"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:150
+msgid "Show close button on all tabs? (needs restart to take effect)"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:155
+#, fuzzy
+msgid "Start tab"
+msgstr "åå§éå±"
+
+#: src/lobbyoptionstab.cpp:158
+msgid "Select which tab to show at startup"
+msgstr ""
+
+#: src/lobbyoptionstab.cpp:241
+msgid "Choose a web browser executable"
+msgstr "éæ©ä¸ä¸ªç½ç»æµè§å¨æ§è¡æ件"
+
+#: src/lobbyoptionstab.cpp:247
+#, fuzzy
+msgid "Choose a editor browser executable"
+msgstr "éæ©ä¸ä¸ªç½ç»æµè§å¨æ§è¡æ件"
+
+#: src/mainchattab.cpp:163 src/mainchattab.cpp:167
+#, fuzzy
+msgid "Disconnected from server, chat closed."
+msgstr "æå¡å¨ä¼ æ¥æªç¥çæ¡"
+
+#: src/mainjoinbattletab.cpp:58
+msgid "Battle list"
+msgstr "游æå表"
+
+#: src/mainjoinbattletab.cpp:140
+msgid "Battleroom"
+msgstr "游ææ¿é´"
+
+#: src/mainjoinbattletab.cpp:146 src/mainsingleplayertab.cpp:43
+#: src/mainwindow.h:188 src/settings++/tab_simple.cpp:134
+msgid "Options"
+msgstr "é项"
+
+#: src/mainjoinbattletab.cpp:149 src/mainsingleplayertab.cpp:45
+#, fuzzy
+msgid "Unit Restrictions"
+msgstr "åä½éå¶"
+
+#: src/mainoptionstab.cpp:64
+msgid "Spring"
+msgstr "Spring"
+
+#: src/mainoptionstab.cpp:68
+msgid "P2P"
+msgstr "ç¹å¯¹ç¹"
+
+#: src/mainoptionstab.cpp:72 src/mainwindow.h:180
+msgid "Chat"
+msgstr "è天"
+
+#: src/mainoptionstab.cpp:75
+#, fuzzy
+msgid "General"
+msgstr "å¡å
å å°"
+
+#: src/mainoptionstab.cpp:78
+msgid "Groups"
+msgstr ""
+
+#: src/mainoptionstab.cpp:80
+msgid "Restore"
+msgstr "æ¢å¤"
+
+#: src/mainoptionstab.cpp:81
+msgid "Apply"
+msgstr "åºç¨"
+
+#: src/mainsingleplayertab.cpp:41
+msgid "Game"
+msgstr "游æ"
+
+#: src/maintorrenttab.cpp:51
+msgid "Transfers in progress: "
+msgstr "æ£å¨ä¼ è¾ä¸ï¼ "
+
+#: src/maintorrenttab.cpp:57
+msgid "Total Outgoing: "
+msgstr "æ»å
±ä¸ä¼ ï¼ "
+
+#: src/maintorrenttab.cpp:58
+msgid "Total Incoming: "
+msgstr "æ»å
±ä¸è½½ï¼ "
+
+#: src/maintorrenttab.cpp:65
+msgid "unknown"
+msgstr "æªç¥"
+
+#: src/maintorrenttab.cpp:72
+msgid "Cancel Download"
+msgstr "åæ¶ä¸è½½"
+
+#: src/maintorrenttab.cpp:75
+msgid "Publish new file"
+msgstr "åå¸æ°æ件"
+
+#: src/maintorrenttab.cpp:77
+msgid "Search file"
+msgstr "æç´¢æ件"
+
+#: src/maintorrenttab.cpp:79
+#, fuzzy
+msgid "Download Lua widgets"
+msgstr "å¯ç¨ Luaå¾å½¢çé¢æ件"
+
+#: src/maintorrenttab.cpp:115
+msgid "Lua widget downloader"
+msgstr ""
+
+#: src/maintorrenttab.cpp:153
+msgid "not available"
+msgstr "ä¸å¯ç¨"
+
+#: src/maintorrenttab.cpp:156
+msgid "seeding"
+msgstr "åç§"
+
+#: src/maintorrenttab.cpp:157
+msgid "leeching"
+msgstr "å¸è¡ä¸"
+
+#: src/maintorrenttab.cpp:158
+msgid "queued"
+msgstr "éåä¸"
+
+#: src/maintorrenttab.cpp:204
+msgid "Status: not connected"
+msgstr "ç¶æï¼æªè¿æ¥"
+
+#: src/maintorrenttab.cpp:208
+msgid "Status: connected"
+msgstr "ç¶æï¼å·²è¿æ¥"
+
+#: src/maintorrenttab.cpp:212
+msgid "Status: throttled or paused (ingame)"
+msgstr "ç¶æï¼æåï¼å¨æ¸¸æä¸ï¼"
+
+#: src/maintorrenttab.cpp:216
+msgid "Status: unknown"
+msgstr "ç¶æï¼æªç¥"
+
+#: src/maintorrenttab.cpp:222
+#, c-format
+msgid "Total Outgoing: %.2f KB/s"
+msgstr "æ»å
±ä¸ä¼ ï¼ %.2f KB/s"
+
+#: src/maintorrenttab.cpp:223
+#, c-format
+msgid "Total Incoming: %.2f KB/s"
+msgstr "æ»å
±ä¸è½½ï¼ %.2f KB/s"
+
+#: src/mainwindow.cpp:118
+msgid "SpringLobby"
+msgstr "Spring游æ大å
"
+
+#: src/mainwindow.cpp:129
+msgid "&Connect..."
+msgstr "(&C) è¿æ¥..."
+
+#: src/mainwindow.cpp:130
+msgid "&Disconnect"
+msgstr "(&D) æå¼"
+
+#: src/mainwindow.cpp:133
+#, fuzzy
+msgid "&Save options"
+msgstr "å¾å½¢çé¢é项"
+
+#: src/mainwindow.cpp:136
+msgid "&Quit"
+msgstr "(&Q) éåº"
+
+#: src/mainwindow.cpp:150
+msgid "&Join channel..."
+msgstr "(&J) å å
¥é¢é..."
+
+#: src/mainwindow.cpp:151
+#, fuzzy
+msgid "Channel &list"
+msgstr "é¢éä¿¡æ¯"
+
+#: src/mainwindow.cpp:152
+msgid "Open private &chat..."
+msgstr "(&C) æå¼ç§äººè天..."
+
+#: src/mainwindow.cpp:153
+msgid "&Autojoin channels..."
+msgstr "(&A) èªå¨å å
¥é¢é"
+
+#: src/mainwindow.cpp:154
+msgid "&View screenshots"
+msgstr ""
+
+#: src/mainwindow.cpp:156
+msgid "&Reload maps/mods"
+msgstr "(&R) éæ°è½½å
¥å°å¾/模ç»"
+
+#: src/mainwindow.cpp:162
+msgid "Check for new Version"
+msgstr "æ£æ¥æ°çæ¬"
+
+#: src/mainwindow.cpp:163
+msgid "SpringSettings"
+msgstr "Spring设置"
+
+#: src/mainwindow.cpp:167
+msgid "&About"
+msgstr "(&A) å
³äº"
+
+#: src/mainwindow.cpp:168
+#, fuzzy
+msgid "&Change language"
+msgstr "é¢éä¿¡æ¯"
+
+#: src/mainwindow.cpp:169
+msgid "&Report a bug..."
+msgstr "(&R) æ¥åä¸ä¸ªBug..."
+
+#: src/mainwindow.cpp:170
+msgid "&Documentation"
+msgstr "(&D) ææ¡£"
+
+#: src/mainwindow.cpp:173
+msgid "&File"
+msgstr "(&F) æ件"
+
+#: src/mainwindow.cpp:178
+msgid "&Tools"
+msgstr "å·¥å
·(&T)"
+
+#: src/mainwindow.cpp:179
+msgid "&Help"
+msgstr "帮å©(&H)"
+
+#: src/mainwindow.cpp:450
+msgid "You need to be connected to server to view channel list"
+msgstr ""
+
+#: src/mainwindow.cpp:450
+#, fuzzy
+msgid "Not connected"
+msgstr "ç¶æï¼å·²è¿æ¥"
+
+#: src/mainwindow.cpp:464
+msgid "Join channel..."
+msgstr "å å
¥é¢é..."
+
+#: src/mainwindow.cpp:464
+msgid "Name of channel to join"
+msgstr "å å
¥é¢éçå称"
+
+#: src/mainwindow.cpp:476
+msgid "Open Private Chat..."
+msgstr "æå¼ç§è..."
+
+#: src/mainwindow.cpp:476
+msgid "Name of user"
+msgstr "ç¨æ·å"
+
+#: src/mainwindow.cpp:490
+msgid "SpringLobby is a cross-plattform lobby client for the RTS Spring engine"
+msgstr "SpringLobby æ¯ä¸ä¸ªä¾RTS Spring å¼æ使ç¨ç跨平å°æ¸¸æ大å
客æ·ç«¯"
+
+#: src/mainwindow.cpp:544
+msgid "There were no screenshots found in your spring data directory."
+msgstr ""
+
+#: src/mainwindow.cpp:544
+#, fuzzy
+msgid "No files found"
+msgstr "没ææ¾å°å°å¾"
+
+#: src/mainwindow.cpp:576
+msgid "Manually &Start Torrent System"
+msgstr "æå¨ (&S) å¯å¨ Torrent ç³»ç»"
+
+#: src/mainwindow.cpp:580
+msgid "Manually &Stop Torrent System"
+msgstr "æå¨ (&S) åæ¢ Torrent ç³»ç»"
+
+#: src/mainwindow.cpp:638
+msgid "You need to restart SpringLobby for the language change to take effect."
+msgstr ""
+
+#: src/mainwindow.cpp:639
+msgid "Restart required"
+msgstr ""
+
+#: src/mainwindow.cpp:661 src/mainwindow.cpp:669 src/mainwindow.cpp:678
+msgid "Layout manager"
+msgstr ""
+
+#: src/mainwindow.cpp:661
+msgid "Enter a profile name"
+msgstr ""
+
+#: src/mainwindow.cpp:669
+msgid "Which profile fo you want to load?"
+msgstr ""
+
+#: src/mainwindow.cpp:678
+#, fuzzy
+msgid "Which profile do you want to be default?"
+msgstr "ä½ æ³è¦ç§»é¤åªä¸ªç¨æ·å¸æ·ï¼"
+
+#: src/mainwindow.h:181
+msgid "Multiplayer"
+msgstr ""
+
+#: src/mainwindow.h:182
+msgid "Singleplayer"
+msgstr ""
+
+#: src/mainwindow.h:183
+#, fuzzy
+msgid "Savegames"
+msgstr "ä¿å..."
+
+#: src/mainwindow.h:184
+#, fuzzy
+msgid "Replays"
+msgstr "æ»æ¯"
+
+#: src/mainwindow.h:186
+#, fuzzy
+msgid "Downloads"
+msgstr "ä¸è½½"
+
+#: src/mapctrl.cpp:587
+#, c-format
+msgid "Metal: %.1f%%"
+msgstr ""
+
+#: src/mapctrl.cpp:692 src/mapctrl.cpp:693
+msgid "Refresh"
+msgstr "å·æ°"
+
+#: src/mapctrl.cpp:694 src/mapctrl.cpp:695 src/widgets/infopanel.cpp:91
+msgid "Download"
+msgstr "ä¸è½½"
+
+#: src/mapctrl.cpp:895
+msgid "side:"
+msgstr "éµè¥ï¼"
+
+#: src/mapctrl.cpp:908
+#, c-format
+msgid "ally: %d"
+msgstr "èçï¼%d"
+
+#: src/mapctrl.cpp:919
+#, c-format
+msgid "bonus: %d%%"
+msgstr "å æï¼%d%%"
+
+#: src/mapselectdialog.cpp:67
+msgid "Select map (click and drag to scroll)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:70
+msgid "Vertical sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:76
+msgid "Horizontal sort key"
+msgstr ""
+
+#: src/mapselectdialog.cpp:82
+msgid "Show"
+msgstr ""
+
+#: src/mapselectdialog.cpp:83
+msgid "All maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:84
+msgid "Shows all available maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:86
+msgid "Popular maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:87
+msgid ""
+"Shows only maps which are currently being player on the server. You must be "
+"online to use this."
+msgstr ""
+
+#: src/mapselectdialog.cpp:89
+msgid "Recently played maps"
+msgstr ""
+
+#: src/mapselectdialog.cpp:91
+msgid "Shows only maps you played recently. (Based on your replays.)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:94
+#, fuzzy
+msgid "Filter"
+msgstr "æ件"
+
+#: src/mapselectdialog.cpp:96
+msgid "Shows only maps which contain this text in their name or description."
+msgstr ""
+
+#: src/mapselectdialog.cpp:99
+#, fuzzy
+msgid "Map details"
+msgstr "éå±å«é"
+
+#: src/mapselectdialog.cpp:162
+#, fuzzy
+msgid "Start positions"
+msgstr "åºçä½ç½®"
+
+#: src/mapselectdialog.cpp:265
+#, fuzzy
+msgid "Minimum wind"
+msgstr "æä½éæ±çº§å«"
+
+#: src/mapselectdialog.cpp:266
+msgid "Maximum wind"
+msgstr ""
+
+#: src/mapselectdialog.cpp:267
+#, fuzzy
+msgid "Average wind"
+msgstr "大ä¼çº§æ°å
µ"
+
+#: src/mapselectdialog.cpp:268
+msgid "Size (map area)"
+msgstr ""
+
+#: src/mapselectdialog.cpp:269
+#, fuzzy
+msgid "Aspect ratio"
+msgstr "è§çè
"
+
+#: src/mapselectdialog.cpp:270
+#, fuzzy
+msgid "Number of start positions"
+msgstr "éæºåºçä½ç½®"
+
+#: src/mmoptionswrapper.cpp:121
+msgid "Start Position Type"
+msgstr "åºçä½ç½®ç±»å"
+
+#: src/mmoptionswrapper.cpp:121
+#, fuzzy
+msgid ""
+"How players will select where to be spawned in the map\n"
+"0: fixed map positions\n"
+"1: random map positions\n"
+"2: choose in game\n"
+"3: choose in the lobby before starting"
+msgstr ""
+"ç©å®¶å¦ä½éæ©åºçç¹ï¼\n"
+"0ï¼åºå®çåºçç¹\n"
+"1ï¼éæºçåºçç¹\n"
+"2ï¼å¨æ¸¸æä¸éæ©\n"
+"3ï¼æ¸¸æå¼å§åå¨å¤§å
ä¸éæ©"
+
+#: src/mmoptionswrapper.cpp:124
+#, fuzzy
+msgid "Choose in-game"
+msgstr "å¨æ¸¸æä¸éæ©"
+
+#: src/mmoptionswrapper.cpp:125
+#, fuzzy
+msgid "Choose before game"
+msgstr "å¨æ¸¸æä¸éæ©"
+
+#: src/mmoptionswrapper.cpp:131
+#, fuzzy
+msgid "List of restricted units"
+msgstr "éå¶åä½"
+
+#: src/mmoptionswrapper.cpp:132
+msgid "Map name"
+msgstr ""
+
+#: src/mmoptionwindows.cpp:39
+#, fuzzy
+msgid "Change option"
+msgstr "å¾å½¢çé¢é项"
+
+#: src/nicklistctrl.cpp:58
+msgid "s"
+msgstr "ç¶æ"
+
+#: src/nicklistctrl.cpp:59
+msgid "c"
+msgstr "å½å®¶/å°åº"
+
+#: src/nicklistctrl.cpp:60
+msgid "r"
+msgstr "级å«"
+
+#: src/nonportable.h:6
+msgid "Executables (*.exe)|*.exe|Any File (*.*)|*.*"
+msgstr "ç¨åºæ件 (*.exe)|*.exe|æææ件 (*.*)|*.*"
+
+#: src/nonportable.h:13
+msgid "Any file (*)|*"
+msgstr "æææ件 (*)|*"
+
+#: src/nonportable.h:19
+msgid "App Bundles (*.app)|*.app|Any File (*.*)|*.*"
+msgstr "ç¨åºå
(*.app)|*.app|æææ件 (*.*)|*.*"
+
+#: src/playback/playbackfilter.cpp:60
+#, fuzzy
+msgid "Filter settings"
+msgstr "ä¿å设置"
+
+#: src/playback/playbackfilter.cpp:164
+#, fuzzy
+msgid "Filesize in KB:"
+msgstr "æ件大å°ï¼MB)"
+
+#: src/playback/playbackfilter.cpp:190
+#, fuzzy
+msgid "Duration (hh:mm:ss):"
+msgstr "æç»æ¶é´ï¼"
+
+#: src/playback/playbacklistctrl.cpp:41
+#, fuzzy
+msgid "Date"
+msgstr "åå°ç"
+
+#: src/playback/playbacklistctrl.cpp:41
+msgid "Date of recording"
+msgstr ""
+
+#: src/playback/playbacklistctrl.cpp:42
+#, fuzzy
+msgid "Modname"
+msgstr "模å¼"
+
+#: src/playback/playbacklistctrl.cpp:43
+#, fuzzy
+msgid "Mapname"
+msgstr "å·´æ¿é©¬"
+
+#: src/playback/playbacklistctrl.cpp:45
+#, fuzzy
+msgid "Duration"
+msgstr "æç»æ¶é´ï¼"
+
+#: src/playback/playbacklistctrl.cpp:46
+#, fuzzy
+msgid "Spring Version"
+msgstr "Springè¿è¡é误"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize"
+msgstr "æ件大å°ï¼MB)"
+
+#: src/playback/playbacklistctrl.cpp:47
+#, fuzzy
+msgid "Filesize in kilobyte"
+msgstr "æ件大å°ï¼MB)"
+
+#: src/playback/playbacklistctrl.cpp:48 src/settings++/frame.cpp:228
+msgid "File"
+msgstr "æ件"
+
+#: src/playback/playbacktab.cpp:134
+msgid "Watch"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:134
+#, fuzzy
+msgid "Load"
+msgstr "è½½å
¥..."
+
+#: src/playback/playbacktab.cpp:140
+msgid "Reload list"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "replay"
+msgstr "æ»æ¯"
+
+#: src/playback/playbacktab.cpp:278
+#, fuzzy
+msgid "savegame"
+msgstr "ä¿å..."
+
+#: src/playback/playbacktab.cpp:286
+#, fuzzy
+msgid "Couldn't get your spring versions from any unitsync library."
+msgstr ""
+"æ æ³ä»UnitSyncåºä¸è·åä½ çSpringçæ¬ã\n"
+"\n"
+"å¨çº¿æ¸¸æå°è¢«ç¦ç¨ã"
+
+#: src/playback/playbacktab.cpp:304
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this %s requires "
+"version: %s\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:305 src/ui.cpp:626
+msgid "Your current installed versions are:"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:326
+#, fuzzy
+msgid ""
+"You need to download the mod before you can watch this replay.\n"
+"\n"
+msgstr ""
+"å¨ä½ è½å¤å å
¥è¯¥æ¸¸æåï¼ä½ éè¦ä¸è½½æ¨¡ç»ã\n"
+"\n"
+
+#: src/playback/playbacktab.cpp:338
+msgid ""
+" I couldn't find the map to be able to watch this replay\n"
+"This can be caused by tasclient writing broken map hash value\n"
+"If you're sure you have the map, press no\n"
+"You need to download the map to be able to watch this replay.\n"
+"\n"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+msgid ""
+"I don't think you will be able to watch this replay.\n"
+"Try anyways? (MIGHT CRASH!)"
+msgstr ""
+
+#: src/playback/playbacktab.cpp:359
+#, fuzzy
+msgid "Invalid replay"
+msgstr "æ æç端å£"
+
+#: src/playback/playbacktab.cpp:376
+msgid "Could not delete Replay: "
+msgstr ""
+
+#: src/selectusersdialog.cpp:51
+msgid "Filter names"
+msgstr ""
+
+#: src/selectusersdialog.cpp:56
+msgid "Enter text filter to filter the online users list"
+msgstr ""
+
+#: src/selectusersdialog.h:67
+#, fuzzy
+msgid "Select Users"
+msgstr "å
¨é"
+
+#: src/serverevents.cpp:127
+#, c-format
+msgid "ping reply took %s ms"
+msgstr ""
+
+#: src/serverevents.cpp:144
+#, fuzzy
+msgid " is online"
+msgstr " ç¨æ·ä¸å¨çº¿ã"
+
+#: src/serverevents.cpp:167
+msgid " is now "
+msgstr ""
+
+#: src/serverevents.cpp:193
+msgid "OnUserStatus() failed ! (exception)"
+msgstr "OnUserStatus() 失败ï¼ï¼å¼å¸¸ï¼"
+
+#: src/serverevents.cpp:225
+#, fuzzy
+msgid " just went offline"
+msgstr " ç¨æ·ä¸å¨çº¿ã"
+
+#: src/serverevents.cpp:260
+#, fuzzy
+msgid " opened battle "
+msgstr " å å
¥ "
+
+#: src/serverevents.cpp:582
+msgid "Join channel failed"
+msgstr "å å
¥é¢é失败"
+
+#: src/serverevents.cpp:582
+msgid "Could not join channel "
+msgstr "æ æ³å å
¥é¢é "
+
+#: src/serverevents.cpp:582
+msgid " because: "
+msgstr " å ä¸ºï¼ "
+
+#: src/serverevents.cpp:801
+msgid "Server Message"
+msgstr "æå¡å¨æ¶æ¯"
+
+#: src/serverevents.cpp:847
+#, c-format
+msgid " has ip=%s"
+msgstr " æ¥æ IP=%s"
+
+#: src/serverevents.cpp:853
+msgid " does not really support nat traversal"
+msgstr " ä¸çæ£æ¯æNATç©¿è¶"
+
+#: src/serverevents.cpp:866
+msgid "You were kicked from the battle!"
+msgstr "ä½ ä»ææä¸è¢«è¸¢åºäºï¼"
+
+#: src/serverevents.cpp:866
+msgid "Kicked by Host"
+msgstr "被主æºè¸¢åº"
+
+#: src/serverevents.cpp:896
+msgid "Begin mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:896
+#, fuzzy, c-format
+msgid "%s mutelist"
+msgstr "游æå表"
+
+#: src/serverevents.cpp:905
+msgid " indefinite time remaining"
+msgstr ""
+
+#: src/serverevents.cpp:906
+#, c-format
+msgid " %d minutes remaining"
+msgstr ""
+
+#: src/serverevents.cpp:914
+msgid "End mutelist for "
+msgstr ""
+
+#: src/serverevents.cpp:950
+#, fuzzy
+msgid "Download update"
+msgstr "ä¸è½½å®æ¯"
+
+#: src/serverevents.cpp:950
+#, c-format
+msgid ""
+"Would you like to download %s ? The file offers the following updates:\n"
+"\n"
+"%s\n"
+"\n"
+"The download will be started in the background, you will be notified on "
+"operation completed."
+msgstr ""
+
+#: src/serverevents.cpp:970
+#, fuzzy
+msgid "There was an error downloading for the latest version.\n"
+msgstr ""
+"æ£æ¥ææ°çæ¬æ¶åçé误ã\n"
+"请ç¨åå°è¯ã\n"
+"å¦æé®é¢ä¾ç¶åå¨ï¼è¯·ä½¿ç¨ å¸®å© -> æ¥åBugã"
+
+#: src/serverevents.cpp:975
+msgid "Network Error"
+msgstr ""
+
+#: src/serverevents.cpp:978
+#, fuzzy
+msgid "Negotiation error"
+msgstr "éç¥"
+
+#: src/serverevents.cpp:984
+#, fuzzy
+msgid "Invalid Value"
+msgstr "æ æçæ°å"
+
+#: src/serverevents.cpp:987
+#, fuzzy
+msgid "No Handler"
+msgstr "ä¸æ¯ä¸ä¸ªæ°å"
+
+#: src/serverevents.cpp:990
+#, fuzzy
+msgid "File doesn't exit"
+msgstr "å°å¾ä¸åå¨ã"
+
+#: src/serverevents.cpp:993
+#, fuzzy
+msgid "Action Aborted"
+msgstr "å·²å¼å§"
+
+#: src/serverevents.cpp:996
+#, fuzzy
+msgid "Reconnection Error"
+msgstr "éæ°è¿æ¥"
+
+#: src/serverevents.cpp:999
+#, fuzzy
+msgid "Unknown Error"
+msgstr "æªç¥"
+
+#: src/serverevents.cpp:1009
+#, fuzzy
+msgid "Download complete, location is: "
+msgstr "ä¸è½½å®æ¯"
+
+#: src/serverevents.cpp:1010
+msgid ""
+"\n"
+"lobby will get closed now."
+msgstr ""
+
+#: src/serverevents.cpp:1011
+#, fuzzy
+msgid "Download complete."
+msgstr "ä¸è½½å®æ¯"
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer. File location is: "
+msgstr "æ æ³å¯å¨æµè§å¨ãå°åæ¯ï¼ "
+
+#: src/serverevents.cpp:1016
+#, fuzzy
+msgid "Couldn't launch installer."
+msgstr "æ æ³å¯å¨æµè§å¨ã"
+
+#: src/settings++/Defs.hpp:212
+msgid "Scrollwheel speed"
+msgstr "é¼ æ æ»è½®é度"
+
+#: src/settings++/Defs.hpp:213
+msgid ""
+"Higher values mean faster zoom with mouse wheel.\n"
+"Negative values will invert zoom direction.\n"
+"Results may vary depending on camera mode!"
+msgstr ""
+"æ´é«çå¼è¡¨ç¤ºä½¿ç¨é¼ æ æ»è½®æ¾å¤§æ´å¿«ã\n"
+"è´æ°å¼å¯ä»¥å转æ»è½®æ¹åã\n"
+"ææå¯è½å¨ä¸åè§è§æ¨¡å¼ä¸ä¸åï¼"
+
+#: src/settings++/Defs.hpp:223
+msgid "Shadow-map size"
+msgstr "é´å½±åºåç»´æ°"
+
+#: src/settings++/Defs.hpp:223
+msgid ""
+"higher value = better looking shadows\n"
+"possible values: 1024, 2048, 4096, 8192"
+msgstr ""
+"æ´é«çå¼ = æ´å¥½ççé´å½±\n"
+"å¯ä½¿ç¨çå¼æï¼ 1024ï¼2048ï¼4096ï¼8192"
+
+#: src/settings++/Defs.hpp:225
+msgid "Tree view-distance"
+msgstr "æ æ¨æ¾ç¤ºè·ç¦»"
+
+#: src/settings++/Defs.hpp:225
+msgid "sets the maximum distance at which trees will still be rendered"
+msgstr "设置æ æ¨è¢«æ¸²æçæ大è·ç¦»"
+
+#: src/settings++/Defs.hpp:226
+msgid "Terrain detail"
+msgstr "å°å½¢ç»è"
+
+#: src/settings++/Defs.hpp:226
+msgid "higher value = more terrain details"
+msgstr "æ´é«çå¼ = æ´å¤çå°å½¢ç»è"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "Unit LOD distance"
+msgstr "æ¾ç¤ºåä½å¾æ çè·ç¦»"
+
+#: src/settings++/Defs.hpp:227
+#, fuzzy
+msgid "higher value = units will remain detailed even when zooming out"
+msgstr "æ´é«çå¼ = åä½ç»èç¨åº¦è¶é«"
+
+#: src/settings++/Defs.hpp:228
+msgid "Grass detail"
+msgstr "èä¸ç»è"
+
+#: src/settings++/Defs.hpp:228
+#, fuzzy
+msgid "higher value = more detailed grass"
+msgstr "æ´é«çå¼ = æ´å ç»è´çèä¸"
+
+#: src/settings++/Defs.hpp:229
+msgid "Ground decals"
+msgstr "å°è¡¨è´´å¾"
+
+#: src/settings++/Defs.hpp:229
+msgid ""
+"settings higher than 1 might have unwelcome side-effects / be very resource "
+"hungry"
+msgstr ""
+
+#: src/settings++/Defs.hpp:230
+msgid "Unit icon distance"
+msgstr "æ¾ç¤ºåä½å¾æ çè·ç¦»"
+
+#: src/settings++/Defs.hpp:230
+msgid ""
+"determines at which range units are still fully rendered\n"
+"higher value = greater range = more units rendered at the same time"
+msgstr ""
+"å³å®äºåä½è¢«å®æ´æ¸²æçæ大è·ç¦»\n"
+"æ´é«çå¼ = æ´è¿çè·ç¦» = æ´å¤åä½åæ¶è¢«æ¸²æ"
+
+#: src/settings++/Defs.hpp:232
+msgid "Max simultaneous particles"
+msgstr "æ大ç²åæ°"
+
+#: src/settings++/Defs.hpp:232 src/settings++/Defs.hpp:233
+msgid "limits how many particles are displayed at the same time"
+msgstr "éå¶åæ¶æå¤æ¾ç¤ºå¤å°ç²å"
+
+#: src/settings++/Defs.hpp:233
+#, fuzzy
+msgid "Max nano simultaneous particles"
+msgstr "æ大ç²åæ°"
+
+#: src/settings++/Defs.hpp:241
+msgid "Run full-screen"
+msgstr "å
¨å±è¿è¡"
+
+#: src/settings++/Defs.hpp:241
+msgid "run fullscreen or in a window?"
+msgstr "å
¨å±è¿è¡è¿æ¯çªå£åè¿è¡ï¼"
+
+#: src/settings++/Defs.hpp:242
+msgid "Dual-screen mode"
+msgstr "åå±æ¨¡å¼"
+
+#: src/settings++/Defs.hpp:242
+msgid "if you have two monitors you can use both"
+msgstr "å¦æä½ æ¥æ两å°æ¾ç¤ºå¨ï¼å¯ä»¥é½ä½¿ç¨"
+
+#: src/settings++/Defs.hpp:243
+#, fuzzy
+msgid "Enable v-sync"
+msgstr "å¯ç¨ åç´åæ¥"
+
+#: src/settings++/Defs.hpp:243
+msgid "V-Sync on/off"
+msgstr "åç´åæ¥ å¼/å
³"
+
+#: src/settings++/Defs.hpp:249
+msgid "16-bit Z-buffer"
+msgstr "16ä½ æ·±åº¦ç¼å²"
+
+#: src/settings++/Defs.hpp:249 src/settings++/Defs.hpp:250
+msgid "placeholder"
+msgstr "å ä½ç¬¦"
+
+#: src/settings++/Defs.hpp:250
+msgid "24-bit Z-buffer"
+msgstr "24ä½ æ·±åº¦ç¼å²"
+
+#: src/settings++/Defs.hpp:257
+#, fuzzy
+msgid "Full-scene anti-aliasing samples"
+msgstr "å
¨å±æé¯é½¿åæ ·"
+
+#: src/settings++/Defs.hpp:257
+msgid "how much anti-aliasing should be applied"
+msgstr "æé¯é½¿éæ ·åºè¯¥å 次"
+
+#: src/settings++/Defs.hpp:269
+msgid "Maximum simultaneous sounds"
+msgstr "æ大声é³æ°"
+
+#: src/settings++/Defs.hpp:269
+msgid ""
+"maximum different sounds played at the same time\n"
+"Set this to zero to disable sound completely."
+msgstr ""
+"æå¤å¯ä»¥åæ¶ææ¾ä¸å声é³çæ°ç®\n"
+"设置为0åå®å
¨ç¦ç¨å£°é³ã"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "Master sound volume"
+msgstr "æ»ä½çé³é"
+
+#: src/settings++/Defs.hpp:271
+#, fuzzy
+msgid "master sound volume"
+msgstr "æ»ä½çé³é"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "General sound volume"
+msgstr "æ»ä½çé³é"
+
+#: src/settings++/Defs.hpp:272
+#, fuzzy
+msgid "general volume relative to master volume"
+msgstr "ç¸å¯¹å
¨å±é³éçåä½åå¤é³é"
+
+#: src/settings++/Defs.hpp:273
+msgid "Unit reply volume"
+msgstr "åä½åå¤é³é"
+
+#: src/settings++/Defs.hpp:273
+#, fuzzy
+msgid "reply volume relative to master volume"
+msgstr "ç¸å¯¹å
¨å±é³éçåä½åå¤é³é"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "Battle volume"
+msgstr "游ææ¿é´"
+
+#: src/settings++/Defs.hpp:274
+#, fuzzy
+msgid "battle volume relative to global volume"
+msgstr "ç¸å¯¹å
¨å±é³éçåä½åå¤é³é"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "User interface volume"
+msgstr "åä½åå¤é³é"
+
+#: src/settings++/Defs.hpp:275
+#, fuzzy
+msgid "ui volume relative to global volume"
+msgstr "ç¸å¯¹å
¨å±é³éçåä½åå¤é³é"
+
+#: src/settings++/Defs.hpp:282
+msgid "Shadows (slow)"
+msgstr "é´å½±ï¼æ
¢ï¼"
+
+#: src/settings++/Defs.hpp:282
+msgid "enable shadows?"
+msgstr "å¯ç¨é´å½±ï¼"
+
+#: src/settings++/Defs.hpp:283
+msgid "3D trees"
+msgstr "3D æ æ¨"
+
+#: src/settings++/Defs.hpp:283
+msgid ""
+"want better looking trees?\n"
+"needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card"
+msgstr ""
+"æ³è¦æ´å¥½ççæ æ¨ï¼\n"
+"éè¦ GeForce 2/Radeon 8500/Intel 830ææ´æ°çº§å«çæ¾å¡"
+
+#: src/settings++/Defs.hpp:285
+msgid "High-resolution clouds"
+msgstr "é«è§£æ度äº"
+
+#: src/settings++/Defs.hpp:285
+msgid ""
+"want better looking sky?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"æ³è¦æ´å¥½ççäºï¼\n"
+"éè¦ GeForce 5/Radeon 9500/Intel 915ææ´æ°çº§å«çæ¾å¡"
+
+#: src/settings++/Defs.hpp:287
+msgid "Dynamic clouds (slow)"
+msgstr "å¨æäºå±ï¼æ
¢ï¼"
+
+#: src/settings++/Defs.hpp:287
+msgid "want moving clouds in the sky?"
+msgstr "æ³è¦å¨ç©ºä¸æä¼ç§»å¨çäºåï¼"
+
+#: src/settings++/Defs.hpp:288
+msgid "Reflective units"
+msgstr "åå°å
线çåä½"
+
+#: src/settings++/Defs.hpp:288
+msgid ""
+"shiny units?\n"
+"needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card"
+msgstr ""
+"ç©ç®çåä½ï¼\n"
+"éè¦ GeForce 5/Radeon 9500/Intel 915ææ´æ°çº§å«çæ¾å¡"
+
+#: src/settings++/Defs.hpp:290
+msgid "Never use shaders when rendering SM3 maps"
+msgstr "å½æ¸²æSM3å°å¾æ¶æ°¸è¿ä¸ä½¿ç¨æ¸²æå¨"
+
+#: src/settings++/Defs.hpp:290
+msgid "problems with sm3 maps? enable this"
+msgstr "使ç¨SM3å°å¾æé®é¢ï¼è¯·å¯ç¨å®"
+
+#: src/settings++/Defs.hpp:291
+msgid "Enable LuaShaders support"
+msgstr "å¯ç¨ Lua渲æå¨æ¯æ"
+
+#: src/settings++/Defs.hpp:291
+msgid "makes for some cool effects"
+msgstr "è¾¾å°æ´å¤æ¼äº®çææ"
+
+#: src/settings++/Defs.hpp:292
+msgid "Use Pixelbuffer objects"
+msgstr ""
+
+#: src/settings++/Defs.hpp:292
+msgid ""
+"If supported, it speeds up the dynamic loading of terrain textures -> "
+"smoother camera movement"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid "Compress textures"
+msgstr ""
+
+#: src/settings++/Defs.hpp:293
+msgid ""
+"Runtime texture compression. (Ideal for graphic cards with small amount of "
+"vram)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:294
+msgid "High-resolution LOS textures"
+msgstr "é«å辨ççè§éè´´å¾"
+
+#: src/settings++/Defs.hpp:294
+msgid "smoother Line of Sight overlays"
+msgstr "æ´å¹³æ»çè§éè¦çå¾"
+
+#: src/settings++/Defs.hpp:295
+msgid "Draw smooth points"
+msgstr "ç»å¶å
æ»ç¹"
+
+#: src/settings++/Defs.hpp:295
+msgid "should points be anti-aliased"
+msgstr "ç¹æ¯å¦è¦æé¯é½¿"
+
+#: src/settings++/Defs.hpp:296
+msgid "Draw smooth lines"
+msgstr "ç»å¶å
æ»ç´çº¿"
+
+#: src/settings++/Defs.hpp:296
+msgid "should lines be anti-aliased"
+msgstr "ç´çº¿æ¯å¦è¦æé¯é½¿"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue commands on mini-map"
+msgstr "å¨å°å°å¾ä¸æ½å å½ä»¤"
+
+#: src/settings++/Defs.hpp:303
+msgid "Issue orders on the mini-map like you would "
+msgstr "å¨å°å°å¾ä¸å大å°å¾ä¸ä¸æ ·æ½å å½ä»¤ "
+
+#: src/settings++/Defs.hpp:304
+msgid "Show commands on mini-map"
+msgstr "å¨å°å°å¾ä¸æ¾ç¤ºå½ä»¤"
+
+#: src/settings++/Defs.hpp:304 src/settings++/Defs.hpp:305
+#: src/settings++/Defs.hpp:306
+msgid "default value is \"on\""
+msgstr "é»è®¤å¼ä¸º å¯ç¨"
+
+#: src/settings++/Defs.hpp:305
+msgid "Draw icons on mini-map"
+msgstr "å¨å°å°å¾ä¸ç»å¶å¾æ "
+
+#: src/settings++/Defs.hpp:306
+msgid "Draw markers on mini-map"
+msgstr "å¨å°å°å¾ä¸ç»å¶æ è®°"
+
+#: src/settings++/Defs.hpp:307
+msgid "Mini-map on left (single screen)"
+msgstr "å°å°å¾å¨å·¦ä¾§ï¼åå±å¹ï¼"
+
+#: src/settings++/Defs.hpp:307 src/settings++/Defs.hpp:308
+msgid "left is the default"
+msgstr "é»è®¤å¼ä¸º 左侧"
+
+#: src/settings++/Defs.hpp:308
+msgid "Mini-map on left (dual screen)"
+msgstr "å°å°å¾å¨å·¦ä¾§ï¼åå±å¹ï¼"
+
+#: src/settings++/Defs.hpp:309
+msgid "Simplified mini-map colors"
+msgstr "ç®åçå°å°å¾é¢è²"
+
+#: src/settings++/Defs.hpp:309
+msgid "Use less colors"
+msgstr "使ç¨æ´å°çé¢è²"
+
+#: src/settings++/Defs.hpp:311
+msgid "Team-colored nanospray"
+msgstr "éä¼é¢è²ç纳米ç²å"
+
+#: src/settings++/Defs.hpp:312
+msgid "Should nano particels be the color of your team?"
+msgstr "纳米ç²åçé¢è²æ¯å¦ä¸éä¼é¢è²ä¸è´ï¼"
+
+#: src/settings++/Defs.hpp:313
+msgid "Colorized elevation map"
+msgstr "é«åº¦å±å°å¾åè²"
+
+#: src/settings++/Defs.hpp:313
+msgid "makes differences in height clearer"
+msgstr "使é«åº¦å·®å«æ´ææ¾"
+
+#: src/settings++/Defs.hpp:315
+msgid "Show in-game clock"
+msgstr "æ¾ç¤ºæ¸¸æä¸çæ¶é"
+
+#: src/settings++/Defs.hpp:316 src/settings++/Defs.hpp:318
+#: src/settings++/Defs.hpp:320
+msgid ""
+"requires \"Enable LuaWidgets\" to be set.\n"
+"Will be displayed in the bottom right corner"
+msgstr ""
+"éè¦å¯ç¨ âå¯ç¨ Luaæ件âã\n"
+"å°ä¼å¨å±å¹å³ä¸æ¹æ¾ç¤º"
+
+#: src/settings++/Defs.hpp:317
+msgid "Show in-game player information"
+msgstr "æ¾ç¤ºæ¸¸æä¸åç©å®¶çä¿¡æ¯"
+
+#: src/settings++/Defs.hpp:319
+msgid "Show in-game framerate"
+msgstr "æ¾ç¤ºæ¸¸æä¸ç帧é"
+
+#: src/settings++/Defs.hpp:322
+msgid "Fix rendering on alt-tab"
+msgstr "ä¿®å¤Alt+Tab导è´ç渲æé®é¢"
+
+#: src/settings++/Defs.hpp:322
+msgid "Do not change if not needed"
+msgstr "å¦æä¸å¿
è¦è¯·ä¸è¦ä¿®æ¹"
+
+#: src/settings++/Defs.hpp:323
+msgid "Disallow helper AI's"
+msgstr "ç¦ç¨AIå©æ"
+
+#: src/settings++/Defs.hpp:323
+msgid ""
+"Disables Economy AI, etc.\n"
+"If enabled might screw with LuaUi."
+msgstr ""
+"ç¦ç¨ ç»æµAI ççã\n"
+"å¦æå¯ç¨ï¼å¯è½å¯¼è´Luaå¾å½¢çé¢æ件åè½ç´ä¹±ã"
+
+#: src/settings++/Defs.hpp:325
+msgid "Enable scroll on window edge"
+msgstr "å¯ç¨ å±å¹è¾¹ç¼æ»å±"
+
+#: src/settings++/Defs.hpp:325
+msgid "Scroll the screen when mouse reaches the screen's edge."
+msgstr "å½é¼ æ 移å¨å°å±å¹è¾¹ç¼æ¶ï¼æ»å¨å±å¹è§é"
+
+#: src/settings++/Defs.hpp:326
+msgid "Invert Mouse"
+msgstr "é¼ æ ä¸ä¸åå"
+
+#: src/settings++/Defs.hpp:326
+msgid "Inverts the Mouse Y-axis in FPS mode"
+msgstr "å¨FPS模å¼ä¸ä½¿é¼ æ ä¸ä¸åå"
+
+#: src/settings++/Defs.hpp:327
+msgid "Use Hardware Cursor"
+msgstr ""
+
+#: src/settings++/Defs.hpp:327
+msgid "Use native OS mouse cursor (hardware accelerated)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:335
+msgid "Overhead camera"
+msgstr "顶é¨è§è§"
+
+#: src/settings++/Defs.hpp:335 src/settings++/Defs.hpp:336
+#: src/settings++/Defs.hpp:337 src/settings++/Defs.hpp:338
+#: src/settings++/Defs.hpp:339
+msgid "set the scroll speed (mouse + keyboard) for this mode"
+msgstr "设置该模å¼ä¸çæ»å¨é度ï¼é¼ æ ä¸é®çï¼"
+
+#: src/settings++/Defs.hpp:336
+msgid "Rotatable overhead camera"
+msgstr "å¯æ转ç顶é¨è§è§"
+
+#: src/settings++/Defs.hpp:337
+msgid "Total war camera"
+msgstr "å
¨é¢æäºæ¨¡å¼è§è§"
+
+#: src/settings++/Defs.hpp:338
+msgid "First person camera"
+msgstr "第ä¸äººç§°è§è§"
+
+#: src/settings++/Defs.hpp:339 src/settings++/Defs.hpp:398
+msgid "Free camera"
+msgstr "èªç±è§è§"
+
+#: src/settings++/Defs.hpp:345 src/settings++/Defs.hpp:347
+#: src/settings++/Defs.hpp:349 src/settings++/Defs.hpp:351
+#: src/settings++/Defs.hpp:353
+msgid ""
+"Make this the default view when startins Spring.\n"
+"Can be changed ingame."
+msgstr ""
+"设置该è§è§ä¸ºè¿å
¥Springåçé»è®¤è§è§ã\n"
+"å¯ä»¥å¨æ¸¸æä¸æ´æ¹ã"
+
+#: src/settings++/Defs.hpp:360
+msgid "Console verbose level (0=min,10=max)"
+msgstr "æ§å¶å°æ¶æ¯éï¼0=æå° 10=æå¤ï¼"
+
+#: src/settings++/Defs.hpp:360
+msgid "How much information should be outputted?"
+msgstr "å¤å°ä¿¡æ¯å¯ä»¥è¢«è¾åºå°æ§å¶å°ï¼"
+
+#: src/settings++/Defs.hpp:366
+msgid "Catch AI exceptions"
+msgstr "ææAIå¼å¸¸"
+
+#: src/settings++/Defs.hpp:366
+msgid "disable for AI debugging"
+msgstr "ç¦ç¨AIè°è¯"
+
+#: src/settings++/Defs.hpp:372 src/settings++/Defs.hpp:383
+msgid "Basic"
+msgstr "åºæ¬ç"
+
+#: src/settings++/Defs.hpp:372
+msgid ""
+"Depending on the power of your graphics card,\n"
+"selecting higher quality than basic can have a\n"
+"major impact on Spring's performance.\n"
+msgstr ""
+"åå³äºä½ çæ¾å¡è½åï¼éæ©æ´\n"
+"é«è´¨éå¯è½ä¼å¯¹Springçè¿è¡\n"
+"é度产çè¾å¤§å½±åã\n"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective"
+msgstr "åå°ç"
+
+#: src/settings++/Defs.hpp:383
+msgid "Reflective + refractive"
+msgstr "åå°ç + æå°ç"
+
+#: src/settings++/Defs.hpp:383
+msgid "Dynamic"
+msgstr "å¨æç"
+
+#: src/settings++/Defs.hpp:383
+msgid "Bump-mapped"
+msgstr ""
+
+#: src/settings++/Defs.hpp:387
+msgid "Invert mouse y-axis"
+msgstr "é¼ æ ä¸ä¸åå"
+
+#: src/settings++/Defs.hpp:387
+msgid "swap up/down with down/up"
+msgstr "å° ä¸/ä¸ ç¿»è½¬ä¸º ä¸/ä¸"
+
+#: src/settings++/Defs.hpp:388
+msgid "Mini-map 3-button mouse support"
+msgstr "å°å°å¾ä¸é®é¼ æ æ¯æ"
+
+#: src/settings++/Defs.hpp:388
+msgid "if you don't want to able to use that button, disable it here"
+msgstr "å¦æä½ ä¸æ³ä½¿ç¨é£ä¸ªæé®ï¼å¨è¿éç¦ç¨å®"
+
+#: src/settings++/Defs.hpp:394
+msgid "Overhead"
+msgstr "顶é¨è§è§"
+
+#: src/settings++/Defs.hpp:394
+msgid "Static bird's eye view"
+msgstr "åºå®ç俯è§è§è§"
+
+#: src/settings++/Defs.hpp:395
+msgid "Rotatable overhead"
+msgstr "å¯æ转ç顶é¨è§è§"
+
+#: src/settings++/Defs.hpp:395
+msgid "Same as overhead, but you can rotate around the z-axis"
+msgstr "ä¸é¡¶é¨è§è§ç¸åï¼ä½è§è§å¯ä»¥å·¦å³æ转"
+
+#: src/settings++/Defs.hpp:396
+msgid "Total war"
+msgstr "å
¨é¢æäºæ¨¡å¼è§è§"
+
+#: src/settings++/Defs.hpp:396
+msgid "top-view camera, which can be tilted on the X axis"
+msgstr "俯è§è§è§ï¼å¯ä»¥éä½è§å¯é«åº¦ä¸è§åº¦"
+
+#: src/settings++/Defs.hpp:397
+msgid "First person"
+msgstr "第ä¸äººç§°è§è§"
+
+#: src/settings++/Defs.hpp:397
+msgid "Camera from unit's point of view"
+msgstr "è·éåä½çè§è§"
+
+#: src/settings++/Defs.hpp:398
+msgid "Modify the view anyway you want"
+msgstr "对è§è§ä½ä»»ä½ä½ æ³ä½çè°æ´"
+
+#: src/settings++/Defs.hpp:404
+msgid "screen width"
+msgstr "å±å¹å®½åº¦"
+
+#: src/settings++/Defs.hpp:405
+msgid "screen height"
+msgstr "å±å¹é«åº¦"
+
+#: src/settings++/Defs.hpp:413
+#, fuzzy
+msgid "Blur reflection"
+msgstr "åå°ç"
+
+#: src/settings++/Defs.hpp:414
+msgid "Use depth texture"
+msgstr ""
+
+#: src/settings++/Defs.hpp:414
+msgid "enables smoother blending on coastlines"
+msgstr ""
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Shore waves"
+msgstr "å¯ç¨é´å½±ï¼"
+
+#: src/settings++/Defs.hpp:415
+#, fuzzy
+msgid "Enables shorewaves"
+msgstr "å¯ç¨é´å½±ï¼"
+
+#: src/settings++/Defs.hpp:416
+#, fuzzy
+msgid "Reflection"
+msgstr "åå°ç"
+
+#: src/settings++/Defs.hpp:416
+msgid "Turn on water reflections"
+msgstr ""
+
+#: src/settings++/Defs.hpp:418
+#, fuzzy
+msgid "Reflection texture size"
+msgstr "åå°ç"
+
+#: src/settings++/Defs.hpp:419
+#, fuzzy
+msgid "Refraction"
+msgstr "éå¶"
+
+#: src/settings++/Defs.hpp:419
+msgid ""
+"Turn on water refractions.\n"
+"(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow))."
+msgstr ""
+
+#: src/settings++/Defs.hpp:421
+msgid "Anisotropy"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+#, fuzzy
+msgid "off"
+msgstr "å
³é"
+
+#: src/settings++/Defs.hpp:429
+msgid "screencopy(fast)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:429
+msgid "own rendering pass(slow)"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "128"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "256"
+msgstr ""
+
+#: src/settings++/Defs.hpp:430
+msgid "512"
+msgstr ""
+
+#: src/settings++/frame.cpp:43
+msgid "Combined Options"
+msgstr "综åé项"
+
+#: src/settings++/frame.cpp:44
+msgid "Render quality / Video mode"
+msgstr "渲æè´¨é / æ¾ç¤ºæ¨¡å¼"
+
+#: src/settings++/frame.cpp:45
+msgid "Render detail"
+msgstr "渲æç»è"
+
+#: src/settings++/frame.cpp:46
+msgid "UI options"
+msgstr "å¾å½¢çé¢é项"
+
+#: src/settings++/frame.cpp:47
+msgid "Audio"
+msgstr "声é³"
+
+#: src/settings++/frame.cpp:48
+msgid ""
+"Changes made on Quality/Detail tab in expert mode\n"
+" will be lost if you change simple options again.\n"
+"Also these changes WILL NOT be reflected by the \n"
+"selected choices on the Combined options tab.\n"
+"(this message can be disabled in the \"File\" menu)"
+msgstr ""
+"å¨ä¸å®¶æ¨¡å¼ä¸å¯¹ å¾åè´¨é/ç»è é项å¡ä¸é项æä½çä¿®æ¹\n"
+" å°ä¼å 为å¨ç®æ模å¼ä¸å次修æ¹è丢失ã\n"
+"ææè¿äºä¿®æ¹å°ä¸ä¼è¢«åæ å¨ \n"
+"综åé项ä¸çé项ä¸ã\n"
+"ï¼è¿æ¡æ¶æ¯å¯ä»¥å¨âæ件âèåä¸è¢«ç¦ç¨ï¼"
+
+#: src/settings++/frame.cpp:80 src/settings++/frame.cpp:105
+msgid "Error!"
+msgstr "é误ï¼"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+msgid "Save Spring settings before exiting?"
+msgstr "éåºåæ¯å¦ä¿åSpring设置ï¼"
+
+#: src/settings++/frame.cpp:120 src/settings++/frame.cpp:136
+#: src/settings++/frame.cpp:251
+msgid "Confirmation needed"
+msgstr "éè¦ç¡®è®¤"
+
+#: src/settings++/frame.cpp:187 src/settings++/frame.cpp:324
+msgid "SpringSettings (expert mode)"
+msgstr "Spring设置ï¼ä¸å®¶æ¨¡å¼ï¼"
+
+#: src/settings++/frame.cpp:189 src/settings++/frame.cpp:275
+msgid "SpringSettings (simple mode)"
+msgstr "Spring设置ï¼ç®æ模å¼ï¼"
+
+#: src/settings++/frame.cpp:198
+msgid "Save settings"
+msgstr "ä¿å设置"
+
+#: src/settings++/frame.cpp:199
+msgid "Reset settings to default values"
+msgstr "é设ææé项为é»è®¤å¼"
+
+#: src/settings++/frame.cpp:200
+msgid "Disable expert mode warning"
+msgstr "ç¦ç¨ ä¸å®¶æ¨¡å¼è¦å"
+
+#: src/settings++/frame.cpp:202
+msgid "Quit"
+msgstr "éåº"
+
+#: src/settings++/frame.cpp:207
+msgid "Simple (few options)"
+msgstr "ç®æï¼è¾å°é项ï¼"
+
+#: src/settings++/frame.cpp:208
+msgid "Expert (all options"
+msgstr "ä¸å®¶ï¼å
¨é¨é项ï¼"
+
+#: src/settings++/frame.cpp:211
+msgid "About"
+msgstr "å
³äº"
+
+#: src/settings++/frame.cpp:212
+msgid "Contact"
+msgstr "èç³»"
+
+#: src/settings++/frame.cpp:213
+msgid "Credits"
+msgstr "å
³äºä½è
"
+
+#: src/settings++/frame.cpp:214
+msgid "Report a bug"
+msgstr "æ¥å Bug"
+
+#: src/settings++/frame.cpp:229
+msgid "Mode"
+msgstr "模å¼"
+
+#: src/settings++/frame.cpp:230
+msgid "Info/Help"
+msgstr "ä¿¡æ¯/帮å©"
+
+#: src/settings++/frame.cpp:251
+msgid "Reset ALL settings to default values?"
+msgstr "å°ææ设置å
¨é¨é设为é»è®¤å¼ï¼"
+
+#: src/settings++/frame.cpp:277
+msgid "Hint"
+msgstr "æ示"
+
+#: src/settings++/helpmenufunctions.cpp:28
+msgid ""
+"SpringSettings is a graphical frontend to the Settings of the Spring engine"
+msgstr "Spring设置æ¯ä¸ä¸ªSpringå¼æå¾å½¢æ¹é¢ç设置软件"
+
+#: src/settings++/helpmenufunctions.cpp:37
+msgid "Kloot"
+msgstr "Kloot"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid "The SpringLobby team"
+msgstr "SpringLobby å¢é"
+
+#: src/settings++/helpmenufunctions.cpp:38
+msgid ""
+"thanks for inviting me in, code to re-use, infrastructure and help in general"
+msgstr "æè°¢ä½ ä»¬é请æå å
¥ï¼éç¨ä»£ç ï¼åºç¡æ¯æ以ååç§å¸®å©"
+
+#: src/settings++/helpmenufunctions.cpp:39
+msgid "everyone reporting bugs/suggestions"
+msgstr "æ¯ä¸ªæ¥åBug/æåºæè§ç人"
+
+#: src/settings++/Main.cpp:91
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please enable wxUSE_DEBUGREPORT"
+msgstr ""
+"è¿ä¸ªç¨åºå·²ç»äº§çäºä¸ä¸ªä¸¥éé误ï¼å³å°è¢«å
³é\n"
+"并ä¸æ æ³çæä¸ä¸ªBugæ¥å\n"
+"\n"
+"请å¯ç¨ wxUSE_DEBUGREPORT"
+
+#: src/settings++/Main.cpp:91 src/springlobbyapp.cpp:248
+msgid "Critical error"
+msgstr "è´å½é误"
+
+#: src/settings++/Main.cpp:99 src/springlobbyapp.cpp:274
+msgid "show this help message"
+msgstr ""
+
+#: src/settings++/Main.cpp:100 src/springlobbyapp.cpp:275
+msgid "don't use the crash handler (useful for debugging)"
+msgstr ""
+
+#: src/settings++/Main.cpp:101 src/springlobbyapp.cpp:277
+msgid "shows application log to the console(if available)"
+msgstr ""
+
+#: src/settings++/Main.cpp:102 src/springlobbyapp.cpp:279
+msgid "enables application log window"
+msgstr ""
+
+#: src/settings++/Main.cpp:103 src/springlobbyapp.cpp:284
+msgid ""
+"overrides default logging verbosity, can be:\n"
+" 0: no log\n"
+" 1: critical errors\n"
+" 2: errors\n"
+" 3: warnings (default)\n"
+" 4: messages\n"
+" 5: function trace"
+msgstr ""
+
+#: src/settings++/panel_pathoption.cpp:33
+msgid "Path to unitsync shared library"
+msgstr "UnitSyncå
±äº«åºçç®å½è·¯å¾"
+
+#: src/settings++/panel_pathoption.cpp:34
+msgid ""
+"There was a problem retrieving your settings.\n"
+"Please check that the path below is correct.\n"
+"When you have corrected it, click\n"
+"the \"Use this Path\" button to try again."
+msgstr ""
+"è·åä½ ç设置æ¶åçé®é¢ã\n"
+"请æ£æ¥ä¸ä¸è·¯å¾æ¯å¦æ£ç¡®ã\n"
+"å½ä½ æ´æ£å¥½ä»¥åï¼ç¹å»\n"
+"â使ç¨è¯¥è·¯å¾âæé®éè¯ã"
+
+#: src/settings++/panel_pathoption.cpp:41
+msgid "Use this path"
+msgstr "使ç¨è¯¥è·¯å¾"
+
+#: src/settings++/panel_pathoption.cpp:47
+msgid "unitsync.so on linux, unitsync.dll on windows"
+msgstr "Linuxä¸çunitsync.so Windowsä¸çunitsync.dll"
+
+#: src/settings++/panel_pathoption.cpp:53
+msgid "Path settings"
+msgstr "è·¯å¾è®¾ç½®"
+
+#: src/settings++/panel_pathoption.cpp:76
+msgid "Choose an unitsync library"
+msgstr "éæ©ä¸ä¸ªunitsyncåº"
+
+#: src/settings++/panel_pathoption.cpp:78 src/springoptionstab.cpp:194
+#: src/springoptionstab.cpp:198
+msgid "Any File"
+msgstr "æææ件"
+
+#: src/settings++/panel_pathoption.cpp:90
+msgid ""
+"SpringSettings is unable to load your unitsync library.\n"
+"You might want to take another look at your unitsync setting.\n"
+"Your Spring version has to be 0.76 or newer, otherwise \n"
+"this will fail in any case."
+msgstr ""
+"Spring设置æ æ³è½½å
¥ä½ çUnitSyncåºã\n"
+"ä½ ä¹è®¸éè¦å次æ£æ¥ä½ çUnitSync设置ã\n"
+"ä½ çSpringçæ¬å¿
须为0.76ææ´æ°ï¼å¦å \n"
+"ç¨åºæ æ³æ£ç¡®è¿è¡ã"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "low"
+msgstr "ä½"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "medium"
+msgstr "ä¸"
+
+#: src/settings++/presets.h:44 src/settings++/presets.h:45
+msgid "high"
+msgstr "é«"
+
+#: src/settings++/presets.h:45
+msgid "very low"
+msgstr "é常ä½"
+
+#: src/settings++/presets.h:45
+msgid "very high"
+msgstr "é常é«"
+
+#: src/settings++/se_utils.cpp:41
+msgid "can't launch default browser"
+msgstr "æ æ³å¯å¨é»è®¤æµè§å¨"
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser. URL is: "
+msgstr "æ æ³å¯å¨æµè§å¨ãå°åæ¯ï¼ "
+
+#: src/settings++/se_utils.cpp:42 src/ui.cpp:365 src/ui.cpp:373
+msgid "Couldn't launch browser."
+msgstr "æ æ³å¯å¨æµè§å¨ã"
+
+#: src/settings++/tab_abstract.cpp:129
+msgid "Could not access your settings.\n"
+msgstr "æ æ³è·å¾ä½ ç设置ã\n"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "Could not save, unitsync not properly loaded"
+msgstr "æ æ³ä¿åï¼UnitSyncæ æ³æ£ç¡®è½½å
¥"
+
+#: src/settings++/tab_abstract.cpp:591
+msgid "SpringSettings Error"
+msgstr "Spring设置 åºé"
+
+#: src/settings++/tab_audio.cpp:55
+msgid "Audio Options"
+msgstr "声é³é项"
+
+#: src/settings++/tab_quality_video.cpp:64
+msgid "Screen Resolution"
+msgstr "å±å¹å辨ç"
+
+#: src/settings++/tab_quality_video.cpp:160
+msgid ""
+"If an option needs special hardware to work\n"
+"it will be mentioned in the tooltip."
+msgstr ""
+"å¦æä¸ä¸ªé项éè¦ç¹æ®ç硬件é
ç½®æè½è¿è¡\n"
+"å®å°ä¼è¢«æ示ã"
+
+#: src/settings++/tab_quality_video.cpp:173
+msgid "Water Quality"
+msgstr "æ°´é¢è´¨é"
+
+#: src/settings++/tab_quality_video.cpp:203
+msgid "Resolution in bit"
+msgstr "ä½è§£æ度"
+
+#: src/settings++/tab_quality_video.cpp:267
+msgid "Render Quality Options"
+msgstr "渲æè´¨éé项"
+
+#: src/settings++/tab_quality_video.cpp:268
+msgid "Video Mode Options"
+msgstr "è§é¢æ¨¡å¼é项"
+
+#: src/settings++/tab_quality_video.cpp:269
+msgid "Anti-Aliasing Options"
+msgstr "æé¯é½¿é项"
+
+#: src/settings++/tab_quality_video.cpp:270
+msgid "Z-/Depth-Buffer"
+msgstr "深度ç¼å²"
+
+#: src/settings++/tab_quality_video.cpp:271
+msgid "Bump-mapped Water"
+msgstr ""
+
+#: src/settings++/tab_render_detail.cpp:64
+msgid "Rendering detail levels"
+msgstr "渲æç»è级å«"
+
+#: src/settings++/tab_simple.cpp:40
+msgid ""
+"These options let you roughly control Spring's rendering.\n"
+"For more speed try lowering the settings.\n"
+"Full control over all settings is available in the\n"
+"\"Expert mode\", either click on the button on the\n"
+"right or use the \"Mode\" menu in the top menubar.\n"
+"You can go back to this mode at any time by choosing\n"
+"\"Simple mode\" from the \"Mode\" menu.\n"
+"If you encounter error messages concerning graphics\n"
+"when running Spring it might be necessary to disable\n"
+" some options in expert mode.\n"
+msgstr ""
+"è¿äºéé¡¹è®©ä½ ç²ç¥çè°æ´Springç渲æã\n"
+"å¦ææ³è¦æ´é«ç游ææµç
度ï¼å¯ä»¥å°è¯è°ä½è®¾ç½®ã\n"
+"æ³è¦å
¨é¢è°èææ设置ï¼å¯ä»¥è¿å
¥âä¸å®¶æ¨¡å¼âï¼\n"
+"ç¹å»å³ä¾§çæé®æ使ç¨é¡¶é¨èåæ ä¸çâ模å¼âèåã\n"
+"ä½ å¯éæ¶åå°ç®æ模å¼ï¼åªéå¨â模å¼âèåä¸ç¹éâç®æ模å¼âå³å¯ã\n"
+"å¦æä½ å¨è¿è¡Springçæ¶åéå°ä»»ä½å
³äºå¾åçé误信æ¯ï¼\n"
+"ä¹è®¸éè¦ä½ å¨âä¸å®¶æ¨¡å¼âä¸ç¦ç¨æäºé项ã\n"
+
+#: src/settings++/tab_simple.cpp:51
+msgid "Graphics quality"
+msgstr "å¾åè´¨é"
+
+#: src/settings++/tab_simple.cpp:52
+msgid "Graphics detail"
+msgstr "å¾åç»è"
+
+#: src/settings++/tab_simple.cpp:53
+msgid "Screen resolution"
+msgstr "å±å¹å辨ç"
+
+#: src/settings++/tab_simple.cpp:54
+msgid "Switch to expert mode"
+msgstr "åæ¢å°ä¸å®¶æ¨¡å¼"
+
+#: src/settings++/tab_simple.cpp:77
+msgid " (current)"
+msgstr " (å½å)"
+
+#: src/settings++/tab_simple.cpp:88
+msgid "Sets all quality options to predefined values according to your choice."
+msgstr "æ ¹æ®ä½ çéæ©è®¾ç½®ææç»è´¨é项为é¢è®¾å¼ã"
+
+#: src/settings++/tab_simple.cpp:94
+msgid "Sets all detail options to predefined values according to your choice."
+msgstr "æ ¹æ®ä½ çéæ©è®¾ç½®ææç»èé项为é¢è®¾å¼ã"
+
+#: src/settings++/tab_simple.cpp:99
+msgid ""
+"Select the resolution fitting your monitor(s).\n"
+"Selecting a dual screen resolution will automatically enable dual screen "
+"mode.\n"
+"If the appropiate resolution is not available you can set it manually in "
+"expert mode.\n"
+"Please also contact the author so it can be added in future releases."
+msgstr ""
+"éæ©éåä½ æ¾ç¤ºå¨çå辨çã\n"
+"éæ©ä¸ä¸ªåå±å¹çå辨çå°ä¼èªå¨å¯ç¨ åå±å¹æ¨¡å¼ã\n"
+"å¦ææ£ç¡®çå辨çæªè¢«ååºï¼ä½ å¯ä»¥å¨ä¸å®¶æ¨¡å¼ä¸æå¨è®¾ç½®ã\n"
+"åæ¶è¯·èç³»ä½è
ï¼ä»¥ä¾¿å¨åæçæ¬ä¸å å
¥ã"
+
+#: src/settings++/tab_simple.cpp:135
+msgid "Info"
+msgstr "ä¿¡æ¯"
+
+#: src/settings++/tab_ui.cpp:37
+msgid ""
+"Setting a slider to 0 will exclude that\n"
+"mode from being cycled through ingame."
+msgstr ""
+"设置ä¸ä¸ªæ»åå°0å°ä¼ä½¿è¯¥è§è§æ¨¡å¼å¨\n"
+"游æä¸è¢«ç¦ç¨ã"
+
+#: src/settings++/tab_ui.cpp:128
+msgid "Scroll Speeds (mouse + keyboard)"
+msgstr "æ»å¨é度ï¼é¼ æ + é®çï¼"
+
+#: src/settings++/tab_ui.cpp:132
+msgid "Default Camera Mode"
+msgstr "é»è®¤è§è§æ¨¡å¼"
+
+#: src/settings++/tab_ui.cpp:134
+msgid "Misc. UI Options"
+msgstr "å
¶ä» å¾å½¢çé¢é项"
+
+#: src/settings++/tab_ui.cpp:136
+msgid "Zoom"
+msgstr "缩æ¾"
+
+#: src/singleplayertab.cpp:57
+msgid ""
+"You can drag the sun/bot icon around to define start position.\n"
+" Hover over the icon for a popup that lets you change side, ally and bonus."
+msgstr ""
+"ä½ å¯ä»¥å°å¤ªé³/æºå¨äººå¾æ æå¨å°é¢å
设å®çèµ·å§ç¹éè¿ã\n"
+" å°é¼ æ 移è³å¾æ ä¸ä¼å¼¹åºä¸ä¸ªçé¢è®©ä½ éæ©éµè¥ï¼èç以åèµæºå æã"
+
+#: src/singleplayertab.cpp:81
+msgid "Add bot..."
+msgstr "æ·»å AI..."
+
+#: src/singleplayertab.cpp:100
+#, fuzzy
+msgid "Spectate only"
+msgstr "è§çè
"
+
+#: src/singleplayertab.cpp:103
+#, fuzzy
+msgid "Random start positions"
+msgstr "éæºåºçä½ç½®"
+
+#: src/singleplayertab.cpp:145 src/singleplayertab.cpp:169
+msgid "-- Select one --"
+msgstr "-- 请éæ©ä¸ä¸ª --"
+
+#: src/singleplayertab.cpp:235 src/singleplayertab.cpp:242
+msgid "Gamesetup error"
+msgstr "游æ设置é误"
+
+#: src/singleplayertab.cpp:242
+msgid "You have to select a map first."
+msgstr "ä½ å¿
é¡»å
éæ©ä¸ä¸ªå°å¾"
+
+#: src/singleplayertab.cpp:249
+msgid ""
+"Continue without adding a bot first?.\n"
+" The game will be over pretty fast.\n"
+" "
+msgstr ""
+"ä¸æ·»å AI并继ç»ï¼\n"
+" 游æå°ä¼é常快çç»æã\n"
+" "
+
+#: src/singleplayertab.cpp:250
+msgid "No Bot added"
+msgstr "没æAI被添å "
+
+#: src/singleplayertab.cpp:313
+msgid "You cannot start a spring instance while another is already running"
+msgstr "ä½ ä¸è½å¨æå¦ä¸ä¸ªSpringæ£å¨æ§è¡çæ¶åå次å¯å¨Spring"
+
+#: src/springlobbyapp.cpp:168
+msgid "Hi "
+msgstr "å¨ "
+
+#: src/springlobbyapp.cpp:168
+msgid ""
+",\n"
+"It looks like this is your first time using SpringLobby. I have guessed a "
+"configuration that I think will work for you but you should review it, "
+"especially the Spring configuration. \n"
+"\n"
+"When you are done you can go to the File menu, connect to a server, and "
+"enjoy a nice game of Spring :)"
+msgstr ""
+"ï¼\n"
+"çæ¥è¿æ¯ä½ 第ä¸æ¬¡ä½¿ç¨Spring游æ大å
ãæå·²ç»ä¸ºä½ é¢å
è¿è¡äºé项设置ãä¸è¿ä½ æ好"
+"åèªå·±çä¸ä¸ï¼å°¤å
¶æ¯Springçé
ç½®ã \n"
+"\n"
+"å½ä½ å®æåï¼ä½ å¯ä»¥æå¼æ件èåï¼è¿æ¥å°ä¸ä¸ªæå¡å¨ï¼å¹¶äº«åSpring带ç»ä½ ç精彩游"
+"æã :)"
+
+#: src/springlobbyapp.cpp:168
+msgid "Welcome"
+msgstr "欢è¿"
+
+#: src/springlobbyapp.cpp:172
+msgid ""
+"By default SpringLobby reports some usage statistics.\n"
+"You can disable that on options tab --> General."
+msgstr ""
+
+#: src/springlobbyapp.cpp:172
+#, fuzzy
+msgid "Notice"
+msgstr "æ "
+
+#: src/springlobbyapp.cpp:188
+msgid "Should I try to import (some) TASClient settings?\n"
+msgstr ""
+
+#: src/springlobbyapp.cpp:188
+#, fuzzy
+msgid "Import settings?"
+msgstr "è·¯å¾è®¾ç½®"
+
+#: src/springlobbyapp.cpp:248
+msgid ""
+"The application has generated a fatal error and will be terminated\n"
+"Generating a bug report is not possible\n"
+"\n"
+"please get a wxWidgets library that supports wxUSE_DEBUGREPORT"
+msgstr ""
+"该ç¨åºäº§çäºä¸ä¸ªä¸¥éé误ï¼å³å°è¢«å
³é\n"
+"并ä¸çæä¸ä¸ªBugæ¥åæ¯ä¸å¯è½ç\n"
+"\n"
+"请使ç¨æ¯æwxUSE_DEBUGREPORTçwxWidgetsåº"
+
+#: src/springlobbyapp.cpp:281
+msgid "only run update, quit immediately afterwards"
+msgstr ""
+
+#: src/springlobbyapp.cpp:451 src/springlobbyapp.cpp:452
+#, fuzzy
+msgid "Ignore chat"
+msgstr "å
¬ä¼è天"
+
+#: src/springlobbyapp.cpp:453 src/springlobbyapp.cpp:454
+#, fuzzy
+msgid "Battle Autokick"
+msgstr "游æå表"
+
+#: src/springlobbyapp.cpp:455 src/springlobbyapp.cpp:456
+#: src/springlobbyapp.cpp:457 src/springlobbyapp.cpp:458
+#: src/springlobbyapp.cpp:459
+#, fuzzy
+msgid "Friends"
+msgstr "æ¥æ¾"
+
+#: src/springoptionstab.cpp:57
+msgid "Search only in current installed path"
+msgstr ""
+
+#: src/springoptionstab.cpp:65
+msgid "Spring executable"
+msgstr "Spring æ§è¡æ件"
+
+#: src/springoptionstab.cpp:67 src/springoptionstab.cpp:78
+msgid "Location"
+msgstr "ä½ç½®"
+
+#: src/springoptionstab.cpp:70 src/springoptionstab.cpp:80
+msgid "Find"
+msgstr "æ¥æ¾"
+
+#: src/springoptionstab.cpp:75
+msgid "UnitSync library"
+msgstr "UnitSyncåº"
+
+#: src/springoptionstab.cpp:82
+msgid "Auto Configure"
+msgstr "èªå¨é
ç½®"
+
+#: src/springoptionstab.cpp:83
+msgid "Change Datadir path"
+msgstr ""
+
+#: src/springoptionstab.cpp:182
+msgid "Choose a Spring executable"
+msgstr "éæ©Springæ§è¡æ件"
+
+#: src/springoptionstab.cpp:190 src/springoptionstab.cpp:192
+#: src/springoptionstab.cpp:198
+msgid "Library"
+msgstr "åº"
+
+#: src/springoptionstab.cpp:195
+msgid "Choose UnitSync library"
+msgstr "éæ©UnitSyncåº"
+
+#: src/springoptionstab.cpp:218
+msgid ""
+"SpringLobby is unable to load your UnitSync library.\n"
+"\n"
+"You might want to take another look at your unitsync setting."
+msgstr ""
+"Spring大å
æ æ³è½½å
¥ä½ çUnitSyncåºã\n"
+"\n"
+"ä½ å¯è½éè¦å次æ£æ¥ä½ çUnitSync设置ã"
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid ""
+"Do you want to change spring's datadir location? (select yes only if you "
+"know what you're doing)"
+msgstr "ä»ä¹é½ä¸åï¼åªæå¨ä½ ç¥éä½ å¨åä»ä¹çæ¶åæéæ©å®ï¼"
+
+#: src/springoptionstab.cpp:277
+#, fuzzy
+msgid "Data dir wizard"
+msgstr "é¦æ¬¡ä½¿ç¨å导"
+
+#: src/springoptionstab.cpp:281
+msgid "Choose a folder"
+msgstr "éæ©æ件夹"
+
+#: src/springoptionstab.cpp:294
+msgid ""
+"Something went wrong when creating the directories\n"
+"Please create manually the following folders:"
+msgstr ""
+"å建ç®å½æ¶åçé误\n"
+"请æå¨å建ä¸åç®å½ï¼"
+
+#: src/tasserver.cpp:392 src/ui.cpp:246
+msgid "Connection timed out"
+msgstr "è¿æ¥è¶
æ¶"
+
+#: src/tasserver.cpp:405
+msgid "Unknown answer from server"
+msgstr "æå¡å¨ä¼ æ¥æªç¥çæ¡"
+
+#: src/tasserver.cpp:517
+msgid ""
+"Failed to punch through NAT, playing this battle might not work for you or "
+"for other players."
+msgstr "æ æ³ç©¿è¶NATï¼ä½ æå
¶ä»ç©å®¶å¯è½æ æ³åä¸è¿åºææã"
+
+#: src/tdfcontainer.cpp:128
+msgid "line "
+msgstr ""
+
+#: src/tdfcontainer.cpp:128
+msgid " , column "
+msgstr ""
+
+#: src/torrentlistctrl.cpp:44
+#, fuzzy
+msgid "Numcopies"
+msgstr "æ°å"
+
+#: src/torrentlistctrl.cpp:48
+#, fuzzy
+msgid "MB downloaded"
+msgstr "ä¸ä¼ å
åè"
+
+#: src/torrentlistctrl.cpp:52
+msgid "MB uploaded"
+msgstr "ä¸ä¼ å
åè"
+
+#: src/torrentlistctrl.cpp:56
+#, fuzzy
+msgid "Status"
+msgstr "ç¶æï¼"
+
+#: src/torrentlistctrl.cpp:60
+#, c-format
+msgid "% complete"
+msgstr "è¿åº¦ %c"
+
+#: src/torrentlistctrl.cpp:64
+msgid "KB/s up"
+msgstr "KB/s ä¸ä¼ "
+
+#: src/torrentlistctrl.cpp:68
+msgid "KB/s down"
+msgstr "KB/s ä¸è½½"
+
+#: src/torrentlistctrl.cpp:72
+msgid "ETA (s)"
+msgstr "估计å©ä½æ¶é´ï¼ç§ï¼"
+
+#: src/torrentlistctrl.cpp:76
+msgid "Filesize (MB)"
+msgstr "æ件大å°ï¼MB)"
+
+#: src/torrentoptionspanel.cpp:37
+msgid "Torrent system autostart"
+msgstr "Torrentç³»ç»èªå¨å¼å§"
+
+#: src/torrentoptionspanel.cpp:39
+msgid "at lobby connection (default)"
+msgstr "å½å¤§å
è¿æ¥å°æå¡å¨æ¶ï¼é»è®¤ï¼"
+
+#: src/torrentoptionspanel.cpp:40
+msgid "at lobby start"
+msgstr "å½å¤§å
å¯å¨æ¶"
+
+#: src/torrentoptionspanel.cpp:41
+msgid "manual"
+msgstr "æå¨"
+
+#: src/torrentoptionspanel.cpp:51
+msgid "At game start suspend mode"
+msgstr "游æå¼å§æ¶èªå¨æå"
+
+#: src/torrentoptionspanel.cpp:53
+msgid "Pause all torrents"
+msgstr "æåææTorrent"
+
+#: src/torrentoptionspanel.cpp:54
+msgid "Throttle speeds:"
+msgstr "è°èé度ï¼"
+
+#: src/torrentoptionspanel.cpp:57
+msgid "upload (KB/s)"
+msgstr "ä¸ä¼ ï¼KB/sï¼"
+
+#: src/torrentoptionspanel.cpp:59
+msgid "download (KB/s)"
+msgstr "ä¸è½½ï¼KB/sï¼"
+
+#: src/torrentoptionspanel.cpp:72
+msgid "Numbers"
+msgstr "æ°å"
+
+#: src/torrentoptionspanel.cpp:76
+msgid "maximum upload speed in KB/sec(-1 for infinite)"
+msgstr "æ大ä¸ä¼ é度ï¼KB/sï¼ï¼-1代表æ ä¸é"
+
+#: src/torrentoptionspanel.cpp:83
+msgid "maximum download speed in KB/sec (-1 for infinite)"
+msgstr "æ大ä¸è½½é度ï¼KB/sï¼ï¼-1代表æ ä¸é"
+
+#: src/torrentoptionspanel.cpp:90
+msgid "port used for torrent connections"
+msgstr "Torrentè¿æ¥ç«¯å£"
+
+#: src/torrentoptionspanel.cpp:97
+msgid "maximum number of concurrent connections"
+msgstr "æ大åæ¶è¿æ¥æ°é"
+
+#: src/torrentwrapper.cpp:443
+msgid ""
+"Tried all known trackers for torrent system. No connection could be "
+"established"
+msgstr ""
+
+#: src/torrentwrapper.cpp:444
+#, fuzzy
+msgid "Torrent system failure"
+msgstr "Torrentç³»ç»èªå¨å¼å§"
+
+#: src/ui.cpp:165
+msgid "Server password"
+msgstr "æå¡å¨å¯ç "
+
+#: src/ui.cpp:241
+msgid ""
+"Registration successful,\n"
+"you should now be able to login."
+msgstr ""
+"注åæåï¼\n"
+"ä½ ç°å¨å°±åºè¯¥è½å¤ç»éã"
+
+#: src/ui.cpp:241
+msgid "Registration successful"
+msgstr "注åæå"
+
+#: src/ui.cpp:247
+msgid "Registration failed, the reason was:\n"
+msgstr "注å失败ï¼åå æ¯ï¼\n"
+
+#: src/ui.cpp:373
+msgid ""
+"\n"
+"Broser path is: "
+msgstr ""
+"\n"
+"æµè§å¨è·¯å¾ä¸ºï¼ "
+
+#: src/ui.cpp:482
+msgid "Help error"
+msgstr "帮å©é误"
+
+#: src/ui.cpp:482
+msgid "Type /help in a chat box."
+msgstr "å¨è天ææ¬æ¡ä¸è¾å
¥ /helpã"
+
+#: src/ui.cpp:487
+msgid "SpringLobby commands help."
+msgstr "Spring大å
æ令帮å©ã"
+
+#: src/ui.cpp:489
+msgid "Global commands:"
+msgstr "å
¨å±æ令ï¼"
+
+#: src/ui.cpp:490
+msgid " \"/away\" - Sets your status to away."
+msgstr " /away è®¾ç½®ä½ çç¶æ为离å¼ã"
+
+#: src/ui.cpp:491
+msgid " \"/back\" - Resets your away status."
+msgstr " /back åæ¶ä½ ç离å¼ç¶æã"
+
+#: src/ui.cpp:492
+msgid ""
+" \"/changepassword oldpassword newpassword\" - Changes the current active "
+"account's password."
+msgstr " /changepassword æ§å¯ç æ°å¯ç ä¿®æ¹å½åæ´»å¨å¸æ·çå¯ç ã"
+
+#: src/ui.cpp:493
+msgid " \"/channels\" - Lists currently active channels."
+msgstr " /channels å举ææå½åæ´»å¨çé¢éã"
+
+#: src/ui.cpp:494
+msgid ""
+" \"/help [topic]\" - Put topic if you want to know more specific "
+"information about a command."
+msgstr " /help [è¯é¢] å¦æä½ æ³äºè§£æå
³ä¸ä¸ªæ令çæ´å¤è¯¦ç»ä¿¡æ¯ï¼è¯·å°è¯é¢åå
¥ã"
+
+#: src/ui.cpp:495
+#, fuzzy
+msgid ""
+" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel."
+msgstr " /join é¢éå [å¯ç ] [,é¢éå2 [å¯ç 2]...] å å
¥ä¸ä¸ª/å¤ä¸ªé¢éã"
+
+#: src/ui.cpp:496
+msgid " \"/j\" - Alias to /join."
+msgstr " /j çäº /joinã"
+
+#: src/ui.cpp:497
+#, fuzzy
+msgid " \"/ingame\" - Shows how much time you have in game."
+msgstr " /ingame æ¾ç¤ºä½ å¨æ¸¸æä¸çæ¶é´é¿åº¦ã"
+
+#: src/ui.cpp:498
+#, fuzzy
+msgid ""
+" \"/msg username [text]\" - Sends a private message containing text to "
+"username."
+msgstr " /msg ç¨æ·å [æ¶æ¯ææ¬] åæ个ç¨æ·åéç§äººæ¶æ¯ã"
+
+#: src/ui.cpp:499
+#, fuzzy
+msgid " \"/part\" - Leaves current channel."
+msgstr " /channels å举ææå½åæ´»å¨çé¢éã"
+
+#: src/ui.cpp:500
+#, fuzzy
+msgid " \"/p\" - Alias to /part."
+msgstr " /j çäº /joinã"
+
+#: src/ui.cpp:501
+msgid " \"/rename newalias\" - Changes your nickname to newalias."
+msgstr " /rename æ°ç¨æ·å å°ä½ çæµç§°ä¿®æ¹ä¸ºæ°çç¨æ·åã"
+
+#: src/ui.cpp:502
+#, fuzzy
+msgid " \"/sayver\" - Says what version of springlobby you have in chat."
+msgstr " /sayver åè¯ç¨æ·ä½ æ£å¨ä½¿ç¨çSpring大å
çæ¬å·ã"
+
+#: src/ui.cpp:503
+msgid " \"/testmd5 text\" - Returns md5-b64 hash of given text."
+msgstr " /testmd5 ææ¬ è¿åç»å®ææ¬çMD5åå¸å¼ã"
+
+#: src/ui.cpp:504
+#, fuzzy
+msgid " \"/ver\" - Displays what version of SpringLobby you have."
+msgstr " /ver æ¾ç¤ºä½ æ¥æçSpring大å
çæ¬å·ã"
+
+#: src/ui.cpp:505
+msgid " \"/clear\" - Clears all text from current chat panel"
+msgstr ""
+
+#: src/ui.cpp:507
+msgid "Chat commands:"
+msgstr "è天å½ä»¤ï¼"
+
+#: src/ui.cpp:508
+msgid " \"/me action\" - Say IRC style action message."
+msgstr " /me è¡ä¸º åéIRCæ ·å¼çè¡ä¸ºæ¶æ¯ã"
+
+#: src/ui.cpp:510
+msgid ""
+"If you are missing any commands, go to #springlobby and try to type it "
+"there :)"
+msgstr "å¦æä½ å¿è®°ä»»ä½çå½ä»¤ï¼å°#springlobbyé¢é并å¨é£éå°è¯è¾å
¥ :)"
+
+#: src/ui.cpp:515
+msgid "No topics written yet."
+msgstr "è¿æ²¡æåè¯é¢ã"
+
+#: src/ui.cpp:519
+msgid "The topic \""
+msgstr "è¯é¢ â"
+
+#: src/ui.cpp:519
+msgid "\" was not found. Type \"/help topics\" only for available topics."
+msgstr "âæªè¢«æ¾å°ãè¾å
¥â/help è¯é¢åâæ¶ä»
éå¯ç¨çè¯é¢ã"
+
+#: src/ui.cpp:609
+#, fuzzy
+msgid ""
+"Couldn't get your spring versions from any unitsync library.\n"
+"\n"
+"Online play is currently disabled."
+msgstr ""
+"æ æ³ä»UnitSyncåºä¸è·åä½ çSpringçæ¬ã\n"
+"\n"
+"å¨çº¿æ¸¸æå°è¢«ç¦ç¨ã"
+
+#: src/ui.cpp:625
+#, c-format
+msgid ""
+"No compatible installed spring version has been found, this server requires "
+"version: %s\n"
+msgstr ""
+
+#: src/ui.cpp:628
+#, fuzzy
+msgid "Online play is currently disabled."
+msgstr "å¨çº¿æ¸¸æå°è¢«ç¦ç¨ã"
+
+#: src/ui.cpp:661
+#, fuzzy
+msgid "Disconnected from server."
+msgstr "æå¡å¨ä¼ æ¥æªç¥çæ¡"
+
+#: src/ui.cpp:673
+msgid ""
+"A connection couldn't be established with the server\n"
+"Would you like to try again with the same server?\n"
+"No to switch to next server in the list"
+msgstr ""
+
+#: src/ui.cpp:673
+#, fuzzy
+msgid "Connection failure"
+msgstr "è¿æ¥è¶
æ¶"
+
+#: src/ui.cpp:835
+msgid "no active chat panels open."
+msgstr "没ææ´»å¨çè天é¢æ¿å¼å¯"
+
+#: src/ui.cpp:838
+#, c-format
+msgid "(%d users)"
+msgstr "(%d åç¨æ·ï¼"
+
+#: src/ui.cpp:902
+msgid "Server message"
+msgstr "æå¡å¨æ¶æ¯"
+
+#: src/ui.cpp:947
+msgid "The current battle was closed by the host."
+msgstr "å½åææ被主建è
å
³é"
+
+#: src/ui.cpp:947
+msgid "Battle closed"
+msgstr "æåºå·²å
³é"
+
+#: src/ui.cpp:1051
+msgid ""
+"Your spring settings are probably not configured correctly,\n"
+"you should take another look at your settings before trying\n"
+"to play online."
+msgstr "ä½ çSpring设置并ä¸æ£ç¡®ï¼å¨å¼å§ç½ä¸å¯¹æå请å次æ£æ¥ä½ ç设置ã"
+
+#: src/ui.cpp:1051
+msgid "Spring settings error"
+msgstr "Spring设置é误"
+
+#: src/ui.cpp:1258
+msgid "The selected preset requires the map "
+msgstr ""
+
+#: src/ui.cpp:1258
+msgid ""
+". Should it be downloaded? \n"
+" Selecting \"no\" will remove the missing map from the preset.\n"
+" Please reselect the preset after "
+"download finished"
+msgstr ""
+
+#: src/ui.cpp:1261
+msgid "Map missing"
+msgstr ""
+
+#: src/updater/updater.cpp:46
+msgid ""
+"There was an error checking for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"æ£æ¥ææ°çæ¬æ¶åçé误ã\n"
+"请ç¨åå°è¯ã\n"
+"å¦æé®é¢ä¾ç¶åå¨ï¼è¯·ä½¿ç¨ å¸®å© -> æ¥åBugã"
+
+#: src/updater/updater.cpp:51
+msgid "Your Version: "
+msgstr "ä½ ççæ¬ï¼ "
+
+#: src/updater/updater.cpp:51
+msgid "Latest Version: "
+msgstr "ææ°çæ¬ï¼ "
+
+#: src/updater/updater.cpp:55 src/updater/updater.cpp:68
+msgid ""
+"Your SpringLobby version is not up to date.\n"
+"\n"
+msgstr ""
+"ä½ ç SpringLobby çæ¬ä¸æ¯ææ°çã\n"
+"\n"
+
+#: src/updater/updater.cpp:55
+msgid ""
+"\n"
+"\n"
+"Would you like for me to autodownload the new version? Changes will take "
+"effect next you launch the lobby again."
+msgstr ""
+
+#: src/updater/updater.cpp:55
+#, fuzzy
+msgid "Not up to date"
+msgstr "ä¸æ¯ææ°ç"
+
+#: src/updater/updater.cpp:62
+msgid "SpringLobby -- downloading update"
+msgstr ""
+
+#: src/updater/updater.cpp:68
+msgid "Not up to Date"
+msgstr "ä¸æ¯ææ°ç"
+
+#: src/updater/updater.cpp:82
+msgid ""
+"Unable to write to the lobby installation directory.\n"
+"Please update manually or enable write permissions for the current user."
+msgstr ""
+
+#: src/updater/updater.cpp:97
+#, fuzzy
+msgid ""
+"There was an error downloading for the latest version.\n"
+"Please try again later.\n"
+"If the problem persists, please use Help->Report Bug to report this bug."
+msgstr ""
+"æ£æ¥ææ°çæ¬æ¶åçé误ã\n"
+"请ç¨åå°è¯ã\n"
+"å¦æé®é¢ä¾ç¶åå¨ï¼è¯·ä½¿ç¨ å¸®å© -> æ¥åBugã"
+
+#: src/updater/updater.cpp:102 src/updater/updater.cpp:105
+#, fuzzy, c-format
+msgid ""
+"There was an error while trying to replace the current executable version\n"
+" manual copy is necessary from: %s\n"
+" to: %s\n"
+"Please use Help->Report Bug to report this bug."
+msgstr ""
+"æ£æ¥ææ°çæ¬æ¶åçé误ã\n"
+"请ç¨åå°è¯ã\n"
+"å¦æé®é¢ä¾ç¶åå¨ï¼è¯·ä½¿ç¨ å¸®å© -> æ¥åBugã"
+
+#: src/updater/updater.cpp:113 src/updater/updater.cpp:116
+msgid "Update complete. The changes will be available next lobby start."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid ""
+"Binary updated successfully. \n"
+"Some translation files could not be updated.\n"
+"Please report this in #springlobby after restarting."
+msgstr ""
+
+#: src/updater/updater.cpp:123 src/updater/updater.cpp:126
+msgid "Partial success"
+msgstr ""
+
+#: src/useractions.cpp:179
+msgid ""
+"To prevent logical inconsistencies, adding a user to more than one group is "
+"not allowed"
+msgstr ""
+
+#: src/useractions.cpp:180
+msgid "Cannot add user to group"
+msgstr ""
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "none"
+msgstr "æ "
+
+#: src/useractions.h:11
+#, fuzzy
+msgid "highlight"
+msgstr "é«äº®æ¾ç¤º"
+
+#: src/useractions.h:11
+msgid "notify login/out"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore chat"
+msgstr ""
+
+#: src/useractions.h:11
+msgid "ignore pm"
+msgstr ""
+
+#: src/useractions.h:12
+msgid "autokick"
+msgstr ""
+
+#: src/useractions.h:12
+#, fuzzy
+msgid "notify hosted battle"
+msgstr "å å
¥åä¸ææ"
+
+#: src/useractions.h:12
+msgid "notify status change"
+msgstr ""
+
+#: src/useractions.h:19
+#, fuzzy
+msgid "no action at all"
+msgstr "没ææ´»å¨çè天é¢æ¿å¼å¯"
+
+#: src/useractions.h:19
+msgid "highlight user in nick list and battles he participates in"
+msgstr ""
+
+#: src/useractions.h:20
+msgid "popup a message box when user logs in/out from the server"
+msgstr ""
+
+#: src/useractions.h:21
+msgid ""
+"ignore private messages of these users, no pm window will open if any of "
+"these try to contact you privately"
+msgstr ""
+
+#: src/useractions.h:22
+msgid "popup a message box when user hosts a new battle"
+msgstr ""
+
+#: src/useractions.h:23
+msgid "popup a message box when user changes away status"
+msgstr ""
+
+#: src/user.cpp:77
+#, fuzzy
+msgid "away"
+msgstr "æ»æ¯"
+
+#: src/user.cpp:77
+msgid "back"
+msgstr ""
+
+#: src/user.cpp:79
+#, fuzzy
+msgid "ingame"
+msgstr "æµç§°"
+
+#: src/user.cpp:79
+msgid "back from game"
+msgstr ""
+
+#: src/user.cpp:188
+msgid "Newbie"
+msgstr "æ°æ"
+
+#: src/user.cpp:189
+msgid "Beginner"
+msgstr "åå¦è
"
+
+#: src/user.cpp:190
+msgid "Average"
+msgstr "大ä¼çº§æ°å
µ"
+
+#: src/user.cpp:191
+msgid "Above average"
+msgstr "èå
µ"
+
+#: src/user.cpp:192
+msgid "Experienced"
+msgstr "å¯æç»éªçç©å®¶"
+
+#: src/user.cpp:193
+msgid "Highly experienced"
+msgstr "æå¯ç»éªç"
+
+#: src/user.cpp:194
+msgid "Veteran"
+msgstr "èé¸"
+
+#: src/user.cpp:195
+#, fuzzy
+msgid "Unknown"
+msgstr "æªç¥"
+
+#: src/usermenu.h:23
+msgid "Create new group..."
+msgstr ""
+
+#: src/usermenu.h:29
+#, fuzzy
+msgid "Add to group..."
+msgstr "æ·»å AI..."
+
+#: src/usermenu.h:30
+#, fuzzy
+msgid "Remove from group"
+msgstr "移é¤ç¨æ·å¸æ·"
+
+#: src/widgets/downloaddialog.cpp:14
+msgid "widgets"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:35
+msgid "getting infos"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:64
+#, fuzzy
+msgid "Author"
+msgstr "奥å°å©"
+
+#: src/widgets/infopanel.cpp:69
+msgid "Suitable mods"
+msgstr ""
+
+#: src/widgets/infopanel.cpp:74
+#, fuzzy
+msgid "Current version"
+msgstr "ä½ çSpringçæ¬"
+
+#: src/widgets/infopanel.cpp:79
+#, fuzzy
+msgid "# downloaded"
+msgstr "ä¸ä¼ å
åè"
+
+#: src/widgets/infopanel.cpp:84
+#, fuzzy
+msgid "Published on"
+msgstr "åå¸æ°æ件"
+
+#: src/widgets/infopanel.cpp:121
+#, fuzzy
+msgid "Changelog"
+msgstr "åæ¶"
+
+#: src/widgets/infopanel.cpp:126
+#, fuzzy
+msgid "Screenshots"
+msgstr "å±å¹å辨ç"
+
+#: src/widgets/infopanel.cpp:158
+msgid "Widget files have been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:161
+msgid "Widget files have not been installed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:170
+msgid "Widget files have been removed."
+msgstr ""
+
+#: src/widgets/infopanel.cpp:173
+msgid "Widget files have not been removed."
+msgstr ""
+
+#, fuzzy
+#~ msgid "spectators"
+#~ msgstr "æè§è
:"
+
+#, fuzzy
+#~ msgid "players"
+#~ msgstr "ç©å®¶ï¼"
+
+#, fuzzy
+#~ msgid "team"
+#~ msgstr "éä¼"
+
+#, fuzzy
+#~ msgid "ally"
+#~ msgstr "èç"
+
+#~ msgid "cpu"
+#~ msgstr "CPU"
+
+#~ msgid "Test firewall"
+#~ msgstr "æµè¯é²ç«å¢"
+
+#, fuzzy
+#~ msgid "Game is closed."
+#~ msgstr "è天被å
³éã"
+
+#, fuzzy
+#~ msgid "Game is in progress."
+#~ msgstr "æ£å¨ä¼ è¾ä¸ï¼ "
+
+#, fuzzy
+#~ msgid "Game is in progress and full."
+#~ msgstr "æ£å¨ä¼ è¾ä¸ï¼ "
+
+#, fuzzy
+#~ msgid "Tab icons"
+#~ msgstr "å°å¾é项"
+
+#, fuzzy
+#~ msgid "Chose in game"
+#~ msgstr "å¨æ¸¸æä¸éæ©"
+
+#, fuzzy
+#~ msgid "Download started"
+#~ msgstr "ä¸è½½å®æ¯"
+
+#, fuzzy
+#~ msgid "Disconnecting"
+#~ msgstr "æå¼è¿æ¥"
+
+#~ msgid "Debug"
+#~ msgstr "è°è¯"
+
+#~ msgid "Debug Options"
+#~ msgstr "è°è¯é项"
+
+#, fuzzy
+#~ msgid "Player"
+#~ msgstr "ç©å®¶:"
+
+#~ msgid "status"
+#~ msgstr "ç¶æ"
+
+#, fuzzy
+#~ msgid "Choose color"
+#~ msgstr "éæ©æ件夹"
+
+#, fuzzy
+#~ msgid "Grouping size"
+#~ msgstr "å¨ä½"
+
+#~ msgid "a"
+#~ msgstr "a"
+
+#~ msgid "p"
+#~ msgstr "ç©å®¶æ°"
+
+#~ msgid "m"
+#~ msgstr "æ大ç©å®¶æ°"
+
+#~ msgid "%d%"
+#~ msgstr "%d%"
+
+#~ msgid "t"
+#~ msgstr "éä¼"
+
+#~ msgid ""
+#~ "Value out of range.\n"
+#~ " Enter an integer between 0 & 100."
+#~ msgstr ""
+#~ "æ°å¼è¶
åºèå´ã\n"
+#~ " 请è¾å
¥ä»0ä¸100ä¹é´çä¸ä¸ªæ´æ°ã"
+
+#~ msgid ""
+#~ "There are two or more bots on the same team. Because bots don't know how "
+#~ "to share, this won't work."
+#~ msgstr ""
+#~ "æ两个æ以ä¸çAI使ç¨åä¸ä¸ªéä¼å·ç ãå 为AI没æå
±äº«éä¼çè½åï¼å æ¤ä¸è½æ§"
+#~ "è¡ã"
+
+#~ msgid "Bot team sharing."
+#~ msgstr "AIéä¼å
±ç¨ã"
+
+#, fuzzy
+#~ msgid "Num players error"
+#~ msgstr "ç©å®¶æ°é"
+
+#, fuzzy
+#~ msgid "Channel name"
+#~ msgstr "é¢éä¿¡æ¯"
+
+#, fuzzy
+#~ msgid "topic"
+#~ msgstr "è¯é¢ â"
+
+#~ msgid "Use smart scrolling"
+#~ msgstr "å¯ç¨æºè½æ»å¨"
+
+#~ msgid "_SERVER"
+#~ msgstr "_SERVER"
+
+#~ msgid "Download failed"
+#~ msgstr "ä¸è½½å¤±è´¥"
+
+#, fuzzy
+#~ msgid ""
+#~ "You need to download the map to be able to watch this replay.\n"
+#~ "\n"
+#~ msgstr ""
+#~ "å¨ç©æ¤æ¸¸æåä½ éè¦ä¸è½½å°å¾ã\n"
+#~ "\n"
+
+#~ msgid "Unit detail"
+#~ msgstr "åä½ç»è"
+
+#~ msgid "only on/off available at this time"
+#~ msgstr "该çæ¬ä»
æ å¯ç¨/ç¦ç¨ éæ©"
+
+#~ msgid "Global sound volume"
+#~ msgstr "å
¨å±é³é"
+
+#~ msgid "mark to be able to use"
+#~ msgstr "å¾é以å¯ç¨"
+
+#~ msgid "Send debug info to console"
+#~ msgstr "å°è°è¯ä¿¡æ¯è¾åºå°æ§å¶å°"
+
+#~ msgid "if disabled these will only be logged"
+#~ msgstr "å¦æ被ç¦ç¨ï¼å®ä»¬åªä¼è¢«è®°å½èä¸ä¼è¢«è¾åº"
+
+#~ msgid ""
+#~ "You're using a wxwidgets library of the 2.6.x series\n"
+#~ " battle filtering, advanced gui and joining/hosting games using nat "
+#~ "traversal\n"
+#~ " won't be available"
+#~ msgstr ""
+#~ "ä½ æ£å¨ä½¿ç¨2.6.xç³»åçæ¬çwxWidgetsåº\n"
+#~ " ææè¿æ»¤ï¼é«çº§çå¾å½¢çé¢ä»¥å使ç¨NATç©¿è¶è¿å
¥/主建游æ\n"
+#~ " å°ä¸è¢«æ¯æ"
+
+#~ msgid "Missing Functionality"
+#~ msgstr "丢失çåè½"
+
+#, fuzzy
+#~ msgid ""
+#~ "Do you want to download OTA content?\n"
+#~ "You need this to be able to play TA based mods.\n"
+#~ "You need to own a copy of Total Annihilation do legally download it."
+#~ msgstr ""
+#~ "ä½ æ³è¦ä¸è½½OTAèµæåï¼\n"
+#~ "ä½ éè¦è¿ä¸ªæ¥ç©åºäºTAå¼åçå类模ç»ã\n"
+#~ "ä½ éè¦æä¸ä»½æ£ççTotal Annihilationæ¥ä½¿ä½ è½åæ³çä¸è½½OTAèµæã"
+
+#~ msgid "Download OTA content?"
+#~ msgstr "ä¸è½½OTAèµæï¼"
+
+#, fuzzy
+#~ msgid "Create a spring directory in my documents folder"
+#~ msgstr "å¨å½åç®å½ä¸å建ä¸ä¸ª.springç®å½ï¼æ¨èï¼"
+
+#, fuzzy
+#~ msgid "Do nothing"
+#~ msgstr "ç©¿å"
+
+#~ msgid "Create a folder in a custom path (you'll get prompted for the path)"
+#~ msgstr "å建ä¸ä¸ªèªå®ä¹è·¯å¾çç®å½ï¼ä½ å°ä¼è¢«è¦æ±è¾å
¥è¯¥è·¯å¾ï¼"
+
+#~ msgid "I have already a SpringData folder, i want to browse manually for it"
+#~ msgstr "æå·²ç»æä¸ä¸ªSpringæ°æ®ç®å½äºï¼ææ³æå¨æµè§å¯»æ¾å®ã"
+
+#, fuzzy
+#~ msgid ""
+#~ "Looks like you don't have yet a user SpringData folder structure\n"
+#~ "What would you like to do? (leave default choice if you don't know what "
+#~ "this is for)"
+#~ msgstr ""
+#~ "çèµ·æ¥ä½ è¿æ²¡æä¸ä¸ªç¨æ·çSpringæ°æ®ç®å½ç»æ\n"
+#~ "ä½ æ³è¦åä»ä¹ï¼ï¼å¦æä½ ä¸ç¥éè¿æ¯ä»ä¹ï¼å°±ä¿æé»è®¤çéæ©ï¼"
+
+#, fuzzy
+#~ msgid "Disconnected from server"
+#~ msgstr "æå¡å¨ä¼ æ¥æªç¥çæ¡"
+
+#, fuzzy
+#~ msgid "Not online"
+#~ msgstr "ä¸å¨çº¿"
+
+#~ msgid ""
+#~ "This game uses NAT traversal that is not supported by wx 2.6 build of "
+#~ "springlobby. \n"
+#~ "\n"
+#~ "You will not be able to play in this battle. \n"
+#~ "Update your wxwidgets to 2.8 or newer to enable NAT traversal support."
+#~ msgstr ""
+#~ "è¿ä¸ªæ¸¸æ使ç¨ä¸æ¯æNAT traversalçwx2.6çSpringlobbyã\n"
+#~ "ä½ ä¸è½å å
¥è¿åºææã\n"
+#~ "请æ´æ°ä½ çwxwidgetså°2.8ææ´æ°ç以æå¼NAT traversalæ¯æ"
+
+#, fuzzy
+#~ msgid "Only the host can change the game options"
+#~ msgstr "åªæ主æºå¯ä»¥éå®æ¸¸æã"
+
+#~ msgid "Only the host can start the battle."
+#~ msgstr "åªæ主æºæè½å¼å§ææã"
+
+#, fuzzy
+#~ msgid "Only the host can use those functions."
+#~ msgstr "åªæ主æºå¯ä»¥éå®æ¸¸æã"
+
+#~ msgid "Only the host can lock the game."
+#~ msgstr "åªæ主æºå¯ä»¥éå®æ¸¸æã"
+
+#, fuzzy
+#~ msgid "Only the host can toggle autohost mode."
+#~ msgstr "åªæ主æºå¯ä»¥éå®æ¸¸æã"
+
+#~ msgid "Invalid host/port or servername."
+#~ msgstr "æ æç主æº/端å£ææå¡å¨å称ã"
+
+#~ msgid "Active chat channels:"
+#~ msgstr "æ´»å¨çè天é¢éï¼"
+
+#~ msgid "no rank"
+#~ msgstr "没æ级å«"
+
+#, fuzzy
+#~ msgid "Battle filter is active"
+#~ msgstr "游æå表"
+
+#~ msgid "Only the host can fix player colours."
+#~ msgstr "åªæ主æºæè½ä¿®æ¹ç©å®¶é¢è²ã"
+
+#~ msgid "Select all"
+#~ msgstr "å
¨é"
+
+#, fuzzy
+#~ msgid "Add user"
+#~ msgstr "(%d åç¨æ·ï¼"
+
+#, fuzzy
+#~ msgid "Remove selected"
+#~ msgstr "模ç»æªéæ©ã"
+
+#, fuzzy
+#~ msgid "you can also enter a ';' seperated list of usernames:"
+#~ msgstr "è¾å
¥ä¸ä¸ªç± ; åéå¼çå表"
+
+#, fuzzy
+#~ msgid "Invalid usernames"
+#~ msgstr "æ æçæ°å"
+
+#, fuzzy
+#~ msgid ""
+#~ "A short description of the game, this will show up in the battle list. "
+#~ "This will be read-only for ladder"
+#~ msgstr "游æçç®çæè¿°ï¼è¿å°ä¼æ¾ç¤ºå¨å¤§å
ä¸ç游æå表ä¸ã"
+
+#, fuzzy
+#~ msgid "Select the ladder to play on."
+#~ msgstr "éæ©æ¸¸æ使ç¨ç模ç»ã"
+
+#, fuzzy
+#~ msgid "Normal game"
+#~ msgstr "æ®é"
+
+#~ msgid "NAT traversal to use. Experimental support."
+#~ msgstr "使ç¨çNATç©¿è¶æ¹å¼ãä¸å®å
¨æ¯æã"
+
+#, fuzzy
+#~ msgid "Unitsync error"
+#~ msgstr "UnitSyncé®é¢"
+
+#~ msgid "You have one or more bots sharing team, this is not possible."
+#~ msgstr "ä½ æå¤ä¸ªAIå
±ç¨éä¼åºå·ï¼è¿æ¯ä¸å
许çã"
+
+#~ msgid ""
+#~ "Please enter password needed to join this channel, leave blank for no "
+#~ "passwrd."
+#~ msgstr "请è¾å
¥å å
¥è¯¥é¢éæéçå¯ç ï¼ä¿æ空ç½ä»£è¡¨æ å¯ç ã"
+
+#~ msgid "Continue if commander dies"
+#~ msgstr "ææ¥å®è¢«æ¶çå游æ继ç»"
+
+#~ msgid "End if commander dies"
+#~ msgstr "ææ¥å®è¢«æ¶çå游æç»æ"
+
+#~ msgid "Lineage mode"
+#~ msgstr "è¡ç»æ¨¡å¼"
+
+#~ msgid "End condition"
+#~ msgstr "游æç»ææ¡ä»¶"
+
+#~ msgid "Resources"
+#~ msgstr "èµæº"
+
+#~ msgid "The amount of metal each player starts with."
+#~ msgstr "æ¯ä¸ªç©å®¶æ¸¸æå¼å§æ¶æ¥æçéå±"
+
+#~ msgid "Start Energy"
+#~ msgstr "åå§è½é"
+
+#~ msgid "The amount of energy each player starts with."
+#~ msgstr "æ¯ä¸ªç©å®¶æ¸¸æå¼å§æ¶æ¥æçè½é"
+
+#~ msgid "Max units"
+#~ msgstr "åä½æ°ä¸é"
+
+#~ msgid "The maximum number of units allowed per player."
+#~ msgstr "æ¯ä¸ªç©å®¶æ¥æçåä½ä¸ªæ°"
+
+#~ msgid "Limit d-gun"
+#~ msgstr "éå¶ä½¿ç¨ D-Gun"
+
+#~ msgid "Ghosted buildings"
+#~ msgstr "建çç©æ®å½±"
+
+#~ msgid "Diminishing metal makers"
+#~ msgstr "éå±è½¬æ¢å¨æçéæ¸åä½"
+
+#~ msgid "This chat is exclusively for participants of this battle."
+#~ msgstr "æ¤æ¬¡è天ä»
éæ¬æ¬¡ææçåä¸è
å
é¨è¿è¡ã"
+
+#~ msgid "Cannot add bot, maximum number of players already reached."
+#~ msgstr "æ æ³æ·»å AIï¼å·²è¾¾å°æ大ç©å®¶ä¸ªæ°ã"
+
+#~ msgid "Max players reached"
+#~ msgstr "已达å°æ大ç©å®¶ä¸ªæ°"
+
+#~ msgid "Autoconnect last server"
+#~ msgstr "èªå¨è¿æ¥å°æè¿ä½¿ç¨çæå¡å¨"
+
+#~ msgid "Save to:"
+#~ msgstr "ä¿åå°ï¼"
+
+#~ msgid "Browse..."
+#~ msgstr "æµè§..."
+
+#~ msgid "Choose a directory"
+#~ msgstr "éæ©ä¸ä¸ªç®å½"
+
+#~ msgid "Map/Mod Options"
+#~ msgstr "å°å¾/模ç»é项"
+
+#~ msgid ""
+#~ "Your SpringLobby version is up to date!\n"
+#~ "\n"
+#~ msgstr ""
+#~ "ä½ ç SpringLobby çæ¬æ¯ææ°çï¼\n"
+#~ "\n"
+
+#~ msgid "Up to Date"
+#~ msgstr "ææ°ç"
+
+#~ msgid ""
+#~ "\n"
+#~ "\n"
+#~ "Would you like to visit a page with instructions on how to download the "
+#~ "newest version?"
+#~ msgstr ""
+#~ "\n"
+#~ "\n"
+#~ "ä½ æ¯å¦æ³è¦è®¿é®ç¸å
³ä»ç»/ä¸è½½ææ°çæ¬ç页é¢ï¼"
+
+#~ msgid "Limit D-Gun"
+#~ msgstr "éå¶ D-Gun 使ç¨"
+
+#~ msgid ""
+#~ "Disables commander's D-gun when being too far away from the starting point"
+#~ msgstr "å½ææ¥å®ç¦»åºçä½ç½®è¿è¿æ¶ç¦ç¨ D-Gun"
+
+#~ msgid "Ghosted Buildings"
+#~ msgstr "建çç©èå"
+
+#~ msgid ""
+#~ "Enemy buildings will leave a ghost image on the map after losing LoS on "
+#~ "them"
+#~ msgstr "è§éæ¶å¤±åææ¹å»ºçç©å°ä¼çä¸ä¸ä¸ªèå"
+
+#~ msgid "Diminishing MM"
+#~ msgstr "éå±è½¬æ¢å¨æçéæ¸éä½"
+
+#~ msgid ""
+#~ "Efficiency of MetalMakers will progressively reduce as much as you build "
+#~ "them"
+#~ msgstr "ä½ å»ºé çéå±è½¬æ¢å¨è¶å¤ï¼å
¶è¿è¡æçå°±ä¼è¶ä½"
+
+#~ msgid "Game Ending condition"
+#~ msgstr "游æç»ææ¡ä»¶"
+
+#~ msgid ""
+#~ "The condition that will end the game\n"
+#~ "0: when all units will be destroyed\n"
+#~ "1: when the commander will be destroyed\n"
+#~ "2: lineage mode (see option 1, but given away units will still die"
+#~ msgstr ""
+#~ "ç»æ游æçæ¡ä»¶\n"
+#~ "0ï¼å½ææåä½é½è¢«æ¶çå\n"
+#~ "1ï¼å½ææ¥å®è¢«æ¶çå\n"
+#~ "2ï¼è¡ç»æ¨¡å¼ ï¼è§é项1ï¼ä½è¢«å
±äº«/èµ éçåä½ä¹ä¼æ»äº¡ï¼"
+
+#~ msgid "Sets the amount of metal that players will start with"
+#~ msgstr "设置ç©å®¶å¼å§æ¸¸ææ¶æ¥æçéå±"
+
+#~ msgid "Sets the amount of energy that players will start with"
+#~ msgstr "设置ç©å®¶å¼å§æ¸¸ææ¶æ¥æçè½é"
+
+#~ msgid "Max Units Allowed"
+#~ msgstr "æ大ç©å®¶äººæ°"
+
+#~ msgid ""
+#~ "Sets the maximum amount of units that a player will be allowed to build"
+#~ msgstr "设置æ¯ä¸ªç©å®¶æå¤è½å¤å»ºé çåä½ä¸ªæ°"
+
+#~ msgid "Reset"
+#~ msgstr "éç½®"
+
+#~ msgid ""
+#~ "You have bots that are not assingled to startpositions. In the current "
+#~ "version of spring you are only allowed to use start positions positioning "
+#~ "them freely is not allowed.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "æçAIæªè¢«åé
å°åºçå°ç¹ãå¨ç®åçæ¬çSpringï¼ä½ åªè½å°å®ä»¬åé
å°é¢è®¾çåºç"
+#~ "å°ç¹ï¼éæ设置åºçå°ç¹ä¸è¢«å
许ã\n"
+#~ "\n"
+#~ "è¿å°ä¼å¨ä¸ä¸ªçæ¬çSpringä¸è¢«ä¿®æ£ã"
+
+#~ msgid ""
+#~ "You are not using consecutive start position numbers.\n"
+#~ "\n"
+#~ "In the current version of spring you are not allowed to skip any "
+#~ "startpositions. You have to use all consecutive position.\n"
+#~ "\n"
+#~ "Example: if you have 2 bots + yourself you have to use start positions "
+#~ "1,2,3 not 1,3,4 or 2,3,4.\n"
+#~ "\n"
+#~ "This will be fixed in next version of Spring."
+#~ msgstr ""
+#~ "ä½ æ²¡æ使ç¨è¿ç»çåºçå°ç¹åºå·ã\n"
+#~ "\n"
+#~ "å¨ç®åçæ¬çSpringä¸ï¼ä½ ä¸è½è·³è¿ä»»ä½åºçå°ç¹ãä½ å¿
须使ç¨è¿ç»çåºçå°ç¹åº"
+#~ "å·ã\n"
+#~ "\n"
+#~ "举ä¾ï¼å¦æä½ æ两个AIåä½ èªå·±ï¼ä½ å¿
须使ç¨1ï¼2ï¼3èä¸æ¯1ï¼3ï¼4æ2ï¼3ï¼4ã\n"
+#~ "\n"
+#~ "è¿å°å¨ä¸ä¸ä¸ªçæ¬çSpringä¸è¢«ä¿®æ£ã"
+
+#~ msgid "Spring directory"
+#~ msgstr "Spring ç®å½"
+
+#~ msgid "Default location."
+#~ msgstr "é»è®¤ä½ç½®ã"
+
+#~ msgid "The Spring executable is installed in the default location"
+#~ msgstr "Spring æ§è¡æ件被å®è£
å¨é»è®¤ä½ç½®"
+
+#~ msgid "Specify the location of the Spring executable"
+#~ msgstr "èªå®ä¹Springæ§è¡æ件çä½ç½®"
+
+#~ msgid "The UnitSync library is installed in the default location"
+#~ msgstr "UnitSyncåºè¢«å®è£
å¨é»è®¤ä½ç½®"
+
+#~ msgid ""
+#~ "SpringLobby is unable to determine your Spring version from the UnitSync "
+#~ "library.\n"
+#~ "\n"
+#~ "You might want to take another look at your settings."
+#~ msgstr ""
+#~ "Spring大å
æ æ³ä»ä½ çUnitSyncåºå¤æä½ çSpringçæ¬ã\n"
+#~ "\n"
+#~ "ä½ å¯è½éè¦å次æ£æ¥ä½ ç设置ã"
+
+#~ msgid ""
+#~ "Unitsync loading was aborted because your spring data directory is not "
+#~ "writable. Please check."
+#~ msgstr "UnitSyncè½½å
¥è¢«ä¸æ¢ï¼å ä¸ºä½ çSpringæ°æ®ç®å½ä¸å¯åå
¥ã请æ£æ¥ã"
+
+#~ msgid "is not supported by the lobby server that requires version"
+#~ msgstr "ä¸è¢«éè¦æå®çæ¬ç大å
æå¡å¨ææ¯æ"
+
+#~ msgid ""
+#~ "This is the SpringLobby channel, please report any problems you are "
+#~ "having with SpringLobby here and the friendly developers will help you."
+#~ msgstr ""
+#~ "è¿æ¯SpringLobbyé¢éï¼å¦æä½ ä½¿ç¨Spring大å
éå°ä»»ä½é®é¢ï¼è¯·å¨è¿éæ¥åãåå"
+#~ "çå¼åè
们å°ä¼å¸®å©ä½ ã"
diff --git a/src/Helper/TextCompletionDatabase.cpp b/src/Helper/TextCompletionDatabase.cpp
new file mode 100644
index 0000000..b9ad6e0
--- /dev/null
+++ b/src/Helper/TextCompletionDatabase.cpp
@@ -0,0 +1,128 @@
+#include "TextCompletionDatabase.hpp"
+#include <wx/string.h>
+#include <wx/regex.h>
+
+//--------------------------------------------------------------------------------
+///
+/// Konstruktor
+///
+//--------------------------------------------------------------------------------
+TextCompletionDatabase::TextCompletionDatabase() {
+
+}
+
+//--------------------------------------------------------------------------------
+///
+/// Destruktor
+///
+//--------------------------------------------------------------------------------
+TextCompletionDatabase::~TextCompletionDatabase() {
+
+}
+
+//--------------------------------------------------------------------------------
+///
+/// Returns the current Count of Mapping in the TextCompletionDatabase.
+///
+/// \return
+/// The current Count of Mapping in the TextCompletionDatabase.
+///
+//--------------------------------------------------------------------------------
+unsigned int
+TextCompletionDatabase::Size() {
+
+ return hm.size();
+}
+
+//--------------------------------------------------------------------------------
+///
+/// Insert an Abbreviation and it's corresponding Mapping into the TextCompletionDatabase
+///
+/// \parem abbreviaton
+/// The Abbreviation to insert into the TextCompletionDatabase.
+///
+/// \parem mapping
+/// The Mapping of Abbreviation to insert into the TextCompletionDatabase.
+///
+//--------------------------------------------------------------------------------
+void
+TextCompletionDatabase::Insert_Mapping( const wxString& abbreviation, const wxString& mapping ) {
+
+ HashMap_String_String::iterator iter = hm.find( abbreviation );
+
+ if ( iter == hm.end() ) {
+ hm[abbreviation] = mapping;
+ }
+}
+
+//--------------------------------------------------------------------------------
+///
+/// Delete an Abbreviation and it's corresponding Mapping into the TextCompletionDatabase
+///
+/// \parem abbreviaton
+/// The Abbreviation to insert into the TextCompletionDatabase.
+///
+//--------------------------------------------------------------------------------
+void
+TextCompletionDatabase::Delete_Mapping( const wxString& abbreviation ) {
+
+ HashMap_String_String::iterator iter = hm.find( abbreviation );
+
+ if ( iter != hm.end() ) {
+ hm.erase( iter );
+ }
+}
+
+//--------------------------------------------------------------------------------
+///
+/// Get all Abbreviations, that match the provided Abbreviation. All matching Abbreviations and their corresponding Mapping are returned.
+///
+/// \parem abbreviaton
+/// The Abbreviation to search for matching Abbreviations already contained in the TextCompletionDatabase.
+///
+/// \return
+/// A HashMap containing all Matches.
+///
+//--------------------------------------------------------------------------------
+HashMap_String_String
+TextCompletionDatabase::GetMapping( wxString abbreviation ) {
+
+ HashMap_String_String hashmap;
+
+ // Search for all Abbreviations, containing the provided one.
+
+ // The Regex Container
+ wxRegEx regex_Abbreviations;
+
+ // We build the regular Expression:
+
+ // We need to escape all regular Expression Characters, that have a special Meaning
+ abbreviation.Replace( _T("["), _T("\\[") );
+ abbreviation.Replace( _T("]"), _T("\\]") );
+
+ wxString regex_Text;
+ regex_Text.append( abbreviation );
+ regex_Text.append( wxT( ".*" ) );
+
+ // We compile the regular Expression and if it's correct, we store it in the Regex Container
+ #ifdef wxHAS_REGEX_ADVANCED
+ regex_Abbreviations.Compile( regex_Text, wxRE_ADVANCED | wxRE_ICASE );
+ #else
+ regex_Abbreviations.Compile( regex_Text, wxRE_EXTENDED | wxRE_ICASE );
+ #endif
+
+
+ // Now we iterate over all stored Abbreviations and search for Abbreviations containing the provided Abbreviation
+
+ // std::cout << "Abbr: (" << abbreviation.char_str() << ")" << std::endl;
+
+ for ( HashMap_String_String::iterator iter = hm.begin() ; iter != hm.end() ; ++iter ) {
+ // std::cout << "iter->first: (" << iter->first.char_str() << ")" << std::endl;
+ if ( regex_Abbreviations.Matches( iter->first ) ) {
+ // std::cout << "Match found!" << std::endl;
+ hashmap[ iter->first ] = iter->second;
+ }
+ }
+
+ return hashmap;
+}
diff --git a/src/Helper/TextCompletionDatabase.hpp b/src/Helper/TextCompletionDatabase.hpp
new file mode 100644
index 0000000..a55479c
--- /dev/null
+++ b/src/Helper/TextCompletionDatabase.hpp
@@ -0,0 +1,33 @@
+#ifndef TEXTCOMPLETIONDATABASE_HPP
+#define TEXTCOMPLETIONDATABASE_HPP
+
+// wxWidgets
+#include <wx/hashmap.h>
+#include <wx/string.h>
+
+
+WX_DECLARE_STRING_HASH_MAP( wxString, HashMap_String_String );
+
+
+class TextCompletionDatabase {
+
+ private:
+ HashMap_String_String hm;
+
+ public:
+ TextCompletionDatabase();
+ virtual ~TextCompletionDatabase();
+
+ unsigned int Size();
+
+ void Insert_Mapping( const wxString& abbreviation, const wxString& mapping );
+ void Delete_Mapping( const wxString& abbreviation );
+ HashMap_String_String GetMapping( wxString text );
+
+
+
+ protected:
+
+};
+
+#endif // TEXTCOMPLETIONDATABASE_HPP
diff --git a/src/Helper/colorbutton.cpp b/src/Helper/colorbutton.cpp
new file mode 100644
index 0000000..6c67399
--- /dev/null
+++ b/src/Helper/colorbutton.cpp
@@ -0,0 +1,78 @@
+#include "colorbutton.h"
+
+#include "../uiutils.h"
+#include "../utils/controls.h"
+#include <wx/image.h>
+
+#ifdef __WXMSW__
+ #include "../images/colourbox.xpm"
+#endif
+
+
+ColorButton::ColorButton(wxWindow* parent, wxWindowID id, const wxBitmap& bitmap,
+ const wxPoint& pos , const wxSize& size , long style , const wxValidator& validator,
+ const wxString& name )
+ : wxBitmapButton( parent, id, bitmap, pos , size , style , validator, name ),
+ m_size(size), m_color()
+{
+ //ctor
+}
+
+ColorButton::ColorButton(wxWindow* parent, wxWindowID id, const wxColour& color,
+ const wxPoint& pos , const wxSize& size , long style , const wxValidator& validator,
+ const wxString& name )
+ : wxBitmapButton( parent, id, wxBitmap(), pos , size , style , validator, name ),
+ m_size(size),m_color(color)
+{
+ SetColor( color );
+}
+
+ColorButton::~ColorButton()
+{
+ //dtor
+}
+
+wxColour ColorButton::GetColor( )
+{
+ return m_color;
+}
+
+void ColorButton::SetColor( const wxColour& color )
+{
+ m_color = color;
+ SetBitmapLabel ( GetBitmapFromColor( color ) );
+
+ #ifdef __WXMSW__
+ SetBackgroundColour( GetDefaultAttributes().colBg );
+ #endif
+}
+
+wxBitmap ColorButton::GetBitmapFromColor( const wxColour& colour )
+{
+ #ifdef __WXMSW__
+ wxImage img( colourbox_xpm );
+
+ img.Replace( 1, 1, 1, colour.Red(), colour.Green(), colour.Blue() );
+
+ int r,g,b;
+ r = colour.Red()+80;
+ g = colour.Green()+80;
+ b = colour.Blue()+80;
+ img.Replace( 2, 2, 2, r>255?255:r, g>255?255:g, b>255?255:b );
+ return wxBitmap ( img );
+ #else
+ unsigned int h = m_size.GetHeight() > 0 ? m_size.GetHeight() : CONTROL_HEIGHT;
+ unsigned int w = m_size.GetWidth() > 0 ? m_size.GetWidth() : m_size.GetHeight();
+ wxImage img ( w, h, true );
+ unsigned char* data = img.GetData();
+ unsigned int pixels = w * h;
+
+ for (unsigned int i = 0; i < pixels*3; i+=3)
+ {
+ data[i] = colour.Red();
+ data[i+1] = colour.Green();
+ data[i+2] = colour.Blue();
+ }
+ return wxBitmap ( img );
+ #endif
+}
diff --git a/src/Helper/colorbutton.h b/src/Helper/colorbutton.h
new file mode 100644
index 0000000..435883d
--- /dev/null
+++ b/src/Helper/colorbutton.h
@@ -0,0 +1,44 @@
+#ifndef SL_HEADERGUARD_COLORBUTTON_H
+#define SL_HEADERGUARD_COLORBUTTON_H
+
+#include <wx/bmpbuttn.h>
+
+
+class ColorButton : public wxBitmapButton
+{
+ public:
+ ColorButton(wxWindow* parent, wxWindowID id, const wxBitmap& bitmap = wxBitmap(), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxBU_AUTODRAW,
+ const wxValidator& validator = wxDefaultValidator, const wxString& name = _T("button") );
+ ColorButton(wxWindow* parent, wxWindowID id, const wxColour& color, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxBU_AUTODRAW,
+ const wxValidator& validator = wxDefaultValidator, const wxString& name = _T("button") );
+ virtual ~ColorButton();
+
+ void SetColor( const wxColour& color );
+ wxColour GetColor( );
+
+ protected:
+ wxSize m_size;
+ wxColour m_color;
+ wxBitmap GetBitmapFromColor( const wxColour& color );
+
+};
+
+#endif // SL_HEADERGUARD_COLORBUTTON_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/Helper/imageviewer.cpp b/src/Helper/imageviewer.cpp
new file mode 100644
index 0000000..fea4c71
--- /dev/null
+++ b/src/Helper/imageviewer.cpp
@@ -0,0 +1,185 @@
+#include "imageviewer.h"
+
+#include <stdexcept>
+//#include <wx/intl.h>
+//#include <wx/imaglist.h>
+#include <wx/bitmap.h>
+#include <wx/sizer.h>
+//#include <wx/notebook.h>
+#include <wx/listctrl.h>
+#include <wx/image.h>
+#include <wx/scrolwin.h>
+#include <wx/dcclient.h>
+#include <wx/button.h>
+#include <wx/filedlg.h>
+
+#include "../settings++/custom_dialogs.h"
+#include "../uiutils.h"
+
+BEGIN_EVENT_TABLE( ImagePanel, wxPanel )
+ EVT_PAINT(ImagePanel::OnPaint)
+ EVT_SIZE( ImagePanel::OnSize)
+END_EVENT_TABLE()
+
+BEGIN_EVENT_TABLE( ImageViewerPanel, wxPanel )
+ EVT_BUTTON( ImageViewerPanel::ID_NEXT, ImageViewerPanel::OnNext )
+ EVT_BUTTON( ImageViewerPanel::ID_DELETE, ImageViewerPanel::OnDelete )
+ EVT_BUTTON( ImageViewerPanel::ID_PREV, ImageViewerPanel::OnPrev )
+ EVT_BUTTON( ImageViewerPanel::ID_SAVE_AS, ImageViewerPanel::OnSaveAs )
+END_EVENT_TABLE()
+
+ImagePanel::ImagePanel( const wxString& file, wxWindow* parent, wxWindowID id )
+ : wxPanel( parent, id ),
+ m_file( file )
+{}
+
+ImagePanel::ImagePanel( wxWindow* parent, wxWindowID id )
+ : wxPanel( parent, id )
+{}
+
+ImagePanel::~ImagePanel()
+{}
+
+void ImagePanel::SetBitmap( const wxString& file )
+{
+ m_file = file;
+ wxPaintEvent p;
+ OnPaint( p );
+}
+
+void ImagePanel::OnPaint(wxPaintEvent& WXUNUSED(event))
+{
+ wxPaintDC dc( this );
+ dc.Clear();
+
+ wxImage im;
+ if ( !im.LoadFile( m_file ) )
+ return;
+
+ wxSize c_sz = GetClientSize();
+ wxSize im_sz ( im.GetWidth(), im.GetHeight() );
+ im_sz = MakeFit( im_sz, c_sz );
+
+ dc.DrawBitmap( wxBitmap(im.Rescale( im_sz.GetWidth(), im_sz.GetHeight() ) ), 0, 0, true /* use mask */ );
+}
+void ImagePanel::OnSize(wxSizeEvent& WXUNUSED(event))
+{
+ wxPaintEvent p;
+ OnPaint( p );
+}
+
+ImageViewerPanel::ImageViewerPanel(const wxArrayString& filenames, bool enable_delete, wxWindow* parent,
+ wxWindowID id, long /*style*/ )
+ : wxPanel ( parent, id, wxDefaultPosition, wxDefaultSize ),
+ m_filenames( filenames ),
+ m_current_file_index( 0 ),
+ m_num_files( filenames.Count() ),
+ m_enable_delete( enable_delete ),
+ m_delete( 0 )
+{
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+ m_button_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_panel = new ImagePanel( this, -1 );
+ m_main_sizer->Add( m_panel, 1, wxEXPAND | wxALL, 0 );
+
+ m_prev = new wxButton( this, ID_PREV, _("previous") );
+ m_button_sizer->Add( m_prev, 0, wxALL, 5 );
+
+ m_next = new wxButton( this, ID_NEXT, _("next") );
+ m_button_sizer->Add( m_next, 0, wxALL, 5 );
+
+ if ( m_enable_delete ) {
+ m_delete = new wxButton( this, ID_DELETE, _("delete") );
+ m_button_sizer->Add( m_delete, 0, wxALL, 5 );
+ }
+
+ m_save_as = new wxButton( this, ID_SAVE_AS, _("save as") );
+ m_button_sizer->Add( m_save_as, 0, wxALL, 5 );
+
+ m_main_sizer->Add( m_button_sizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 0 );
+ SetSizer( m_main_sizer );
+
+ SetButtonStates();
+ SetImage();
+
+ Layout();
+ m_panel->Refresh();
+}
+
+ImageViewerPanel::~ImageViewerPanel()
+{
+}
+
+void ImageViewerPanel::SetButtonStates()
+{
+ m_next->Enable( m_current_file_index < m_num_files -1 );
+ m_prev->Enable( m_current_file_index > 0 );
+ if ( m_delete )
+ m_delete->Enable( m_num_files > 0 );
+ m_save_as->Enable( m_num_files > 0 );
+}
+
+void ImageViewerPanel::SetImage()
+{
+ SetButtonStates();
+ m_panel->SetBitmap( m_filenames[m_current_file_index] );
+// SetTitle( m_filenames[m_current_file_index] );
+}
+
+void ImageViewerPanel::OnNext( wxCommandEvent& /*evt*/ )
+{
+ m_current_file_index++;
+ SetImage();
+}
+
+void ImageViewerPanel::OnDelete( wxCommandEvent& /*evt*/ )
+{
+ wxString file = m_filenames[m_current_file_index];
+ if ( wxRemoveFile( file ) ) {
+ m_filenames.RemoveAt( m_current_file_index );
+ m_num_files--;
+ if ( m_current_file_index > m_num_files -1 )
+ m_current_file_index--;
+ SetImage();
+ }
+ else {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("couldn't remove file"), _("Error") );
+ }
+}
+
+void ImageViewerPanel::OnPrev( wxCommandEvent& /*evt*/ )
+{
+ m_current_file_index--;
+ SetImage();
+}
+
+void ImageViewerPanel::OnSaveAs( wxCommandEvent& /*evt*/ )
+{
+ wxString ext = m_filenames[m_current_file_index].AfterLast( '.' );
+ wxString mask = _T("*.") + ext;
+ wxFileDialog fd( this, _("Choose a filename"), _T(""), _T(""), mask, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
+ if ( fd.ShowModal() == wxID_OK ) {
+ wxString new_file = fd.GetPath();
+ if ( !new_file.EndsWith( ext ) )
+ new_file += _T(".") + ext;
+
+ if ( wxCopyFile( m_filenames[m_current_file_index], new_file ) ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("File successfully saved"), _("Success") );
+ }
+ else {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("Couldn't save file"), _("Error") );
+ }
+ }
+}
+
+ImageViewerDialog::ImageViewerDialog(const wxArrayString& filenames, bool enable_delete, wxWindow* parent, wxWindowID id,
+ const wxString& title, long style )
+ : wxDialog ( parent, id, title, wxDefaultPosition, wxDefaultSize, style)
+{
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+ long p_style = 0;
+ m_imageviewer_panel = new ImageViewerPanel( filenames, enable_delete, this, -1,p_style );
+ m_main_sizer->Add( m_imageviewer_panel, 1, wxEXPAND|wxALIGN_CENTER, 0 );
+ SetSizer( m_main_sizer );
+
+}
diff --git a/src/Helper/imageviewer.h b/src/Helper/imageviewer.h
new file mode 100644
index 0000000..005ea51
--- /dev/null
+++ b/src/Helper/imageviewer.h
@@ -0,0 +1,82 @@
+#ifndef SPRINGLOBBY_IMAGEVIEWER_H_INCLUDED
+#define SPRINGLOBBY_IMAGEVIEWER_H_INCLUDED
+
+#include <wx/dialog.h>
+#include <wx/panel.h>
+
+class wxPaintEvent;
+class SL_JPEGHandler;
+class wxPaintDC;
+
+class ImagePanel : public wxPanel
+{
+ public:
+ ImagePanel( const wxString& file, wxWindow* parent, wxWindowID id );
+ ImagePanel( wxWindow* parent, wxWindowID id );
+ virtual ~ImagePanel();
+ void SetBitmap( const wxString& file );
+
+ protected:
+ wxString m_file;
+// SL_JPEGHandler* m_jpeg_handler;
+
+ void OnPaint(wxPaintEvent& WXUNUSED(event));
+ void OnSize(wxSizeEvent& WXUNUSED(event));
+
+ DECLARE_EVENT_TABLE()
+};
+
+class wxBoxSizer;
+class wxButton;
+
+class ImageViewerPanel : public wxPanel
+{
+ public:
+ ImageViewerPanel(const wxArrayString& filenames, bool enable_delete, wxWindow* parent, wxWindowID id, long style );
+ virtual ~ImageViewerPanel();
+
+ protected:
+ wxArrayString m_filenames;
+ unsigned int m_current_file_index;
+ unsigned int m_num_files;
+ bool m_enable_delete;
+
+ wxBoxSizer* m_main_sizer;
+ wxBoxSizer* m_button_sizer;
+ wxButton* m_next;
+ wxButton* m_prev;
+ wxButton* m_delete;
+ wxButton* m_save_as;
+ ImagePanel* m_panel;
+
+ void OnNext( wxCommandEvent& evt );
+ void OnDelete( wxCommandEvent& evt );
+ void OnPrev( wxCommandEvent& evt );
+ void OnSaveAs( wxCommandEvent& evt );
+
+ void SetButtonStates();
+ void SetImage();
+
+ enum {
+ ID_DELETE,
+ ID_NEXT,
+ ID_PREV,
+ ID_SAVE_AS
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+class ImageViewerDialog : public wxDialog
+{
+ public:
+ ImageViewerDialog(const wxArrayString& filenames, bool enable_delete, wxWindow* parent, wxWindowID id, const wxString& title = _T(""),
+ long style = wxCAPTION | wxRESIZE_BORDER | wxCLOSE_BOX | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxDEFAULT_DIALOG_STYLE );
+ virtual ~ImageViewerDialog(){}
+
+ protected:
+ ImageViewerPanel* m_imageviewer_panel;
+ wxBoxSizer* m_main_sizer;
+};
+
+#endif // SPRINGLOBBY_IMAGEVIEWER_H_INCLUDED
diff --git a/src/Helper/listctrl.cpp b/src/Helper/listctrl.cpp
new file mode 100644
index 0000000..c863ce7
--- /dev/null
+++ b/src/Helper/listctrl.cpp
@@ -0,0 +1,5897 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: src/generic/listctrl.cpp
+// Purpose: generic implementation of wxListCtrl
+// Author: Robert Roebling
+// Vadim Zeitlin (virtual list control support)
+// Id: $Id: listctrl.cpp 8318 2008-04-01 18:41:23Z gonosztopi $
+// Copyright: (c) 1998 Robert Roebling
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// TODO
+//
+// 1. we need to implement searching/sorting for virtual controls somehow
+// 2. when changing selection the lines are refreshed twice
+
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#if wxUSE_LISTCTRL
+
+#include "listctrl.h"
+
+#ifndef WX_PRECOMP
+ #include <wx/scrolwin.h>
+ #include <wx/timer.h>
+ #include <wx/settings.h>
+ #include <wx/dynarray.h>
+ #include <wx/dcclient.h>
+ #include <wx/dcscreen.h>
+ #include <wx/math.h>
+#endif
+
+#include <wx/imaglist.h>
+#include <wx/selstore.h>
+#include <wx/renderer.h>
+#include <wx/dcbuffer.h>
+
+#ifdef __WXMAC__
+ #include <wx/mac/private.h>
+#endif
+
+
+// NOTE: If using the wxListBox visual attributes works everywhere then this can
+// be removed, as well as the #else case below.
+#define _USE_VISATTR 0
+
+namespace SL_Extern {
+
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// // the height of the header window (FIXME: should depend on its font!)
+// static const int HEADER_HEIGHT = 23;
+
+static const int SCROLL_UNIT_X = 15;
+
+// the spacing between the lines (in report mode)
+static const int LINE_SPACING = 0;
+
+// extra margins around the text label
+#ifdef __WXGTK__
+static const int EXTRA_WIDTH = 6;
+#else
+static const int EXTRA_WIDTH = 4;
+#endif
+static const int EXTRA_HEIGHT = 4;
+
+// margin between the window and the items
+static const int EXTRA_BORDER_X = 2;
+static const int EXTRA_BORDER_Y = 2;
+
+// offset for the header window
+static const int HEADER_OFFSET_X = 0;
+static const int HEADER_OFFSET_Y = 0;
+
+// margin between rows of icons in [small] icon view
+static const int MARGIN_BETWEEN_ROWS = 6;
+
+// when autosizing the columns, add some slack
+static const int AUTOSIZE_COL_MARGIN = 10;
+
+// default width for the header columns
+static const int WIDTH_COL_DEFAULT = 80;
+
+// the space between the image and the text in the report mode
+static const int IMAGE_MARGIN_IN_REPORT_MODE = 5;
+
+// the space between the image and the text in the report mode in header
+static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2;
+
+// ============================================================================
+// private classes
+// ============================================================================
+
+//-----------------------------------------------------------------------------
+// wxColWidthInfo (internal)
+//-----------------------------------------------------------------------------
+
+struct wxColWidthInfo
+{
+ int nMaxWidth;
+ bool bNeedsUpdate; // only set to true when an item whose
+ // width == nMaxWidth is removed
+
+ wxColWidthInfo(int w = 0, bool needsUpdate = false)
+ {
+ nMaxWidth = w;
+ bNeedsUpdate = needsUpdate;
+ }
+};
+
+WX_DEFINE_ARRAY_PTR(wxColWidthInfo *, ColWidthArray);
+
+//-----------------------------------------------------------------------------
+// wxListItemData (internal)
+//-----------------------------------------------------------------------------
+
+class wxListItemData
+{
+public:
+ wxListItemData(wxListMainWindow *owner);
+ ~wxListItemData();
+
+ void SetItem( const wxListItem &info );
+ void SetImage( int image ) { m_image = image; }
+ void SetData( wxUIntPtr data ) { m_data = data; }
+ void SetPosition( int x, int y );
+ void SetSize( int width, int height );
+
+ bool HasText() const { return !m_text.empty(); }
+ const wxString& GetText() const { return m_text; }
+ void SetText(const wxString& text) { m_text = text; }
+
+ // we can't use empty string for measuring the string width/height, so
+ // always return something
+ wxString GetTextForMeasuring() const
+ {
+ wxString s = GetText();
+ if ( s.empty() )
+ s = _T('H');
+
+ return s;
+ }
+
+ bool IsHit( int x, int y ) const;
+
+ int GetX() const;
+ int GetY() const;
+ int GetWidth() const;
+ int GetHeight() const;
+
+ int GetImage() const { return m_image; }
+ bool HasImage() const { return GetImage() != -1; }
+
+ void GetItem( wxListItem &info ) const;
+
+ void SetAttr(wxListItemAttr *attr) { m_attr = attr; }
+ wxListItemAttr *GetAttr() const { return m_attr; }
+
+public:
+ // the item image or -1
+ int m_image;
+
+ // user data associated with the item
+ wxUIntPtr m_data;
+
+ // the item coordinates are not used in report mode; instead this pointer is
+ // NULL and the owner window is used to retrieve the item position and size
+ wxRect *m_rect;
+
+ // the list ctrl we are in
+ wxListMainWindow *m_owner;
+
+ // custom attributes or NULL
+ wxListItemAttr *m_attr;
+
+protected:
+ // common part of all ctors
+ void Init();
+
+ wxString m_text;
+};
+
+//-----------------------------------------------------------------------------
+// wxListHeaderData (internal)
+//-----------------------------------------------------------------------------
+
+class wxListHeaderData : public wxObject
+{
+public:
+ wxListHeaderData();
+ wxListHeaderData( const wxListItem &info );
+ void SetItem( const wxListItem &item );
+ void SetPosition( int x, int y );
+ void SetWidth( int w );
+ void SetState( int state );
+ void SetFormat( int format );
+ void SetHeight( int h );
+ bool HasImage() const;
+
+ bool HasText() const { return !m_text.empty(); }
+ const wxString& GetText() const { return m_text; }
+ void SetText(const wxString& text) { m_text = text; }
+
+ void GetItem( wxListItem &item );
+
+ bool IsHit( int x, int y ) const;
+ int GetImage() const;
+ int GetWidth() const;
+ int GetFormat() const;
+ int GetState() const;
+
+protected:
+ long m_mask;
+ int m_image;
+ wxString m_text;
+ int m_format;
+ int m_width;
+ int m_xpos,
+ m_ypos;
+ int m_height;
+ int m_state;
+
+private:
+ void Init();
+};
+
+//-----------------------------------------------------------------------------
+// wxListLineData (internal)
+//-----------------------------------------------------------------------------
+
+WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxListItemDataList)
+
+class wxListLineData
+{
+public:
+ // the list of subitems: only may have more than one item in report mode
+ wxListItemDataList m_items;
+
+ // this is not used in report view
+ struct GeometryInfo
+ {
+ // total item rect
+ wxRect m_rectAll;
+
+ // label only
+ wxRect m_rectLabel;
+
+ // icon only
+ wxRect m_rectIcon;
+
+ // the part to be highlighted
+ wxRect m_rectHighlight;
+
+ // extend all our rects to be centered inside the one of given width
+ void ExtendWidth(wxCoord w)
+ {
+ wxASSERT_MSG( m_rectAll.width <= w,
+ _T("width can only be increased") );
+
+ m_rectAll.width = w;
+ m_rectLabel.x = m_rectAll.x + (w - m_rectLabel.width) / 2;
+ m_rectIcon.x = m_rectAll.x + (w - m_rectIcon.width) / 2;
+ m_rectHighlight.x = m_rectAll.x + (w - m_rectHighlight.width) / 2;
+ }
+ }
+ *m_gi;
+
+ // is this item selected? [NB: not used in virtual mode]
+ bool m_highlighted;
+
+ // back pointer to the list ctrl
+ wxListMainWindow *m_owner;
+
+public:
+ wxListLineData(wxListMainWindow *owner);
+
+ ~wxListLineData()
+ {
+ WX_CLEAR_LIST(wxListItemDataList, m_items);
+ delete m_gi;
+ }
+
+ // are we in report mode?
+ inline bool InReportView() const;
+
+ // are we in virtual report mode?
+ inline bool IsVirtual() const;
+
+ // these 2 methods shouldn't be called for report view controls, in that
+ // case we determine our position/size ourselves
+
+ // calculate the size of the line
+ void CalculateSize( wxDC *dc, int spacing );
+
+ // remember the position this line appears at
+ void SetPosition( int x, int y, int spacing );
+
+ // wxListCtrl API
+
+ void SetImage( int image ) { SetImage(0, image); }
+ int GetImage() const { return GetImage(0); }
+ void SetImage( int index, int image );
+ int GetImage( int index ) const;
+
+ bool HasImage() const { return GetImage() != -1; }
+ bool HasText() const { return !GetText(0).empty(); }
+
+ void SetItem( int index, const wxListItem &info );
+ void GetItem( int index, wxListItem &info );
+
+ wxString GetText(int index) const;
+ void SetText( int index, const wxString& s );
+
+ wxListItemAttr *GetAttr() const;
+ void SetAttr(wxListItemAttr *attr);
+
+ // return true if the highlighting really changed
+ bool Highlight( bool on );
+
+ void ReverseHighlight();
+
+ bool IsHighlighted() const
+ {
+ wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
+
+ return m_highlighted;
+ }
+
+ // draw the line on the given DC in icon/list mode
+ void Draw( wxDC *dc );
+
+ // the same in report mode
+ void DrawInReportMode( wxDC *dc,
+ const wxRect& rect,
+ const wxRect& rectHL,
+ bool highlighted );
+
+private:
+ // set the line to contain num items (only can be > 1 in report mode)
+ void InitItems( int num );
+
+ // get the mode (i.e. style) of the list control
+ inline int GetMode() const;
+
+ // prepare the DC for drawing with these item's attributes, return true if
+ // we need to draw the items background to highlight it, false otherwise
+ bool SetAttributes(wxDC *dc,
+ const wxListItemAttr *attr,
+ bool highlight);
+
+ // draw the text on the DC with the correct justification; also add an
+ // ellipsis if the text is too large to fit in the current width
+ void DrawTextFormatted(wxDC *dc,
+ const wxString &text,
+ int col,
+ int x,
+ int yMid, // this is middle, not top, of the text
+ int width);
+};
+
+WX_DECLARE_OBJARRAY(wxListLineData, wxListLineDataArray);
+#include <wx/arrimpl.cpp>
+WX_DEFINE_OBJARRAY(wxListLineDataArray)
+
+//-----------------------------------------------------------------------------
+// wxListHeaderWindow (internal)
+//-----------------------------------------------------------------------------
+
+class wxListHeaderWindow : public wxWindow
+{
+protected:
+ wxListMainWindow *m_owner;
+ const wxCursor *m_currentCursor;
+ wxCursor *m_resizeCursor;
+ bool m_isDragging;
+
+ // column being resized or -1
+ int m_column;
+
+ // divider line position in logical (unscrolled) coords
+ int m_currentX;
+
+ // minimal position beyond which the divider line
+ // can't be dragged in logical coords
+ int m_minX;
+
+public:
+ wxListHeaderWindow();
+
+ wxListHeaderWindow( wxWindow *win,
+ wxWindowID id,
+ wxListMainWindow *owner,
+ const wxPoint &pos = wxDefaultPosition,
+ const wxSize &size = wxDefaultSize,
+ long style = 0,
+ const wxString &name = wxT("wxlistctrlcolumntitles") );
+
+ virtual ~wxListHeaderWindow();
+
+ void DrawCurrent();
+ void AdjustDC( wxDC& dc );
+
+ void OnPaint( wxPaintEvent &event );
+ void OnMouse( wxMouseEvent &event );
+ void OnSetFocus( wxFocusEvent &event );
+
+ // needs refresh
+ bool m_dirty;
+
+private:
+ // common part of all ctors
+ void Init();
+
+ // generate and process the list event of the given type, return true if
+ // it wasn't vetoed, i.e. if we should proceed
+ bool SendListEvent(wxEventType type, const wxPoint& pos);
+
+// DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
+ DECLARE_EVENT_TABLE()
+};
+
+//-----------------------------------------------------------------------------
+// wxListRenameTimer (internal)
+//-----------------------------------------------------------------------------
+
+class wxListRenameTimer: public wxTimer
+{
+private:
+ wxListMainWindow *m_owner;
+
+public:
+ wxListRenameTimer( wxListMainWindow *owner );
+ void Notify();
+};
+
+//-----------------------------------------------------------------------------
+// wxListTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing
+//-----------------------------------------------------------------------------
+
+class wxListTextCtrlWrapper : public wxEvtHandler
+{
+public:
+ // NB: text must be a valid object but not Create()d yet
+ wxListTextCtrlWrapper(wxListMainWindow *owner,
+ wxTextCtrl *text,
+ size_t itemEdit);
+
+ wxTextCtrl *GetText() const { return m_text; }
+
+ void AcceptChangesAndFinish();
+
+protected:
+ void OnChar( wxKeyEvent &event );
+ void OnKeyUp( wxKeyEvent &event );
+ void OnKillFocus( wxFocusEvent &event );
+
+ bool AcceptChanges();
+ void Finish();
+
+private:
+ wxListMainWindow *m_owner;
+ wxTextCtrl *m_text;
+ wxString m_startValue;
+ size_t m_itemEdited;
+ bool m_finished;
+ bool m_aboutToFinish;
+
+ DECLARE_EVENT_TABLE()
+};
+
+//-----------------------------------------------------------------------------
+// wxListMainWindow (internal)
+//-----------------------------------------------------------------------------
+
+WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxListHeaderDataList)
+
+class wxListMainWindow : public wxScrolledWindow
+{
+public:
+ wxListMainWindow();
+ wxListMainWindow( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString &name = _T("listctrlmainwindow") );
+
+ virtual ~wxListMainWindow();
+
+ bool HasFlag(int flag) const { return m_parent->HasFlag(flag); }
+
+ // return true if this is a virtual list control
+ bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); }
+
+ // return true if the control is in report mode
+ bool InReportView() const { return HasFlag(wxLC_REPORT); }
+
+ // return true if we are in single selection mode, false if multi sel
+ bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); }
+
+ // do we have a header window?
+ bool HasHeader() const
+ { return InReportView() && !HasFlag(wxLC_NO_HEADER); }
+
+ void HighlightAll( bool on );
+
+ // all these functions only do something if the line is currently visible
+
+ // change the line "selected" state, return true if it really changed
+ bool HighlightLine( size_t line, bool highlight = true);
+
+ // as HighlightLine() but do it for the range of lines: this is incredibly
+ // more efficient for virtual list controls!
+ //
+ // NB: unlike HighlightLine() this one does refresh the lines on screen
+ void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true );
+
+ // toggle the line state and refresh it
+ void ReverseHighlight( size_t line )
+ { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); }
+
+ // return true if the line is highlighted
+ bool IsHighlighted(size_t line) const;
+
+ // refresh one or several lines at once
+ void RefreshLine( size_t line );
+ void RefreshLines( size_t lineFrom, size_t lineTo );
+
+ // refresh all selected items
+ void RefreshSelected();
+
+ // refresh all lines below the given one: the difference with
+ // RefreshLines() is that the index here might not be a valid one (happens
+ // when the last line is deleted)
+ void RefreshAfter( size_t lineFrom );
+
+ // the methods which are forwarded to wxListLineData itself in list/icon
+ // modes but are here because the lines don't store their positions in the
+ // report mode
+
+ // get the bound rect for the entire line
+ wxRect GetLineRect(size_t line) const;
+
+ // get the bound rect of the label
+ wxRect GetLineLabelRect(size_t line) const;
+
+ // get the bound rect of the items icon (only may be called if we do have
+ // an icon!)
+ wxRect GetLineIconRect(size_t line) const;
+
+ // get the rect to be highlighted when the item has focus
+ wxRect GetLineHighlightRect(size_t line) const;
+
+ // get the size of the total line rect
+ wxSize GetLineSize(size_t line) const
+ { return GetLineRect(line).GetSize(); }
+
+ // return the hit code for the corresponding position (in this line)
+ long HitTestLine(size_t line, int x, int y) const;
+
+ // bring the selected item into view, scrolling to it if necessary
+ void MoveToItem(size_t item);
+
+ // bring the current item into view
+ void MoveToFocus() { MoveToItem(m_current); }
+
+ // start editing the label of the given item
+ wxTextCtrl *EditLabel(long item,
+ wxClassInfo* textControlClass = CLASSINFO(wxTextCtrl));
+ wxTextCtrl *GetEditControl() const
+ {
+ return m_textctrlWrapper ? m_textctrlWrapper->GetText() : NULL;
+ }
+
+ void FinishEditing(wxTextCtrl *text)
+ {
+ delete text;
+ m_textctrlWrapper = NULL;
+ SetFocusIgnoringChildren();
+ }
+
+ // suspend/resume redrawing the control
+ void Freeze();
+ void Thaw();
+
+ void OnRenameTimer();
+ bool OnRenameAccept(size_t itemEdit, const wxString& value);
+ void OnRenameCancelled(size_t itemEdit);
+
+ void OnMouse( wxMouseEvent &event );
+
+ // called to switch the selection from the current item to newCurrent,
+ void OnArrowChar( size_t newCurrent, const wxKeyEvent& event );
+
+ void OnChar( wxKeyEvent &event );
+ void OnKeyDown( wxKeyEvent &event );
+ void OnKeyUp( wxKeyEvent &event );
+ void OnSetFocus( wxFocusEvent &event );
+ void OnKillFocus( wxFocusEvent &event );
+ void OnScroll( wxScrollWinEvent& event );
+
+ void OnPaint( wxPaintEvent &event );
+
+ void DrawImage( int index, wxDC *dc, int x, int y );
+ void GetImageSize( int index, int &width, int &height ) const;
+ int GetTextLength( const wxString &s ) const;
+
+ void SetImageList( wxImageList *imageList, int which );
+ void SetItemSpacing( int spacing, bool isSmall = false );
+ int GetItemSpacing( bool isSmall = false );
+
+ void SetColumn( int col, wxListItem &item );
+ void SetColumnWidth( int col, int width );
+ void GetColumn( int col, wxListItem &item ) const;
+ int GetColumnWidth( int col ) const;
+ int GetColumnCount() const { return m_columns.GetCount(); }
+
+ // returns the sum of the heights of all columns
+ int GetHeaderWidth() const;
+
+ int GetCountPerPage() const;
+
+ void SetItem( wxListItem &item );
+ void GetItem( wxListItem &item ) const;
+ void SetItemState( long item, long state, long stateMask );
+ void SetItemStateAll( long state, long stateMask );
+ int GetItemState( long item, long stateMask ) const;
+ void GetItemRect( long index, wxRect &rect ) const;
+ wxRect GetViewRect() const;
+ bool GetItemPosition( long item, wxPoint& pos ) const;
+ int GetSelectedItemCount() const;
+
+ wxString GetItemText(long item) const
+ {
+ wxListItem info;
+ info.m_mask = wxLIST_MASK_TEXT;
+ info.m_itemId = item;
+ GetItem( info );
+ return info.m_text;
+ }
+
+ void SetItemText(long item, const wxString& value)
+ {
+ wxListItem info;
+ info.m_mask = wxLIST_MASK_TEXT;
+ info.m_itemId = item;
+ info.m_text = value;
+ SetItem( info );
+ }
+
+ // set the scrollbars and update the positions of the items
+ void RecalculatePositions(bool noRefresh = false);
+
+ // refresh the window and the header
+ void RefreshAll();
+
+ long GetNextItem( long item, int geometry, int state ) const;
+ void DeleteItem( long index );
+ void DeleteAllItems();
+ void DeleteColumn( int col );
+ void DeleteEverything();
+ void EnsureVisible( long index );
+ long FindItem( long start, const wxString& str, bool partial = false );
+ long FindItem( long start, wxUIntPtr data);
+ long FindItem( const wxPoint& pt );
+ long HitTest( int x, int y, int &flags ) const;
+ void InsertItem( wxListItem &item );
+ void InsertColumn( long col, wxListItem &item );
+ int GetItemWidthWithImage(wxListItem * item);
+ void SortItems( wxListCtrlCompare fn, long data );
+
+ size_t GetItemCount() const;
+ bool IsEmpty() const { return GetItemCount() == 0; }
+ void SetItemCount(long count);
+
+ // change the current (== focused) item, send a notification event
+ void ChangeCurrent(size_t current);
+ void ResetCurrent() { ChangeCurrent((size_t)-1); }
+ bool HasCurrent() const { return m_current != (size_t)-1; }
+
+ // send out a wxListEvent
+ void SendNotify( size_t line,
+ wxEventType command,
+ const wxPoint& point = wxDefaultPosition );
+
+ // override base class virtual to reset m_lineHeight when the font changes
+ virtual bool SetFont(const wxFont& font)
+ {
+ if ( !wxScrolledWindow::SetFont(font) )
+ return false;
+
+ m_lineHeight = 0;
+
+ return true;
+ }
+
+ // these are for wxListLineData usage only
+
+ // get the backpointer to the list ctrl
+ wxGenericListCtrl *GetListCtrl() const
+ {
+ return wxStaticCast(GetParent(), wxGenericListCtrl);
+ }
+
+ // get the height of all lines (assuming they all do have the same height)
+ wxCoord GetLineHeight() const;
+
+ // get the y position of the given line (only for report view)
+ wxCoord GetLineY(size_t line) const;
+
+ // get the brush to use for the item highlighting
+ wxBrush *GetHighlightBrush() const
+ {
+ return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush;
+ }
+
+ bool HasFocus() const
+ {
+ return m_hasFocus;
+ }
+
+//protected:
+ // the array of all line objects for a non virtual list control (for the
+ // virtual list control we only ever use m_lines[0])
+ wxListLineDataArray m_lines;
+
+ // the list of column objects
+ wxListHeaderDataList m_columns;
+
+ // currently focused item or -1
+ size_t m_current;
+
+ // the number of lines per page
+ int m_linesPerPage;
+
+ // this flag is set when something which should result in the window
+ // redrawing happens (i.e. an item was added or deleted, or its appearance
+ // changed) and OnPaint() doesn't redraw the window while it is set which
+ // allows to minimize the number of repaintings when a lot of items are
+ // being added. The real repainting occurs only after the next OnIdle()
+ // call
+ bool m_dirty;
+
+ wxColour *m_highlightColour;
+ wxImageList *m_small_image_list;
+ wxImageList *m_normal_image_list;
+ int m_small_spacing;
+ int m_normal_spacing;
+ bool m_hasFocus;
+
+ bool m_lastOnSame;
+ wxTimer *m_renameTimer;
+ bool m_isCreated;
+ int m_dragCount;
+ wxPoint m_dragStart;
+ ColWidthArray m_aColWidths;
+
+ // for double click logic
+ size_t m_lineLastClicked,
+ m_lineBeforeLastClicked,
+ m_lineSelectSingleOnUp;
+
+protected:
+ wxWindow *GetMainWindowOfCompositeControl() { return GetParent(); }
+
+ // the total count of items in a virtual list control
+ size_t m_countVirt;
+
+ // the object maintaining the items selection state, only used in virtual
+ // controls
+ wxSelectionStore m_selStore;
+
+ // common part of all ctors
+ void Init();
+
+ // get the line data for the given index
+ wxListLineData *GetLine(size_t n) const
+ {
+ wxASSERT_MSG( n != (size_t)-1, _T("invalid line index") );
+
+ if ( IsVirtual() )
+ {
+ wxConstCast(this, wxListMainWindow)->CacheLineData(n);
+ n = 0;
+ }
+
+ return &m_lines[n];
+ }
+
+ // get a dummy line which can be used for geometry calculations and such:
+ // you must use GetLine() if you want to really draw the line
+ wxListLineData *GetDummyLine() const;
+
+ // cache the line data of the n-th line in m_lines[0]
+ void CacheLineData(size_t line);
+
+ // get the range of visible lines
+ void GetVisibleLinesRange(size_t *from, size_t *to);
+
+ // force us to recalculate the range of visible lines
+ void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; }
+
+ // get the colour to be used for drawing the rules
+ wxColour GetRuleColour() const
+ {
+ return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
+ }
+
+private:
+ // initialize the current item if needed
+ void UpdateCurrent();
+
+ // delete all items but don't refresh: called from dtor
+ void DoDeleteAllItems();
+
+ // the height of one line using the current font
+ wxCoord m_lineHeight;
+
+ // the total header width or 0 if not calculated yet
+ wxCoord m_headerWidth;
+
+ // the first and last lines being shown on screen right now (inclusive),
+ // both may be -1 if they must be calculated so never access them directly:
+ // use GetVisibleLinesRange() above instead
+ size_t m_lineFrom,
+ m_lineTo;
+
+ // the brushes to use for item highlighting when we do/don't have focus
+ wxBrush *m_highlightBrush,
+ *m_highlightUnfocusedBrush;
+
+ // if this is > 0, the control is frozen and doesn't redraw itself
+ size_t m_freezeCount;
+
+ // wrapper around the text control currently used for in place editing or
+ // NULL if no item is being edited
+ wxListTextCtrlWrapper *m_textctrlWrapper;
+
+
+ //DECLARE_DYNAMIC_CLASS(wxListMainWindow)
+ DECLARE_EVENT_TABLE()
+
+ friend class wxGenericListCtrl;
+};
+
+
+wxListItemData::~wxListItemData()
+{
+ // in the virtual list control the attributes are managed by the main
+ // program, so don't delete them
+ if ( !m_owner->IsVirtual() )
+ delete m_attr;
+
+ delete m_rect;
+}
+
+void wxListItemData::Init()
+{
+ m_image = -1;
+ m_data = 0;
+
+ m_attr = NULL;
+}
+
+wxListItemData::wxListItemData(wxListMainWindow *owner)
+{
+ Init();
+
+ m_owner = owner;
+
+ if ( owner->InReportView() )
+ m_rect = NULL;
+ else
+ m_rect = new wxRect;
+}
+
+void wxListItemData::SetItem( const wxListItem &info )
+{
+ if ( info.m_mask & wxLIST_MASK_TEXT )
+ SetText(info.m_text);
+ if ( info.m_mask & wxLIST_MASK_IMAGE )
+ m_image = info.m_image;
+ if ( info.m_mask & wxLIST_MASK_DATA )
+ m_data = info.m_data;
+
+ if ( info.HasAttributes() )
+ {
+ if ( m_attr )
+ m_attr->AssignFrom(*info.GetAttributes());
+ else
+ m_attr = new wxListItemAttr(*info.GetAttributes());
+ }
+
+ if ( m_rect )
+ {
+ m_rect->x =
+ m_rect->y =
+ m_rect->height = 0;
+ m_rect->width = info.m_width;
+ }
+}
+
+void wxListItemData::SetPosition( int x, int y )
+{
+ wxCHECK_RET( m_rect, _T("unexpected SetPosition() call") );
+
+ m_rect->x = x;
+ m_rect->y = y;
+}
+
+void wxListItemData::SetSize( int width, int height )
+{
+ wxCHECK_RET( m_rect, _T("unexpected SetSize() call") );
+
+ if ( width != -1 )
+ m_rect->width = width;
+ if ( height != -1 )
+ m_rect->height = height;
+}
+
+bool wxListItemData::IsHit( int x, int y ) const
+{
+ wxCHECK_MSG( m_rect, false, _T("can't be called in this mode") );
+
+ return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x, y);
+}
+
+int wxListItemData::GetX() const
+{
+ wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
+
+ return m_rect->x;
+}
+
+int wxListItemData::GetY() const
+{
+ wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
+
+ return m_rect->y;
+}
+
+int wxListItemData::GetWidth() const
+{
+ wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
+
+ return m_rect->width;
+}
+
+int wxListItemData::GetHeight() const
+{
+ wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
+
+ return m_rect->height;
+}
+
+void wxListItemData::GetItem( wxListItem &info ) const
+{
+ long mask = info.m_mask;
+ if ( !mask )
+ // by default, get everything for backwards compatibility
+ mask = -1;
+
+ if ( mask & wxLIST_MASK_TEXT )
+ info.m_text = m_text;
+ if ( mask & wxLIST_MASK_IMAGE )
+ info.m_image = m_image;
+ if ( mask & wxLIST_MASK_DATA )
+ info.m_data = m_data;
+
+ if ( m_attr )
+ {
+ if ( m_attr->HasTextColour() )
+ info.SetTextColour(m_attr->GetTextColour());
+ if ( m_attr->HasBackgroundColour() )
+ info.SetBackgroundColour(m_attr->GetBackgroundColour());
+ if ( m_attr->HasFont() )
+ info.SetFont(m_attr->GetFont());
+ }
+}
+
+//-----------------------------------------------------------------------------
+// wxListHeaderData
+//-----------------------------------------------------------------------------
+
+void wxListHeaderData::Init()
+{
+ m_mask = 0;
+ m_image = -1;
+ m_format = 0;
+ m_width = 0;
+ m_xpos = 0;
+ m_ypos = 0;
+ m_height = 0;
+ m_state = 0;
+}
+
+wxListHeaderData::wxListHeaderData()
+{
+ Init();
+}
+
+wxListHeaderData::wxListHeaderData( const wxListItem &item )
+{
+ Init();
+
+ SetItem( item );
+}
+
+void wxListHeaderData::SetItem( const wxListItem &item )
+{
+ m_mask = item.m_mask;
+
+ if ( m_mask & wxLIST_MASK_TEXT )
+ m_text = item.m_text;
+
+ if ( m_mask & wxLIST_MASK_IMAGE )
+ m_image = item.m_image;
+
+ if ( m_mask & wxLIST_MASK_FORMAT )
+ m_format = item.m_format;
+
+ if ( m_mask & wxLIST_MASK_WIDTH )
+ SetWidth(item.m_width);
+
+ if ( m_mask & wxLIST_MASK_STATE )
+ SetState(item.m_state);
+}
+
+void wxListHeaderData::SetPosition( int x, int y )
+{
+ m_xpos = x;
+ m_ypos = y;
+}
+
+void wxListHeaderData::SetHeight( int h )
+{
+ m_height = h;
+}
+
+void wxListHeaderData::SetWidth( int w )
+{
+ m_width = w < 0 ? WIDTH_COL_DEFAULT : w;
+}
+
+void wxListHeaderData::SetState( int flag )
+{
+ m_state = flag;
+}
+
+void wxListHeaderData::SetFormat( int format )
+{
+ m_format = format;
+}
+
+bool wxListHeaderData::HasImage() const
+{
+ return m_image != -1;
+}
+
+bool wxListHeaderData::IsHit( int x, int y ) const
+{
+ return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height));
+}
+
+void wxListHeaderData::GetItem( wxListItem& item )
+{
+ item.m_mask = m_mask;
+ item.m_text = m_text;
+ item.m_image = m_image;
+ item.m_format = m_format;
+ item.m_width = m_width;
+ item.m_state = m_state;
+}
+
+int wxListHeaderData::GetImage() const
+{
+ return m_image;
+}
+
+int wxListHeaderData::GetWidth() const
+{
+ return m_width;
+}
+
+int wxListHeaderData::GetFormat() const
+{
+ return m_format;
+}
+
+int wxListHeaderData::GetState() const
+{
+ return m_state;
+}
+
+//-----------------------------------------------------------------------------
+// wxListLineData
+//-----------------------------------------------------------------------------
+
+inline int wxListLineData::GetMode() const
+{
+ return m_owner->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE;
+}
+
+inline bool wxListLineData::InReportView() const
+{
+ return m_owner->HasFlag(wxLC_REPORT);
+}
+
+inline bool wxListLineData::IsVirtual() const
+{
+ return m_owner->IsVirtual();
+}
+
+wxListLineData::wxListLineData( wxListMainWindow *owner )
+{
+ m_owner = owner;
+
+ if ( InReportView() )
+ m_gi = NULL;
+ else // !report
+ m_gi = new GeometryInfo;
+
+ m_highlighted = false;
+
+ InitItems( GetMode() == wxLC_REPORT ? m_owner->GetColumnCount() : 1 );
+}
+
+void wxListLineData::CalculateSize( wxDC *dc, int spacing )
+{
+ wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
+ wxCHECK_RET( node, _T("no subitems at all??") );
+
+ wxListItemData *item = node->GetData();
+
+ wxString s;
+ wxCoord lw, lh;
+
+ switch ( GetMode() )
+ {
+ case wxLC_ICON:
+ case wxLC_SMALL_ICON:
+ m_gi->m_rectAll.width = spacing;
+
+ s = item->GetText();
+
+ if ( s.empty() )
+ {
+ lh =
+ m_gi->m_rectLabel.width =
+ m_gi->m_rectLabel.height = 0;
+ }
+ else // has label
+ {
+ dc->GetTextExtent( s, &lw, &lh );
+ lw += EXTRA_WIDTH;
+ lh += EXTRA_HEIGHT;
+
+ m_gi->m_rectAll.height = spacing + lh;
+ if (lw > spacing)
+ m_gi->m_rectAll.width = lw;
+
+ m_gi->m_rectLabel.width = lw;
+ m_gi->m_rectLabel.height = lh;
+ }
+
+ if (item->HasImage())
+ {
+ int w, h;
+ m_owner->GetImageSize( item->GetImage(), w, h );
+ m_gi->m_rectIcon.width = w + 8;
+ m_gi->m_rectIcon.height = h + 8;
+
+ if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
+ m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
+ if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
+ m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
+ }
+
+ if ( item->HasText() )
+ {
+ m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
+ m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
+ }
+ else // no text, highlight the icon
+ {
+ m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
+ m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
+ }
+ break;
+
+ case wxLC_LIST:
+ s = item->GetTextForMeasuring();
+
+ dc->GetTextExtent( s, &lw, &lh );
+ lw += EXTRA_WIDTH;
+ lh += EXTRA_HEIGHT;
+
+ m_gi->m_rectLabel.width = lw;
+ m_gi->m_rectLabel.height = lh;
+
+ m_gi->m_rectAll.width = lw;
+ m_gi->m_rectAll.height = lh;
+
+ if (item->HasImage())
+ {
+ int w, h;
+ m_owner->GetImageSize( item->GetImage(), w, h );
+ m_gi->m_rectIcon.width = w;
+ m_gi->m_rectIcon.height = h;
+
+ m_gi->m_rectAll.width += 4 + w;
+ if (h > m_gi->m_rectAll.height)
+ m_gi->m_rectAll.height = h;
+ }
+
+ m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
+ m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
+ break;
+
+ case wxLC_REPORT:
+ wxFAIL_MSG( _T("unexpected call to SetSize") );
+ break;
+
+ default:
+ wxFAIL_MSG( _T("unknown mode") );
+ break;
+ }
+}
+
+void wxListLineData::SetPosition( int x, int y, int spacing )
+{
+ wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
+ wxCHECK_RET( node, _T("no subitems at all??") );
+
+ wxListItemData *item = node->GetData();
+
+ switch ( GetMode() )
+ {
+ case wxLC_ICON:
+ case wxLC_SMALL_ICON:
+ m_gi->m_rectAll.x = x;
+ m_gi->m_rectAll.y = y;
+
+ if ( item->HasImage() )
+ {
+ m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4 +
+ (m_gi->m_rectAll.width - m_gi->m_rectIcon.width) / 2;
+ m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4;
+ }
+
+ if ( item->HasText() )
+ {
+ if (m_gi->m_rectAll.width > spacing)
+ m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2);
+ else
+ m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2) + (spacing / 2) - (m_gi->m_rectLabel.width / 2);
+ m_gi->m_rectLabel.y = m_gi->m_rectAll.y + m_gi->m_rectAll.height + 2 - m_gi->m_rectLabel.height;
+ m_gi->m_rectHighlight.x = m_gi->m_rectLabel.x - 2;
+ m_gi->m_rectHighlight.y = m_gi->m_rectLabel.y - 2;
+ }
+ else // no text, highlight the icon
+ {
+ m_gi->m_rectHighlight.x = m_gi->m_rectIcon.x - 4;
+ m_gi->m_rectHighlight.y = m_gi->m_rectIcon.y - 4;
+ }
+ break;
+
+ case wxLC_LIST:
+ m_gi->m_rectAll.x = x;
+ m_gi->m_rectAll.y = y;
+
+ m_gi->m_rectHighlight.x = m_gi->m_rectAll.x;
+ m_gi->m_rectHighlight.y = m_gi->m_rectAll.y;
+ m_gi->m_rectLabel.y = m_gi->m_rectAll.y + 2;
+
+ if (item->HasImage())
+ {
+ m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 2;
+ m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 2;
+ m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 4 + (EXTRA_WIDTH/2) + m_gi->m_rectIcon.width;
+ }
+ else
+ {
+ m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2);
+ }
+ break;
+
+ case wxLC_REPORT:
+ wxFAIL_MSG( _T("unexpected call to SetPosition") );
+ break;
+
+ default:
+ wxFAIL_MSG( _T("unknown mode") );
+ break;
+ }
+}
+
+void wxListLineData::InitItems( int num )
+{
+ for (int i = 0; i < num; i++)
+ m_items.Append( new wxListItemData(m_owner) );
+}
+
+void wxListLineData::SetItem( int index, const wxListItem &info )
+{
+ wxListItemDataList::compatibility_iterator node = m_items.Item( index );
+ wxCHECK_RET( node, _T("invalid column index in SetItem") );
+
+ wxListItemData *item = node->GetData();
+ item->SetItem( info );
+}
+
+void wxListLineData::GetItem( int index, wxListItem &info )
+{
+ wxListItemDataList::compatibility_iterator node = m_items.Item( index );
+ if (node)
+ {
+ wxListItemData *item = node->GetData();
+ item->GetItem( info );
+ }
+}
+
+wxString wxListLineData::GetText(int index) const
+{
+ wxString s;
+
+ wxListItemDataList::compatibility_iterator node = m_items.Item( index );
+ if (node)
+ {
+ wxListItemData *item = node->GetData();
+ s = item->GetText();
+ }
+
+ return s;
+}
+
+void wxListLineData::SetText( int index, const wxString& s )
+{
+ wxListItemDataList::compatibility_iterator node = m_items.Item( index );
+ if (node)
+ {
+ wxListItemData *item = node->GetData();
+ item->SetText( s );
+ }
+}
+
+void wxListLineData::SetImage( int index, int image )
+{
+ wxListItemDataList::compatibility_iterator node = m_items.Item( index );
+ wxCHECK_RET( node, _T("invalid column index in SetImage()") );
+
+ wxListItemData *item = node->GetData();
+ item->SetImage(image);
+}
+
+int wxListLineData::GetImage( int index ) const
+{
+ wxListItemDataList::compatibility_iterator node = m_items.Item( index );
+ wxCHECK_MSG( node, -1, _T("invalid column index in GetImage()") );
+
+ wxListItemData *item = node->GetData();
+ return item->GetImage();
+}
+
+wxListItemAttr *wxListLineData::GetAttr() const
+{
+ wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
+ wxCHECK_MSG( node, NULL, _T("invalid column index in GetAttr()") );
+
+ wxListItemData *item = node->GetData();
+ return item->GetAttr();
+}
+
+void wxListLineData::SetAttr(wxListItemAttr *attr)
+{
+ wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
+ wxCHECK_RET( node, _T("invalid column index in SetAttr()") );
+
+ wxListItemData *item = node->GetData();
+ item->SetAttr(attr);
+}
+
+bool wxListLineData::SetAttributes(wxDC *dc,
+ const wxListItemAttr *attr,
+ bool highlighted)
+{
+ wxWindow *listctrl = m_owner->GetParent();
+
+ // fg colour
+
+ // don't use foreground colour for drawing highlighted items - this might
+ // make them completely invisible (and there is no way to do bit
+ // arithmetics on wxColour, unfortunately)
+ wxColour colText;
+ if ( highlighted )
+#ifdef __WXMAC__
+ {
+ if (m_owner->HasFocus()
+#ifdef __WXMAC__
+ && IsControlActive( (ControlRef)m_owner->GetHandle() )
+#endif
+ )
+ colText = *wxWHITE;
+ else
+ colText = *wxBLACK;
+ }
+#else
+ colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+#endif
+ else if ( attr && attr->HasTextColour() )
+ colText = attr->GetTextColour();
+ else
+ colText = listctrl->GetForegroundColour();
+
+ dc->SetTextForeground(colText);
+
+ // font
+ wxFont font;
+ if ( attr && attr->HasFont() )
+ font = attr->GetFont();
+ else
+ font = listctrl->GetFont();
+
+ dc->SetFont(font);
+
+ // bg colour
+ bool hasBgCol = attr && attr->HasBackgroundColour();
+ if ( highlighted || hasBgCol )
+ {
+ if ( highlighted )
+ dc->SetBrush( *m_owner->GetHighlightBrush() );
+ else
+ dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
+
+ dc->SetPen( *wxTRANSPARENT_PEN );
+
+ return true;
+ }
+
+ return false;
+}
+
+void wxListLineData::Draw( wxDC *dc )
+{
+ wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
+ wxCHECK_RET( node, _T("no subitems at all??") );
+
+ bool highlighted = IsHighlighted();
+
+ wxListItemAttr *attr = GetAttr();
+
+ if ( SetAttributes(dc, attr, highlighted) )
+#if ( !defined(__WXGTK20__) && !defined(__WXMAC__) )
+ {
+ dc->DrawRectangle( m_gi->m_rectHighlight );
+ }
+#else
+ {
+ if (highlighted)
+ {
+ int flags = wxCONTROL_SELECTED;
+ if (m_owner->HasFocus()
+#ifdef __WXMAC__
+ && IsControlActive( (ControlRef)m_owner->GetHandle() )
+#endif
+ )
+ flags |= wxCONTROL_FOCUSED;
+ wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, m_gi->m_rectHighlight, flags );
+
+ }
+ else
+ {
+ dc->DrawRectangle( m_gi->m_rectHighlight );
+ }
+ }
+#endif
+
+ // just for debugging to better see where the items are
+#if 0
+ dc->SetPen(*wxRED_PEN);
+ dc->SetBrush(*wxTRANSPARENT_BRUSH);
+ dc->DrawRectangle( m_gi->m_rectAll );
+ dc->SetPen(*wxGREEN_PEN);
+ dc->DrawRectangle( m_gi->m_rectIcon );
+#endif
+
+ wxListItemData *item = node->GetData();
+ if (item->HasImage())
+ {
+ // centre the image inside our rectangle, this looks nicer when items
+ // ae aligned in a row
+ const wxRect& rectIcon = m_gi->m_rectIcon;
+
+ m_owner->DrawImage(item->GetImage(), dc, rectIcon.x, rectIcon.y);
+ }
+
+ if (item->HasText())
+ {
+ const wxRect& rectLabel = m_gi->m_rectLabel;
+
+ wxDCClipper clipper(*dc, rectLabel);
+ dc->DrawText(item->GetText(), rectLabel.x, rectLabel.y);
+ }
+}
+
+void wxListLineData::DrawInReportMode( wxDC *dc,
+ const wxRect& rect,
+ const wxRect& rectHL,
+ bool highlighted )
+{
+ // TODO: later we should support setting different attributes for
+ // different columns - to do it, just add "col" argument to
+ // GetAttr() and move these lines into the loop below
+ wxListItemAttr *attr = GetAttr();
+ if ( SetAttributes(dc, attr, highlighted) )
+#if ( !defined(__WXGTK20__) && !defined(__WXMAC__) )
+ {
+ dc->DrawRectangle( rectHL );
+ }
+#else
+ {
+ if (highlighted)
+ {
+ int flags = wxCONTROL_SELECTED;
+ if (m_owner->HasFocus()
+#ifdef __WXMAC__
+ && IsControlActive( (ControlRef)m_owner->GetHandle() )
+#endif
+ )
+ flags |= wxCONTROL_FOCUSED;
+ wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, rectHL, flags );
+ }
+ else
+ {
+ dc->DrawRectangle( rectHL );
+ }
+ }
+#endif
+
+ wxCoord x = rect.x + HEADER_OFFSET_X,
+ yMid = rect.y + rect.height/2;
+#ifdef __WXGTK__
+ // This probably needs to be done
+ // on all platforms as the icons
+ // otherwise nearly touch the border
+ x += 2;
+#endif
+
+ size_t col = 0;
+ for ( wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
+ node;
+ node = node->GetNext(), col++ )
+ {
+ wxListItemData *item = node->GetData();
+
+ int width = m_owner->GetColumnWidth(col);
+ int xOld = x;
+ x += width;
+
+ if ( item->HasImage() )
+ {
+ int ix, iy;
+ m_owner->GetImageSize( item->GetImage(), ix, iy );
+ m_owner->DrawImage( item->GetImage(), dc, xOld, yMid - iy/2 );
+
+ ix += IMAGE_MARGIN_IN_REPORT_MODE;
+
+ xOld += ix;
+ width -= ix;
+ }
+
+ if ( item->HasText() )
+ DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width - 8);
+ }
+}
+
+void wxListLineData::DrawTextFormatted(wxDC *dc,
+ const wxString& textOrig,
+ int col,
+ int x,
+ int yMid,
+ int width)
+{
+ // we don't support displaying multiple lines currently (and neither does
+ // wxMSW FWIW) so just merge all the lines
+ wxString text(textOrig);
+ text.Replace(_T("\n"), _T(" "));
+
+ wxCoord w, h;
+ dc->GetTextExtent(text, &w, &h);
+
+ const wxCoord y = yMid - (h + 1)/2;
+
+ wxDCClipper clipper(*dc, x, y, width, h);
+
+ // determine if the string can fit inside the current width
+ if (w <= width)
+ {
+ // it can, draw it using the items alignment
+ wxListItem item;
+ m_owner->GetColumn(col, item);
+ switch ( item.GetAlign() )
+ {
+ case wxLIST_FORMAT_LEFT:
+ // nothing to do
+ break;
+
+ case wxLIST_FORMAT_RIGHT:
+ x += width - w;
+ break;
+
+ case wxLIST_FORMAT_CENTER:
+ x += (width - w) / 2;
+ break;
+
+ default:
+ wxFAIL_MSG( _T("unknown list item format") );
+ break;
+ }
+
+ dc->DrawText(text, x, y);
+ }
+ else // otherwise, truncate and add an ellipsis if possible
+ {
+ // determine the base width
+ wxString ellipsis(wxT("..."));
+ wxCoord base_w;
+ dc->GetTextExtent(ellipsis, &base_w, &h);
+
+ // continue until we have enough space or only one character left
+ wxCoord w_c, h_c;
+ size_t len = text.length();
+ wxString drawntext = text.Left(len);
+ while (len > 1)
+ {
+ dc->GetTextExtent(drawntext.Last(), &w_c, &h_c);
+ drawntext.RemoveLast();
+ len--;
+ w -= w_c;
+ if (w + base_w <= width)
+ break;
+ }
+
+ // if still not enough space, remove ellipsis characters
+ while (ellipsis.length() > 0 && w + base_w > width)
+ {
+ ellipsis = ellipsis.Left(ellipsis.length() - 1);
+ dc->GetTextExtent(ellipsis, &base_w, &h);
+ }
+
+ // now draw the text
+ dc->DrawText(drawntext, x, y);
+ dc->DrawText(ellipsis, x + w, y);
+ }
+}
+
+bool wxListLineData::Highlight( bool on )
+{
+ wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") );
+
+ if ( on == m_highlighted )
+ return false;
+
+ m_highlighted = on;
+
+ return true;
+}
+
+void wxListLineData::ReverseHighlight( void )
+{
+ Highlight(!IsHighlighted());
+}
+
+//-----------------------------------------------------------------------------
+// wxListHeaderWindow
+//-----------------------------------------------------------------------------
+
+//IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow)
+
+BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow)
+ EVT_PAINT (wxListHeaderWindow::OnPaint)
+ EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse)
+ EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus)
+END_EVENT_TABLE()
+
+void wxListHeaderWindow::Init()
+{
+ m_currentCursor = (wxCursor *) NULL;
+ m_isDragging = false;
+ m_dirty = false;
+}
+
+wxListHeaderWindow::wxListHeaderWindow()
+{
+ Init();
+
+ m_owner = (wxListMainWindow *) NULL;
+ m_resizeCursor = (wxCursor *) NULL;
+}
+
+wxListHeaderWindow::wxListHeaderWindow( wxWindow *win,
+ wxWindowID id,
+ wxListMainWindow *owner,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxString &name )
+ : wxWindow( win, id, pos, size, style, name )
+{
+ Init();
+
+ m_owner = owner;
+ m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
+
+#if _USE_VISATTR
+ wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
+ SetOwnForegroundColour( attr.colFg );
+ SetOwnBackgroundColour( attr.colBg );
+ if (!m_hasFont)
+ SetOwnFont( attr.font );
+#else
+ SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+ SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
+ if (!m_hasFont)
+ SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT ));
+#endif
+}
+
+wxListHeaderWindow::~wxListHeaderWindow()
+{
+ delete m_resizeCursor;
+}
+
+#ifdef __WXUNIVERSAL__
+#include "wx/univ/renderer.h"
+#include "wx/univ/theme.h"
+#endif
+
+// shift the DC origin to match the position of the main window horz
+// scrollbar: this allows us to always use logical coords
+void wxListHeaderWindow::AdjustDC(wxDC& dc)
+{
+ int xpix;
+ m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
+
+ int view_start;
+ m_owner->GetViewStart( &view_start, NULL );
+
+
+ int org_x = 0;
+ int org_y = 0;
+ dc.GetDeviceOrigin( &org_x, &org_y );
+
+ // account for the horz scrollbar offset
+#ifdef __WXGTK__
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ // Maybe we just have to check for m_signX
+ // in the DC, but I leave the #ifdef __WXGTK__
+ // for now
+ dc.SetDeviceOrigin( org_x + (view_start * xpix), org_y );
+ }
+ else
+#endif
+ dc.SetDeviceOrigin( org_x - (view_start * xpix), org_y );
+}
+
+void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
+{
+ wxPaintDC dc( this );
+
+ PrepareDC( dc );
+ AdjustDC( dc );
+
+ dc.SetFont( GetFont() );
+
+ // width and height of the entire header window
+ int w, h;
+ GetClientSize( &w, &h );
+ m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
+
+ dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetTextForeground(GetForegroundColour());
+
+ int x = HEADER_OFFSET_X;
+ int numColumns = m_owner->GetColumnCount();
+ wxListItem item;
+ for ( int i = 0; i < numColumns && x < w; i++ )
+ {
+ m_owner->GetColumn( i, item );
+ int wCol = item.m_width;
+
+ int cw = wCol;
+ int ch = h;
+
+ int flags = 0;
+ if (!m_parent->IsEnabled())
+ flags |= wxCONTROL_DISABLED;
+
+// NB: The code below is not really Mac-specific, but since we are close
+// to 2.8 release and I don't have time to test on other platforms, I
+// defined this only for wxMac. If this behavior is desired on
+// other platforms, please go ahead and revise or remove the #ifdef.
+#ifdef __WXMAC__
+ if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) &&
+ (item.m_state & wxLIST_STATE_SELECTED) )
+ flags |= wxCONTROL_SELECTED;
+#endif
+
+ wxRendererNative::Get().DrawHeaderButton
+ (
+ this,
+ dc,
+ wxRect(x, HEADER_OFFSET_Y, cw, ch),
+ flags
+ );
+
+ // see if we have enough space for the column label
+
+ // for this we need the width of the text
+ wxCoord wLabel;
+ wxCoord hLabel;
+ dc.GetTextExtent(item.GetText(), &wLabel, &hLabel);
+ wLabel += 2 * EXTRA_WIDTH;
+
+ // and the width of the icon, if any
+ int ix = 0, iy = 0; // init them just to suppress the compiler warnings
+ const int image = item.m_image;
+ wxImageList *imageList;
+ if ( image != -1 )
+ {
+ imageList = m_owner->m_small_image_list;
+ if ( imageList )
+ {
+ imageList->GetSize(image, ix, iy);
+ wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
+ }
+ }
+ else
+ {
+ imageList = NULL;
+ }
+
+ // ignore alignment if there is not enough space anyhow
+ int xAligned;
+ switch ( wLabel < cw ? item.GetAlign() : wxLIST_FORMAT_LEFT )
+ {
+ default:
+ wxFAIL_MSG( _T("unknown list item format") );
+ // fall through
+
+ case wxLIST_FORMAT_LEFT:
+ xAligned = x;
+ break;
+
+ case wxLIST_FORMAT_RIGHT:
+ xAligned = x + cw - wLabel;
+ break;
+
+ case wxLIST_FORMAT_CENTER:
+ xAligned = x + (cw - wLabel) / 2;
+ break;
+ }
+
+ // draw the text and image clipping them so that they
+ // don't overwrite the column boundary
+ wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h );
+
+ // if we have an image, draw it on the right of the label
+ if ( imageList )
+ {
+ imageList->Draw
+ (
+ image,
+ dc,
+ xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE,
+ HEADER_OFFSET_Y + (h - 4 - iy)/2,
+ wxIMAGELIST_DRAW_TRANSPARENT
+ );
+ }
+
+ dc.DrawText( item.GetText(),
+ xAligned + EXTRA_WIDTH, h / 2 - hLabel / 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT );
+
+ x += wCol;
+ }
+}
+
+void wxListHeaderWindow::DrawCurrent()
+{
+#if 1
+ m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
+#else
+ int x1 = m_currentX;
+ int y1 = 0;
+ m_owner->ClientToScreen( &x1, &y1 );
+
+ int x2 = m_currentX;
+ int y2 = 0;
+ m_owner->GetClientSize( NULL, &y2 );
+ m_owner->ClientToScreen( &x2, &y2 );
+
+ wxScreenDC dc;
+ dc.SetLogicalFunction( wxINVERT );
+ dc.SetPen( wxPen( *wxBLACK, 2, wxSOLID ) );
+ dc.SetBrush( *wxTRANSPARENT_BRUSH );
+
+ AdjustDC(dc);
+
+ dc.DrawLine( x1, y1, x2, y2 );
+
+ dc.SetLogicalFunction( wxCOPY );
+
+ dc.SetPen( wxNullPen );
+ dc.SetBrush( wxNullBrush );
+#endif
+}
+
+void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
+{
+ // we want to work with logical coords
+ int x;
+ m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
+ int y = event.GetY();
+
+ if (m_isDragging)
+ {
+ SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
+
+ // we don't draw the line beyond our window, but we allow dragging it
+ // there
+ int w = 0;
+ GetClientSize( &w, NULL );
+ m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
+ w -= 6;
+
+ // erase the line if it was drawn
+ if ( m_currentX < w )
+ DrawCurrent();
+
+ if (event.ButtonUp())
+ {
+ ReleaseMouse();
+ m_isDragging = false;
+ m_dirty = true;
+ m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
+ SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
+ }
+ else
+ {
+ if (x > m_minX + 7)
+ m_currentX = x;
+ else
+ m_currentX = m_minX + 7;
+
+ // draw in the new location
+ if ( m_currentX < w )
+ DrawCurrent();
+ }
+ }
+ else // not dragging
+ {
+ m_minX = 0;
+ bool hit_border = false;
+
+ // end of the current column
+ int xpos = 0;
+
+ // find the column where this event occurred
+ int col,
+ countCol = m_owner->GetColumnCount();
+ for (col = 0; col < countCol; col++)
+ {
+ xpos += m_owner->GetColumnWidth( col );
+ m_column = col;
+
+ if ( (abs(x-xpos) < 3) && (y < 22) )
+ {
+ // near the column border
+ hit_border = true;
+ break;
+ }
+
+ if ( x < xpos )
+ {
+ // inside the column
+ break;
+ }
+
+ m_minX = xpos;
+ }
+
+ if ( col == countCol )
+ m_column = -1;
+
+ if (event.LeftDown() || event.RightUp())
+ {
+ if (hit_border && event.LeftDown())
+ {
+ if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG,
+ event.GetPosition()) )
+ {
+ m_isDragging = true;
+ m_currentX = x;
+ CaptureMouse();
+ DrawCurrent();
+ }
+ //else: column resizing was vetoed by the user code
+ }
+ else // click on a column
+ {
+ // record the selected state of the columns
+ if (event.LeftDown())
+ {
+ for (int i=0; i < m_owner->GetColumnCount(); i++)
+ {
+ wxListItem colItem;
+ m_owner->GetColumn(i, colItem);
+ long state = colItem.GetState();
+ if (i == m_column)
+ colItem.SetState(state | wxLIST_STATE_SELECTED);
+ else
+ colItem.SetState(state & ~wxLIST_STATE_SELECTED);
+ m_owner->SetColumn(i, colItem);
+ }
+ }
+
+ SendListEvent( event.LeftDown()
+ ? wxEVT_COMMAND_LIST_COL_CLICK
+ : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK,
+ event.GetPosition());
+ }
+ }
+ else if (event.Moving())
+ {
+ bool setCursor;
+ if (hit_border)
+ {
+ setCursor = m_currentCursor == wxSTANDARD_CURSOR;
+ m_currentCursor = m_resizeCursor;
+ }
+ else
+ {
+ setCursor = m_currentCursor != wxSTANDARD_CURSOR;
+ m_currentCursor = wxSTANDARD_CURSOR;
+ }
+
+ if ( setCursor )
+ SetCursor(*m_currentCursor);
+ }
+ }
+}
+
+void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
+{
+ m_owner->SetFocus();
+ m_owner->Update();
+}
+
+bool wxListHeaderWindow::SendListEvent(wxEventType type, const wxPoint& pos)
+{
+ wxWindow *parent = GetParent();
+ wxListEvent le( type, parent->GetId() );
+ le.SetEventObject( parent );
+ le.m_pointDrag = pos;
+
+ // the position should be relative to the parent window, not
+ // this one for compatibility with MSW and common sense: the
+ // user code doesn't know anything at all about this header
+ // window, so why should it get positions relative to it?
+ le.m_pointDrag.y -= GetSize().y;
+
+ le.m_col = m_column;
+ return !parent->GetEventHandler()->ProcessEvent( le ) || le.IsAllowed();
+}
+
+//-----------------------------------------------------------------------------
+// wxListRenameTimer (internal)
+//-----------------------------------------------------------------------------
+
+wxListRenameTimer::wxListRenameTimer( wxListMainWindow *owner )
+{
+ m_owner = owner;
+}
+
+void wxListRenameTimer::Notify()
+{
+ m_owner->OnRenameTimer();
+}
+
+//-----------------------------------------------------------------------------
+// wxListTextCtrlWrapper (internal)
+//-----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(wxListTextCtrlWrapper, wxEvtHandler)
+ EVT_CHAR (wxListTextCtrlWrapper::OnChar)
+ EVT_KEY_UP (wxListTextCtrlWrapper::OnKeyUp)
+ EVT_KILL_FOCUS (wxListTextCtrlWrapper::OnKillFocus)
+END_EVENT_TABLE()
+
+wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow *owner,
+ wxTextCtrl *text,
+ size_t itemEdit)
+ : m_startValue(owner->GetItemText(itemEdit)),
+ m_itemEdited(itemEdit)
+{
+ m_owner = owner;
+ m_text = text;
+ m_finished = false;
+ m_aboutToFinish = false;
+
+ wxRect rectLabel = owner->GetLineLabelRect(itemEdit);
+
+ m_owner->CalcScrolledPosition(rectLabel.x, rectLabel.y,
+ &rectLabel.x, &rectLabel.y);
+
+ m_text->Create(owner, wxID_ANY, m_startValue,
+ wxPoint(rectLabel.x-4,rectLabel.y-4),
+ wxSize(rectLabel.width+11,rectLabel.height+8));
+ m_text->SetFocus();
+
+ m_text->PushEventHandler(this);
+}
+
+void wxListTextCtrlWrapper::Finish()
+{
+ if ( !m_finished )
+ {
+ m_finished = true;
+
+ m_text->RemoveEventHandler(this);
+ m_owner->FinishEditing(m_text);
+
+ wxPendingDelete.Append( this );
+ }
+}
+
+bool wxListTextCtrlWrapper::AcceptChanges()
+{
+ const wxString value = m_text->GetValue();
+
+ // notice that we should always call OnRenameAccept() to generate the "end
+ // label editing" event, even if the user hasn't really changed anything
+ if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
+ {
+ // vetoed by the user
+ return false;
+ }
+
+ // accepted, do rename the item (unless nothing changed)
+ if ( value != m_startValue )
+ m_owner->SetItemText(m_itemEdited, value);
+
+ return true;
+}
+
+void wxListTextCtrlWrapper::AcceptChangesAndFinish()
+{
+ m_aboutToFinish = true;
+
+ // Notify the owner about the changes
+ AcceptChanges();
+
+ // Even if vetoed, close the control (consistent with MSW)
+ Finish();
+}
+
+void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event )
+{
+ switch ( event.m_keyCode )
+ {
+ case WXK_RETURN:
+ AcceptChangesAndFinish();
+ break;
+
+ case WXK_ESCAPE:
+ m_owner->OnRenameCancelled( m_itemEdited );
+ Finish();
+ break;
+
+ default:
+ event.Skip();
+ }
+}
+
+void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
+{
+ if (m_finished)
+ {
+ event.Skip();
+ return;
+ }
+
+ // auto-grow the textctrl:
+ wxSize parentSize = m_owner->GetSize();
+ wxPoint myPos = m_text->GetPosition();
+ wxSize mySize = m_text->GetSize();
+ int sx, sy;
+ m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
+ if (myPos.x + sx > parentSize.x)
+ sx = parentSize.x - myPos.x;
+ if (mySize.x > sx)
+ sx = mySize.x;
+ m_text->SetSize(sx, wxDefaultCoord);
+
+ event.Skip();
+}
+
+void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
+{
+ if ( !m_finished && !m_aboutToFinish )
+ {
+ if ( !AcceptChanges() )
+ m_owner->OnRenameCancelled( m_itemEdited );
+
+ Finish();
+ }
+
+ // We must let the native text control handle focus
+ event.Skip();
+}
+
+//-----------------------------------------------------------------------------
+// wxListMainWindow
+//-----------------------------------------------------------------------------
+
+//IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow)
+
+BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow)
+ EVT_PAINT (wxListMainWindow::OnPaint)
+ EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse)
+ EVT_CHAR (wxListMainWindow::OnChar)
+ EVT_KEY_DOWN (wxListMainWindow::OnKeyDown)
+ EVT_KEY_UP (wxListMainWindow::OnKeyUp)
+ EVT_SET_FOCUS (wxListMainWindow::OnSetFocus)
+ EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus)
+ EVT_SCROLLWIN (wxListMainWindow::OnScroll)
+END_EVENT_TABLE()
+
+void wxListMainWindow::Init()
+{
+ m_dirty = true;
+ m_countVirt = 0;
+ m_lineFrom =
+ m_lineTo = (size_t)-1;
+ m_linesPerPage = 0;
+
+ m_headerWidth =
+ m_lineHeight = 0;
+
+ m_small_image_list = (wxImageList *) NULL;
+ m_normal_image_list = (wxImageList *) NULL;
+
+ m_small_spacing = 30;
+ m_normal_spacing = 40;
+
+ m_hasFocus = false;
+ m_dragCount = 0;
+ m_isCreated = false;
+
+ m_lastOnSame = false;
+ m_renameTimer = new wxListRenameTimer( this );
+ m_textctrlWrapper = NULL;
+
+ m_current =
+ m_lineLastClicked =
+ m_lineSelectSingleOnUp =
+ m_lineBeforeLastClicked = (size_t)-1;
+
+ m_freezeCount = 0;
+}
+
+wxListMainWindow::wxListMainWindow()
+{
+ Init();
+
+ m_highlightBrush =
+ m_highlightUnfocusedBrush = (wxBrush *) NULL;
+}
+
+wxListMainWindow::wxListMainWindow( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxString &name )
+ : wxScrolledWindow( parent, id, pos, size,
+ style | wxHSCROLL | wxVSCROLL, name )
+{
+ Init();
+
+ m_highlightBrush = new wxBrush
+ (
+ wxSystemSettings::GetColour
+ (
+ wxSYS_COLOUR_HIGHLIGHT
+ ),
+ wxSOLID
+ );
+
+ m_highlightUnfocusedBrush = new wxBrush
+ (
+ wxSystemSettings::GetColour
+ (
+ wxSYS_COLOUR_BTNSHADOW
+ ),
+ wxSOLID
+ );
+
+ SetScrollbars( 0, 0, 0, 0, 0, 0 );
+
+ wxVisualAttributes attr = wxGenericListCtrl::GetClassDefaultAttributes();
+ SetOwnForegroundColour( attr.colFg );
+ SetOwnBackgroundColour( attr.colBg );
+ if (!m_hasFont)
+ SetOwnFont( attr.font );
+}
+
+wxListMainWindow::~wxListMainWindow()
+{
+ DoDeleteAllItems();
+ WX_CLEAR_LIST(wxListHeaderDataList, m_columns);
+ WX_CLEAR_ARRAY(m_aColWidths);
+
+ delete m_highlightBrush;
+ delete m_highlightUnfocusedBrush;
+ delete m_renameTimer;
+}
+
+void wxListMainWindow::CacheLineData(size_t line)
+{
+ wxGenericListCtrl *listctrl = GetListCtrl();
+
+ wxListLineData *ld = GetDummyLine();
+
+ size_t countCol = GetColumnCount();
+ for ( size_t col = 0; col < countCol; col++ )
+ {
+ ld->SetText(col, listctrl->OnGetItemText(line, col));
+ ld->SetImage(col, listctrl->OnGetItemColumnImage(line, col));
+ }
+
+ ld->SetAttr(listctrl->OnGetItemAttr(line));
+}
+
+wxListLineData *wxListMainWindow::GetDummyLine() const
+{
+ wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
+ wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") );
+
+ wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
+
+ // we need to recreate the dummy line if the number of columns in the
+ // control changed as it would have the incorrect number of fields
+ // otherwise
+ if ( !m_lines.IsEmpty() &&
+ m_lines[0].m_items.GetCount() != (size_t)GetColumnCount() )
+ {
+ self->m_lines.Clear();
+ }
+
+ if ( m_lines.IsEmpty() )
+ {
+ wxListLineData *line = new wxListLineData(self);
+ self->m_lines.Add(line);
+
+ // don't waste extra memory -- there never going to be anything
+ // else/more in this array
+ self->m_lines.Shrink();
+ }
+
+ return &m_lines[0];
+}
+
+// ----------------------------------------------------------------------------
+// line geometry (report mode only)
+// ----------------------------------------------------------------------------
+
+wxCoord wxListMainWindow::GetLineHeight() const
+{
+ // we cache the line height as calling GetTextExtent() is slow
+ if ( !m_lineHeight )
+ {
+ wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
+
+ wxClientDC dc( self );
+ dc.SetFont( GetFont() );
+
+ wxCoord y;
+ dc.GetTextExtent(_T("H"), NULL, &y);
+
+ if ( m_small_image_list && m_small_image_list->GetImageCount() )
+ {
+ int iw = 0, ih = 0;
+ m_small_image_list->GetSize(0, iw, ih);
+ y = wxMax(y, ih);
+ }
+
+ y += EXTRA_HEIGHT;
+ self->m_lineHeight = y + LINE_SPACING;
+ }
+
+ return m_lineHeight;
+}
+
+wxCoord wxListMainWindow::GetLineY(size_t line) const
+{
+ wxASSERT_MSG( InReportView(), _T("only works in report mode") );
+
+ return LINE_SPACING + line * GetLineHeight();
+}
+
+wxRect wxListMainWindow::GetLineRect(size_t line) const
+{
+ if ( !InReportView() )
+ return GetLine(line)->m_gi->m_rectAll;
+
+ wxRect rect;
+ rect.x = HEADER_OFFSET_X;
+ rect.y = GetLineY(line);
+ rect.width = GetHeaderWidth();
+ rect.height = GetLineHeight();
+
+ return rect;
+}
+
+wxRect wxListMainWindow::GetLineLabelRect(size_t line) const
+{
+ if ( !InReportView() )
+ return GetLine(line)->m_gi->m_rectLabel;
+
+ int image_x = 0;
+ wxListLineData *data = GetLine(line);
+ wxListItemDataList::compatibility_iterator node = data->m_items.GetFirst();
+ if (node)
+ {
+ wxListItemData *item = node->GetData();
+ if ( item->HasImage() )
+ {
+ int ix, iy;
+ GetImageSize( item->GetImage(), ix, iy );
+ image_x = 3 + ix + IMAGE_MARGIN_IN_REPORT_MODE;
+ }
+ }
+
+ wxRect rect;
+ rect.x = image_x + HEADER_OFFSET_X;
+ rect.y = GetLineY(line);
+ rect.width = GetColumnWidth(0) - image_x;
+ rect.height = GetLineHeight();
+
+ return rect;
+}
+
+wxRect wxListMainWindow::GetLineIconRect(size_t line) const
+{
+ if ( !InReportView() )
+ return GetLine(line)->m_gi->m_rectIcon;
+
+ wxListLineData *ld = GetLine(line);
+ wxASSERT_MSG( ld->HasImage(), _T("should have an image") );
+
+ wxRect rect;
+ rect.x = HEADER_OFFSET_X;
+ rect.y = GetLineY(line);
+ GetImageSize(ld->GetImage(), rect.width, rect.height);
+
+ return rect;
+}
+
+wxRect wxListMainWindow::GetLineHighlightRect(size_t line) const
+{
+ return InReportView() ? GetLineRect(line)
+ : GetLine(line)->m_gi->m_rectHighlight;
+}
+
+long wxListMainWindow::HitTestLine(size_t line, int x, int y) const
+{
+ wxASSERT_MSG( line < GetItemCount(), _T("invalid line in HitTestLine") );
+
+ wxListLineData *ld = GetLine(line);
+
+ if ( ld->HasImage() && GetLineIconRect(line).Contains(x, y) )
+ return wxLIST_HITTEST_ONITEMICON;
+
+ // VS: Testing for "ld->HasText() || InReportView()" instead of
+ // "ld->HasText()" is needed to make empty lines in report view
+ // possible
+ if ( ld->HasText() || InReportView() )
+ {
+ wxRect rect = InReportView() ? GetLineRect(line)
+ : GetLineLabelRect(line);
+
+ if ( rect.Contains(x, y) )
+ return wxLIST_HITTEST_ONITEMLABEL;
+ }
+
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+// highlight (selection) handling
+// ----------------------------------------------------------------------------
+
+bool wxListMainWindow::IsHighlighted(size_t line) const
+{
+ if ( IsVirtual() )
+ {
+ return m_selStore.IsSelected(line);
+ }
+ else // !virtual
+ {
+ wxListLineData *ld = GetLine(line);
+ wxCHECK_MSG( ld, false, _T("invalid index in IsHighlighted") );
+
+ return ld->IsHighlighted();
+ }
+}
+
+void wxListMainWindow::HighlightLines( size_t lineFrom,
+ size_t lineTo,
+ bool highlight )
+{
+ if ( IsVirtual() )
+ {
+ wxArrayInt linesChanged;
+ if ( !m_selStore.SelectRange(lineFrom, lineTo, highlight,
+ &linesChanged) )
+ {
+ // meny items changed state, refresh everything
+ RefreshLines(lineFrom, lineTo);
+ }
+ else // only a few items changed state, refresh only them
+ {
+ size_t count = linesChanged.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ RefreshLine(linesChanged[n]);
+ }
+ }
+ }
+ else // iterate over all items in non report view
+ {
+ for ( size_t line = lineFrom; line <= lineTo; line++ )
+ {
+ if ( HighlightLine(line, highlight) )
+ RefreshLine(line);
+ }
+ }
+}
+
+bool wxListMainWindow::HighlightLine( size_t line, bool highlight )
+{
+ bool changed;
+
+ if ( IsVirtual() )
+ {
+ changed = m_selStore.SelectItem(line, highlight);
+ }
+ else // !virtual
+ {
+ wxListLineData *ld = GetLine(line);
+ wxCHECK_MSG( ld, false, _T("invalid index in HighlightLine") );
+
+ changed = ld->Highlight(highlight);
+ }
+
+ if ( changed )
+ {
+ SendNotify( line, highlight ? wxEVT_COMMAND_LIST_ITEM_SELECTED
+ : wxEVT_COMMAND_LIST_ITEM_DESELECTED );
+ }
+
+ return changed;
+}
+
+void wxListMainWindow::RefreshLine( size_t line )
+{
+ if ( InReportView() )
+ {
+ size_t visibleFrom, visibleTo;
+ GetVisibleLinesRange(&visibleFrom, &visibleTo);
+
+ if ( line < visibleFrom || line > visibleTo )
+ return;
+ }
+
+ wxRect rect = GetLineRect(line);
+
+ CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+ RefreshRect( rect );
+}
+
+void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo )
+{
+ // we suppose that they are ordered by caller
+ wxASSERT_MSG( lineFrom <= lineTo, _T("indices in disorder") );
+
+ wxASSERT_MSG( lineTo < GetItemCount(), _T("invalid line range") );
+
+ if ( InReportView() )
+ {
+ size_t visibleFrom, visibleTo;
+ GetVisibleLinesRange(&visibleFrom, &visibleTo);
+
+ if ( lineFrom < visibleFrom )
+ lineFrom = visibleFrom;
+ if ( lineTo > visibleTo )
+ lineTo = visibleTo;
+
+ wxRect rect;
+ rect.x = 0;
+ rect.y = GetLineY(lineFrom);
+ rect.width = GetClientSize().x;
+ rect.height = GetLineY(lineTo) - rect.y + GetLineHeight();
+
+ CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+ RefreshRect( rect );
+ }
+ else // !report
+ {
+ // TODO: this should be optimized...
+ for ( size_t line = lineFrom; line <= lineTo; line++ )
+ {
+ RefreshLine(line);
+ }
+ }
+}
+
+void wxListMainWindow::RefreshAfter( size_t lineFrom )
+{
+ if ( InReportView() )
+ {
+ size_t visibleFrom, visibleTo;
+ GetVisibleLinesRange(&visibleFrom, &visibleTo);
+
+ if ( lineFrom < visibleFrom )
+ lineFrom = visibleFrom;
+ else if ( lineFrom > visibleTo )
+ return;
+
+ wxRect rect;
+ rect.x = 0;
+ rect.y = GetLineY(lineFrom);
+ CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+
+ wxSize size = GetClientSize();
+ rect.width = size.x;
+
+ // refresh till the bottom of the window
+ rect.height = size.y - rect.y;
+
+ RefreshRect( rect );
+ }
+ else // !report
+ {
+ // TODO: how to do it more efficiently?
+ m_dirty = true;
+ }
+}
+
+void wxListMainWindow::RefreshSelected()
+{
+ if ( IsEmpty() )
+ return;
+
+ size_t from, to;
+ if ( InReportView() )
+ {
+ GetVisibleLinesRange(&from, &to);
+ }
+ else // !virtual
+ {
+ from = 0;
+ to = GetItemCount() - 1;
+ }
+
+ if ( HasCurrent() && m_current >= from && m_current <= to )
+ RefreshLine(m_current);
+
+ for ( size_t line = from; line <= to; line++ )
+ {
+ // NB: the test works as expected even if m_current == -1
+ if ( line != m_current && IsHighlighted(line) )
+ RefreshLine(line);
+ }
+}
+
+void wxListMainWindow::Freeze()
+{
+ m_freezeCount++;
+}
+
+void wxListMainWindow::Thaw()
+{
+ wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") );
+
+ if ( --m_freezeCount == 0 )
+ Refresh();
+}
+
+void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
+{
+ // Note: a wxPaintDC must be constructed even if no drawing is
+ // done (a Windows requirement).
+ wxPaintDC dc( this );
+
+ if ( IsEmpty() || m_freezeCount )
+ // nothing to draw or not the moment to draw it
+ return;
+
+ if ( m_dirty )
+ // delay the repainting until we calculate all the items positions
+ return;
+
+ PrepareDC( dc );
+
+ int dev_x, dev_y;
+ CalcScrolledPosition( 0, 0, &dev_x, &dev_y );
+
+ dc.SetFont( GetFont() );
+
+ if ( InReportView() )
+ {
+ int lineHeight = GetLineHeight();
+
+ size_t visibleFrom, visibleTo;
+ GetVisibleLinesRange(&visibleFrom, &visibleTo);
+
+ wxRect rectLine;
+ int xOrig = dc.LogicalToDeviceX( 0 );
+ int yOrig = dc.LogicalToDeviceY( 0 );
+
+ // tell the caller cache to cache the data
+ if ( IsVirtual() )
+ {
+ wxListEvent evCache(wxEVT_COMMAND_LIST_CACHE_HINT,
+ GetParent()->GetId());
+ evCache.SetEventObject( GetParent() );
+ evCache.m_oldItemIndex = visibleFrom;
+ evCache.m_itemIndex = visibleTo;
+ GetParent()->GetEventHandler()->ProcessEvent( evCache );
+ }
+
+ for ( size_t line = visibleFrom; line <= visibleTo; line++ )
+ {
+ rectLine = GetLineRect(line);
+
+
+ if ( !IsExposed(rectLine.x + xOrig, rectLine.y + yOrig,
+ rectLine.width, rectLine.height) )
+ {
+ // don't redraw unaffected lines to avoid flicker
+ continue;
+ }
+
+ GetLine(line)->DrawInReportMode( &dc,
+ rectLine,
+ GetLineHighlightRect(line),
+ IsHighlighted(line) );
+ }
+
+ if ( HasFlag(wxLC_HRULES) )
+ {
+ wxPen pen(GetRuleColour(), 1, wxSOLID);
+ wxSize clientSize = GetClientSize();
+
+ size_t i = visibleFrom;
+ if (i == 0) i = 1; // Don't draw the first one
+ for ( ; i <= visibleTo; i++ )
+ {
+ dc.SetPen(pen);
+ dc.SetBrush( *wxTRANSPARENT_BRUSH );
+ dc.DrawLine(0 - dev_x, i * lineHeight,
+ clientSize.x - dev_x, i * lineHeight);
+ }
+
+ // Draw last horizontal rule
+ if ( visibleTo == GetItemCount() - 1 )
+ {
+ dc.SetPen( pen );
+ dc.SetBrush( *wxTRANSPARENT_BRUSH );
+ dc.DrawLine(0 - dev_x, (m_lineTo + 1) * lineHeight,
+ clientSize.x - dev_x , (m_lineTo + 1) * lineHeight );
+ }
+ }
+
+ // Draw vertical rules if required
+ if ( HasFlag(wxLC_VRULES) && !IsEmpty() )
+ {
+ wxPen pen(GetRuleColour(), 1, wxSOLID);
+ wxRect firstItemRect, lastItemRect;
+
+ GetItemRect(visibleFrom, firstItemRect);
+ GetItemRect(visibleTo, lastItemRect);
+ int x = firstItemRect.GetX();
+ dc.SetPen(pen);
+ dc.SetBrush(* wxTRANSPARENT_BRUSH);
+
+ for (int col = 0; col < GetColumnCount(); col++)
+ {
+ int colWidth = GetColumnWidth(col);
+ x += colWidth;
+ int x_pos = x - dev_x;
+ if (col < GetColumnCount()-1) x_pos -= 2;
+ dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y,
+ x_pos, lastItemRect.GetBottom() + 1 - dev_y);
+ }
+ }
+ }
+ else // !report
+ {
+ size_t count = GetItemCount();
+ for ( size_t i = 0; i < count; i++ )
+ {
+ GetLine(i)->Draw( &dc );
+ }
+ }
+
+#ifndef __WXMAC__
+ // Don't draw rect outline under Mac at all.
+ if ( HasCurrent() )
+ {
+ if ( m_hasFocus )
+ {
+ wxRect rect( GetLineHighlightRect( m_current ) );
+#ifndef __WXGTK20__
+ dc.SetPen( *wxBLACK_PEN );
+ dc.SetBrush( *wxTRANSPARENT_BRUSH );
+ dc.DrawRectangle( rect );
+#else
+ wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, wxCONTROL_CURRENT|wxCONTROL_FOCUSED );
+
+#endif
+ }
+ }
+#endif
+}
+
+void wxListMainWindow::HighlightAll( bool on )
+{
+ if ( IsSingleSel() )
+ {
+ wxASSERT_MSG( !on, _T("can't do this in a single selection control") );
+
+ // we just have one item to turn off
+ if ( HasCurrent() && IsHighlighted(m_current) )
+ {
+ HighlightLine(m_current, false);
+ RefreshLine(m_current);
+ }
+ }
+ else // multi selection
+ {
+ if ( !IsEmpty() )
+ HighlightLines(0, GetItemCount() - 1, on);
+ }
+}
+
+void wxListMainWindow::SendNotify( size_t line,
+ wxEventType command,
+ const wxPoint& point )
+{
+ wxListEvent le( command, GetParent()->GetId() );
+ le.SetEventObject( GetParent() );
+
+ le.m_itemIndex = line;
+
+ // set only for events which have position
+ if ( point != wxDefaultPosition )
+ le.m_pointDrag = point;
+
+ // don't try to get the line info for virtual list controls: the main
+ // program has it anyhow and if we did it would result in accessing all
+ // the lines, even those which are not visible now and this is precisely
+ // what we're trying to avoid
+ if ( !IsVirtual() )
+ {
+ if ( line != (size_t)-1 )
+ {
+ GetLine(line)->GetItem( 0, le.m_item );
+ }
+ //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event
+ }
+ //else: there may be no more such item
+
+ GetParent()->GetEventHandler()->ProcessEvent( le );
+}
+
+void wxListMainWindow::ChangeCurrent(size_t current)
+{
+ m_current = current;
+
+ // as the current item changed, we shouldn't start editing it when the
+ // "slow click" timer expires as the click happened on another item
+ if ( m_renameTimer->IsRunning() )
+ m_renameTimer->Stop();
+
+ SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED);
+}
+
+wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass)
+{
+ wxCHECK_MSG( (item >= 0) && ((size_t)item < GetItemCount()), NULL,
+ wxT("wrong index in wxGenericListCtrl::EditLabel()") );
+
+ wxASSERT_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)),
+ wxT("EditLabel() needs a text control") );
+
+ size_t itemEdit = (size_t)item;
+
+ wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
+ le.SetEventObject( GetParent() );
+ le.m_itemIndex = item;
+ wxListLineData *data = GetLine(itemEdit);
+ wxCHECK_MSG( data, NULL, _T("invalid index in EditLabel()") );
+ data->GetItem( 0, le.m_item );
+
+ if ( GetParent()->GetEventHandler()->ProcessEvent( le ) && !le.IsAllowed() )
+ {
+ // vetoed by user code
+ return NULL;
+ }
+
+ // We have to call this here because the label in question might just have
+ // been added and no screen update taken place.
+ if ( m_dirty )
+ {
+ wxSafeYield();
+
+ // Pending events dispatched by wxSafeYield might have changed the item
+ // count
+ if ( (size_t)item >= GetItemCount() )
+ return NULL;
+ }
+
+ wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
+ m_textctrlWrapper = new wxListTextCtrlWrapper(this, text, item);
+ return m_textctrlWrapper->GetText();
+}
+
+void wxListMainWindow::OnRenameTimer()
+{
+ wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
+
+ EditLabel( m_current );
+}
+
+bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value)
+{
+ wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
+ le.SetEventObject( GetParent() );
+ le.m_itemIndex = itemEdit;
+
+ wxListLineData *data = GetLine(itemEdit);
+
+ wxCHECK_MSG( data, false, _T("invalid index in OnRenameAccept()") );
+
+ data->GetItem( 0, le.m_item );
+ le.m_item.m_text = value;
+ return !GetParent()->GetEventHandler()->ProcessEvent( le ) ||
+ le.IsAllowed();
+}
+
+void wxListMainWindow::OnRenameCancelled(size_t itemEdit)
+{
+ // let owner know that the edit was cancelled
+ wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
+
+ le.SetEditCanceled(true);
+
+ le.SetEventObject( GetParent() );
+ le.m_itemIndex = itemEdit;
+
+ wxListLineData *data = GetLine(itemEdit);
+ wxCHECK_RET( data, _T("invalid index in OnRenameCancelled()") );
+
+ data->GetItem( 0, le.m_item );
+ GetEventHandler()->ProcessEvent( le );
+}
+
+void wxListMainWindow::OnMouse( wxMouseEvent &event )
+{
+
+#ifdef __WXMAC__
+ // On wxMac we can't depend on the EVT_KILL_FOCUS event to properly
+ // shutdown the edit control when the mouse is clicked elsewhere on the
+ // listctrl because the order of events is different (or something like
+ // that), so explicitly end the edit if it is active.
+ if ( event.LeftDown() && m_textctrlWrapper )
+ m_textctrlWrapper->AcceptChangesAndFinish();
+#endif // __WXMAC__
+
+ if ( event.LeftDown() )
+ SetFocusIgnoringChildren();
+
+ event.SetEventObject( GetParent() );
+ if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
+ return;
+
+ if (event.GetEventType() == wxEVT_MOUSEWHEEL)
+ {
+ // let the base handle mouse wheel events.
+ event.Skip();
+ return;
+ }
+
+ if ( !HasCurrent() || IsEmpty() )
+ {
+ if (event.RightDown())
+ {
+ SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
+ // Allow generation of context menu event
+ event.Skip();
+ }
+ return;
+ }
+
+ if (m_dirty)
+ return;
+
+ if ( !(event.Dragging() || event.ButtonDown() || event.LeftUp() ||
+ event.ButtonDClick()) )
+ return;
+
+ int x = event.GetX();
+ int y = event.GetY();
+ CalcUnscrolledPosition( x, y, &x, &y );
+
+ // where did we hit it (if we did)?
+ long hitResult = 0;
+
+ size_t count = GetItemCount(),
+ current;
+
+ if ( InReportView() )
+ {
+ current = y / GetLineHeight();
+ if ( current < count )
+ hitResult = HitTestLine(current, x, y);
+ }
+ else // !report
+ {
+ // TODO: optimize it too! this is less simple than for report view but
+ // enumerating all items is still not a way to do it!!
+ for ( current = 0; current < count; current++ )
+ {
+ hitResult = HitTestLine(current, x, y);
+ if ( hitResult )
+ break;
+ }
+ }
+
+ if (event.Dragging())
+ {
+ if (m_dragCount == 0)
+ {
+ // we have to report the raw, physical coords as we want to be
+ // able to call HitTest(event.m_pointDrag) from the user code to
+ // get the item being dragged
+ m_dragStart = event.GetPosition();
+ }
+
+ m_dragCount++;
+
+ if (m_dragCount != 3)
+ return;
+
+ int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
+ : wxEVT_COMMAND_LIST_BEGIN_DRAG;
+
+ wxListEvent le( command, GetParent()->GetId() );
+ le.SetEventObject( GetParent() );
+ le.m_itemIndex = m_lineLastClicked;
+ le.m_pointDrag = m_dragStart;
+ GetParent()->GetEventHandler()->ProcessEvent( le );
+
+ return;
+ }
+ else
+ {
+ m_dragCount = 0;
+ }
+
+ if ( !hitResult )
+ {
+ // outside of any item
+ if (event.RightDown())
+ {
+ SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
+
+ wxContextMenuEvent evtCtx(
+ wxEVT_CONTEXT_MENU,
+ GetParent()->GetId(),
+ ClientToScreen(event.GetPosition()));
+ evtCtx.SetEventObject(GetParent());
+ GetParent()->GetEventHandler()->ProcessEvent(evtCtx);
+ }
+ else
+ {
+ // reset the selection and bail out
+ HighlightAll(false);
+ }
+
+ return;
+ }
+
+ bool forceClick = false;
+ if (event.ButtonDClick())
+ {
+ if ( m_renameTimer->IsRunning() )
+ m_renameTimer->Stop();
+
+ m_lastOnSame = false;
+
+ if ( current == m_lineLastClicked )
+ {
+ SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
+
+ return;
+ }
+ else
+ {
+ // The first click was on another item, so don't interpret this as
+ // a double click, but as a simple click instead
+ forceClick = true;
+ }
+ }
+
+ if (event.LeftUp())
+ {
+ if (m_lineSelectSingleOnUp != (size_t)-1)
+ {
+ // select single line
+ HighlightAll( false );
+ ReverseHighlight(m_lineSelectSingleOnUp);
+ }
+
+ if (m_lastOnSame)
+ {
+ if ((current == m_current) &&
+ (hitResult == wxLIST_HITTEST_ONITEMLABEL) &&
+ HasFlag(wxLC_EDIT_LABELS) )
+ {
+ if (InReportView())
+ {
+ wxRect label = GetLineLabelRect( current );
+ if (label.Contains( x, y ))
+ m_renameTimer->Start( 250, true );
+
+ }
+ else
+ m_renameTimer->Start( 250, true );
+ }
+ }
+
+ m_lastOnSame = false;
+ m_lineSelectSingleOnUp = (size_t)-1;
+ }
+ else
+ {
+ // This is necessary, because after a DnD operation in
+ // from and to ourself, the up event is swallowed by the
+ // DnD code. So on next non-up event (which means here and
+ // now) m_lineSelectSingleOnUp should be reset.
+ m_lineSelectSingleOnUp = (size_t)-1;
+ }
+ if (event.RightDown())
+ {
+ m_lineBeforeLastClicked = m_lineLastClicked;
+ m_lineLastClicked = current;
+
+ // If the item is already selected, do not update the selection.
+ // Multi-selections should not be cleared if a selected item is clicked.
+ if (!IsHighlighted(current))
+ {
+ HighlightAll(false);
+ ChangeCurrent(current);
+ ReverseHighlight(m_current);
+ }
+
+ SendNotify( current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
+
+ wxContextMenuEvent evtCtx(
+ wxEVT_CONTEXT_MENU,
+ GetParent()->GetId(),
+ ClientToScreen(event.GetPosition()));
+ evtCtx.SetEventObject(GetParent());
+ GetParent()->GetEventHandler()->ProcessEvent(evtCtx);
+ }
+ else if (event.MiddleDown())
+ {
+ SendNotify( current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK );
+ }
+ else if ( event.LeftDown() || forceClick )
+ {
+ m_lineBeforeLastClicked = m_lineLastClicked;
+ m_lineLastClicked = current;
+
+ size_t oldCurrent = m_current;
+ bool oldWasSelected = IsHighlighted(m_current);
+
+ bool cmdModifierDown = event.CmdDown();
+ if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
+ {
+ if ( IsSingleSel() || !IsHighlighted(current) )
+ {
+ HighlightAll( false );
+
+ ChangeCurrent(current);
+
+ ReverseHighlight(m_current);
+ }
+ else // multi sel & current is highlighted & no mod keys
+ {
+ m_lineSelectSingleOnUp = current;
+ ChangeCurrent(current); // change focus
+ }
+ }
+ else // multi sel & either ctrl or shift is down
+ {
+ if (cmdModifierDown)
+ {
+ ChangeCurrent(current);
+
+ ReverseHighlight(m_current);
+ }
+ else if (event.ShiftDown())
+ {
+ ChangeCurrent(current);
+
+ size_t lineFrom = oldCurrent,
+ lineTo = current;
+
+ if ( lineTo < lineFrom )
+ {
+ lineTo = lineFrom;
+ lineFrom = m_current;
+ }
+
+ HighlightLines(lineFrom, lineTo);
+ }
+ else // !ctrl, !shift
+ {
+ // test in the enclosing if should make it impossible
+ wxFAIL_MSG( _T("how did we get here?") );
+ }
+ }
+
+ if (m_current != oldCurrent)
+ RefreshLine( oldCurrent );
+
+ // forceClick is only set if the previous click was on another item
+ m_lastOnSame = !forceClick && (m_current == oldCurrent) && oldWasSelected;
+ }
+}
+
+void wxListMainWindow::MoveToItem(size_t item)
+{
+ if ( item == (size_t)-1 )
+ return;
+
+ wxRect rect = GetLineRect(item);
+
+ int client_w, client_h;
+ GetClientSize( &client_w, &client_h );
+
+ const int hLine = GetLineHeight();
+
+ int view_x = SCROLL_UNIT_X * GetScrollPos( wxHORIZONTAL );
+ int view_y = hLine * GetScrollPos( wxVERTICAL );
+
+ if ( InReportView() )
+ {
+ // the next we need the range of lines shown it might be different,
+ // so recalculate it
+ ResetVisibleLinesRange();
+
+ if (rect.y < view_y)
+ Scroll( -1, rect.y / hLine );
+ if (rect.y + rect.height + 5 > view_y + client_h)
+ Scroll( -1, (rect.y + rect.height - client_h + hLine) / hLine );
+
+#ifdef __WXMAC__
+ // At least on Mac the visible lines value will get reset inside of
+ // Scroll *before* it actually scrolls the window because of the
+ // Update() that happens there, so it will still have the wrong value.
+ // So let's reset it again and wait for it to be recalculated in the
+ // next paint event. I would expect this problem to show up in wxGTK
+ // too but couldn't duplicate it there. Perhaps the order of events
+ // is different... --Robin
+ ResetVisibleLinesRange();
+#endif
+ }
+ else // !report
+ {
+ if (rect.x-view_x < 5)
+ Scroll( (rect.x - 5) / SCROLL_UNIT_X, -1 );
+ if (rect.x + rect.width - 5 > view_x + client_w)
+ Scroll( (rect.x + rect.width - client_w + SCROLL_UNIT_X) / SCROLL_UNIT_X, -1 );
+ }
+}
+
+// ----------------------------------------------------------------------------
+// keyboard handling
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
+{
+ wxCHECK_RET( newCurrent < (size_t)GetItemCount(),
+ _T("invalid item index in OnArrowChar()") );
+
+ size_t oldCurrent = m_current;
+
+ // in single selection we just ignore Shift as we can't select several
+ // items anyhow
+ if ( event.ShiftDown() && !IsSingleSel() )
+ {
+ ChangeCurrent(newCurrent);
+
+ // refresh the old focus to remove it
+ RefreshLine( oldCurrent );
+
+ // select all the items between the old and the new one
+ if ( oldCurrent > newCurrent )
+ {
+ newCurrent = oldCurrent;
+ oldCurrent = m_current;
+ }
+
+ HighlightLines(oldCurrent, newCurrent);
+ }
+ else // !shift
+ {
+ // all previously selected items are unselected unless ctrl is held
+ // in a multiselection control
+ if ( !event.ControlDown() || IsSingleSel() )
+ HighlightAll(false);
+
+ ChangeCurrent(newCurrent);
+
+ // refresh the old focus to remove it
+ RefreshLine( oldCurrent );
+
+ // in single selection mode we must always have a selected item
+ if ( !event.ControlDown() || IsSingleSel() )
+ HighlightLine( m_current, true );
+ }
+
+ RefreshLine( m_current );
+
+ MoveToFocus();
+}
+
+void wxListMainWindow::OnKeyDown( wxKeyEvent &event )
+{
+ wxWindow *parent = GetParent();
+
+ // propagate the key event upwards
+ wxKeyEvent ke( wxEVT_KEY_DOWN );
+ ke.m_shiftDown = event.m_shiftDown;
+ ke.m_controlDown = event.m_controlDown;
+ ke.m_altDown = event.m_altDown;
+ ke.m_metaDown = event.m_metaDown;
+ ke.m_keyCode = event.m_keyCode;
+ ke.m_x = event.m_x;
+ ke.m_y = event.m_y;
+ ke.SetEventObject( parent );
+ if (parent->GetEventHandler()->ProcessEvent( ke )) return;
+
+ event.Skip();
+}
+
+void wxListMainWindow::OnKeyUp( wxKeyEvent &event )
+{
+ wxWindow *parent = GetParent();
+
+ // propagate the key event upwards
+ wxKeyEvent ke( wxEVT_KEY_UP );
+ ke.m_shiftDown = event.m_shiftDown;
+ ke.m_controlDown = event.m_controlDown;
+ ke.m_altDown = event.m_altDown;
+ ke.m_metaDown = event.m_metaDown;
+ ke.m_keyCode = event.m_keyCode;
+ ke.m_x = event.m_x;
+ ke.m_y = event.m_y;
+ ke.SetEventObject( parent );
+ if (parent->GetEventHandler()->ProcessEvent( ke )) return;
+
+ event.Skip();
+}
+
+void wxListMainWindow::OnChar( wxKeyEvent &event )
+{
+ wxWindow *parent = GetParent();
+
+ // send a list_key event up
+ if ( HasCurrent() )
+ {
+ wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() );
+ le.m_itemIndex = m_current;
+ GetLine(m_current)->GetItem( 0, le.m_item );
+ le.m_code = event.GetKeyCode();
+ le.SetEventObject( parent );
+ parent->GetEventHandler()->ProcessEvent( le );
+ }
+
+ // propagate the char event upwards
+ wxKeyEvent ke( wxEVT_CHAR );
+ ke.m_shiftDown = event.m_shiftDown;
+ ke.m_controlDown = event.m_controlDown;
+ ke.m_altDown = event.m_altDown;
+ ke.m_metaDown = event.m_metaDown;
+ ke.m_keyCode = event.m_keyCode;
+ ke.m_x = event.m_x;
+ ke.m_y = event.m_y;
+ ke.SetEventObject( parent );
+ if (parent->GetEventHandler()->ProcessEvent( ke )) return;
+
+ if (event.GetKeyCode() == WXK_TAB)
+ {
+ wxNavigationKeyEvent nevent;
+ nevent.SetWindowChange( event.ControlDown() );
+ nevent.SetDirection( !event.ShiftDown() );
+ nevent.SetEventObject( GetParent()->GetParent() );
+ nevent.SetCurrentFocus( m_parent );
+ if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
+ return;
+ }
+
+ // no item -> nothing to do
+ if (!HasCurrent())
+ {
+ event.Skip();
+ return;
+ }
+
+ // don't use m_linesPerPage directly as it might not be computed yet
+ const int pageSize = GetCountPerPage();
+ wxCHECK_RET( pageSize, _T("should have non zero page size") );
+
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ if (event.GetKeyCode() == WXK_RIGHT)
+ event.m_keyCode = WXK_LEFT;
+ else if (event.GetKeyCode() == WXK_LEFT)
+ event.m_keyCode = WXK_RIGHT;
+ }
+
+ switch ( event.GetKeyCode() )
+ {
+ case WXK_UP:
+ if ( m_current > 0 )
+ OnArrowChar( m_current - 1, event );
+ break;
+
+ case WXK_DOWN:
+ if ( m_current < (size_t)GetItemCount() - 1 )
+ OnArrowChar( m_current + 1, event );
+ break;
+
+ case WXK_END:
+ if (!IsEmpty())
+ OnArrowChar( GetItemCount() - 1, event );
+ break;
+
+ case WXK_HOME:
+ if (!IsEmpty())
+ OnArrowChar( 0, event );
+ break;
+
+ case WXK_PAGEUP:
+ {
+ int steps = InReportView() ? pageSize - 1
+ : m_current % pageSize;
+
+ int index = m_current - steps;
+ if (index < 0)
+ index = 0;
+
+ OnArrowChar( index, event );
+ }
+ break;
+
+ case WXK_PAGEDOWN:
+ {
+ int steps = InReportView()
+ ? pageSize - 1
+ : pageSize - (m_current % pageSize) - 1;
+
+ size_t index = m_current + steps;
+ size_t count = GetItemCount();
+ if ( index >= count )
+ index = count - 1;
+
+ OnArrowChar( index, event );
+ }
+ break;
+
+ case WXK_LEFT:
+ if ( !InReportView() )
+ {
+ int index = m_current - pageSize;
+ if (index < 0)
+ index = 0;
+
+ OnArrowChar( index, event );
+ }
+ break;
+
+ case WXK_RIGHT:
+ if ( !InReportView() )
+ {
+ size_t index = m_current + pageSize;
+
+ size_t count = GetItemCount();
+ if ( index >= count )
+ index = count - 1;
+
+ OnArrowChar( index, event );
+ }
+ break;
+
+ case WXK_SPACE:
+ if ( IsSingleSel() )
+ {
+ if ( event.ControlDown() )
+ {
+ ReverseHighlight(m_current);
+ }
+ else // normal space press
+ {
+ SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
+ }
+ }
+ else // multiple selection
+ {
+ ReverseHighlight(m_current);
+ }
+ break;
+
+ case WXK_RETURN:
+ case WXK_EXECUTE:
+ SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
+ break;
+
+ default:
+ event.Skip();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// focus handling
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
+{
+ if ( GetParent() )
+ {
+ wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
+ event.SetEventObject( GetParent() );
+ if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
+ return;
+ }
+
+ // wxGTK sends us EVT_SET_FOCUS events even if we had never got
+ // EVT_KILL_FOCUS before which means that we finish by redrawing the items
+ // which are already drawn correctly resulting in horrible flicker - avoid
+ // it
+ if ( !m_hasFocus )
+ {
+ m_hasFocus = true;
+
+ RefreshSelected();
+ }
+}
+
+void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
+{
+ if ( GetParent() )
+ {
+ wxFocusEvent event( wxEVT_KILL_FOCUS, GetParent()->GetId() );
+ event.SetEventObject( GetParent() );
+ if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
+ return;
+ }
+
+ m_hasFocus = false;
+ RefreshSelected();
+}
+
+void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y )
+{
+ if ( HasFlag(wxLC_ICON) && (m_normal_image_list))
+ {
+ m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
+ }
+ else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list))
+ {
+ m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
+ }
+ else if ( HasFlag(wxLC_LIST) && (m_small_image_list))
+ {
+ m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
+ }
+ else if ( InReportView() && (m_small_image_list))
+ {
+ m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
+ }
+}
+
+void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
+{
+ if ( HasFlag(wxLC_ICON) && m_normal_image_list )
+ {
+ m_normal_image_list->GetSize( index, width, height );
+ }
+ else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
+ {
+ m_small_image_list->GetSize( index, width, height );
+ }
+ else if ( HasFlag(wxLC_LIST) && m_small_image_list )
+ {
+ m_small_image_list->GetSize( index, width, height );
+ }
+ else if ( InReportView() && m_small_image_list )
+ {
+ m_small_image_list->GetSize( index, width, height );
+ }
+ else
+ {
+ width =
+ height = 0;
+ }
+}
+
+int wxListMainWindow::GetTextLength( const wxString &s ) const
+{
+ wxClientDC dc( wxConstCast(this, wxListMainWindow) );
+ dc.SetFont( GetFont() );
+
+ wxCoord lw;
+ dc.GetTextExtent( s, &lw, NULL );
+
+ return lw + AUTOSIZE_COL_MARGIN;
+}
+
+void wxListMainWindow::SetImageList( wxImageList *imageList, int which )
+{
+ m_dirty = true;
+
+ // calc the spacing from the icon size
+ int width = 0, height = 0;
+
+ if ((imageList) && (imageList->GetImageCount()) )
+ imageList->GetSize(0, width, height);
+
+ if (which == wxIMAGE_LIST_NORMAL)
+ {
+ m_normal_image_list = imageList;
+ m_normal_spacing = width + 8;
+ }
+
+ if (which == wxIMAGE_LIST_SMALL)
+ {
+ m_small_image_list = imageList;
+ m_small_spacing = width + 14;
+ m_lineHeight = 0; // ensure that the line height will be recalc'd
+ }
+}
+
+void wxListMainWindow::SetItemSpacing( int spacing, bool isSmall )
+{
+ m_dirty = true;
+ if (isSmall)
+ m_small_spacing = spacing;
+ else
+ m_normal_spacing = spacing;
+}
+
+int wxListMainWindow::GetItemSpacing( bool isSmall )
+{
+ return isSmall ? m_small_spacing : m_normal_spacing;
+}
+
+// ----------------------------------------------------------------------------
+// columns
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::SetColumn( int col, wxListItem &item )
+{
+ wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col );
+
+ wxCHECK_RET( node, _T("invalid column index in SetColumn") );
+
+ if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER )
+ item.m_width = GetTextLength( item.m_text );
+
+ wxListHeaderData *column = node->GetData();
+ column->SetItem( item );
+
+ wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
+ if ( headerWin )
+ headerWin->m_dirty = true;
+
+ m_dirty = true;
+
+ // invalidate it as it has to be recalculated
+ m_headerWidth = 0;
+}
+
+void wxListMainWindow::SetColumnWidth( int col, int width )
+{
+ wxCHECK_RET( col >= 0 && col < GetColumnCount(),
+ _T("invalid column index") );
+
+ wxCHECK_RET( InReportView(),
+ _T("SetColumnWidth() can only be called in report mode.") );
+
+ m_dirty = true;
+ wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
+ if ( headerWin )
+ headerWin->m_dirty = true;
+
+ wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col );
+ wxCHECK_RET( node, _T("no column?") );
+
+ wxListHeaderData *column = node->GetData();
+
+ size_t count = GetItemCount();
+
+ if (width == wxLIST_AUTOSIZE_USEHEADER)
+ {
+ width = GetTextLength(column->GetText());
+ width += 2*EXTRA_WIDTH;
+
+ // check for column header's image availability
+ const int image = column->GetImage();
+ if ( image != -1 )
+ {
+ if ( m_small_image_list )
+ {
+ int ix = 0, iy = 0;
+ m_small_image_list->GetSize(image, ix, iy);
+ width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
+ }
+ }
+ }
+ else if ( width == wxLIST_AUTOSIZE )
+ {
+ if ( IsVirtual() )
+ {
+ // TODO: determine the max width somehow...
+ width = WIDTH_COL_DEFAULT;
+ }
+ else // !virtual
+ {
+ wxClientDC dc(this);
+ dc.SetFont( GetFont() );
+
+ int max = AUTOSIZE_COL_MARGIN;
+
+ // if the cached column width isn't valid then recalculate it
+ if (m_aColWidths.Item(col)->bNeedsUpdate)
+ {
+ for (size_t i = 0; i < count; i++)
+ {
+ wxListLineData *line = GetLine( i );
+ wxListItemDataList::compatibility_iterator n = line->m_items.Item( col );
+
+ wxCHECK_RET( n, _T("no subitem?") );
+
+ wxListItemData *itemData = n->GetData();
+ wxListItem item;
+
+ itemData->GetItem(item);
+ int itemWidth = GetItemWidthWithImage(&item);
+ if (itemWidth > max)
+ max = itemWidth;
+ }
+
+ m_aColWidths.Item(col)->bNeedsUpdate = false;
+ m_aColWidths.Item(col)->nMaxWidth = max;
+ }
+
+ max = m_aColWidths.Item(col)->nMaxWidth;
+ width = max + AUTOSIZE_COL_MARGIN;
+ }
+ }
+
+ column->SetWidth( width );
+
+ // invalidate it as it has to be recalculated
+ m_headerWidth = 0;
+}
+
+int wxListMainWindow::GetHeaderWidth() const
+{
+ if ( !m_headerWidth )
+ {
+ wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
+
+ size_t count = GetColumnCount();
+ for ( size_t col = 0; col < count; col++ )
+ {
+ self->m_headerWidth += GetColumnWidth(col);
+ }
+ }
+
+ return m_headerWidth;
+}
+
+void wxListMainWindow::GetColumn( int col, wxListItem &item ) const
+{
+ wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col );
+ wxCHECK_RET( node, _T("invalid column index in GetColumn") );
+
+ wxListHeaderData *column = node->GetData();
+ column->GetItem( item );
+}
+
+int wxListMainWindow::GetColumnWidth( int col ) const
+{
+ wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col );
+ wxCHECK_MSG( node, 0, _T("invalid column index") );
+
+ wxListHeaderData *column = node->GetData();
+ return column->GetWidth();
+}
+
+// ----------------------------------------------------------------------------
+// item state
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::SetItem( wxListItem &item )
+{
+ long id = item.m_itemId;
+ wxCHECK_RET( id >= 0 && (size_t)id < GetItemCount(),
+ _T("invalid item index in SetItem") );
+
+ if ( !IsVirtual() )
+ {
+ wxListLineData *line = GetLine((size_t)id);
+ line->SetItem( item.m_col, item );
+
+ // Set item state if user wants
+ if ( item.m_mask & wxLIST_MASK_STATE )
+ SetItemState( item.m_itemId, item.m_state, item.m_state );
+
+ if (InReportView())
+ {
+ // update the Max Width Cache if needed
+ int width = GetItemWidthWithImage(&item);
+
+ if (width > m_aColWidths.Item(item.m_col)->nMaxWidth)
+ m_aColWidths.Item(item.m_col)->nMaxWidth = width;
+ }
+ }
+
+ // update the item on screen
+ wxRect rectItem;
+ GetItemRect(id, rectItem);
+ RefreshRect(rectItem);
+}
+
+void wxListMainWindow::SetItemStateAll(long state, long stateMask)
+{
+ if ( IsEmpty() )
+ return;
+
+ // first deal with selection
+ if ( stateMask & wxLIST_STATE_SELECTED )
+ {
+ // set/clear select state
+ if ( IsVirtual() )
+ {
+ // optimized version for virtual listctrl.
+ m_selStore.SelectRange(0, GetItemCount() - 1, state == wxLIST_STATE_SELECTED);
+ Refresh();
+ }
+ else if ( state & wxLIST_STATE_SELECTED )
+ {
+ const long count = GetItemCount();
+ for( long i = 0; i < count; i++ )
+ {
+ SetItemState( i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
+ }
+
+ }
+ else
+ {
+ // clear for non virtual (somewhat optimized by using GetNextItem())
+ long i = -1;
+ while ( (i = GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != -1 )
+ {
+ SetItemState( i, 0, wxLIST_STATE_SELECTED );
+ }
+ }
+ }
+
+ if ( HasCurrent() && (state == 0) && (stateMask & wxLIST_STATE_FOCUSED) )
+ {
+ // unfocus all: only one item can be focussed, so clearing focus for
+ // all items is simply clearing focus of the focussed item.
+ SetItemState(m_current, state, stateMask);
+ }
+ //(setting focus to all items makes no sense, so it is not handled here.)
+}
+
+void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
+{
+ if ( litem == -1 )
+ {
+ SetItemStateAll(state, stateMask);
+ return;
+ }
+
+ wxCHECK_RET( litem >= 0 && (size_t)litem < GetItemCount(),
+ _T("invalid list ctrl item index in SetItem") );
+
+ size_t oldCurrent = m_current;
+ size_t item = (size_t)litem; // safe because of the check above
+
+ // do we need to change the focus?
+ if ( stateMask & wxLIST_STATE_FOCUSED )
+ {
+ if ( state & wxLIST_STATE_FOCUSED )
+ {
+ // don't do anything if this item is already focused
+ if ( item != m_current )
+ {
+ ChangeCurrent(item);
+
+ if ( oldCurrent != (size_t)-1 )
+ {
+ if ( IsSingleSel() )
+ {
+ HighlightLine(oldCurrent, false);
+ }
+
+ RefreshLine(oldCurrent);
+ }
+
+ RefreshLine( m_current );
+ }
+ }
+ else // unfocus
+ {
+ // don't do anything if this item is not focused
+ if ( item == m_current )
+ {
+ ResetCurrent();
+
+ if ( IsSingleSel() )
+ {
+ // we must unselect the old current item as well or we
+ // might end up with more than one selected item in a
+ // single selection control
+ HighlightLine(oldCurrent, false);
+ }
+
+ RefreshLine( oldCurrent );
+ }
+ }
+ }
+
+ // do we need to change the selection state?
+ if ( stateMask & wxLIST_STATE_SELECTED )
+ {
+ bool on = (state & wxLIST_STATE_SELECTED) != 0;
+
+ if ( IsSingleSel() )
+ {
+ if ( on )
+ {
+ // selecting the item also makes it the focused one in the
+ // single sel mode
+ if ( m_current != item )
+ {
+ ChangeCurrent(item);
+
+ if ( oldCurrent != (size_t)-1 )
+ {
+ HighlightLine( oldCurrent, false );
+ RefreshLine( oldCurrent );
+ }
+ }
+ }
+ else // off
+ {
+ // only the current item may be selected anyhow
+ if ( item != m_current )
+ return;
+ }
+ }
+
+ if ( HighlightLine(item, on) )
+ {
+ RefreshLine(item);
+ }
+ }
+}
+
+int wxListMainWindow::GetItemState( long item, long stateMask ) const
+{
+ wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0,
+ _T("invalid list ctrl item index in GetItemState()") );
+
+ int ret = wxLIST_STATE_DONTCARE;
+
+ if ( stateMask & wxLIST_STATE_FOCUSED )
+ {
+ if ( (size_t)item == m_current )
+ ret |= wxLIST_STATE_FOCUSED;
+ }
+
+ if ( stateMask & wxLIST_STATE_SELECTED )
+ {
+ if ( IsHighlighted(item) )
+ ret |= wxLIST_STATE_SELECTED;
+ }
+
+ return ret;
+}
+
+void wxListMainWindow::GetItem( wxListItem &item ) const
+{
+ wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(),
+ _T("invalid item index in GetItem") );
+
+ wxListLineData *line = GetLine((size_t)item.m_itemId);
+ line->GetItem( item.m_col, item );
+
+ // Get item state if user wants it
+ if ( item.m_mask & wxLIST_MASK_STATE )
+ item.m_state = GetItemState( item.m_itemId, wxLIST_STATE_SELECTED |
+ wxLIST_STATE_FOCUSED );
+}
+
+// ----------------------------------------------------------------------------
+// item count
+// ----------------------------------------------------------------------------
+
+size_t wxListMainWindow::GetItemCount() const
+{
+ return IsVirtual() ? m_countVirt : m_lines.GetCount();
+}
+
+void wxListMainWindow::SetItemCount(long count)
+{
+ m_selStore.SetItemCount(count);
+ m_countVirt = count;
+
+ ResetVisibleLinesRange();
+
+ // scrollbars must be reset
+ m_dirty = true;
+}
+
+int wxListMainWindow::GetSelectedItemCount() const
+{
+ // deal with the quick case first
+ if ( IsSingleSel() )
+ return HasCurrent() ? IsHighlighted(m_current) : false;
+
+ // virtual controls remmebers all its selections itself
+ if ( IsVirtual() )
+ return m_selStore.GetSelectedCount();
+
+ // TODO: we probably should maintain the number of items selected even for
+ // non virtual controls as enumerating all lines is really slow...
+ size_t countSel = 0;
+ size_t count = GetItemCount();
+ for ( size_t line = 0; line < count; line++ )
+ {
+ if ( GetLine(line)->IsHighlighted() )
+ countSel++;
+ }
+
+ return countSel;
+}
+
+// ----------------------------------------------------------------------------
+// item position/size
+// ----------------------------------------------------------------------------
+
+wxRect wxListMainWindow::GetViewRect() const
+{
+ wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
+ _T("wxListCtrl::GetViewRect() only works in icon mode") );
+
+ // we need to find the longest/tallest label
+ wxCoord xMax = 0, yMax = 0;
+ const int count = GetItemCount();
+ if ( count )
+ {
+ for ( int i = 0; i < count; i++ )
+ {
+ wxRect r;
+ GetItemRect(i, r);
+
+ wxCoord x = r.GetRight(),
+ y = r.GetBottom();
+
+ if ( x > xMax )
+ xMax = x;
+ if ( y > yMax )
+ yMax = y;
+ }
+ }
+
+ // some fudge needed to make it look prettier
+ xMax += 2 * EXTRA_BORDER_X;
+ yMax += 2 * EXTRA_BORDER_Y;
+
+ // account for the scrollbars if necessary
+ const wxSize sizeAll = GetClientSize();
+ if ( xMax > sizeAll.x )
+ yMax += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
+ if ( yMax > sizeAll.y )
+ xMax += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
+
+ return wxRect(0, 0, xMax, yMax);
+}
+
+void wxListMainWindow::GetItemRect( long index, wxRect &rect ) const
+{
+ wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
+ _T("invalid index in GetItemRect") );
+
+ // ensure that we're laid out, otherwise we could return nonsense
+ if ( m_dirty )
+ {
+ wxConstCast(this, wxListMainWindow)->
+ RecalculatePositions(true /* no refresh */);
+ }
+
+ rect = GetLineRect((size_t)index);
+
+ CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
+}
+
+bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos) const
+{
+ wxRect rect;
+ GetItemRect(item, rect);
+
+ pos.x = rect.x;
+ pos.y = rect.y;
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// geometry calculation
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::RecalculatePositions(bool noRefresh)
+{
+ const int lineHeight = GetLineHeight();
+
+ wxClientDC dc( this );
+ dc.SetFont( GetFont() );
+
+ const size_t count = GetItemCount();
+
+ int iconSpacing;
+ if ( HasFlag(wxLC_ICON) )
+ iconSpacing = m_normal_spacing;
+ else if ( HasFlag(wxLC_SMALL_ICON) )
+ iconSpacing = m_small_spacing;
+ else
+ iconSpacing = 0;
+
+ // Note that we do not call GetClientSize() here but
+ // GetSize() and subtract the border size for sunken
+ // borders manually. This is technically incorrect,
+ // but we need to know the client area's size WITHOUT
+ // scrollbars here. Since we don't know if there are
+ // any scrollbars, we use GetSize() instead. Another
+ // solution would be to call SetScrollbars() here to
+ // remove the scrollbars and call GetClientSize() then,
+ // but this might result in flicker and - worse - will
+ // reset the scrollbars to 0 which is not good at all
+ // if you resize a dialog/window, but don't want to
+ // reset the window scrolling. RR.
+ // Furthermore, we actually do NOT subtract the border
+ // width as 2 pixels is just the extra space which we
+ // need around the actual content in the window. Other-
+ // wise the text would e.g. touch the upper border. RR.
+ int clientWidth,
+ clientHeight;
+ GetSize( &clientWidth, &clientHeight );
+
+ if ( InReportView() )
+ {
+ // all lines have the same height and we scroll one line per step
+ int entireHeight = count * lineHeight + LINE_SPACING;
+
+ m_linesPerPage = clientHeight / lineHeight;
+
+ ResetVisibleLinesRange();
+
+ SetScrollbars( SCROLL_UNIT_X, lineHeight,
+ GetHeaderWidth() / SCROLL_UNIT_X,
+ (entireHeight + lineHeight - 1) / lineHeight,
+ GetScrollPos(wxHORIZONTAL),
+ GetScrollPos(wxVERTICAL),
+ true );
+ }
+ else // !report
+ {
+ // we have 3 different layout strategies: either layout all items
+ // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or
+ // to arrange them in top to bottom, left to right (don't ask me why
+ // not the other way round...) order
+ if ( HasFlag(wxLC_ALIGN_LEFT | wxLC_ALIGN_TOP) )
+ {
+ int x = EXTRA_BORDER_X;
+ int y = EXTRA_BORDER_Y;
+
+ wxCoord widthMax = 0;
+
+ size_t i;
+ for ( i = 0; i < count; i++ )
+ {
+ wxListLineData *line = GetLine(i);
+ line->CalculateSize( &dc, iconSpacing );
+ line->SetPosition( x, y, iconSpacing );
+
+ wxSize sizeLine = GetLineSize(i);
+
+ if ( HasFlag(wxLC_ALIGN_TOP) )
+ {
+ if ( sizeLine.x > widthMax )
+ widthMax = sizeLine.x;
+
+ y += sizeLine.y;
+ }
+ else // wxLC_ALIGN_LEFT
+ {
+ x += sizeLine.x + MARGIN_BETWEEN_ROWS;
+ }
+ }
+
+ if ( HasFlag(wxLC_ALIGN_TOP) )
+ {
+ // traverse the items again and tweak their sizes so that they are
+ // all the same in a row
+ for ( i = 0; i < count; i++ )
+ {
+ wxListLineData *line = GetLine(i);
+ line->m_gi->ExtendWidth(widthMax);
+ }
+ }
+
+ SetScrollbars
+ (
+ SCROLL_UNIT_X,
+ lineHeight,
+ (x + SCROLL_UNIT_X) / SCROLL_UNIT_X,
+ (y + lineHeight) / lineHeight,
+ GetScrollPos( wxHORIZONTAL ),
+ GetScrollPos( wxVERTICAL ),
+ true
+ );
+ }
+ else // "flowed" arrangement, the most complicated case
+ {
+ // at first we try without any scrollbars, if the items don't fit into
+ // the window, we recalculate after subtracting the space taken by the
+ // scrollbar
+
+ int entireWidth = 0;
+
+ for (int tries = 0; tries < 2; tries++)
+ {
+ entireWidth = 2 * EXTRA_BORDER_X;
+
+ if (tries == 1)
+ {
+ // Now we have decided that the items do not fit into the
+ // client area, so we need a scrollbar
+ entireWidth += SCROLL_UNIT_X;
+ }
+
+ int x = EXTRA_BORDER_X;
+ int y = EXTRA_BORDER_Y;
+ int maxWidthInThisRow = 0;
+
+ m_linesPerPage = 0;
+ int currentlyVisibleLines = 0;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ currentlyVisibleLines++;
+ wxListLineData *line = GetLine( i );
+ line->CalculateSize( &dc, iconSpacing );
+ line->SetPosition( x, y, iconSpacing );
+
+ wxSize sizeLine = GetLineSize( i );
+
+ if ( maxWidthInThisRow < sizeLine.x )
+ maxWidthInThisRow = sizeLine.x;
+
+ y += sizeLine.y;
+ if (currentlyVisibleLines > m_linesPerPage)
+ m_linesPerPage = currentlyVisibleLines;
+
+ if ( y + sizeLine.y >= clientHeight )
+ {
+ currentlyVisibleLines = 0;
+ y = EXTRA_BORDER_Y;
+ maxWidthInThisRow += MARGIN_BETWEEN_ROWS;
+ x += maxWidthInThisRow;
+ entireWidth += maxWidthInThisRow;
+ maxWidthInThisRow = 0;
+ }
+
+ // We have reached the last item.
+ if ( i == count - 1 )
+ entireWidth += maxWidthInThisRow;
+
+ if ( (tries == 0) &&
+ (entireWidth + SCROLL_UNIT_X > clientWidth) )
+ {
+ clientHeight -= wxSystemSettings::
+ GetMetric(wxSYS_HSCROLL_Y);
+ m_linesPerPage = 0;
+ break;
+ }
+
+ if ( i == count - 1 )
+ tries = 1; // Everything fits, no second try required.
+ }
+ }
+
+ SetScrollbars
+ (
+ SCROLL_UNIT_X,
+ lineHeight,
+ (entireWidth + SCROLL_UNIT_X) / SCROLL_UNIT_X,
+ 0,
+ GetScrollPos( wxHORIZONTAL ),
+ 0,
+ true
+ );
+ }
+ }
+
+ if ( !noRefresh )
+ {
+ // FIXME: why should we call it from here?
+ UpdateCurrent();
+
+ RefreshAll();
+ }
+}
+
+void wxListMainWindow::RefreshAll()
+{
+ m_dirty = false;
+ Refresh();
+
+ wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
+ if ( headerWin && headerWin->m_dirty )
+ {
+ headerWin->m_dirty = false;
+ headerWin->Refresh();
+ }
+}
+
+void wxListMainWindow::UpdateCurrent()
+{
+ if ( !HasCurrent() && !IsEmpty() )
+ ChangeCurrent(0);
+}
+
+long wxListMainWindow::GetNextItem( long item,
+ int WXUNUSED(geometry),
+ int state ) const
+{
+ long ret = item,
+ max = GetItemCount();
+ wxCHECK_MSG( (ret == -1) || (ret < max), -1,
+ _T("invalid listctrl index in GetNextItem()") );
+
+ // notice that we start with the next item (or the first one if item == -1)
+ // and this is intentional to allow writing a simple loop to iterate over
+ // all selected items
+ ret++;
+ if ( ret == max )
+ // this is not an error because the index was OK initially,
+ // just no such item
+ return -1;
+
+ if ( !state )
+ // any will do
+ return (size_t)ret;
+
+ size_t count = GetItemCount();
+ for ( size_t line = (size_t)ret; line < count; line++ )
+ {
+ if ( (state & wxLIST_STATE_FOCUSED) && (line == m_current) )
+ return line;
+
+ if ( (state & wxLIST_STATE_SELECTED) && IsHighlighted(line) )
+ return line;
+ }
+
+ return -1;
+}
+
+// ----------------------------------------------------------------------------
+// deleting stuff
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::DeleteItem( long lindex )
+{
+ size_t count = GetItemCount();
+
+ wxCHECK_RET( (lindex >= 0) && ((size_t)lindex < count),
+ _T("invalid item index in DeleteItem") );
+
+ size_t index = (size_t)lindex;
+
+ // we don't need to adjust the index for the previous items
+ if ( HasCurrent() && m_current >= index )
+ {
+ // if the current item is being deleted, we want the next one to
+ // become selected - unless there is no next one - so don't adjust
+ // m_current in this case
+ if ( m_current != index || m_current == count - 1 )
+ m_current--;
+ }
+
+ if ( InReportView() )
+ {
+ // mark the Column Max Width cache as dirty if the items in the line
+ // we're deleting contain the Max Column Width
+ wxListLineData * const line = GetLine(index);
+ wxListItemDataList::compatibility_iterator n;
+ wxListItemData *itemData;
+ wxListItem item;
+ int itemWidth;
+
+ for (size_t i = 0; i < m_columns.GetCount(); i++)
+ {
+ n = line->m_items.Item( i );
+ itemData = n->GetData();
+ itemData->GetItem(item);
+
+ itemWidth = GetItemWidthWithImage(&item);
+
+ if (itemWidth >= m_aColWidths.Item(i)->nMaxWidth)
+ m_aColWidths.Item(i)->bNeedsUpdate = true;
+ }
+
+ ResetVisibleLinesRange();
+ }
+
+ SendNotify( index, wxEVT_COMMAND_LIST_DELETE_ITEM, wxDefaultPosition );
+
+ if ( IsVirtual() )
+ {
+ m_countVirt--;
+ m_selStore.OnItemDelete(index);
+ }
+ else
+ {
+ m_lines.RemoveAt( index );
+ }
+
+ // we need to refresh the (vert) scrollbar as the number of items changed
+ m_dirty = true;
+
+ RefreshAfter(index);
+}
+
+void wxListMainWindow::DeleteColumn( int col )
+{
+ wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col );
+
+ wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") );
+
+ m_dirty = true;
+ delete node->GetData();
+ m_columns.Erase( node );
+
+ if ( !IsVirtual() )
+ {
+ // update all the items
+ for ( size_t i = 0; i < m_lines.GetCount(); i++ )
+ {
+ wxListLineData * const line = GetLine(i);
+ wxListItemDataList::compatibility_iterator n = line->m_items.Item( col );
+ delete n->GetData();
+ line->m_items.Erase(n);
+ }
+ }
+
+ if ( InReportView() ) // we only cache max widths when in Report View
+ {
+ delete m_aColWidths.Item(col);
+ m_aColWidths.RemoveAt(col);
+ }
+
+ // invalidate it as it has to be recalculated
+ m_headerWidth = 0;
+}
+
+void wxListMainWindow::DoDeleteAllItems()
+{
+ if ( IsEmpty() )
+ // nothing to do - in particular, don't send the event
+ return;
+
+ ResetCurrent();
+
+ // to make the deletion of all items faster, we don't send the
+ // notifications for each item deletion in this case but only one event
+ // for all of them: this is compatible with wxMSW and documented in
+ // DeleteAllItems() description
+
+ wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetParent()->GetId() );
+ event.SetEventObject( GetParent() );
+ GetParent()->GetEventHandler()->ProcessEvent( event );
+
+ if ( IsVirtual() )
+ {
+ m_countVirt = 0;
+ m_selStore.Clear();
+ }
+
+ if ( InReportView() )
+ {
+ ResetVisibleLinesRange();
+ for (size_t i = 0; i < m_aColWidths.GetCount(); i++)
+ {
+ m_aColWidths.Item(i)->bNeedsUpdate = true;
+ }
+ }
+
+ m_lines.Clear();
+}
+
+void wxListMainWindow::DeleteAllItems()
+{
+ DoDeleteAllItems();
+
+ RecalculatePositions();
+}
+
+void wxListMainWindow::DeleteEverything()
+{
+ WX_CLEAR_LIST(wxListHeaderDataList, m_columns);
+ WX_CLEAR_ARRAY(m_aColWidths);
+
+ DeleteAllItems();
+}
+
+// ----------------------------------------------------------------------------
+// scanning for an item
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::EnsureVisible( long index )
+{
+ wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
+ _T("invalid index in EnsureVisible") );
+
+ // We have to call this here because the label in question might just have
+ // been added and its position is not known yet
+ if ( m_dirty )
+ RecalculatePositions(true /* no refresh */);
+
+ MoveToItem((size_t)index);
+}
+
+long wxListMainWindow::FindItem(long start, const wxString& str, bool partial )
+{
+ if (str.empty())
+ return wxNOT_FOUND;
+
+ long pos = start;
+ wxString str_upper = str.Upper();
+ if (pos < 0)
+ pos = 0;
+
+ size_t count = GetItemCount();
+ for ( size_t i = (size_t)pos; i < count; i++ )
+ {
+ wxListLineData *line = GetLine(i);
+ wxString line_upper = line->GetText(0).Upper();
+ if (!partial)
+ {
+ if (line_upper == str_upper )
+ return i;
+ }
+ else
+ {
+ if (line_upper.find(str_upper) == 0)
+ return i;
+ }
+ }
+
+ return wxNOT_FOUND;
+}
+
+long wxListMainWindow::FindItem(long start, wxUIntPtr data)
+{
+ long pos = start;
+ if (pos < 0)
+ pos = 0;
+
+ size_t count = GetItemCount();
+ for (size_t i = (size_t)pos; i < count; i++)
+ {
+ wxListLineData *line = GetLine(i);
+ wxListItem item;
+ line->GetItem( 0, item );
+ if (item.m_data == data)
+ return i;
+ }
+
+ return wxNOT_FOUND;
+}
+
+long wxListMainWindow::FindItem( const wxPoint& pt )
+{
+ size_t topItem;
+ GetVisibleLinesRange( &topItem, NULL );
+
+ wxPoint p;
+ GetItemPosition( GetItemCount() - 1, p );
+ if ( p.y == 0 )
+ return topItem;
+
+ long id = (long)floor( pt.y * double(GetItemCount() - topItem - 1) / p.y + topItem );
+ if ( id >= 0 && id < (long)GetItemCount() )
+ return id;
+
+ return wxNOT_FOUND;
+}
+
+long wxListMainWindow::HitTest( int x, int y, int &flags ) const
+{
+ CalcUnscrolledPosition( x, y, &x, &y );
+
+ size_t count = GetItemCount();
+
+ if ( InReportView() )
+ {
+ size_t current = y / GetLineHeight();
+ if ( current < count )
+ {
+ flags = HitTestLine(current, x, y);
+ if ( flags )
+ return current;
+ }
+ }
+ else // !report
+ {
+ // TODO: optimize it too! this is less simple than for report view but
+ // enumerating all items is still not a way to do it!!
+ for ( size_t current = 0; current < count; current++ )
+ {
+ flags = HitTestLine(current, x, y);
+ if ( flags )
+ return current;
+ }
+ }
+
+ return wxNOT_FOUND;
+}
+
+// ----------------------------------------------------------------------------
+// adding stuff
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::InsertItem( wxListItem &item )
+{
+ wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
+
+ int count = GetItemCount();
+ wxCHECK_RET( item.m_itemId >= 0, _T("invalid item index") );
+
+ if (item.m_itemId > count)
+ item.m_itemId = count;
+
+ size_t id = item.m_itemId;
+
+ m_dirty = true;
+
+ if ( InReportView() )
+ {
+ ResetVisibleLinesRange();
+
+ // calculate the width of the item and adjust the max column width
+ wxColWidthInfo *pWidthInfo = m_aColWidths.Item(item.GetColumn());
+ int width = GetItemWidthWithImage(&item);
+ item.SetWidth(width);
+ if (width > pWidthInfo->nMaxWidth)
+ pWidthInfo->nMaxWidth = width;
+ }
+
+ wxListLineData *line = new wxListLineData(this);
+
+ line->SetItem( item.m_col, item );
+
+ m_lines.Insert( line, id );
+
+ m_dirty = true;
+
+ // If an item is selected at or below the point of insertion, we need to
+ // increment the member variables because the current row's index has gone
+ // up by one
+ if ( HasCurrent() && m_current >= id )
+ m_current++;
+
+ SendNotify(id, wxEVT_COMMAND_LIST_INSERT_ITEM);
+
+ RefreshLines(id, GetItemCount() - 1);
+}
+
+void wxListMainWindow::InsertColumn( long col, wxListItem &item )
+{
+ m_dirty = true;
+ if ( InReportView() )
+ {
+ if (item.m_width == wxLIST_AUTOSIZE_USEHEADER)
+ item.m_width = GetTextLength( item.m_text );
+
+ wxListHeaderData *column = new wxListHeaderData( item );
+ wxColWidthInfo *colWidthInfo = new wxColWidthInfo();
+
+ bool insert = (col >= 0) && ((size_t)col < m_columns.GetCount());
+ if ( insert )
+ {
+ wxListHeaderDataList::compatibility_iterator
+ node = m_columns.Item( col );
+ m_columns.Insert( node, column );
+ m_aColWidths.Insert( colWidthInfo, col );
+ }
+ else
+ {
+ m_columns.Append( column );
+ m_aColWidths.Add( colWidthInfo );
+ }
+
+ if ( !IsVirtual() )
+ {
+ // update all the items
+ for ( size_t i = 0; i < m_lines.GetCount(); i++ )
+ {
+ wxListLineData * const line = GetLine(i);
+ wxListItemData * const data = new wxListItemData(this);
+ if ( insert )
+ line->m_items.Insert(col, data);
+ else
+ line->m_items.Append(data);
+ }
+ }
+
+ // invalidate it as it has to be recalculated
+ m_headerWidth = 0;
+ }
+}
+
+int wxListMainWindow::GetItemWidthWithImage(wxListItem * item)
+{
+ int width = 0;
+ wxClientDC dc(this);
+
+ dc.SetFont( GetFont() );
+
+ if (item->GetImage() != -1)
+ {
+ int ix, iy;
+ GetImageSize( item->GetImage(), ix, iy );
+ width += ix + 5;
+ }
+
+ if (!item->GetText().empty())
+ {
+ wxCoord w;
+ dc.GetTextExtent( item->GetText(), &w, NULL );
+ width += w;
+ }
+
+ return width;
+}
+
+// ----------------------------------------------------------------------------
+// sorting
+// ----------------------------------------------------------------------------
+
+wxListCtrlCompare list_ctrl_compare_func_2;
+long list_ctrl_compare_data;
+
+int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData **arg2 )
+{
+ wxListLineData *line1 = *arg1;
+ wxListLineData *line2 = *arg2;
+ wxListItem item;
+ line1->GetItem( 0, item );
+ wxUIntPtr data1 = item.m_data;
+ line2->GetItem( 0, item );
+ wxUIntPtr data2 = item.m_data;
+ return list_ctrl_compare_func_2( data1, data2, list_ctrl_compare_data );
+}
+
+void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
+{
+ // selections won't make sense any more after sorting the items so reset
+ // them
+ HighlightAll(false);
+ ResetCurrent();
+
+ list_ctrl_compare_func_2 = fn;
+ list_ctrl_compare_data = data;
+ m_lines.Sort( list_ctrl_compare_func_1 );
+ m_dirty = true;
+}
+
+// ----------------------------------------------------------------------------
+// scrolling
+// ----------------------------------------------------------------------------
+
+void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
+{
+ // FIXME
+#if ( defined(__WXGTK__) || defined(__WXMAC__) ) && !defined(__WXUNIVERSAL__)
+ wxScrolledWindow::OnScroll(event);
+#else
+ HandleOnScroll( event );
+#endif
+
+ // update our idea of which lines are shown when we redraw the window the
+ // next time
+ ResetVisibleLinesRange();
+
+ if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() )
+ {
+ wxGenericListCtrl* lc = GetListCtrl();
+ wxCHECK_RET( lc, _T("no listctrl window?") );
+
+ lc->m_headerWin->Refresh();
+ lc->m_headerWin->Update();
+ }
+}
+
+int wxListMainWindow::GetCountPerPage() const
+{
+ if ( !m_linesPerPage )
+ {
+ wxConstCast(this, wxListMainWindow)->
+ m_linesPerPage = GetClientSize().y / GetLineHeight();
+ }
+
+ return m_linesPerPage;
+}
+
+void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
+{
+ wxASSERT_MSG( InReportView(), _T("this is for report mode only") );
+
+ if ( m_lineFrom == (size_t)-1 )
+ {
+ size_t count = GetItemCount();
+ if ( count )
+ {
+ m_lineFrom = GetScrollPos(wxVERTICAL);
+
+ // this may happen if SetScrollbars() hadn't been called yet
+ if ( m_lineFrom >= count )
+ m_lineFrom = count - 1;
+
+ // we redraw one extra line but this is needed to make the redrawing
+ // logic work when there is a fractional number of lines on screen
+ m_lineTo = m_lineFrom + m_linesPerPage;
+ if ( m_lineTo >= count )
+ m_lineTo = count - 1;
+ }
+ else // empty control
+ {
+ m_lineFrom = 0;
+ m_lineTo = (size_t)-1;
+ }
+ }
+
+ wxASSERT_MSG( IsEmpty() ||
+ (m_lineFrom <= m_lineTo && m_lineTo < GetItemCount()),
+ _T("GetVisibleLinesRange() returns incorrect result") );
+
+ if ( from )
+ *from = m_lineFrom;
+ if ( to )
+ *to = m_lineTo;
+}
+
+// -------------------------------------------------------------------------------------
+// wxGenericListCtrl
+// -------------------------------------------------------------------------------------
+BEGIN_EVENT_TABLE(wxGenericListCtrl,wxControl)
+ EVT_SIZE(wxGenericListCtrl::OnSize)
+END_EVENT_TABLE()
+
+wxGenericListCtrl::wxGenericListCtrl()
+{
+ m_imageListNormal = (wxImageList *) NULL;
+ m_imageListSmall = (wxImageList *) NULL;
+ m_imageListState = (wxImageList *) NULL;
+
+ m_ownsImageListNormal =
+ m_ownsImageListSmall =
+ m_ownsImageListState = false;
+
+ m_mainWin = (wxListMainWindow*) NULL;
+ m_headerWin = (wxListHeaderWindow*) NULL;
+ m_headerHeight = 0;
+}
+
+wxGenericListCtrl::~wxGenericListCtrl()
+{
+ if (m_ownsImageListNormal)
+ delete m_imageListNormal;
+ if (m_ownsImageListSmall)
+ delete m_imageListSmall;
+ if (m_ownsImageListState)
+ delete m_imageListState;
+}
+
+void wxGenericListCtrl::CalculateAndSetHeaderHeight()
+{
+ if ( m_headerWin )
+ {
+#ifdef __WXMAC__
+ SInt32 h;
+ GetThemeMetric( kThemeMetricListHeaderHeight, &h );
+#else
+ // we use 'g' to get the descent, too
+ int w, h, d;
+ m_headerWin->GetTextExtent(wxT("Hg"), &w, &h, &d);
+ h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
+#endif
+
+ // only update if changed
+ if ( h != m_headerHeight )
+ {
+ m_headerHeight = h;
+
+ if ( HasHeader() )
+ ResizeReportView(true);
+ else //why is this needed if it doesn't have a header?
+ m_headerWin->SetSize(m_headerWin->GetSize().x, m_headerHeight);
+ }
+ }
+}
+
+void wxGenericListCtrl::CreateHeaderWindow()
+{
+ m_headerWin = new wxListHeaderWindow
+ (
+ this, wxID_ANY, m_mainWin,
+ wxPoint(0,0),
+ wxSize(GetClientSize().x, m_headerHeight),
+ wxTAB_TRAVERSAL
+ );
+ CalculateAndSetHeaderHeight();
+}
+
+bool wxGenericListCtrl::Create(wxWindow *parent,
+ wxWindowID id,
+ const wxPoint &pos,
+ const wxSize &size,
+ long style,
+ const wxValidator &validator,
+ const wxString &name)
+{
+ m_imageListNormal =
+ m_imageListSmall =
+ m_imageListState = (wxImageList *) NULL;
+ m_ownsImageListNormal =
+ m_ownsImageListSmall =
+ m_ownsImageListState = false;
+
+ m_mainWin = (wxListMainWindow*) NULL;
+ m_headerWin = (wxListHeaderWindow*) NULL;
+
+ m_headerHeight = 0;
+
+ if ( !(style & wxLC_MASK_TYPE) )
+ {
+ style = style | wxLC_LIST;
+ }
+
+ // add more styles here that should only appear
+ // in the main window
+ unsigned long only_main_window_style = wxALWAYS_SHOW_SB;
+
+ if ( !wxControl::Create( parent, id, pos, size, style & ~only_main_window_style, validator, name ) )
+ return false;
+
+ // don't create the inner window with the border
+ style &= ~wxBORDER_MASK;
+
+ m_mainWin = new wxListMainWindow( this, wxID_ANY, wxPoint(0, 0), size, style );
+
+#ifdef __WXMAC_CARBON__
+ // Human Interface Guidelines ask us for a special font in this case
+ if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL )
+ {
+ wxFont font;
+ font.MacCreateThemeFont( kThemeViewsFont );
+ SetFont( font );
+ }
+#endif
+
+ if ( InReportView() )
+ {
+ CreateHeaderWindow();
+
+#ifdef __WXMAC_CARBON__
+ if (m_headerWin)
+ {
+ wxFont font;
+ font.MacCreateThemeFont( kThemeSmallSystemFont );
+ m_headerWin->SetFont( font );
+ CalculateAndSetHeaderHeight();
+ }
+#endif
+
+ if ( HasFlag(wxLC_NO_HEADER) )
+ // VZ: why do we create it at all then?
+ m_headerWin->Show( false );
+ }
+
+ SetInitialSize(size);
+
+ return true;
+}
+
+void wxGenericListCtrl::SetSingleStyle( long style, bool add )
+{
+ wxASSERT_MSG( !(style & wxLC_VIRTUAL),
+ _T("wxLC_VIRTUAL can't be [un]set") );
+
+ long flag = GetWindowStyle();
+
+ if (add)
+ {
+ if (style & wxLC_MASK_TYPE)
+ flag &= ~(wxLC_MASK_TYPE | wxLC_VIRTUAL);
+ if (style & wxLC_MASK_ALIGN)
+ flag &= ~wxLC_MASK_ALIGN;
+ if (style & wxLC_MASK_SORT)
+ flag &= ~wxLC_MASK_SORT;
+ }
+
+ if (add)
+ flag |= style;
+ else
+ flag &= ~style;
+
+ SetWindowStyleFlag( flag );
+}
+
+void wxGenericListCtrl::SetWindowStyleFlag( long flag )
+{
+ if (m_mainWin)
+ {
+ m_mainWin->DeleteEverything();
+
+ // has the header visibility changed?
+ bool hasHeader = HasHeader();
+ bool willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER);
+
+ if ( hasHeader != willHaveHeader )
+ {
+ // toggle it
+ if ( hasHeader )
+ {
+ if ( m_headerWin )
+ {
+ // don't delete, just hide, as we can reuse it later
+ m_headerWin->Show(false);
+ }
+ //else: nothing to do
+ }
+ else // must show header
+ {
+ if (!m_headerWin)
+ {
+ CreateHeaderWindow();
+ }
+ else // already have it, just show
+ {
+ m_headerWin->Show( true );
+ }
+ }
+
+ ResizeReportView(willHaveHeader);
+ }
+ }
+
+ wxWindow::SetWindowStyleFlag( flag );
+}
+
+bool wxGenericListCtrl::GetColumn(int col, wxListItem &item) const
+{
+ m_mainWin->GetColumn( col, item );
+ return true;
+}
+
+bool wxGenericListCtrl::SetColumn( int col, wxListItem& item )
+{
+ m_mainWin->SetColumn( col, item );
+ return true;
+}
+
+int wxGenericListCtrl::GetColumnWidth( int col ) const
+{
+ return m_mainWin->GetColumnWidth( col );
+}
+
+bool wxGenericListCtrl::SetColumnWidth( int col, int width )
+{
+ m_mainWin->SetColumnWidth( col, width );
+ return true;
+}
+
+int wxGenericListCtrl::GetCountPerPage() const
+{
+ return m_mainWin->GetCountPerPage(); // different from Windows ?
+}
+
+bool wxGenericListCtrl::GetItem( wxListItem &info ) const
+{
+ m_mainWin->GetItem( info );
+ return true;
+}
+
+bool wxGenericListCtrl::SetItem( wxListItem &info )
+{
+ m_mainWin->SetItem( info );
+ return true;
+}
+
+long wxGenericListCtrl::SetItem( long index, int col, const wxString& label, int imageId )
+{
+ wxListItem info;
+ info.m_text = label;
+ info.m_mask = wxLIST_MASK_TEXT;
+ info.m_itemId = index;
+ info.m_col = col;
+ if ( imageId > -1 )
+ {
+ info.m_image = imageId;
+ info.m_mask |= wxLIST_MASK_IMAGE;
+ }
+
+ m_mainWin->SetItem(info);
+ return true;
+}
+
+int wxGenericListCtrl::GetItemState( long item, long stateMask ) const
+{
+ return m_mainWin->GetItemState( item, stateMask );
+}
+
+bool wxGenericListCtrl::SetItemState( long item, long state, long stateMask )
+{
+ m_mainWin->SetItemState( item, state, stateMask );
+ return true;
+}
+
+bool
+wxGenericListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) )
+{
+ return SetItemColumnImage(item, 0, image);
+}
+
+bool
+wxGenericListCtrl::SetItemColumnImage( long item, long column, int image )
+{
+ wxListItem info;
+ info.m_image = image;
+ info.m_mask = wxLIST_MASK_IMAGE;
+ info.m_itemId = item;
+ info.m_col = column;
+ m_mainWin->SetItem( info );
+ return true;
+}
+
+wxString wxGenericListCtrl::GetItemText( long item ) const
+{
+ return m_mainWin->GetItemText(item);
+}
+
+void wxGenericListCtrl::SetItemText( long item, const wxString& str )
+{
+ m_mainWin->SetItemText(item, str);
+}
+
+wxUIntPtr wxGenericListCtrl::GetItemData( long item ) const
+{
+ wxListItem info;
+ info.m_mask = wxLIST_MASK_DATA;
+ info.m_itemId = item;
+ m_mainWin->GetItem( info );
+ return info.m_data;
+}
+
+bool wxGenericListCtrl::SetItemPtrData( long item, wxUIntPtr data )
+{
+ wxListItem info;
+ info.m_mask = wxLIST_MASK_DATA;
+ info.m_itemId = item;
+ info.m_data = data;
+ m_mainWin->SetItem( info );
+ return true;
+}
+
+bool wxGenericListCtrl::SetItemData(long item, long data)
+{
+ return SetItemPtrData(item, data);
+}
+
+wxRect wxGenericListCtrl::GetViewRect() const
+{
+ return m_mainWin->GetViewRect();
+}
+
+bool wxGenericListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const
+{
+ m_mainWin->GetItemRect( item, rect );
+ if ( m_mainWin->HasHeader() )
+ rect.y += m_headerHeight + 1;
+ return true;
+}
+
+bool wxGenericListCtrl::GetItemPosition( long item, wxPoint& pos ) const
+{
+ m_mainWin->GetItemPosition( item, pos );
+ return true;
+}
+
+bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) )
+{
+ return 0;
+}
+
+int wxGenericListCtrl::GetItemCount() const
+{
+ return m_mainWin->GetItemCount();
+}
+
+int wxGenericListCtrl::GetColumnCount() const
+{
+ return m_mainWin->GetColumnCount();
+}
+
+void wxGenericListCtrl::SetItemSpacing( int spacing, bool isSmall )
+{
+ m_mainWin->SetItemSpacing( spacing, isSmall );
+}
+
+wxSize wxGenericListCtrl::GetItemSpacing() const
+{
+ const int spacing = m_mainWin->GetItemSpacing(HasFlag(wxLC_SMALL_ICON));
+
+ return wxSize(spacing, spacing);
+}
+
+#if WXWIN_COMPATIBILITY_2_6
+int wxGenericListCtrl::GetItemSpacing( bool isSmall ) const
+{
+ return m_mainWin->GetItemSpacing( isSmall );
+}
+#endif // WXWIN_COMPATIBILITY_2_6
+
+void wxGenericListCtrl::SetItemTextColour( long item, const wxColour &col )
+{
+ wxListItem info;
+ info.m_itemId = item;
+ info.SetTextColour( col );
+ m_mainWin->SetItem( info );
+}
+
+wxColour wxGenericListCtrl::GetItemTextColour( long item ) const
+{
+ wxListItem info;
+ info.m_itemId = item;
+ m_mainWin->GetItem( info );
+ return info.GetTextColour();
+}
+
+void wxGenericListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
+{
+ wxListItem info;
+ info.m_itemId = item;
+ info.SetBackgroundColour( col );
+ m_mainWin->SetItem( info );
+}
+
+wxColour wxGenericListCtrl::GetItemBackgroundColour( long item ) const
+{
+ wxListItem info;
+ info.m_itemId = item;
+ m_mainWin->GetItem( info );
+ return info.GetBackgroundColour();
+}
+
+int wxGenericListCtrl::GetScrollPos( int orient ) const
+{
+ return m_mainWin->GetScrollPos( orient );
+}
+
+void wxGenericListCtrl::SetScrollPos( int orient, int pos, bool refresh )
+{
+ m_mainWin->SetScrollPos( orient, pos, refresh );
+}
+
+void wxGenericListCtrl::SetItemFont( long item, const wxFont &f )
+{
+ wxListItem info;
+ info.m_itemId = item;
+ info.SetFont( f );
+ m_mainWin->SetItem( info );
+}
+
+wxFont wxGenericListCtrl::GetItemFont( long item ) const
+{
+ wxListItem info;
+ info.m_itemId = item;
+ m_mainWin->GetItem( info );
+ return info.GetFont();
+}
+
+int wxGenericListCtrl::GetSelectedItemCount() const
+{
+ return m_mainWin->GetSelectedItemCount();
+}
+
+wxColour wxGenericListCtrl::GetTextColour() const
+{
+ return GetForegroundColour();
+}
+
+void wxGenericListCtrl::SetTextColour(const wxColour& col)
+{
+ SetForegroundColour(col);
+}
+
+long wxGenericListCtrl::GetTopItem() const
+{
+ size_t top;
+ m_mainWin->GetVisibleLinesRange(&top, NULL);
+ return (long)top;
+}
+
+long wxGenericListCtrl::GetNextItem( long item, int geom, int state ) const
+{
+ return m_mainWin->GetNextItem( item, geom, state );
+}
+
+wxImageList *wxGenericListCtrl::GetImageList(int which) const
+{
+ if (which == wxIMAGE_LIST_NORMAL)
+ return m_imageListNormal;
+ else if (which == wxIMAGE_LIST_SMALL)
+ return m_imageListSmall;
+ else if (which == wxIMAGE_LIST_STATE)
+ return m_imageListState;
+
+ return (wxImageList *) NULL;
+}
+
+void wxGenericListCtrl::SetImageList( wxImageList *imageList, int which )
+{
+ if ( which == wxIMAGE_LIST_NORMAL )
+ {
+ if (m_ownsImageListNormal)
+ delete m_imageListNormal;
+ m_imageListNormal = imageList;
+ m_ownsImageListNormal = false;
+ }
+ else if ( which == wxIMAGE_LIST_SMALL )
+ {
+ if (m_ownsImageListSmall)
+ delete m_imageListSmall;
+ m_imageListSmall = imageList;
+ m_ownsImageListSmall = false;
+ }
+ else if ( which == wxIMAGE_LIST_STATE )
+ {
+ if (m_ownsImageListState)
+ delete m_imageListState;
+ m_imageListState = imageList;
+ m_ownsImageListState = false;
+ }
+
+ m_mainWin->SetImageList( imageList, which );
+}
+
+void wxGenericListCtrl::AssignImageList(wxImageList *imageList, int which)
+{
+ SetImageList(imageList, which);
+ if ( which == wxIMAGE_LIST_NORMAL )
+ m_ownsImageListNormal = true;
+ else if ( which == wxIMAGE_LIST_SMALL )
+ m_ownsImageListSmall = true;
+ else if ( which == wxIMAGE_LIST_STATE )
+ m_ownsImageListState = true;
+}
+
+bool wxGenericListCtrl::Arrange( int WXUNUSED(flag) )
+{
+ return 0;
+}
+
+bool wxGenericListCtrl::DeleteItem( long item )
+{
+ m_mainWin->DeleteItem( item );
+ return true;
+}
+
+bool wxGenericListCtrl::DeleteAllItems()
+{
+ m_mainWin->DeleteAllItems();
+ return true;
+}
+
+bool wxGenericListCtrl::DeleteAllColumns()
+{
+ size_t count = m_mainWin->m_columns.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ DeleteColumn( 0 );
+ return true;
+}
+
+void wxGenericListCtrl::ClearAll()
+{
+ m_mainWin->DeleteEverything();
+}
+
+bool wxGenericListCtrl::DeleteColumn( int col )
+{
+ m_mainWin->DeleteColumn( col );
+
+ // if we don't have the header any longer, we need to relayout the window
+ if ( !GetColumnCount() )
+ ResizeReportView(false /* no header */);
+ return true;
+}
+
+wxTextCtrl *wxGenericListCtrl::EditLabel(long item,
+ wxClassInfo* textControlClass)
+{
+ return m_mainWin->EditLabel( item, textControlClass );
+}
+
+wxTextCtrl *wxGenericListCtrl::GetEditControl() const
+{
+ return m_mainWin->GetEditControl();
+}
+
+bool wxGenericListCtrl::EnsureVisible( long item )
+{
+ m_mainWin->EnsureVisible( item );
+ return true;
+}
+
+long wxGenericListCtrl::FindItem( long start, const wxString& str, bool partial )
+{
+ return m_mainWin->FindItem( start, str, partial );
+}
+
+long wxGenericListCtrl::FindItem( long start, wxUIntPtr data )
+{
+ return m_mainWin->FindItem( start, data );
+}
+
+long wxGenericListCtrl::FindItem( long WXUNUSED(start), const wxPoint& pt,
+ int WXUNUSED(direction))
+{
+ return m_mainWin->FindItem( pt );
+}
+
+// TODO: sub item hit testing
+long wxGenericListCtrl::HitTest(const wxPoint& point, int& flags, long *) const
+{
+ return m_mainWin->HitTest( (int)point.x, (int)point.y, flags );
+}
+
+long wxGenericListCtrl::InsertItem( wxListItem& info )
+{
+ m_mainWin->InsertItem( info );
+ return info.m_itemId;
+}
+
+long wxGenericListCtrl::InsertItem( long index, const wxString &label )
+{
+ wxListItem info;
+ info.m_text = label;
+ info.m_mask = wxLIST_MASK_TEXT;
+ info.m_itemId = index;
+ return InsertItem( info );
+}
+
+long wxGenericListCtrl::InsertItem( long index, int imageIndex )
+{
+ wxListItem info;
+ info.m_mask = wxLIST_MASK_IMAGE;
+ info.m_image = imageIndex;
+ info.m_itemId = index;
+ return InsertItem( info );
+}
+
+long wxGenericListCtrl::InsertItem( long index, const wxString &label, int imageIndex )
+{
+ wxListItem info;
+ info.m_text = label;
+ info.m_image = imageIndex;
+ info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE;
+ info.m_itemId = index;
+ return InsertItem( info );
+}
+
+long wxGenericListCtrl::InsertColumn( long col, wxListItem &item )
+{
+ wxCHECK_MSG( m_headerWin, -1, _T("can't add column in non report mode") );
+
+ m_mainWin->InsertColumn( col, item );
+
+ // if we hadn't had a header before but have one now
+ // then we need to relayout the window
+ if ( GetColumnCount() == 1 && m_mainWin->HasHeader() )
+ ResizeReportView(true /* have header */);
+
+ m_headerWin->Refresh();
+
+ return 0;
+}
+
+long wxGenericListCtrl::InsertColumn( long col, const wxString &heading,
+ int format, int width )
+{
+ wxListItem item;
+ item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
+ item.m_text = heading;
+ if (width >= -2)
+ {
+ item.m_mask |= wxLIST_MASK_WIDTH;
+ item.m_width = width;
+ }
+
+ item.m_format = format;
+
+ return InsertColumn( col, item );
+}
+
+bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) )
+{
+ return 0;
+}
+
+// Sort items.
+// fn is a function which takes 3 long arguments: item1, item2, data.
+// item1 is the long data associated with a first item (NOT the index).
+// item2 is the long data associated with a second item (NOT the index).
+// data is the same value as passed to SortItems.
+// The return value is a negative number if the first item should precede the second
+// item, a positive number of the second item should precede the first,
+// or zero if the two items are equivalent.
+// data is arbitrary data to be passed to the sort function.
+
+bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn, long data )
+{
+ m_mainWin->SortItems( fn, data );
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+void wxGenericListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
+{
+ if ( !m_mainWin )
+ return;
+
+ ResizeReportView(m_mainWin->HasHeader());
+ m_mainWin->RecalculatePositions();
+}
+
+void wxGenericListCtrl::ResizeReportView(bool showHeader)
+{
+ int cw, ch;
+ GetClientSize( &cw, &ch );
+
+ if ( showHeader )
+ {
+ m_headerWin->SetSize( 0, 0, cw, m_headerHeight );
+ if(ch > m_headerHeight)
+ m_mainWin->SetSize( 0, m_headerHeight + 1,
+ cw, ch - m_headerHeight - 1 );
+ else
+ m_mainWin->SetSize( 0, m_headerHeight + 1,
+ cw, 0);
+ }
+ else // no header window
+ {
+ m_mainWin->SetSize( 0, 0, cw, ch );
+ }
+}
+
+void wxGenericListCtrl::OnInternalIdle()
+{
+ wxWindow::OnInternalIdle();
+
+ // do it only if needed
+ if ( !m_mainWin->m_dirty )
+ return;
+
+ m_mainWin->RecalculatePositions();
+}
+
+// ----------------------------------------------------------------------------
+// font/colours
+// ----------------------------------------------------------------------------
+
+bool wxGenericListCtrl::SetBackgroundColour( const wxColour &colour )
+{
+ if (m_mainWin)
+ {
+ m_mainWin->SetBackgroundColour( colour );
+ m_mainWin->m_dirty = true;
+ }
+
+ return true;
+}
+
+bool wxGenericListCtrl::SetForegroundColour( const wxColour &colour )
+{
+ if ( !wxWindow::SetForegroundColour( colour ) )
+ return false;
+
+ if (m_mainWin)
+ {
+ m_mainWin->SetForegroundColour( colour );
+ m_mainWin->m_dirty = true;
+ }
+
+ if (m_headerWin)
+ m_headerWin->SetForegroundColour( colour );
+
+ return true;
+}
+
+bool wxGenericListCtrl::SetFont( const wxFont &font )
+{
+ if ( !wxWindow::SetFont( font ) )
+ return false;
+
+ if (m_mainWin)
+ {
+ m_mainWin->SetFont( font );
+ m_mainWin->m_dirty = true;
+ }
+
+ if (m_headerWin)
+ {
+ m_headerWin->SetFont( font );
+ CalculateAndSetHeaderHeight();
+ }
+
+ Refresh();
+
+ return true;
+}
+
+// static
+wxVisualAttributes
+wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant)
+{
+#if _USE_VISATTR
+ // Use the same color scheme as wxListBox
+ return wxListBox::GetClassDefaultAttributes(variant);
+#else
+ wxUnusedVar(variant);
+ wxVisualAttributes attr;
+ attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+ attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
+ attr.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+ return attr;
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// methods forwarded to m_mainWin
+// ----------------------------------------------------------------------------
+
+#if wxUSE_DRAG_AND_DROP
+
+void wxGenericListCtrl::SetDropTarget( wxDropTarget *dropTarget )
+{
+ m_mainWin->SetDropTarget( dropTarget );
+}
+
+wxDropTarget *wxGenericListCtrl::GetDropTarget() const
+{
+ return m_mainWin->GetDropTarget();
+}
+
+#endif
+
+bool wxGenericListCtrl::SetCursor( const wxCursor &cursor )
+{
+ return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : false;
+}
+
+wxColour wxGenericListCtrl::GetBackgroundColour() const
+{
+ return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour();
+}
+
+wxColour wxGenericListCtrl::GetForegroundColour() const
+{
+ return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour();
+}
+
+bool wxGenericListCtrl::DoPopupMenu( wxMenu *menu, int x, int y )
+{
+#if wxUSE_MENUS
+ return m_mainWin->PopupMenu( menu, x, y );
+#else
+ return false;
+#endif
+}
+
+void wxGenericListCtrl::DoClientToScreen( int *x, int *y ) const
+{
+ m_mainWin->DoClientToScreen(x, y);
+}
+
+void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const
+{
+ m_mainWin->DoScreenToClient(x, y);
+}
+
+void wxGenericListCtrl::SetFocus()
+{
+ // The test in window.cpp fails as we are a composite
+ // window, so it checks against "this", but not m_mainWin.
+ if ( DoFindFocus() != this )
+ m_mainWin->SetFocus();
+}
+
+wxSize wxGenericListCtrl::DoGetBestSize() const
+{
+ // Something is better than nothing...
+ // 100x80 is what the MSW version will get from the default
+ // wxControl::DoGetBestSize
+ return wxSize(100, 80);
+}
+
+// ----------------------------------------------------------------------------
+// virtual list control support
+// ----------------------------------------------------------------------------
+
+wxString wxGenericListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const
+{
+ // this is a pure virtual function, in fact - which is not really pure
+ // because the controls which are not virtual don't need to implement it
+ wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") );
+
+ return wxEmptyString;
+}
+
+int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item)) const
+{
+ wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL),
+ -1,
+ wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden."));
+ return -1;
+}
+
+int wxGenericListCtrl::OnGetItemColumnImage(long item, long column) const
+{
+ if (!column)
+ return OnGetItemImage(item);
+
+ return -1;
+}
+
+wxListItemAttr *
+wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
+{
+ wxASSERT_MSG( item >= 0 && item < GetItemCount(),
+ _T("invalid item index in OnGetItemAttr()") );
+
+ // no attributes by default
+ return NULL;
+}
+
+void wxGenericListCtrl::SetItemCount(long count)
+{
+ wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
+
+ m_mainWin->SetItemCount(count);
+}
+
+void wxGenericListCtrl::RefreshItem(long item)
+{
+ m_mainWin->RefreshLine(item);
+}
+
+void wxGenericListCtrl::RefreshItems(long itemFrom, long itemTo)
+{
+ m_mainWin->RefreshLines(itemFrom, itemTo);
+}
+
+// Generic wxListCtrl is more or less a container for two other
+// windows which drawings are done upon. These are namely
+// 'm_headerWin' and 'm_mainWin'.
+// Here we override 'virtual wxWindow::Refresh()' to mimic the
+// behaviour wxListCtrl has under wxMSW.
+//
+void wxGenericListCtrl::Refresh(bool eraseBackground, const wxRect *rect)
+{
+ if (!rect)
+ {
+ // The easy case, no rectangle specified.
+ if (m_headerWin)
+ m_headerWin->Refresh(eraseBackground);
+
+ if (m_mainWin)
+ m_mainWin->Refresh(eraseBackground);
+ }
+ else
+ {
+ // Refresh the header window
+ if (m_headerWin)
+ {
+ wxRect rectHeader = m_headerWin->GetRect();
+ rectHeader.Intersect(*rect);
+ if (rectHeader.GetWidth() && rectHeader.GetHeight())
+ {
+ int x, y;
+ m_headerWin->GetPosition(&x, &y);
+ rectHeader.Offset(-x, -y);
+ m_headerWin->Refresh(eraseBackground, &rectHeader);
+ }
+ }
+
+ // Refresh the main window
+ if (m_mainWin)
+ {
+ wxRect rectMain = m_mainWin->GetRect();
+ rectMain.Intersect(*rect);
+ if (rectMain.GetWidth() && rectMain.GetHeight())
+ {
+ int x, y;
+ m_mainWin->GetPosition(&x, &y);
+ rectMain.Offset(-x, -y);
+ m_mainWin->Refresh(eraseBackground, &rectMain);
+ }
+ }
+ }
+}
+
+void wxGenericListCtrl::Freeze()
+{
+ m_mainWin->Freeze();
+}
+
+void wxGenericListCtrl::Thaw()
+{
+ m_mainWin->Thaw();
+}
+
+} // namespace SL_Extern
+
+#endif // wxUSE_LISTCTRL
diff --git a/src/Helper/slhtmlwindow.cpp b/src/Helper/slhtmlwindow.cpp
new file mode 100644
index 0000000..645be57
--- /dev/null
+++ b/src/Helper/slhtmlwindow.cpp
@@ -0,0 +1,26 @@
+#include "slhtmlwindow.h"
+
+#include "../ui.h"
+
+BEGIN_EVENT_TABLE( slHtmlWindow, wxHtmlWindow )
+ EVT_HTML_LINK_CLICKED(wxID_ANY, slHtmlWindow::OnLinkClicked)
+END_EVENT_TABLE()
+
+slHtmlWindow::slHtmlWindow( wxWindow *parent, wxWindowID id, const wxPoint& pos ,
+ const wxSize& size, long style,
+ const wxString& name )
+ : wxHtmlWindow( parent, id, pos, size, style, name )
+{
+ //ctor
+}
+
+slHtmlWindow::~slHtmlWindow()
+{
+ //dtor
+}
+
+void slHtmlWindow::OnLinkClicked( wxHtmlLinkEvent& evt )
+{
+ wxString url = evt.GetLinkInfo().GetHref();
+ ui().OpenWebBrowser( url );
+}
diff --git a/src/Helper/slhtmlwindow.h b/src/Helper/slhtmlwindow.h
new file mode 100644
index 0000000..946f29c
--- /dev/null
+++ b/src/Helper/slhtmlwindow.h
@@ -0,0 +1,21 @@
+#ifndef SLHTMLWINDOW_H
+#define SLHTMLWINDOW_H
+
+#include <wx/html/htmlwin.h>
+
+
+class slHtmlWindow : public wxHtmlWindow
+{
+ public:
+ slHtmlWindow( wxWindow *parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize, long style = wxHW_DEFAULT_STYLE,
+ const wxString& name = _T("htmlWindow") );
+ virtual ~slHtmlWindow();
+
+ void OnLinkClicked( wxHtmlLinkEvent& evt );
+
+ protected:
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // SLHTMLWINDOW_H
diff --git a/src/Helper/sortutil.h b/src/Helper/sortutil.h
new file mode 100644
index 0000000..995030c
--- /dev/null
+++ b/src/Helper/sortutil.h
@@ -0,0 +1,74 @@
+#ifndef SPRINGLOBBY_SORTUTIL_H_INCLUDED
+#define SPRINGLOBBY_SORTUTIL_H_INCLUDED
+
+
+template< class ContainerType, class Comparator >
+void SLBubbleSort( ContainerType& data, const Comparator& cmp )
+{
+ const int n = data.size();
+ int j = 0;
+ bool swapped = true;
+ while ( swapped )
+ {
+ j++;
+ swapped = false;
+ for ( int i = 0; i < n - j; ++i )
+ {
+ if ( cmp ( data[i], data[i+1] ) )
+ {
+ typename Comparator::ObjType tmp = data[i+1];
+ data[i+1] = data[i];
+ data[i] = tmp;
+ swapped = true;
+ }
+ }
+ }
+}
+
+ //! set direction to +1 for down, -1 for up
+struct SortOrderItem {
+ int col;
+ int direction;
+};
+//! map sort priority <--> ( column, direction )
+typedef std::map<int,SortOrderItem> SortOrder;
+
+
+template< class ContainerType, class Comparator >
+void SLInsertionSort( ContainerType& data, const Comparator& cmp )
+{
+ const int n = data.size();
+ for ( int i = 0; i < n; i++ )
+ {
+ typename Comparator::ObjType v = data[i];
+ int j;
+
+ for ( j = i - 1; j >= 0; j--)
+ {
+ if ( cmp( data[j], v ) )
+ break;
+ data[j + 1] = data[j];
+ }
+ data[j + 1] = v;
+ }
+}
+
+#endif // SPRINGLOBBY_SORTUTIL_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/Helper/tasclientimport.cpp b/src/Helper/tasclientimport.cpp
new file mode 100644
index 0000000..6e66324
--- /dev/null
+++ b/src/Helper/tasclientimport.cpp
@@ -0,0 +1,88 @@
+#include "tasclientimport.h"
+#include <wx/platform.h>
+
+#ifdef __WXMSW__
+
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/tokenzr.h>
+#include <wx/log.h>
+
+#include "../settings.h"
+
+#include <wx/msw/registry.h>
+
+template < typename T >
+static T GetVal( const wxRegKey& reg, const wxString& name, const T def )
+{
+ T val = def;
+ if ( reg.QueryValue( name, &val ) )
+ return val;
+ else
+ return def;
+}
+
+template < >
+static wxString GetVal( const wxRegKey& reg, const wxString& name, const wxString def )
+{
+ wxString val = def;
+ if ( reg.QueryValue( name, val ) )
+ return val;
+ else
+ return def;
+}
+
+wxString GetChan( const wxString& token )
+{
+ wxString ret = token.AfterFirst('#');
+ ret = ret.Left( ret.Find( ' ' ) );
+ return ret;
+}
+
+bool ImportAutojoins()
+{
+ wxString sep = wxFileName::GetPathSeparator();
+ wxString fname = sett().GetLobbyWriteDir();
+ fname.Replace( _T("SpringLobby") , wxEmptyString );
+
+ fname = fname + sep + _T("var") + sep + _T("perform.dat");
+ if ( wxFileName::FileExists( fname ) ) {
+ wxTextFile file( fname );
+ wxLogWarning( _T("parsing file: ") + fname );
+ file.Open();
+ for ( wxString line = file.GetFirstLine(); !file.Eof(); line = file.GetNextLine() ) {
+ wxString chan = GetChan( line );
+ sett().AddChannelJoin( chan, _T("") );
+ }
+ return true;
+ }
+ else {
+ wxLogError( _T("Not found: ") + fname );
+ return false;
+ }
+}
+
+bool ImportTASClientSettings()
+{
+ wxRegKey base( _T("HKEY_CURRENT_USER\\Software\\TASClient\\Preferences") );
+
+ sett().SetAutoConnect( GetVal( base, _T("ConnectOnStartup"), (long) sett().GetAutoConnect() ) );
+ sett().SetChatPMSoundNotificationEnabled( GetVal( base, _T("DisableAllSounds"), (long) sett().GetChatPMSoundNotificationEnabled() ) );
+ sett().SetServerAccountPass( sett().GetDefaultServer(), GetVal( base, _T("Password"), sett().GetServerAccountPass( sett().GetDefaultServer() ) ) );
+ sett().SetServerAccountSavePass( sett().GetDefaultServer() , GetVal( base, _T("RememberPasswords"), (long) sett().GetServerAccountSavePass( sett().GetDefaultServer() ) ) );
+ sett().SetServerAccountNick( sett().GetDefaultServer() , GetVal( base, _T("Username"), sett().GetServerAccountNick( sett().GetDefaultServer() ) ) );
+
+ bool ret = ImportAutojoins();
+
+ sett().SaveSettings();
+
+ return ret;
+
+}
+
+bool TASClientPresent()
+{
+ wxRegKey base( _T("HKEY_CURRENT_USER\\Software\\TASClient\\Preferences") );
+ return base.Exists();
+}
+#endif
diff --git a/src/Helper/tasclientimport.h b/src/Helper/tasclientimport.h
new file mode 100644
index 0000000..4ee5369
--- /dev/null
+++ b/src/Helper/tasclientimport.h
@@ -0,0 +1,27 @@
+#ifndef TASCLIENTIMPORT_H
+#define TASCLIENTIMPORT_H
+
+#ifdef __WXMSW__
+bool ImportTASClientSettings();
+bool TASClientPresent();
+#endif
+
+#endif // TASCLIENTIMPORT_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/Helper/wxTranslationHelper.cpp b/src/Helper/wxTranslationHelper.cpp
new file mode 100644
index 0000000..9d4f28c
--- /dev/null
+++ b/src/Helper/wxTranslationHelper.cpp
@@ -0,0 +1,164 @@
+#include "wxTranslationHelper.h"
+#include <wx/dir.h>
+#include <wx/config.h>
+#include <wx/fileconf.h>
+#include <wx/filename.h>
+#include <wx/app.h>
+#include <wx/log.h>
+#include <wx/choicdlg.h>
+#include <wx/intl.h>
+#include "../settings.h"
+#include "../settings++/custom_dialogs.h"
+
+wxTranslationHelper::wxTranslationHelper( wxApp & app,
+ const wxString & search_path )
+: m_App(app), m_SearchPath(search_path), m_Locale(NULL)
+{
+ if(search_path.IsEmpty())
+ {
+ m_SearchPath = wxPathOnly(m_App.argv[0]);
+ }
+}
+
+wxTranslationHelper::~wxTranslationHelper()
+{
+ if(m_Locale)
+ {
+ Save();
+ wxDELETE(m_Locale);
+ }
+}
+
+wxLocale * wxTranslationHelper::GetLocale()
+{
+ return m_Locale;
+}
+
+const wxString & wxTranslationHelper::GetSearchPath()
+{
+ return m_SearchPath;
+}
+
+void wxTranslationHelper::SetSearchPath( wxString& value )
+{
+ m_SearchPath = value;
+ if( m_SearchPath.IsEmpty() )
+ {
+ m_SearchPath = wxPathOnly( m_App.argv[0] );
+ }
+}
+
+bool wxTranslationHelper::Load()
+{
+ long language = sett().GetLanguageID();
+ if(language == wxLANGUAGE_UNKNOWN)
+ {
+ return false;
+ }
+
+ wxArrayString names;
+ wxArrayLong identifiers;
+ int dummy;
+ GetInstalledLanguages( names, identifiers, dummy );
+ for(size_t i = 0; i < identifiers.Count(); i++)
+ {
+ if( identifiers[i] == language )
+ {
+ if(m_Locale) wxDELETE( m_Locale );
+ m_Locale = new wxLocale;
+ m_Locale->Init( identifiers[i] );
+ m_Locale->AddCatalogLookupPathPrefix( m_SearchPath );
+ m_Locale->AddCatalog( m_App.GetAppName() );
+ m_Locale->AddCatalog( _T("wxstd") );
+ return true;
+ }
+ }
+ return false;
+}
+
+void wxTranslationHelper::Save()
+{
+ sett().SetLanguageID( m_Locale->GetLanguage() );
+ sett().SaveSettings();
+}
+
+void wxTranslationHelper::GetInstalledLanguages( wxArrayString & names,
+ wxArrayLong & identifiers,
+ int& selected_index )
+{
+ names.Clear();
+ identifiers.Clear();
+ wxString filename;
+ const wxLanguageInfo * langinfo;
+ wxString name = wxLocale::GetLanguageName( wxLANGUAGE_DEFAULT );
+ if(!name.IsEmpty())
+ {
+ names.Add( _("Default") );
+ identifiers.Add( wxLANGUAGE_DEFAULT );
+ }
+ if( !wxDir::Exists( m_SearchPath ) )
+ {
+ wxLogError( _T("Directory %s DOES NOT EXIST !!!"),
+ m_SearchPath.GetData() );
+ return;
+ }
+ wxDir dir( m_SearchPath );
+
+#ifdef __WXMSW__
+ wxString mask = wxT("*.*");
+#else
+ wxString mask = wxT("*");
+#endif
+
+ selected_index = -1;
+ for(bool cont = dir.GetFirst(&filename, mask, wxDIR_DEFAULT);
+ cont; cont = dir.GetNext( &filename) )
+ {
+ langinfo = wxLocale::FindLanguageInfo(filename);
+ if(langinfo != NULL)
+ {
+ wxString mo_file = dir.GetName() +
+ wxFileName::GetPathSeparator() +
+ filename +
+ wxFileName::GetPathSeparator() +
+ _T("LC_MESSAGES") +
+ wxFileName::GetPathSeparator() +
+ m_App.GetAppName()+ wxT(".mo") ;
+ wxLogInfo( _("SEARCHING FOR %s"), mo_file.GetData() );
+ if( wxFileExists( mo_file ) )
+ {
+ names.Add(langinfo->Description);
+ identifiers.Add(langinfo->Language);
+ if ( langinfo->Language == sett().GetLanguageID() )
+ selected_index = names.GetCount() -1;
+ }
+ }
+ }
+}
+
+bool wxTranslationHelper::AskUserForLanguage( wxArrayString& names,
+ wxArrayLong& identifiers,
+ int selected_index)
+{
+ wxCHECK_MSG( names.Count() == identifiers.Count(), false,
+ _("Array of language names and identifiers should have the same size.") );
+ long index = GetSingleChoiceIndex( _("Select the language"),
+ _("Language"), names, selected_index );
+ if( index != -1 )
+ {
+ if( m_Locale )
+ {
+ wxDELETE( m_Locale );
+ }
+ m_Locale = new wxLocale;
+ m_Locale->Init( identifiers[index] );
+ m_Locale->AddCatalogLookupPathPrefix( m_SearchPath );
+ wxLogInfo( _("wxTranslationHelper: Path Prefix = \"%s\""),
+ m_SearchPath.GetData() );
+ m_Locale->AddCatalog( _T("springlobby") );
+ wxLogInfo( _("wxTranslationHelper: Catalog Name = \"%s\""),
+ _T("springlobby") );
+ return true;
+ }
+ return false;
+}
diff --git a/src/Helper/wxTranslationHelper.h b/src/Helper/wxTranslationHelper.h
new file mode 100644
index 0000000..2aef842
--- /dev/null
+++ b/src/Helper/wxTranslationHelper.h
@@ -0,0 +1,61 @@
+#ifndef _WX_TRANSLATION_HELPER_H
+#define _WX_TRANSLATION_HELPER_H
+
+//note: copied from http://wxwidgets.info/?q=wxTranslation
+// and modified to fit SL needs
+
+#include <wx/string.h>
+
+class wxApp;
+class wxLocale;
+class wxArrayString;
+class wxArrayLong;
+
+class wxTranslationHelper
+{
+
+public:
+ wxTranslationHelper( wxApp & app, const wxString & search_path );
+ ~wxTranslationHelper();
+ wxLocale * GetLocale();
+
+ /** \brief put names and ID for all found .mo files
+ \param current_selected will contain the index of currently in settings selected languageID
+ in name/identifiers array, or -1 if notfound
+ */
+ void GetInstalledLanguages( wxArrayString& names, wxArrayLong& identifiers, int& current_selected );
+ bool AskUserForLanguage( wxArrayString& names, wxArrayLong& identifiers, int selected_index );
+ bool Load();
+ void Save();
+
+ const wxString & GetSearchPath();
+ void SetSearchPath( wxString& value );
+
+private:
+ wxApp& m_App;
+ wxString m_SearchPath;
+ wxLocale * m_Locale;
+ bool m_UseNativeConfig;
+
+ wxTranslationHelper( const wxTranslationHelper& );
+};
+
+#endif
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/Helper/wxtextctrlhist.cpp b/src/Helper/wxtextctrlhist.cpp
new file mode 100644
index 0000000..12c543c
--- /dev/null
+++ b/src/Helper/wxtextctrlhist.cpp
@@ -0,0 +1,162 @@
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWidgets headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include "wxtextctrlhist.h"
+#include "TextCompletionDatabase.hpp"
+#include <wx/regex.h>
+#include "../utils/misc.h"
+#include "../settings.h"
+
+BEGIN_EVENT_TABLE(wxTextCtrlHist, wxTextCtrl)
+ EVT_TEXT_ENTER(wxID_ANY, wxTextCtrlHist::OnSendMessage)
+ EVT_KEY_DOWN(wxTextCtrlHist::OnChar)
+END_EVENT_TABLE()
+
+void GetArrayStringFromHashMap( const HashMap_String_String& hm , wxArrayString& matches )
+{
+ for ( HashMap_String_String::const_iterator it = hm.begin(); it != hm.end(); ++it )
+ matches.Add( it->second );
+}
+
+wxTextCtrlHist::wxTextCtrlHist(TextCompletionDatabase& textDb, wxWindow* parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long /*unused*/ )
+ : wxTextCtrl(parent, id, value, pos, size, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB ),
+ textcompletiondatabase(textDb), current_pos(0), history_max(32)
+{
+}
+
+void wxTextCtrlHist::OnSendMessage( wxCommandEvent &event )
+{
+ Historical.Add(GetLineText(0));
+ current_pos = Historical.GetCount();
+
+ if(current_pos > history_max) {
+ Historical.RemoveAt(0);
+ --current_pos;
+ }
+ event.Skip();
+}
+
+void wxTextCtrlHist::OnChar(wxKeyEvent & event)
+{
+ int keyCode = event.GetKeyCode();
+
+ if ( current_pos == Historical.GetCount() ) {
+ m_original = GetValue();
+ }
+
+ if(keyCode == WXK_UP)
+ {
+ if(current_pos > 0)
+ {
+ --current_pos;
+ SetValue(Historical[current_pos]);
+ SetInsertionPointEnd();
+ }
+ }
+ else
+ if(keyCode == WXK_DOWN)
+ {
+ if(current_pos < static_cast<int>(Historical.GetCount())-1)
+ {
+ ++current_pos;
+ SetValue(Historical[current_pos]);
+ }
+ else
+ {
+ current_pos = Historical.GetCount();
+ SetValue( m_original );
+ SetInsertionPointEnd();
+ }
+ }
+ else
+ if(keyCode == WXK_TAB)
+ {
+ wxString text = this->GetValue();
+ long pos_Cursor = this->GetInsertionPoint();
+ wxString selection_Begin_InsertPos = this->GetRange( 0, pos_Cursor );
+ wxString selection_InsertPos_End = this->GetRange( pos_Cursor, this->GetLastPosition() );
+
+ // Search for the shortest Match, starting from the Insertionpoint to the left, until we find a "\ "
+ // Special Characters according to regular Expression Syntax needs to be escaped: [,]
+ wxRegEx regex_currentWord;
+ #ifdef wxHAS_REGEX_ADVANCED
+ regex_currentWord.Compile( wxT("(_|\\[|\\]|\\w)+$"), wxRE_ADVANCED );
+ #else
+ regex_currentWord.Compile( wxT("(_|\\[|\\]|\\w)+$"), wxRE_EXTENDED );
+ #endif
+
+ if ( regex_currentWord.Matches( selection_Begin_InsertPos ) ) {
+ wxString currentWord = regex_currentWord.GetMatch( selection_Begin_InsertPos );
+ // std::cout << "#########: Current Word: (" << currentWord.char_str() << ")" << std::endl;
+
+ wxString selection_Begin_BeforeCurrentWord = this->GetRange( 0, pos_Cursor - currentWord.length() );
+ // std::cout << "#########: selection_Begin_BeforeCurrentWord: (" << selection_Begin_BeforeCurrentWord.char_str() << ")" << std::endl;
+
+ HashMap_String_String hm = textcompletiondatabase.GetMapping( currentWord );
+
+ // std::cout << "#########: Mapping-Size: (" << hm.size() << ")" << std::endl;
+
+ wxString completed_Text;
+ int new_Cursor_Pos = 0;
+ if( hm.size() == 1 ) {
+ completed_Text.append( selection_Begin_BeforeCurrentWord );
+ completed_Text.append( hm.begin()->second );
+ completed_Text.append( selection_InsertPos_End );
+ new_Cursor_Pos = selection_Begin_BeforeCurrentWord.length() + hm.begin()->second.length();
+ } else {
+ //match nearest only makes sense when there's actually more than one match
+ if ( hm.size() > 1 && sett().GetCompletionMethod() == Settings::MatchNearest ) {
+ wxArrayString matches;
+ GetArrayStringFromHashMap( hm , matches );
+ wxString newWord = GetBestMatch( matches, currentWord );
+
+ bool realCompletion = newWord.Length() >= currentWord.Length(); // otherwise we have actually less word than before :P
+ if ( realCompletion )
+ currentWord = newWord;
+
+ completed_Text.append( selection_Begin_BeforeCurrentWord );
+ completed_Text.append( currentWord );
+ completed_Text.append( selection_InsertPos_End );
+ new_Cursor_Pos = selection_Begin_BeforeCurrentWord.length() + currentWord.length();
+
+ // We ring the System Bell, to signalise the User, that no Completion was applied.
+ if (!realCompletion)
+ wxBell();
+ }
+ else {
+ completed_Text.append( selection_Begin_BeforeCurrentWord );
+ completed_Text.append( currentWord );
+ completed_Text.append( selection_InsertPos_End );
+ new_Cursor_Pos = selection_Begin_BeforeCurrentWord.length() + currentWord.length();
+ // We ring the System Bell, to signalise the User, that no Completion was applied.
+ wxBell();
+ }
+ }
+ // Replace the old Text with our completed Text
+ // or
+ // if nothing was found remove the typed TAB, so that the User stays comfortable not to remove the TAB by himself.
+ this->ChangeValue( completed_Text );
+ this->SetInsertionPoint( new_Cursor_Pos );
+ } else {
+ wxString old_Text;
+ old_Text.append( selection_Begin_InsertPos );
+ old_Text.append( selection_InsertPos_End );
+ this->ChangeValue( old_Text );
+ this->SetInsertionPoint( selection_Begin_InsertPos.length() );
+ wxBell();
+ }
+ }
+ else
+ event.Skip();
+
+}
diff --git a/src/Helper/wxtextctrlhist.h b/src/Helper/wxtextctrlhist.h
new file mode 100644
index 0000000..6f38c86
--- /dev/null
+++ b/src/Helper/wxtextctrlhist.h
@@ -0,0 +1,45 @@
+#ifndef SL_HEADERGUARD_TEXTHISTCONROL_H
+#define SL_HEADERGUARD_TEXTHISTCONROL_H
+//copied from http://wxforum.shadonet.com/viewtopic.php?t=7924 (thanks go to Lamego)
+//modified some (textcompletion,etc)
+
+// Extends wxTextCtrl with input historical functions
+// to allow user to navigate to previously entered messages
+class TextCompletionDatabase;
+
+class wxTextCtrlHist : public wxTextCtrl
+{
+ public:
+ wxTextCtrlHist(TextCompletionDatabase& textcompletiondatabase, wxWindow* parent, wxWindowID id, const wxString& value = _T(""),
+ const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
+ void SetHistoryMax(int max) { history_max = max; }
+ private:
+ TextCompletionDatabase& textcompletiondatabase;
+ wxString m_original;
+ int current_pos;
+ int history_max;
+ wxArrayString Historical;
+ void OnSendMessage( wxCommandEvent &event );
+ void OnChar(wxKeyEvent & event);
+ DECLARE_EVENT_TABLE()
+};
+
+#endif //SL_HEADERGUARD_TEXTHISTCONROL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/addbotdialog.cpp b/src/addbotdialog.cpp
new file mode 100644
index 0000000..07aa03a
--- /dev/null
+++ b/src/addbotdialog.cpp
@@ -0,0 +1,309 @@
+#include "addbotdialog.h"
+
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/textctrl.h>
+#include <wx/button.h>
+#include <wx/choice.h>
+#include <wx/statline.h>
+#include <wx/filename.h>
+#include <wx/dir.h>
+#include <wx/listctrl.h>
+
+#include "settings.h"
+#include "utils/controls.h"
+#include "uiutils.h"
+#include "battle.h"
+#include "iunitsync.h"
+#include "mmoptionwindows.h"
+#include "utils/conversion.h"
+
+#include "settings++/custom_dialogs.h"
+
+BEGIN_EVENT_TABLE( AddBotDialog, wxDialog )
+ EVT_BUTTON( ADDBOT_CANCEL, AddBotDialog::OnClose )
+ EVT_BUTTON( ADDBOT_ADD, AddBotDialog::OnAddBot )
+ EVT_CHOICE( ADDBOT_AI, AddBotDialog::OnSelectBot )
+ EVT_LIST_ITEM_ACTIVATED ( ADDBOT_OPTIONLIST, AddBotDialog::OnOptionActivate )
+END_EVENT_TABLE()
+
+
+AddBotDialog::AddBotDialog( wxWindow* parent, IBattle& battle , bool singleplayer):
+ wxDialog( parent, wxID_ANY, _("Add bot"), wxDefaultPosition, wxDefaultSize ),
+ m_battle( battle ),
+ m_sp(singleplayer)
+{
+
+ this->SetSizeHints( wxDefaultSize, wxDefaultSize );
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* m_nick_sizer;
+ m_nick_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_nick_lbl = new wxStaticText( this, wxID_ANY, _("Nickname:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_nick_sizer->Add( m_nick_lbl, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ int bot = m_battle.GetNumBots()+1;
+
+ m_nick = new wxTextCtrl( this, wxID_ANY, wxString::Format( _T("Bot%d"), bot ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_nick_sizer->Add( m_nick, 2, wxALL, 5 );
+
+ m_main_sizer->Add( m_nick_sizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* m_ai_sizer;
+ m_ai_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_ai_lbl = new wxStaticText( this, wxID_ANY, _("AI:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_ai_sizer->Add( m_ai_lbl, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ m_ai = new wxChoice( this, ADDBOT_AI );
+ m_ai->SetToolTip( TE(_("Choose the AI library to use with this bot.") ) );
+
+ m_ai_sizer->Add( m_ai, 2, wxALL, 5 );
+
+ m_main_sizer->Add( m_ai_sizer, 0, wxEXPAND, 5 );
+
+ if ( usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) )
+ {
+ m_ai_infos_lst = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER );
+ wxListItem col;
+ col.SetText( _("property") );
+ col.SetImage( -1 );
+ m_ai_infos_lst->InsertColumn( 0, col );
+ wxListItem col2;
+ col2.SetText( _("value") );
+ col2.SetImage( -1 );
+ m_ai_infos_lst->InsertColumn( 1, col2 );
+
+ m_opts_list = new wxListCtrl( this, ADDBOT_OPTIONLIST, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER );
+ wxListItem col3;
+ col3.SetText( _("property") );
+ col3.SetImage( -1 );
+ m_opts_list->InsertColumn( 0, col3 );
+ wxListItem col4;
+ col4.SetText( _("value") );
+ col4.SetImage( -1 );
+ m_opts_list->InsertColumn( 1, col4 );
+
+ m_info_sizer = new wxBoxSizer(wxVERTICAL);
+ m_info_sizer->Add( m_ai_infos_lst, 1, wxALL|wxEXPAND );
+ m_info_sizer->Add( m_opts_list, 1, wxALL|wxEXPAND );
+ m_main_sizer->Add( m_info_sizer, 1, wxALL|wxEXPAND );
+
+ }
+ else
+ {
+ this->SetSize( wxSize(-1, 155) );
+ m_main_sizer->AddStretchSpacer();
+ }
+
+
+ m_buttons_sep = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ m_main_sizer->Add( m_buttons_sep, 0, wxALL|wxEXPAND );
+
+ wxBoxSizer* m_buttons_sizer;
+ m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_cancel_btn = new wxButton( this, ADDBOT_CANCEL, _("Cancel"), wxDefaultPosition, wxSize(-1,CONTROL_HEIGHT), 0 );
+ m_buttons_sizer->Add( m_cancel_btn, 0, wxALL );
+
+ m_buttons_sizer->Add( 0, 0, 1, wxEXPAND );
+
+ m_add_btn = new wxButton( this, ADDBOT_ADD, _("Add Bot"), wxDefaultPosition, wxSize(-1,CONTROL_HEIGHT), 0 );
+ m_buttons_sizer->Add( m_add_btn, 0, wxALL );
+
+ m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND );
+
+ this->SetSizer( m_main_sizer );
+ this->Layout();
+
+ ReloadAIList();
+}
+
+
+wxString AddBotDialog::GetNick()
+{
+ wxString s = m_nick->GetValue();
+ s.Replace( _T(" "), _T("_") );
+ return s;
+}
+
+
+wxString AddBotDialog::GetAIShortName()
+{
+ wxArrayString infos = usync().GetAIInfos( m_ai->GetSelection() );
+ int namepos = infos.Index( _T("shortName") );
+ if ( namepos == wxNOT_FOUND ) return m_ais[ m_ai->GetSelection() ];
+ return infos[namepos +1];
+}
+
+wxString AddBotDialog::GetAIVersion()
+{
+ wxArrayString infos = usync().GetAIInfos( m_ai->GetSelection() );
+ int namepos = infos.Index( _T("version") );
+ if ( namepos == wxNOT_FOUND ) return _T("");
+ return infos[namepos +1];
+}
+
+int AddBotDialog::GetAIType()
+{
+ return m_ai->GetSelection();
+}
+
+wxString AddBotDialog::RefineAIName( const wxString& name )
+{
+ wxString ret = name;
+ if ( !usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) )
+ {
+ if ( ret.Contains(_T('.')) ) ret = ret.BeforeLast(_T('.'));
+ if ( ret.Contains(_T('/')) ) ret = ret.AfterLast(_T('/'));
+ if ( ret.Contains(_T('\\')) ) ret = ret.AfterLast(_T('\\'));
+ if ( ret.Contains(_T("LuaAI:")) ) ret = ret.AfterFirst(_T(':'));
+ }
+ if ( m_ai->FindString( ret ) == wxNOT_FOUND ) return ret;
+ wxString ret2;
+ int i = 2;
+ do {
+ ret2 = ret + wxString::Format( _T(" (%d)"), i );
+ i++;
+ } while ( m_ai->FindString( ret2 ) != wxNOT_FOUND );
+ return ret2;
+}
+
+
+void AddBotDialog::ReloadAIList()
+{
+ try
+ {
+ m_ais = usync().GetAIList( m_battle.GetHostModName() );
+ } catch (...) {}
+
+ m_ai->Clear();
+ for ( unsigned int i = 0; i < m_ais.GetCount(); i++ ) m_ai->Append( RefineAIName(m_ais[i]) );
+ if ( m_ais.GetCount() > 0 )
+ {
+ m_ai->SetStringSelection( sett().GetLastAI() );
+ if ( m_ai->GetStringSelection() == wxEmptyString ) m_ai->SetSelection( 0 );
+ }
+ else
+ {
+ customMessageBox(SL_MAIN_ICON, _("No AI bots found in your Spring installation."), _("No bot-libs found"), wxOK );
+ }
+ m_add_btn->Enable( m_ai->GetStringSelection() != wxEmptyString );
+ ShowAIInfo();
+ ShowAIOptions();
+}
+
+
+void AddBotDialog::OnClose( wxCommandEvent& /*event*/ )
+{
+ EndModal( wxID_CANCEL );
+}
+
+
+void AddBotDialog::OnAddBot( wxCommandEvent& /*event*/ )
+{
+ sett().SetLastAI( m_ai->GetStringSelection() );
+ EndModal( wxID_OK );
+}
+
+
+void AddBotDialog::OnSelectBot( wxCommandEvent& /*unused*/ )
+{
+ ShowAIInfo();
+ ShowAIOptions();
+}
+
+void AddBotDialog::ShowAIInfo()
+{
+ m_add_btn->Enable( m_ai->GetStringSelection() != wxEmptyString );
+ if ( !usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) ) return;
+ m_ai_infos_lst->DeleteAllItems();
+ wxArrayString info = usync().GetAIInfos( GetAIType() );
+ int count = info.GetCount();
+ for ( int i = 0; i < count; i = i + 3 )
+ {
+ long index = m_ai_infos_lst->InsertItem( i, info[i] );
+ m_ai_infos_lst->SetItem( index, 0, info[i] );
+ m_ai_infos_lst->SetItem( index, 1, info[i+1] );
+ }
+ m_ai_infos_lst->SetColumnWidth( 0, wxLIST_AUTOSIZE );
+ m_ai_infos_lst->SetColumnWidth( 1, wxLIST_AUTOSIZE );
+ Layout();
+ SetSize( wxDefaultSize );
+}
+
+
+void AddBotDialog::ShowAIOptions()
+{
+ if ( !usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) ) return;
+ m_opts_list->DeleteAllItems();
+ m_opt_list_map.clear();
+ m_battle.CustomBattleOptions().loadAIOptions( m_battle.GetHostModName(), GetAIType(), GetNick() );
+ AddMMOptionsToList( 0, m_battle.CustomBattleOptions().GetAIOptionIndex( GetNick() ) );
+ m_opts_list->SetColumnWidth( 0, wxLIST_AUTOSIZE );
+ m_opts_list->SetColumnWidth( 1, wxLIST_AUTOSIZE );
+ Layout();
+ SetSize( wxDefaultSize );
+}
+
+long AddBotDialog::AddMMOptionsToList( long pos, int optFlag )
+{
+ OptionsWrapper::wxStringTripleVec optlist = m_battle.CustomBattleOptions().getOptions( (OptionsWrapper::GameOption)optFlag );
+ for ( OptionsWrapper::wxStringTripleVec::iterator it = optlist.begin(); it != optlist.end(); ++it )
+ {
+ m_opts_list->InsertItem( pos, it->second.first );
+ wxString tag = wxString::Format( _T( "%d_" ), optFlag ) + it->first;
+ m_opt_list_map[ tag ] = pos;
+ UpdateOption( tag );
+ pos++;
+ }
+ return pos;
+}
+
+
+void AddBotDialog::UpdateOption( const wxString& Tag )
+{
+ long index = m_opt_list_map[ Tag ];
+ OptionsWrapper::GameOption type = ( OptionsWrapper::GameOption )s2l( Tag.BeforeFirst( '_' ) );
+ wxString key = Tag.AfterFirst( '_' );
+ wxString value;
+
+ OptionType DataType = m_battle.CustomBattleOptions().GetSingleOptionType( key );
+ value = m_battle.CustomBattleOptions().getSingleValue( key, ( OptionsWrapper::GameOption )type );
+ if ( m_battle.CustomBattleOptions().getDefaultValue( key, type ) == value ) m_opts_list->SetItemFont( index, wxFont( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT ) );
+ else m_opts_list->SetItemFont( index, wxFont( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD ) );
+ if ( DataType == opt_bool )
+ {
+ value = bool2yn( s2l( value ) ); // convert from 0/1 to literal Yes/No
+ }
+ else if ( DataType == opt_list )
+ {
+ value = m_battle.CustomBattleOptions().GetNameListOptValue( key, type ); // get the key full name not short key
+ }
+ m_opts_list->SetItem( index, 1, value );
+ m_opts_list->SetColumnWidth( 1, wxLIST_AUTOSIZE );
+}
+
+void AddBotDialog::OnOptionActivate( wxListEvent& event )
+{
+ long index = event.GetIndex();
+ wxString tag;
+ for ( OptionListMap::iterator itor = m_opt_list_map.begin(); itor != m_opt_list_map.end(); itor++ )
+ {
+ if ( itor->second == index )
+ {
+ tag = itor->first;
+ break;
+ }
+ }
+ OptionsWrapper& optWrap = m_battle.CustomBattleOptions();
+ OptionsWrapper::GameOption optFlag = ( OptionsWrapper::GameOption )s2l( tag.BeforeFirst( '_' ) );
+ wxString key = tag.AfterFirst( '_' );
+ OptionType type = optWrap.GetSingleOptionType( key );
+ if ( !optWrap.keyExists( key, optFlag, false, type ) ) return;
+ SingleOptionDialog dlg( m_battle, tag );
+ dlg.ShowModal();
+ UpdateOption( tag );
+}
diff --git a/src/addbotdialog.h b/src/addbotdialog.h
new file mode 100644
index 0000000..c623f9d
--- /dev/null
+++ b/src/addbotdialog.h
@@ -0,0 +1,103 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_ADDBOTDIALOG_H
+#define SPRINGLOBBY_HEADERGUARD_ADDBOTDIALOG_H
+
+#include <wx/dialog.h>
+#include <map>
+
+class wxTextCtrl;
+class wxStaticText;
+class wxChoice;
+class wxStaticLine;
+class wxButton;
+class wxCommandEvent;
+class IBattle;
+class wxListCtrl;
+class wxBoxSizer;
+class wxListEvent;
+
+/** \brief used in SP/MP BattletAB to present choice of AIs to add
+ * \todo DOCMEMORE */
+class AddBotDialog : public wxDialog
+{
+ public:
+
+ AddBotDialog( wxWindow* parent, IBattle& battle, bool singleplayer = false );
+
+ wxString GetNick();
+ wxString GetAIShortName();
+ wxString GetAIVersion();
+ int GetAIType();
+
+ void ReloadAIList();
+ void ShowAIInfo();
+
+ void OnClose( wxCommandEvent& event );
+ void OnAddBot( wxCommandEvent& event );
+ void OnSelectBot( wxCommandEvent& event );
+
+ void OnOptionActivate( wxListEvent& event );
+ void UpdateOption( const wxString& Tag );
+ long AddMMOptionsToList( long pos, int optFlag );
+ void ShowAIOptions();
+
+
+ protected:
+ AddBotDialog( const AddBotDialog& );
+
+ wxStaticText* m_nick_lbl;
+ wxTextCtrl* m_nick;
+ wxStaticText* m_ai_lbl;
+ wxChoice* m_ai;
+ wxStaticLine* m_buttons_sep;
+ wxButton* m_cancel_btn;
+ wxButton* m_add_btn;
+ wxListCtrl* m_ai_infos_lst;
+ wxListCtrl* m_opts_list;
+
+ typedef std::map<wxString, long> OptionListMap;
+ OptionListMap m_opt_list_map;
+
+ wxBoxSizer* m_main_sizer;
+ wxBoxSizer* m_info_sizer;
+
+
+ IBattle& m_battle;
+
+ wxArrayString m_ais;
+
+ bool m_sp;
+
+ wxString RefineAIName( const wxString& name );
+
+ enum
+ {
+ ADDBOT_ADD = wxID_HIGHEST,
+ ADDBOT_CANCEL,
+ ADDBOT_AI,
+ ADDBOT_OPTIONLIST,
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_ADDBOTDIALOG_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/agreementdialog.cpp b/src/agreementdialog.cpp
new file mode 100644
index 0000000..388ea6b
--- /dev/null
+++ b/src/agreementdialog.cpp
@@ -0,0 +1,67 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: AgreementDialog
+//
+#include "agreementdialog.h"
+
+#include <wx/textctrl.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/statline.h>
+
+#include "uiutils.h"
+
+BEGIN_EVENT_TABLE( AgreementDialog, wxDialog )
+
+ EVT_BUTTON ( AGREE_YES, AgreementDialog::OnYes )
+ EVT_BUTTON ( AGREE_NO, AgreementDialog::OnNo )
+
+END_EVENT_TABLE()
+
+
+AgreementDialog::AgreementDialog( wxWindow* parent, const wxString& agreement ):
+ wxDialog( parent, -1, _( "Accept Agreement" ), wxDefaultPosition, wxDefaultSize )
+{
+ SetSizeHints( wxDefaultSize, wxDefaultSize );
+
+ wxBoxSizer* m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_text = new wxTextCtrl( this, wxID_ANY, RTFtoText( agreement ), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_RICH | wxTE_WORDWRAP );
+ m_main_sizer->Add( m_text, 1, wxALL | wxEXPAND, 5 );
+
+ m_accept_lbl = new wxStaticText( this, wxID_ANY, _( "Do you accept the terms of this agreement?" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_main_sizer->Add( m_accept_lbl, 0, wxALL, 5 );
+
+ m_button_sep = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ m_main_sizer->Add( m_button_sep, 0, wxALL | wxEXPAND, 5 );
+
+ wxBoxSizer* m_button_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_yes_btn = new wxButton( this, AGREE_YES, _( "Yes" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_button_sizer->Add( m_yes_btn, 0, wxALL, 5 );
+
+ m_button_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+ m_no_btn = new wxButton( this, AGREE_NO, _( "No" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_button_sizer->Add( m_no_btn, 0, wxALL, 5 );
+
+ m_main_sizer->Add( m_button_sizer, 0, wxEXPAND, 5 );
+
+ m_no_btn->SetDefault();
+
+ SetSizer( m_main_sizer );
+ Layout();
+}
+
+
+void AgreementDialog::OnYes( wxCommandEvent& /*unused*/ )
+{
+ EndModal( 1 );
+}
+
+
+void AgreementDialog::OnNo( wxCommandEvent& /*unused*/ )
+{
+ EndModal( 0 );
+}
diff --git a/src/agreementdialog.h b/src/agreementdialog.h
new file mode 100644
index 0000000..a0f0f3c
--- /dev/null
+++ b/src/agreementdialog.h
@@ -0,0 +1,55 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_AGREEMENTDIALOG_H
+#define SPRINGLOBBY_HEADERGUARD_AGREEMENTDIALOG_H
+
+#include <wx/dialog.h>
+
+class wxTextCtrl;
+class wxStaticText;
+class wxStaticLine;
+class wxButton;
+
+/** \brief dialog showing agreement on first start/ register that user needs to accept
+ * \todo DOCMEMORE */
+class AgreementDialog : public wxDialog
+{
+ public:
+ AgreementDialog( wxWindow* parent, const wxString& agreement );
+
+ void OnYes( wxCommandEvent& event );
+ void OnNo( wxCommandEvent& event );
+
+ protected:
+ wxTextCtrl* m_text;
+ wxStaticText* m_accept_lbl;
+ wxStaticLine* m_button_sep;
+ wxButton* m_yes_btn;
+ wxButton* m_no_btn;
+
+ enum {
+ AGREE_YES = wxID_HIGHEST,
+ AGREE_NO,
+ };
+
+ DECLARE_EVENT_TABLE()
+
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_AGREEMENTDIALOG_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/aui/artprovider.cpp b/src/aui/artprovider.cpp
new file mode 100644
index 0000000..199d3bd
--- /dev/null
+++ b/src/aui/artprovider.cpp
@@ -0,0 +1,677 @@
+#include "artprovider.h"
+#include <wx/dc.h>
+#include <wx/settings.h>
+#include <wx/image.h>
+#include <wx/menu.h>
+#include <wx/aui/framemanager.h>
+#include <wx/aui/dockart.h>
+#include <wx/aui/floatpane.h>
+#include "auiutils.h"
+#include "../uiutils.h"
+
+SLArtProvider::SLArtProvider()
+{
+ m_normal_font = *wxNORMAL_FONT;
+ m_selected_font = *wxNORMAL_FONT;
+ m_selected_font.SetWeight(wxBOLD);
+ m_measuring_font = m_selected_font;
+
+ m_fixed_tab_width = 100;
+ m_tab_ctrl_height = 0;
+
+#ifdef __WXMAC__
+ wxBrush toolbarbrush;
+ toolbarbrush.MacSetTheme( kThemeBrushToolbarBackground );
+ wxColour base_colour = toolbarbrush.GetColour();
+#else
+ wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
+#endif
+
+ // the base_colour is too pale to use as our base colour,
+ // so darken it a bit --
+ if ((255-base_colour.Red()) +
+ (255-base_colour.Green()) +
+ (255-base_colour.Blue()) < 60)
+ {
+ base_colour = wxAuiStepColour(base_colour, 92);
+ }
+
+ m_base_colour = base_colour;
+ wxColour border_colour = wxAuiStepColour(base_colour, 75);
+
+ m_border_pen = wxPen(border_colour);
+ m_base_colour_pen = wxPen(m_base_colour);
+ m_base_colour_brush = wxBrush(m_base_colour);
+
+ m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
+ m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
+
+ m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
+ m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
+
+ m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
+ m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
+
+ m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
+ m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
+
+ m_flags = 0;
+}
+
+SLArtProvider::~SLArtProvider()
+{
+}
+
+wxAuiTabArt* SLArtProvider::Clone()
+{
+ SLArtProvider* art = new SLArtProvider;
+ art->SetNormalFont(m_normal_font);
+ art->SetSelectedFont(m_selected_font);
+ art->SetMeasuringFont(m_measuring_font);
+
+ return art;
+}
+
+void SLArtProvider::SetFlags(unsigned int flags)
+{
+ m_flags = flags;
+}
+
+void SLArtProvider::SetSizingInfo(const wxSize& tab_ctrl_size,
+ size_t tab_count)
+{
+ m_fixed_tab_width = 100;
+
+ int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
+
+ if (m_flags & wxAUI_NB_CLOSE_BUTTON)
+ tot_width -= m_active_close_bmp.GetWidth();
+ if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
+ tot_width -= m_active_windowlist_bmp.GetWidth();
+
+ if (tab_count > 0)
+ {
+ m_fixed_tab_width = tot_width/(int)tab_count;
+ }
+
+
+ if (m_fixed_tab_width < 100)
+ m_fixed_tab_width = 100;
+
+ if (m_fixed_tab_width > tot_width/2)
+ m_fixed_tab_width = tot_width/2;
+
+ if (m_fixed_tab_width > 220)
+ m_fixed_tab_width = 220;
+
+ m_tab_ctrl_height = tab_ctrl_size.y;
+}
+
+
+void SLArtProvider::DrawBackground(wxDC& dc,
+ wxWindow* WXUNUSED(wnd),
+ const wxRect& rect)
+{
+ // draw background
+ wxColour top_color = wxAuiStepColour(m_base_colour, 90);
+ wxColour bottom_color = wxAuiStepColour(m_base_colour, 170);
+ wxRect r;
+
+ if (m_flags &wxAUI_NB_BOTTOM)
+ r = wxRect(rect.x, rect.y, rect.width+2, rect.height);
+ // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
+ // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
+ else //for wxAUI_NB_TOP
+ r = wxRect(rect.x, rect.y, rect.width+2, rect.height-3);
+ dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
+
+ // draw base lines
+ dc.SetPen(m_border_pen);
+ int y = rect.GetHeight();
+ int w = rect.GetWidth();
+
+ if (m_flags &wxAUI_NB_BOTTOM)
+ {
+ dc.SetBrush(wxBrush(bottom_color));
+ dc.DrawRectangle(-1, 0, w+2, 4);
+ }
+ // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
+ // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
+ else //for wxAUI_NB_TOP
+ {
+ dc.SetBrush(m_base_colour_brush);
+ dc.DrawRectangle(-1, y-4, w+2, 4);
+ }
+}
+
+
+// DrawTab() draws an individual tab.
+//
+// dc - output dc
+// in_rect - rectangle the tab should be confined to
+// caption - tab's caption
+// active - whether or not the tab is active
+// out_rect - actual output rectangle
+// x_extent - the advance x; where the next tab should start
+
+void SLArtProvider::DrawTab(wxDC& dc,
+ wxWindow* wnd,
+ const wxAuiNotebookPage& page,
+ const wxRect& in_rect,
+ int close_button_state,
+ wxRect* out_tab_rect,
+ wxRect* out_button_rect,
+ int* x_extent)
+{
+ wxCoord normal_textx, normal_texty;
+ wxCoord selected_textx, selected_texty;
+ wxCoord texty;
+
+ // if the caption is empty, measure some temporary text
+ wxString caption = page.caption;
+ if (caption.empty())
+ caption = wxT("Xj");
+
+ dc.SetFont(m_selected_font);
+ dc.GetTextExtent(caption, &selected_textx, &selected_texty);
+
+ dc.SetFont(m_normal_font);
+ dc.GetTextExtent(caption, &normal_textx, &normal_texty);
+
+ // figure out the size of the tab
+ wxSize tab_size = GetTabSize(dc,
+ wnd,
+ page.caption,
+ page.bitmap,
+ page.active,
+ close_button_state,
+ x_extent);
+
+ wxCoord tab_height = m_tab_ctrl_height - 3;
+ wxCoord tab_width = tab_size.x;
+ wxCoord tab_x = in_rect.x;
+ wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
+
+
+ caption = page.caption;
+
+
+ // select pen, brush and font for the tab to be drawn
+
+ if (page.active)
+ {
+ dc.SetFont(m_selected_font);
+ texty = selected_texty;
+ }
+ else
+ {
+ dc.SetFont(m_normal_font);
+ texty = normal_texty;
+ }
+
+
+ // create points that will make the tab outline
+
+ int clip_width = tab_width;
+ if (tab_x + clip_width > in_rect.x + in_rect.width)
+ clip_width = (in_rect.x + in_rect.width) - tab_x;
+
+/*
+ wxPoint clip_points[6];
+ clip_points[0] = wxPoint(tab_x, tab_y+tab_height-3);
+ clip_points[1] = wxPoint(tab_x, tab_y+2);
+ clip_points[2] = wxPoint(tab_x+2, tab_y);
+ clip_points[3] = wxPoint(tab_x+clip_width-1, tab_y);
+ clip_points[4] = wxPoint(tab_x+clip_width+1, tab_y+2);
+ clip_points[5] = wxPoint(tab_x+clip_width+1, tab_y+tab_height-3);
+
+ // FIXME: these ports don't provide wxRegion ctor from array of points
+#if !defined(__WXDFB__) && !defined(__WXCOCOA__)
+ // set the clipping region for the tab --
+ wxRegion clipping_region(WXSIZEOF(clip_points), clip_points);
+ dc.SetClippingRegion(clipping_region);
+#endif // !wxDFB && !wxCocoa
+*/
+ // since the above code above doesn't play well with WXDFB or WXCOCOA,
+ // we'll just use a rectangle for the clipping region for now --
+ dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3);
+
+
+ wxPoint border_points[6];
+ if (m_flags &wxAUI_NB_BOTTOM)
+ {
+ border_points[0] = wxPoint(tab_x, tab_y);
+ border_points[1] = wxPoint(tab_x, tab_y+tab_height-6);
+ border_points[2] = wxPoint(tab_x+2, tab_y+tab_height-4);
+ border_points[3] = wxPoint(tab_x+tab_width-2, tab_y+tab_height-4);
+ border_points[4] = wxPoint(tab_x+tab_width, tab_y+tab_height-6);
+ border_points[5] = wxPoint(tab_x+tab_width, tab_y);
+ }
+ else //if (m_flags & wxAUI_NB_TOP) {}
+ {
+ border_points[0] = wxPoint(tab_x, tab_y+tab_height-4);
+ border_points[1] = wxPoint(tab_x, tab_y+2);
+ border_points[2] = wxPoint(tab_x+2, tab_y);
+ border_points[3] = wxPoint(tab_x+tab_width-2, tab_y);
+ border_points[4] = wxPoint(tab_x+tab_width, tab_y+2);
+ border_points[5] = wxPoint(tab_x+tab_width, tab_y+tab_height-4);
+ }
+ // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
+ // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
+
+ int drawn_tab_yoff = border_points[1].y;
+ int drawn_tab_height = border_points[0].y - border_points[1].y;
+
+
+ if (page.active)
+ {
+ // draw active tab
+
+ // draw base background color
+ wxRect r(tab_x, tab_y, tab_width, tab_height);
+ dc.SetPen(m_base_colour_pen);
+ dc.SetBrush(m_base_colour_brush);
+ dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4);
+
+ // this white helps fill out the gradient at the top of the tab
+ dc.SetPen(*wxWHITE_PEN);
+ dc.SetBrush(*wxWHITE_BRUSH);
+ dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4);
+
+ // these two points help the rounded corners appear more antialiased
+ dc.SetPen(m_base_colour_pen);
+ dc.DrawPoint(r.x+2, r.y+1);
+ dc.DrawPoint(r.x+r.width-2, r.y+1);
+
+ // set rectangle down a bit for gradient drawing
+ r.SetHeight(r.GetHeight()/2);
+ r.x += 2;
+ r.width -= 2;
+ r.y += r.height;
+ r.y -= 2;
+
+ // draw gradient background
+ wxColour top_color = *wxWHITE;
+ wxColour bottom_color = m_base_colour;
+ dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
+ }
+ else
+ {
+ // draw inactive tab
+
+ wxRect r(tab_x, tab_y+1, tab_width, tab_height-3);
+
+ // start the gradent up a bit and leave the inside border inset
+ // by a pixel for a 3D look. Only the top half of the inactive
+ // tab will have a slight gradient
+ r.x += 3;
+ r.y++;
+ r.width -= 4;
+ r.height /= 2;
+ r.height--;
+
+ // -- draw top gradient fill for glossy look
+ wxColour top_color = m_base_colour;
+ wxColour bottom_color = wxAuiStepColour(top_color, 160);
+ dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
+
+ r.y += r.height;
+ r.y--;
+
+ // -- draw bottom fill for glossy look
+ top_color = m_base_colour;
+ bottom_color = m_base_colour;
+ dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
+ }
+
+ // draw tab outline
+ dc.SetPen(m_border_pen);
+ dc.SetBrush(*wxTRANSPARENT_BRUSH);
+ dc.DrawPolygon(WXSIZEOF(border_points), border_points);
+
+ // there are two horizontal grey lines at the bottom of the tab control,
+ // this gets rid of the top one of those lines in the tab control
+ if (page.active)
+ {
+ if (m_flags &wxAUI_NB_BOTTOM)
+ dc.SetPen(wxPen(wxColour(wxAuiStepColour(m_base_colour, 170))));
+ // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
+ // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
+ else //for wxAUI_NB_TOP
+ dc.SetPen(m_base_colour_pen);
+ dc.DrawLine(border_points[0].x+1,
+ border_points[0].y,
+ border_points[5].x,
+ border_points[5].y);
+ }
+
+
+ int text_offset = tab_x + 8;
+ int close_button_width = 0;
+ if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
+ {
+ close_button_width = m_active_close_bmp.GetWidth();
+ }
+
+
+ int bitmap_offset = 0;
+ if (page.bitmap.IsOk())
+ {
+ bitmap_offset = tab_x + 8;
+
+ // draw bitmap
+ dc.DrawBitmap(page.bitmap,
+ bitmap_offset,
+ drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
+ true);
+
+ text_offset = bitmap_offset + page.bitmap.GetWidth();
+ text_offset += 3; // bitmap padding
+ }
+ else
+ {
+ text_offset = tab_x + 8;
+ }
+
+
+ wxString draw_text = wxAuiChopText(dc,
+ caption,
+ tab_width - (text_offset-tab_x) - close_button_width);
+
+ // draw tab text
+ wxColour fg_color = dc.GetTextForeground( );
+ if (!page.active ) {
+
+ wxColour fg_color_new = fg_color;
+ if ( AreColoursSimilar( fg_color, dc.GetTextBackground() , 50 ) )
+ {
+ fg_color_new = wxColour( ( fg_color.Red() +125 ) % 255 , ( fg_color.Green() +125 ) % 255, ( fg_color.Blue() +125 ) % 255 );
+ }
+ dc.SetTextForeground( wxAuiLightContrastColour(fg_color_new) );
+ }
+
+ dc.DrawText(draw_text,
+ text_offset,
+ drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1);
+ dc.SetTextForeground( (fg_color) );
+
+ // draw close button if necessary
+ if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
+ {
+ wxBitmap bmp = m_disabled_close_bmp;
+
+ if (close_button_state == wxAUI_BUTTON_STATE_HOVER ||
+ close_button_state == wxAUI_BUTTON_STATE_PRESSED)
+ {
+ bmp = m_active_close_bmp;
+ }
+
+ wxRect rect(tab_x + tab_width - close_button_width - 1,
+ tab_y + (tab_height/2) - (bmp.GetHeight()/2),
+ close_button_width,
+ tab_height);
+ IndentPressedBitmap(&rect, close_button_state);
+ dc.DrawBitmap(bmp, rect.x, rect.y, true);
+
+ *out_button_rect = rect;
+ }
+
+ *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
+
+#ifndef __WXMAC__
+ // draw focus rectangle
+ if (page.active && (wnd->FindFocus() == wnd))
+ {
+ wxRect focusRectText(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1),
+ selected_textx, selected_texty);
+
+ wxRect focusRect;
+ wxRect focusRectBitmap;
+
+ if (page.bitmap.IsOk())
+ focusRectBitmap = wxRect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
+ page.bitmap.GetWidth(), page.bitmap.GetHeight());
+
+ if (page.bitmap.IsOk() && draw_text.IsEmpty())
+ focusRect = focusRectBitmap;
+ else if (!page.bitmap.IsOk() && !draw_text.IsEmpty())
+ focusRect = focusRectText;
+ else if (page.bitmap.IsOk() && !draw_text.IsEmpty())
+ focusRect = focusRectText.Union(focusRectBitmap);
+
+ focusRect.Inflate(2, 2);
+
+ DrawFocusRect(wnd, dc, focusRect, 0);
+ }
+#endif
+
+ dc.DestroyClippingRegion();
+}
+
+int SLArtProvider::GetIndentSize()
+{
+ return 5;
+}
+
+wxSize SLArtProvider::GetTabSize(wxDC& dc,
+ wxWindow* WXUNUSED(wnd),
+ const wxString& caption,
+ const wxBitmap& bitmap,
+ bool WXUNUSED(active),
+ int close_button_state,
+ int* x_extent)
+{
+ wxCoord measured_textx, measured_texty, tmp;
+
+ dc.SetFont(m_measuring_font);
+ dc.GetTextExtent(caption, &measured_textx, &measured_texty);
+
+ dc.GetTextExtent(wxT("ABCDEFXj"), &tmp, &measured_texty);
+
+ // add padding around the text
+ wxCoord tab_width = measured_textx;
+ wxCoord tab_height = measured_texty;
+
+ // if the close button is showing, add space for it
+ if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
+ tab_width += m_active_close_bmp.GetWidth() + 3;
+
+ // if there's a bitmap, add space for it
+ if (bitmap.IsOk())
+ {
+ tab_width += bitmap.GetWidth();
+ tab_width += 3; // right side bitmap padding
+ tab_height = wxMax(tab_height, bitmap.GetHeight());
+ }
+
+ // add padding
+ tab_width += 16;
+ tab_height += 10;
+
+ if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
+ {
+ tab_width = m_fixed_tab_width;
+ }
+
+ *x_extent = tab_width;
+
+ return wxSize(tab_width, tab_height);
+}
+
+
+void SLArtProvider::DrawButton(wxDC& dc,
+ wxWindow* WXUNUSED(wnd),
+ const wxRect& in_rect,
+ int bitmap_id,
+ int button_state,
+ int orientation,
+ wxRect* out_rect)
+{
+ wxBitmap bmp;
+ wxRect rect;
+
+ switch (bitmap_id)
+ {
+ case wxAUI_BUTTON_CLOSE:
+ if (button_state & wxAUI_BUTTON_STATE_DISABLED)
+ bmp = m_disabled_close_bmp;
+ else
+ bmp = m_active_close_bmp;
+ break;
+ case wxAUI_BUTTON_LEFT:
+ if (button_state & wxAUI_BUTTON_STATE_DISABLED)
+ bmp = m_disabled_left_bmp;
+ else
+ bmp = m_active_left_bmp;
+ break;
+ case wxAUI_BUTTON_RIGHT:
+ if (button_state & wxAUI_BUTTON_STATE_DISABLED)
+ bmp = m_disabled_right_bmp;
+ else
+ bmp = m_active_right_bmp;
+ break;
+ case wxAUI_BUTTON_WINDOWLIST:
+ if (button_state & wxAUI_BUTTON_STATE_DISABLED)
+ bmp = m_disabled_windowlist_bmp;
+ else
+ bmp = m_active_windowlist_bmp;
+ break;
+ default: break;
+ }
+
+
+ if (!bmp.IsOk())
+ return;
+
+ rect = in_rect;
+
+ if (orientation == wxLEFT)
+ {
+ rect.SetX(in_rect.x);
+ rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
+ rect.SetWidth(bmp.GetWidth());
+ rect.SetHeight(bmp.GetHeight());
+ }
+ else
+ {
+ rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
+ ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
+ bmp.GetWidth(), bmp.GetHeight());
+ }
+
+ IndentPressedBitmap(&rect, button_state);
+ dc.DrawBitmap(bmp, rect.x, rect.y, true);
+
+ *out_rect = rect;
+}
+
+
+int SLArtProvider::ShowDropDown(wxWindow* wnd,
+ const wxAuiNotebookPageArray& pages,
+ int active_idx)
+{
+ wxMenu menuPopup;
+
+ size_t i, count = pages.GetCount();
+ for (i = 0; i < count; ++i)
+ {
+ const wxAuiNotebookPage& page = pages.Item(i);
+ wxString caption = page.caption;
+
+ // if there is no caption, make it a space. This will prevent
+ // an assert in the menu code.
+ if (caption.IsEmpty())
+ caption = wxT(" ");
+
+ menuPopup.AppendCheckItem(1000+i, caption);
+ }
+
+ if (active_idx != -1)
+ {
+ menuPopup.Check(1000+active_idx, true);
+ }
+
+ // find out where to put the popup menu of window items
+ wxPoint pt = ::wxGetMousePosition();
+ pt = wnd->ScreenToClient(pt);
+
+ // find out the screen coordinate at the bottom of the tab ctrl
+ wxRect cli_rect = wnd->GetClientRect();
+ pt.y = cli_rect.y + cli_rect.height;
+
+ wxAuiCommandCapture* cc = new wxAuiCommandCapture;
+ wnd->PushEventHandler(cc);
+ wnd->PopupMenu(&menuPopup, pt);
+ int command = cc->GetCommandId();
+ wnd->PopEventHandler(true);
+
+ if (command >= 1000)
+ return command-1000;
+
+ return -1;
+}
+
+int SLArtProvider::GetBestTabCtrlSize(wxWindow* wnd,
+ const wxAuiNotebookPageArray& pages,
+ const wxSize& required_bmp_size)
+{
+ wxClientDC dc(wnd);
+ dc.SetFont(m_measuring_font);
+
+ // sometimes a standard bitmap size needs to be enforced, especially
+ // if some tabs have bitmaps and others don't. This is important because
+ // it prevents the tab control from resizing when tabs are added.
+ wxBitmap measure_bmp;
+ if (required_bmp_size.IsFullySpecified())
+ {
+ measure_bmp.Create(required_bmp_size.x,
+ required_bmp_size.y);
+ }
+
+
+ int max_y = 0;
+ size_t i, page_count = pages.GetCount();
+ for (i = 0; i < page_count; ++i)
+ {
+ wxAuiNotebookPage& page = pages.Item(i);
+
+ wxBitmap bmp;
+ if (measure_bmp.IsOk())
+ bmp = measure_bmp;
+ else
+ bmp = page.bitmap;
+
+ // we don't use the caption text because we don't
+ // want tab heights to be different in the case
+ // of a very short piece of text on one tab and a very
+ // tall piece of text on another tab
+ int x_ext = 0;
+ wxSize s = GetTabSize(dc,
+ wnd,
+ wxT("ABCDEFGHIj"),
+ bmp,
+ true,
+ wxAUI_BUTTON_STATE_HIDDEN,
+ &x_ext);
+
+ max_y = wxMax(max_y, s.y);
+ }
+
+ return max_y+2;
+}
+
+void SLArtProvider::SetNormalFont(const wxFont& font)
+{
+ m_normal_font = font;
+}
+
+void SLArtProvider::SetSelectedFont(const wxFont& font)
+{
+ m_selected_font = font;
+}
+
+void SLArtProvider::SetMeasuringFont(const wxFont& font)
+{
+ m_measuring_font = font;
+}
+
diff --git a/src/aui/artprovider.h b/src/aui/artprovider.h
new file mode 100644
index 0000000..a7cafbd
--- /dev/null
+++ b/src/aui/artprovider.h
@@ -0,0 +1,107 @@
+#ifndef SPRINGLOBBY_ARTPROVIDER_H_INCLUDED
+#define SPRINGLOBBY_ARTPROVIDER_H_INCLUDED
+
+#include <wx/aui/aui.h>
+
+class SLArtProvider : public wxAuiTabArt
+{
+
+public:
+
+ SLArtProvider();
+ virtual ~SLArtProvider();
+
+ wxAuiTabArt* Clone();
+ void SetFlags(unsigned int flags);
+ void SetSizingInfo(const wxSize& tab_ctrl_size,
+ size_t tab_count);
+
+ void SetNormalFont(const wxFont& font);
+ void SetSelectedFont(const wxFont& font);
+ void SetMeasuringFont(const wxFont& font);
+
+ void DrawBackground(
+ wxDC& dc,
+ wxWindow* wnd,
+ const wxRect& rect);
+
+ void DrawTab(wxDC& dc,
+ wxWindow* wnd,
+ const wxAuiNotebookPage& pane,
+ const wxRect& in_rect,
+ int close_button_state,
+ wxRect* out_tab_rect,
+ wxRect* out_button_rect,
+ int* x_extent);
+
+ void DrawButton(
+ wxDC& dc,
+ wxWindow* wnd,
+ const wxRect& in_rect,
+ int bitmap_id,
+ int button_state,
+ int orientation,
+ wxRect* out_rect);
+
+ int GetIndentSize();
+
+ wxSize GetTabSize(
+ wxDC& dc,
+ wxWindow* wnd,
+ const wxString& caption,
+ const wxBitmap& bitmap,
+ bool active,
+ int close_button_state,
+ int* x_extent);
+
+ int ShowDropDown(
+ wxWindow* wnd,
+ const wxAuiNotebookPageArray& items,
+ int active_idx);
+
+ int GetBestTabCtrlSize(wxWindow* wnd,
+ const wxAuiNotebookPageArray& pages,
+ const wxSize& required_bmp_size);
+
+protected:
+
+ wxFont m_normal_font;
+ wxFont m_selected_font;
+ wxFont m_measuring_font;
+ wxColour m_base_colour;
+ wxPen m_base_colour_pen;
+ wxPen m_border_pen;
+ wxBrush m_base_colour_brush;
+ wxBitmap m_active_close_bmp;
+ wxBitmap m_disabled_close_bmp;
+ wxBitmap m_active_left_bmp;
+ wxBitmap m_disabled_left_bmp;
+ wxBitmap m_active_right_bmp;
+ wxBitmap m_disabled_right_bmp;
+ wxBitmap m_active_windowlist_bmp;
+ wxBitmap m_disabled_windowlist_bmp;
+
+ int m_fixed_tab_width;
+ int m_tab_ctrl_height;
+ unsigned int m_flags;
+};
+
+#endif // SPRINGLOBBY_ARTPROVIDER_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/aui/auimanager.cpp b/src/aui/auimanager.cpp
new file mode 100644
index 0000000..e2fcab6
--- /dev/null
+++ b/src/aui/auimanager.cpp
@@ -0,0 +1,8 @@
+#include "auimanager.h"
+#include "../globalsmanager.h"
+
+AuiManagerContainer& GetAui()
+{
+ static GlobalObjectHolder<AuiManagerContainer> m_aui;
+ return m_aui;
+}
diff --git a/src/aui/auimanager.h b/src/aui/auimanager.h
new file mode 100644
index 0000000..76f407c
--- /dev/null
+++ b/src/aui/auimanager.h
@@ -0,0 +1,49 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_AUIMANAGER_H
+#define SPRINGLOBBY_HEADERGUARD_AUIMANAGER_H
+
+#include <wx/aui/aui.h>
+
+class wxAuiManagerDupe {
+ public:
+ wxAuiManagerDupe(wxWindow* managed_wnd = NULL, unsigned int flags = 0 ) {}
+ bool AddPane(wxWindow* window, int direction = wxLEFT, const wxString& caption = wxEmptyString) { return false; }
+ bool DetachPane(wxWindow* window) { return false; }
+ void UnInit() {}
+ wxString SavePerspective() { return wxEmptyString; }
+ bool LoadPerspective(const wxString& perspective, bool update = true) { return false; }
+};
+
+class AuiManagerContainer
+{
+ public:
+ AuiManagerContainer() {}
+
+ typedef wxAuiManager
+ ManagerType;
+
+ ManagerType* manager;
+};
+
+AuiManagerContainer& GetAui();
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_AUIMANAGER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/aui/auiutils.h b/src/aui/auiutils.h
new file mode 100644
index 0000000..f6f71e2
--- /dev/null
+++ b/src/aui/auiutils.h
@@ -0,0 +1,257 @@
+#ifndef AUIUITLS_H_INCLUDED
+#define AUIUITLS_H_INCLUDED
+
+#include <wx/aui/tabmdi.h>
+#include <wx/dcbuffer.h>
+#include <wx/log.h>
+
+#ifdef __WXMSW__
+#include <wx/msw/private.h>
+#endif
+
+#ifdef __WXMAC__
+#include <wx/mac/carbon/private.h>
+#endif
+
+
+
+static double wxAuiBlendColour(double fg, double bg, double alpha)
+{
+ double result = bg + (alpha * (fg - bg));
+ if (result < 0.0)
+ result = 0.0;
+ if (result > 255)
+ result = 255;
+ return result;
+}
+
+// wxAuiStepColour() it a utility function that simply darkens
+// or lightens a color, based on the specified percentage
+// ialpha of 0 would be completely black, 100 completely white
+// an ialpha of 100 returns the same colour
+static wxColor wxAuiStepColour(const wxColor& c, int ialpha)
+{
+ if (ialpha == 100)
+ return c;
+
+ double r = c.Red(), g = c.Green(), b = c.Blue();
+ double bg;
+
+ // ialpha is 0..200 where 0 is completely black
+ // and 200 is completely white and 100 is the same
+ // convert that to normal alpha 0.0 - 1.0
+ ialpha = wxMin(ialpha, 200);
+ ialpha = wxMax(ialpha, 0);
+ double alpha = ((double)(ialpha - 100.0))/100.0;
+
+ if (ialpha > 100)
+ {
+ // blend with white
+ bg = 255.0;
+ alpha = 1.0 - alpha; // 0 = transparent fg; 1 = opaque fg
+ }
+ else
+ {
+ // blend with black
+ bg = 0.0;
+ alpha = 1.0 + alpha; // 0 = transparent fg; 1 = opaque fg
+ }
+
+ r = wxAuiBlendColour(r, bg, alpha);
+ g = wxAuiBlendColour(g, bg, alpha);
+ b = wxAuiBlendColour(b, bg, alpha);
+
+ return wxColour((unsigned char)r, (unsigned char)g, (unsigned char)b);
+}
+
+
+static wxColor wxAuiLightContrastColour(const wxColour& c)
+{
+ int amount = 120;
+
+ // if the color is especially dark, then
+ // make the contrast even lighter
+ if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
+ amount = 160;
+
+ return wxAuiStepColour(c, amount);
+}
+
+// wxAuiBitmapFromBits() is a utility function that creates a
+// masked bitmap from raw bits (XBM format)
+static wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h,
+ const wxColour& color)
+{
+ wxImage img = wxBitmap((const char*)bits, w, h).ConvertToImage();
+ img.Replace(0,0,0,123,123,123);
+ img.Replace(255,255,255,color.Red(),color.Green(),color.Blue());
+ img.SetMaskColour(123,123,123);
+ return wxBitmap(img);
+}
+
+// -- bitmaps --
+
+#if defined( __WXMAC__ )
+ static unsigned char close_bits[]={
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
+ 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
+ 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
+#elif defined( __WXGTK__)
+ static unsigned char close_bits[]={
+ 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
+ 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
+ 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+#else
+ static unsigned char close_bits[]={
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9,
+ 0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+#endif
+
+static unsigned char left_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
+ 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static unsigned char right_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
+ 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static unsigned char list_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size)
+{
+ wxCoord x,y;
+
+ // first check if the text fits with no problems
+ dc.GetTextExtent(text, &x, &y);
+ if (x <= max_size)
+ return text;
+
+ size_t i, len = text.Length();
+ size_t last_good_length = 0;
+ for (i = 0; i < len; ++i)
+ {
+ wxString s = text.Left(i);
+ s += wxT("...");
+
+ dc.GetTextExtent(s, &x, &y);
+ if (x > max_size)
+ break;
+
+ last_good_length = i;
+ }
+
+ wxString ret = text.Left(last_good_length);
+ ret += wxT("...");
+ return ret;
+}
+
+static void IndentPressedBitmap(wxRect* rect, int button_state)
+{
+ if (button_state == wxAUI_BUTTON_STATE_PRESSED)
+ {
+ rect->x++;
+ rect->y++;
+ }
+}
+
+static void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
+{
+#if (defined(__WXMAC__))
+
+
+#else
+ wxUnusedVar(win);
+ wxUnusedVar(flags);
+
+ // draw the pixels manually because the "dots" in wxPen with wxDOT style
+ // may be short traits and not really dots
+ //
+ // note that to behave in the same manner as DrawRect(), we must exclude
+ // the bottom and right borders from the rectangle
+ wxCoord x1 = rect.GetLeft(),
+ y1 = rect.GetTop(),
+ x2 = rect.GetRight(),
+ y2 = rect.GetBottom();
+
+ dc.SetPen(*wxBLACK_PEN);
+
+#ifdef __WXMAC__
+ dc.SetLogicalFunction(wxCOPY);
+#else
+ // this seems to be closer than what Windows does than wxINVERT although
+ // I'm still not sure if it's correct
+ dc.SetLogicalFunction(wxAND_REVERSE);
+#endif
+
+ wxCoord z;
+ for ( z = x1 + 1; z < x2; z += 2 )
+ dc.DrawPoint(z, rect.GetTop());
+
+ wxCoord shift = z == x2 ? 0 : 1;
+ for ( z = y1 + shift; z < y2; z += 2 )
+ dc.DrawPoint(x2, z);
+
+ shift = z == y2 ? 0 : 1;
+ for ( z = x2 - shift; z > x1; z -= 2 )
+ dc.DrawPoint(z, y2);
+
+ shift = z == x1 ? 0 : 1;
+ for ( z = y2 - shift; z > y1; z -= 2 )
+ dc.DrawPoint(x1, z);
+
+ dc.SetLogicalFunction(wxCOPY);
+#endif
+}
+
+// -- GUI helper classes and functions --
+
+class wxAuiCommandCapture : public wxEvtHandler
+{
+public:
+
+ wxAuiCommandCapture() { m_last_id = 0; }
+ int GetCommandId() const { return m_last_id; }
+
+ bool ProcessEvent(wxEvent& evt)
+ {
+ if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED)
+ {
+ m_last_id = evt.GetId();
+ return true;
+ }
+
+ if (GetNextHandler())
+ return GetNextHandler()->ProcessEvent(evt);
+
+ return false;
+ }
+
+private:
+ int m_last_id;
+};
+
+#endif // AUIUITLS_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/aui/slbook.cpp b/src/aui/slbook.cpp
new file mode 100644
index 0000000..a1a53ea
--- /dev/null
+++ b/src/aui/slbook.cpp
@@ -0,0 +1,16 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+
+#include "slbook.h"
+#include "../settings.h"
+
+
+SLNotebook ::SLNotebook (wxWindow* parent, wxWindowID id , const wxPoint& pos , const wxSize& size , long style )
+ : wxAuiNotebook( parent, id, pos, size, sett().GetShowXallTabs() ? style | wxAUI_NB_CLOSE_ON_ALL_TABS : style )
+{
+ m_mgr.SetFlags(wxAUI_MGR_ALLOW_FLOATING |
+
+ wxAUI_MGR_HINT_FADE |
+ wxAUI_MGR_VENETIAN_BLINDS_HINT
+ );
+}
+
diff --git a/src/aui/slbook.h b/src/aui/slbook.h
new file mode 100644
index 0000000..91a6255
--- /dev/null
+++ b/src/aui/slbook.h
@@ -0,0 +1,31 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SLBOOK_H
+#define SPRINGLOBBY_HEADERGUARD_SLBOOK_H
+
+#include <wx/aui/aui.h>
+
+class SLNotebook : public wxAuiNotebook {
+
+ public:
+ SLNotebook (wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxAUI_NB_DEFAULT_STYLE);
+// wxAuiManager& GetAuiManager() { return m_mgr; }
+
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_SLBOOK_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/autobalancedialog.cpp b/src/autobalancedialog.cpp
new file mode 100644
index 0000000..56d3df2
--- /dev/null
+++ b/src/autobalancedialog.cpp
@@ -0,0 +1,107 @@
+#include "autobalancedialog.h"
+
+#include "settings.h"
+#include "utils/controls.h"
+#include "utils/conversion.h"
+
+//(*InternalHeaders(AutoBalanceDialog)
+#include <wx/intl.h>
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/statline.h>
+#include <wx/choice.h>
+#include <wx/button.h>
+//*)
+
+const long AutoBalanceDialog::ID_STATICTEXT1 = wxNewId();
+const long AutoBalanceDialog::ID_METHOD = wxNewId();
+const long AutoBalanceDialog::ID_STATICTEXT2 = wxNewId();
+const long AutoBalanceDialog::ID_STATICTEXT3 = wxNewId();
+const long AutoBalanceDialog::ID_CHOICE1 = wxNewId();
+const long AutoBalanceDialog::ID_CHOICE2 = wxNewId();
+const long AutoBalanceDialog::ID_STATICLINE1 = wxNewId();
+const long AutoBalanceDialog::ID_CANCEL = wxNewId();
+const long AutoBalanceDialog::ID_OK = wxNewId();
+
+BEGIN_EVENT_TABLE(AutoBalanceDialog,wxDialog)
+END_EVENT_TABLE()
+
+
+AutoBalanceDialog::AutoBalanceDialog( wxWindow* parent, const BalanceOptions& defaultval )
+{
+ wxFlexGridSizer* m_choices_sizer;
+ wxBoxSizer* m_buttons_sizer;
+ wxBoxSizer* m_main_sizer;
+
+ Create(parent, wxID_ANY, _("Autobalance players into teams"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, _T("wxID_ANY"));
+ m_main_sizer = new wxBoxSizer(wxVERTICAL);
+ m_choices_sizer = new wxFlexGridSizer(0, 2, wxDLG_UNIT(this,wxSize(4,0)).GetWidth(), wxDLG_UNIT(this,wxSize(10,0)).GetWidth());
+ m_method_label = new wxStaticText(this, ID_STATICTEXT1, _("Method"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT1"));
+ m_choices_sizer->Add(m_method_label, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 0);
+ m_method_choice = new wxChoice(this, ID_METHOD, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_METHOD"));
+ m_method_choice->SetSelection( m_method_choice->Append(_("Divide ranks evenly")) );
+ m_method_choice->Append(_("Random"));
+ m_choices_sizer->Add(m_method_choice, 0, wxALL|wxEXPAND|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0);
+ StaticText1 = new wxStaticText(this, ID_STATICTEXT2, _("Clans"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT2"));
+ m_choices_sizer->Add(StaticText1, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 0);
+ m_clans_choice = new wxChoice(this, ID_CHOICE1, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_CHOICE1"));
+ m_clans_choice->SetSelection( m_clans_choice->Append(_("None")) );
+ m_clans_choice->Append(_("Fair"));
+ m_clans_choice->Append(_("Always"));
+ m_clans_choice->SetToolTip(TE(_("Put members of same clan ( users having same clantag, like \'[smurfzor]Alice\' and \'[smurfzor]Bob\' ) together into same alliance. \nNone: nothing special for clans.\nFair: put clanmembers into alliance, unless this makes alliances unfair.\nAlways: always put clanmembers into alliance, even if that alliance is unfair.")));
+ m_choices_sizer->Add(m_clans_choice, 0, wxALL|wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 0);
+ StaticText2 = new wxStaticText(this, ID_STATICTEXT3, _("Number of allies"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT3"));
+ m_choices_sizer->Add(StaticText2, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 0);
+ m_group_choice = new wxChoice(this, ID_CHOICE2, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_CHOICE2"));
+ m_group_choice->Append( _("Auto select") );
+ for ( unsigned int i = 1; i < 17; i++ ) m_group_choice->Append( TowxString( i ) );
+ m_choices_sizer->Add(m_group_choice, 0, wxALL|wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 0);
+ m_main_sizer->Add(m_choices_sizer, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ wxSize __SpacerSize_1 = wxDLG_UNIT(this,wxSize(0,0));
+ m_main_sizer->Add(__SpacerSize_1.GetWidth(),__SpacerSize_1.GetHeight(),0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ m_separator1 = new wxStaticLine(this, ID_STATICLINE1, wxDefaultPosition, wxSize(10,-1), wxLI_HORIZONTAL, _T("ID_STATICLINE1"));
+ m_main_sizer->Add(m_separator1, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ m_buttons_sizer = new wxBoxSizer(wxHORIZONTAL);
+ m_cancel_button = new wxButton(this, ID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_CANCEL"));
+ m_buttons_sizer->Add(m_cancel_button, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
+ m_buttons_sizer->Add(0,0,1, wxALL|wxEXPAND|wxSHAPED|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ m_ok_button = new wxButton(this, ID_OK, _("Ok"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_OK"));
+ m_buttons_sizer->Add(m_ok_button, 0, wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
+ m_main_sizer->Add(m_buttons_sizer, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ SetSizer(m_main_sizer);
+ m_main_sizer->Fit(this);
+ m_main_sizer->SetSizeHints(this);
+
+ Connect(ID_CANCEL,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&AutoBalanceDialog::OnCancel);
+ Connect(ID_OK,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&AutoBalanceDialog::OnOk);
+
+ m_method_choice->SetSelection( defaultval.type );
+ m_clans_choice->SetSelection( defaultval.respectclans + ( defaultval.respectclans && defaultval.strongclans ) );
+ m_group_choice->SetSelection( defaultval.groupingsize );
+}
+
+AutoBalanceDialog::~AutoBalanceDialog()
+{
+}
+
+
+void AutoBalanceDialog::OnCancel(wxCommandEvent& /*unused*/)
+{
+ EndModal( wxID_CANCEL );
+}
+
+void AutoBalanceDialog::OnOk(wxCommandEvent& /*unused*/)
+{
+ EndModal( wxID_OK );
+}
+
+AutoBalanceDialog::BalanceOptions AutoBalanceDialog::GetResult()
+{
+ BalanceOptions ret;
+ ret.type = (IBattle::BalanceType)m_method_choice->GetSelection();
+ ret.respectclans = ( m_clans_choice->GetSelection() > 0 );
+ ret.strongclans = ( m_clans_choice->GetSelection() > 1 );
+ ret.groupingsize = m_group_choice->GetSelection();
+ return ret;
+}
+
diff --git a/src/autobalancedialog.h b/src/autobalancedialog.h
new file mode 100644
index 0000000..c59661f
--- /dev/null
+++ b/src/autobalancedialog.h
@@ -0,0 +1,89 @@
+#ifndef AUTOBALANCEDIALOG_H
+#define AUTOBALANCEDIALOG_H
+
+//(*Headers(AutoBalanceDialog)
+#include <wx/dialog.h>
+#include "ibattle.h"
+//*)
+
+class wxButton;
+class wxChoice;
+class wxStaticLine;
+class wxStaticText;
+
+
+/** \brief lets host automatically assign players to teams, optionally taking clan/rank into account
+ * dialog sets balancing options in Settings handler for the calling class to use after modal display ends
+ * \todo use this in a non-modal way? */
+class AutoBalanceDialog: public wxDialog
+{
+ public:
+
+ struct BalanceOptions
+ {
+ IBattle::BalanceType type;
+ bool respectclans;
+ bool strongclans;
+ int groupingsize;
+ };
+
+ AutoBalanceDialog(wxWindow* parent, const BalanceOptions& defaultval );
+ virtual ~AutoBalanceDialog();
+
+ BalanceOptions GetResult();
+
+ //(*Declarations(AutoBalanceDialog)
+ wxButton* m_ok_button;
+ wxChoice* m_method_choice;
+ wxStaticLine* m_separator1;
+ wxStaticText* StaticText1;
+ wxChoice* m_clans_choice;
+ wxStaticText* m_method_label;
+ wxButton* m_cancel_button;
+ wxStaticText* StaticText2;
+ wxChoice* m_group_choice;
+ //*)
+
+ protected:
+
+ //(*Identifiers(AutoBalanceDialog)
+ static const long ID_STATICTEXT1;
+ static const long ID_METHOD;
+ static const long ID_STATICTEXT2;
+ static const long ID_STATICTEXT3;
+ static const long ID_CHOICE1;
+ static const long ID_CHOICE2;
+ static const long ID_STATICLINE1;
+ static const long ID_CANCEL;
+ static const long ID_OK;
+ //*)
+
+ private:
+
+ //(*Handlers(AutoBalanceDialog)
+ void OnCancel(wxCommandEvent& event);
+ void OnOk(wxCommandEvent& event);
+ //*)
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/autohost.cpp b/src/autohost.cpp
new file mode 100644
index 0000000..93eb468
--- /dev/null
+++ b/src/autohost.cpp
@@ -0,0 +1,303 @@
+/* Author: Tobi Vollebregt */
+
+#include "autohost.h"
+#include "battle.h"
+#include "server.h"
+#include "settings.h"
+#include "user.h"
+#include "utils/conversion.h"
+#include "utils/misc.h"
+
+#include <wx/tokenzr.h>
+
+
+AutoHost::AutoHost( Battle& battle )
+ : m_battle( battle ),
+ m_enabled( false ),
+ m_lastActionTime( 0 )
+{
+}
+
+
+void AutoHost::SetEnabled( const bool enabled )
+{
+ m_enabled = enabled;
+}
+
+bool AutoHost::GetEnabled()
+{
+ return m_enabled;
+}
+
+void AutoHost::OnSaidBattle( const wxString& /*unused*/, const wxString& msg )
+{
+ // do nothing if autohost functionality is disabled
+
+ if ( !m_enabled )
+ return;
+
+ // protect against command spam
+
+ time_t currentTime = time( NULL );
+
+ if ( ( currentTime - m_lastActionTime ) < 5 )
+ return;
+
+ // check for autohost commands
+ wxString command = msg.BeforeFirst( _T( ' ' ) );
+ wxString params = msg.AfterFirst( _T( ' ' ) );
+ if ( command == _T( "!start" ) ) {
+ StartBattle();
+ }
+ else if ( command == _T( "!balance" ) ) {
+ unsigned int num = s2l( params );
+ m_battle.Autobalance( IBattle::balance_random, false, false, num );
+ m_battle.DoAction( _T( "is auto-balancing alliances ..." ) );
+ }
+ else if ( command == _T( "!cbalance" ) ) {
+ unsigned int num = s2l( params );
+ m_battle.Autobalance( IBattle::balance_random, true, false, num );
+ m_battle.DoAction( _T( "is auto-balancing alliances ..." ) );
+ }
+ else if ( command == _T( "!help" ) ) {
+ m_battle.DoAction( _T( "The following commands are available ( <> = mandatory value, {} = optional value ):" ) );
+ m_battle.DoAction( _T( "!addbox <allynumber> <topx> <topy> <bottomx> <bottomy>: adds a <allynumber> start restriction to the given coordinates, coordinates range from 0 to 200." ) );
+ m_battle.DoAction( _T( "!balance {number}: tries to put players into allyteams by how many start boxes there are, uses {number} allyteams if present." ) );
+ m_battle.DoAction( _T( "!cbalance {number}: see !balance but tries to put clanmates together first." ) );
+ m_battle.DoAction( _T( "!fixcolors: changes players duplicate colours so they are unique." ) );
+ m_battle.DoAction( _T( "!fixids {number}: tries to put players into control teams by number, if number is omitted it assignes as different controlteam per player." ) );
+ m_battle.DoAction( _T( "!cfixids {number}: see !fixids but tries to put clanmates together first." ) );
+ m_battle.DoAction( _T( "!help: this guide." ) );
+ m_battle.DoAction( _T( "!listprofiles: lists the available battle profiles." ) );
+ m_battle.DoAction( _T( "!loadprofile profilename: loads an available battle profile." ) );
+ m_battle.DoAction( _T( "!lock: prevents more people to join." ) );
+ m_battle.DoAction( _T( "!map <name>: switches to <name>." ) );
+ m_battle.DoAction( _T( "!removebox <allynumber>: deletes <allynumber> start restriction's box." ) );
+ m_battle.DoAction( _T( "!ring {name}: rings players that are not ready or {name} if specified." ) );
+ m_battle.DoAction( _T( "!set <optionname> <value>: sets battle option <optionname> to <value>" ) );
+ m_battle.DoAction( _T( "!spectunsynced: sets all players with unsynced status to be spectators." ) );
+ m_battle.DoAction( _T( "!start: starts the battle." ) );
+ m_battle.DoAction( _T( "!unlock: opens the battle again." ) );
+ }
+ else if ( command == _T( "!ring" ) ) {
+ if ( !params.IsEmpty() )
+ {
+ wxString user = GetBestMatch( m_userlist, params );
+ try
+ {
+ User& u = m_battle.GetUser( user );
+ m_battle.RingPlayer( u );
+ m_battle.DoAction( _T( "is ringing " ) + user );
+ }
+ catch ( ... )
+ {
+ m_battle.DoAction( _T( "cannot ring " ) + user );
+ }
+ }
+ else
+ {
+ m_battle.RingNotReadyPlayers();
+ m_battle.DoAction( _T( "is ringing players not ready ..." ) );
+ }
+ }
+ else if ( command == _T( "!listprofiles" ) ) {
+ wxArrayString profilelist = m_battle.GetPresetList();
+ unsigned int count = profilelist.GetCount();
+ if ( count == 0 ) {
+ m_battle.DoAction( _T( "There are no presets available." ) );
+ }
+ else {
+ m_battle.DoAction( _T( "The following presets are available:" ) );
+ for ( unsigned int i = 0; i < count; i++ ) {
+ m_battle.DoAction( profilelist[i] );
+ }
+ }
+ }
+ else if ( command == _T( "!loadprofile" ) ) {
+ wxString profilename = GetBestMatch( m_battle.GetPresetList(), params );
+ if ( !m_battle.LoadOptionsPreset( profilename ) )
+ m_battle.DoAction( _T( "Profile not found, use !listprofiles for a list of available profiles." ) );
+ else m_battle.DoAction( _T( "has loaded profile: " ) + profilename );
+ }
+ else if ( command == _T( "!fixcolors" ) ) {
+ m_battle.FixColours();
+ m_battle.DoAction( _T( "is fixing colors." ) );
+ }
+ else if ( command == _T( "!lock" ) ) {
+ m_battle.SetIsLocked( true );
+ m_battle.DoAction( _T( "has locked the battle." ) );
+ m_battle.SendHostInfo( IBattle::HI_Locked );
+ }
+ else if ( command == _T( "!unlock" ) ) {
+ m_battle.SetIsLocked( false );
+ m_battle.DoAction( _T( "has unlocked the battle." ) );
+ m_battle.SendHostInfo( IBattle::HI_Locked );
+ }
+ else if ( command == _T( "!fixids" ) ) {
+ unsigned int num = s2l( params );
+ m_battle.FixTeamIDs( IBattle::balance_divide, false, false, num );
+ m_battle.DoAction( _T( "is auto-balancing control teams ..." ) );
+ }
+ else if ( command == _T( "!cfixids" ) ) {
+ unsigned int num = s2l( params );
+ m_battle.FixTeamIDs( IBattle::balance_divide, true, true, num );
+ m_battle.DoAction( _T( "is auto-balancing control teams ..." ) );
+ }
+ else if ( command == _T( "!spectunsynced" ) ) {
+ m_battle.ForceUnsyncedToSpectate();
+ m_battle.DoAction( _T( "is forcing unsynced players to be spectators." ) );
+ }
+ else if ( command == _T( "!map" ) ) {
+ if ( params.IsEmpty() ) m_battle.DoAction( _T( "cannot switch to void mapname" ) );
+ else
+ {
+ wxString mapname = GetBestMatch( usync().GetMapList(), params );
+ try
+ {
+ UnitSyncMap map = usync().GetMap( mapname );
+ m_battle.SetLocalMap( map );
+ m_battle.DoAction( _T( "is switching to map " ) + mapname );
+ m_battle.SendHostInfo( IBattle::HI_Map );
+ } catch ( ... )
+ {
+ m_battle.DoAction( _T( "cannot switch to map " ) + mapname );
+ }
+ }
+ }
+ else if ( command == _T( "!set" ) ) {
+ wxString key = params.BeforeFirst( _T( ' ' ) );
+ wxString value = params.AfterFirst( _T( ' ' ) );
+ bool exists = m_battle.CustomBattleOptions().keyExists( key );
+ if ( exists )
+ {
+ bool result = m_battle.CustomBattleOptions().setSingleOption( key, value );
+ if ( result )
+ {
+ OptionsWrapper::GameOption section = m_battle.CustomBattleOptions().GetSection( key );
+ m_battle.SendHostInfo( wxString::Format( _T( "%d_%s" ), section, key.c_str() ) );
+ m_battle.DoAction( _T( "has set option " ) + key + _T( " to value " ) + value );
+ }
+ else m_battle.DoAction( _T( "cannot set option " ) + key + _T( " to value " ) + value + _T( ", reason: invalid value." ) );
+ }
+ else
+ {
+ m_battle.DoAction( _T( "cannot find option entry " ) + key );
+ }
+ }
+ else if ( command == _T( "!addbox" ) ) {
+ long allynumber;
+ long topleftx;
+ long toplefty;
+ long bottomrightx;
+ long bottomrighty;
+ wxArrayString values = wxStringTokenize( params, _T( " " ) );
+ if ( values.GetCount() != 5 ) m_battle.DoAction( _T( "has recieved an invalid number of params for !addbox" ) );
+ else
+ {
+ bool valueok = values[0].ToLong( &allynumber );
+ valueok = valueok && values[1].ToLong( &topleftx );
+ valueok = valueok && values[2].ToLong( &toplefty );
+ valueok = valueok && values[3].ToLong( &bottomrightx );
+ valueok = valueok && values[4].ToLong( &bottomrighty );
+ valueok = valueok && ( allynumber > 0 );
+ valueok = valueok && ( topleftx >= 0 ) && ( topleftx <= 200 );
+ valueok = valueok && ( toplefty >= 0 ) && ( toplefty <= 200 );
+ valueok = valueok && ( bottomrightx >= 0 ) && ( bottomrightx <= 200 );
+ valueok = valueok && ( bottomrighty >= 0 ) && ( bottomrighty <= 200 );
+ if ( valueok )
+ {
+ allynumber = allynumber - 1;
+ BattleStartRect rect = m_battle.GetStartRect( allynumber );
+ if ( rect.IsOk() )
+ {
+ m_battle.DoAction( _T( "cannot add a startbox for allyteam " ) + TowxString( allynumber ) + _T( " because one is already present." ) );
+ }
+ else
+ {
+ m_battle.AddStartRect( allynumber, topleftx, toplefty, bottomrightx, bottomrighty );
+ m_battle.SendHostInfo( IBattle::HI_StartRects );
+ m_battle.DoAction( _T( "has added start box for allyteam " ) + TowxString( allynumber ) );
+ }
+ }
+ else
+ {
+ m_battle.DoAction( _T( "has recieved an invalid param for !addbox" ) );
+ }
+ }
+ }
+ else if ( command == _T( "!removebox" ) ) {
+ long boxnumber;
+ bool numberok = params.ToLong( &boxnumber );
+ if ( numberok )
+ {
+ boxnumber = boxnumber - 1;
+ BattleStartRect rect = m_battle.GetStartRect( boxnumber );
+ if ( rect.IsOk() )
+ {
+ m_battle.RemoveStartRect( boxnumber );
+ m_battle.SendHostInfo( IBattle::HI_StartRects );
+ m_battle.DoAction( _T( "has removed the start box for allyteam " ) + TowxString( boxnumber ) );
+ }
+ else
+ {
+ m_battle.DoAction( _T( "cannot find start box " ) + params );
+ }
+ }
+ else
+ {
+ m_battle.DoAction( _T( "has recieved an invalid param to !removebox command" ) );
+ }
+ }
+ else return;
+ m_lastActionTime = currentTime;
+}
+
+
+/// Should only be called if user isn't immediately kicked (ban / rank limit)
+void AutoHost::OnUserAdded( User& user )
+{
+ m_userlist.Add( user.GetNick() );
+ // do nothing if autohost functionality is disabled
+ if ( !m_enabled )
+ return;
+ m_battle.DoAction( _T( "Hi " ) + user.GetNick() + _T( ", this battle is in SpringLobby autohost mode. For help say !help" ) );
+}
+
+
+void AutoHost::OnUserRemoved( User& user )
+{
+ m_userlist.Remove( user.GetNick() );
+ // do nothing if autohost functionality is disabled
+ if ( !m_enabled )
+ return;
+
+ if ( m_battle.GetNumUsers() == 1 && m_battle.IsLocked() )
+ {
+ m_battle.SetIsLocked( false );
+ m_battle.DoAction( _T( "has auto-unlocked the battle." ) );
+ m_battle.SendHostInfo( IBattle::HI_Locked );
+ }
+}
+
+
+void AutoHost::StartBattle()
+{
+ // todo: the logic here is copied from BattleRoomTab::OnStart, may wish to refactor this sometime.
+ // note: the strings here must remain untranslated because they're visible to everyone in the battle!
+
+ m_battle.GetMe().BattleStatus().ready = true;
+
+ if ( !m_battle.IsEveryoneReady() ) {
+ m_battle.DoAction( _T( "Some players are not ready yet." ) );
+ return;
+ }
+
+ m_battle.DoAction( _T( "is starting game ..." ) );
+ m_battle.GetServer().StartHostedBattle();
+
+ m_battle.SaveMapDefaults(); // save map preset
+
+ // todo: copied from Ui::StartHostedBattle
+ sett().SetLastHostMap( m_battle.GetHostMapName() );
+ sett().SaveSettings();
+}
diff --git a/src/autohost.h b/src/autohost.h
new file mode 100644
index 0000000..50a4818
--- /dev/null
+++ b/src/autohost.h
@@ -0,0 +1,56 @@
+/* Author: Tobi Vollebregt */
+
+#ifndef SPRINGLOBBY_HEADERGUARD_AUTOHOST_H
+#define SPRINGLOBBY_HEADERGUARD_AUTOHOST_H
+
+//including this header is only really needed for time_t ..
+#include <wx/string.h>
+#include <wx/arrstr.h>
+
+class Battle;
+class User;
+class wxString;
+
+//! @brief Autohost logic
+class AutoHost
+{
+ public:
+
+ AutoHost( Battle& battle );
+
+ void SetEnabled( const bool enabled );
+ bool GetEnabled();
+
+ void OnSaidBattle( const wxString& nick, const wxString& msg );
+ void OnUserAdded( User& user );
+ void OnUserRemoved( User& user );
+ private:
+
+ void StartBattle();
+
+ Battle& m_battle;
+
+ bool m_enabled;
+ time_t m_lastActionTime;
+ wxArrayString m_userlist;
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_AUTOHOST_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/autopointers.h b/src/autopointers.h
new file mode 100644
index 0000000..62ba07d
--- /dev/null
+++ b/src/autopointers.h
@@ -0,0 +1,272 @@
+#ifndef autopointers_h_
+#define autopointers_h_
+//
+// (C) 2005..2006 Dmytry Lavrov.
+// Several automatic pointer types used in Volumetrics.
+//
+#include <cstdlib>
+
+class Lockable {
+public:
+ int lock_count;
+ Lockable():lock_count(0) {}
+ ;
+ virtual ~Lockable() {}
+ ;
+ bool Locked() {
+ return lock_count>0;
+ }
+ void Lock() {
+ ++lock_count;
+ //debug_message("Lock()");
+ }
+ void UnLock() {
+ --lock_count;
+ //debug_message("UnLock()");
+ }
+};
+
+template<Lockable *T>
+class StaticLocker {
+public:
+ inline StaticLocker() {
+ T->Lock();
+ }
+ inline ~StaticLocker() {
+ T->UnLock();
+ };
+};
+
+class Locker {
+ Lockable &lock;
+ public:
+ inline Locker(Lockable &lock_): lock(lock_) {
+ lock.Lock();
+ }
+ inline ~Locker() {
+ lock.UnLock();
+ };
+};
+
+class RefcountedContainer {
+public:
+ Lockable ref_lock;
+
+ RefcountedContainer() {
+ //ref_lock.Lock();
+ };
+ /*
+ RefcountedContainer* operator new( size_t zSiz){
+ RefcountedContainer* tmp=new RefcountedContainer();
+ };
+ */
+
+ virtual ~RefcountedContainer() {}
+ ;
+ RefcountedContainer* NewCopy() {
+ return new RefcountedContainer(*this);
+ }
+ inline void Reference() {
+ ref_lock.Lock();
+ }
+ inline void Dereference() {
+ ref_lock.UnLock();
+ }
+ inline bool Referenced() {
+ return ref_lock.Locked();
+ }
+};
+
+
+template <class T , bool TDestroy=true>
+class RefcountedPointer {
+public:
+ T *data;
+ RefcountedPointer():data(0) {}
+ RefcountedPointer (T *p):data(p) {
+ if(data)data->Reference();
+ }
+ RefcountedPointer(const RefcountedPointer<T,TDestroy> &p):data(p.data) {
+ if(data) {
+ data->Reference();
+ }
+ else {
+ // error("RefcountedPointer copy : null");
+ }
+ };
+
+ /* */
+template<class U>
+explicit RefcountedPointer(RefcountedPointer<U> p){
+
+ /// std::cout<<"doing dynamic cast"<<std::endl;
+ data=dynamic_cast<T*>(p.data);
+ /// std::cout<<"... done"<<std::endl;*/
+ if(data) {
+ data->Reference();
+ }
+ else {
+ ///error("RefcountedPointer copy : null (cast)");
+ }
+ };
+ /* */
+ ~RefcountedPointer() {
+ Dispose();
+ };
+ RefcountedPointer<T, TDestroy> &operator= (const RefcountedPointer &p) throw() {
+ if (this != &p) {
+ Dispose();
+ data = p.data;
+ if(data) {
+ data->Reference();
+ }
+ else {
+ ///error("RefcountedPointer operator= : bad parameter");
+ }
+ }
+ return *this;
+ }
+ void Dispose() {
+ if(!data) {
+ ///error("Something wrong with RefcountedPointer.dispose");
+ return;
+ }
+ data->Dereference();
+ if(TDestroy) {
+ if(!data->Referenced()) {
+ delete data;
+ }
+ }
+ data=NULL;
+ }
+ T &Data() const {
+ return *data;
+ }
+ T *Ptr() const {
+ return data;
+ }
+ RefcountedPointer<T, TDestroy> Copy() {
+ if(data) {
+ RefcountedPointer<T, TDestroy> result(data->NewCopy());
+ return result;
+ }
+ else {
+ RefcountedPointer<T, TDestroy> result;
+ return result;
+ }
+ }
+
+ T &operator *() const {
+ return *data;
+ }
+ T *operator ->() const {
+ return data;
+ }
+ bool operator <(RefcountedPointer<T, TDestroy> p) const{
+ return data<p.data;
+ }
+ bool operator >(RefcountedPointer<T, TDestroy> p) const{
+ return data>p.data;
+ }
+ bool operator ==(RefcountedPointer<T, TDestroy> p) const{
+ return data==p.data;
+ }
+ bool operator !=(RefcountedPointer<T, TDestroy> p) const{
+ return !(data==p.data);
+ }
+ bool operator <(T *p) const {
+ return data<p;
+ }
+ bool operator >(T *p) const {
+ return data>p;
+ }
+ bool operator ==(T *p) const {
+ return data==p;
+ }
+ bool operator !=(T *p) const {
+ return !(data==p);
+ }
+ /*
+ operator bool() const {
+ return data;
+ }*/
+ bool Ok() const{
+ return data;
+ }
+ bool ok() const{
+ return data;
+ }
+};
+
+template<class T> class SingleInstance{
+ T *data;
+ public:
+ SingleInstance():data(NULL){}
+ ~SingleInstance(){delete data;}
+ T *Get(){
+ if(!data)data=new T;
+ return data;
+ }
+};
+
+template <class SRC,class DEST>
+class BidirectionalConnector{
+ SRC *self_end ;
+ DEST *other_end ;
+ BidirectionalConnector<DEST,SRC> *other;
+ public:
+ BidirectionalConnector(SRC *self_end_):
+ self_end(self_end_),
+ other_end(NULL),
+ other(NULL)
+ {
+ }
+ ~BidirectionalConnector(){
+ Disconnect();
+ }
+ void Disconnect(){
+ if(other){
+ other->other_end=NULL;
+ other->other=NULL;
+ other=NULL;
+ other_end=NULL;
+ }
+ }
+ void Connect(BidirectionalConnector<DEST,SRC> *other_){
+ if(other_==other)return;
+ Disconnect();
+ if(other_){
+ other_->Disconnect();
+ other=other_;
+ other->other=this;
+ this->other_end=other->self_end;
+ other->other_end=this->self_end;
+ }
+ }
+ SRC *GetSelfEnd(){
+ return self_end;
+ }
+ DEST *GetOtherEnd(){
+ return other_end;
+ }
+};
+
+#endif
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/base64.cpp b/src/base64.cpp
new file mode 100644
index 0000000..f08a845
--- /dev/null
+++ b/src/base64.cpp
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
+ * http://www.gnu.org/licenses/lgpl-3.0.html
+ *
+ * $Revision: 4909 $
+ * $Id: base64.cpp 4909 2008-02-27 13:15:26Z mortenmacfly $
+ * $HeadURL: svn://svn.berlios.de/codeblocks/tags/8.02/src/sdk/base64.cpp $
+ */
+
+//*********************************************************************
+//* Base64 - a simple base64 encoder and decoder.
+//*
+//* Copyright (c) 1999, Bob Withers - bwit at pobox.com
+//*
+//* This code may be freely used for any purpose, either personal
+//* or commercial, provided the authors copyright notice remains
+//* intact.
+//*********************************************************************
+//
+// converted to wxWindows by Frank Bu?
+//
+
+#include "base64.h"
+
+const wxChar fillchar = '=';
+
+ // 00000000001111111111222222
+ // 01234567890123456789012345
+static wxString cvt = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+ // 22223333333333444444444455
+ // 67890123456789012345678901
+ "abcdefghijklmnopqrstuvwxyz"
+
+ // 555555556666
+ // 234567890123
+ "0123456789+/");
+
+wxString wxBase64::Encode(const wxString& data)
+{
+ return wxBase64::Encode((const wxUint8*)data.c_str(), data.Length());
+}
+
+wxString wxBase64::Encode(const wxUint8* pData, size_t len)
+{
+ size_t c;
+ wxString ret;
+ ret.Alloc(len * 4 / 3 + len * 2);
+
+ for (size_t i = 0; i < len; ++i)
+ {
+ c = (pData[i] >> 2) & 0x3f;
+ ret.Append(cvt[c], 1);
+ c = (pData[i] << 4) & 0x3f;
+ if (++i < len)
+ c |= (pData[i] >> 4) & 0x0f;
+
+ ret.Append(cvt[c], 1);
+ if (i < len)
+ {
+ c = (pData[i] << 2) & 0x3f;
+ if (++i < len)
+ c |= (pData[i] >> 6) & 0x03;
+
+ ret.Append(cvt[c], 1);
+ }
+ else
+ {
+ ++i;
+ ret.Append(fillchar, 1);
+ }
+
+ if (i < len)
+ {
+ c = pData[i] & 0x3f;
+ ret.Append(cvt[c], 1);
+ }
+ else
+ {
+ ret.Append(fillchar, 1);
+ }
+ }
+
+ return ret;
+}
+
+std::string wxBase64::Decode(const wxString& data)
+{
+ int c;
+ int c1;
+ size_t len = data.Length();
+ std::string ret;
+ ret.reserve(data.length() * 3 / 4);
+
+ for (size_t i = 0; i < len; ++i)
+ {
+ // TODO: check all Find results for -1 as result of wrong input data for release build
+ c = cvt.find(data[i]);
+ wxASSERT_MSG(c >= 0, _T("invalid base64 input"));
+ ++i;
+ c1 = cvt.find(data[i]);
+ wxASSERT_MSG(c1 >= 0, _T("invalid base64 input"));
+ c = (c << 2) | ((c1 >> 4) & 0x3);
+ ret.push_back(c);
+ if (++i < len)
+ {
+ c = data[i];
+ if ((char)fillchar == c)
+ break;
+
+ c = cvt.find(c);
+ wxASSERT_MSG(c >= 0, _T("invalid base64 input"));
+ c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
+ ret.push_back(c1);
+ }
+
+ if (++i < len)
+ {
+ c1 = data[i];
+ if ((char)fillchar == c1)
+ break;
+
+ c1 = cvt.find(c1);
+ wxASSERT_MSG(c1 >= 0, _T("invalid base64 input"));
+ c = ((c << 6) & 0xc0) | c1;
+ ret.push_back(c);
+ }
+ }
+
+ return ret;
+}
diff --git a/src/base64.h b/src/base64.h
new file mode 100644
index 0000000..0c18f22
--- /dev/null
+++ b/src/base64.h
@@ -0,0 +1,20 @@
+/*
+ * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
+ * http://www.gnu.org/licenses/lgpl-3.0.html
+ */
+
+#ifndef CB_BASE64_H
+#define CB_BASE64_H
+
+#include <wx/defs.h>
+#include <wx/string.h>
+#include <string>
+
+namespace wxBase64
+{
+ wxString Encode(const wxUint8* pData, size_t len);
+ wxString Encode(const wxString& data);
+ std::string Decode(const wxString& data);
+};
+
+#endif // CB_BASE64_H
diff --git a/src/battle.cpp b/src/battle.cpp
new file mode 100644
index 0000000..b01c800
--- /dev/null
+++ b/src/battle.cpp
@@ -0,0 +1,1100 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: Battle
+//
+#include "battle.h"
+#include "ui.h"
+#include "iunitsync.h"
+#include "server.h"
+#include "user.h"
+#include "utils/misc.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "utils/math.h"
+#include "uiutils.h"
+#include "settings.h"
+#include "useractions.h"
+#include "settings++/custom_dialogs.h"
+#include "springunitsynclib.h"
+#include "iconimagelist.h"
+#include "spring.h"
+
+#include <wx/timer.h>
+#include <wx/image.h>
+#include <wx/string.h>
+#include <wx/log.h>
+#include <wx/filename.h>
+
+const unsigned int TIMER_INTERVAL = 1000;
+const unsigned int TIMER_ID = 101;
+
+BEGIN_EVENT_TABLE(Battle, wxEvtHandler)
+ EVT_TIMER(TIMER_ID, Battle::OnTimer)
+END_EVENT_TABLE()
+
+Battle::Battle( Server& serv, int id ) :
+ m_serv(serv),
+ m_ah(*this),
+ m_autolock_on_start(false),
+ m_id( id )
+
+{
+ m_opts.battleid = m_id;
+}
+
+
+Battle::~Battle()
+{
+ if ( m_is_self_in )
+ susynclib().UnSetCurrentMod();
+}
+
+
+void Battle::SendHostInfo( HostInfo update )
+{
+ m_serv.SendHostInfo( update );
+}
+
+
+void Battle::SendHostInfo( const wxString& Tag )
+{
+ m_serv.SendHostInfo( Tag );
+}
+
+
+void Battle::Update()
+{
+ ui().OnBattleInfoUpdated( *this );
+}
+
+
+void Battle::Update( const wxString& Tag )
+{
+ ui().OnBattleInfoUpdated( *this, Tag );
+}
+
+
+void Battle::Join( const wxString& password )
+{
+ m_serv.JoinBattle( m_opts.battleid, password );
+ m_is_self_in = true;
+}
+
+
+void Battle::Leave()
+{
+ m_serv.LeaveBattle( m_opts.battleid );
+ m_is_self_in = false;
+ susynclib().UnSetCurrentMod( );
+}
+
+
+void Battle::OnRequestBattleStatus()
+{
+ int lowest = GetFreeTeamNum( true );
+
+ UserBattleStatus& bs = m_serv.GetMe().BattleStatus();
+ bs.team = lowest;
+ bs.ally = lowest;
+ bs.spectator = false;
+ bs.colour = sett().GetBattleLastColour();
+ // theres some highly annoying bug with color changes on player join/leave.
+ if ( !bs.colour.IsColourOk() ) bs.colour = GetFreeColour( GetMe() );
+
+ SendMyBattleStatus();
+}
+
+
+void Battle::SendMyBattleStatus()
+{
+ UserBattleStatus& bs = m_serv.GetMe().BattleStatus();
+ if ( IsSynced() ) bs.sync = SYNC_SYNCED;
+ else bs.sync = SYNC_UNSYNCED;
+ m_serv.SendMyBattleStatus( bs );
+}
+
+
+void Battle::SetImReady( bool ready )
+{
+ UserBattleStatus& bs = m_serv.GetMe().BattleStatus();
+
+ bs.ready = ready;
+
+ //m_serv.GetMe().SetBattleStatus( bs );
+ SendMyBattleStatus();
+}
+
+
+
+
+
+/*bool Battle::HasMod()
+{
+ return usync().ModExists( m_opts.modname );
+}*/
+
+
+void Battle::Say( const wxString& msg )
+{
+ m_serv.SayBattle( m_opts.battleid, msg );
+}
+
+
+void Battle::DoAction( const wxString& msg )
+{
+ m_serv.DoActionBattle( m_opts.battleid, msg );
+}
+
+void Battle::SetLocalMap( const UnitSyncMap& map )
+{
+ IBattle::SetLocalMap( map );
+ if ( IsFounderMe() ) LoadMapDefaults( map.name );
+}
+
+User& Battle::GetMe()
+{
+ return m_serv.GetMe();
+}
+
+void Battle::SaveMapDefaults()
+{
+ // save map preset
+ wxString mapname = LoadMap().name;
+ wxString startpostype = CustomBattleOptions().getSingleValue( _T("startpostype"), OptionsWrapper::EngineOption );
+ sett().SetMapLastStartPosType( mapname, startpostype);
+ std::vector<Settings::SettStartBox> rects;
+ for( unsigned int i = 0; i <= GetLastRectIdx(); ++i )
+ {
+ BattleStartRect rect = GetStartRect( i );
+ if ( rect.IsOk() )
+ {
+ Settings::SettStartBox box;
+ box.ally = rect.ally;
+ box.topx = rect.left;
+ box.topy = rect.top;
+ box.bottomx = rect.right;
+ box.bottomy = rect.bottom;
+ rects.push_back( box );
+ }
+ }
+ sett().SetMapLastRectPreset( mapname, rects );
+}
+
+void Battle::LoadMapDefaults( const wxString& mapname )
+{
+ CustomBattleOptions().setSingleOption( _T("startpostype"), sett().GetMapLastStartPosType( mapname ), OptionsWrapper::EngineOption );
+ SendHostInfo( wxString::Format( _T("%d_startpostype"), OptionsWrapper::EngineOption ) );
+
+ for( unsigned int i = 0; i <= GetLastRectIdx(); ++i ) if ( GetStartRect( i ).IsOk() ) RemoveStartRect(i); // remove all rects
+ SendHostInfo( IBattle::HI_StartRects );
+
+ std::vector<Settings::SettStartBox> savedrects = sett().GetMapLastRectPreset( mapname );
+ for ( std::vector<Settings::SettStartBox>::iterator itor = savedrects.begin(); itor != savedrects.end(); itor++ )
+ {
+ AddStartRect( itor->ally, itor->topx, itor->topy, itor->bottomx, itor->bottomy );
+ }
+ SendHostInfo( IBattle::HI_StartRects );
+}
+
+User& Battle::OnUserAdded( User& user )
+{
+ user = IBattle::OnUserAdded( user );
+ if ( &user == &GetMe() )
+ {
+ m_timer = new wxTimer(this,TIMER_ID);
+ m_timer->Start( TIMER_INTERVAL );
+ }
+ user.SetBattle( this );
+ user.BattleStatus().isfromdemo = false;
+
+ if ( IsFounderMe() )
+ {
+ if ( CheckBan( user ) ) return user;
+
+ if ( ( &user != &GetMe() ) && !user.BattleStatus().IsBot() && ( m_opts.rankneeded > UserStatus::RANK_1 ) && ( user.GetStatus().rank < m_opts.rankneeded ))
+ {
+ switch ( m_opts.ranklimittype )
+ {
+ case rank_limit_none:
+ break;
+ case rank_limit_autospec:
+ if ( !user.BattleStatus().spectator )
+ {
+ DoAction( _T("Rank limit autospec: ") + user.GetNick() );
+ ForceSpectator( user, true );
+ }
+ break;
+ case rank_limit_autokick:
+ DoAction( _T("Rank limit autokick: ") + user.GetNick() );
+ KickPlayer( user );
+ return user;
+ default:
+ wxLogError( _T("unknown ranklimittype in Battle::OnUserAdded") );
+ break;
+ }
+ }
+
+ m_ah.OnUserAdded( user );
+ if ( !user.BattleStatus().IsBot() && sett().GetBattleLastAutoAnnounceDescription() ) DoAction( m_opts.description );
+ }
+ // any code here may be skipped if the user was autokicked
+ return user;
+}
+
+void Battle::OnUserBattleStatusUpdated( User &user, UserBattleStatus status )
+{
+ if ( IsFounderMe() )
+ {
+ if ( ( &user != &GetMe() ) && !status.IsBot() && ( m_opts.rankneeded > UserStatus::RANK_1 ) && ( user.GetStatus().rank < m_opts.rankneeded ))
+ {
+ switch ( m_opts.ranklimittype )
+ {
+ case rank_limit_none:
+ break;
+ case rank_limit_autospec:
+ if ( !status.spectator )
+ {
+ DoAction( _T("Rank limit autospec: ") + user.GetNick() );
+ ForceSpectator( user, true );
+ }
+ break;
+ case rank_limit_autokick:
+ DoAction( _T("Rank limit autokick: ") + user.GetNick() );
+ KickPlayer( user );
+ break;
+ }
+ }
+
+ }
+ IBattle::OnUserBattleStatusUpdated( user, status );
+ if ( status.handicap != 0 )
+ {
+ ui().OnBattleAction( *this, wxString(_T(" ")) , ( _T("Warning: user ") + user.GetNick() + _T(" got bonus ") ) << status.handicap );
+ }
+ if ( IsFounderMe() )
+ {
+ if ( ShouldAutoStart() )
+ {
+ if ( sett().GetBattleLastAutoStartState() )
+ {
+ if ( !ui().IsSpringRunning() ) ui().StartHostedBattle();
+ }
+ }
+ }
+ ui().OnUserBattleStatus( *this, user );
+}
+
+
+void Battle::OnUserRemoved( User& user )
+{
+ m_ah.OnUserRemoved(user);
+ IBattle::OnUserRemoved( user );
+}
+
+
+void Battle::RingNotReadyPlayers()
+{
+ for (user_map_t::size_type i = 0; i < GetNumUsers(); i++)
+ {
+ User& u = GetUser(i);
+ UserBattleStatus& bs = u.BattleStatus();
+ if ( bs.IsBot() ) continue;
+ if ( !bs.ready && !bs.spectator ) m_serv.Ring( u.GetNick() );
+ }
+}
+
+void Battle::RingNotSyncedPlayers()
+{
+ for (user_map_t::size_type i = 0; i < GetNumUsers(); i++)
+ {
+ User& u = GetUser(i);
+ UserBattleStatus& bs = u.BattleStatus();
+ if ( bs.IsBot() ) continue;
+ if ( !bs.sync && !bs.spectator ) m_serv.Ring( u.GetNick() );
+ }
+}
+
+void Battle::RingNotSyncedAndNotReadyPlayers()
+{
+ for (user_map_t::size_type i = 0; i < GetNumUsers(); i++)
+ {
+ User& u = GetUser(i);
+ UserBattleStatus& bs = u.BattleStatus();
+ if ( bs.IsBot() ) continue;
+ if ( ( !bs.sync || !bs.ready ) && !bs.spectator ) m_serv.Ring( u.GetNick() );
+ }
+}
+
+void Battle::RingPlayer( const User& u )
+{
+ if ( u.BattleStatus().IsBot() ) return;
+ m_serv.Ring( u.GetNick() );
+}
+
+bool Battle::ExecuteSayCommand( const wxString& cmd )
+{
+ wxString cmd_name=cmd.BeforeFirst(' ').Lower();
+ if ( cmd_name == _T("/me") )
+ {
+ m_serv.DoActionBattle( m_opts.battleid, cmd.AfterFirst(' ') );
+ return true;
+ }
+ if ( cmd_name == _T("/replacehostip") )
+ {
+ wxString ip = cmd.AfterFirst(' ');
+ if ( ip.IsEmpty() ) return false;
+ m_opts.ip = ip;
+ return true;
+ }
+ //< quick hotfix for bans
+ if (IsFounderMe())
+ {
+ if ( cmd_name == _T("/ban") )
+ {
+ wxString nick=cmd.AfterFirst(' ');
+ m_banned_users.insert(nick);
+ try
+ {
+ User& user = GetUser( nick );
+ m_serv.BattleKickPlayer( m_opts.battleid, user );
+ }
+ catch( assert_exception ) {}
+ ui().OnBattleAction(*this,wxString(_T(" ")),nick+_T(" banned"));
+ //m_serv.DoActionBattle( m_opts.battleid, cmd.AfterFirst(' ') );
+ return true;
+ }
+ if ( cmd_name == _T("/unban") )
+ {
+ wxString nick=cmd.AfterFirst(' ');
+ m_banned_users.erase(nick);
+ ui().OnBattleAction(*this,wxString(_T(" ")),nick+_T(" unbanned"));
+ //m_serv.DoActionBattle( m_opts.battleid, cmd.AfterFirst(' ') );
+ return true;
+ }
+ if ( cmd_name == _T("/banlist") )
+ {
+ ui().OnBattleAction(*this,wxString(_T(" ")),_T("banlist:"));
+ for (std::set<wxString>::iterator i=m_banned_users.begin();i!=m_banned_users.end();++i)
+ {
+ ui().OnBattleAction(*this,wxString(_T(" ")), *i);
+ }
+ for (std::set<wxString>::iterator i=m_banned_ips.begin();i!=m_banned_ips.end();++i)
+ {
+ ui().OnBattleAction(*this,wxString(_T(" ")), *i);
+ }
+ return true;
+ }
+ if ( cmd_name == _T("/unban") )
+ {
+ wxString nick=cmd.AfterFirst(' ');
+ m_banned_users.erase(nick);
+ m_banned_ips.erase(nick);
+ ui().OnBattleAction(*this,wxString(_T(" ")),nick+_T(" unbanned"));
+ //m_serv.DoActionBattle( m_opts.battleid, cmd.AfterFirst(' ') );
+ return true;
+ }
+ if ( cmd_name == _T("/ipban") )
+ {
+ wxString nick=cmd.AfterFirst(' ');
+ m_banned_users.insert(nick);
+ ui().OnBattleAction(*this,wxString(_T(" ")),nick+_T(" banned"));
+ if (UserExists(nick))
+ {
+ User &user=GetUser(nick);
+ if (!user.BattleStatus().ip.empty())
+ {
+ m_banned_ips.insert(user.BattleStatus().ip);
+ ui().OnBattleAction(*this,wxString(_T(" ")),user.BattleStatus().ip+_T(" banned"));
+ }
+ m_serv.BattleKickPlayer( m_opts.battleid, user );
+ }
+ //m_banned_ips.erase(nick);
+
+ //m_serv.DoActionBattle( m_opts.battleid, cmd.AfterFirst(' ') );
+ return true;
+ }
+ }
+ //>
+ return false;
+}
+///< quick hotfix for bans
+/// returns true if user is banned (and hence has been kicked)
+bool Battle::CheckBan(User &user)
+{
+ if (IsFounderMe())
+ {
+ if (m_banned_users.count(user.GetNick())>0
+ || useractions().DoActionOnUser(UserActions::ActAutokick, user.GetNick() ) )
+ {
+ KickPlayer(user);
+ ui().OnBattleAction(*this,wxString(_T(" ")),user.GetNick()+_T(" is banned, kicking"));
+ return true;
+ }
+ else if (m_banned_ips.count(user.BattleStatus().ip)>0)
+ {
+ ui().OnBattleAction(*this,wxString(_T(" ")),user.BattleStatus().ip+_T(" is banned, kicking"));
+ KickPlayer(user);
+ return true;
+ }
+ }
+ return false;
+}
+///>
+
+void Battle::SetAutoLockOnStart( bool value )
+{
+ m_autolock_on_start = value;
+}
+
+bool Battle::GetAutoLockOnStart()
+{
+ return m_autolock_on_start;
+}
+
+void Battle::SetLockExternalBalanceChanges( bool value )
+{
+ if ( value ) DoAction( _T("has locked player balance changes") );
+ else DoAction( _T("has unlocked player balance changes") );
+ m_opts.lockexternalbalancechanges = value;
+}
+
+bool Battle::GetLockExternalBalanceChanges()
+{
+ return m_opts.lockexternalbalancechanges;
+}
+
+
+void Battle::AddBot( const wxString& nick, UserBattleStatus status )
+{
+ m_serv.AddBot( m_opts.battleid, nick, status );
+}
+
+
+
+void Battle::ForceSide( User& user, int side )
+{
+ m_serv.ForceSide( m_opts.battleid, user, side );
+}
+
+
+void Battle::ForceTeam( User& user, int team )
+{
+ IBattle::ForceTeam( user, team );
+ m_serv.ForceTeam( m_opts.battleid, user, team );
+}
+
+
+void Battle::ForceAlly( User& user, int ally )
+{
+ IBattle::ForceAlly( user, ally );
+ m_serv.ForceAlly( m_opts.battleid, user, ally );
+
+}
+
+
+void Battle::ForceColour( User& user, const wxColour& col )
+{
+ IBattle::ForceColour( user, col );
+ m_serv.ForceColour( m_opts.battleid, user, col );
+}
+
+
+void Battle::ForceSpectator( User& user, bool spectator )
+{
+ m_serv.ForceSpectator( m_opts.battleid, user, spectator );
+}
+
+
+void Battle::KickPlayer( User& user )
+{
+ m_serv.BattleKickPlayer( m_opts.battleid, user );
+}
+
+void Battle::SetHandicap( User& user, int handicap)
+{
+ m_serv.SetHandicap ( m_opts.battleid, user, handicap );
+}
+
+
+
+void Battle::ForceUnsyncedToSpectate()
+{
+ size_t numusers = GetNumUsers();
+ for ( size_t i = 0; i < numusers; ++i )
+ {
+ User &user = GetUser(i);
+ UserBattleStatus& bs = user.BattleStatus();
+ if ( bs.IsBot() ) continue;
+ if ( !bs.spectator && !bs.sync ) ForceSpectator( user, true );
+ }
+}
+
+void Battle::ForceUnReadyToSpectate()
+{
+ size_t numusers = GetNumUsers();
+ for ( size_t i = 0; i < numusers; ++i )
+ {
+ User &user = GetUser(i);
+ UserBattleStatus& bs = user.BattleStatus();
+ if ( bs.IsBot() ) continue;
+ if ( !bs.spectator && !bs.ready ) ForceSpectator( user, true );
+ }
+}
+
+void Battle::ForceUnsyncedAndUnreadyToSpectate()
+{
+ size_t numusers = GetNumUsers();
+ for ( size_t i = 0; i < numusers; ++i )
+ {
+ User &user = GetUser(i);
+ UserBattleStatus& bs = user.BattleStatus();
+ if ( bs.IsBot() ) continue;
+ if ( !bs.spectator && ( !bs.sync || !bs.ready ) ) ForceSpectator( user, true );
+ }
+}
+
+
+void Battle::UserPositionChanged( const User& user )
+{
+ m_serv.SendUserPosition( user );
+}
+
+
+void Battle::SendScriptToClients()
+{
+ m_serv.SendScriptToClients( GetScript() );
+}
+
+
+void Battle::StartSpring()
+{
+ if ( UserExists( GetMe().GetNick() ) )
+ {
+ if ( IsFounderMe() )
+ {
+ if ( sett().GetBattleLastAutoControlState() )
+ {
+ FixTeamIDs( (IBattle::BalanceType)sett().GetFixIDMethod(), sett().GetFixIDClans(), sett().GetFixIDStrongClans(), sett().GetFixIDGrouping() );
+ Autobalance( (IBattle::BalanceType)sett().GetBalanceMethod(), sett().GetBalanceClans(), sett().GetBalanceStrongClans(), sett().GetBalanceGrouping() );
+ FixColours();
+ }
+ }
+ if ( IsProxy() )
+ {
+ wxString hostscript = spring().WriteScriptTxt( *this );
+ try
+ {
+ wxString path = sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T("relayhost_script.txt");
+ if ( !wxFile::Access( path, wxFile::write ) ) wxLogError( _T("Access denied to script.txt.") );
+
+ wxFile f( path, wxFile::write );
+ f.Write( hostscript );
+ f.Close();
+
+ } catch (...) {}
+ m_serv.SendScriptToProxy( hostscript );
+ }
+ GetMe().BattleStatus().ready = false;
+ SendMyBattleStatus();
+ if( IsFounderMe() && GetAutoLockOnStart() )
+ {
+ SetIsLocked( true );
+ SendHostInfo( IBattle::HI_Locked );
+ }
+ GetMe().Status().in_game = spring().Run( *this );
+ GetMe().SendMyUserStatus();
+ }
+ ui().OnBattleStarted( *this );
+}
+
+void Battle::OnTimer( wxTimerEvent& event )
+{
+ if ( !IsFounderMe() ) return;
+ if ( m_ingame ) return;
+ int autospect_trigger_time = sett().GetBattleLastAutoSpectTime();
+ if ( autospect_trigger_time == 0 ) return;
+ time_t now = time(0);
+ for ( unsigned int i = 0; i < GetNumUsers(); i++)
+ {
+ User& usr = GetUser( i );
+ UserBattleStatus& status = usr.BattleStatus();
+ if ( status.IsBot() || status.spectator ) continue;
+ if ( status.sync && status.ready ) continue;
+ if ( &usr == &GetMe() ) continue;
+ std::map<wxString, time_t>::iterator itor = m_ready_up_map.find( usr.GetNick() );
+ if ( itor != m_ready_up_map.end() )
+ {
+ if ( ( now - itor->second ) > autospect_trigger_time )
+ {
+ ForceSpectator( usr, true );
+ }
+ }
+ }
+}
+
+void Battle::SetInGame( bool value )
+{
+ time_t now = time(0);
+ if ( m_ingame && !value )
+ {
+ for ( int i = 0; i < GetNumUsers(); i++ )
+ {
+ User& user = GetUser( i );
+ UserBattleStatus& status = user.BattleStatus();
+ if ( status.IsBot() || status.spectator ) continue;
+ if ( status.ready && status.sync ) continue;
+ m_ready_up_map[user.GetNick()] = now;
+ }
+ }
+ IBattle::SetInGame( value );
+}
+
+
+
+void Battle::FixColours()
+{
+ if ( !IsFounderMe() )return;
+ std::vector<wxColour> &palette = GetFixColoursPalette( m_teams_sizes.size() + 1 );
+ std::vector<int> palette_use( palette.size(), 0 );
+
+ wxColour my_col = GetMe().BattleStatus().colour; // Never changes color of founder (me) :-)
+ int my_diff = 0;
+ int my_col_i = GetClosestFixColour( my_col, palette_use,my_diff );
+ palette_use[my_col_i]++;
+ std::set<int> parsed_teams;
+
+ for ( user_map_t::size_type i = 0; i < GetNumUsers(); i++ )
+ {
+ User &user=GetUser(i);
+ if ( &user == &GetMe() ) continue; // skip founder ( yourself )
+ UserBattleStatus& status = user.BattleStatus();
+ if ( status.spectator ) continue;
+ if ( parsed_teams.find( status.team ) != parsed_teams.end() ) continue; // skip duplicates
+ parsed_teams.insert( status.team );
+
+ wxColour &user_col=status.colour;
+ int user_col_i=GetClosestFixColour(user_col,palette_use, 60);
+ palette_use[user_col_i]++;
+ for ( user_map_t::size_type j = 0; j < GetNumUsers(); j++ )
+ {
+ User &usr=GetUser(j);
+ if ( usr.BattleStatus().team == status.team )
+ {
+ ForceColour( usr, palette[user_col_i]);
+ }
+ }
+ }
+}
+
+
+bool PlayerRankCompareFunction( User *a, User *b ) // should never operate on nulls. Hence, ASSERT_LOGIC is appropriate here.
+{
+ ASSERT_LOGIC( a, _T("fail in Autobalance, NULL player") );
+ ASSERT_LOGIC( b, _T("fail in Autobalance, NULL player") );
+ return ( a->GetBalanceRank() > b->GetBalanceRank() );
+}
+
+bool PlayerTeamCompareFunction( User *a, User *b ) // should never operate on nulls. Hence, ASSERT_LOGIC is appropriate here.
+{
+ ASSERT_LOGIC( a, _T("fail in Autobalance, NULL player") );
+ ASSERT_LOGIC( b, _T("fail in Autobalance, NULL player") );
+ return ( a->BattleStatus().team > b->BattleStatus().team );
+}
+
+struct Alliance
+{
+ std::vector<User *>players;
+ float ranksum;
+ int allynum;
+ Alliance(): ranksum(0) {}
+ Alliance(int i): ranksum(0), allynum(i) {}
+ void AddPlayer( User *player )
+ {
+ if ( player )
+ {
+ players.push_back( player );
+ ranksum += player->GetBalanceRank();
+ }
+ }
+ void AddAlliance( Alliance &other )
+ {
+ for ( std::vector<User *>::iterator i = other.players.begin(); i != other.players.end(); ++i ) AddPlayer( *i );
+ }
+ bool operator < ( const Alliance &other ) const
+ {
+ return ranksum < other.ranksum;
+ }
+};
+
+struct ControlTeam
+{
+ std::vector<User*> players;
+ float ranksum;
+ int teamnum;
+ ControlTeam(): ranksum(0) {}
+ ControlTeam( int i ): ranksum(0), teamnum(i) {}
+ void AddPlayer( User *player )
+ {
+ if ( player )
+ {
+ players.push_back( player );
+ ranksum += player->GetBalanceRank();
+ }
+ }
+ void AddTeam( ControlTeam &other )
+ {
+ for ( std::vector<User*>::iterator i = other.players.begin(); i != other.players.end(); ++i ) AddPlayer( *i );
+ }
+ bool operator < (const ControlTeam &other) const
+ {
+ return ranksum < other.ranksum;
+ }
+};
+
+int my_random( int range )
+{
+ return rand() % range;
+}
+
+void shuffle(std::vector<User *> &players) // proper shuffle.
+{
+ for ( size_t i=0; i < players.size(); ++i ) // the players below i are shuffled, the players above arent
+ {
+ int rn = i + my_random( players.size() - i ); // the top of shuffled part becomes random card from unshuffled part
+ User *tmp = players[i];
+ players[i] = players[rn];
+ players[rn] = tmp;
+ }
+}
+
+/*
+bool ClanRemovalFunction(const std::map<wxString, Alliance>::value_type &v){
+ return v.second.players.size()<2;
+}
+*/
+/*
+struct ClannersRemovalPredicate{
+ std::map<wxString, Alliance> &clans;
+ PlayerRemovalPredicate(std::map<wxString, Alliance> &clans_):clans(clans_)
+ {
+ }
+ bool operator()(User *u) const{
+ return clans.find(u->GetClan());
+ }
+}*/
+
+void Battle::Autobalance( BalanceType balance_type, bool support_clans, bool strong_clans, int numallyteams )
+{
+ wxLogMessage(_T("Autobalancing alliances, type=%d, clans=%d, strong_clans=%d, numallyteams=%d"),balance_type, support_clans,strong_clans, numallyteams);
+ //size_t i;
+ //int num_alliances;
+ std::vector<Alliance>alliances;
+ if ( numallyteams == 0 ) // 0 == use num start rects
+ {
+ int ally = 0;
+ for ( int i = 0; i < GetNumRects(); ++i )
+ {
+ BattleStartRect sr = GetStartRect(i);
+ if ( sr.IsOk() )
+ {
+ ally=i;
+ alliances.push_back( Alliance( ally ) );
+ ally++;
+ }
+ }
+ // make at least two alliances
+ while ( alliances.size() < 2 )
+ {
+ alliances.push_back( Alliance( ally ) );
+ ally++;
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < numallyteams; i++ ) alliances.push_back( Alliance( i ) );
+ }
+
+ //for(i=0;i<alliances.size();++i)alliances[i].allynum=i;
+
+ wxLogMessage( _T("number of alliances: %u"), alliances.size() );
+
+ std::vector<User*> players_sorted;
+ players_sorted.reserve( GetNumUsers() );
+
+ for ( size_t i = 0; i < GetNumUsers(); ++i )
+ {
+ User& usr = GetUser( i );
+ if ( !usr.BattleStatus().spectator )
+ {
+ players_sorted.push_back( &usr );
+ }
+ }
+
+ // remove players in the same team so only one remains
+ std::map< int, User*> dedupe_teams;
+ for ( std::vector<User*>::iterator it = players_sorted.begin(); it != players_sorted.end(); it++ )
+ {
+ dedupe_teams[(*it)->BattleStatus().team] = *it;
+ }
+ players_sorted.clear();
+ players_sorted.reserve( dedupe_teams.size() );
+ for ( std::map<int, User*>::iterator it = dedupe_teams.begin(); it != dedupe_teams.end(); it++ )
+ {
+ players_sorted.push_back( it->second );
+ }
+
+ shuffle( players_sorted );
+
+ std::map<wxString, Alliance> clan_alliances;
+ if ( support_clans )
+ {
+ for ( size_t i=0; i < players_sorted.size(); ++i )
+ {
+ wxString clan = players_sorted[i]->GetClan();
+ if ( !clan.empty() )
+ {
+ clan_alliances[clan].AddPlayer( players_sorted[i] );
+ }
+ }
+ };
+
+ if ( balance_type != balance_random ) std::sort( players_sorted.begin(), players_sorted.end(), PlayerRankCompareFunction );
+
+ if ( support_clans )
+ {
+ std::map<wxString, Alliance>::iterator clan_it = clan_alliances.begin();
+ while ( clan_it != clan_alliances.end() )
+ {
+ Alliance &clan = (*clan_it).second;
+ // if clan is too small (only 1 clan member in battle) or too big, dont count it as clan
+ if ( ( clan.players.size() < 2 ) || ( !strong_clans && ( clan.players.size() > ( ( players_sorted.size() + alliances.size() -1 ) / alliances.size() ) ) ) )
+ {
+ wxLogMessage( _T("removing clan %s"), (*clan_it).first.c_str() );
+ std::map<wxString, Alliance>::iterator next = clan_it;
+ ++next;
+ clan_alliances.erase( clan_it );
+ clan_it = next;
+ continue;
+ }
+ wxLogMessage( _T("Inserting clan %s"), (*clan_it).first.c_str() );
+ std::sort( alliances.begin(), alliances.end() );
+ float lowestrank = alliances[0].ranksum;
+ int rnd_k = 1;// number of alliances with rank equal to lowestrank
+ while ( size_t( rnd_k ) < alliances.size() )
+ {
+ if ( fabs( alliances[rnd_k].ranksum - lowestrank ) > 0.01 ) break;
+ rnd_k++;
+ }
+ wxLogMessage( _T("number of lowestrank alliances with same rank=%d"), rnd_k );
+ alliances[my_random( rnd_k )].AddAlliance( clan );
+ ++clan_it;
+ }
+ }
+
+ for ( size_t i = 0; i < players_sorted.size(); ++i )
+ {
+ // skip clanners, those have been added already.
+ if ( clan_alliances.count( players_sorted[i]->GetClan() ) > 0 )
+ {
+ wxLogMessage( _T("clanner already added, nick=%s"), players_sorted[i]->GetNick().c_str() );
+ continue;
+ }
+
+ // find alliances with lowest ranksum
+ // insert current user into random one out of them
+ // since performance doesnt matter here, i simply sort alliances,
+ // then find how many alliances in beginning have lowest ranksum
+ // note that balance player ranks range from 1 to 1.1 now
+ // i.e. them are quasi equal
+ // so we're essentially adding to alliance with smallest number of players,
+ // the one with smallest ranksum.
+
+ std::sort( alliances.begin(), alliances.end() );
+ float lowestrank = alliances[0].ranksum;
+ int rnd_k = 1;// number of alliances with rank equal to lowestrank
+ while ( size_t( rnd_k ) < alliances.size() )
+ {
+ if ( fabs( alliances[rnd_k].ranksum - lowestrank ) > 0.01 ) break;
+ rnd_k++;
+ }
+ wxLogMessage( _T("number of lowestrank alliances with same rank=%d"), rnd_k );
+ alliances[my_random( rnd_k )].AddPlayer( players_sorted[i] );
+ }
+
+ UserList::user_map_t::size_type totalplayers = GetNumUsers();
+ for ( size_t i = 0; i < alliances.size(); ++i )
+ {
+ for ( size_t j = 0; j < alliances[i].players.size(); ++j )
+ {
+ ASSERT_LOGIC( alliances[i].players[j], _T("fail in Autobalance, NULL player") );
+ int balanceteam = alliances[i].players[j]->BattleStatus().team;
+ wxLogMessage( _T("setting team %d to alliance %d"), balanceteam, i );
+ for ( size_t h = 0; h < totalplayers; h++ ) // change ally num of all players in the team
+ {
+ User& usr = GetUser( h );
+ if ( usr.BattleStatus().team == balanceteam ) ForceAlly( usr, alliances[i].allynum );
+ }
+ }
+ }
+}
+
+void Battle::FixTeamIDs( BalanceType balance_type, bool support_clans, bool strong_clans, int numcontrolteams )
+{
+ wxLogMessage(_T("Autobalancing teams, type=%d, clans=%d, strong_clans=%d, numcontrolteams=%d"),balance_type, support_clans, strong_clans, numcontrolteams);
+ //size_t i;
+ //int num_alliances;
+ std::vector<ControlTeam> teams;
+
+ if ( numcontrolteams == 0 ) numcontrolteams = GetNumUsers(); // 0 == use num players, will use comshare only if no available team slots
+ IBattle::StartType position_type = (IBattle::StartType)s2l( CustomBattleOptions().getSingleValue( _T("startpostype"), OptionsWrapper::EngineOption ) );
+ if ( ( position_type == ST_Fixed ) || ( position_type == ST_Random ) ) // if fixed start pos type or random, use max teams = start pos count
+ {
+ try
+ {
+ numcontrolteams = std::min( numcontrolteams, LoadMap().info.posCount );
+ }
+ catch( assert_exception ) {}
+ }
+
+ if ( numcontrolteams >= (int)( GetNumUsers() - GetSpectators() ) ) // autobalance behaves weird when trying to put one player per team and i CBA to fix it, so i'll reuse the old code :P
+ {
+ // apparently tasserver doesnt like when i fix/force ids of everyone.
+ std::set<int> allteams;
+ size_t numusers = GetNumUsers();
+ for( size_t i = 0; i < numusers; ++i )
+ {
+ User &user = GetUser(i);
+ if( !user.BattleStatus().spectator ) allteams.insert( user.BattleStatus().team );
+ }
+ std::set<int> teams;
+ int t = 0;
+ for( size_t i = 0; i < GetNumUsers(); ++i )
+ {
+ User &user = GetUser(i);
+ if( !user.BattleStatus().spectator )
+ {
+ if( teams.count( user.BattleStatus().team ) )
+ {
+ while( allteams.count(t) || teams.count( t ) ) t++;
+ ForceTeam( GetUser(i), t );
+ teams.insert( t );
+ }
+ else
+ {
+ teams.insert( user.BattleStatus().team );
+ }
+ }
+ }
+ return;
+ }
+ for ( int i = 0; i < numcontrolteams; i++ ) teams.push_back( ControlTeam( i ) );
+
+ wxLogMessage(_T("number of teams: %u"), teams.size() );
+
+ std::vector<User*> players_sorted;
+ players_sorted.reserve( GetNumUsers() );
+
+ int player_team_counter = 0;
+
+ for ( size_t i = 0; i < GetNumUsers(); ++i ) // don't count spectators
+ {
+ if ( !GetUser(i).BattleStatus().spectator )
+ {
+ players_sorted.push_back( &GetUser(i) );
+ // -- server fail? it doesnt work right.
+ //ForceTeam(GetUser(i),player_team_counter);
+ player_team_counter++;
+ }
+ }
+
+ shuffle( players_sorted );
+
+ std::map<wxString, ControlTeam> clan_teams;
+ if ( support_clans )
+ {
+ for ( size_t i = 0; i < players_sorted.size(); ++i )
+ {
+ wxString clan = players_sorted[i]->GetClan();
+ if ( !clan.empty() )
+ {
+ clan_teams[clan].AddPlayer( players_sorted[i] );
+ }
+ }
+ };
+
+ if ( balance_type != balance_random ) std::sort( players_sorted.begin(), players_sorted.end(), PlayerRankCompareFunction );
+
+ if ( support_clans )
+ {
+ std::map<wxString, ControlTeam>::iterator clan_it = clan_teams.begin();
+ while ( clan_it != clan_teams.end() )
+ {
+ ControlTeam &clan = (*clan_it).second;
+ // if clan is too small (only 1 clan member in battle) or too big, dont count it as clan
+ if ( ( clan.players.size() < 2 ) || ( !strong_clans && ( clan.players.size() > ( ( players_sorted.size() + teams.size() -1 ) / teams.size() ) ) ) )
+ {
+ wxLogMessage(_T("removing clan %s"),(*clan_it).first.c_str());
+ std::map<wxString, ControlTeam>::iterator next = clan_it;
+ ++next;
+ clan_teams.erase( clan_it );
+ clan_it = next;
+ continue;
+ }
+ wxLogMessage( _T("Inserting clan %s"), (*clan_it).first.c_str() );
+ std::sort( teams.begin(), teams.end() );
+ float lowestrank = teams[0].ranksum;
+ int rnd_k = 1; // number of alliances with rank equal to lowestrank
+ while ( size_t( rnd_k ) < teams.size() )
+ {
+ if ( fabs( teams[rnd_k].ranksum - lowestrank ) > 0.01 ) break;
+ rnd_k++;
+ }
+ wxLogMessage(_T("number of lowestrank teams with same rank=%d"), rnd_k );
+ teams[my_random( rnd_k )].AddTeam( clan );
+ ++clan_it;
+ }
+ }
+
+ for (size_t i = 0; i < players_sorted.size(); ++i )
+ {
+ // skip clanners, those have been added already.
+ if ( clan_teams.count( players_sorted[i]->GetClan() ) > 0 )
+ {
+ wxLogMessage( _T("clanner already added, nick=%s"),players_sorted[i]->GetNick().c_str() );
+ continue;
+ }
+
+ // find teams with lowest ranksum
+ // insert current user into random one out of them
+ // since performance doesnt matter here, i simply sort teams,
+ // then find how many teams in beginning have lowest ranksum
+ // note that balance player ranks range from 1 to 1.1 now
+ // i.e. them are quasi equal
+ // so we're essentially adding to teams with smallest number of players,
+ // the one with smallest ranksum.
+
+ std::sort( teams.begin(), teams.end() );
+ float lowestrank = teams[0].ranksum;
+ int rnd_k = 1; // number of alliances with rank equal to lowestrank
+ while ( size_t( rnd_k ) < teams.size() )
+ {
+ if ( fabs ( teams[rnd_k].ranksum - lowestrank ) > 0.01 ) break;
+ rnd_k++;
+ }
+ wxLogMessage( _T("number of lowestrank teams with same rank=%d"), rnd_k );
+ teams[my_random( rnd_k )].AddPlayer( players_sorted[i] );
+ }
+
+
+ for ( size_t i=0; i < teams.size(); ++i )
+ {
+ for ( size_t j = 0; j < teams[i].players.size(); ++j )
+ {
+ ASSERT_LOGIC( teams[i].players[j], _T("fail in Autobalance teams, NULL player") );
+ wxString msg = wxString::Format( _T("setting player %s to team and ally %d"), teams[i].players[j]->GetNick().c_str(), i );
+ wxLogMessage( _T("%s"), msg.c_str() );
+ ForceTeam( *teams[i].players[j], teams[i].teamnum );
+ ForceAlly( *teams[i].players[j], teams[i].teamnum );
+ }
+ }
+}
diff --git a/src/battle.h b/src/battle.h
new file mode 100644
index 0000000..dc9ba4e
--- /dev/null
+++ b/src/battle.h
@@ -0,0 +1,142 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLE_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLE_H
+
+#include <set>
+
+#include "autohost.h"
+#include "ibattle.h"
+
+class Ui;
+class Server;
+class User;
+class wxTimerEvent;
+
+
+/** \brief model of a sp/mp battle
+ * \todo DOCME */
+class Battle : public IBattle
+{
+ public:
+ Battle( Server& serv, int id );
+ ~Battle();
+
+ //const BattleOptions& opts() { return m_opts; }
+
+ Server& GetServer() { return m_serv; }
+ AutoHost& GetAutoHost() { return m_ah; }
+
+ void SendHostInfo( HostInfo update );
+ void SendHostInfo( const wxString& Tag );
+
+ int GetMyPlayerNum() const;
+
+ void Update();
+ void Update( const wxString& Tag );
+
+ void Join( const wxString& password = _T("") );
+ void Leave();
+
+ void KickPlayer( User& user );
+
+ void RingNotReadyPlayers();
+ void RingNotSyncedPlayers();
+ void RingNotSyncedAndNotReadyPlayers();
+ void RingPlayer( const User& u );
+
+ void Say( const wxString& msg );
+ void DoAction( const wxString& msg );
+
+ void SetLocalMap( const UnitSyncMap& map );
+
+ void OnRequestBattleStatus();
+ void SendMyBattleStatus();
+
+ bool ExecuteSayCommand( const wxString& cmd );
+
+ void AddBot( const wxString& nick, UserBattleStatus status );
+
+ void ForceSide( User& user, int side );
+ void ForceTeam( User& user, int team );
+ void ForceAlly( User& user, int ally );
+ void ForceColour( User& user, const wxColour& col );
+ void ForceSpectator( User& user, bool spectator );
+ void BattleKickPlayer( User& user );
+ void SetHandicap( User& user, int handicap);
+
+ User& OnUserAdded( User& user );
+ void OnUserBattleStatusUpdated( User &user, UserBattleStatus status );
+ void OnUserRemoved( User& user );
+
+ void ForceUnsyncedToSpectate();
+ void ForceUnReadyToSpectate();
+ void ForceUnsyncedAndUnreadyToSpectate();
+
+ void SetAutoLockOnStart( bool value );
+ bool GetAutoLockOnStart();
+
+ void SetLockExternalBalanceChanges( bool value );
+ bool GetLockExternalBalanceChanges();
+
+ void FixColours();
+ void Autobalance( BalanceType balance_type = balance_divide, bool clans = true, bool strong_clans = true, int allyteamsize = 0 );
+ void FixTeamIDs( BalanceType balance_type = balance_divide, bool clans = true, bool strong_clans = true, int controlteamsize = 0 );
+
+ void SendScriptToClients();
+
+ ///< quick hotfix for bans
+ bool CheckBan(User &user);
+ ///>
+
+ void SetImReady( bool ready );
+
+ User& GetMe();
+
+ void UserPositionChanged( const User& user );
+
+ int GetID() { return m_id; }
+
+ void SaveMapDefaults();
+ void LoadMapDefaults( const wxString& mapname );
+
+ void StartSpring();
+
+ void OnTimer( wxTimerEvent& event );
+
+ void SetInGame( bool ingame );
+
+ protected:
+ // Battle variables
+
+ ///< quick hotfix for bans
+ std::set<wxString> m_banned_users;
+ std::set<wxString> m_banned_ips;
+ ///>
+
+ Server& m_serv;
+ AutoHost m_ah;
+ bool m_autolock_on_start;
+
+ const int m_id;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLE_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battlelist.cpp b/src/battlelist.cpp
new file mode 100644
index 0000000..720ca61
--- /dev/null
+++ b/src/battlelist.cpp
@@ -0,0 +1,69 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+#include <stdexcept>
+
+#include "battlelist.h"
+#include "battle.h"
+
+
+BattleList::BattleList()
+{
+}
+
+
+void BattleList::AddBattle( Battle& battle )
+{
+ m_battles[battle.GetBattleId()] = &battle;
+}
+
+
+void BattleList::RemoveBattle( battle_id_t const& id ) {
+ m_battles.erase(id);
+}
+
+
+/*
+Battle& BattleList::GetFirstBattle()
+{
+ return *m_battles.begin()->second;
+}
+*/
+
+
+BattleList::battle_map_t::size_type BattleList_Iter::GetNumBattles()
+{
+ return (m_battlelist)?(m_battlelist->m_battles.size()):0;
+}
+
+
+void BattleList_Iter::IteratorBegin()
+{
+ if (m_battlelist) m_iterator = m_battlelist->m_battles.begin();
+}
+
+Battle* BattleList_Iter::GetBattle()
+{
+
+ Battle* battle = m_iterator->second;
+ if ( m_battlelist && m_iterator != m_battlelist->m_battles.end() ) ++m_iterator;
+ return battle;
+}
+
+bool BattleList_Iter::EOL()
+{
+ return ( m_battlelist && m_iterator == m_battlelist->m_battles.end() )?true:false;
+}
+
+
+Battle& BattleList_Iter::GetBattle( BattleList::battle_id_t const& id ) {
+ if (!m_battlelist) throw std::logic_error("BattleList_Iter::GetBattle(): no battlelist");
+ BattleList::battle_iter_t b = m_battlelist->m_battles.find(id);
+ if (b == m_battlelist->m_battles.end()) throw std::runtime_error("BattleList_Iter::GetBattle(): no such battle");
+ return *b->second;
+}
+
+
+bool BattleList_Iter::BattleExists( BattleList::battle_id_t const& id ) {
+ if (!m_battlelist) throw std::logic_error("BattleList_Iter::BattleExists(): no battlelist");
+ return m_battlelist->m_battles.find(id) != m_battlelist->m_battles.end();
+}
+
diff --git a/src/battlelist.h b/src/battlelist.h
new file mode 100644
index 0000000..4c94dd1
--- /dev/null
+++ b/src/battlelist.h
@@ -0,0 +1,68 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLELIST_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLELIST_H
+
+#include <map>
+
+class Battle;
+
+
+/** \brief encapsulates a <battle_id_t, Battle*> map
+ */
+class BattleList
+{
+ friend class BattleList_Iter;
+ public:
+ BattleList();
+
+ typedef unsigned int battle_id_t;
+
+ void AddBattle( Battle& battle );
+ void RemoveBattle( battle_id_t const& id );
+
+ //! @brief mapping from battle id number to battle object
+ typedef std::map<battle_id_t, Battle*> battle_map_t;
+ //! @brief iterator for battle map
+ typedef battle_map_t::iterator battle_iter_t;
+
+ private:
+ battle_map_t m_battles;
+};
+
+/** BattleList_Iter gives us the posibility to get Battles out of the list without the rights to change the list */
+class BattleList_Iter
+{
+ public:
+ BattleList_Iter(BattleList* battlelist) : m_battlelist( battlelist ) {};
+ ~BattleList_Iter() {};
+ void IteratorBegin();
+ Battle* GetBattle();
+ bool EOL();
+ Battle& GetBattle( BattleList::battle_id_t const& id );
+ //Battle& GetFirstBattle();
+ bool BattleExists( BattleList::battle_id_t const& id );
+ BattleList::battle_map_t::size_type GetNumBattles();
+ private:
+ BattleList::battle_iter_t m_iterator;
+ BattleList* m_battlelist;
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLELIST_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battlelistctrl.cpp b/src/battlelistctrl.cpp
new file mode 100644
index 0000000..5ec1b9d
--- /dev/null
+++ b/src/battlelistctrl.cpp
@@ -0,0 +1,405 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include "battlelistctrl.h"
+
+#include <wx/intl.h>
+#include <wx/menu.h>
+
+#include "user.h"
+#include "iconimagelist.h"
+#include "battle.h"
+#include "uiutils.h"
+#include "ui.h"
+#include "server.h"
+#include "countrycodes.h"
+#include "settings.h"
+#include "settings++/custom_dialogs.h"
+#include "useractions.h"
+#include "Helper/sortutil.h"
+#include "aui/auimanager.h"
+
+template<> SortOrder CustomVirtListCtrl<IBattle*,BattleListCtrl>::m_sortorder = SortOrder();
+
+BEGIN_EVENT_TABLE(BattleListCtrl, BattleListCtrl::BaseType )
+
+ EVT_LIST_ITEM_RIGHT_CLICK( BLIST_LIST, BattleListCtrl::OnListRightClick )
+ EVT_MENU ( BLIST_DLMAP, BattleListCtrl::OnDLMap )
+ EVT_MENU ( BLIST_DLMOD, BattleListCtrl::OnDLMod )
+#if wxUSE_TIPWINDOW
+#if !defined(__WXMSW__) /* && !defined(__WXMAC__) */ //disables tooltips on msw /* and mac */
+ EVT_MOTION(BattleListCtrl::OnMouseMotion)
+#endif
+#endif
+END_EVENT_TABLE()
+
+BattleListCtrl::BattleListCtrl( wxWindow* parent, Ui& ui )
+ : CustomVirtListCtrl< IBattle *,BattleListCtrl>(parent, BLIST_LIST, wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_ALIGN_LEFT, _T("BattleListCtrl"), 10, 4, &CompareOneCrit,
+ true /*highlight*/, UserActions::ActHighlight, true /*periodic sort*/ ),
+ m_popup( 0 ),
+ m_ui(ui)
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("battlelistctrl") );
+
+
+ const int hd = wxLIST_AUTOSIZE_USEHEADER;
+
+#if defined(__WXMAC__)
+/// on mac, autosize does not work at all
+ const int widths[10] = {20,20,20,170,140,130,110,28,28,28};
+#else
+ const int widths[10] = {hd,hd,hd,170,140,130,110,hd,hd,hd};
+#endif
+
+ AddColumn( 0, widths[0], _T("Status"), _T("Status") );
+ AddColumn( 1, widths[1], _T("Country"), _T("Country") );
+ AddColumn( 2, widths[2], _T("Rank"), _T("Minimum rank to join") );
+ AddColumn( 3, widths[3], _("Description"), _T("Game description") );
+ AddColumn( 4, widths[4], _("Map"), _T("Mapname") );
+ AddColumn( 5, widths[5], _("Mod"), _T("Modname") );
+ AddColumn( 6, widths[6], _("Host"), _T("Name of the Host") );
+ AddColumn( 7, widths[7], _("Spectators"), _T("Number of Spectators") );
+ AddColumn( 8, widths[8], _("Players"), _T("Number of Players joined") );
+ AddColumn( 9, widths[9], _("Max"), _T("Maximum number of Players that can join") );
+
+ if ( m_sortorder.size() == 0 ) {
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = true;
+ m_sortorder[1].col = 5;
+ m_sortorder[1].direction = true;
+ m_sortorder[2].col = 9;
+ m_sortorder[2].direction = true;
+ m_sortorder[3].col = 4;
+ m_sortorder[3].direction = true;
+ }
+
+}
+
+
+BattleListCtrl::~BattleListCtrl()
+{
+ if ( m_popup )
+ delete m_popup;
+}
+
+wxString BattleListCtrl::GetItemText(long item, long column) const
+{
+ if ( m_data[item] == NULL )
+ return wxEmptyString;
+
+ const IBattle& battle= *m_data[item];
+ const BattleOptions& opts = battle.GetBattleOptions();
+
+ switch ( column ) {
+ case 0:
+ case 1:
+ case 2:
+ default: return wxEmptyString;
+
+ case 3: return ( opts.description );
+ case 4: return ( RefineMapname( battle.GetHostMapName() ) );
+ case 5: return ( RefineModname( battle.GetHostModName() ) );
+ case 6: return ( opts.founder );
+ case 7: return ( wxString::Format(_T("%d"), int(battle.GetSpectators())) );
+ case 8: return ( wxString::Format(_T("%d"), int(battle.GetNumUsers()) - int(battle.GetSpectators()) ) );
+ case 9: return ( wxString::Format(_T("%d"), int(battle.GetMaxPlayers())) );
+ }
+}
+
+int BattleListCtrl::GetItemImage(long item) const
+{
+ if ( m_data[item] == NULL )
+ return -1;
+
+ return icons().GetBattleStatusIcon( *m_data[item] );
+}
+
+int BattleListCtrl::GetItemColumnImage(long item, long column) const
+{
+ if ( m_data[item] == NULL )
+ return -1;
+
+ const IBattle& battle= *m_data[item];
+
+ switch ( column ) {
+ default: return -1;
+
+ case 0: return icons().GetBattleStatusIcon( battle );
+ case 1:
+ {
+ try
+ {
+ return icons().GetFlagIcon( battle.GetFounder().GetCountry() );
+ }catch(...){}
+ break;
+ }
+ case 2: return icons().GetRankIcon( battle.GetRankNeeded(), false );
+ case 4: return battle.MapExists() ? icons().ICON_EXISTS : icons().ICON_NEXISTS;
+ case 5: return battle.ModExists() ? icons().ICON_EXISTS : icons().ICON_NEXISTS;
+ }
+}
+
+wxListItemAttr* BattleListCtrl::GetItemAttr(long item) const
+{
+ if ( item < (long)m_data.size() && item > -1 ) {
+ const IBattle& b = *m_data[item];
+ try
+ {
+ wxString host = b.GetFounder().GetNick();
+ wxListItemAttr* attr = HighlightItemUser( host );
+ if ( attr != NULL )
+ return attr;
+
+ //to avoid color flicker check first if highlighting should be done
+ //and return if it should
+ for ( unsigned int i = 0; i < b.GetNumUsers(); ++i){
+ wxString name = b.GetUser(i).GetNick();
+ attr = HighlightItemUser( name );
+ if ( attr != NULL )
+ return attr;
+
+ }
+ }catch(...){}
+ }
+ return NULL;
+}
+
+
+void BattleListCtrl::AddBattle( IBattle& battle )
+{
+ if ( AddItem( &battle ) )
+ return;
+
+ wxLogWarning( _T("Battle already in list.") );
+}
+
+void BattleListCtrl::RemoveBattle( IBattle& battle )
+{
+ if ( RemoveItem( &battle ) )
+ return;
+
+ wxLogError( _T("Didn't find the battle to remove.") );
+}
+
+void BattleListCtrl::UpdateBattle( IBattle& battle )
+{
+ int index = GetIndexFromData( &battle );
+
+ RefreshItem( index );
+ MarkDirtySort();
+}
+
+void BattleListCtrl::OnListRightClick( wxListEvent& event )
+{
+ int idx = event.GetIndex();
+ if ( idx < (long)m_data.size() && idx > -1 ) {
+
+ DataType dt = m_data[idx];
+ bool mod_missing = !dt->ModExists();
+ bool map_missing = !dt->MapExists();
+ m_popup = new wxMenu( _T("") );
+ // &m enables shortcout "alt + m" and underlines m
+ if ( map_missing )
+ m_popup->Append( BLIST_DLMAP, _("Download &map") );
+
+ if ( mod_missing )
+ m_popup->Append( BLIST_DLMOD, _("Download m&od") );
+
+ if ( map_missing || mod_missing )
+ PopupMenu( m_popup );
+ }
+}
+
+void BattleListCtrl::OnDLMap( wxCommandEvent& /*unused*/ )
+{
+ if ( m_selected_index > 0 && (long)m_data.size() > m_selected_index ) {
+ DataType dt = m_data[m_selected_index];
+ m_ui.DownloadMap( dt->GetHostMapHash(), dt->GetHostMapName() );
+ }
+}
+
+void BattleListCtrl::OnDLMod( wxCommandEvent& /*unused*/ )
+{
+ if ( m_selected_index > 0 && (long)m_data.size() > m_selected_index ) {
+ DataType dt = m_data[m_selected_index];
+ m_ui.DownloadMod( dt->GetHostModHash(), dt->GetHostModName() );
+ }
+}
+
+void BattleListCtrl::Sort()
+{
+ if ( m_data.size() > 0 )
+ {
+ SaveSelection();
+ SLInsertionSort( m_data, m_comparator );
+ RestoreSelection();
+ }
+}
+
+int BattleListCtrl::CompareOneCrit( DataType u1, DataType u2, int col, int dir )
+{
+ switch ( col ) {
+ case 0: return dir * CompareStatus( u1, u2 );
+ case 1:
+ {
+ try
+ {
+ return dir * u1->GetFounder().GetCountry().CmpNoCase( u2->GetFounder().GetCountry() );
+ }catch(...){}
+ break;
+ }
+ case 2: return dir * compareSimple( u1->GetRankNeeded(), u2->GetRankNeeded() );
+ case 3: return dir * u1->GetDescription().CmpNoCase( u2->GetDescription() );
+ case 4: return dir * RefineMapname( u1->GetHostMapName() ).CmpNoCase( RefineMapname( u2->GetHostMapName() ) );
+ case 5: return dir * RefineModname( u1->GetHostModName() ).CmpNoCase( RefineModname( u2->GetHostModName() ) );
+ case 6:
+ {
+ try
+ {
+ return dir * u1->GetFounder().GetNick().CmpNoCase( u2->GetFounder().GetNick() );
+ }catch(...){}
+ break;
+ }
+ case 7: return dir * compareSimple( u1->GetSpectators(), u2->GetSpectators() );
+ case 8: return dir * ComparePlayer( u1, u2 );
+ case 9: return dir * compareSimple( u1->GetMaxPlayers(), u2->GetMaxPlayers() );
+ default: return 0;
+ }
+}
+
+int BattleListCtrl::CompareStatus( DataType u1, DataType u2 )
+{
+ const IBattle& battle1 = *u1;
+ const IBattle& battle2 = *u2;
+
+ int b1 = 0, b2 = 0;
+
+ if ( battle1.GetInGame() )
+ b1 += 1000;
+ if ( battle2.GetInGame() )
+ b2 += 1000;
+ if ( battle1.IsLocked() )
+ b1 += 100;
+ if ( battle2.IsLocked() )
+ b2 += 100;
+ if ( battle1.IsPassworded() )
+ b1 += 50;
+ if ( battle2.IsPassworded() )
+ b2 += 50;
+ if ( battle1.IsFull() )
+ b1 += 25;
+ if ( battle2.IsFull() )
+ b2 += 25;
+
+ // inverse the order
+ if ( b1 < b2 )
+ return -1;
+ if ( b1 > b2 )
+ return 1;
+
+ return 0;
+}
+
+
+int BattleListCtrl::ComparePlayer( DataType u1, DataType u2 )
+{
+ const IBattle& battle1 = *u1;
+ const IBattle& battle2 = *u2;
+
+ int n1 = battle1.GetNumUsers() - battle1.GetSpectators();
+ int n2 = battle2.GetNumUsers() - battle2.GetSpectators();
+ return compareSimple( n1, n2 );
+}
+
+void BattleListCtrl::SetTipWindowText( const long item_hit, const wxPoint& position)
+{
+ if ( (long)m_data.size() < item_hit ) {
+ m_tiptext = _T("");
+ return;
+ }
+
+ const IBattle& battle= *m_data[item_hit];
+
+ int column = getColumnFromPosition(position);
+ switch (column)
+ {
+ case 0: // status
+ m_tiptext = icons().GetBattleStatus(battle);
+ break;
+ case 1: // country
+ try
+ {
+ m_tiptext = GetFlagNameFromCountryCode(battle.GetFounder().GetCountry());
+ }catch(...){}
+ break;
+ case 2: // rank_min
+ m_tiptext = m_colinfovec[column].tip;
+ break;
+ case 3: // descrp
+ m_tiptext = battle.GetDescription();
+ break;
+ case 4: //map
+ m_tiptext = RefineMapname(battle.GetHostMapName());
+ break;
+ case 5: //mod
+ m_tiptext = RefineModname(battle.GetHostModName());
+ break;
+ case 6: // host
+ try
+ {
+ m_tiptext = battle.GetFounder().GetNick();
+ }catch(...){}
+ break;
+ case 7: // specs
+ m_tiptext = _("Spectators:");
+ for (unsigned int i = 0; i < battle.GetNumUsers(); ++i )
+ {
+ if ( battle.GetUser(i).BattleStatus().spectator ) m_tiptext << _T("\n") << battle.GetUser(i).GetNick();
+ }
+ break;
+ case 8: // player
+ m_tiptext = _("Active Players:");
+ for ( unsigned int i = 0; i < battle.GetNumUsers(); ++i )
+ {
+ if ( !battle.GetUser(i).BattleStatus().spectator ) m_tiptext << _T("\n") << battle.GetUser(i).GetNick();
+ }
+ break;
+ case 9: //may player
+ m_tiptext = (m_colinfovec[column].tip);
+ break;
+
+ default: m_tiptext = _T("");
+ break;
+ }
+}
+
+
+int BattleListCtrl::GetIndexFromData( const DataType& data ) const
+{
+ static long seekpos;
+ seekpos = clamp( seekpos, 0l , (long)m_data.size() );
+ int index = seekpos;
+
+ for ( DataCIter f_idx = m_data.begin() + seekpos; f_idx != m_data.end() ; ++f_idx )
+ {
+ if ( *f_idx != 0 && data->Equals( *(*f_idx) ) )
+ {
+ seekpos = index;
+ return seekpos;
+ }
+ index++;
+ }
+ //it's ok to init with seekpos, if it had changed this would not be reached
+ int r_index = seekpos - 1;
+ for ( DataRevCIter r_idx = m_data.rbegin() + ( m_data.size() - seekpos ); r_idx != m_data.rend() ; ++r_idx )
+ {
+ if ( *r_idx != 0 && data->Equals( *(*r_idx) ) )
+ {
+ seekpos = r_index;
+ return seekpos;
+ }
+ r_index--;
+ }
+
+ return -1;
+}
diff --git a/src/battlelistctrl.h b/src/battlelistctrl.h
new file mode 100644
index 0000000..0c952eb
--- /dev/null
+++ b/src/battlelistctrl.h
@@ -0,0 +1,83 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLELISTCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLELISTCTRL_H
+
+#include "battlelistfilter.h"
+#include "battlelist.h"
+
+#include "customvirtlistctrl.h"
+
+class wxMenu;
+class IBattle;
+class wxListEvent;
+class wxCommandEvent;
+class Ui;
+
+/** \brief The ListCtrll contained in BattleListTab dispalying all currently active battles with their infos
+ * \todo DOCMEMORE */
+class BattleListCtrl : public CustomVirtListCtrl< IBattle *, BattleListCtrl>
+{
+ public:
+ BattleListCtrl( wxWindow* parent, Ui& ui );
+ ~BattleListCtrl();
+
+ void AddBattle( IBattle& battle );
+ void RemoveBattle( IBattle& battle );
+ void UpdateBattle( IBattle& battle );
+
+
+ void OnListRightClick( wxListEvent& event );
+ void OnDLMap( wxCommandEvent& event );
+ void OnDLMod( wxCommandEvent& event );
+ virtual void SetTipWindowText( const long item_hit, const wxPoint& position);
+
+ //these are overloaded to use list in virtual style
+ wxString GetItemText(long item, long column) const;
+ int GetItemImage(long item) const;
+ int GetItemColumnImage(long item, long column) const;
+ wxListItemAttr * GetItemAttr(long item) const;
+
+ enum {
+ BLIST_LIST = wxID_HIGHEST,
+ BLIST_DLMOD,
+ BLIST_DLMAP
+ };
+
+
+ protected:
+ static int wxCALLBACK CompareStatusDOWN(long item1, long item2, long sortData);
+
+ static int CompareStatus( DataType u1, DataType u2 );
+ static int ComparePlayer( DataType u1, DataType u2 );
+
+ static int CompareOneCrit( DataType u1, DataType u2, int col, int dir ) ;
+ int GetIndexFromData( const DataType& data ) const;
+
+ wxMenu* m_popup;
+ Ui& m_ui;
+
+ virtual void Sort();
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLELISTCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battlelistfilter.cpp b/src/battlelistfilter.cpp
new file mode 100644
index 0000000..af91322
--- /dev/null
+++ b/src/battlelistfilter.cpp
@@ -0,0 +1,667 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+//
+// Class: BattleOptionsTab
+//
+
+
+#if wxUSE_TOGGLEBTN
+#include <wx/tglbtn.h>
+#endif
+#include <wx/stattext.h>
+#include <wx/checkbox.h>
+#include <wx/sizer.h>
+#include <wx/textctrl.h>
+#include <wx/intl.h>
+#include <wx/choice.h>
+#include <wx/button.h>
+#include <wx/string.h>
+#include <wx/statbox.h>
+#include <wx/event.h>
+#include <wx/regex.h>
+
+#include "battlelistfilter.h"
+#include "battlelistfiltervalues.h"
+#include "battlelistctrl.h"
+#include "battle.h"
+#include "uiutils.h"
+#include "utils/tasutil.h"
+#include "settings.h"
+#include "aui/auimanager.h"
+#include "useractions.h"
+///////////////////////////////////////////////////////////////////////////
+
+BEGIN_EVENT_TABLE( BattleListFilter, wxPanel )
+
+ EVT_BUTTON ( BATTLE_FILTER_RANK_BUTTON , BattleListFilter::OnRankButton )
+ EVT_BUTTON ( BATTLE_FILTER_PLAYER_BUTTON , BattleListFilter::OnPlayerButton )
+ EVT_BUTTON ( BATTLE_FILTER_MAXPLAYER_BUTTON, BattleListFilter::OnMaxPlayerButton )
+ EVT_BUTTON ( BATTLE_FILTER_SPECTATOR_BUTTON, BattleListFilter::OnSpectatorButton )
+ EVT_CHOICE ( BATTLE_FILTER_SPECTATOR_CHOICE, BattleListFilter::OnSpectatorChange )
+ EVT_CHOICE ( BATTLE_FILTER_MAXPLAYER_CHOICE, BattleListFilter::OnMaxPlayerChange )
+ EVT_CHOICE ( BATTLE_FILTER_PLAYER_CHOICE , BattleListFilter::OnPlayerChange )
+ EVT_CHOICE ( BATTLE_FILTER_RANK_CHOICE , BattleListFilter::OnRankChange )
+ EVT_CHECKBOX ( BATTLE_FILTER_LOCKED , BattleListFilter::OnChange )
+ EVT_CHECKBOX ( BATTLE_FILTER_OPEN , BattleListFilter::OnChange )
+ EVT_CHECKBOX ( BATTLE_FILTER_PASSWORDED , BattleListFilter::OnChange )
+ EVT_CHECKBOX ( BATTLE_FILTER_FULL , BattleListFilter::OnChange )
+ EVT_CHECKBOX ( BATTLE_FILTER_STARTED , BattleListFilter::OnChange )
+ EVT_TEXT ( BATTLE_FILTER_HOST_EDIT , BattleListFilter::OnChangeHost )
+ EVT_TEXT ( BATTLE_FILTER_DESCRIPTION_EDIT, BattleListFilter::OnChangeDescription )
+ EVT_TEXT ( BATTLE_FILTER_MAP_EDIT , BattleListFilter::OnChangeMap )
+ EVT_TEXT ( BATTLE_FILTER_MOD_EDIT , BattleListFilter::OnChangeMod )
+ EVT_CHECKBOX ( BATTLE_FILTER_MAP_SHOW , BattleListFilter::OnChange )
+ EVT_CHECKBOX ( BATTLE_FILTER_MOD_SHOW , BattleListFilter::OnChange )
+ EVT_CHECKBOX ( BATTLE_FILTER_HIGHLIGHTED , BattleListFilter::OnChange )
+
+END_EVENT_TABLE()
+
+
+BattleListFilter::BattleListFilter( wxWindow* parent, wxWindowID id, BattleListTab* parentBattleListTab,
+ const wxPoint& pos, const wxSize& size, long style )
+ : wxPanel( parent, id, pos, size, style ),
+ m_parent_battlelisttab( parentBattleListTab ),
+ m_filter_host_edit( 0 ),
+ m_filter_host_expression( 0 ),
+ m_filter_description_edit( 0 ),
+ m_filter_description_expression( 0 ),
+ m_filter_map_edit( 0 ),
+ m_filter_map_expression( 0 ),
+ m_filter_mod_edit( 0 ), m_filter_mod_expression( 0 ),
+ m_filter_highlighted( false )
+
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "battlelistfilter" ) );
+
+ BattleListFilterValues f_values = sett().GetBattleFilterValues( sett().GetLastBattleFilterProfileName() );
+
+ wxBoxSizer* m_filter_sizer;
+ m_filter_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxStaticBoxSizer* m_filter_body_sizer;
+ m_filter_body_sizer = new wxStaticBoxSizer( new wxStaticBox( this, -1, wxEmptyString ), wxVERTICAL );
+
+ wxBoxSizer* m_filter_body_row1_sizer;
+ m_filter_body_row1_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_column_1;
+ m_filter_column_1 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_host_text = new wxStaticText( this, wxID_ANY, _( "Host:" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_host_text->Wrap( -1 );
+ m_filter_host_text->SetMinSize( wxSize( 90, -1 ) );
+
+
+ m_filter_column_1->Add( m_filter_host_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_host_edit = new wxTextCtrl( this, BATTLE_FILTER_HOST_EDIT, f_values.host, wxDefaultPosition, wxSize( -1, -1 ), 0 | wxSIMPLE_BORDER );
+ m_filter_host_edit->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
+ m_filter_host_edit->SetMinSize( wxSize( 220, -1 ) );
+ m_filter_host_expression = new wxRegEx( m_filter_host_edit->GetValue(), wxRE_ICASE );
+
+ m_filter_column_1->Add( m_filter_host_edit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row1_sizer->Add( m_filter_column_1, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_status_sizer1;
+ m_filter_status_sizer1 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_status_text = new wxStaticText( this, wxID_ANY, _( "Status:" ), wxPoint( -1, -1 ), wxDefaultSize, 0 );
+ m_filter_status_text->Wrap( -1 );
+ m_filter_status_sizer1->Add( m_filter_status_text, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_status_locked = new wxCheckBox( this, BATTLE_FILTER_LOCKED, _( "Locked" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_status_locked->SetValue( f_values.status_locked );
+
+ m_filter_status_sizer1->Add( m_filter_status_locked, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
+
+ m_filter_status_pass = new wxCheckBox( this, BATTLE_FILTER_PASSWORDED, _( "Passworded" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_status_pass->SetValue( f_values.status_passworded );
+
+ m_filter_status_sizer1->Add( m_filter_status_pass, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
+
+ m_filter_highlighted = new wxCheckBox( this, BATTLE_FILTER_HIGHLIGHTED , _( "Highlighted only" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_highlighted->SetValue( f_values.highlighted_only );
+
+ m_filter_status_sizer1->Add( m_filter_highlighted, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
+
+ m_filter_body_row1_sizer->Add( m_filter_status_sizer1, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_rank_sizer;
+ m_filter_rank_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_rank_text = new wxStaticText( this, wxID_ANY, _( "Rank Limit:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_rank_text->Wrap( -1 );
+ m_filter_rank_sizer->Add( m_filter_rank_text, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_rank_button = new wxButton( this, BATTLE_FILTER_RANK_BUTTON, f_values.rank_mode, wxDefaultPosition, wxSize( 25, 25 ), 0 );
+ m_filter_rank_sizer->Add( m_filter_rank_button, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxArrayString m_filter_rank_choiceChoices;
+
+ m_filter_rank_choiceChoices.Add( _T( "All" ) );
+ m_filter_rank_choiceChoices.Add( _T( "1" ) );
+ m_filter_rank_choiceChoices.Add( _T( "2" ) );
+ m_filter_rank_choiceChoices.Add( _T( "3" ) );
+ m_filter_rank_choiceChoices.Add( _T( "4" ) );
+ m_filter_rank_choiceChoices.Add( _T( "5" ) );
+ m_filter_rank_choiceChoices.Add( _T( "6" ) );
+ m_filter_rank_choiceChoices.Add( _T( "7" ) );
+
+ m_filter_rank_choice = new wxChoice( this, BATTLE_FILTER_RANK_CHOICE, wxDefaultPosition, wxSize( -1, -1 ), m_filter_rank_choiceChoices, wxSIMPLE_BORDER );
+ m_filter_rank_choice->SetSelection( GetIntParam( f_values.rank ) );
+ m_filter_rank_choice->SetMinSize( wxSize( 40, -1 ) );
+
+ m_filter_rank_sizer->Add( m_filter_rank_choice, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row1_sizer->Add( m_filter_rank_sizer, 0, wxEXPAND, 5 );
+
+ m_filter_body_sizer->Add( m_filter_body_row1_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_body_row2_sizer;
+ m_filter_body_row2_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_description_sizer;
+ m_filter_description_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_description_text = new wxStaticText( this, wxID_ANY, _( "Description:" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_description_text->Wrap( -1 );
+ m_filter_description_text->SetMinSize( wxSize( 90, -1 ) );
+
+ m_filter_description_sizer->Add( m_filter_description_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_description_edit = new wxTextCtrl( this, BATTLE_FILTER_DESCRIPTION_EDIT, f_values.description, wxDefaultPosition, wxSize( -1, -1 ), 0 | wxSIMPLE_BORDER );
+ m_filter_description_edit->SetMinSize( wxSize( 220, -1 ) );
+ m_filter_description_expression = new wxRegEx( m_filter_description_edit->GetValue(), wxRE_ICASE );
+
+ m_filter_description_sizer->Add( m_filter_description_edit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row2_sizer->Add( m_filter_description_sizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_sizer2;
+ m_filter_sizer2 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_status_text1 = new wxStaticText( this, wxID_ANY, _( "Status:" ), wxPoint( -1, -1 ), wxDefaultSize, 0 );
+ m_filter_status_text1->Wrap( -1 );
+ m_filter_sizer2->Add( m_filter_status_text1, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_status_start = new wxCheckBox( this, BATTLE_FILTER_STARTED, _( "Started" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_status_start->SetValue( f_values.status_start );
+
+ m_filter_sizer2->Add( m_filter_status_start, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
+
+ m_filter_status_full = new wxCheckBox( this, BATTLE_FILTER_FULL, _( "Full" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_status_full->SetValue( f_values.status_full );
+
+ m_filter_sizer2->Add( m_filter_status_full, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
+
+ m_filter_status_open = new wxCheckBox( this, BATTLE_FILTER_OPEN, _( "Open" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_status_open->SetValue( f_values.status_open );
+
+ m_filter_sizer2->Add( m_filter_status_open, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
+
+ m_filter_body_row2_sizer->Add( m_filter_sizer2, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_player_sizer;
+ m_filter_player_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_player_text = new wxStaticText( this, wxID_ANY, _( "Player:" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_player_text->Wrap( -1 );
+ m_filter_player_sizer->Add( m_filter_player_text, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_player_button = new wxButton( this, BATTLE_FILTER_PLAYER_BUTTON, f_values.player_mode, wxDefaultPosition, wxSize( 25, 25 ), 0 );
+ m_filter_player_sizer->Add( m_filter_player_button, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxArrayString m_filter_player_choiceChoices;
+
+ m_filter_player_choiceChoices.Add( _( "All" ) );
+ for ( wxLongLong i = 0;i <= 32;i++ ) m_filter_player_choiceChoices.Add( i.ToString() );
+
+ m_filter_player_choice = new wxChoice( this, BATTLE_FILTER_PLAYER_CHOICE, wxDefaultPosition, wxSize( -1, -1 ), m_filter_player_choiceChoices, 0 );
+ m_filter_player_choice->SetSelection( GetIntParam( f_values.player_num ) );
+ m_filter_player_choice->SetMinSize( wxSize( 40, -1 ) );
+
+ m_filter_player_sizer->Add( m_filter_player_choice, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row2_sizer->Add( m_filter_player_sizer, 0, wxEXPAND | wxLEFT, 5 );
+
+ m_filter_body_sizer->Add( m_filter_body_row2_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_body_row3_sizer;
+ m_filter_body_row3_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_map_sizer;
+ m_filter_map_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_map_text = new wxStaticText( this, wxID_ANY, _( "Map:" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_map_text->Wrap( -1 );
+ m_filter_map_text->SetMinSize( wxSize( 90, -1 ) );
+
+ m_filter_map_sizer->Add( m_filter_map_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_map_edit = new wxTextCtrl( this, BATTLE_FILTER_MAP_EDIT, f_values.map, wxDefaultPosition, wxSize( -1, -1 ), 0 | wxSIMPLE_BORDER );
+ m_filter_map_edit->SetMinSize( wxSize( 140, -1 ) );
+ m_filter_map_expression = new wxRegEx( m_filter_map_edit->GetValue(), wxRE_ICASE );
+
+ m_filter_map_sizer->Add( m_filter_map_edit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row3_sizer->Add( m_filter_map_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_only_map_sizer;
+ m_filter_only_map_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_map_show = new wxCheckBox( this, BATTLE_FILTER_MAP_SHOW, _( "Only maps i have" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_map_show->SetValue( f_values.map_show );
+ m_filter_map_show->SetMinSize( wxSize( 140, -1 ) );
+
+ m_filter_only_map_sizer->Add( m_filter_map_show, 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row3_sizer->Add( m_filter_only_map_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_maxplayer_sizer;
+ m_filter_maxplayer_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_maxplayer_text = new wxStaticText( this, wxID_ANY, _( "Max.Player:" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_maxplayer_text->Wrap( -1 );
+ m_filter_maxplayer_sizer->Add( m_filter_maxplayer_text, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_maxplayer_button = new wxButton( this, BATTLE_FILTER_MAXPLAYER_BUTTON, f_values.maxplayer_mode, wxDefaultPosition, wxSize( 25, 25 ), 0 );
+ m_filter_maxplayer_sizer->Add( m_filter_maxplayer_button, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxArrayString m_filter_maxplayer_choiceChoices;
+ m_filter_maxplayer_choiceChoices.Add( _T( "All" ) );
+ for ( wxLongLong i = 0;i <= 32;i++ ) m_filter_maxplayer_choiceChoices.Add( i.ToString() );
+
+ m_filter_maxplayer_choice = new wxChoice( this, BATTLE_FILTER_MAXPLAYER_CHOICE, wxDefaultPosition, wxSize( -1, -1 ), m_filter_maxplayer_choiceChoices, 0 );
+ m_filter_maxplayer_choice->SetSelection( GetIntParam( f_values.maxplayer ) );
+ m_filter_maxplayer_choice->SetMinSize( wxSize( 40, -1 ) );
+
+ m_filter_maxplayer_sizer->Add( m_filter_maxplayer_choice, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row3_sizer->Add( m_filter_maxplayer_sizer, 0, wxEXPAND, 5 );
+
+ m_filter_body_sizer->Add( m_filter_body_row3_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_body_row4_sizer;
+ m_filter_body_row4_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_mod_sizer;
+ m_filter_mod_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_mod_text = new wxStaticText( this, wxID_ANY, _( "Mod:" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_mod_text->Wrap( -1 );
+ m_filter_mod_text->SetMinSize( wxSize( 90, -1 ) );
+
+ m_filter_mod_sizer->Add( m_filter_mod_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_mod_edit = new wxTextCtrl( this, BATTLE_FILTER_MOD_EDIT, f_values.mod, wxDefaultPosition, wxSize( -1, -1 ), 0 | wxSIMPLE_BORDER );
+ m_filter_mod_edit->SetMinSize( wxSize( 140, -1 ) );
+ m_filter_mod_expression = new wxRegEx( m_filter_mod_edit->GetValue(), wxRE_ICASE );
+
+ m_filter_mod_sizer->Add( m_filter_mod_edit, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row4_sizer->Add( m_filter_mod_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_only_mod_sizer;
+ m_filter_only_mod_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_mod_show = new wxCheckBox( this, BATTLE_FILTER_MOD_SHOW, _( "Only mods i have" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_mod_show->SetValue( f_values.mod_show );
+ m_filter_mod_show->SetMinSize( wxSize( 140, -1 ) );
+
+ m_filter_only_mod_sizer->Add( m_filter_mod_show, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL | wxEXPAND, 5 );
+
+ m_filter_body_row4_sizer->Add( m_filter_only_mod_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_spectator_sizer;
+ m_filter_spectator_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_spectator_text = new wxStaticText( this, wxID_ANY, _( " Spectator:" ), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ m_filter_spectator_text->Wrap( -1 );
+ m_filter_spectator_sizer->Add( m_filter_spectator_text, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ m_filter_spectator_button = new wxButton( this, BATTLE_FILTER_SPECTATOR_BUTTON, f_values.spectator_mode, wxDefaultPosition, wxSize( 25, 25 ), 0 );
+ m_filter_spectator_sizer->Add( m_filter_spectator_button, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxArrayString m_filter_spectator_choiceChoices;
+ m_filter_spectator_choiceChoices.Add( _T( "All" ) );
+ for ( wxLongLong i = 0;i <= 32;i++ ) m_filter_spectator_choiceChoices.Add( i.ToString() );
+
+ m_filter_spectator_choice = new wxChoice( this, BATTLE_FILTER_SPECTATOR_CHOICE, wxDefaultPosition, wxSize( -1, -1 ), m_filter_spectator_choiceChoices, 0 );
+ m_filter_spectator_choice->SetSelection( GetIntParam( f_values.spectator ) );
+ m_filter_spectator_choice->SetMinSize( wxSize( 40, -1 ) );
+
+ m_filter_spectator_sizer->Add( m_filter_spectator_choice, 0, wxALIGN_RIGHT | wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row4_sizer->Add( m_filter_spectator_sizer, 0, wxEXPAND, 5 );
+
+ m_filter_body_sizer->Add( m_filter_body_row4_sizer, 1, wxEXPAND, 5 );
+
+ m_filter_sizer->Add( m_filter_body_sizer, 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ m_activ = false;
+ m_filter_rank_mode = _GetButtonMode( f_values.rank_mode );
+ m_filter_player_mode = _GetButtonMode( f_values.player_mode );
+ m_filter_maxplayer_mode = _GetButtonMode( f_values.maxplayer_mode );
+ m_filter_spectator_mode = _GetButtonMode( f_values.spectator_mode );
+ m_filter_rank_choice_value = m_filter_rank_choice->GetSelection() - 1;
+ m_filter_player_choice_value = m_filter_player_choice->GetSelection() - 1;
+ m_filter_maxplayer_choice_value = m_filter_maxplayer_choice->GetSelection() - 1;
+ m_filter_spectator_choice_value = m_filter_spectator_choice->GetSelection() - 1 ;
+
+ this->SetSizer( m_filter_sizer );
+ this->Layout();
+ m_filter_sizer->Fit( this );
+
+ if ( m_filter_map_expression != NULL ) {
+ delete m_filter_map_expression;
+ }
+ m_filter_map_expression = new wxRegEx( m_filter_map_edit->GetValue(), wxRE_ICASE );
+ if ( m_filter_mod_expression != NULL ) {
+ delete m_filter_mod_expression;
+ }
+ m_filter_mod_expression = new wxRegEx( m_filter_mod_edit->GetValue(), wxRE_ICASE );
+ if ( m_filter_description_expression != NULL ) {
+ delete m_filter_description_expression;
+ }
+ m_filter_description_expression = new wxRegEx( m_filter_description_edit->GetValue(), wxRE_ICASE );
+ if ( m_filter_host_expression != NULL ) {
+ delete m_filter_host_expression;
+ }
+ m_filter_host_expression = new wxRegEx( m_filter_host_edit->GetValue(), wxRE_ICASE );
+ wxCommandEvent dummy;
+ OnChange( dummy );
+}
+
+BattleListFilter::ButtonMode BattleListFilter::_GetButtonMode( const wxString sign )
+{
+ if ( sign == _T( "<" ) )
+ return BattleListFilter::BUTTON_MODE_SMALLER;
+ if ( sign == _T( ">" ) )
+ return BattleListFilter::BUTTON_MODE_BIGGER;
+ return BattleListFilter::BUTTON_MODE_EQUAL;
+}
+
+wxString BattleListFilter::_GetButtonSign( const BattleListFilter::ButtonMode value )
+{
+ switch ( value ) {
+ case BUTTON_MODE_EQUAL :
+ return _T( "=" );
+ case BUTTON_MODE_SMALLER :
+ return _T( "<" );
+ case BUTTON_MODE_BIGGER :
+ default :
+ return _T( ">" );
+ }
+}
+
+
+BattleListFilter::ButtonMode BattleListFilter::_GetNextMode( const BattleListFilter::ButtonMode value )
+{
+ switch ( value ) {
+ case BUTTON_MODE_EQUAL :
+ return BUTTON_MODE_SMALLER;
+ case BUTTON_MODE_SMALLER :
+ return BUTTON_MODE_BIGGER;
+ case BUTTON_MODE_BIGGER :
+ default :
+ return BUTTON_MODE_EQUAL;
+ }
+}
+
+bool BattleListFilter::_IntCompare( const int a, const int b, const BattleListFilter::ButtonMode mode )
+{
+ switch ( mode ) {
+ case BUTTON_MODE_EQUAL :
+ return ( a == b );
+ case BUTTON_MODE_SMALLER :
+ return ( a < b );
+ case BUTTON_MODE_BIGGER :
+ return ( a > b );
+ default :
+ return false;
+ }
+}
+
+void BattleListFilter::OnRankButton ( wxCommandEvent& event )
+{
+ m_filter_rank_mode = _GetNextMode( m_filter_rank_mode );
+ m_filter_rank_button->SetLabel( _GetButtonSign( m_filter_rank_mode ) );
+ OnChange( event );
+}
+
+void BattleListFilter::OnPlayerButton ( wxCommandEvent& event )
+{
+ m_filter_player_mode = _GetNextMode( m_filter_player_mode );
+ m_filter_player_button->SetLabel( _GetButtonSign( m_filter_player_mode ) );
+ OnChange( event );
+}
+
+
+void BattleListFilter::OnMaxPlayerButton( wxCommandEvent& event )
+{
+ m_filter_maxplayer_mode = _GetNextMode( m_filter_maxplayer_mode );
+ m_filter_maxplayer_button->SetLabel( _GetButtonSign( m_filter_maxplayer_mode ) );
+ OnChange( event );
+}
+
+
+void BattleListFilter::OnSpectatorButton( wxCommandEvent& event )
+{
+ m_filter_spectator_mode = _GetNextMode( m_filter_spectator_mode );
+ m_filter_spectator_button->SetLabel( _GetButtonSign( m_filter_spectator_mode ) );
+ OnChange( event );
+}
+
+void BattleListFilter::SetActiv( bool state )
+{
+ m_activ = state;
+ if ( m_parent_battlelisttab != 0 ) {
+ m_parent_battlelisttab->UpdateList();
+ }
+}
+
+bool BattleListFilter::FilterBattle( IBattle& battle )
+{
+ if ( !m_activ )
+ return true;
+
+ if ( m_filter_highlighted->IsChecked() )
+ {
+ try
+ {
+ wxString host = battle.GetFounder().GetNick();
+ if ( !useractions().DoActionOnUser( UserActions::ActHighlight, host ) )
+ return false;
+
+ for ( unsigned int i = 0; i < battle.GetNumUsers(); ++i ) {
+ wxString name = battle.GetUser( i ).GetNick();
+ if ( !useractions().DoActionOnUser( UserActions::ActHighlight, name ) )
+ return false;
+ }
+ }catch(...){}
+ }
+
+ //Battle Status Check
+ if ( !m_filter_status_start->GetValue() && battle.GetInGame() )
+ return false;
+ if ( !m_filter_status_locked->GetValue() && battle.IsLocked() )
+ return false;
+ if ( !m_filter_status_pass->GetValue() && battle.IsPassworded() )
+ return false;
+ if ( !m_filter_status_full->GetValue() && battle.IsFull() )
+ return false;
+ if ( !m_filter_status_open->GetValue() && !battle.IsPassworded() && !battle.IsLocked() && !battle.GetInGame() && !battle.IsFull() )
+ return false;
+
+ //Rank Check
+
+ /** @fixme Is `nonsenserank' useful, or can it be removed? Why is
+ * it here in the first place?
+ */
+ /* `Nonsense', in this context, apparently means that the battle
+ * requires rank 100, exactly, AND we're filtering for values less
+ * than some number.
+ */
+ bool nonsenserank = ( m_filter_rank_mode == BUTTON_MODE_SMALLER ) && ( battle.GetRankNeeded() == 100 ) ;
+
+ if ( m_filter_rank_choice_value != -1 /* don't have "all" selected */
+ && !nonsenserank /* Nonsensical `nonsenserank' flag isn't set. */
+ && !_IntCompare( battle.GetRankNeeded(),
+ m_filter_rank_choice_value,
+ m_filter_rank_mode ) )
+ return false;
+
+ //Player Check
+ if ( ( m_filter_player_choice_value != -1 ) && !_IntCompare( battle.GetNumUsers() - battle.GetSpectators() , m_filter_player_choice_value , m_filter_player_mode ) )
+ return false;
+
+ //MaxPlayer Check
+ if ( ( m_filter_maxplayer_choice_value != -1 ) && !_IntCompare( battle.GetMaxPlayers() , m_filter_maxplayer_choice_value , m_filter_maxplayer_mode ) )
+ return false;
+
+ //Spectator Check
+ if ( ( m_filter_spectator_choice_value != -1 ) && !_IntCompare( battle.GetSpectators() , m_filter_spectator_choice_value , m_filter_spectator_mode ) )
+ return false;
+
+ //Only Maps i have Check
+ if ( m_filter_map_show->GetValue() && !battle.MapExists() )
+ return false;
+
+ //Only Mods i have Check
+ if ( m_filter_mod_show->GetValue() && !battle.ModExists() )
+ return false;
+
+ //Strings Plain Text & RegEx Check (Case insensitiv)
+
+ //Description:
+ if ( !battle.GetDescription().Upper().Contains( m_filter_description_edit->GetValue().Upper() ) && !m_filter_description_expression->Matches( battle.GetDescription() ) )
+ return false;
+
+ //Host:
+ try
+ {
+ if ( !battle.GetFounder().GetNick().Upper().Contains( m_filter_host_edit->GetValue().Upper() ) && !m_filter_host_expression->Matches( battle.GetFounder().GetNick() ) )
+ return false;
+ }catch(...){}
+ //Map:
+ if ( !RefineMapname( battle.GetHostMapName() ).Upper().Contains( m_filter_map_edit->GetValue().Upper() ) && !m_filter_map_expression->Matches( RefineMapname( battle.GetHostMapName() ) ) )
+ return false;
+
+ //Mod:
+ if ( !battle.GetHostModName().Upper().Contains( m_filter_mod_edit->GetValue().Upper() ) && !RefineModname( battle.GetHostModName() ).Upper().Contains( m_filter_mod_edit->GetValue().Upper() ) && !m_filter_mod_expression->Matches( RefineModname( battle.GetHostModName() ) ) )
+ return false;
+
+ return true;
+}
+
+void BattleListFilter::OnChange ( wxCommandEvent& /*unused*/ )
+{
+ if ( !m_activ )
+ return;
+ m_parent_battlelisttab->UpdateList();
+}
+
+void BattleListFilter::OnChangeMap ( wxCommandEvent& event )
+{
+ if ( m_filter_map_edit == NULL )
+ return;
+ if ( m_filter_map_expression != NULL ) {
+ delete m_filter_map_expression;
+ }
+ m_filter_map_expression = new wxRegEx( m_filter_map_edit->GetValue(), wxRE_ICASE );
+ OnChange( event );
+}
+
+void BattleListFilter::OnChangeMod ( wxCommandEvent& event )
+{
+ if ( m_filter_mod_edit == NULL )
+ return;
+ if ( m_filter_mod_expression != NULL ) {
+ delete m_filter_mod_expression;
+ }
+ m_filter_mod_expression = new wxRegEx( m_filter_mod_edit->GetValue(), wxRE_ICASE );
+ OnChange( event );
+}
+
+void BattleListFilter::OnChangeDescription ( wxCommandEvent& event )
+{
+ if ( m_filter_description_edit == NULL )
+ return;
+ if ( m_filter_description_expression != NULL ) {
+ delete m_filter_description_expression;
+ }
+ m_filter_description_expression = new wxRegEx( m_filter_description_edit->GetValue(), wxRE_ICASE );
+ OnChange( event );
+}
+
+void BattleListFilter::OnChangeHost ( wxCommandEvent& event )
+{
+ if ( m_filter_host_edit == NULL )
+ return;
+ if ( m_filter_host_expression != NULL ) {
+ delete m_filter_host_expression;
+ }
+ m_filter_host_expression = new wxRegEx( m_filter_host_edit->GetValue(), wxRE_ICASE );
+ OnChange( event );
+}
+
+
+void BattleListFilter::OnRankChange( wxCommandEvent& event )
+{
+ m_filter_rank_choice_value = m_filter_rank_choice->GetSelection() - 1;
+ OnChange( event );
+}
+
+
+void BattleListFilter::OnPlayerChange( wxCommandEvent& event )
+{
+ m_filter_player_choice_value = m_filter_player_choice->GetSelection() - 1;
+ OnChange( event );
+}
+
+
+void BattleListFilter::OnMaxPlayerChange( wxCommandEvent& event )
+{
+ m_filter_maxplayer_choice_value = m_filter_maxplayer_choice->GetSelection() - 1;
+ OnChange( event );
+}
+
+
+void BattleListFilter::OnSpectatorChange( wxCommandEvent& event )
+{
+ m_filter_spectator_choice_value = m_filter_spectator_choice->GetSelection() - 1;
+ OnChange( event );
+}
+
+
+bool BattleListFilter::GetActiv() const
+{
+ return m_activ;
+}
+
+void BattleListFilter::SaveFilterValues()
+{
+ BattleListFilterValues filtervalues;
+ filtervalues.description = m_filter_description_edit->GetValue() ;
+ filtervalues.host = m_filter_host_edit->GetValue();
+ filtervalues.map = m_filter_map_edit->GetValue();
+ filtervalues.map_show = m_filter_map_show->GetValue();
+ filtervalues.map = m_filter_map_edit->GetValue();
+ filtervalues.maxplayer = wxString::Format( _( "%d" ), m_filter_maxplayer_choice->GetSelection() );
+ filtervalues.maxplayer_mode = _GetButtonSign( m_filter_maxplayer_mode );
+ filtervalues.mod = m_filter_mod_edit->GetValue();
+ filtervalues.mod_show = m_filter_mod_show->GetValue();
+ filtervalues.player_mode = _GetButtonSign( m_filter_player_mode );
+ filtervalues.player_num = wxString::Format( _( "%d" ), m_filter_player_choice->GetSelection() );
+ filtervalues.rank = wxString::Format( _( "%d" ), m_filter_rank_choice->GetSelection() );
+ filtervalues.rank_mode = _GetButtonSign( m_filter_rank_mode );
+ filtervalues.spectator = wxString::Format( _( "%d" ), m_filter_spectator_choice->GetSelection() );
+ filtervalues.spectator_mode = _GetButtonSign( m_filter_spectator_mode );
+ filtervalues.status_full = m_filter_status_full->IsChecked();
+ filtervalues.status_locked = m_filter_status_locked->IsChecked();
+ filtervalues.status_open = m_filter_status_open->IsChecked();
+ filtervalues.status_passworded = m_filter_status_pass->IsChecked();
+ filtervalues.status_start = m_filter_status_start->IsChecked();
+ filtervalues.highlighted_only = m_filter_highlighted->IsChecked();
+ sett().SetBattleFilterValues( filtervalues );
+}
diff --git a/src/battlelistfilter.h b/src/battlelistfilter.h
new file mode 100644
index 0000000..11549db
--- /dev/null
+++ b/src/battlelistfilter.h
@@ -0,0 +1,185 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLELISTFILTER_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLELISTFILTER_H
+
+#include <wx/panel.h>
+
+#include "battlelisttab.h"
+#include "battle.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+class BattleListTab;
+class wxToggleButton;
+class wxCheckBox;
+class wxStaticText;
+class wxTextCtrl;
+class wxChoice;
+class wxButton;
+class wxRegEx;
+class wxStaticText;
+
+
+/** \brief The panel contained in BattleListTab used to filter for diff info of battles
+ * \todo DOCMEMORE */
+class BattleListFilter : public wxPanel
+{
+ public:
+ BattleListFilter( wxWindow* parent, wxWindowID id, BattleListTab* parentBattleListTab, const wxPoint& pos, const wxSize& size, long style );
+
+ void OnRankButton ( wxCommandEvent& event );
+ void OnPlayerButton ( wxCommandEvent& event );
+ void OnMaxPlayerButton( wxCommandEvent& event );
+ void OnSpectatorButton( wxCommandEvent& event );
+ void OnActivate ( wxCommandEvent& event );
+
+ void SetActiv ( bool state );
+
+ void OnChange ( wxCommandEvent& event );
+ void OnChangeMap ( wxCommandEvent& event );
+ void OnChangeMod ( wxCommandEvent& event );
+ void OnChangeDescription ( wxCommandEvent& event );
+ void OnChangeHost ( wxCommandEvent& event );
+
+ void OnRankChange ( wxCommandEvent& event );
+ void OnPlayerChange ( wxCommandEvent& event );
+ void OnMaxPlayerChange ( wxCommandEvent& event );
+ void OnSpectatorChange ( wxCommandEvent& event );
+
+ bool FilterBattle(IBattle& battle);
+ bool GetActiv() const;
+
+ void SetFilterHighlighted( bool state );
+
+ void SaveFilterValues();
+
+ enum ButtonMode {
+ BUTTON_MODE_EQUAL,
+ BUTTON_MODE_BIGGER,
+ BUTTON_MODE_SMALLER
+ };
+ protected:
+
+ wxString _GetButtonSign(ButtonMode value);
+ ButtonMode _GetNextMode(ButtonMode value);
+ ButtonMode _GetButtonMode(wxString sign);
+ bool _IntCompare(int a,int b,ButtonMode mode);
+
+ bool m_activ;
+
+ BattleListTab* m_parent_battlelisttab;
+#if wxUSE_TOGGLEBTN
+ wxToggleButton* m_filter_show;
+#else
+ wxCheckBox* m_filter_show;
+#endif
+ wxStaticText* m_filter_text;
+
+ wxCheckBox* m_filter_activ;
+
+ //Host
+ wxStaticText* m_filter_host_text;
+ wxTextCtrl* m_filter_host_edit;
+ wxRegEx* m_filter_host_expression;
+
+ //Status
+ wxStaticText* m_filter_status_text;
+ wxStaticText* m_filter_status_text1;
+ wxCheckBox* m_filter_status_locked;
+ wxCheckBox* m_filter_status_pass;
+ wxCheckBox* m_filter_status_start;
+ wxCheckBox* m_filter_status_full;
+ wxCheckBox* m_filter_status_open;
+
+ //Rank
+ wxStaticText* m_filter_rank_text;
+ ButtonMode m_filter_rank_mode;
+ wxButton* m_filter_rank_button;
+ wxChoice* m_filter_rank_choice;
+ int m_filter_rank_choice_value;
+
+ //Description
+ wxStaticText* m_filter_description_text;
+ wxTextCtrl* m_filter_description_edit;
+ wxRegEx* m_filter_description_expression;
+
+ //Player
+ wxStaticText* m_filter_player_text;
+ wxButton* m_filter_player_button;
+ ButtonMode m_filter_player_mode;
+ wxChoice* m_filter_player_choice;
+ int m_filter_player_choice_value;
+
+ //Map
+ wxStaticText* m_filter_map_text;
+ wxTextCtrl* m_filter_map_edit;
+ wxCheckBox* m_filter_map_show;
+ wxRegEx* m_filter_map_expression;
+
+ //Max Player
+ wxStaticText* m_filter_maxplayer_text;
+ wxButton* m_filter_maxplayer_button;
+ ButtonMode m_filter_maxplayer_mode;
+ wxChoice* m_filter_maxplayer_choice;
+ int m_filter_maxplayer_choice_value;
+
+ //Mod
+ wxStaticText* m_filter_mod_text;
+ wxTextCtrl* m_filter_mod_edit;
+ wxCheckBox* m_filter_mod_show;
+ wxRegEx* m_filter_mod_expression;
+
+ //Spectator
+ wxStaticText* m_filter_spectator_text;
+ wxButton* m_filter_spectator_button;
+ ButtonMode m_filter_spectator_mode;
+ wxChoice* m_filter_spectator_choice;
+ int m_filter_spectator_choice_value;
+
+ wxCheckBox* m_filter_highlighted;
+
+ DECLARE_EVENT_TABLE();
+};
+
+enum
+{
+ BATTLE_FILTER_HOST_EDIT,
+ BATTLE_FILTER_DESCRIPTION_EDIT,
+ BATTLE_FILTER_MAP_EDIT,
+ BATTLE_FILTER_MOD_EDIT,
+ BATTLE_FILTER_LOCKED,
+ BATTLE_FILTER_OPEN,
+ BATTLE_FILTER_PASSWORDED,
+ BATTLE_FILTER_FULL,
+ BATTLE_FILTER_STARTED,
+ BATTLE_FILTER_RANK_CHOICE,
+ BATTLE_FILTER_RANK_BUTTON,
+ BATTLE_FILTER_PLAYER_CHOICE,
+ BATTLE_FILTER_MAXPLAYER_CHOICE,
+ BATTLE_FILTER_SPECTATOR_CHOICE,
+ BATTLE_FILTER_MAP_SHOW,
+ BATTLE_FILTER_MOD_SHOW,
+ BATTLE_FILTER_PLAYER_BUTTON,
+ BATTLE_FILTER_MAXPLAYER_BUTTON,
+ BATTLE_FILTER_SPECTATOR_BUTTON,
+ BATTLE_FILTER_HIGHLIGHTED
+};
+
+#endif //SPRINGLOBBY_HEADERGUARD_BATTLELISTFILTER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battlelistfiltervalues.h b/src/battlelistfiltervalues.h
new file mode 100644
index 0000000..d5a2658
--- /dev/null
+++ b/src/battlelistfiltervalues.h
@@ -0,0 +1,47 @@
+#include <wx/string.h>
+
+struct BattleListFilterValues
+{
+ // checkboxes
+ bool status_locked;
+ bool status_passworded;
+ bool status_start;
+ bool status_full;
+ bool status_open;
+ bool map_show;
+ bool mod_show;
+ bool highlighted_only;
+ //text fields
+ wxString host;
+ wxString description;
+ wxString map;
+ wxString mod;
+ //choices
+ wxString rank;
+ wxString player_num;
+ wxString maxplayer;
+ wxString spectator;
+ //modifiers
+ wxString rank_mode;
+ wxString player_mode;
+ wxString maxplayer_mode;
+ wxString spectator_mode;
+};
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battlelisttab.cpp b/src/battlelisttab.cpp
new file mode 100644
index 0000000..42aad07
--- /dev/null
+++ b/src/battlelisttab.cpp
@@ -0,0 +1,639 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include <wx/intl.h>
+#include <wx/stattext.h>
+#include <wx/statline.h>
+#include <wx/textdlg.h>
+#include <wx/combobox.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/checkbox.h>
+#include <wx/log.h>
+#include <stdexcept>
+#if wxUSE_TOGGLEBTN
+#include <wx/tglbtn.h>
+#endif
+
+
+#include "aui/auimanager.h"
+#include "battlelisttab.h"
+#include "battlelistctrl.h"
+#include "battle.h"
+#include "ui.h"
+#include "chatpanel.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "uiutils.h"
+#include "hostbattledialog.h"
+#include "server.h"
+#include "settings.h"
+#include "iunitsync.h"
+#include "mapctrl.h"
+#include "nicklistctrl.h"
+#include "mainwindow.h"
+#include "mainjoinbattletab.h"
+#include "battlelistfilter.h"
+#include "iconimagelist.h"
+#include "useractions.h"
+#include "settings++/custom_dialogs.h"
+
+const unsigned int BATTLELIST_COLUMNCOUNT = 10;
+
+BEGIN_EVENT_TABLE( BattleListTab, wxPanel )
+
+ EVT_BUTTON ( BattleListTab::BATTLE_JOIN , BattleListTab::OnJoin )
+ EVT_BUTTON ( BattleListTab::BATTLE_HOST , BattleListTab::OnHost )
+ EVT_LIST_ITEM_ACTIVATED ( BattleListTab::BATTLE_JOIN , BattleListTab::OnListJoin )
+ EVT_LIST_ITEM_SELECTED ( BattleListCtrl::BLIST_LIST , BattleListTab::OnSelect )
+ EVT_CHECKBOX ( BattleListTab::BATTLE_LIST_FILTER_ACTIV, BattleListTab::OnFilterActiv )
+ #if wxUSE_TOGGLEBTN
+ EVT_TOGGLEBUTTON ( BattleListTab::BATTLE_LIST_FILTER_BUTTON, BattleListTab::OnFilter )
+ EVT_TOGGLEBUTTON ( BattleListTab::BATTLE_LIST_INFO_BUTTON, BattleListTab::OnInfoShow )
+ #else
+ EVT_CHECKBOX ( BattleListTab::BATTLE_LIST_FILTER_BUTTON, BattleListTab::OnFilter )
+ EVT_CHECKBOX ( BattleListTab::BATTLE_LIST_INFO_BUTTON, BattleListTab::OnOnInfoShow )
+ #endif
+ EVT_SIZE( BattleListTab::OnResize )
+
+
+END_EVENT_TABLE()
+
+
+BattleListTab::BattleListTab( wxWindow* parent, Ui& ui )
+ : wxScrolledWindow( parent, -1 ),
+ m_ui( ui ),
+ m_sel_battle( 0 )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "battlelisttab" ) );
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* m_filter_sizer;
+ m_filter_sizer = new wxBoxSizer( wxVERTICAL );
+
+
+ m_battlelist_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_battle_list = new BattleListCtrl( this, m_ui );
+ m_battle_list->SetHighLightAction ( UserActions::ActHighlight );
+ m_battlelist_sizer->Add( m_battle_list, 1, wxALL | wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_battlelist_sizer, 1, wxEXPAND, 5 );;
+
+ m_info_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_minimap = new MapCtrl( this, 100, 0, m_ui, true, true, false, false );
+ m_info_sizer->Add( m_minimap, 0, wxALL, 5 );
+
+ m_data_sizer = new wxFlexGridSizer( 4, 2, 0, 0 );
+
+ m_map_lbl = new wxStaticText( this, wxID_ANY, _( "Map:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_map_lbl, 0, wxALL, 5 );
+
+ m_map_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_map_text, 0, wxALL, 5 );
+
+ m_mod_lbl = new wxStaticText( this, wxID_ANY, _( "Mod:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_mod_lbl, 0, wxALL, 5 );
+
+ m_mod_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_mod_text, 0, wxALL, 5 );
+
+ m_players_lbl = new wxStaticText( this, wxID_ANY, _( "Players:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_players_lbl, 0, wxALL, 5 );
+
+ m_players_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_players_text, 0, wxALL, 5 );
+
+ m_spec_lbl = new wxStaticText( this, wxID_ANY, _( "Spectators:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_spec_lbl, 0, wxALL, 5 );
+
+ m_spec_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_spec_text, 0, wxALL, 5 );
+
+ m_info_sizer->Add( m_data_sizer, 1, wxEXPAND, 5 );
+
+ m_players = new NickListCtrl( this, false );
+ m_info_sizer->Add( m_players, 1, wxALL | wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_info_sizer, 0, wxEXPAND, 5 );
+
+
+ m_filter = new BattleListFilter( this , wxID_ANY, this , wxDefaultPosition, wxSize( -1, -1 ), wxEXPAND );
+ m_filter_sizer->Add( m_filter, 0, wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_filter_sizer, 0, wxEXPAND, 5 );
+
+ m_buttons_sep = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ m_main_sizer->Add( m_buttons_sep, 0, wxALL | wxEXPAND, 5 );
+
+ wxBoxSizer* m_buttons_sizer;
+ m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_buttons_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+#if wxUSE_TOGGLEBTN
+ m_filter_show = new wxToggleButton( this, BATTLE_LIST_FILTER_BUTTON , _( " Filter " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
+#else
+ m_filter_show = new wxCheckBox( this, BATTLE_LIST_FILTER_BUTTON , _( " Filter " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
+#endif
+ m_buttons_sizer->Add( m_filter_show, 0, 0, 5 );
+
+ m_filter_activ = new wxCheckBox( this, BATTLE_LIST_FILTER_ACTIV , _( "Activated" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_buttons_sizer->Add( m_filter_activ, 0, wxALL, 5 );
+
+#if wxUSE_TOGGLEBTN
+ m_info_show = new wxToggleButton( this, BATTLE_LIST_INFO_BUTTON , _( " Battle infos " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
+#else
+ m_info_show = new wxCheckBox( this, BATTLE_LIST_INFO_BUTTON, _( " Battle infos " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
+#endif
+ m_buttons_sizer->Add( m_info_show , 0, 0, 5 );
+
+ m_battle_num = new wxStaticText( this, wxID_ANY, _( "0 battles displayed" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_buttons_sizer->Add( m_battle_num, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, 4 );
+ m_buttons_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+ m_host_btn = new wxButton( this, BATTLE_HOST, _( "Host new..." ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
+ m_buttons_sizer->Add( m_host_btn, 0, wxBOTTOM | wxLEFT | wxRIGHT, 5 );
+
+ m_join_btn = new wxButton( this, BATTLE_JOIN, _( "Join" ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
+ m_buttons_sizer->Add( m_join_btn, 0, wxBOTTOM | wxRIGHT, 5 );
+
+ m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND, 5 );
+
+ m_filter->Hide();
+
+ this->SetSizer( m_main_sizer );
+ this->Layout();
+
+ SelectBattle( 0 );
+}
+
+
+BattleListTab::~BattleListTab()
+{
+ if ( m_filter != 0 )
+ m_filter->SaveFilterValues();
+}
+
+void BattleListTab::SetNumDisplayed()
+{
+ int num = m_battle_list->GetItemCount();
+ m_battle_num->SetLabel( wxString::Format( _( "%d battles displayed" ), num ) );
+}
+
+void BattleListTab::SelectBattle( IBattle* battle )
+{
+ m_sel_battle = battle;
+ m_minimap->SetBattle( m_sel_battle );
+ m_players->ClearUsers();
+ if ( m_sel_battle != 0 )
+ {
+ m_map_text->SetLabel( RefineMapname( m_sel_battle->GetHostMapName() ) );
+ m_mod_text->SetLabel( m_sel_battle->GetHostModName() );
+ m_players_text->SetLabel( wxString::Format( _T( "%d / %d" ), int( m_sel_battle->GetNumUsers() ) - int( m_sel_battle->GetSpectators() ), int( m_sel_battle->GetMaxPlayers() ) ) );
+ m_spec_text->SetLabel( wxString::Format( _T( "%d" ), m_sel_battle->GetSpectators() ) );
+ for ( unsigned int i = 0; i < m_sel_battle->GetNumUsers(); i++ )
+ {
+ User& usr = m_sel_battle->GetUser( i );
+ if ( usr.BattleStatus().IsBot() ) continue;
+ m_players->AddUser( usr );
+ }
+ } else
+ {
+ m_map_text->SetLabel( wxEmptyString );
+ m_mod_text->SetLabel( wxEmptyString );
+ m_players_text->SetLabel( _T( "0 / 0" ) );
+ m_spec_text->SetLabel( _T( "0" ) );
+ }
+}
+
+void BattleListTab::AddBattle( IBattle& battle ) {
+ if ( battle.GetGUIListActiv() || ( m_filter->GetActiv() && !m_filter->FilterBattle( battle ) ) ) {
+ return;
+ }
+
+ m_battle_list->AddBattle( battle );
+ battle.SetGUIListActiv( true );
+ m_battle_list->MarkDirtySort();
+ SetNumDisplayed();
+}
+
+
+void BattleListTab::RemoveBattle( IBattle& battle )
+{
+
+ if ( &battle == m_sel_battle ) {
+ m_battle_list->ResetSelection();
+ SelectBattle( 0 );
+ }
+
+ m_battle_list->RemoveBattle( battle );
+
+ battle.SetGUIListActiv( false );
+ SetNumDisplayed();
+}
+
+
+void BattleListTab::UserUpdate( User& user )
+{
+ if ( m_sel_battle && user.GetBattle() == m_sel_battle ) {
+ m_players->UserUpdated( user );
+ }
+}
+
+
+void BattleListTab::UpdateBattle( IBattle& battle )
+{
+ if ( !battle.GetGUIListActiv() ) {
+ AddBattle( battle );
+ return;
+ }
+
+ if ( m_filter->GetActiv() && !m_filter->FilterBattle( battle ) ) {
+ RemoveBattle( battle );
+ return;
+ }
+
+ m_battle_list->UpdateBattle( battle );
+
+ if ( &battle == m_sel_battle )
+ SelectBattle( m_sel_battle );
+
+}
+
+
+void BattleListTab::RemoveAllBattles()
+{
+ SelectBattle( 0 );
+ m_ui.GetServer().battles_iter->IteratorBegin();
+ while ( ! m_ui.GetServer().battles_iter->EOL() )
+ {
+ Battle* temp_battle = m_ui.GetServer().battles_iter->GetBattle();
+ if ( temp_battle != 0 )
+ temp_battle->SetGUIListActiv( false );
+ }
+ m_battle_list->Clear();
+ SetNumDisplayed();
+}
+
+
+void BattleListTab::UpdateList() {
+ m_ui.GetServer().battles_iter->IteratorBegin();
+ while ( ! m_ui.GetServer().battles_iter->EOL() ) {
+ Battle* b = m_ui.GetServer().battles_iter->GetBattle();
+ if ( b != 0 )
+ UpdateBattle( *b );
+ }
+ m_battle_list->RefreshVisibleItems();
+}
+
+
+void BattleListTab::SetFilterActiv( bool activ )
+{
+ m_filter->SetActiv( activ );
+ m_filter_activ->SetValue( activ );
+ sett().SetBattleFilterActivState( activ );
+ m_battle_list->MarkDirtySort();
+}
+
+
+void BattleListTab::OnHost( wxCommandEvent& /*unused*/ )
+{
+ if ( !m_ui.IsConnected() )
+ {
+ wxLogWarning( _T( "Trying to host while offline" ) );
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "You cannot host a game while being offline. Please connect to a lobby server." ), _( "Not Online." ), wxOK );
+ m_ui.ShowConnectWindow();
+ return;
+ }
+ if ( !m_ui.IsSpringCompatible() )
+ {
+ wxLogWarning( _T( "Hosting is disabled due to the incompatible version " ) );
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "Hosting is disabled due to the incompatible version you're using" ), _( "Spring error" ), wxICON_EXCLAMATION | wxOK );
+ return;
+ }
+ if ( m_ui.IsSpringRunning() )
+ {
+ wxLogWarning( _T( "trying to host while spring is running" ) );
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "You already are running a Spring instance, close it first in order to be able to host a new game" ), _( "Spring error" ), wxICON_EXCLAMATION | wxOK );
+ return;
+ }
+ Battle* battle = m_ui.mw().GetJoinTab().GetCurrentBattle();
+ if ( battle != 0 )
+ {
+ if ( m_ui.Ask( _( "Already in a battle" ), _( "You are already in a battle.\n\nDo you want to leave current battle to start a new?" ) ) ) {
+ battle->Leave();
+ m_ui.mw().GetJoinTab().LeaveCurrentBattle();
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ HostBattleDialog dlg( this );
+ if ( dlg.ShowModal() == wxID_OK )
+ {
+ BattleOptions bo;
+ bo.description = sett().GetLastHostDescription();
+ bo.port = sett().GetLastHostPort();
+ bo.nattype = NatType( sett().GetLastHostNATSetting() );
+
+ if ( bo.nattype == NAT_None && sett().GetTestHostPort() )
+ {
+ switch ( m_ui.TestHostPort( bo.port ) )
+ {
+ case Server::porttest_pass :
+ break; // success
+ case Server::porttest_pass_WX26 :
+ wxLogWarning( _T( "hosting port %d: test aborted (wx26)" ), bo.port );
+ customMessageBoxNoModal( SL_MAIN_ICON, wxString::Format( _( "Your using wxWidgets prior to version 2.8,\n "
+ "port testing is not supported.\n Hosting may or may not work." ), bo.port ) );
+ sett().SetTestHostPort( false ); // no need to have it checked anymore
+ break;
+
+ case Server::porttest_unreachable :
+ wxLogWarning( _T( "hosting port %d: test undetermined" ), bo.port );
+ customMessageBoxNoModal( SL_MAIN_ICON, wxString::Format( _( "The server used for testing your port %d "
+ "is unreachable. \nHosting may or may not work with this setting." ), bo.port ) );
+ break; //inconclusive test shouldn't hinder hosting imo (koshi)
+
+ case Server::porttest_timeout :
+ case Server::porttest_socketNotOk :
+ case Server::porttest_socketError :
+ wxLogWarning( _T( "hosting port %d: test unsuccessful, closing battle" ), bo.port );
+ customMessageBoxNoModal( SL_MAIN_ICON, wxString::Format( _( "Battle not started because the port you selected (%d) "
+ "is unable to recieve incoming packets\n checks your router & firewall configuration again or change port "
+ "in the dialog.\n\nIf everything else fails, enable the Hole Punching NAT Traversal\n "
+ "option in the hosting settings." ), bo.port ) );
+ return;
+ default:
+ wxLogWarning( _T( "unknonw port forward test result" ) );
+ break;
+
+ }
+ if ( !m_ui.TestHostPort( bo.port ) )
+ {
+ wxLogWarning( _T( "hosting port %d: test unsuccessful, closing battle" ), bo.port );
+ customMessageBoxNoModal( SL_MAIN_ICON, wxString::Format( _( "Battle not started because the port you selected (%d) is unable to recieve incoming packets\n checks your router & firewall configuration again or change port in the dialog.\n\nIf everything else fails, enable the Hole Punching NAT Traversal\n option in the hosting settings." ), bo.port ) );
+ return;
+ }
+ }
+
+ // Get selected mod from unitsync.
+ UnitSyncMod mod;
+ try
+ {
+ mod = usync().GetMod( sett().GetLastHostMod() );
+ bo.modhash = mod.hash;
+ bo.modname = mod.name;
+ }
+ catch ( ... )
+ {
+ wxLogWarning( _T( "can't host: mod not found" ) );
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "Battle not started beacuse the mod you selected could not be found. " ), _( "Error starting battle." ), wxOK );
+ return;
+ }
+
+ UnitSyncMap map;
+ wxString mname = sett().GetLastHostMap();
+ try {
+ if ( usync().MapExists( mname ) )
+ map = usync().GetMap( mname );
+ else if ( usync().GetNumMaps() <= 0 )
+ {
+ wxLogWarning( _T( "no maps found" ) );
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "Couldn't find any maps in your spring installation. This could happen when you set the Spring settings incorrectly." ), _( "No maps found" ), wxOK );
+ return;
+ }
+ else
+ {
+ map = usync().GetMap( 0 );
+ }
+ }
+ catch ( ... )
+ {
+ wxLogWarning( _T( "no maps found" ) );
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "Couldn't find any maps in your spring installation. This could happen when you set the Spring settings incorrectly." ), _( "No maps found" ), wxOK );
+ return;
+ }
+ bo.maphash = map.hash;
+ bo.mapname = map.name;
+
+ bo.rankneeded = sett().GetLastRankLimit();
+
+ bo.maxplayers = sett().GetLastHostPlayerNum();
+
+ bo.isproxy = sett().GetLastHostRelayedMode();
+ if ( bo.isproxy ) bo.nattype = NAT_None;
+ bo.relayhost = sett().GetLastRelayedHost();
+ m_ui.GetServer().HostBattle( bo, sett().GetLastHostPassword() );
+ }
+}
+
+
+void BattleListTab::OnFilter( wxCommandEvent& /*unused*/ )
+{
+ if ( m_filter_show->GetValue() )
+ {
+ m_filter->Show( );
+ this->Layout();
+ }
+ else
+ {
+ m_filter->Hide( );
+ this->Layout();
+ }
+}
+
+
+void BattleListTab::OnFilterActiv( wxCommandEvent& /*unused*/ )
+{
+ bool active = m_filter_activ->GetValue();
+ if ( !m_ui.IsConnected() )
+ {
+ m_filter_activ->SetValue( !active );
+ return;
+ }
+ m_filter->SetActiv( active );
+ sett().SetBattleFilterActivState( active );
+ SetNumDisplayed();
+}
+
+
+void BattleListTab::OnJoin( wxCommandEvent& /*unused*/ )
+{
+ try
+ {
+ ASSERT_LOGIC( m_battle_list != 0, _T( "m_battle_list = 0" ) );
+ } catch ( ... ) {
+ return;
+ }
+
+ if ( m_battle_list->GetSelectedIndex() < 0 ) return;
+
+ int id = m_battle_list->GetSelectedData()->GetBattleId();
+ DoJoin( m_ui.GetServer().battles_iter->GetBattle( id ) );
+}
+
+
+void BattleListTab::OnListJoin( wxListEvent& event )
+{
+ try
+ {
+ ASSERT_LOGIC( m_battle_list != 0, _T( "m_battle_list = 0" ) );
+ } catch ( ... ) {
+ return;
+ }
+ if ( event.GetIndex() < 0 ) return;
+
+ int id = m_battle_list->GetSelectedData()->GetBattleId();
+ DoJoin( m_ui.GetServer().battles_iter->GetBattle( id ) );
+}
+
+
+void BattleListTab::DoJoin( Battle& battle )
+{
+ if ( !m_ui.IsSpringCompatible() )
+ {
+ wxLogWarning( _T( "trying to join battles with imcompatible spring version" ) );
+ customMessageBox( SL_MAIN_ICON, _( "Joining battles is disabled due to the incompatible spring version you're using." ), _( "Spring error" ), wxICON_EXCLAMATION | wxOK );
+ return;
+ }
+
+ Battle* curbattle = m_ui.mw().GetJoinTab().GetCurrentBattle();
+
+ if ( curbattle != 0 && curbattle->GetID() == battle.GetID() )
+ {
+ if ( m_ui.Ask( _( "Already in this battle" ), _( "You are already in this battle.\n\nDo you want to leave it?" ) ) )
+ {
+ curbattle->Leave();
+ m_ui.mw().GetJoinTab().LeaveCurrentBattle();
+ return;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if ( curbattle != 0 )
+ {
+ if ( m_ui.Ask( _( "Already in another battle" ), _( "You are already in a battle.\n\nDo you want to leave your current battle and join this one?" ) ) ) {
+ curbattle->Leave();
+ m_ui.mw().GetJoinTab().LeaveCurrentBattle();
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if ( m_ui.IsSpringRunning() )
+ {
+ wxLogWarning( _T( "trying to join a battle while spring is running" ) );
+ customMessageBox( SL_MAIN_ICON, _( "You already are running a Spring instance, close it first in order to be able to join another battle." ), _( "Spring error" ), wxICON_EXCLAMATION | wxOK );
+ return;
+ }
+
+#ifdef NO_TORRENT_SYSTEM
+ wxString downloadProc = _( "Do you want me to take you to the download page?" );
+#else
+ wxString downloadProc = _( "Should i try to download it for you?\nYou can see the progress in the \"Download Manager\" tab." );
+#endif
+
+ if ( !battle.ModExists() )
+ {
+ if ( customMessageBox( SL_MAIN_ICON, _( "You need to download the mod before you can join this game.\n\n" ) + downloadProc, _( "Mod not available" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
+ wxString modhash = battle.GetHostModHash();
+ wxString modname = battle.GetHostModName();
+ m_ui.DownloadMod ( modhash, modname );
+ }
+ return;
+ }
+
+ if ( !battle.MapExists() )
+ {
+ if ( customMessageBox( SL_MAIN_ICON, _( "You need to download the map to be able to play in this game.\n\n" ) + downloadProc, _( "Map not available" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
+ wxString maphash = battle.GetHostMapHash();
+ wxString mapname = battle.GetHostMapName();
+ m_ui.DownloadMap ( maphash, mapname );
+ }
+ }
+
+ if ( battle.IsPassworded() )
+ {
+ wxPasswordEntryDialog pw( this, _( "Battle password" ), _( "Enter password" ) );
+ pw.SetFocus();
+ if ( pw.ShowModal() == wxID_OK ) battle.Join( pw.GetValue() );
+ }
+ else
+ {
+ battle.Join();
+ }
+}
+
+
+void BattleListTab::OnSelect( wxListEvent& event )
+{
+ wxLogDebugFunc( _T( "" ) );
+ if ( event.GetIndex() == -1 )
+ {
+ SelectBattle( 0 );
+ } else {
+ IBattle* b = ( m_battle_list->GetDataFromIndex( event.GetIndex() ) ) ;
+ SelectBattle( b );//
+ }
+}
+
+
+void BattleListTab::OnUnitSyncReloaded()
+{
+ if ( ! m_ui.GetServerStatus() ) {
+ return;
+ }
+
+ m_ui.GetServer().battles_iter->IteratorBegin();
+ while ( ! m_ui.GetServer().battles_iter->EOL() )
+ {
+ Battle* b = m_ui.GetServer().battles_iter->GetBattle();
+ if ( b != 0 ) b->OnUnitSyncReloaded();
+ }
+ UpdateList();
+ m_minimap->UpdateMinimap();
+}
+
+void BattleListTab::UpdateHighlights()
+{
+ m_battle_list->RefreshVisibleItems();
+}
+
+
+void BattleListTab::SortBattleList()
+{
+ m_battle_list->SortList();
+}
+
+void BattleListTab::ShowExtendedInfos( bool show )
+{
+ const bool recursive = true;
+ m_main_sizer->Show( m_info_sizer, show, recursive );
+ m_main_sizer->Show( m_buttons_sep, show, recursive );
+ m_info_show->SetValue( show );
+ Layout();
+}
+
+void BattleListTab::OnInfoShow( wxCommandEvent& /*unused*/ )
+{
+ ShowExtendedInfos( m_info_show->GetValue() );
+}
+
+void BattleListTab::OnResize( wxSizeEvent& event )
+{
+ SetSize( event.GetSize() );
+ Layout();
+ // window too small, hide additional infos
+ ShowExtendedInfos( ( GetClientSize().GetHeight() > 400 ) );
+}
+
diff --git a/src/battlelisttab.h b/src/battlelisttab.h
new file mode 100644
index 0000000..9a18a67
--- /dev/null
+++ b/src/battlelisttab.h
@@ -0,0 +1,134 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLELISTTAB_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLELISTTAB_H
+
+#include <wx/scrolwin.h>
+
+class User;
+class Ui;
+class IBattle;
+class Battle;
+class BattleListCtrl;
+class BattleListFilter;
+class MapCtrl;
+class NickListCtrl;
+class wxCommandEvent;
+class wxListEvent;
+class wxStaticText;
+class wxComboBox;
+class wxButton;
+class wxBoxSizer;
+class wxStaticText;
+class wxStaticLine;
+class wxCheckBox;
+class wxToggleButton;
+class wxFlexGridSizer;
+/** \brief The panel containing a BattleListCtrl and a BattleListFilter
+ * \todo DOCME */
+class BattleListTab : public wxScrolledWindow
+{
+ friend class BattleListFilter;
+ public:
+ BattleListTab( wxWindow* parent, Ui& ui );
+ ~BattleListTab();
+
+ void AddBattle( IBattle& battle );
+ void RemoveBattle( IBattle& battle );
+ void UpdateBattle( IBattle& battle );
+
+ void UserUpdate( User& user );
+
+ void RemoveAllBattles();
+
+ void UpdateList();
+
+ void SelectBattle( IBattle* battle );
+
+ void OnHost( wxCommandEvent& event );
+ void OnFilter( wxCommandEvent& event );
+ void OnInfoShow( wxCommandEvent& event );
+ void OnFilterActiv( wxCommandEvent& event );
+ void SetFilterActiv(bool activ);
+ void OnJoin( wxCommandEvent& event );
+ void OnListJoin( wxListEvent& event );
+ void OnResize( wxSizeEvent& event );
+ void ShowExtendedInfos( bool show );
+
+ void DoJoin( Battle& battle );
+
+ void OnSelect( wxListEvent& event );
+ void OnUnitSyncReloaded();
+
+ void UpdateHighlights();
+
+ void SortBattleList();
+
+ protected:
+ BattleListFilter* m_filter;
+ BattleListCtrl* m_battle_list;
+ MapCtrl* m_minimap;
+ wxStaticText* m_map_lbl;
+ wxStaticText* m_map_text;
+ wxStaticText* m_mod_lbl;
+ wxStaticText* m_mod_text;
+ wxStaticText* m_players_lbl;
+ wxStaticText* m_players_text;
+ wxStaticText* m_spec_lbl;
+ wxStaticText* m_spec_text;
+ wxStaticText* m_battle_num;
+ NickListCtrl* m_players;
+ wxStaticLine* m_buttons_sep;
+ wxButton* m_host_btn;
+ wxButton* m_join_btn;
+ wxBoxSizer* m_battlelist_sizer;
+ wxFlexGridSizer* m_data_sizer;
+ wxBoxSizer* m_main_sizer;
+ wxBoxSizer* m_info_sizer;
+
+ wxCheckBox* m_filter_activ;
+
+#if wxUSE_TOGGLEBTN
+ wxToggleButton* m_filter_show;
+ wxToggleButton* m_info_show;
+#else
+ wxCheckBox* m_filter_show;
+ wxCheckBox* m_info_show;
+#endif
+
+ Ui& m_ui;
+
+ IBattle* m_sel_battle;
+
+ void SetNumDisplayed();
+
+ enum {
+ BATTLE_JOIN = wxID_HIGHEST,
+ BATTLE_HOST,
+ BATTLE_LIST,
+ BATTLE_LIST_FILTER_BUTTON,
+ BATTLE_LIST_INFO_BUTTON,
+ BATTLE_LIST_FILTER_ACTIV
+ };
+
+ DECLARE_EVENT_TABLE();
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLELISTTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battlemaptab.cpp b/src/battlemaptab.cpp
new file mode 100644
index 0000000..8759cf1
--- /dev/null
+++ b/src/battlemaptab.cpp
@@ -0,0 +1,284 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: BattleMapTab
+//
+
+#include <wx/splitter.h>
+#include <wx/intl.h>
+#include <wx/combobox.h>
+#include <wx/stattext.h>
+#include <wx/statline.h>
+#include <wx/checkbox.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/radiobox.h>
+#include <wx/window.h>
+#include <wx/listctrl.h>
+#include <wx/settings.h>
+#include <wx/arrstr.h>
+#include <wx/choice.h>
+
+#include <stdexcept>
+
+#include "battlemaptab.h"
+#include "ui.h"
+#include "iunitsync.h"
+#include "user.h"
+#include "battle.h"
+#include "utils/debug.h"
+#include "chatpanel.h"
+#include "mapctrl.h"
+#include "mapselectdialog.h"
+#include "uiutils.h"
+#include "server.h"
+#include "settings.h"
+#include "aui/auimanager.h"
+
+BEGIN_EVENT_TABLE( BattleMapTab, wxPanel )
+
+ EVT_CHOICE ( BMAP_MAP_SEL, BattleMapTab::OnMapSelect )
+ EVT_BUTTON ( BMAP_MAP_BROWSE, BattleMapTab::OnMapBrowse )
+ EVT_RADIOBOX ( BMAP_START_TYPE, BattleMapTab::OnStartTypeSelect )
+ EVT_MOUSEWHEEL ( BattleMapTab::OnMouseWheel )
+
+END_EVENT_TABLE()
+
+
+BattleMapTab::BattleMapTab( wxWindow* parent, Ui& ui, Battle& battle )
+ : wxScrolledWindow( parent, -1 ),
+ m_ui( ui ),
+ m_battle( battle ),
+ m_map_dlg( 0 )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "battlemaptab" ) );
+
+ wxBoxSizer* m_main_sizer = new wxBoxSizer( wxHORIZONTAL );
+ wxBoxSizer* m_map_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_map_sizer->SetMinSize( wxSize( 352, -1 ) );
+ m_minimap = new MapCtrl( this, 352, &m_battle, m_ui, !battle.IsFounderMe(), false, true, false );
+ m_minimap->SetMinSize( wxSize( 352, 352 ) );
+
+ m_map_sizer->Add( m_minimap, 1, wxALL | wxEXPAND, 2 );
+
+ wxBoxSizer* m_selmap_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_map_combo = new wxChoice( this, BMAP_MAP_SEL, wxDefaultPosition, wxDefaultSize );
+ m_selmap_sizer->Add( m_map_combo, 1, wxALL, 2 );
+
+ m_browse_btn = new wxButton( this, BMAP_MAP_BROWSE, _( "Select" ), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_selmap_sizer->Add( m_browse_btn, 0, wxALL, 2 );
+
+ m_map_sizer->Add( m_selmap_sizer, 0, wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_map_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_opts_sizer = new wxBoxSizer( wxVERTICAL );
+
+ //m_opts_sizer->SetMinSize(wxSize( 200,-1 ));
+ m_map_opts_list = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxSize( 150, 160 ), wxLC_NO_HEADER | wxLC_REPORT );
+ m_map_opts_list->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
+ m_map_opts_list->SetFont( wxFont( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT ) );
+
+ wxListItem col;
+
+ col.SetText( _( "Option" ) );
+ m_map_opts_list->InsertColumn( 0, col );
+ col.SetText( _( "Value" ) );
+ m_map_opts_list->InsertColumn( 1, col );
+ m_map_opts_list->SetColumnWidth( 0, 90 );
+ m_map_opts_list->SetColumnWidth( 1, 50 );
+
+ m_map_opts_list->InsertItem( 0, _( "Size" ) );
+ m_map_opts_list->InsertItem( 1, _( "Windspeed" ) );
+ m_map_opts_list->InsertItem( 2, _( "Tidal strength" ) );
+ m_map_opts_list->InsertItem( 3, _( "Gravity" ) );
+ m_map_opts_list->InsertItem( 4, _( "Extractor radius" ) );
+ m_map_opts_list->InsertItem( 5, _( "Max metal" ) );
+
+ m_opts_sizer->Add( m_map_opts_list, 0, wxALL, 2 );
+
+
+ wxString m_start_radiosChoices[] = { _( "Fixed" ), _( "Random" ), _( "Choose in game" ), _( "Chose before game" ) };
+ int m_start_radiosNChoices = sizeof( m_start_radiosChoices ) / sizeof( wxString );
+ //TODO these need to be tooltipped, no idea how yet
+ m_start_radios = new wxRadioBox( this, BMAP_START_TYPE, _( "Startpositions" ), wxDefaultPosition, wxSize( 150, -1 ), m_start_radiosNChoices, m_start_radiosChoices, 1, wxRA_SPECIFY_COLS );
+
+ m_opts_sizer->Add( m_start_radios, 0, wxALL, 2 );
+
+ m_main_sizer->Add( m_opts_sizer, 0, wxEXPAND, 5 );
+ //m_main_sizer->AddStretchSpacer();
+ SetSizer( m_main_sizer );
+ Layout();
+
+ ReloadMaplist();
+ Update();
+
+ //m_map_combo->Enable( m_battle.IsFounderMe() );
+ m_start_radios->Enable( m_battle.IsFounderMe() );
+ SetScrollRate( 3, 3 );
+ Layout();
+}
+
+
+BattleMapTab::~BattleMapTab()
+{
+ if ( GetAui().manager )
+ GetAui().manager->DetachPane( this );
+ if ( m_map_dlg ) {
+ m_map_dlg->EndModal( 0 );
+ }
+}
+
+void BattleMapTab::OnMouseWheel( wxMouseEvent& event )
+{
+ if ( m_minimap ) {
+ wxRect map_rect = m_minimap->GetRect();
+ if ( map_rect.Contains( event.GetPosition() ) ) {
+ m_minimap->OnMouseWheel( event );
+ return;
+ }
+ }
+ event.Skip();
+}
+
+void BattleMapTab::Update()
+{
+ wxString value = m_battle.CustomBattleOptions().getSingleValue( _T( "startpostype" ), OptionsWrapper::EngineOption );
+ long longval;
+ value.ToLong( &longval );
+ m_start_radios->SetSelection( longval );
+
+ m_minimap->UpdateMinimap();
+
+ if ( !m_battle.MapExists() ) return;
+
+ UnitSyncMap map = m_battle.LoadMap();
+
+ m_map_opts_list->SetItem( 0, 1, wxString::Format( _T( "%dx%d" ), map.info.width / 512, map.info.height / 512 ) );
+ m_map_opts_list->SetItem( 1, 1, wxString::Format( _T( "%d-%d" ), map.info.minWind, map.info.maxWind ) );
+ m_map_opts_list->SetItem( 2, 1, wxString::Format( _T( "%d" ), map.info.tidalStrength ) );
+ m_map_opts_list->SetItem( 3, 1, wxString::Format( _T( "%d" ), map.info.gravity ) );
+ m_map_opts_list->SetItem( 4, 1, wxString::Format( _T( "%d" ), map.info.extractorRadius ) );
+ m_map_opts_list->SetItem( 5, 1, wxString::Format( _T( "%.3f" ), map.info.maxMetal ) );
+
+ int index = m_map_combo->FindString( RefineMapname( map.name ) );
+ if ( index == wxNOT_FOUND ) return;
+ m_map_combo->SetSelection( index );
+}
+
+
+void BattleMapTab::Update( const wxString& Tag )
+{
+ long type;
+ Tag.BeforeFirst( '_' ).ToLong( &type );
+ wxString key = Tag.AfterFirst( '_' );
+ wxString value = m_battle.CustomBattleOptions().getSingleValue( key, ( OptionsWrapper::GameOption )type );
+ long longval;
+ value.ToLong( &longval );
+ if ( type == OptionsWrapper::EngineOption )
+ {
+ if ( key == _T( "startpostype" ) )
+ {
+ m_start_radios->SetSelection( longval );
+ m_minimap->UpdateMinimap();
+ }
+ }
+ else if ( type == OptionsWrapper::PrivateOptions )
+ {
+ if ( key == _T( "mapname" ) )
+ {
+ Update();
+ }
+ }
+}
+
+
+void BattleMapTab::ReloadMaplist()
+{
+ m_map_combo->Clear();
+
+ wxArrayString maplist = usync().GetMapList();
+// maplist.Sort(CompareStringIgnoreCase);
+
+ size_t nummaps = maplist.Count();
+ for ( size_t i = 0; i < nummaps; i++ ) m_map_combo->Insert( RefineMapname( maplist[i] ), i );
+}
+
+
+void BattleMapTab::UpdateUser( User& user )
+{
+ if ( &m_battle.GetMe() == &user ) {
+ try {
+ m_minimap->UpdateMinimap();
+ } catch ( ... ) { }
+ }
+}
+
+
+void BattleMapTab::SetMap( int index )
+{
+ try
+ {
+ UnitSyncMap map = usync().GetMapEx( index );
+ m_battle.SetLocalMap( map );
+
+ m_battle.SendHostInfo( IBattle::HI_Map );
+ } catch ( ... ) {}
+}
+
+
+void BattleMapTab::OnMapSelect( wxCommandEvent& /*unused*/ )
+{
+ if ( !m_battle.IsFounderMe() )
+ {
+ try
+ {
+ m_battle.DoAction( _T( "suggests " ) + usync().GetMap( m_map_combo->GetCurrentSelection() ).name );
+ }
+ catch ( ... )
+ {
+ }
+ return;
+ }
+ SetMap( m_map_combo->GetCurrentSelection() );
+}
+
+
+void BattleMapTab::OnMapBrowse( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T( "" ) );
+ m_map_dlg = new MapSelectDialog ( ( wxWindow* )&m_ui.mw(), m_ui );
+
+ if ( m_map_dlg->ShowModal() == wxID_OK && m_map_dlg->GetSelectedMap() != NULL )
+ {
+ wxString mapname = m_map_dlg->GetSelectedMap()->name;
+ wxLogDebugFunc( mapname );
+ if ( !m_battle.IsFounderMe() )
+ {
+ m_battle.DoAction( _T( "suggests " ) + mapname );
+ return;
+ }
+ const int idx = m_map_combo->FindString( RefineMapname( mapname ), true /*case sensitive*/ );
+ if ( idx != wxNOT_FOUND )
+ SetMap( idx );
+ }
+
+}
+
+
+void BattleMapTab::OnStartTypeSelect( wxCommandEvent& /*unused*/ )
+{
+ wxString pos = wxString::Format( _T( "%d" ), m_start_radios->GetSelection() );
+ m_battle.CustomBattleOptions().setSingleOption( _T( "startpostype" ), pos, OptionsWrapper::EngineOption );
+ m_battle.SendHostInfo( wxString::Format( _T( "%d_startpostype" ), OptionsWrapper::EngineOption ) );
+}
+
+
+void BattleMapTab::OnUnitSyncReloaded()
+{
+ m_minimap->UpdateMinimap();
+ ReloadMaplist();
+}
+
diff --git a/src/battlemaptab.h b/src/battlemaptab.h
new file mode 100644
index 0000000..3648fa9
--- /dev/null
+++ b/src/battlemaptab.h
@@ -0,0 +1,88 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLEMAPTAB_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLEMAPTAB_H
+
+#include <wx/scrolwin.h>
+
+class Ui;
+class Battle;
+class User;
+class ChatPanel;
+class wxCommandEvent;
+class wxBoxSizer;
+class wxComboBox;
+class wxStaticText;
+class wxSplitterWindow;
+class wxStaticLine;
+class wxButton;
+class wxCheckBox;
+class MapCtrl;
+class wxListCtrl;
+class wxChoice;
+class wxRadioBox;
+class wxMouseEvent;
+class MapSelectDialog;
+
+/** \brief select map, draw startboxes (in sp define startpos)
+ * \todo DOCMEMORE */
+class BattleMapTab : public wxScrolledWindow
+{
+ public:
+ BattleMapTab( wxWindow* parent, Ui& ui, Battle& battle );
+ ~BattleMapTab();
+
+ void UpdateUser( User& user );
+
+ void Update();
+ void Update( const wxString& Tag );
+ void ReloadMaplist();
+
+ void OnMapSelect( wxCommandEvent& event );
+ void OnMapBrowse( wxCommandEvent& event );
+ void OnStartTypeSelect( wxCommandEvent& event );
+ void OnMouseWheel( wxMouseEvent& event );
+
+ void OnUnitSyncReloaded();
+
+ void SetMap( int index );
+
+ protected:
+ Ui& m_ui;
+ Battle& m_battle;
+ //UnitSyncMap m_map;
+
+ MapCtrl* m_minimap;
+ wxChoice* m_map_combo;
+ wxButton* m_browse_btn;
+ wxRadioBox* m_start_radios;
+ wxListCtrl* m_map_opts_list;
+ MapSelectDialog* m_map_dlg;
+
+ enum {
+ BMAP_MAP_SEL = wxID_HIGHEST,
+ BMAP_MAP_BROWSE,
+ BMAP_START_TYPE
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLEMAPTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battleoptionstab.cpp b/src/battleoptionstab.cpp
new file mode 100644
index 0000000..5ec07e5
--- /dev/null
+++ b/src/battleoptionstab.cpp
@@ -0,0 +1,270 @@
+/* Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: BattleOptionsTab
+//
+
+#include "battleoptionstab.h"
+
+#include <wx/splitter.h>
+#include <wx/intl.h>
+#include <wx/stattext.h>
+#include <wx/statbox.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/window.h>
+#include <wx/listbox.h>
+#include <wx/arrstr.h>
+#include <wx/choice.h>
+#include <wx/tokenzr.h>
+#include <wx/checklst.h>
+#include <wx/numdlg.h>
+
+#include "ui.h"
+#include "iunitsync.h"
+#include "ibattle.h"
+#include "utils/controls.h"
+#include "server.h"
+#include "mmoptionswrapper.h"
+#include "aui/auimanager.h"
+
+
+BEGIN_EVENT_TABLE( BattleOptionsTab, wxPanel )
+
+ EVT_BUTTON( BOPTS_RESTRICT, BattleOptionsTab::OnRestrict )
+ EVT_BUTTON( BOPTS_ALLOW, BattleOptionsTab::OnAllow )
+ EVT_BUTTON( BOPTS_CLEARRES, BattleOptionsTab::OnClearRestrictions )
+
+END_EVENT_TABLE()
+
+
+BattleOptionsTab::BattleOptionsTab( wxWindow* parent, Ui& ui, IBattle& battle ):
+ wxScrolledWindow( parent, -1 ), m_ui( ui ), m_battle( battle )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "battleoptionstab" ) );
+
+ wxBoxSizer* m_main_sizer;
+ m_main_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_main_options_sizer;
+ m_main_options_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxStaticBoxSizer* m_restr_box;
+ m_restr_box = new wxStaticBoxSizer( new wxStaticBox( this, -1, _( "Unit restrictions" ) ), wxVERTICAL );
+
+ wxBoxSizer* m_top_restr_sizer;
+ m_top_restr_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_allowed_sizer;
+ m_allowed_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_aloowed_lbl = new wxStaticText( this, wxID_ANY, _( "Allowed units" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_allowed_sizer->Add( m_aloowed_lbl, 0, wxALL, 5 );
+
+ m_allowed_list = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE | wxLB_NEEDED_SB | wxLB_SORT );
+ m_allowed_list->SetToolTip( TE( _( "Units in this list will be available in the game." ) ) );
+
+ m_allowed_sizer->Add( m_allowed_list, 1, wxALL | wxEXPAND, 5 );
+
+ m_top_restr_sizer->Add( m_allowed_sizer, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* m_mid_btn_sizer;
+ m_mid_btn_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_mid_btn_sizer->Add( 0, 50, 0, wxEXPAND, 0 );
+
+ m_restrict_btn = new wxButton( this, BOPTS_RESTRICT, _T( ">" ), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ m_restrict_btn->SetToolTip( TE( _( "Disable selected units." ) ) );
+ m_mid_btn_sizer->Add( m_restrict_btn, 0, wxALL, 5 );
+
+ m_allow_btn = new wxButton( this, BOPTS_ALLOW, _T( "<" ), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ m_allow_btn->SetToolTip( TE( _( "Re-enable selected units." ) ) );
+ m_mid_btn_sizer->Add( m_allow_btn, 0, wxALL, 5 );
+
+ m_clear_btn = new wxButton( this, BOPTS_CLEARRES, _( "<<" ), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ m_clear_btn->SetToolTip( TE( _( "Enable all units." ) ) );
+
+ m_mid_btn_sizer->Add( m_clear_btn, 0, wxALL, 5 );
+
+ m_top_restr_sizer->Add( m_mid_btn_sizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* m_restricted_sizer;
+ m_restricted_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_restricted_lbl = new wxStaticText( this, wxID_ANY, _( "Restricted units" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_restricted_sizer->Add( m_restricted_lbl, 0, wxALL, 5 );
+
+ m_restrict_list = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE | wxLB_NEEDED_SB | wxLB_SORT );
+ m_restrict_list->SetToolTip( TE( _( "Units in this list will not be available in the game." ) ) );
+
+ m_restricted_sizer->Add( m_restrict_list, 1, wxALL | wxEXPAND, 5 );
+
+ m_top_restr_sizer->Add( m_restricted_sizer, 1, wxEXPAND, 5 );
+
+ m_restr_box->Add( m_top_restr_sizer, 1, wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_restr_box, 1, wxALL | wxEXPAND, 5 );
+
+ SetScrollRate( 3, 3 );
+ this->SetSizer( m_main_sizer );
+ this->Layout();
+
+ ReloadRestrictions();
+
+ if ( !m_battle.IsFounderMe() ) {
+ m_restrict_btn->Disable();
+ m_allow_btn->Disable();
+ m_clear_btn->Disable();
+ }
+}
+
+
+BattleOptionsTab::~BattleOptionsTab()
+{
+ if ( GetAui().manager )
+ GetAui().manager->DetachPane( this );
+}
+
+
+void BattleOptionsTab::UpdateBattle( const wxString& Tag )
+{
+ long type;
+ Tag.BeforeFirst( '_' ).ToLong( &type );
+ wxString key = Tag.AfterFirst( '_' );
+ if ( type == OptionsWrapper::PrivateOptions ) {
+ if ( key == _T( "restrictions" ) ) ReloadRestrictions();
+ }
+}
+
+void BattleOptionsTab::ReloadRestrictions()
+{
+ m_allowed_list->Clear();
+ m_restrict_list->Clear();
+ if ( m_battle.GetHostModName() == wxEmptyString )
+ return;
+
+ try {
+ m_allowed_list->InsertItems( usync().GetUnitsList( m_battle.GetHostModName() ), 0 );
+ } catch ( ... ) {}
+ std::map<wxString, int> units = m_battle.RestrictedUnits();
+
+ for ( std::map<wxString, int>::iterator itor = units.begin(); itor != units.end(); itor++ )
+ Restrict( itor->first, itor->second );
+}
+
+
+int BattleOptionsTab::GetAllowedUnitIndex( const wxString& name )
+{
+ for ( unsigned int i = 0; i < m_allowed_list->GetCount(); i++ ) {
+ wxString tmp = m_allowed_list->GetString( i );
+ tmp = tmp.AfterLast( '(' );
+ tmp = tmp.BeforeLast( ')' );
+ if ( name == tmp ) return i;
+ }
+ return -1;
+}
+
+
+int BattleOptionsTab::GetRestrictedUnitIndex( const wxString& name )
+{
+ for ( unsigned int i = 0; i < m_restrict_list->GetCount(); i++ ) {
+ wxString tmp = m_restrict_list->GetString( i );
+ tmp = tmp.AfterLast( '(' );
+ tmp = tmp.BeforeLast( ')' );
+ if ( name == tmp ) return i;
+ }
+ return -1;
+}
+
+
+bool BattleOptionsTab::IsRestricted( const wxString& name )
+{
+ return ( GetRestrictedUnitIndex( name ) >= 0 );
+}
+
+
+void BattleOptionsTab::Restrict( const wxString& name, int count )
+{
+ int i = GetAllowedUnitIndex( name );
+ Restrict( i, count );
+}
+
+
+void BattleOptionsTab::Allow( const wxString& name )
+{
+ int i = GetRestrictedUnitIndex( name );
+ Allow( i );
+}
+
+
+void BattleOptionsTab::Restrict( int index, int count )
+{
+ if ( index >= 0 ) {
+ wxString unit = m_allowed_list->GetString( index );
+ m_restrict_list->Append( unit << _T( " [" ) << count << _T( "]" ) );
+ m_allowed_list->Delete( index );
+ }
+}
+
+
+void BattleOptionsTab::Allow( int index )
+{
+ if ( index >= 0 ) {
+ wxString unit = m_restrict_list->GetString( index );
+ m_allowed_list->Append( unit );
+ m_restrict_list->Delete( index );
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// EVENTS
+//////////////////////////////////////////////////////////////////////////
+
+
+void BattleOptionsTab::OnRestrict( wxCommandEvent& /*unused*/ )
+{
+ wxArrayInt sel;
+ wxArrayString names;
+
+ m_allowed_list->GetSelections( sel );
+ for ( unsigned int i = 0; i < sel.Count(); i++ ) {
+ wxString name = m_allowed_list->GetString( sel.Item( i ) );
+ name = name.AfterLast( '(' );
+ name = name.BeforeLast( ')' );
+ names.Add( name );
+ }
+ for ( unsigned int i = 0; i < names.Count(); i++ ) {
+ wxString unit = names.Item( i );
+ int count = wxGetNumberFromUser( _( "How many units of this type do you wish to allow?" ), _T( "" ), _( "Unit restriction" ), 0, 0, 500000 );
+ if ( count >= 0 ) m_battle.RestrictUnit( unit, count );
+ }
+ if ( names.Count() > 0 ) m_battle.SendHostInfo( IBattle::HI_Restrictions );
+}
+
+
+void BattleOptionsTab::OnAllow( wxCommandEvent& /*unused*/ )
+{
+ wxArrayInt sel;
+ wxArrayString names;
+
+ m_restrict_list->GetSelections( sel );
+ for ( unsigned int i = 0; i < sel.Count(); i++ ) {
+ wxString name = m_restrict_list->GetString( sel.Item( i ) );
+ name = name.AfterLast( '(' );
+ name = name.BeforeLast( ')' );
+ names.Add( name );
+ }
+ for ( unsigned int i = 0; i < names.Count(); i++ ) {
+ wxString unit = names.Item( i );
+ m_battle.UnrestrictUnit( unit );
+ }
+ if ( names.Count() > 0 ) m_battle.SendHostInfo( IBattle::HI_Restrictions );
+
+}
+
+
+void BattleOptionsTab::OnClearRestrictions( wxCommandEvent& /*unused*/ )
+{
+ m_battle.UnrestrictAllUnits();
+ ReloadRestrictions();
+}
diff --git a/src/battleoptionstab.h b/src/battleoptionstab.h
new file mode 100644
index 0000000..1e6b3cf
--- /dev/null
+++ b/src/battleoptionstab.h
@@ -0,0 +1,103 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLEOPTIONSTAB_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLEOPTIONSTAB_H
+
+#include <wx/scrolwin.h>
+
+class Ui;
+class IBattle;
+class wxCommandEvent;
+class wxBoxSizer;
+class wxStaticText;
+class wxSplitterWindow;
+class wxButton;
+class wxCheckBox;
+class wxListBox;
+class wxRadioBox;
+class wxCheckListBox;
+
+/** \brief manipulate "standard" engine options, unit restriction list
+ * \todo DOCMEMORE */
+class BattleOptionsTab : public wxScrolledWindow
+{
+ public:
+ BattleOptionsTab( wxWindow* parent, Ui& ui, IBattle& battle );
+ ~BattleOptionsTab();
+
+ void UpdateBattle( const wxString& Tag );
+ void ReloadRestrictions();
+
+ int GetAllowedUnitIndex( const wxString& name );
+ int GetRestrictedUnitIndex( const wxString& name );
+ bool IsRestricted( const wxString& name );
+ void Restrict( const wxString& name, int count );
+ void Allow( const wxString& name );
+ void Restrict( int index, int count );
+ void Allow( int index );
+
+
+ void OnRestrict( wxCommandEvent& event );
+ void OnAllow( wxCommandEvent& event );
+ void OnClearRestrictions( wxCommandEvent& event );
+
+ protected:
+
+ void UpdateBattle();
+
+ Ui& m_ui;
+ IBattle& m_battle;
+
+ wxStaticText* m_aloowed_lbl;
+ wxListBox* m_allowed_list;
+ wxButton* m_restrict_btn;
+ wxButton* m_allow_btn;
+ wxStaticText* m_restricted_lbl;
+ wxListBox* m_restrict_list;
+ wxButton* m_clear_btn;
+
+ enum {
+ BOPTS_END = wxID_HIGHEST,
+ BOPTS_OPTS,
+ BOPTS_SLIDE,
+
+ BOPTS_RESTRICT,
+ BOPTS_ALLOW,
+ BOPTS_CLEARRES,
+
+ BOPTS_LOADPRES,
+ BOPTS_SAVEPRES,
+ BOPTS_DELETEPRES,
+ BOPTS_SETDEFAULTPRES,
+ BOPTS_CHOSEPRES
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+enum
+{
+ BOPTS_RESTRICT = wxID_HIGHEST,
+ BOPTS_ALLOW,
+ BOPTS_CLEARRES
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLEOPTIONSTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battleroomlistctrl.cpp b/src/battleroomlistctrl.cpp
new file mode 100644
index 0000000..dc5b1df
--- /dev/null
+++ b/src/battleroomlistctrl.cpp
@@ -0,0 +1,852 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: BattleroomListCtrl
+//
+
+#include <wx/intl.h>
+#include <wx/menu.h>
+#include <wx/numdlg.h>
+#include <wx/colordlg.h>
+#include <wx/colour.h>
+#include <wx/log.h>
+
+#include <stdexcept>
+#include <vector>
+
+#include "battleroomlistctrl.h"
+#include "iconimagelist.h"
+#include "iunitsync.h"
+#include "battle.h"
+#include "ibattle.h"
+#include "uiutils.h"
+#include "ui.h"
+#include "user.h"
+#include "server.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "uiutils.h"
+#include "countrycodes.h"
+#include "mainwindow.h"
+#include "aui/auimanager.h"
+#include "settings++/custom_dialogs.h"
+#include "settings.h"
+
+template<> SortOrder CustomVirtListCtrl<User*,BattleroomListCtrl>::m_sortorder = SortOrder();
+
+IBattle* BattleroomListCtrl::s_battle = 0;
+
+BEGIN_EVENT_TABLE( BattleroomListCtrl, BattleroomListCtrl::BaseType )
+
+ EVT_LIST_ITEM_RIGHT_CLICK( BRLIST_LIST, BattleroomListCtrl::OnListRightClick )
+ EVT_MENU ( BRLIST_SPEC, BattleroomListCtrl::OnSpecSelect )
+ EVT_MENU ( BRLIST_KICK, BattleroomListCtrl::OnKickPlayer )
+ EVT_LIST_ITEM_ACTIVATED( BRLIST_LIST, BattleroomListCtrl::OnActivateItem )
+// EVT_MENU ( BRLIST_ADDCREATEGROUP, BattleroomListCtrl::OnPlayerAddToGroup )
+// EVT_MENU ( BRLIST_ADDTOGROUP, BattleroomListCtrl::OnPlayerAddToGroup )
+ EVT_MENU ( BRLIST_RING, BattleroomListCtrl::OnRingPlayer )
+ EVT_MENU ( BRLIST_COLOUR, BattleroomListCtrl::OnColourSelect )
+ EVT_MENU ( BRLIST_HANDICAP, BattleroomListCtrl::OnHandicapSelect )
+#if wxUSE_TIPWINDOW
+#ifndef __WXMSW__ //disables tooltips on win
+ EVT_MOTION(BattleroomListCtrl::OnMouseMotion)
+#endif
+#endif
+END_EVENT_TABLE()
+
+
+BattleroomListCtrl::BattleroomListCtrl( wxWindow* parent, IBattle* battle, Ui& ui, bool readonly )
+ : CustomVirtListCtrl< User *,BattleroomListCtrl>(parent, BRLIST_LIST, wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL, _T("BattleroomListCtrl"), 10, 3, &CompareOneCrit,
+ true /*highlight*/, UserActions::ActHighlight, !readonly /*periodic sort*/ ),
+ m_battle(battle),
+ m_popup(0),
+ m_sel_user(0),
+ m_sides(0),
+ m_spec_item(0),
+ m_handicap_item(0),
+ m_ui(ui),
+ m_ro(readonly)
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("battleroomlistctrl") );
+
+ wxListItem col;
+
+ const int hd = wxLIST_AUTOSIZE_USEHEADER;
+
+#if defined(__WXMAC__)
+/// on mac, autosize does not work at all
+ const int widths[10] = {20,20,20,170,140,130,110,28,28,28}; //!TODO revise plox
+#else
+ const int widths[10] = {hd,hd,hd,hd,hd,170,hd,hd,80,130};
+#endif
+
+ AddColumn( 0, widths[0], _T("Status"), _T("Player/Bot") );
+ AddColumn( 1, widths[1], _T("Faction"), _T("Faction icon") );
+ AddColumn( 2, widths[2], _T("Colour"), _T("Teamcolour") );
+ AddColumn( 3, widths[3], _T("Country"), _T("Country") );
+ AddColumn( 4, widths[4], _T("Rank"), _T("Rank") );
+ AddColumn( 5, widths[5], _("Nickname"), _T("Ingame name"));
+ AddColumn( 6, widths[6], _("Team"), _T("Team number") );
+ AddColumn( 7, widths[7], _("Ally"), _T("Ally number") );
+ AddColumn( 8, widths[8], _("CPU"), _T("CPU speed (might not be accurate)") );
+ AddColumn( 9, widths[9], _("Resource Bonus"), _T("Resource Bonus") );
+
+ if ( m_sortorder.size() == 0 ) {
+ m_sortorder[0].col = 6;
+ m_sortorder[0].direction = true;
+ m_sortorder[1].col = 7;
+ m_sortorder[1].direction = true;
+ m_sortorder[2].col = 5;
+ m_sortorder[2].direction = true;
+ }
+
+ if ( !m_ro )
+ {
+ m_popup = new UserMenu(this);
+ wxMenu* m_teams;
+ m_teams = new wxMenu();
+
+ for ( unsigned int i = 0; i < SPRING_MAX_TEAMS; i++ )
+ {
+ wxMenuItem* team = new wxMenuItem( m_teams, BRLIST_TEAM + i, wxString::Format( _T("%d"), i+1 ) , wxEmptyString, wxITEM_NORMAL );
+ m_teams->Append( team );
+ Connect( BRLIST_TEAM + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnTeamSelect ) );
+ }
+ m_popup->Append( -1, _("Team"), m_teams );
+
+ wxMenu* m_allies = new wxMenu();
+ for ( unsigned int i = 0; i < SPRING_MAX_ALLIES; i++ )
+ {
+ wxMenuItem* ally = new wxMenuItem( m_allies, BRLIST_ALLY + i, wxString::Format( _T("%d"), i+1 ) , wxEmptyString, wxITEM_NORMAL );
+ m_allies->Append( ally );
+ Connect( BRLIST_ALLY + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnAllySelect ) );
+ }
+ m_popup->Append( -1, _("Ally"), m_allies );
+
+ m_sides = new wxMenu();
+ try
+ {
+ wxArrayString sides = usync().GetSides( m_battle->GetHostModName() );
+ for ( unsigned int i = 0; i < sides.GetCount(); i++ )
+ {
+ wxMenuItem* side = new wxMenuItem( m_sides, BRLIST_SIDE + i, sides[i], wxEmptyString, wxITEM_NORMAL );
+ m_sides->Append( side );
+ Connect( BRLIST_SIDE + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnSideSelect ) );
+ }
+ } catch (...) {}
+ m_popup->Append( -1, _("Side"), m_sides );
+
+ m_popup->AppendSeparator();
+
+ wxMenuItem* m_colours = new wxMenuItem( m_popup, BRLIST_COLOUR, _("Set color"), wxEmptyString, wxITEM_NORMAL );
+ m_popup->Append( m_colours );
+
+ m_popup->AppendSeparator();
+
+ m_handicap_item = new wxMenuItem( m_popup, BRLIST_HANDICAP, _("Set Resource Bonus"), wxEmptyString, wxITEM_NORMAL );
+ m_popup->Append( m_handicap_item );
+
+ m_popup->AppendSeparator();
+
+ m_spec_item = new wxMenuItem( m_popup, BRLIST_SPEC, wxString( _("Spectator") ) , wxEmptyString, wxITEM_CHECK );
+ m_popup->Append( m_spec_item );
+
+ m_popup->AppendSeparator();
+
+ wxMenuItem* kick = new wxMenuItem( m_popup, BRLIST_KICK, wxString( _("Kick") ) , wxEmptyString, wxITEM_NORMAL );
+ m_popup->Append( kick );
+ wxMenuItem* ring = new wxMenuItem( m_popup, BRLIST_RING, wxString( _("Ring") ) , wxEmptyString, wxITEM_NORMAL );
+ m_popup->Append( ring );
+ }
+}
+
+
+BattleroomListCtrl::~BattleroomListCtrl()
+{
+
+}
+
+void BattleroomListCtrl::SetBattle( IBattle* battle )
+{
+ m_battle = battle;
+}
+
+IBattle& BattleroomListCtrl::GetBattle()
+{
+ ASSERT_EXCEPTION( m_battle, _T("m_battle == 0") );
+ return *m_battle;
+}
+
+void BattleroomListCtrl::AddUser( User& user )
+{
+ if ( AddItem( &user ) )
+ return;
+
+ wxLogWarning( _T("user already in battleroom list.") );
+}
+
+void BattleroomListCtrl::RemoveUser( User& user )
+{
+ if ( RemoveItem( &user ) )
+ return;
+
+ wxLogError( _T("Didn't find the user to remove in battleroomlistctrl.") );
+}
+
+void BattleroomListCtrl::UpdateUser( User& user )
+{
+ if ( !user.BattleStatus().spectator )
+ icons().SetColourIcon( user.BattleStatus().team, user.BattleStatus().colour );
+ wxArrayString sides = usync().GetSides( m_battle->GetHostModName() );
+ ASSERT_EXCEPTION( user.BattleStatus().side < (long)sides.GetCount(), _T("Side index too high") );
+ user.SetSideiconIndex( icons().GetSideIcon( m_battle->GetHostModName(), user.BattleStatus().side ) );
+ int index = GetIndexFromData( &user );
+ UpdateUser( index );
+}
+
+wxListItemAttr * BattleroomListCtrl::GetItemAttr(long item) const
+{
+ if ( item == -1 || item >= (long)m_data.size())
+ return NULL;
+
+ const User& user = *GetDataFromIndex( item );
+ bool is_bot = user.BattleStatus().IsBot();
+
+ if ( !is_bot ) {
+ return HighlightItemUser( user.GetNick() );
+ }
+
+ return NULL;
+}
+
+int BattleroomListCtrl::GetItemColumnImage(long item, long column) const
+{
+ if ( item == -1 || item >= (long)m_data.size())
+ return -1;
+
+ const User& user = *GetDataFromIndex( item );
+ bool is_bot = user.BattleStatus().IsBot();
+ bool is_spec = user.BattleStatus().spectator;
+
+ switch ( column ) {
+ case 0: {
+ if ( !is_bot ) {
+ if ( m_battle->IsFounder( user ) ) {
+ return icons().GetHostIcon( is_spec );
+ }
+ else {
+ return icons().GetReadyIcon( is_spec, user.BattleStatus().ready, user.BattleStatus().sync, is_bot );
+ }
+ }
+ else
+ return icons().ICON_BOT;
+ }
+ case 2: return is_spec ? -1: icons().GetColourIcon( user.BattleStatus().team );
+ case 3: return is_bot ? -1 : icons().GetFlagIcon( user.GetCountry() );
+ case 4: return is_bot ? -1 : icons().GetRankIcon( user.GetStatus().rank );
+ case 1: return is_spec ? -1 : user.GetSideiconIndex();
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 5: return -1;
+ default: {
+ wxLogWarning( _T("column oob in BattleroomListCtrl::OnGetItemColumnImage") );
+ return -1;
+ }
+ }
+}
+
+wxString BattleroomListCtrl::GetItemText(long item, long column) const
+{
+ if ( item == -1 || item >= (long)m_data.size())
+ return _T("");
+
+ const User& user = *GetDataFromIndex( item );
+ bool is_bot = user.BattleStatus().IsBot();
+ bool is_spec = user.BattleStatus().spectator;
+
+ switch ( column ) {
+ case 1: {
+ try {
+ wxArrayString sides = usync().GetSides( m_battle->GetHostModName() );
+ ASSERT_EXCEPTION( user.BattleStatus().side < (long)sides.GetCount(), _T("Side index too high") );
+ }
+ catch ( ... ) {
+ return wxString::Format( _T("s%d"), user.BattleStatus().side + 1 );
+ }
+ return _T("");
+ }
+ case 5: return is_bot ? user.GetNick() + _T(" (") + user.BattleStatus().owner + _T(")") : user.GetNick();
+ case 6: return is_spec ? _T("") : wxString::Format( _T("%d"), user.BattleStatus().team + 1 );
+ case 7: return is_spec ? _T("") : wxString::Format( _T("%d"), user.BattleStatus().ally + 1 );
+ case 8: {
+ if (!is_bot )
+ return wxString::Format( _T("%.1f GHz"), user.GetCpu() / 1000.0 );
+ else { //!TODO could prolly be cached
+ wxString botname = user.BattleStatus().aishortname;
+ if ( !user.BattleStatus().aiversion.IsEmpty() ) botname += _T(" ") + user.BattleStatus().aiversion;
+ if ( !usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) )
+ {
+ if ( botname.Contains(_T('.')) ) botname = botname.BeforeLast(_T('.'));
+ if ( botname.Contains(_T('/')) ) botname = botname.AfterLast(_T('/'));
+ if ( botname.Contains(_T('\\')) ) botname = botname.AfterLast(_T('\\'));
+ if ( botname.Contains(_T("LuaAI:")) ) botname = botname.AfterFirst(_T(':'));
+ }
+ return botname;
+ }
+ }
+ case 9: return is_spec ? _T("") : wxString::Format( _T("%d%%"), user.BattleStatus().handicap );
+ case 0:
+ case 2:
+ case 3:
+ case 4: return _T("");
+ default: {
+ wxLogWarning( _T("column oob in BattleroomListCtrl::OnGetItemText") );
+ return _T("");
+ }
+ }
+}
+
+void BattleroomListCtrl::UpdateUser( const int& index )
+{
+ Freeze();
+ RefreshItem( index );
+ Thaw();
+ MarkDirtySort();
+}
+
+void BattleroomListCtrl::OnListRightClick( wxListEvent& event )
+{
+ wxLogDebugFunc( _T("") );
+ if ( m_ro ) return;
+ int index = event.GetIndex();
+
+ if ( index == -1 || index >= (long)m_data.size()) return;
+
+ User& user = *GetDataFromIndex( event.GetIndex() );
+ m_sel_user = &user; //this is set for event handlers
+
+ if ( user.BattleStatus().IsBot() )
+ {
+ wxLogMessage(_T("Bot"));
+
+ int item = m_popup->FindItem( _("Spectator") );
+ m_popup->Enable( item, false );
+ m_popup->Check( item, false );
+ m_popup->Enable( m_popup->FindItem( _("Ring") ), false );
+ m_popup->Enable( m_popup->FindItem( _("Kick") ),true);
+ }
+ else
+ {
+ wxLogMessage(_T("User"));
+ int item = m_popup->FindItem( _("Spectator") );
+ m_popup->Check( item, m_sel_user->BattleStatus().spectator );
+ m_popup->Enable( item, true );
+ m_popup->Enable( m_popup->FindItem( _("Ring") ), true );
+ bool isSelUserMe = ( m_ui.IsThisMe(user) );
+ m_popup->Enable( m_popup->FindItem( _("Kick") ),!isSelUserMe);
+ }
+
+ wxLogMessage(_T("Popup"));
+ m_popup->EnableItems( !user.BattleStatus().IsBot(), GetSelectedUserNick() );
+ PopupMenu( m_popup );
+ wxLogMessage(_T("Done"));
+}
+
+
+void BattleroomListCtrl::OnTeamSelect( wxCommandEvent& event )
+{
+ wxLogDebugFunc( _T("") );
+ int team = event.GetId() - BRLIST_TEAM;
+ if( m_sel_user ) ((Battle*)m_battle)->ForceTeam( *m_sel_user, team );
+}
+
+
+void BattleroomListCtrl::OnAllySelect( wxCommandEvent& event )
+{
+ wxLogDebugFunc( _T("") );
+ int ally = event.GetId() - BRLIST_ALLY;
+ if( m_sel_user ) ((Battle*)m_battle)->ForceAlly( *m_sel_user, ally );
+}
+
+
+void BattleroomListCtrl::OnColourSelect( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+
+ wxColour CurrentColour = m_sel_user->BattleStatus().colour;
+ CurrentColour = GetColourFromUser(this, CurrentColour);
+ if ( !CurrentColour.IsColourOk() ) return;
+ if( m_sel_user ) ((Battle*)m_battle)->ForceColour( *m_sel_user, CurrentColour );
+
+}
+
+
+void BattleroomListCtrl::OnSideSelect( wxCommandEvent& event )
+{
+ wxLogDebugFunc( _T("") );
+ int side = event.GetId() - BRLIST_SIDE;
+ if( m_sel_user ) ((Battle*)m_battle)->ForceSide( *m_sel_user, side );
+}
+
+
+void BattleroomListCtrl::OnHandicapSelect( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ if( !m_sel_user ) return;
+ long handicap = wxGetNumberFromUser( _("Please enter a value between 0 and 100"), _("Set Resource Bonus"), _T(""), m_sel_user->BattleStatus().handicap, 0, 100, (wxWindow*)&ui().mw(), wxDefaultPosition );
+ if ( handicap != -1 )
+ {
+ ((Battle*)m_battle)->SetHandicap( *m_sel_user, handicap );
+ }
+}
+
+
+void BattleroomListCtrl::OnSpecSelect( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ if ( m_sel_user ) ((Battle*)m_battle)->ForceSpectator( *m_sel_user, m_spec_item->IsChecked() );
+}
+
+
+void BattleroomListCtrl::OnKickPlayer( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ if ( m_sel_user ) ((Battle*)m_battle)->KickPlayer( *m_sel_user );
+}
+
+
+void BattleroomListCtrl::OnRingPlayer( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ if ( m_sel_user ) ((Battle*)m_battle)->GetServer().Ring( m_sel_user->GetNick() );
+}
+
+void BattleroomListCtrl::Sort()
+{
+ if ( m_data.size() > 0 )
+ {
+ SaveSelection();
+ s_battle = m_battle;
+ SLInsertionSort( m_data, m_comparator );
+ RestoreSelection();
+ }
+}
+
+int BattleroomListCtrl::CompareOneCrit(DataType u1, DataType u2, int col, int dir)
+{
+ switch ( col ) {
+ case 0: return dir * CompareStatus( u1, u2, s_battle );
+ case 1: return dir * CompareSide( u1, u2 );
+ case 2: return dir * CompareColor( u1, u2 );
+ case 3: return dir * compareSimple( u1, u2 );
+ case 4: return dir * CompareRank( u1, u2 );
+ case 5: return dir * u1->GetNick().CmpNoCase( u2->GetNick() );
+ case 6: return dir * CompareTeam( u1, u2 );
+ case 7: return dir * CompareAlly( u1, u2 );
+ case 8: return dir * CompareCpu( u1, u2 );
+ case 9: return dir * CompareHandicap( u1, u2 );
+ default: return 0;
+ }
+}
+
+int BattleroomListCtrl::CompareStatus(const DataType user1, const DataType user2, const IBattle* m_battle )
+{
+ int status1 = 0;
+ if ( user1->BattleStatus().IsBot() )
+ {
+ status1 = 9;
+ }
+ else
+ {
+ try
+ {
+ if ( &m_battle->GetFounder() != user1 )
+ status1 = 1;
+ }catch(...){}
+ if ( user1->BattleStatus().ready )
+ status1 += 5;
+ if ( user1->BattleStatus().sync )
+ status1 += 7;
+ if ( user1->BattleStatus().spectator )
+ status1 += 10;
+ }
+
+ int status2 = 0;
+ if ( user1->BattleStatus().IsBot() )
+ {
+ status2 = 9;
+ }
+ else
+ {
+ try
+ {
+ if ( &m_battle->GetFounder() != user2 )
+ status2 = 1;
+ }catch(...){}
+ if ( user2->BattleStatus().ready )
+ status2 += 5;
+ if ( user2->BattleStatus().sync )
+ status2 += 7;
+ if ( user2->BattleStatus().spectator )
+ status2 += 10;
+ }
+
+ if ( status1 < status2 )
+ return -1;
+ if ( status1 > status2 )
+ return 1;
+
+ return 0;
+}
+
+int BattleroomListCtrl::CompareSide(const DataType user1, const DataType user2)
+{
+ if ( !user1 && !user2 ) return 0;
+ else if ( !user1 ) return 1;
+ else if ( !user2 ) return -1;
+
+ int side1;
+ if ( user1->BattleStatus().spectator )
+ side1 = 1000;
+ else
+ side1 = user1->BattleStatus().side;
+
+ int side2;
+ if ( user2->BattleStatus().spectator )
+ side2 = 1000;
+ else
+ side2 = user2->BattleStatus().side;
+
+ if ( side1 < side2 )
+ return -1;
+ if ( side1 > side2 )
+ return 1;
+
+ return 0;
+}
+
+int BattleroomListCtrl::CompareColor(const DataType user1, const DataType user2)
+{
+ if ( !user1 && !user2 ) return 0;
+ else if ( !user1 ) return 1;
+ else if ( !user2 ) return -1;
+
+ int color1_r, color1_g, color1_b;
+
+ if ( user1->BattleStatus().spectator ) return -1;
+ color1_r = user1->BattleStatus().colour.Red();
+ color1_g = user1->BattleStatus().colour.Green();
+ color1_b = user1->BattleStatus().colour.Blue();
+
+ int color2_r, color2_g, color2_b;
+
+ if ( user2->BattleStatus().spectator ) return 1;
+ color2_r = user2->BattleStatus().colour.Red();
+ color2_g = user2->BattleStatus().colour.Green();
+ color2_b = user2->BattleStatus().colour.Blue();
+
+ if ( (color1_r + color1_g + color1_b)/3 < (color2_r + color2_g + color2_b)/3 )
+ return -1;
+ if ( (color1_r + color1_g + color1_b)/3 > (color2_r + color2_g + color2_b)/3 )
+ return 1;
+
+ return 0;
+}
+
+
+int BattleroomListCtrl::CompareRank(const DataType user1, const DataType user2)
+{
+ if ( !user1 && !user2 ) return 0;
+ else if ( !user1 ) return 1;
+ else if ( !user2 ) return -1;
+
+ int rank1;
+ if ( user1->BattleStatus().IsBot() )
+ rank1 = 1000;
+ else
+ rank1 = user1->GetStatus().rank;
+
+ int rank2;
+ if ( user2->BattleStatus().IsBot() )
+ rank2 = 1000;
+ else
+ rank2 = user2->GetStatus().rank;
+
+ if ( rank1 < rank2 )
+ return -1;
+ if ( rank1 > rank2 )
+ return 1;
+
+ return 0;
+}
+
+int BattleroomListCtrl::CompareTeam(const DataType user1, const DataType user2)
+{
+ if ( !user1 && !user2 ) return 0;
+ else if ( !user1 ) return 1;
+ else if ( !user2 ) return -1;
+
+ int team1;
+ if ( user1->BattleStatus().spectator )
+ team1 = 1000;
+ else
+ team1 = user1->BattleStatus().team;
+
+ int team2;
+ if ( user2->BattleStatus().spectator )
+ team2 = 1000;
+ else
+ team2 = user2->BattleStatus().team;
+
+ if ( team1 < team2 )
+ return -1;
+ if ( team1 > team2 )
+ return 1;
+
+ return 0;
+}
+
+int BattleroomListCtrl::CompareAlly(const DataType user1, const DataType user2)
+{
+ if ( !user1 && !user2 ) return 0;
+ else if ( !user1 ) return 1;
+ else if ( !user2 ) return -1;
+
+ int ally1;
+ if ( user1->BattleStatus().spectator )
+ ally1 = 1000;
+ else
+ ally1 = user1->BattleStatus().ally;
+
+ int ally2;
+ if ( user2->BattleStatus().spectator )
+ ally2 = 1000;
+ else
+ ally2 = user2->BattleStatus().ally;
+
+ if ( ally1 < ally2 )
+ return -1;
+ if ( ally1 > ally2 )
+ return 1;
+
+ return 0;
+}
+
+int BattleroomListCtrl::CompareCpu(const DataType user1, const DataType user2)
+{
+ if ( !user1 && !user2 ) return 0;
+ else if ( !user1 ) return 1;
+ else if ( !user2 ) return -1;
+
+ if ( user1->BattleStatus().IsBot() )
+ {
+ wxString ailib1 = user1->BattleStatus().aishortname.Upper() + _T(" ") + user1->BattleStatus().aiversion.Upper();
+ if ( user2->BattleStatus().IsBot() )
+ {
+ wxString ailib2 = user2->BattleStatus().aishortname.Upper() + _T(" ") + user2->BattleStatus().aiversion.Upper();
+ if ( ailib1 < ailib2 )
+ return -1;
+ if ( ailib1 > ailib2 )
+ return 1;
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ else
+ {
+ int cpu1 = user1->GetCpu();
+ if ( user1->BattleStatus().IsBot() )
+ {
+ return -1;
+ } else {
+ int cpu2 = user2->GetCpu();
+ if ( cpu1 < cpu2 )
+ return -1;
+ if ( cpu1 > cpu2 )
+ return 1;
+ return 0;
+ }
+ }
+}
+
+int BattleroomListCtrl::CompareHandicap(const DataType user1, const DataType user2)
+{
+ int handicap1;
+ if ( user1->BattleStatus().spectator )
+ handicap1 = 1000;
+ else
+ handicap1 = user1->BattleStatus().handicap;
+
+ int handicap2;
+ if ( user2->BattleStatus().spectator )
+ handicap2 = 1000;
+ else
+ handicap2 = user2->BattleStatus().handicap;
+
+ if ( handicap1 < handicap2 )
+ return -1;
+ if ( handicap1 > handicap2 )
+ return 1;
+
+ return 0;
+}
+
+void BattleroomListCtrl::SetTipWindowText( const long item_hit, const wxPoint& position)
+{
+ if ( item_hit < 0 || item_hit >= (long)m_data.size() )
+ return;
+
+ const User& user = *GetDataFromIndex( item_hit );
+
+ int column = getColumnFromPosition( position );
+ if (column > (int)m_colinfovec.size() || column < 0)
+ {
+ m_tiptext = _T("");
+ }
+ else
+ {
+ switch (column)
+ {
+ case 0: // is bot?
+ m_tiptext = _("");
+
+ if ( user.BattleStatus().IsBot() )
+ m_tiptext += _("AI (bot)\n");
+ else
+ m_tiptext += _("Human\n");
+
+ if ( user.BattleStatus().spectator )
+ m_tiptext += _("Spectator\n");
+ else
+ m_tiptext += _("Player\n");
+
+ if ( m_battle->IsFounder( user ) )
+ m_tiptext += _("Host\n");
+ else
+ m_tiptext += _("Client\n");
+
+ if ( user.BattleStatus().ready )
+ m_tiptext += _("Ready\n");
+ else
+ m_tiptext += _("Not ready\n");
+
+ if ( user.BattleStatus().sync == SYNC_SYNCED )
+ m_tiptext += _("In sync");
+ else
+ m_tiptext += _("Not in sync");
+ break;
+ case 1: // icon
+ if ( user.BattleStatus().spectator )
+ m_tiptext = _T("Spectators have no side");
+ else
+ {
+ wxArrayString sides = usync().GetSides( m_battle->GetHostModName() );
+ int side = user.BattleStatus().side;
+ if ( side < (int)sides.GetCount() ) m_tiptext = sides[side];
+ }
+ break;
+
+ case 3: // country
+ m_tiptext = user.BattleStatus().IsBot() ? _T("This bot is from nowhere particular") : GetFlagNameFromCountryCode(user.GetCountry());
+ break;
+ case 4: // rank
+ m_tiptext = user.BattleStatus().IsBot() ? _T("This bot has no rank") : user.GetRankName(user.GetStatus().rank);
+ break;
+
+ case 5: //name
+ m_tiptext = user.BattleStatus().IsBot() ?user.GetNick() : user.GetNick();
+ break;
+
+ case 8: // cpu
+ m_tiptext = user.BattleStatus().IsBot() ? ( user.BattleStatus().aishortname + _T(" ") + user.BattleStatus().aiversion ) : m_colinfovec[column].tip;
+ break;
+
+ default:
+ m_tiptext =m_colinfovec[column].tip;
+ break;
+ }
+ }
+}
+
+void BattleroomListCtrl::OnUserMenuAddToGroup( wxCommandEvent& event )
+{
+ int id = event.GetId() - GROUP_ID;
+ wxString groupname = m_popup->GetGroupByEvtID(id);
+ wxString nick = GetSelectedUserNick();
+ useractions().AddUserToGroup( groupname, nick );
+}
+
+void BattleroomListCtrl::OnUserMenuDeleteFromGroup( wxCommandEvent& /*unused*/ )
+{
+ wxString nick = GetSelectedUserNick();
+ useractions().RemoveUser( nick );
+}
+
+void BattleroomListCtrl::OnUserMenuCreateGroup( wxCommandEvent& /*unused*/ )
+{
+ wxString name;
+ if ( ui().AskText( _("Enter name"),
+ _("Please enter the name for the new group.\nAfter clicking ok you will be taken to adjust its settings."), name ) )
+ {
+ wxString nick = GetSelectedUserNick();
+
+ useractions().AddGroup( name );
+ useractions().AddUserToGroup( name, nick );
+ ui().mw().ShowConfigure( MainWindow::OPT_PAGE_GROUPS );
+ }
+}
+
+wxString BattleroomListCtrl::GetSelectedUserNick()
+{
+ if ( m_selected_index < 0 || m_selected_index >= (long)m_data.size() )
+ return wxEmptyString;
+ else
+ return m_data[m_selected_index]->GetNick();
+}
+
+void BattleroomListCtrl::OnActivateItem( wxListEvent& /*unused*/ )
+{
+ if ( m_ro )
+ return;
+ if ( m_selected_index < 0 || m_selected_index >= (long)m_data.size() )
+ return;
+
+ const User* usr = m_data[m_selected_index];
+ if ( usr != NULL && !usr->BattleStatus().IsBot() )
+ ui().mw().OpenPrivateChat( *usr );
+}
+
+int BattleroomListCtrl::GetIndexFromData(const DataType& data) const
+{
+ const User* user = data;
+ static long seekpos;
+ seekpos = clamp( seekpos, 0l , (long)m_data.size() );
+ int index = seekpos;
+
+ for ( DataCIter f_idx = m_data.begin() + seekpos; f_idx != m_data.end() ; ++f_idx )
+ {
+ if ( user == *f_idx )
+ {
+ seekpos = index;
+ return seekpos;
+ }
+ index++;
+ }
+ //it's ok to init with seekpos, if it had changed this would not be reached
+ int r_index = seekpos - 1;
+ for ( DataRevCIter r_idx = m_data.rbegin() + ( m_data.size() - seekpos ); r_idx != m_data.rend() ; ++r_idx )
+ {
+ if ( user == *r_idx )
+ {
+ seekpos = r_index;
+ return seekpos;
+ }
+ r_index--;
+ }
+
+ return -1;
+}
+
diff --git a/src/battleroomlistctrl.h b/src/battleroomlistctrl.h
new file mode 100644
index 0000000..e997e15
--- /dev/null
+++ b/src/battleroomlistctrl.h
@@ -0,0 +1,125 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLEROOMLISTCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLEROOMLISTCTRL_H
+
+#include "customvirtlistctrl.h"
+#include "usermenu.h"
+
+class User;
+class IBattle;
+class Ui;
+struct BattleBot;
+class wxIcon;
+
+/** \brief display participants of battle and their info (ally,team,color,cpu...)
+ * \todo DOCMEMORE */
+class BattleroomListCtrl : public CustomVirtListCtrl< User *, BattleroomListCtrl >
+{
+ public:
+ BattleroomListCtrl( wxWindow* parent, IBattle* battle, Ui& ui, bool readonly );
+ ~BattleroomListCtrl();
+
+ void SetBattle( IBattle* battle );
+ IBattle& GetBattle();
+
+ void AddUser( User& user );
+ void RemoveUser( User& user );
+ void UpdateUser( const int& index );
+ void UpdateUser( User& user );
+ void UpdateList();
+
+ int GetIndexFromData( const DataType& data ) const;
+
+ void OnListRightClick( wxListEvent& event );
+ void OnColClick( wxListEvent& event );
+ void OnTeamSelect( wxCommandEvent& event );
+ void OnAllySelect( wxCommandEvent& event );
+ void OnColourSelect( wxCommandEvent& event );
+ void OnSideSelect( wxCommandEvent& event );
+ void OnHandicapSelect( wxCommandEvent& event );
+ void OnSpecSelect( wxCommandEvent& event );
+ void OnActivateItem( wxListEvent& event );
+
+ void OnKickPlayer( wxCommandEvent& event );
+ void OnRingPlayer( wxCommandEvent& event );
+ void OnUserMenuCreateGroup( wxCommandEvent& event );
+ void OnUserMenuDeleteFromGroup( wxCommandEvent& event );
+ void OnUserMenuAddToGroup( wxCommandEvent& event );
+ virtual void SetTipWindowText( const long item_hit, const wxPoint& position);
+
+ wxString GetItemText(long item, long column) const;
+ int GetItemColumnImage(long item, long column) const;
+ wxListItemAttr * GetItemAttr(long item) const;
+
+ protected:
+ static int CompareStatus(const DataType user1, const DataType user2, const IBattle* m_battle );
+ static int CompareSide(const DataType user1, const DataType user2);
+ static int CompareColor(const DataType user1, const DataType user2);
+ static int CompareRank(const DataType user1, const DataType user2);
+ static int CompareTeam(const DataType user1, const DataType user2);
+ static int CompareAlly(const DataType user1, const DataType user2);
+ static int CompareCpu(const DataType user1, const DataType user2);
+ static int CompareHandicap(const DataType user1, const DataType user2);
+
+// wxString GetCellContentsString( long row_number, int column );
+
+ wxString GetSelectedUserNick();
+
+ IBattle* m_battle;
+ static IBattle* s_battle;
+
+ typedef SL_GENERIC::UserMenu<BattleroomListCtrl> UserMenu;
+ UserMenu* m_popup;
+
+ User* m_sel_user;
+
+ wxMenu* m_sides;
+ wxMenuItem* m_spec_item;
+
+ wxMenuItem* m_handicap_item;
+
+ static int CompareOneCrit( DataType u1, DataType u2, int col, int dir ) ;
+
+ Ui& m_ui;
+
+ virtual void Sort();
+
+ bool m_ro;
+
+ enum {
+ BRLIST_LIST = wxID_HIGHEST,
+ BRLIST_TEAM,
+ BRLIST_ALLY = BRLIST_TEAM + 1000,
+ BRLIST_COLOUR = BRLIST_ALLY + 1000,
+ BRLIST_SIDE = BRLIST_COLOUR +1000,
+ BRLIST_HANDICAP = BRLIST_SIDE +1000,
+ BRLIST_SPEC,
+ BRLIST_KICK,
+ BRLIST_RING,
+ BRLIST_ADDTOGROUP
+ };
+
+ DECLARE_EVENT_TABLE();
+
+};
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLEROOMLISTCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battleroommmoptionstab.cpp b/src/battleroommmoptionstab.cpp
new file mode 100644
index 0000000..69ef687
--- /dev/null
+++ b/src/battleroommmoptionstab.cpp
@@ -0,0 +1,578 @@
+
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/checkbox.h>
+#include <wx/slider.h>
+#include <wx/combobox.h>
+#include <wx/stattext.h>
+#include <wx/choicdlg.h>
+#include <wx/defs.h>
+#include <wx/intl.h>
+#include <wx/button.h>
+#include <wx/tipwin.h>
+#include <wx/tooltip.h>
+#include <map>
+
+#include "utils/controls.h"
+#include "utils/math.h"
+#include "mmoptionswrapper.h"
+#include "battle.h"
+#include "spinctld.h"
+#include "settings++/custom_dialogs.h"
+#include "server.h"
+#include "settings.h"
+#include "ui.h"
+#include "aui/auimanager.h"
+
+
+const char sep = *("_");
+const wxString wxsep = _T("_");
+
+BEGIN_EVENT_TABLE_TEMPLATE1( BattleroomMMOptionsTab, wxPanel, BattleType)
+ EVT_COMBOBOX (wxID_ANY, BattleroomMMOptionsTab::OnComBoxChange)
+ EVT_CHECKBOX (wxID_ANY, BattleroomMMOptionsTab::OnChkBoxChange)
+ EVT_TEXT_ENTER (wxID_ANY, BattleroomMMOptionsTab::OnTextCtrlChange)
+ EVT_SPINCTRL (wxID_ANY, BattleroomMMOptionsTab::OnSpinCtrlChange)
+
+// EVT_BUTTON( BOPTS_LOADPRES, BattleroomMMOptionsTab::OnLoadPreset )
+// EVT_BUTTON( BOPTS_SAVEPRES, BattleroomMMOptionsTab::OnSavePreset )
+// EVT_BUTTON( BOPTS_DELETEPRES, BattleroomMMOptionsTab::OnDeletePreset )
+// EVT_BUTTON( BOPTS_SETDEFAULTPRES, BattleroomMMOptionsTab::OnSetModDefaultPreset )
+ EVT_BUTTON( wxID_ANY, BattleroomMMOptionsTab::OnButton )
+
+END_EVENT_TABLE()
+
+template < class BattleType >
+BattleroomMMOptionsTab<BattleType>::BattleroomMMOptionsTab( BattleType& battle, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style )
+: wxScrolledWindow( parent, id, pos, size, style | wxHSCROLL ),m_battle(battle)
+{
+
+ GetAui().manager->AddPane( this, wxLEFT, _T("battleroommmoptionstab") );
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxStaticBoxSizer* m_preset_sizer;
+ m_preset_sizer = new wxStaticBoxSizer( new wxStaticBox( this, -1, _("Manage Presets") ), wxHORIZONTAL );
+
+ m_options_preset_sel = new wxComboBox( this, BOPTS_CHOSEPRES, sett().GetModDefaultPresetName( m_battle.GetHostModName() ), wxDefaultPosition, wxDefaultSize, sett().GetPresetList(), wxCB_READONLY );
+ m_options_preset_sel->SetToolTip(TE(_("Set name.")));
+
+ m_preset_sizer->Add( m_options_preset_sel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ m_load_btn = new wxButton( this, BOPTS_LOADPRES, _("Load..."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_load_btn->SetToolTip( TE(_("Load a saved set of options.")) );
+
+ m_preset_sizer->Add( m_load_btn, 0, wxALL, 5 );
+
+ m_save_btn = new wxButton( this, BOPTS_SAVEPRES, _("Save..."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_save_btn->SetToolTip( TE(_("Save a set of options.")) );
+
+ m_preset_sizer->Add( m_save_btn, 0, wxALL, 5 );
+
+ m_delete_btn = new wxButton( this, BOPTS_DELETEPRES, _("Delete..."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_delete_btn->SetToolTip( TE(_("Delete a set of options.")) );
+
+ m_preset_sizer->Add( m_delete_btn, 0, wxALL, 5 );
+
+ m_default_btn = new wxButton( this, BOPTS_SETDEFAULTPRES, _("Set default..."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_default_btn->SetToolTip( TE(_("Use the current set of options as mod's default.")) );
+
+ m_preset_sizer->Add( m_default_btn, 0, wxALL, 5 );
+
+ m_preset_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+ m_map_mod_container = new wxBoxSizer( wxVERTICAL );
+
+ m_mod_options_sizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Mod Options") ), wxVERTICAL );
+ m_mod_layout = new wxBoxSizer( wxVERTICAL);
+ setupOptionsSizer(m_mod_layout,OptionsWrapper::ModOption);
+ m_mod_options_sizer->Add( m_mod_layout, 1, wxEXPAND, 5 );
+
+ m_map_options_sizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Map Options") ), wxVERTICAL );
+ m_map_layout = new wxBoxSizer( wxVERTICAL);
+ setupOptionsSizer(m_map_layout,OptionsWrapper::MapOption);
+ m_map_options_sizer->Add( m_map_layout, 1, wxEXPAND, 5 );
+
+
+ m_main_sizer->Add( m_preset_sizer, 0, wxALL|wxEXPAND, 5 );
+ m_map_mod_container->Add( m_mod_options_sizer, 0, wxALL|wxEXPAND, 5 );
+ m_map_mod_container->Add( m_map_options_sizer, 0, wxALL|wxEXPAND, 5 );
+ m_main_sizer->Add( m_map_mod_container, 1, wxALL|wxEXPAND, 5 );
+
+
+ //m_main_sizer->FitInside(this);
+
+
+ this->SetSizer( m_main_sizer );
+ this->Layout();
+
+ if ( !m_battle.IsFounderMe() )
+ {
+ m_options_preset_sel->Disable();
+ m_load_btn->Disable();
+ m_save_btn->Disable();
+ m_delete_btn->Disable();
+ m_default_btn->Disable();
+ }
+
+ SetScrollRate( 4, 4 );
+}
+
+template < class BattleType >
+BattleroomMMOptionsTab<BattleType>::~BattleroomMMOptionsTab()
+{
+ if(GetAui().manager)GetAui().manager->DetachPane( this );
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::setupOptionsSizer( wxBoxSizer* parent_sizer, OptionsWrapper::GameOption optFlag )
+{
+ const IUnitSync::OptionMapSection& sections = m_battle.CustomBattleOptions().m_opts[optFlag].section_map;
+
+ unsigned int num_options = 0;
+ IUnitSync::OptionMapSectionConstIter it = sections.begin();
+ for ( ; it != sections.end(); ++it )
+ {
+ wxStaticBoxSizer* section_sizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, it->second.name ), wxVERTICAL );
+ //only add non-empty sizer
+ if ( setupOptionsSectionSizer( it->second, section_sizer, optFlag ) ) {
+ parent_sizer->Add( section_sizer, 0 , wxALL, section_sizer->GetChildren().size() > 0 ? 5 : 0 );
+ num_options++;
+ }
+ else
+ delete section_sizer;
+ }
+
+ //adds options with no asociated section
+ mmOptionSection dummy;
+ wxBoxSizer* section_sizer = new wxBoxSizer( wxVERTICAL );
+ if ( setupOptionsSectionSizer( dummy, section_sizer, optFlag ) == 0 ) {
+ if ( num_options == 0 ) {
+ wxString name = wxString::Format( _T("%d"),optFlag) + wxsep + _T("no_opts");
+ wxStaticText* none_found = new wxStaticText( this, wxID_ANY, _("no options available"),
+ wxDefaultPosition, wxDefaultSize, 0, name );
+ m_statictext_map[name] = none_found;
+ parent_sizer->Add( none_found, 0, wxALL, 3 );
+ }
+ }
+ else {
+ wxStaticBoxSizer* other_section = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("other") ), wxVERTICAL );
+ other_section->Add( section_sizer, 0 , wxALL, section_sizer->GetChildren().size() > 0 ? 5 : 0 );
+ parent_sizer->Add( other_section, 0 , wxALL, 0 );
+ }
+
+}
+
+template < class BattleType >
+wxButton* BattleroomMMOptionsTab<BattleType>::getButton( const wxWindowID id, const wxString& name )
+{
+ m_button_map[name] = new wxButton(this, id + BUTTON_ID_OFFSET, _T("?"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT, wxDefaultValidator, name );
+ return m_button_map[name];
+}
+
+template < class BattleType >
+int BattleroomMMOptionsTab<BattleType>::setupOptionsSectionSizer(const mmOptionSection& section,
+ wxBoxSizer* parent_sizer, OptionsWrapper::GameOption optFlag)
+{
+ const int col_gap = 35;
+ wxString pref = wxString::Format( _T("%d"),optFlag) + wxsep;
+ OptionsWrapper optWrap = m_battle.CustomBattleOptions();
+ bool enable = m_battle.IsFounderMe();
+ wxFlexGridSizer* cbxSizer = new wxFlexGridSizer( 4, 2, 10, 10 );
+ wxFlexGridSizer* spinSizer = new wxFlexGridSizer( 4, 10, 10 );
+ wxFlexGridSizer* textSizer = new wxFlexGridSizer( 4, 10, 10 );
+ wxFlexGridSizer* chkSizer = new wxFlexGridSizer( 4, 10, 10 );
+
+ const int b_gap = 1;
+
+ int total_count = 0;
+ int ctrl_count = 0;
+ for (IUnitSync::OptionMapBoolIter i = optWrap.m_opts[optFlag].bool_map.begin(); i != optWrap.m_opts[optFlag].bool_map.end();++i)
+ {
+ if ( i->second.section == section.key )
+ {
+ mmOptionBool current = i->second;
+ wxCheckBox* temp = new wxCheckBox(this,BOOL_START_ID+ctrl_count,current.name);
+ temp->SetToolTip(TE(current.description));
+ m_name_info_map[pref+current.key] = current.description;
+ temp->SetName(pref+current.key);
+ m_chkbox_map[pref+current.key] = temp;
+ temp->SetValue(current.value);
+ temp->Enable(enable);
+ wxBoxSizer* ct_sizer = new wxBoxSizer( wxHORIZONTAL );
+ ct_sizer->Add(temp, 0, wxRIGHT| wxALIGN_CENTER_VERTICAL, b_gap);
+ ct_sizer->Add(getButton(BOOL_START_ID+ctrl_count,pref+current.key), 0, wxRIGHT| wxALIGN_CENTER_VERTICAL, col_gap);
+ chkSizer->Add( ct_sizer );
+ ctrl_count++;
+ }
+ }
+
+ total_count += ctrl_count;
+ ctrl_count = 0;
+ for ( IUnitSync::OptionMapFloatIter it = optWrap.m_opts[optFlag].float_map.begin(); it != optWrap.m_opts[optFlag].float_map.end(); ++it)
+ {
+ wxString seckey = it->second.section;
+ wxString kkey = section.key ;
+ if ( it->second.section == section.key )
+ {
+ mmOptionFloat current = it->second;
+ wxSpinCtrlDbl* tempspin = new wxSpinCtrlDbl();
+ tempspin->Create(this, FLOAT_START_ID+ctrl_count, _T(""),
+ wxDefaultPosition, wxDefaultSize, 0, double(current.min), double(current.max),
+ double(current.value),double(current.stepping), wxSPINCTRLDBL_AUTODIGITS, current.key);
+ tempspin->SetToolTip(TE(current.description));
+ m_name_info_map[pref+current.key] = current.description;
+ tempspin->Enable(enable);
+ tempspin->SetName(pref+current.key);
+ m_spinctrl_map[pref+current.key] = tempspin;
+ wxStaticText* tempst = new wxStaticText(this,-1,current.name);
+ m_statictext_map[pref+current.key] = tempst;
+ spinSizer->Add(tempst,0, wxALIGN_CENTER_VERTICAL);
+ wxBoxSizer* ct_sizer = new wxBoxSizer( wxHORIZONTAL );
+ ct_sizer->Add(tempspin, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, b_gap);
+ ct_sizer->Add(getButton(FLOAT_START_ID+ctrl_count,pref+current.key), 0, wxRIGHT , col_gap);
+ spinSizer->Add( ct_sizer );
+ ctrl_count++;
+ }
+ }
+
+ total_count += ctrl_count;
+ ctrl_count = 0;
+ for ( IUnitSync::OptionMapListIter it = optWrap.m_opts[optFlag].list_map.begin(); it != optWrap.m_opts[optFlag].list_map.end(); ++it)
+ {
+ if ( it->second.section == section.key )
+ {
+ mmOptionList current = it->second;
+
+ int temp = int(current.cbx_choices.GetCount()-1);
+ int index = clamp(current.cur_choice_index,0,temp);
+ wxComboBox* tempchoice = new wxComboBox(this, LIST_START_ID+ctrl_count, current.cbx_choices[index], wxDefaultPosition,
+ wxDefaultSize, current.cbx_choices, wxCB_READONLY, wxDefaultValidator);
+ wxString tooltip = current.description + _T("\n");
+ for ( ListItemVec::iterator itor = current.listitems.begin(); itor != current.listitems.end(); itor++ )
+ {
+ tooltip+= _T("\n") + itor->name + _T(": ") + itor->desc;
+ }
+ tempchoice->SetToolTip(TE(tooltip));
+ m_name_info_map[pref+current.key] = tooltip;
+ tempchoice->SetName(pref+current.key);
+ tempchoice->Enable(enable);
+ m_combox_map[pref+current.key] = tempchoice;
+ wxStaticText* tempst = new wxStaticText(this,-1,current.name);
+ m_statictext_map[pref+current.key] = tempst;
+ cbxSizer->Add(tempst,0, wxALIGN_CENTER_VERTICAL);
+ wxBoxSizer* ct_sizer = new wxBoxSizer( wxHORIZONTAL );
+ ct_sizer->Add(tempchoice, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, b_gap);
+ ct_sizer->Add(getButton(LIST_START_ID+ctrl_count,pref+current.key), 0, wxRIGHT, col_gap);
+ cbxSizer->Add( ct_sizer );
+
+ ctrl_count++;
+ }
+ }
+
+ total_count += ctrl_count;
+ ctrl_count = 0;
+ for ( IUnitSync::OptionMapStringIter it = optWrap.m_opts[optFlag].string_map.begin(); it != optWrap.m_opts[optFlag].string_map.end(); ++it)
+ {
+ if ( it->second.section == section.key )
+ {
+ mmOptionString current = it->second;
+ wxTextCtrl* temptext = new wxTextCtrl(this, STRING_START_ID+ctrl_count, current.value, wxDefaultPosition,
+ wxDefaultSize, 0, wxDefaultValidator, current.key);
+ temptext->SetToolTip(TE(current.description));
+ m_name_info_map[pref+current.key] = current.description;
+ temptext->SetName(pref+current.key);
+ temptext->Enable(enable);
+ m_textctrl_map[pref+current.key] = temptext;
+ wxStaticText* tempst = new wxStaticText(this,-1,current.name);
+ m_statictext_map[pref+current.key] = tempst;
+ textSizer->Add(tempst,0, wxALIGN_CENTER_VERTICAL);
+ wxBoxSizer* ct_sizer = new wxBoxSizer( wxHORIZONTAL );
+ ct_sizer->Add(temptext,0, wxALIGN_CENTER_VERTICAL | wxRIGHT, b_gap);
+ ct_sizer->Add(getButton(STRING_START_ID+ctrl_count,pref+current.key),0, wxRIGHT, col_gap);
+ textSizer->Add( ct_sizer );
+
+ ctrl_count++;
+ }
+ }
+ total_count += ctrl_count;
+
+ parent_sizer->Add( chkSizer, 0, wxALL, chkSizer->GetChildren().size() > 0 ? 5 : 0 );
+ parent_sizer->Add( spinSizer, 0, wxALL, spinSizer->GetChildren().size() > 0 ? 5 : 0 );
+ parent_sizer->Add( cbxSizer, 0, wxALL, cbxSizer->GetChildren().size() > 0 ? 5 : 0 );
+ parent_sizer->Add( textSizer, 0, wxALL, textSizer->GetChildren().size() > 0 ? 5 : 0 );
+
+ return total_count;
+
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnChkBoxChange(wxCommandEvent& event)
+{
+ wxCheckBox* box = (wxCheckBox*) event.GetEventObject();
+ wxString key = (box->GetName()).AfterFirst(sep);
+ long gameoption ;
+ box->GetName().BeforeFirst(sep).ToLong(&gameoption);
+
+ if( m_battle.CustomBattleOptions().setSingleOption( key , (box->GetValue() ? _T("1") : _T("0")) , (OptionsWrapper::GameOption)gameoption ) )
+ {
+ if (m_battle.IsFounderMe())
+ {
+ m_battle.SendHostInfo( (wxString()<<gameoption) + wxsep + key );
+ }
+ }
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnComBoxChange(wxCommandEvent& event)
+{
+ wxComboBox* box = (wxComboBox*) event.GetEventObject();
+
+ wxString key = (box->GetName()).AfterFirst(sep);
+ long gameoption;
+ box->GetName().BeforeFirst(sep).ToLong(&gameoption);
+ wxString itemKey = m_battle.CustomBattleOptions().GetNameListOptItemKey(key, box->GetValue(), (OptionsWrapper::GameOption)gameoption );
+
+ if(m_battle.CustomBattleOptions().setSingleOption( key, itemKey, (OptionsWrapper::GameOption)gameoption ) )
+ {
+ if (m_battle.IsFounderMe())
+ {
+ m_battle.SendHostInfo( (wxString()<< gameoption) + wxsep + key );
+ }
+ }
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnTextCtrlChange(wxCommandEvent& event)
+{
+ wxTextCtrl* box = (wxTextCtrl*) event.GetEventObject();
+ wxString key = (box->GetName()).AfterFirst(sep);
+ long gameoption;
+ box->GetName().BeforeFirst(sep).ToLong(&gameoption);
+ if(m_battle.CustomBattleOptions().setSingleOption( key, box->GetValue(), (OptionsWrapper::GameOption)gameoption ) )
+ {
+ if (m_battle.IsFounderMe())
+ {
+ m_battle.SendHostInfo( (wxString()<< gameoption) + wxsep + key );
+ }
+
+ }
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnSpinCtrlChange(wxSpinEvent& event)
+{
+ wxSpinCtrlDbl* box = (wxSpinCtrlDbl*) event.GetEventObject();
+ wxString key = (box->GetName()).AfterFirst(sep);
+ long gameoption;
+ box->GetName().BeforeFirst(sep).ToLong(&gameoption);
+ if(m_battle.CustomBattleOptions().setSingleOption( key,wxString::Format( _T("%f"),box->GetValue() ), (OptionsWrapper::GameOption)gameoption ) )
+ {
+ if (m_battle.IsFounderMe())
+ {
+ m_battle.SendHostInfo( (wxString()<< gameoption) + wxsep + key );
+ }
+ }
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::UpdateOptControls(wxString controlName)
+{
+ long gameoption;
+ controlName.BeforeFirst(sep).ToLong(&gameoption);
+ wxString optKey = controlName.AfterFirst(sep);
+
+ if ( gameoption == OptionsWrapper::PrivateOptions )
+ {
+ if ( optKey == _T("mapname") ) OnReloadControls( OptionsWrapper::MapOption );
+ if ( optKey == _T("modname") ) OnReloadControls( OptionsWrapper::ModOption );
+ return;
+ }
+
+ if ( m_chkbox_map.find(controlName) != m_chkbox_map.end() )
+ {
+ wxString value = m_battle.CustomBattleOptions().getSingleValue( optKey, (OptionsWrapper::GameOption)gameoption );
+ wxCheckBox* cur = m_chkbox_map[controlName] ;
+ long l_val;
+ value.ToLong(&l_val);
+ cur->SetValue(l_val);
+ }
+
+ if ( m_combox_map.find(controlName) != m_combox_map.end() )
+ {
+ wxString value = m_battle.CustomBattleOptions().getSingleValue( optKey, (OptionsWrapper::GameOption)gameoption );
+ wxComboBox* cur = m_combox_map[controlName];
+ cur->SetValue(m_battle.CustomBattleOptions().GetNameListOptValue( optKey, (OptionsWrapper::GameOption)gameoption));
+ }
+
+ if ( m_textctrl_map.find(controlName) != m_textctrl_map.end() )
+ {
+ wxString value = m_battle.CustomBattleOptions().getSingleValue( optKey, (OptionsWrapper::GameOption)gameoption );
+ wxTextCtrl* cur = m_textctrl_map[controlName];
+ cur->SetValue(value);
+ }
+
+ if ( m_spinctrl_map.find(controlName) != m_spinctrl_map.end() )
+ {
+ wxString value = m_battle.CustomBattleOptions().getSingleValue( optKey, (OptionsWrapper::GameOption)gameoption );
+ wxSpinCtrlDbl* cur = m_spinctrl_map[controlName] ;
+ double l_val;
+ value.ToDouble(&l_val);
+ cur->SetValue(l_val);
+ }
+
+}
+
+template<class T>
+void RemovePrefixed(T &v, wxString pref){
+ typename T::iterator it = v.begin();
+ while(it != v.end())
+ {
+ typename T::iterator next = it;
+ ++next;
+ wxString key = it->first;
+ if (key.StartsWith(pref))
+ {
+ delete it->second;
+ v.erase(it);
+ }
+ it=next;
+ }
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnReloadControls(OptionsWrapper::GameOption flag)
+{
+ wxString pref = wxString::Format( _T("%d"),flag) + wxsep;
+
+ //purgin existing keys from map
+ RemovePrefixed(m_chkbox_map,pref);
+ RemovePrefixed(m_spinctrl_map,pref);
+ RemovePrefixed(m_textctrl_map,pref);
+ RemovePrefixed(m_combox_map,pref);
+ RemovePrefixed(m_statictext_map,pref);
+ RemovePrefixed(m_button_map,pref);
+
+ //reloading the controls
+ switch (flag)
+ {
+ case OptionsWrapper::ModOption:
+ m_mod_options_sizer->Remove(m_mod_layout);
+ m_mod_layout = new wxBoxSizer( wxVERTICAL);
+ setupOptionsSizer(m_mod_layout,OptionsWrapper::ModOption);
+ //m_mod_options_sizer->Add( m_mod_options_sizer, 1, wxEXPAND, 5 );
+ m_mod_options_sizer->Add( m_mod_layout, 1, wxALL|wxEXPAND, 5 );
+ break;
+ case OptionsWrapper::MapOption:
+ m_map_options_sizer->Remove(m_map_layout);
+ m_map_layout = new wxBoxSizer( wxVERTICAL);
+ setupOptionsSizer(m_map_layout,OptionsWrapper::MapOption);
+ m_map_options_sizer->Add( m_map_layout, 1, wxALL|wxEXPAND, 5 );
+ break;
+ default:
+ break;
+ }
+
+
+ //this->SetSizer( m_main_sizer, true );
+ m_main_sizer->FitInside(this);
+
+ this->Layout();
+ SetScrollbars( 10, 10, 62, 62 );
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnReloadControls()
+{
+ for ( unsigned int i = 0; i < OptionsWrapper::LastOption; i++)
+ OnReloadControls( (OptionsWrapper::GameOption) i );
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnLoadPreset( wxCommandEvent& /*unused*/ )
+{
+ wxString presetname = m_options_preset_sel->GetValue();
+ if ( presetname.IsEmpty() )
+ {
+ customMessageBoxNoModal( SL_MAIN_ICON , _("Cannot load an options set without a name\nPlease select one from the list and try again."), _("error"), wxICON_EXCLAMATION|wxOK );
+ return;
+ }
+ m_battle.LoadOptionsPreset( presetname );
+ m_battle.SendHostInfo( IBattle::HI_Send_All_opts );
+ OnReloadControls( );
+}
+
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnSavePreset( wxCommandEvent& /*unused*/ )
+{
+ wxString presetname;
+ if ( !ui().AskText( _("Enter preset name"), _("Enter a name to save the current set of options\nIf a preset with the same name already exist, it will be overwritten"), presetname ) )
+ return;
+ if ( presetname.IsEmpty() )
+ {
+ customMessageBoxNoModal( SL_MAIN_ICON , _("Cannot save an options set without a name."), _("error"), wxICON_EXCLAMATION|wxOK );
+ return;
+ }
+ m_battle.SaveOptionsPreset( presetname );
+}
+
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnDeletePreset( wxCommandEvent& /*unused*/ )
+{
+ wxArrayString choices = m_battle.GetPresetList();
+ int result = wxGetSingleChoiceIndex(_("Pick an existing option set from the list"),_("Delete preset"), choices );
+ if ( result < 0 ) return;
+ m_battle.DeletePreset( choices[result] );
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnSetModDefaultPreset( wxCommandEvent& /*unused*/ )
+{
+ wxArrayString choices = m_battle.GetPresetList();
+ int result = wxGetSingleChoiceIndex(_("Pick an existing option set from the list"),_("Set mod default preset"), choices );
+ if ( result < 0 ) return;
+ sett().SetModDefaultPresetName( m_battle.GetHostModName(), choices[result] );
+}
+
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::UpdatePresetList()
+{
+ m_options_preset_sel->Clear();
+ m_options_preset_sel->Append(sett().GetPresetList());
+ m_options_preset_sel->SetStringSelection( m_battle.GetCurrentPreset() );
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnButton( wxCommandEvent& event )
+{
+ switch ( event.GetId() ) {
+ case BOPTS_LOADPRES: OnLoadPreset ( event ); break;
+ case BOPTS_SAVEPRES: OnSavePreset ( event ); break;
+ case BOPTS_DELETEPRES: OnDeletePreset ( event ); break;
+ case BOPTS_SETDEFAULTPRES: OnSetModDefaultPreset ( event ); break;
+ default: OnInfoButton( event ); break;
+
+ }
+
+}
+
+template < class BattleType >
+void BattleroomMMOptionsTab<BattleType>::OnInfoButton( wxCommandEvent& event )
+{
+ #ifdef wxUSE_TIPWINDOW
+ wxWindow* button = (wxWindow*) event.GetEventObject();
+ if ( button ) {
+ nameInfoMap::const_iterator iter = m_name_info_map.find( button->GetName() );
+ if ( iter != m_name_info_map.end() ) {
+ //needs to be moved a little away from cursor pos
+ wxPoint pos = wxGetMousePosition();
+ wxTipWindow* tip = new wxTipWindow ( this, iter->second , 1000 );
+ tip->Move( pos.x, pos.y - tip->GetSize().GetHeight() );
+ }
+ }
+ #endif
+}
+
diff --git a/src/battleroommmoptionstab.h b/src/battleroommmoptionstab.h
new file mode 100644
index 0000000..507089f
--- /dev/null
+++ b/src/battleroommmoptionstab.h
@@ -0,0 +1,150 @@
+#ifndef BATTLEROOMMMOPTIONSTAB_H_
+#define BATTLEROOMMMOPTIONSTAB_H_
+
+#include <wx/scrolwin.h>
+#include <map>
+#include "mmoptionswrapper.h"
+
+const int BOOL_START_ID = 3000;
+const int FLOAT_START_ID = 4000;
+const int LIST_START_ID = 5000;
+const int STRING_START_ID = 6000;
+const int BUTTON_ID_OFFSET = 7000;
+
+class wxBoxSizer;
+class wxStaticBoxSizer;
+class OptionsWrapper;
+class wxCheckBox;
+class wxComboBox;
+class wxCommandEvent;
+class Battle;
+class wxSpinCtrlDbl;
+class wxTextCtrl;
+class wxSpinEvent;
+class wxStaticText;
+class wxButton;
+
+//totally ok to store pointers here, since wx takes care of gui element destruction for us
+typedef std::map<wxString,wxCheckBox*> chkBoxMap;
+typedef std::map<wxString,wxComboBox*> comboBoxMap;
+typedef std::map<wxString,wxSpinCtrlDbl*> spinCtrlMap;
+typedef std::map<wxString,wxTextCtrl*> textCtrlMap;
+typedef std::map<wxString,wxStaticText*> staticTextMap;
+typedef std::map<wxString,wxButton*> buttonMap;
+typedef std::map<wxString,wxString> nameInfoMap; //! map control name <-> info (description)
+
+/** \brief a panel displaying programmatically generated gui elements to manipulate mmOptions
+ * Since storing of data is mixed in with gui elements, this is a very delicate place to apply changes to.
+ * If there's ever any need / desire to refactor this, EXTENSIVE testing should be applied afterwards! \n
+ * There's one map per control type, storing the mapping between name and pointer, where name has the format
+ * optionFlag (decimal) + seperator + mmOptionKey \n
+ * That way we can use the inverse mapping in the event handlers to go from the name of event-generating gui element
+ * to the mmOptionKey that needs to be changed.
+ */
+template < class BattleType >
+class BattleroomMMOptionsTab : public wxScrolledWindow
+{
+ public:
+ BattleroomMMOptionsTab( BattleType& battle, wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500,300 ), long style = wxTAB_TRAVERSAL );
+ ~BattleroomMMOptionsTab();
+
+ void UpdateOptControls(wxString controlName);
+ //!relaod single category
+ void OnReloadControls(OptionsWrapper::GameOption flag);
+ //!reload all categories
+ void OnReloadControls();
+
+ void UpdatePresetList();
+
+ void OnButton( wxCommandEvent& event );
+ void OnLoadPreset( wxCommandEvent& event );
+ void OnSavePreset( wxCommandEvent& event );
+ void OnDeletePreset( wxCommandEvent& event );
+ void OnSetModDefaultPreset( wxCommandEvent& event );
+ void OnInfoButton( wxCommandEvent& event );
+
+ protected:
+ BattleType& m_battle;
+
+ wxBoxSizer* m_main_sizer;
+ wxStaticBoxSizer* m_mod_options_sizer;
+ wxBoxSizer* m_mod_layout;
+ wxStaticBoxSizer* m_map_options_sizer;
+ wxBoxSizer* m_map_layout;
+ wxBoxSizer* m_map_mod_container;
+
+ wxButton* m_load_btn;
+ wxButton* m_save_btn;
+ wxButton* m_delete_btn;
+ wxButton* m_default_btn;
+ wxComboBox* m_options_preset_sel;
+
+ OptionsWrapper* m_mapmodoptions;
+
+ chkBoxMap m_chkbox_map;
+ comboBoxMap m_combox_map;
+ spinCtrlMap m_spinctrl_map;
+ textCtrlMap m_textctrl_map;
+ staticTextMap m_statictext_map;
+ buttonMap m_button_map;
+ nameInfoMap m_name_info_map;
+
+ /** \brief setup toplevel sizer per GameOption with all child sizers ( sections )
+ */
+ void setupOptionsSizer( wxBoxSizer* parent_sizer, OptionsWrapper::GameOption optFlag );
+
+
+ /** \brief generate Gui elements from loaded MMoptions
+ * for all values in all option maps create a control (pointer),
+ * set the controls name to the option key and add it to the appropiate map and sizer.
+ * \return the total num of controls in the sizer
+ */
+ int setupOptionsSectionSizer(const mmOptionSection& section, wxBoxSizer* parent_sizer, OptionsWrapper::GameOption optFlag);
+
+ /** \name Event handlers
+ * @{
+ * one event handler per gui element type \n
+ * these trigger a SendHostInfo(key) for the changed option
+ */
+ void OnComBoxChange(wxCommandEvent&);
+ void OnChkBoxChange(wxCommandEvent&);
+ void OnTextCtrlChange(wxCommandEvent& event);
+ void OnSpinCtrlChange(wxSpinEvent& event);
+ /** @} */
+
+ wxButton* getButton( const wxWindowID id, const wxString& name );
+
+
+ DECLARE_EVENT_TABLE();
+};
+
+enum
+{
+ BOPTS_LOADPRES = wxID_HIGHEST,
+ BOPTS_SAVEPRES,
+ BOPTS_DELETEPRES,
+ BOPTS_SETDEFAULTPRES,
+ BOPTS_CHOSEPRES
+};
+
+#include "battleroommmoptionstab.cpp"
+
+#endif /*BATTLEROOMMMOPTIONSTAB_H_*/
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/battleroomtab.cpp b/src/battleroomtab.cpp
new file mode 100644
index 0000000..68b8755
--- /dev/null
+++ b/src/battleroomtab.cpp
@@ -0,0 +1,991 @@
+/* Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: BattleRoomTab
+//
+
+#include <wx/splitter.h>
+#include <wx/intl.h>
+#include <wx/combobox.h>
+#include <wx/stattext.h>
+#include <wx/statbox.h>
+#include <wx/statline.h>
+#include <wx/checkbox.h>
+#include <wx/button.h>
+#include <wx/listctrl.h>
+#include <wx/sizer.h>
+#include <wx/msgdlg.h>
+#include <wx/settings.h>
+#include <wx/choicdlg.h>
+#include <wx/colordlg.h>
+#include <wx/colour.h>
+#include <wx/log.h>
+#include <wx/bmpcbox.h>
+#include <wx/image.h>
+#include <wx/choice.h>
+#if wxUSE_TOGGLEBTN
+#include <wx/tglbtn.h>
+#endif
+#include <wx/numdlg.h>
+
+#include <stdexcept>
+
+#include "battleroomtab.h"
+#include "ui.h"
+#include "iunitsync.h"
+#include "user.h"
+#include "battle.h"
+#include "utils/conversion.h"
+#include "utils/debug.h"
+#include "battleroomlistctrl.h"
+#include "chatpanel.h"
+#include "mapctrl.h"
+#include "uiutils.h"
+#include "addbotdialog.h"
+#include "server.h"
+#include "iconimagelist.h"
+#include "settings++/custom_dialogs.h"
+#include "autobalancedialog.h"
+#include "settings.h"
+#include "Helper/colorbutton.h"
+#include "mapselectdialog.h"
+#include "mmoptionwindows.h"
+#include "aui/auimanager.h"
+
+BEGIN_EVENT_TABLE( BattleRoomTab, wxPanel )
+
+ EVT_BUTTON ( BROOM_START, BattleRoomTab::OnStart )
+ EVT_BUTTON ( BROOM_LEAVE, BattleRoomTab::OnLeave )
+ EVT_BUTTON ( BROOM_ADDBOT, BattleRoomTab::OnAddBot )
+
+ EVT_CHECKBOX ( BROOM_IMREADY, BattleRoomTab::OnImReady )
+ EVT_CHECKBOX ( BROOM_SPEC, BattleRoomTab::OnImSpec )
+ EVT_COMBOBOX ( BROOM_TEAMSEL, BattleRoomTab::OnTeamSel )
+ EVT_COMBOBOX ( BROOM_ALLYSEL, BattleRoomTab::OnAllySel )
+ EVT_BUTTON ( BROOM_COLOURSEL, BattleRoomTab::OnColourSel )
+ EVT_COMBOBOX ( BROOM_SIDESEL, BattleRoomTab::OnSideSel )
+
+ EVT_COMBOBOX ( BROOM_PRESETSEL, BattleRoomTab::OnPresetSel )
+ EVT_BUTTON ( BROOM_SAVEPRES, BattleRoomTab::OnSavePreset )
+ EVT_BUTTON ( BROOM_DELETEPRES, BattleRoomTab::OnDeletePreset )
+ EVT_BUTTON ( BROOM_SETDEFAULTPRES, BattleRoomTab::OnSetModDefaultPreset )
+
+ EVT_BUTTON ( BROOM_MAP_BROWSE, BattleRoomTab::OnMapBrowse )
+ EVT_COMBOBOX ( BROOM_MAP_SEL, BattleRoomTab::OnMapSelect )
+
+ EVT_CHECKBOX ( BROOM_LOCK, BattleRoomTab::OnLock )
+ #if wxUSE_TOGGLEBTN
+ EVT_TOGGLEBUTTON ( BROOM_AUTOLOCK, BattleRoomTab::OnAutoLock )
+ #else
+ EVT_CHECKBOX ( BROOM_AUTOLOCK, BattleRoomTab::OnAutoLock )
+ #endif
+
+ EVT_BUTTON ( BROOM_MANAGE_MENU, BattleRoomTab::OnShowManagePlayersMenu )
+
+ EVT_MENU ( BROOM_AUTOHOST, BattleRoomTab::OnAutoHost )
+ EVT_MENU ( BROOM_AUTOSPECT, BattleRoomTab::OnAutoSpec )
+ EVT_MENU ( BROOM_AUTOSTART, BattleRoomTab::OnAutoStart )
+ EVT_MENU ( BROOM_AUTOCONTROL, BattleRoomTab::OnAutoControl )
+
+ EVT_MENU ( BROOM_RING_UNREADY, BattleRoomTab::OnRingUnready )
+ EVT_MENU ( BROOM_RING_UNSYNC, BattleRoomTab::OnRingUnsynced )
+ EVT_MENU ( BROOM_RING_UNREADY_UNSYNC, BattleRoomTab::OnRingUnreadyUnsynced )
+
+ EVT_MENU ( BROOM_SPECT_UNREADY, BattleRoomTab::OnSpectUnready )
+ EVT_MENU ( BROOM_SPECT_UNSYNC, BattleRoomTab::OnSpectUnsynced )
+ EVT_MENU ( BROOM_SPECT_UNREADY_UNSYNC, BattleRoomTab::OnSpectUnreadyUnsynced )
+
+ EVT_MENU ( BROOM_LOCK_BALANCE, BattleRoomTab::OnLockBalance )
+ EVT_MENU ( BROOM_BALANCE, BattleRoomTab::OnBalance )
+ EVT_MENU ( BROOM_FIXID, BattleRoomTab::OnFixTeams )
+ EVT_MENU ( BROOM_FIXCOLOURS, BattleRoomTab::OnFixColours )
+
+ EVT_LIST_ITEM_ACTIVATED ( BROOM_OPTIONLIST, BattleRoomTab::OnOptionActivate )
+
+END_EVENT_TABLE()
+
+template < int N, int S = 1 >
+class MyStrings : public wxArrayString
+{
+ public:
+ MyStrings()
+ {
+ for ( int i = S; i <= N; ++i )
+ Add( TowxString( i ) );
+ }
+};
+
+const MyStrings<SPRING_MAX_TEAMS> team_choices;
+const MyStrings<SPRING_MAX_ALLIES> ally_choices;
+
+BattleRoomTab::BattleRoomTab( wxWindow* parent, Ui& ui, Battle& battle )
+ : wxScrolledWindow( parent, -1 ),
+ m_ui( ui ),
+ m_battle( battle ),
+ m_map_dlg( 0 )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "battleroomtab" ) );
+
+ // Create all widgets
+ m_splitter = new wxSplitterWindow( this, -1, wxDefaultPosition, wxSize( 100, 60 ) );
+
+ UserBattleStatus& myself = m_battle.GetMe().BattleStatus();
+
+ m_player_panel = new wxScrolledWindow( m_splitter , -1 );
+ m_player_panel->SetScrollRate( 3, 3 );
+ m_team_sel = new wxComboBox( m_player_panel, BROOM_TEAMSEL, _T( "1" ), wxDefaultPosition, wxSize( 50, CONTROL_HEIGHT ), team_choices );
+ m_team_sel->SetToolTip( TE( _( "Players with the same team number share control of their units." ) ) );
+ m_ally_sel = new wxComboBox( m_player_panel, BROOM_ALLYSEL, _T( "1" ), wxDefaultPosition, wxSize( 50, CONTROL_HEIGHT ), ally_choices );
+ m_ally_sel->SetToolTip( TE( _( "Players with the same ally number work together to achieve victory." ) ) );
+ m_color_sel = new ColorButton( m_player_panel, BROOM_COLOURSEL, myself.colour, wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_color_sel->SetToolTip( TE( _( "Select a color to identify your units in-game" ) ) );
+ m_side_sel = new wxBitmapComboBox( m_player_panel, BROOM_SIDESEL, _T( "" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_side_sel->SetToolTip( TE( _( "Select your faction" ) ) );
+ m_spec_chk = new wxCheckBox( m_player_panel, BROOM_SPEC, _( "Spectator" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_spec_chk->SetToolTip( TE( _( "Spectate (watch) the battle instead of playing" ) ) );
+ m_ready_chk = new wxCheckBox( m_player_panel, BROOM_IMREADY, _( "I'm ready" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_ready_chk->SetToolTip( TE( _( "Click this if you are content with the battle settings." ) ) );
+
+ try
+ {
+ wxArrayString sides = usync().GetSides( m_battle.GetHostModName() );
+ for ( unsigned int i = 0; i < sides.GetCount(); i++ )
+ {
+ m_side_sel->Append( sides[i], icons().GetBitmap( icons().GetSideIcon( m_battle.GetHostModName(), i ) ) );
+ }
+ }
+ catch ( ... ) {}
+
+ m_team_lbl = new wxStaticText( m_player_panel, -1, _( "Team" ) );
+ m_ally_lbl = new wxStaticText( m_player_panel, -1, _( "Ally" ) );
+ m_color_lbl = new wxStaticText( m_player_panel, -1, _( "Color" ) );
+ m_side_lbl = new wxStaticText( m_player_panel, -1, _( "Side" ) );
+
+ m_size_lbl = new wxStaticText( this, -1, _T( "" ) );
+ m_wind_lbl = new wxStaticText( this, -1, _T( "" ) );
+ m_tidal_lbl = new wxStaticText( this, -1, _T( "" ) );
+
+ m_map_combo = new wxComboBox( this, BROOM_MAP_SEL, _T( "" ), wxDefaultPosition, wxDefaultSize );
+
+ m_minimap = new MapCtrl( this, 162, &m_battle, m_ui, true, true, true, false );
+ m_minimap->SetToolTip( TE( _( "A preview of the selected map. You can see the starting positions, or (if set) starting boxes." ) ) );
+
+ m_browse_map_btn = new wxButton( this, BROOM_MAP_BROWSE, _( "Map" ), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ m_browse_map_btn->SetSize( m_browse_map_btn->GetSize().GetWidth() * 2 , m_browse_map_btn->GetSize().GetHeight() ) ; // has 0 effect
+
+ m_players = new BattleroomListCtrl( m_player_panel, ( IBattle* )&battle, m_ui, false );
+ m_chat = new ChatPanel( m_splitter, m_ui, battle );
+
+ m_command_line = new wxStaticLine( this, -1, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+
+ m_leave_btn = new wxButton( this, BROOM_LEAVE, _( "Leave" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_leave_btn->SetToolTip( TE( _( "Leave the battle and return to the battle list" ) ) );
+ m_start_btn = new wxButton( this, BROOM_START, _( "Start" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_start_btn->SetToolTip( TE( _( "Start the battle" ) ) );
+
+ m_manage_players_btn = new wxButton( this, BROOM_MANAGE_MENU, _( "Player Management" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_manage_players_btn->SetToolTip( TE( _( "Various functions to make team games simplers to setup" ) ) );
+
+ m_addbot_btn = new wxButton( this, BROOM_ADDBOT, _( "Add Bot..." ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_addbot_btn->SetToolTip( TE( _( "Add a computer-controlled player to the game" ) ) );
+#if wxUSE_TOGGLEBTN
+ m_autolock_chk = new wxToggleButton( this, BROOM_AUTOLOCK , _( "Autolock on start" ), wxDefaultPosition , wxSize( -1, CONTROL_HEIGHT ), 0 );
+#else
+ m_autolock_chk = new wxCheckBox( this, BROOM_AUTOLOCK, _( "Autolock on start" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+#endif
+ m_autolock_chk->SetToolTip( TE( _( "Automatically locks the battle when the game starts and unlock when it's finished." ) ) );
+ m_autolock_chk->SetValue( sett().GetLastAutolockStatus() );
+
+ m_lock_chk = new wxCheckBox( this, BROOM_LOCK, _( "Locked" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_lock_chk->SetToolTip( TE( _( "Prevent additional players from joining the battle" ) ) );
+
+ m_manage_users_mnu = new wxMenu();
+
+ m_autohost_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_AUTOHOST, _( "Autohost" ), _( "Toggle autohost mode. This allows players to control your battle using commands like '!balance' and '!start'." ), wxITEM_CHECK );
+ m_manage_users_mnu->Append( m_autohost_mnu );
+ m_autohost_mnu->Check( false );
+
+ m_autospec_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_AUTOSPECT, _( "AutoSpect" ), _( "Automatically spectate players that don't ready up or become synced within x seconds." ), wxITEM_CHECK );
+ m_manage_users_mnu->Append( m_autospec_mnu );
+ m_autospec_mnu->Check( sett().GetBattleLastAutoSpectTime() > 0 );
+ m_autocontrol_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_AUTOCONTROL, _( "AutoControlBalance" ), _( "Automatically balance teams and allies and fix colors when all players are ready and synced" ), wxITEM_CHECK );
+ m_manage_users_mnu->Append( m_autocontrol_mnu );
+ m_autocontrol_mnu->Check( sett().GetBattleLastAutoControlState() );
+ m_autostart_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_AUTOSTART, _( "AutoStart" ), _( "Automatically start the battle when all players are ready and synced" ), wxITEM_CHECK );
+ m_manage_users_mnu->Append( m_autostart_mnu );
+ m_autostart_mnu->Check( sett().GetBattleLastAutoStartState() );
+
+ m_lock_balance_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_LOCK_BALANCE, _( "Lock Balance" ), _( "When activated, prevents anyone but the host to change team and ally" ), wxITEM_CHECK );
+ m_manage_users_mnu->Append( m_lock_balance_mnu );
+ m_lock_balance_mnu->Check( false );
+
+ wxMenu* ring_menu = new wxMenu;
+ wxMenuItem* ring_unready = new wxMenuItem( ring_menu, BROOM_RING_UNREADY, _( "Ring unready" ), _( "Rings all players that don't have ready status and aren't spectators" ) );
+ ring_menu->Append( ring_unready );
+ wxMenuItem* ring_unsynced = new wxMenuItem( ring_menu, BROOM_RING_UNSYNC, _( "Ring unsynced" ), _( "Rings all players that don't have sync status and aren't spectators" ) );
+ ring_menu->Append( ring_unsynced );
+ wxMenuItem* ring_unready_unsynced = new wxMenuItem( ring_menu, BROOM_RING_UNREADY_UNSYNC, _( "Ring unready and unsynced" ), _( "Rings all players that don't have sync status or don't have ready status and aren't spectators" ) );
+ ring_menu->Append( ring_unready_unsynced );
+ m_manage_users_mnu->Append( wxID_ANY, _( "Ring ..." ), ring_menu );
+
+ wxMenu* spect_menu = new wxMenu;
+ wxMenuItem* spect_unready = new wxMenuItem( spect_menu, BROOM_SPECT_UNREADY, _( "Spect unready" ), _( "Force to spectate all players that don't have ready status" ) );
+ spect_menu->Append( spect_unready );
+ wxMenuItem* spect_unsynced = new wxMenuItem( spect_menu, BROOM_SPECT_UNSYNC, _( "Spect unsynced" ), _( "Force to spectate all players that don't have sync status" ) );
+ spect_menu->Append( spect_unsynced );
+ wxMenuItem* spect_unready_unsynced = new wxMenuItem( spect_menu, BROOM_SPECT_UNREADY_UNSYNC, _( "Force to spectate unready and unsynced" ), _( "Rings all players that don't have sync status or don't have ready status" ) );
+ spect_menu->Append( spect_unready_unsynced );
+ m_manage_users_mnu->Append( wxID_ANY, _( "Force spectate ..." ), spect_menu );
+
+ wxMenuItem* m_balance_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_BALANCE, _( "Balance alliances" ), _( "Automatically balance players into two or more alliances" ) );
+ m_manage_users_mnu->Append( m_balance_mnu );
+
+ wxMenuItem* m_fix_colours_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_FIXCOLOURS, _( "Fix colours" ), _( "Make player colors unique" ) );
+ m_manage_users_mnu->Append( m_fix_colours_mnu );
+
+ wxMenuItem* m_fix_team_mnu = new wxMenuItem( m_manage_users_mnu, BROOM_FIXID, _( "Balance teams" ), _( "Automatically balance players into control teams, by default none shares control" ) );
+ m_manage_users_mnu->Append( m_fix_team_mnu );
+
+ wxStaticBoxSizer* m_preset_sizer;
+ m_preset_sizer = new wxStaticBoxSizer( new wxStaticBox( this, 0, _( "Manage Presets" ) ), wxVERTICAL );
+
+ wxBoxSizer* m_preset_btns_sizer;
+ m_preset_btns_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_options_preset_sel = new wxComboBox( this, BROOM_PRESETSEL, sett().GetModDefaultPresetName( m_battle.GetHostModName() ), wxDefaultPosition, wxDefaultSize, sett().GetPresetList(), wxCB_READONLY );
+ m_options_preset_sel->SetToolTip( TE( _( "Load battle preset" ) ) );
+
+ m_preset_sizer->Add( m_options_preset_sel, 0, wxEXPAND | wxALL );
+
+ m_save_btn = new wxButton( this, BROOM_SAVEPRES, _( "Save" ), wxDefaultPosition, wxDefaultSize );
+ m_save_btn->SetToolTip( TE( _( "Save a set of options." ) ) );
+
+ m_preset_btns_sizer->Add( m_save_btn, 0, wxEXPAND );
+
+ m_delete_btn = new wxButton( this, BROOM_DELETEPRES, _( "Delete" ), wxDefaultPosition, wxDefaultSize );
+ m_delete_btn->SetToolTip( TE( _( "Delete a set of options." ) ) );
+
+ m_preset_btns_sizer->Add( m_delete_btn, 0, wxEXPAND );
+
+ m_default_btn = new wxButton( this, BROOM_SETDEFAULTPRES, _( "Set default" ), wxDefaultPosition, wxDefaultSize );
+ m_default_btn->SetToolTip( TE( _( "Use the current set of options as mod's default." ) ) );
+
+ m_preset_btns_sizer->Add( m_default_btn, 0, wxEXPAND );
+
+ m_preset_sizer->Add( m_preset_btns_sizer, 0, wxEXPAND );
+
+
+ m_opts_list = new wxListCtrl( this, BROOM_OPTIONLIST, wxDefaultPosition, wxDefaultSize, wxLC_NO_HEADER | wxLC_REPORT );
+ //m_opts_list->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
+ m_opts_list->SetFont( wxFont( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT ) );
+ m_opts_list->SetToolTip( TE( _( "Activate an element to quickly change it" ) ) );
+ wxListItem col;
+
+ col.SetText( _( "Option" ) );
+ m_opts_list->InsertColumn( 0, col );
+ col.SetText( _( "Value" ) );
+ m_opts_list->InsertColumn( 1, col );
+
+ long pos = 0;
+
+ m_opts_list->InsertItem( pos, _( "Size" ) );
+ m_opt_list_map[ _( "Size" ) ] = pos++;
+ m_opts_list->InsertItem( pos , _( "Windspeed" ) );
+ m_opt_list_map[ _( "Windspeed" ) ] = pos++;
+ m_opts_list->InsertItem( pos, _( "Tidal strength" ) );
+ m_opt_list_map[ _( "Tidal strength" ) ] = pos++;
+
+ m_opts_list->InsertItem( pos++, wxEmptyString );
+ pos = AddMMOptionsToList( pos++, OptionsWrapper::EngineOption );
+ m_opts_list->InsertItem( pos++, wxEmptyString );
+ pos = AddMMOptionsToList( pos, OptionsWrapper::ModOption );
+ m_opts_list->InsertItem( pos++, wxEmptyString );
+ m_map_opts_index = pos;
+ pos = AddMMOptionsToList( pos, OptionsWrapper::MapOption );
+
+
+ // Create Sizers
+ m_players_sizer = new wxBoxSizer( wxVERTICAL );
+ m_player_sett_sizer = new wxBoxSizer( wxHORIZONTAL );
+ wxBoxSizer* m_map_select_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_info_sizer = new wxBoxSizer( wxVERTICAL );
+ m_top_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
+ //m_info1_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ int side_sel_width = m_side_sel->GetWidestItemWidth();
+ wxBoxSizer* m_side_sel_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_side_sel_sizer->SetMinSize( side_sel_width, CONTROL_HEIGHT );
+ m_side_sel_sizer->Add( m_side_sel, 1, wxEXPAND );
+
+ // Put widgets in place
+ m_player_sett_sizer->Add( m_team_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 2 );
+ m_player_sett_sizer->Add( m_team_sel, 0, wxEXPAND | wxALL, 2 );
+ m_player_sett_sizer->Add( m_ally_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 2 );
+ m_player_sett_sizer->Add( m_ally_sel, 0, wxEXPAND | wxALL, 2 );
+ m_player_sett_sizer->Add( m_color_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 2 );
+ m_player_sett_sizer->Add( m_color_sel, 0, wxEXPAND | wxALL, 2 );
+ m_player_sett_sizer->Add( m_side_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 2 );
+ m_player_sett_sizer->Add( m_side_sel_sizer, 0, wxEXPAND | wxALL, 2 );
+ m_player_sett_sizer->Add( m_spec_chk, 0, wxEXPAND | wxALL, 2 );
+ m_player_sett_sizer->Add( m_ready_chk, 0, wxEXPAND | wxALL, 2 );
+
+ m_players_sizer->Add( m_players, 1, wxEXPAND );
+ m_players_sizer->Add( m_player_sett_sizer, 0, wxEXPAND );
+
+ m_player_panel->SetSizer( m_players_sizer );
+
+ SplitSizerHorizontally( sett().GetSplitBRoomHorizontally() );
+
+ //m_info1_sizer->Add( m_wind_lbl, 1, wxEXPAND );
+ //m_info1_sizer->Add( m_size_lbl, 1, wxEXPAND );
+
+ m_info_sizer->Add( m_minimap, 0, wxEXPAND );
+ m_map_select_sizer->Add( m_map_combo, 0, wxALL | wxEXPAND | wxALIGN_CENTER_VERTICAL );
+ m_map_select_sizer->Add( m_browse_map_btn, 0, wxALIGN_RIGHT );
+ m_info_sizer->Add( m_map_select_sizer, 0, wxALL );
+ //m_info_sizer->Add( m_info1_sizer, 0, wxEXPAND );
+ //m_info_sizer->Add( m_tidal_lbl, 0, wxEXPAND );
+ m_info_sizer->Add( m_opts_list, 1, wxEXPAND | wxTOP, 4 );
+ m_info_sizer->Add( m_preset_sizer, 0, wxEXPAND, 4 );
+
+
+ m_top_sizer->Add( m_splitter, 1, wxEXPAND | wxALL, 2 );
+ m_top_sizer->Add( m_info_sizer, 0, wxEXPAND | wxALL, 2 );
+
+ m_buttons_sizer->AddStretchSpacer();
+ m_buttons_sizer->Add( m_leave_btn, 0, wxEXPAND | wxALL, 2 );
+ m_buttons_sizer->Add( m_addbot_btn, 0, wxEXPAND | wxALL, 2 );
+ m_buttons_sizer->Add( m_autolock_chk, 0, wxEXPAND | wxALL, 2 );
+ m_buttons_sizer->Add( m_lock_chk, 0, wxEXPAND | wxALL, 2 );
+ m_buttons_sizer->Add( m_manage_players_btn, 0, wxEXPAND | wxALL, 2 );
+ m_buttons_sizer->Add( m_start_btn, 0, wxEXPAND | wxALL, 2 );
+
+ m_main_sizer->Add( m_top_sizer, 1, wxEXPAND );
+ m_main_sizer->Add( m_command_line, 0, wxEXPAND );
+ m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND );
+
+ m_splitter->SetMinimumPaneSize( 240 );
+
+ for ( UserList::user_map_t::size_type i = 0; i < battle.GetNumUsers(); i++ )
+ {
+ m_players->AddUser( battle.GetUser( i ) );
+ #ifdef __WXMAC__
+ UpdateUser( battle.GetUser( i ) );
+ #endif
+ }
+
+ if ( !IsHosted() )
+ {
+ m_options_preset_sel->Disable();
+ m_save_btn->Disable();
+ m_delete_btn->Disable();
+ m_default_btn->Disable();
+ m_start_btn->Disable();
+ m_manage_players_btn->Disable();
+ m_lock_chk->Disable();
+ m_autolock_chk->Disable();
+ }
+
+ ReloadMaplist();
+
+ UpdateBattleInfo( wxString::Format( _T( "%d_mapname" ), OptionsWrapper::PrivateOptions ) );
+ UpdateBattleInfo();
+
+ SetScrollRate( 3, 3 );
+ SetSizer( m_main_sizer );
+ Layout();
+ unsigned int widthfraction = m_opts_list->GetClientSize().GetWidth() / 3;
+ m_opts_list->SetColumnWidth( 0, widthfraction * 1.95 );
+ m_opts_list->SetColumnWidth( 1, widthfraction * 0.95 );
+
+}
+
+
+BattleRoomTab::~BattleRoomTab()
+{
+ if ( GetAui().manager )
+ GetAui().manager->DetachPane( this );
+ if ( m_map_dlg ) {
+ m_map_dlg->EndModal( 0 );
+ }
+}
+
+void BattleRoomTab::SplitSizerHorizontally( const bool horizontal )
+{
+ if ( m_splitter->IsSplit() )
+ m_splitter->Unsplit();
+ if ( horizontal )
+ m_splitter->SplitHorizontally( m_player_panel, m_chat );
+ else
+ m_splitter->SplitVertically( m_player_panel, m_chat );
+}
+
+bool BattleRoomTab::IsHosted()
+{
+ return m_battle.IsFounderMe();
+}
+
+wxString _GetStartPosStr( IBattle::StartType t )
+{
+ switch ( t )
+ {
+ case IBattle::ST_Fixed:
+ return _( "Fixed" );
+ case IBattle::ST_Random:
+ return _( "Random" );
+ case IBattle::ST_Choose:
+ return _( "Boxes" );
+ case IBattle::ST_Pick:
+ return _( "Pick" );
+ default:
+ return _T( "?" );
+ };
+}
+
+
+wxString _GetGameTypeStr( IBattle::GameType t )
+{
+ switch ( t )
+ {
+ case IBattle::GT_ComContinue:
+ return _( "Continue" );
+ case IBattle::GT_ComEnds:
+ return _( "End" );
+ case IBattle::GT_Lineage:
+ return _( "Lineage" );
+ default:
+ return _T( "?" );
+ };
+}
+
+
+void BattleRoomTab::UpdateBattleInfo()
+{
+ m_lock_chk->SetValue( m_battle.IsLocked() );
+ m_minimap->UpdateMinimap();
+}
+
+
+void BattleRoomTab::UpdateBattleInfo( const wxString& Tag )
+{
+ long index = m_opt_list_map[ Tag ];
+ OptionsWrapper::GameOption type = ( OptionsWrapper::GameOption )s2l( Tag.BeforeFirst( '_' ) );
+ wxString key = Tag.AfterFirst( '_' );
+ wxString value;
+ if ( ( type == OptionsWrapper::MapOption ) || ( type == OptionsWrapper::ModOption ) || ( type == OptionsWrapper::EngineOption ) )
+ {
+ OptionType DataType = m_battle.CustomBattleOptions().GetSingleOptionType( key );
+ value = m_battle.CustomBattleOptions().getSingleValue( key, ( OptionsWrapper::GameOption )type );
+ if ( m_battle.CustomBattleOptions().getDefaultValue( key, type ) == value ) m_opts_list->SetItemFont( index, wxFont( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT ) );
+ else m_opts_list->SetItemFont( index, wxFont( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD ) );
+ if ( DataType == opt_bool )
+ {
+ value = bool2yn( s2l( value ) ); // convert from 0/1 to literal Yes/No
+ }
+ else if ( DataType == opt_list )
+ {
+ value = m_battle.CustomBattleOptions().GetNameListOptValue( key, type ); // get the key full name not short key
+ }
+ m_opts_list->SetItem( index, 1, value );
+ }
+ else if ( type == OptionsWrapper::PrivateOptions )
+ {
+ if ( key == _T( "mapname" ) ) // the map has been changed
+ {
+ try // updates map info summary
+ {
+ ASSERT_EXCEPTION( m_battle.MapExists(), _( "Map does not exist." ) );
+ UnitSyncMap map = m_battle.LoadMap();
+ m_opts_list->SetItem( m_opt_list_map[ _( "Size" ) ] , 1, wxString::Format( _T( "%.0fx%.0f" ), map.info.width / 512.0, map.info.height / 512.0 ) );
+ m_opts_list->SetItem( m_opt_list_map[ _( "Windspeed" ) ], 1, wxString::Format( _T( "%d-%d" ), map.info.minWind, map.info.maxWind ) );
+ m_opts_list->SetItem( m_opt_list_map[ _( "Tidal strength" ) ], 1, wxString::Format( _T( "%d" ), map.info.tidalStrength ) );
+ // m_opts_list->SetItem( 0, 1, );
+ }
+ catch ( ... )
+ {
+ m_opts_list->SetItem( m_opt_list_map[ _( "Size" ) ], 1, _T( "?x?" ) );
+ m_opts_list->SetItem( m_opt_list_map[ _( "Windspeed" ) ], 1, _T( "?-?" ) );
+ m_opts_list->SetItem( m_opt_list_map[ _( "Tidal strength" ) ], 1, _T( "?" ) );
+ }
+ wxString mapname = RefineMapname( m_battle.GetHostMapName() );
+ int index = m_map_combo->FindString( mapname );
+ if ( index != wxNOT_FOUND ) m_map_combo->SetSelection( index );
+ else m_map_combo->SetValue( mapname );
+
+ //delete any eventual map option from the list and add options of the new map
+ for ( long i = m_map_opts_index; i < m_opts_list->GetItemCount(); i++ ) m_opts_list->DeleteItem( i );
+ AddMMOptionsToList( m_map_opts_index, OptionsWrapper::MapOption );
+
+ m_minimap->UpdateMinimap();
+
+ }
+ else if ( key == _T( "restrictions" ) )
+ {
+ m_opts_list->SetItem( index, 1, bool2yn( m_battle.RestrictedUnits().size() > 0 ) );
+ }
+ }
+}
+
+BattleroomListCtrl& BattleRoomTab::GetPlayersListCtrl()
+{
+ ASSERT_LOGIC( m_players != 0, _T( "m_players = 0" ) );
+ return *m_players;
+}
+
+
+void BattleRoomTab::UpdateUser( User& user )
+{
+ m_players->UpdateUser( user );
+
+ m_minimap->UpdateMinimap();
+
+ if ( &user != &m_battle.GetMe() ) return;
+
+ UserBattleStatus& bs = user.BattleStatus();
+ m_team_sel->SetSelection( bs.team );
+ m_ally_sel->SetSelection( bs.ally );
+ m_side_sel->SetSelection( bs.side );
+ m_spec_chk->SetValue( bs.spectator );
+ m_ready_chk->SetValue( bs.ready );
+ // Enable or disable widgets' sensitivity as appropriate.
+ if ( bs.spectator )
+ {
+ m_side_sel->Disable();
+ m_ally_sel->Disable();
+ m_team_sel->Disable();
+ if ( m_battle.GetBattleType() != BT_Replay ) m_ready_chk->Disable();
+ else m_ready_chk->Enable();
+ }
+ else
+ {
+ m_side_sel->Enable();
+ m_ally_sel->Enable();
+ m_team_sel->Enable();
+ m_ready_chk->Enable();
+ }
+
+ icons().SetColourIcon( bs.team, user.BattleStatus().colour );
+ m_color_sel->SetColor( user.BattleStatus().colour );
+}
+
+
+Battle& BattleRoomTab::GetBattle()
+{
+ return m_battle;
+}
+
+
+ChatPanel& BattleRoomTab::GetChatPanel()
+{
+ wxLogDebugFunc( _T( "" ) );
+ ASSERT_LOGIC( m_chat != 0, _T( "m_chat = 0" ) );
+ return *m_chat;
+}
+
+
+void BattleRoomTab::OnStart( wxCommandEvent& /*unused*/ )
+{
+ m_battle.GetMe().BattleStatus().ready = true;
+
+ if ( !m_battle.IsEveryoneReady() )
+ {
+ int answer = customMessageBox( SL_MAIN_ICON, _( "Some Players are not ready yet\nDo you want to force start?" ), _( "Not ready" ), wxYES_NO );
+ if ( answer == wxNO ) return;
+ }
+
+ m_battle.SaveMapDefaults(); // save map presets
+
+ m_ui.StartHostedBattle();
+}
+
+
+void BattleRoomTab::OnLeave( wxCommandEvent& /*unused*/ )
+{
+ m_battle.Leave();
+}
+
+
+
+void BattleRoomTab::OnBalance( wxCommandEvent& /*unused*/ )
+{
+ AutoBalanceDialog::BalanceOptions defaultval;
+ defaultval.type = ( IBattle::BalanceType )sett().GetBalanceMethod();
+ defaultval.respectclans = sett().GetBalanceClans();
+ defaultval.strongclans = sett().GetBalanceStrongClans();
+ defaultval.groupingsize = sett().GetBalanceGrouping();
+ AutoBalanceDialog dlg( this, defaultval );
+ if ( dlg.ShowModal() == wxID_OK )
+ {
+ AutoBalanceDialog::BalanceOptions balance = dlg.GetResult();
+ sett().SetBalanceMethod( balance.type );
+ sett().SetBalanceClans( balance.respectclans );
+ sett().SetBalanceStrongClans( balance.strongclans );
+ sett().SetBalanceGrouping( balance.groupingsize );
+ m_battle.Autobalance( balance.type, balance.respectclans, balance.strongclans, balance.groupingsize );
+ }
+}
+
+
+void BattleRoomTab::OnFixTeams( wxCommandEvent& /*unused*/ )
+{
+ AutoBalanceDialog::BalanceOptions defaultval;
+ defaultval.type = ( IBattle::BalanceType )sett().GetFixIDMethod();
+ defaultval.respectclans = sett().GetFixIDClans();
+ defaultval.strongclans = sett().GetFixIDStrongClans();
+ defaultval.groupingsize = sett().GetFixIDGrouping();
+ AutoBalanceDialog dlg( this, defaultval );
+ if ( dlg.ShowModal() == wxID_OK )
+ {
+ AutoBalanceDialog::BalanceOptions balance = dlg.GetResult();
+ sett().SetFixIDMethod( balance.type );
+ sett().SetFixIDClans( balance.respectclans );
+ sett().SetFixIDStrongClans( balance.strongclans );
+ sett().SetFixIDGrouping( balance.groupingsize );
+ m_battle.FixTeamIDs( balance.type, balance.respectclans, balance.strongclans, balance.groupingsize );
+ }
+}
+
+
+void BattleRoomTab::OnFixColours( wxCommandEvent& /*unused*/ )
+{
+ wxLogMessage( _T( "" ) );
+ if ( !IsHosted() ) // Works with autohosts, and human hosts knows what it mean.
+ {
+ m_battle.Say( _T( "!fixcolors" ) );
+ return;
+ }
+ //m_battle.Say(_T("fixing colours"));
+ m_battle.FixColours();
+}
+
+
+void BattleRoomTab::OnAddBot( wxCommandEvent& /*unused*/ )
+{
+ //customMessageBox(SL_MAIN_ICON,_T("Max players reached"),_T("Cannot add bot, maximum number of players already reached.") );
+ AddBotDialog dlg( this, m_battle );
+ if ( dlg.ShowModal() == wxID_OK )
+ {
+ UserBattleStatus bs;
+ bs.team = m_battle.GetFreeTeamNum( false );
+ bs.ally = bs.team;
+ bs.sync = SYNC_SYNCED;
+ bs.spectator = false;
+ bs.side = 0;
+ bs.ready = true;
+ bs.handicap = 0;
+ bs.colour = m_battle.GetNewColour();
+ bs.aishortname = dlg.GetAIShortName();
+ bs.aiversion = dlg.GetAIVersion();
+ bs.aitype = dlg.GetAIType();
+ bs.owner = m_battle.GetMe().GetNick();
+ m_ui.GetServer().AddBot( m_battle.GetBattleId(), dlg.GetNick(), bs );
+ }
+}
+
+
+void BattleRoomTab::OnImReady( wxCommandEvent& /*unused*/ )
+{
+ m_battle.SetImReady( m_ready_chk->GetValue() );
+}
+
+
+void BattleRoomTab::OnLock( wxCommandEvent& /*unused*/ )
+{
+ m_battle.SetIsLocked( m_lock_chk->GetValue() );
+ m_battle.SendHostInfo( IBattle::HI_Locked );
+}
+
+
+void BattleRoomTab::OnAutoHost( wxCommandEvent& /*unused*/ )
+{
+ m_battle.GetAutoHost().SetEnabled( m_autohost_mnu->IsChecked() );
+}
+
+
+void BattleRoomTab::OnAutoControl( wxCommandEvent& /*unused*/ )
+{
+ sett().SetBattleLastAutoControlState( m_autocontrol_mnu->IsChecked() );
+}
+
+void BattleRoomTab::OnAutoStart( wxCommandEvent& /*unused*/ )
+{
+ sett().SetBattleLastAutoStartState( m_autostart_mnu->IsChecked() );
+}
+
+void BattleRoomTab::OnAutoSpec( wxCommandEvent& /*unused*/ )
+{
+ int trigger = wxGetNumberFromUser( _( "Enter timeout before autospeccing a player in minutes" ), _( "Set Timeout" ), _T( "" ), sett().GetBattleLastAutoSpectTime() / 60, 1, 60, ( wxWindow* ) & ui().mw(), wxDefaultPosition );
+ if ( trigger < 0 ) trigger = 0;
+ trigger = trigger * 60;
+ m_autospec_mnu->Check( trigger > 0 );
+ sett().SetBattleLastAutoSpectTime( trigger );
+}
+
+void BattleRoomTab::OnImSpec( wxCommandEvent& /*unused*/ )
+{
+ m_battle.ForceSpectator( m_battle.GetMe(), m_spec_chk->GetValue() );
+}
+
+
+void BattleRoomTab::OnTeamSel( wxCommandEvent& /*unused*/ )
+{
+ unsigned long team;
+ m_team_sel->GetValue().ToULong( &team );
+ m_battle.ForceTeam( m_battle.GetMe(), team - 1 );
+}
+
+
+void BattleRoomTab::OnAllySel( wxCommandEvent& /*unused*/ )
+{
+ unsigned long ally;
+ m_ally_sel->GetValue().ToULong( &ally );
+ m_battle.ForceAlly( m_battle.GetMe(), ally - 1 );
+}
+
+
+void BattleRoomTab::OnColourSel( wxCommandEvent& /*unused*/ )
+{
+ User& u = m_battle.GetMe();
+ wxColour CurrentColour = u.BattleStatus().colour;
+ CurrentColour = GetColourFromUser( this, CurrentColour );
+ if ( !CurrentColour.IsColourOk() ) return;
+ sett().SetBattleLastColour( CurrentColour );
+ m_battle.ForceColour( u, CurrentColour );
+}
+
+
+void BattleRoomTab::OnSideSel( wxCommandEvent& /*unused*/ )
+{
+ m_battle.ForceSide( m_battle.GetMe(), m_side_sel->GetSelection() );
+}
+
+
+void BattleRoomTab::OnPresetSel( wxCommandEvent& /*unused*/ )
+{
+ wxString presetname = m_options_preset_sel->GetValue();
+ if ( presetname.IsEmpty() ) return;
+ m_battle.LoadOptionsPreset( presetname );
+ m_battle.SendHostInfo( IBattle::HI_Send_All_opts );
+}
+
+void BattleRoomTab::OnAutoLock( wxCommandEvent& /*unused*/ )
+{
+ m_battle.SetAutoLockOnStart( m_autolock_chk->GetValue() );
+ sett().SetLastAutolockStatus( m_autolock_chk->GetValue() );
+}
+
+
+void BattleRoomTab::OnLockBalance( wxCommandEvent& /*unused*/ )
+{
+ bool locked = m_lock_balance_mnu->IsChecked();
+ m_battle.SetLockExternalBalanceChanges( locked );
+}
+
+void BattleRoomTab::OnSpectUnsynced( wxCommandEvent& /*unused*/ )
+{
+ m_battle.ForceUnsyncedToSpectate();
+}
+
+void BattleRoomTab::OnSpectUnready( wxCommandEvent& /*unused*/ )
+{
+ m_battle.ForceUnReadyToSpectate();
+}
+void BattleRoomTab::OnSpectUnreadyUnsynced( wxCommandEvent& /*unused*/ )
+{
+ m_battle.ForceUnsyncedAndUnreadyToSpectate();
+}
+
+void BattleRoomTab::OnRingUnready( wxCommandEvent& /*unused*/ )
+{
+ m_battle.RingNotReadyPlayers();
+}
+
+void BattleRoomTab::OnRingUnsynced( wxCommandEvent& /*unused*/ )
+{
+ m_battle.RingNotSyncedPlayers();
+}
+
+void BattleRoomTab::OnRingUnreadyUnsynced( wxCommandEvent& /*unused*/ )
+{
+ m_battle.RingNotSyncedAndNotReadyPlayers();
+}
+
+
+void BattleRoomTab::OnShowManagePlayersMenu( wxCommandEvent& /*unused*/ )
+{
+ PopupMenu( m_manage_users_mnu );
+}
+
+void BattleRoomTab::OnUserJoined( User& user )
+{
+ if ( !user.BattleStatus().IsBot() ) m_chat->Joined( user );
+ m_players->AddUser( user );
+
+ UpdateUser(user);
+
+ if ( &user == &m_battle.GetMe() )
+ {
+ m_players->SetSelectedIndex ( m_players->GetIndexFromData( &user ) );
+ }
+}
+
+
+void BattleRoomTab::OnUserLeft( User& user )
+{
+ if ( !user.BattleStatus().IsBot() ) m_chat->Parted( user, wxEmptyString );
+ m_players->RemoveUser( user );
+}
+
+
+void BattleRoomTab::OnUnitSyncReloaded()
+{
+ m_minimap->UpdateMinimap();
+ ReloadMaplist();
+ UpdateBattleInfo();
+ m_battle.SendMyBattleStatus(); // This should reset sync status.
+}
+
+long BattleRoomTab::AddMMOptionsToList( long pos, OptionsWrapper::GameOption optFlag )
+{
+ OptionsWrapper::wxStringTripleVec optlist = m_battle.CustomBattleOptions().getOptions( optFlag );
+ for ( OptionsWrapper::wxStringTripleVec::iterator it = optlist.begin(); it != optlist.end(); ++it )
+ {
+ m_opts_list->InsertItem( pos, it->second.first );
+ wxString tag = wxString::Format( _T( "%d_" ), optFlag ) + it->first;
+ m_opt_list_map[ tag ] = pos;
+ UpdateBattleInfo( tag );
+ pos++;
+ }
+ return pos;
+}
+
+void BattleRoomTab::UpdateHighlights()
+{
+ m_players->RefreshVisibleItems();
+}
+
+
+void BattleRoomTab::UpdatePresetList()
+{
+ m_options_preset_sel->Clear();
+ m_options_preset_sel->Append( sett().GetPresetList() );
+ m_options_preset_sel->SetStringSelection( m_battle.GetCurrentPreset() );
+}
+
+
+void BattleRoomTab::OnSavePreset( wxCommandEvent& /*unused*/ )
+{
+ wxString presetname;
+ if ( !ui().AskText( _( "Enter preset name" ), _( "Enter a name to save the current set of options\nIf a preset with the same name already exist, it will be overwritten" ), presetname ) )
+ return;
+ if ( presetname.IsEmpty() )
+ {
+ customMessageBoxNoModal( SL_MAIN_ICON , _( "Cannot save an options set without a name." ), _( "error" ), wxICON_EXCLAMATION | wxOK );
+ return;
+ }
+ m_battle.SaveOptionsPreset( presetname );
+}
+
+
+void BattleRoomTab::OnDeletePreset( wxCommandEvent& /*unused*/ )
+{
+ wxArrayString choices = m_battle.GetPresetList();
+ int result = wxGetSingleChoiceIndex( _( "Pick an existing option set from the list" ), _( "Delete preset" ), choices );
+ if ( result < 0 ) return;
+ m_battle.DeletePreset( choices[result] );
+}
+
+void BattleRoomTab::OnSetModDefaultPreset( wxCommandEvent& /*unused*/ )
+{
+ wxArrayString choices = m_battle.GetPresetList();
+ int result = wxGetSingleChoiceIndex( _( "Pick an existing option set from the list" ), _( "Set mod default preset" ), choices );
+ if ( result < 0 ) return;
+ sett().SetModDefaultPresetName( m_battle.GetHostModName(), choices[result] );
+}
+
+
+void BattleRoomTab::OnMapBrowse( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T( "" ) );
+ m_map_dlg = new MapSelectDialog ( ( wxWindow* )&m_ui.mw(), m_ui );
+
+ if ( m_map_dlg->ShowModal() == wxID_OK && m_map_dlg->GetSelectedMap() != NULL )
+ {
+ wxString mapname = m_map_dlg->GetSelectedMap()->name;
+ wxLogDebugFunc( mapname );
+ if ( !m_battle.IsFounderMe() )
+ {
+ m_battle.DoAction( _T( "suggests " ) + mapname );
+ return;
+ }
+ const int idx = m_map_combo->FindString( RefineMapname( mapname ), true /*case sensitive*/ );
+ if ( idx != wxNOT_FOUND )
+ SetMap( idx );
+ }
+}
+
+void BattleRoomTab::ReloadMaplist()
+{
+ m_map_combo->Clear();
+
+ wxArrayString maplist = usync().GetMapList();
+// maplist.Sort(CompareStringIgnoreCase);
+
+ size_t nummaps = maplist.Count();
+ for ( size_t i = 0; i < nummaps; i++ ) m_map_combo->Insert( RefineMapname( maplist[i] ), i );
+}
+
+void BattleRoomTab::SetMap( int index )
+{
+ try
+ {
+ UnitSyncMap map = usync().GetMapEx( index );
+ m_battle.SetLocalMap( map );
+ m_battle.SendHostInfo( IBattle::HI_Map );
+ } catch ( ... ) {}
+}
+
+void BattleRoomTab::OnMapSelect( wxCommandEvent& /*unused*/ )
+{
+ if ( !m_battle.IsFounderMe() )
+ {
+ try
+ {
+ m_battle.DoAction( _T( "suggests " ) + usync().GetMap( m_map_combo->GetCurrentSelection() ).name );
+ }
+ catch ( ... )
+ {
+ }
+ return;
+ }
+ SetMap( m_map_combo->GetCurrentSelection() );
+}
+
+void BattleRoomTab::OnOptionActivate( wxListEvent& event )
+{
+ if ( !m_battle.IsFounderMe() ) return;
+ long index = event.GetIndex();
+ if ( index == 0 ) return;
+ wxString tag;
+ for ( OptionListMap::iterator itor = m_opt_list_map.begin(); itor != m_opt_list_map.end(); itor++ )
+ {
+ if ( itor->second == index )
+ {
+ tag = itor->first;
+ break;
+ }
+ }
+ OptionsWrapper& optWrap = m_battle.CustomBattleOptions();
+ OptionsWrapper::GameOption optFlag = ( OptionsWrapper::GameOption )s2l( tag.BeforeFirst( '_' ) );
+ wxString key = tag.AfterFirst( '_' );
+ OptionType type = optWrap.GetSingleOptionType( key );
+ if ( !optWrap.keyExists( key, optFlag, false, type ) ) return;
+ SingleOptionDialog dlg( m_battle, tag );
+ dlg.ShowModal();
+}
+
+void BattleRoomTab::SortPlayerList()
+{
+ m_players->SortList();
+}
diff --git a/src/battleroomtab.h b/src/battleroomtab.h
new file mode 100644
index 0000000..90af3e4
--- /dev/null
+++ b/src/battleroomtab.h
@@ -0,0 +1,239 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_BATTLEROOMTAB_H
+#define SPRINGLOBBY_HEADERGUARD_BATTLEROOMTAB_H
+
+#include <wx/scrolwin.h>
+
+#include "mmoptionswrapper.h"
+#include <map>
+
+class Ui;
+class Battle;
+struct BattleBot;
+class BattleroomListCtrl;
+class User;
+class ChatPanel;
+class wxCommandEvent;
+class wxBoxSizer;
+class wxComboBox;
+class wxStaticText;
+class wxSplitterWindow;
+class wxStaticLine;
+class wxButton;
+class wxCheckBox;
+class wxListCtrl;
+class MapCtrl;
+class ColorButton;
+class wxBitmapComboBox;
+struct UnitSyncMap;
+class wxToggleButton;
+class wxChoice;
+class MapSelectDialog;
+
+typedef std::map<wxString, long> OptionListMap;
+
+/** \brief container for BattleroomListCtrl, battle specific ChatPanel. Also displaying battle info summary
+ * \todo DOCMEMORE */
+class BattleRoomTab : public wxScrolledWindow
+{
+ public:
+ BattleRoomTab( wxWindow* parent, Ui& ui, Battle& battle );
+ ~BattleRoomTab();
+
+ BattleroomListCtrl& GetPlayersListCtrl();
+
+ void UpdateUser( User& user );
+
+ Battle& GetBattle();
+ ChatPanel& GetChatPanel();
+
+ bool IsHosted();
+
+ void UpdateBattleInfo();
+ void UpdateBattleInfo( const wxString& Tag );
+
+ void OnStart( wxCommandEvent& event );
+ void OnLeave( wxCommandEvent& event );
+ void OnBalance( wxCommandEvent& event );
+ void OnFixTeams( wxCommandEvent& event );
+ void OnFixColours( wxCommandEvent& event );
+ void OnAddBot( wxCommandEvent& event );
+ void OnImReady( wxCommandEvent& event );
+ void OnLock( wxCommandEvent& event );
+ void OnAutoHost( wxCommandEvent& event );
+ void OnImSpec( wxCommandEvent& event );
+ void OnTeamSel( wxCommandEvent& event );
+ void OnAllySel( wxCommandEvent& event );
+ void OnColourSel( wxCommandEvent& event );
+ void OnSideSel( wxCommandEvent& event );
+ void OnPresetSel( wxCommandEvent& event );
+ void OnAutoLock( wxCommandEvent& event );
+ void OnLockBalance( wxCommandEvent& event );
+ void OnShowManagePlayersMenu( wxCommandEvent& event );
+ void OnLoadPreset( wxCommandEvent& event );
+ void OnSavePreset( wxCommandEvent& event );
+ void OnDeletePreset( wxCommandEvent& event );
+ void OnSetModDefaultPreset( wxCommandEvent& event );
+ void OnMapBrowse( wxCommandEvent& event );
+ void OnMapSelect( wxCommandEvent& event );
+ void OnOptionActivate( wxListEvent& event );
+
+ void OnSpectUnsynced( wxCommandEvent& event );
+ void OnSpectUnready( wxCommandEvent& event );
+ void OnSpectUnreadyUnsynced( wxCommandEvent& event );
+
+ void OnRingUnready( wxCommandEvent& event );
+ void OnRingUnsynced( wxCommandEvent& event );
+ void OnRingUnreadyUnsynced( wxCommandEvent& event );
+
+ void OnAutoControl( wxCommandEvent& event );
+ void OnAutoStart( wxCommandEvent& event );
+ void OnAutoSpec( wxCommandEvent& event );
+
+ void OnUserJoined( User& user );
+ void OnUserLeft( User& user );
+
+ void OnUnitSyncReloaded();
+ void ReloadMaplist();
+ void SetMap( int index );
+
+ void UpdateHighlights();
+
+ void UpdatePresetList();
+
+ void SortPlayerList();
+
+ protected:
+
+ long AddMMOptionsToList( long pos, OptionsWrapper::GameOption optFlag );
+
+ void SplitSizerHorizontally( const bool horizontal );
+
+ Ui& m_ui;
+ Battle& m_battle;
+ UnitSyncMap m_map;
+
+ long m_map_opts_index;
+
+ OptionListMap m_opt_list_map;
+
+ wxBoxSizer* m_players_sizer;
+ wxBoxSizer* m_player_sett_sizer;
+ wxBoxSizer* m_info_sizer;
+ wxBoxSizer* m_top_sizer;
+ wxBoxSizer* m_buttons_sizer;
+ wxBoxSizer* m_info1_sizer;
+ wxBoxSizer* m_main_sizer;
+
+ wxComboBox* m_team_sel;
+ wxComboBox* m_ally_sel;
+ ColorButton* m_color_sel;
+ wxBitmapComboBox* m_side_sel;
+ wxComboBox* m_options_preset_sel;
+
+ wxStaticText* m_team_lbl;
+ wxStaticText* m_ally_lbl;
+ wxStaticText* m_side_lbl;
+ wxStaticText* m_color_lbl;
+ wxStaticText* m_wind_lbl;
+ wxStaticText* m_tidal_lbl;
+ wxStaticText* m_size_lbl;
+
+ MapCtrl * m_minimap;
+
+ wxScrolledWindow* m_player_panel;
+
+ wxComboBox* m_map_combo;
+
+ BattleroomListCtrl* m_players;
+ ChatPanel* m_chat;
+ wxSplitterWindow* m_splitter;
+
+ wxStaticLine* m_command_line;
+
+ wxButton* m_leave_btn;
+ wxButton* m_start_btn;
+ wxButton* m_addbot_btn;
+ wxButton* m_manage_players_btn;
+ wxButton* m_save_btn;
+ wxButton* m_delete_btn;
+ wxButton* m_default_btn;
+ wxButton* m_browse_map_btn;
+
+ wxMenu* m_manage_users_mnu;
+ wxMenuItem* m_lock_balance_mnu;
+ wxMenuItem* m_autohost_mnu;
+ wxMenuItem* m_autostart_mnu;
+ wxMenuItem* m_autospec_mnu;
+ wxMenuItem* m_autocontrol_mnu;
+
+ wxCheckBox* m_ready_chk;
+ wxCheckBox* m_spec_chk;
+ wxCheckBox* m_lock_chk;
+#if wxUSE_TOGGLEBTN
+ wxToggleButton* m_autolock_chk;
+#else
+ wxCheckBox* m_autolock_chk;
+#endif
+
+ wxListCtrl* m_opts_list;
+
+ MapSelectDialog* m_map_dlg;
+
+ enum {
+ BROOM_LEAVE = wxID_HIGHEST,
+ BROOM_IMREADY,
+ BROOM_LOCK,
+ BROOM_LOCK_BALANCE,
+ BROOM_MANAGE_MENU,
+ BROOM_SPEC,
+ BROOM_TEAMSEL,
+ BROOM_ALLYSEL,
+ BROOM_COLOURSEL,
+ BROOM_SIDESEL,
+ BROOM_START,
+ BROOM_ADDBOT,
+ BROOM_BALANCE,
+ BROOM_FIXID,
+ BROOM_FIXCOLOURS,
+ BROOM_PRESETSEL,
+ BROOM_AUTOHOST,
+ BROOM_AUTOLOCK,
+ BROOM_SAVEPRES,
+ BROOM_DELETEPRES,
+ BROOM_SETDEFAULTPRES,
+ BROOM_MAP_BROWSE,
+ BROOM_MAP_SEL,
+ BROOM_OPTIONLIST,
+ BROOM_RING_UNREADY,
+ BROOM_RING_UNSYNC,
+ BROOM_RING_UNREADY_UNSYNC,
+ BROOM_SPECT_UNREADY,
+ BROOM_SPECT_UNSYNC,
+ BROOM_SPECT_UNREADY_UNSYNC,
+ BROOM_AUTOSPECT,
+ BROOM_AUTOSTART,
+ BROOM_AUTOCONTROL
+ };
+
+ DECLARE_EVENT_TABLE();
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLEROOMTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/bimap.h b/src/bimap.h
new file mode 100644
index 0000000..e8173a1
--- /dev/null
+++ b/src/bimap.h
@@ -0,0 +1,2190 @@
+/* STL-like bidirectional map.
+ *
+ * (C) 2002-2006 Joaquín M López Muñoz (joaquin at tid.es). All rights reserved.
+ *
+ * Permission is granted to use, distribute and modify this code provided that:
+ * · this copyright notice remain unchanged,
+ * · you submit all changes to the copyright holder and properly mark the
+ * changes so they can be told from the original code,
+ * · credits are given to the copyright holder in the documentation of any
+ * software using this code with the following line:
+ * "Portions copyright 2002-2006 Joaquín M López Muñoz (joaquin at tid.es)"
+ *
+ * The author welcomes any suggestions on the code or reportings of actual
+ * use of the code. Please send your comments to joaquin at tid.es.
+ *
+ * The author makes NO WARRANTY or representation, either express or implied,
+ * with respect to this code, its quality, accuracy, merchantability, or
+ * fitness for a particular purpose. This software is provided "AS IS", and
+ * you, its user, assume the entire risk as to its quality and accuracy.
+ *
+ * Changes in v1.1:
+ *
+ * · bimap::erase(to::iterator,to::iterator) incorrectly returned an
+ * iterator. Documentation was also erroneous about this point.
+ * · Incorrect use of allocator::allocate and allocator::deallocate
+ * was causing much more memory to be used than necessary.
+ * · Improved language conformance with respect to missing typename
+ * and template keywords, faulty friend declarations and broken
+ * implementation of some features of <iterator> in MSVC++.
+ * · allocator::rebind used if compiler supports it.
+ * · Fixed some non-conformances about construction of allocator
+ * and comparison objects in copy contructors.
+ * · The allocator object used to be protected for no good reason:
+ * changed to private as the rest of internal objects.
+ * · Some tweaks to make the thing compile under GNU GCC and Metrowerks
+ * CodeWarrior.
+ * · GCC didn't like a template parameter and a defined type to have
+ * the same name: I don't know if this is actually standard conformant.
+ *
+ * Changes in v1.2:
+ *
+ * · Fixed the code to make it work under MSVC 7.1. Contributed by
+ * Steve Robb.
+ *
+ * Changes in v1.3:
+ *
+ * · Fixed some incorrect (standardwise) friend declarations.
+ * · Sprinkled this-> throughout to cope with two-phase name lookup.
+ *
+ * Last modified: October 26th, 2006
+ */
+
+#ifndef BIMAP_H_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761
+#define BIMAP_H_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761
+#define VERSION_BIMAP_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761 0x00010003
+
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <set>
+#include <stddef.h>
+#include <stdexcept>
+#include <utility>
+
+/* offsetof cannot be used on non-POD types (standard 18.1.5) altough bimap
+ * does it in a safe manner. Starting with GCC 3.1, an annoying warning is
+ * issued in this situation. Workarounded it thanks to a tip by Andrew Pollard.
+ */
+
+#if defined(__GNUC__)&&(__GNUC__>3||(__GNUC__==3&&__GNUC_MINOR__>= 1))
+#define BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(type,member) \
+(__extension__ \
+ ( \
+ { \
+ type* t=0; \
+ reinterpret_cast<size_t>( \
+ reinterpret_cast<const char*>( \
+ &(t->member) \
+ ) \
+ ); \
+ } \
+ ) \
+)
+#else
+#define BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(type,member) offsetof(type,member)
+#endif
+
+/* MSVC++ 6.0 do not support allocator::rebind; in these cases, the only
+ * option is use the original allocator_type unrebound, which VC++ 6.0
+ * accepts merrily nevertheless.
+ */
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+#define BIMAP_REBIND_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(type1,type2) type1
+#else
+#define BIMAP_REBIND_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(type1,type2) \
+typename type1::template rebind<type2>::other
+#endif
+
+namespace codeproject{
+
+namespace bimap_detail{
+
+/* Template helper to check for type equality (save possibly constness.)
+ * Refs:
+ * · Alexandrescu, A.: Modern C++ Design: Generic Programming and Design
+ * Patterns Applied, ch. 2, Addison-Wesley, February 2001.
+ * · Boost, type_traits library, boost::is_same<T,U> template,
+ * April 2001, http://boost.org/libs/type_traits/index.htm.
+ */
+
+typedef char equal_types_yes;
+struct equal_types_no {char m[2];};
+equal_types_no equal_types_helper(...);
+template<typename T>
+equal_types_yes equal_types_helper(T,T);
+template <typename T>
+struct equal_types_ptr
+{
+ static const T* make();
+};
+
+template<typename T,typename U> struct equal_types
+{
+ enum{
+ value=
+ (sizeof(equal_types_helper(equal_types_ptr<T>::make(),equal_types_ptr<U>::make()))==
+ sizeof(equal_types_yes))};
+};
+
+/* Template stuff to select one or other type based on a compile-time
+ * condition. This can be used to simulate PTS through derivation.
+ * Refs:
+ * · Marcus, M., Jones, J.: "Simulated partial Specialization for C++",
+ * September 2000, http://opensource.adobe.com/project4/project.shtml
+ * · Czarnecki, K., Eisenecker, U.: Generative Programming - Methods, Tools,
+ * and Applications, Addison-Wesley, June 2000.
+ */
+
+struct select_then
+{
+ template<class then,class els> struct result
+ {
+ typedef then type;
+ };
+};
+
+struct select_else
+{
+ template<class then,class els> struct result
+ {
+ typedef els type;
+ };
+};
+
+template<bool test> struct selector_switch
+{
+ typedef select_then result;
+};
+
+template<> struct selector_switch<false>
+{
+ typedef select_else result;
+};
+
+template<bool test,typename then,typename els>
+struct select
+{
+ typedef typename selector_switch<test>::result sel;
+ typedef typename sel::template result<then,els>::type result;
+};
+
+} /* namespace bimap_detail */
+
+/* inv_pair provides the symmetrical counterpart to std::pair necessary for
+ * the to memberspace of bimap. Its layout matches that of std::pair in the
+ * sense that an inv_pair<T,U> can be reinterpret_cast'ed to be an std::pair<U,T>.
+ * To preserve symmetry, std::pair's should provide the corresponding casting
+ * operator to inv_pair. As this is not feasible (predefined classes cannot be
+ * injected this type of operators), a derivation of std::pair called
+ * direct_pair is defined that plays the role of std::pair.
+ */
+
+#if defined(_MSC_VER)&&_MSC_VER>=1300 /* MSVC++ 7.0 */
+#pragma warning(push)
+#pragma warning(disable:4512)
+/* see http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q87638 */
+#endif
+
+template<typename first_type,typename second_type>
+struct direct_pair;
+
+template<typename first_type_,typename second_type_>
+struct inv_pair
+{
+ typedef first_type_ first_type;
+ typedef second_type_ second_type;
+
+ second_type second;
+ first_type first;
+
+ inv_pair():second(second_type()),first(first_type()){}
+ inv_pair(const first_type& first,const second_type& second):second(second),first(first){}
+ inv_pair(const std::pair<first_type,second_type>& r):second(r.second),first(r.first){}
+ template<typename F,typename S>
+ inv_pair(const inv_pair<F,S>& r):second(r.second),first(r.first){}
+
+ operator direct_pair<second_type,first_type>&()
+ {
+ return *reinterpret_cast<direct_pair<second_type,first_type> *>(this);
+ }
+
+ operator const direct_pair<second_type,first_type>&()const
+ {
+ return *reinterpret_cast<const direct_pair<second_type,first_type> *>(this);
+ }
+};
+
+template<typename first_type,typename second_type>
+struct direct_pair:public std::pair<first_type,second_type>
+{
+private:
+ typedef std::pair<first_type,second_type> super;
+
+public:
+ direct_pair():super(first_type(),second_type()){}
+ direct_pair(const first_type& first,const second_type& second):super(first,second){}
+ direct_pair(const inv_pair<first_type,second_type>& r):super(r.first,r.second){}
+ template<typename F,typename S>
+ direct_pair(const std::pair<F,S>& r):super(r.first,r.second){}
+
+ operator inv_pair<second_type,first_type>&()
+ {
+ return *reinterpret_cast<inv_pair<second_type,first_type> *>(this);
+ }
+
+ operator const inv_pair<second_type,first_type>&()const
+ {
+ return *reinterpret_cast<const inv_pair<second_type,first_type> *>(this);
+ }
+};
+
+#if defined(_MSC_VER)&&_MSC_VER>=1300 /* MSVC++ 7.0 */
+#pragma warning(pop)
+#endif
+
+template<typename first_type,typename second_type>
+inv_pair<first_type,second_type> make_inv_pair(
+ const first_type& first,
+ const second_type& second)
+{
+ return inv_pair<first_type,second_type>(first,second);
+}
+
+/* comparison operators for inv_pair */
+
+/* == */
+
+template<typename first_type,typename second_type>
+bool operator==(
+ const inv_pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return x.first==y.first&&x.second==y.second;
+}
+
+template<typename first_type,typename second_type>
+bool operator==(
+ const inv_pair<first_type,second_type>& x,
+ const std::pair<first_type,second_type>& y)
+{
+ return x.first==y.first&&x.second==y.second;
+}
+
+template<typename first_type,typename second_type>
+bool operator==(
+ const std::pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return x.first==y.first&&x.second==y.second;
+}
+
+/* != */
+
+template<typename first_type,typename second_type>
+bool operator!=(
+ const inv_pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return !(x==y);
+}
+
+template<typename first_type,typename second_type>
+bool operator!=(
+ const inv_pair<first_type,second_type>& x,
+ const std::pair<first_type,second_type>& y)
+{
+ return !(x==y);
+}
+
+template<typename first_type,typename second_type>
+bool operator!=(
+ const std::pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return !(x==y);
+}
+
+/* < */
+
+template<typename first_type,typename second_type>
+bool operator<(
+ const inv_pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return x.first<y.first||x.first==y.first&&x.second<y.second;
+}
+
+template<typename first_type,typename second_type>
+bool operator<(
+ const inv_pair<first_type,second_type>& x,
+ const std::pair<first_type,second_type>& y)
+{
+ return x.first<y.first||x.first==y.first&&x.second<y.second;
+}
+
+template<typename first_type,typename second_type>
+bool operator<(
+ const std::pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return x.first<y.first||x.first==y.first&&x.second<y.second;
+}
+
+/* > */
+
+template<typename first_type,typename second_type>
+bool operator>(
+ const inv_pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return y<x;
+}
+
+template<typename first_type,typename second_type>
+bool operator>(
+ const inv_pair<first_type,second_type>& x,
+ const std::pair<first_type,second_type>& y)
+{
+ return y<x;
+}
+
+template<typename first_type,typename second_type>
+bool operator>(
+ const std::pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return y<x;
+}
+
+/* <= */
+
+template<typename first_type,typename second_type>
+bool operator<=(
+ const inv_pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return !(y<x);
+}
+
+template<typename first_type,typename second_type>
+bool operator<=(
+ const inv_pair<first_type,second_type>& x,
+ const std::pair<first_type,second_type>& y)
+{
+ return !(y<x);
+}
+
+template<typename first_type,typename second_type>
+bool operator<=(
+ const std::pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return !(y<x);
+}
+
+/* >= */
+
+template<typename first_type,typename second_type>
+bool operator>=(
+ const inv_pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return !(x<y);
+}
+
+template<typename first_type,typename second_type>
+bool operator>=(
+ const inv_pair<first_type,second_type>& x,
+ const std::pair<first_type,second_type>& y)
+{
+ return !(x<y);
+}
+
+template<typename first_type,typename second_type>
+bool operator>=(
+ const std::pair<first_type,second_type>& x,
+ const inv_pair<first_type,second_type>& y)
+{
+ return !(x<y);
+}
+
+/* bimap_base is the common base for all bimaps */
+
+struct bimap_base
+{
+ class value_not_found:public std::logic_error
+ {
+ public:
+ value_not_found():logic_error("value not found"){}
+ value_not_found(const std::string& str):logic_error(str){}
+ };
+
+ class duplicate_value:public std::logic_error
+ {
+ public:
+ duplicate_value():logic_error("duplicate value"){}
+ duplicate_value(const std::string& str):logic_error(str){}
+ };
+
+protected:
+ /* from_binding and company implement operator[]s. They're
+ * defined outside from and to memberspaces because
+ * otherwise VC++ chokes and produces an internal compiler
+ * error under some circumstances.
+ */
+
+ template<typename bimap_type>
+ class from_binding
+ {
+ public:
+ from_binding(bimap_type& bm,const typename bimap_type::from_type& f):bm(bm),f(f){}
+
+ const typename bimap_type::to_type& get()const
+ {
+ typename bimap_type::from_set::const_iterator it=bm.fset.find(&f);
+ if(it==bm.fset.end())throw value_not_found();
+ return bimap_type::element_by_from(*it)->second;
+ }
+
+ operator const typename bimap_type::to_type&()const
+ {
+ return get();
+ }
+
+ from_binding& operator=(const typename bimap_type::to_type& t)
+ {
+ /* MSVC++ chokes if a ctor for typename bimap_type::element
+ * is called directly.
+ */
+
+ typedef typename bimap_type::element bimap_element;
+
+ typename bimap_type::fset_iterator fit=bm.fset.find(&f);
+ typename bimap_type::tset_iterator tit=bm.tset.find(&t);
+ if(tit!=bm.tset.end()){ /* v.second shouldn't be already in */
+ /* small chance the pair (f,t) is already inserted */
+ if(fit!=bm.fset.end()&&
+ bimap_type::element_by_from(*fit)==bimap_type::element_by_to(*tit)){
+ return *this;
+ }
+ else throw duplicate_value();
+ }
+
+ bimap_element * pne=0;
+ typename bimap_type::tset_iterator tnit=bm.tset.end();
+ try{
+ pne=bm.new_element(bimap_element(f,t));
+ tnit=bm.tset.insert(&pne->second).first;
+ if(fit==bm.fset.end()){
+ bm.fset.insert(&pne->first);
+ return *this;
+ }
+ else{ // rebound fit
+ bimap_element * pe=bimap_type::element_by_from(*fit);
+ bm.tset.erase(bm.tset.find(&pe->second));
+ bm.delete_element(pe);
+ const_cast<typename bimap_type::from_type *&>(*fit)=
+ &const_cast<typename bimap_type::from_type &>(pne->first);
+ return *this;
+ }
+ }catch(...){
+ if(tnit!=bm.tset.end())bm.tset.erase(tnit);
+ if(pne)bm.delete_element(pne);
+ throw;
+ }
+ }
+
+ private:
+ from_binding& operator=(const from_binding&);
+
+ bimap_type& bm;
+ const typename bimap_type::from_type f;
+ };
+
+ template<typename bimap_type>
+ class const_from_binding
+ {
+ public:
+ const_from_binding(const bimap_type& bm,const typename bimap_type::from_type& f):
+ bm(bm),f(f)
+ {}
+
+ const typename bimap_type::to_type& get()const
+ {
+ typename bimap_type::from_set::const_iterator it=bm.fset.find(&f);
+ if(it==bm.fset.end())throw value_not_found();
+ return bimap_type::element_by_from(*it)->second;
+ }
+
+ operator const typename bimap_type::to_type&()const
+ {
+ return get();
+ }
+
+ private:
+ const_from_binding& operator=(const const_from_binding&);
+
+ const bimap_type& bm;
+ const typename bimap_type::from_type f;
+ };
+
+ template<typename bimap_type>
+ class to_binding
+ {
+ public:
+ to_binding(bimap_type& bm,const typename bimap_type::to_type& t):bm(bm),t(t){}
+
+ const typename bimap_type::from_type& get()const
+ {
+ typename bimap_type::to_set::const_iterator it=bm.tset.find(&t);
+ if(it==bm.tset.end())throw value_not_found();
+ return bimap_type::element_by_to(*it)->first;
+ }
+
+ operator const typename bimap_type::from_type&()const
+ {
+ return get();
+ }
+
+ to_binding& operator=(const typename bimap_type::from_type& f)
+ {
+ /* MSVC++ chokes if a ctor for typename bimap_type::element
+ * is called directly.
+ */
+
+ typedef typename bimap_type::element bimap_element;
+
+ typename bimap_type::tset_iterator tit=bm.tset.find(&t);
+ typename bimap_type::fset_iterator fit=bm.fset.find(&f);
+ if(fit!=bm.fset.end()){ /* v.second shouldn't be already in */
+ /* small chance the pair (f,t) is already inserted */
+ if(tit!=bm.tset.end()&&
+ bimap_type::element_by_to(*tit)==bimap_type::element_by_from(*fit)){
+ return *this;
+ }
+ else throw duplicate_value();
+ }
+
+ bimap_element * pne=0;
+ typename bimap_type::fset_iterator fnit=bm.fset.end();
+ try{
+ pne=bm.new_element(bimap_element(f,t));
+ fnit=bm.fset.insert(&pne->first).first;
+ if(tit==bm.tset.end()){
+ bm.tset.insert(&pne->second);
+ return *this;
+ }
+ else{ // rebound tit
+ bimap_element * pe=bimap_type::element_by_to(*tit);
+ bm.fset.erase(bm.fset.find(&pe->first));
+ bm.delete_element(pe);
+ const_cast<typename bimap_type::to_type *&>(*tit)=
+ &const_cast<typename bimap_type::to_type &>(pne->second);
+ return *this;
+ }
+ }catch(...){
+ if(fnit!=bm.fset.end())bm.fset.erase(fnit);
+ if(pne)bm.delete_element(pne);
+ throw;
+ }
+ }
+
+ private:
+ to_binding& operator=(const to_binding&);
+
+ bimap_type& bm;
+ const typename bimap_type::to_type t;
+ };
+
+ template<typename bimap_type>
+ class const_to_binding
+ {
+ public:
+ const_to_binding(const bimap_type& bm,const typename bimap_type::to_type& t):
+ bm(bm),t(t)
+ {}
+
+ const typename bimap_type::from_type& get()const
+ {
+ typename bimap_type::to_set::const_iterator it=bm.tset.find(&t);
+ if(it==bm.tset.end())throw value_not_found();
+ return bimap_type::element_by_to(*it)->first;
+ }
+
+ operator const typename bimap_type::from_type&()const
+ {
+ return get();
+ }
+
+ private:
+ const_to_binding& operator=(const const_to_binding&);
+
+ const bimap_type& bm;
+ const typename bimap_type::to_type t;
+ };
+};
+
+/* prebimap holds the entire code for bimap except for the
+ * global memberspace, which is constructed via simulated PTS
+ * in bimap (derived from prebimap).
+ */
+
+template<
+ typename from_type_,typename to_type_,
+ typename from_compare,typename to_compare,
+ typename allocator_type_>
+class prebimap:public bimap_base
+{
+private:
+ /* Data structure. The bidirectional map is implemented with two sets
+ * fset and tset indexing the corresponding members of elements of type
+ * direct_pair<from_type,to_type>.
+ */
+
+ typedef from_type_ from_type;
+ typedef to_type_ to_type;
+
+ template<typename type,typename compare>
+ struct p_compare /* pointer compare based on value compare */
+ {
+ p_compare(const compare& c=compare()):c(c){}
+ bool operator()(const type* p1,const type* p2)const{return c(*p1,*p2);}
+ compare get_compare()const{return c;}
+ private:
+ compare c;
+ };
+
+ typedef std::set<
+ const from_type*,
+ p_compare<
+ from_type,
+ from_compare>,
+ BIMAP_REBIND_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(allocator_type_,const from_type*)>
+ from_set;
+ typedef std::set<
+ const to_type*,
+ p_compare<
+ to_type,
+ to_compare>,
+ BIMAP_REBIND_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(allocator_type_,const to_type*)>
+ to_set;
+ typedef typename from_set::allocator_type fset_allocator_type;
+ typedef typename to_set::allocator_type tset_allocator_type;
+ typedef typename from_set::iterator fset_iterator;
+ typedef typename from_set::const_iterator const_fset_iterator;
+ typedef typename to_set::iterator tset_iterator;
+ typedef typename to_set::const_iterator const_tset_iterator;
+ typedef direct_pair<
+ const from_type,
+ const to_type> element;
+ allocator_type_ allocator;
+ from_set fset;
+ to_set tset;
+
+ /* Basic data management */
+
+ /* new_element and delete_element deal only with allocation/
+ * deallocation of elements, i.e. they do not update fset and tset.
+ */
+
+ element * new_element(const element& e)
+ {
+ element * pe=allocator.allocate(1,0);
+ try{
+ allocator.construct(pe,e);
+ }catch(...){
+ allocator.destroy(pe);
+ throw;
+ }
+ return pe;
+ }
+
+ void delete_element(element *pe)
+ {
+ allocator.destroy(pe);
+ allocator.deallocate(pe,1);
+ }
+
+ static element * element_by_from(const from_type* pf)
+ {
+ return
+ reinterpret_cast<element*>(
+ reinterpret_cast<char*>(
+ const_cast<from_type *>(pf))-
+ BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(element,first));
+ }
+
+ static element * element_by_to(const to_type* pt)
+ {
+ return
+ reinterpret_cast<element *>(
+ reinterpret_cast<char*>(
+ const_cast<to_type *>(pt))-
+ BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(element,second));
+ }
+
+public:
+ /* memberspace from */
+
+ class from_impl
+ {
+ public:
+
+ /* assigning a from_impl object is the same as assigning its owner */
+
+ from_impl& operator=(const from_impl& r)
+ {
+ prebimap tmp(r.owner());
+ swap(tmp.from);
+ return *this;
+ }
+
+ /* Comparison */
+
+ bool operator==(const from_impl& r)const
+ {
+ return size()==r.size()&&std::equal(begin(),end(),r.begin());
+ }
+
+ bool operator!=(const from_impl& r)const
+ {
+ return !(*this==r);
+ }
+
+ bool operator<(const from_impl& r)const
+ {
+ return
+ std::lexicographical_compare(
+ begin(),end(),r.begin(),r.end());
+ }
+
+ bool operator>(const from_impl& r)const
+ {
+ return r<*this;
+ }
+
+ bool operator<=(const from_impl& r)const
+ {
+ return !(r<*this);
+ }
+
+ bool operator>=(const from_impl& r)const
+ {
+ return !(*this<r);
+ }
+
+ /* Standard member types */
+
+ typedef from_type_ key_type;
+ typedef to_type_ mapped_type;
+ typedef to_type_ referent_type; /* prestandard synonim */
+ typedef to_type_ data_type; /* prestandard synonim */
+ typedef from_compare key_compare;
+ typedef allocator_type_ allocator_type;
+ typedef
+ direct_pair<
+ const from_type_,
+ const to_type_> value_type;
+
+ /* value_compare lexicographically orders value_type's. This is
+ * compatible with the weaker value_compare implemented by maps.
+ */
+
+ class value_compare:public std::binary_function<value_type,value_type,bool>
+ {
+ public:
+ bool operator()(const value_type& x,const value_type& y)
+ {
+ if(kcomp(x.first,y.first))return true;
+ if(kcomp(y.first,x.first))return false;
+ return tcomp(x.second,y.second);
+ }
+ protected:
+ value_compare(key_compare kcomp,to_compare tcomp):kcomp(kcomp),tcomp(tcomp){}
+ key_compare kcomp;
+ to_compare tcomp;
+ };
+
+ typedef typename allocator_type_::size_type size_type;
+ typedef typename allocator_type_::difference_type difference_type;
+ typedef value_type * pointer;
+ typedef const value_type * const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+
+ /* Iterators */
+
+ class const_iterator;
+ class iterator:public std::iterator<std::bidirectional_iterator_tag,const value_type>
+ {
+ friend class from_impl;
+ friend class const_iterator;
+ friend class prebimap<from_type,to_type,from_compare,to_compare,allocator_type>;
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+ /* MSVC++ 6.0 fails to define reference in std::iterator */
+
+ typedef const value_type& reference;
+#endif
+
+ public:
+ iterator(){}
+
+#ifdef __MWERKS__
+ /* strange bug */
+
+ typename reference operator*()const{return *element_by_from(*fit);}
+ typename value_type * operator->()const{return &operator*();}
+#else
+ typename iterator::reference operator*()const{return *element_by_from(*fit);}
+ typename iterator::value_type * operator->()const{return &operator*();}
+#endif
+
+ iterator& operator++(){++fit;return *this;}
+ const iterator operator++(int){const iterator tmp=*this;++*this;return tmp;}
+ iterator& operator--(){--fit;return *this;}
+ const iterator operator--(int){const iterator tmp=*this;--*this;return tmp;}
+ bool operator==(const iterator& it)const{return fit==it.fit;}
+ bool operator!=(const iterator& it)const{return !(*this==it);}
+ private:
+ iterator(const fset_iterator& fit):fit(fit){}
+ fset_iterator fit;
+ };
+
+ class const_iterator:public std::iterator<std::bidirectional_iterator_tag,const value_type>
+ {
+ friend class from_impl;
+ friend class prebimap<from_type,to_type,from_compare,to_compare,allocator_type>;
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+ /* MSVC++ 6.0 fails to define reference in std::iterator */
+
+ typedef const value_type& reference;
+#endif
+
+ public:
+ const_iterator(){}
+ const_iterator(const iterator& it):fit(it.fit){}
+
+#ifdef __MWERKS__
+ /* strange bug */
+
+ typename reference operator*()const{return *element_by_from(*fit);}
+ const typename value_type * operator->()const{return &operator*();}
+#else
+ typename const_iterator::reference operator*()const{return *element_by_from(*fit);}
+ const typename const_iterator::value_type * operator->()const{return &operator*();}
+#endif
+
+ const_iterator& operator++(){++fit;return *this;}
+ const const_iterator operator++(int){const const_iterator tmp=*this;++*this;return tmp;}
+ const_iterator& operator--(){--fit;return *this;}
+ const const_iterator operator--(int){const const_iterator tmp=*this;--*this;return tmp;}
+ bool operator==(const const_iterator& it)const{return fit==it.fit;}
+ bool operator!=(const const_iterator& it)const{return !(*this==it);}
+ private:
+ const_iterator(const const_fset_iterator& fit):fit(fit){}
+ const_fset_iterator fit;
+ };
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+ typedef
+ std::reverse_bidirectional_iterator<
+ const_iterator,
+ const value_type,
+ const_reference,
+ const value_type *,
+ difference_type> reverse_iterator;
+#else
+ typedef std::reverse_iterator<const_iterator> reverse_iterator;
+#endif
+
+ typedef reverse_iterator const_reverse_iterator;
+
+ /* Iterator retrieval methods */
+
+ iterator begin(){return iterator(owner().fset.begin());}
+ const_iterator begin()const{return const_iterator(owner().fset.begin());}
+ iterator end(){return iterator(owner().fset.end());}
+ const_iterator end()const{return const_iterator(owner().fset.end());}
+
+ reverse_iterator rbegin(){return reverse_iterator(end());}
+ const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}
+ reverse_iterator rend(){return reverse_iterator(begin());}
+ const_reverse_iterator rend()const{return const_reverse_iterator(begin());}
+
+ /* Utility standard methods */
+
+ size_type size()const{return owner().fset.size();}
+ size_type max_size()const{return owner().fset.max_size();}
+ bool empty()const{return owner().fset.empty();}
+ allocator_type get_allocator()const{return owner().allocator;}
+
+ /* operator []. Uses wrapper classes from_binding and const_from_binding. */
+
+ from_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ operator[](const from_type_& f)
+ {
+ return
+ from_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ (owner(),f);
+ }
+
+ const_from_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ operator[](const from_type_& f)const
+ {
+ return
+ const_from_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ (owner(),f);
+ }
+
+ /* Insertion and erasing */
+
+ std::pair<iterator,bool> insert(const value_type& x)
+ {
+ fset_iterator fit=owner().fset.find(&x.first);
+ if(fit!=owner().fset.end()){
+ return std::make_pair(iterator(fit),false);
+ }
+ tset_iterator tit=owner().tset.find(&x.second);
+ if(tit!=owner().tset.end())throw duplicate_value();
+
+ element * pe=0;
+ tset_iterator tnit=owner().tset.end();
+ fset_iterator fnit=owner().fset.end();
+ try{
+ pe=owner().new_element(x);
+ tnit=owner().tset.insert(&pe->second).first;
+ fnit=owner().fset.insert(&pe->first).first;
+ }catch(...){
+ if(tnit!=owner().tset.end())owner().tset.erase(tnit);
+ if(pe)owner().delete_element(pe);
+ throw;
+ }
+ return std::make_pair(iterator(fnit),true);
+ }
+
+ iterator insert(iterator it,const value_type& x)
+ {
+ if(!adjacent(it.fit,x.first))return insert(x).first;
+
+ tset_iterator tit=owner().tset.find(&x.second);
+ if(tit!=owner().tset.end())throw duplicate_value();
+
+ element * pe=0;
+ tset_iterator tnit=owner().tset.end();
+ fset_iterator fnit=owner().fset.end();
+ try{
+ pe=owner().new_element(x);
+ tnit=owner().tset.insert(&pe->second).first;
+ fnit=owner().fset.insert(it.fit,&pe->first);
+ }catch(...){
+ if(tnit!=owner().tset.end())owner().tset.erase(tnit);
+ if(pe)owner().delete_element(pe);
+ throw;
+ }
+ return iterator(fnit);
+ }
+
+ template<typename it_type>
+ void insert(it_type first,it_type last)
+ {
+ while(first!=last){
+ insert(*first);
+ ++first;
+ }
+ }
+
+
+#ifdef _MSC_VER
+ /* The standard says the return type for iterator-based erases
+ * in associative containers is void. Strangely enough, VC++
+ * implementation returns an iterator. We keep the iterator return
+ * for the first version of erase.
+ */
+
+ iterator erase(iterator it)
+ {
+ fset_iterator& fit=it.fit;
+ element * pe=element_by_from(*fit);
+ tset_iterator tit=owner().tset.find(&pe->second);
+ owner().delete_element(pe);
+ owner().tset.erase(tit);
+ return(iterator(owner().fset.erase(fit)));
+ }
+#else
+ void erase(iterator it)
+ {
+ fset_iterator& fit=it.fit;
+ element * pe=element_by_from(*fit);
+ tset_iterator tit=owner().tset.find(&pe->second);
+ owner().delete_element(pe);
+ owner().tset.erase(tit);
+ owner().fset.erase(fit);
+ }
+#endif
+
+ void erase(iterator first,iterator last)
+ {
+ while(first!=last)erase(first++);
+ }
+
+ size_type erase(const key_type& key)
+ {
+ fset_iterator fit=owner().fset.find(&key);
+ if(fit==owner().fset.end())return 0;
+ element * pe=element_by_from(*fit);
+ owner().tset.erase(owner().tset.find(&pe->second));
+ owner().fset.erase(fit);
+ owner().delete_element(pe);
+ return 1;
+ }
+
+ void clear()
+ {
+ erase(begin(),end());
+ }
+
+ void swap(from_impl& x)
+ {
+ /* assumes allocator equivalence */
+
+ owner().fset.swap(x.owner().fset);
+ owner().tset.swap(x.owner().tset);
+ }
+
+ /* Search methods */
+
+ key_compare key_comp()const
+ {
+ return owner().fset.key_comp().get_compare();
+ }
+
+ value_compare value_comp()const
+ {
+ return
+ value_compare(
+ owner().fset.key_comp().get_compare(),
+ owner().tset.key_comp().get_compare());
+ }
+
+ iterator find(const key_type& key)
+ {
+ return iterator(owner().fset.find(&key));
+ }
+
+ const_iterator find(const key_type& key)const
+ {
+ return const_iterator(owner().fset.find(&key));
+ }
+
+ size_type count(const key_type& key)const
+ {
+ return owner().fset.count(&key);
+ }
+
+ iterator lower_bound(const key_type& key)
+ {
+ return iterator(owner().fset.lower_bound(&key));
+ }
+
+ const_iterator lower_bound(const key_type& key)const
+ {
+ return const_iterator(owner().fset.lower_bound(&key));
+ }
+
+ iterator upper_bound(const key_type& key)
+ {
+ return iterator(owner().fset.upper_bound(&key));
+ }
+
+ const_iterator upper_bound(const key_type& key)const
+ {
+ return const_iterator(owner().fset.upper_bound(&key));
+ }
+
+ std::pair<iterator,iterator> equal_range(const key_type& key)
+ {
+ return std::make_pair(lower_bound(key),upper_bound(key));
+ }
+
+ std::pair<const_iterator,const_iterator> equal_range(const key_type& key)const
+ {
+ return std::make_pair(lower_bound(key),upper_bound(key));
+ }
+
+ protected:
+ from_impl(){}
+ from_impl(const from_impl&);
+
+ prebimap& owner()
+ {
+ return *reinterpret_cast<prebimap*>(
+ reinterpret_cast<char*>(this)-
+ BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(prebimap,from));
+ };
+ const prebimap& owner()const
+ {
+ return *reinterpret_cast<const prebimap*>(
+ reinterpret_cast<const char*>(this)-
+ BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(prebimap,from));
+ };
+
+ bool adjacent(const_fset_iterator fit,const from_type_& f)const
+ {
+ if(fit==owner().fset.end()){
+ if(owner().fset.size()==0)return true;
+ const_fset_iterator fit2=fit;
+ --fit2;
+ return owner().fset.key_comp()(*fit2,&f);
+ }
+ else if(owner().fset.key_comp()(&f,*fit)){
+ if(fit==owner().fset.begin())return true;
+ const_fset_iterator fit2=fit;
+ --fit2;
+ return owner().fset.key_comp()(*fit2,&f);
+
+ }
+ else if(owner().fset.key_comp()(*fit,&f)){
+ const_fset_iterator fit2=fit;
+ ++fit2;
+ if(fit2==owner().fset.end())return true;
+ return owner().fset.key_comp()(&f,*fit2);
+ }
+ else return false;
+ }
+ };
+
+ friend class from_impl;
+
+ class from:public from_impl
+ {
+ friend class prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_>;
+
+ public:
+ friend void swap(from& x,from& y)
+ {
+ x.swap(y);
+ }
+ }from; /* from memberspace */
+
+#ifdef __MWERKS__
+ /* strange bug */
+
+ friend class from_impl::iterator;
+ friend class from_impl::const_iterator;
+#elif defined(_MSC_VER)
+ friend typename from::iterator;
+ friend typename from::const_iterator;
+#endif
+
+ friend class from_binding<prebimap>;
+ friend class const_from_binding<prebimap>;
+
+ /* memberspace to, symetrical to from */
+
+ class to_impl
+ {
+ public:
+
+ to_impl& operator=(const to_impl& r)
+ {
+ prebimap tmp(r.owner());
+ swap(tmp.to);
+ return *this;
+ }
+
+ /* Comparison */
+
+ bool operator==(const to_impl& r)const
+ {
+ return size()==r.size()&&std::equal(begin(),end(),r.begin());
+ }
+
+ bool operator!=(const to_impl& r)const
+ {
+ return !(*this==r);
+ }
+
+ bool operator<(const to_impl& r)const
+ {
+ return
+ std::lexicographical_compare(
+ begin(),end(),r.begin(),r.end());
+ }
+
+ bool operator>(const to_impl& r)const
+ {
+ return r<*this;
+ }
+
+ bool operator<=(const to_impl& r)const
+ {
+ return !(r<*this);
+ }
+
+ bool operator>=(const to_impl& r)const
+ {
+ return !(*this<r);
+ }
+
+ /* Standard member types */
+
+ typedef to_type_ key_type;
+ typedef from_type_ mapped_type;
+ typedef from_type_ referent_type; /* prestandard synonim */
+ typedef from_type_ data_type; /* prestandard synonim */
+ typedef to_compare key_compare;
+ typedef allocator_type_ allocator_type;
+ typedef
+ inv_pair<
+ const to_type_,
+ const from_type_> value_type;
+
+ class value_compare:public std::binary_function<value_type,value_type,bool>
+ {
+ public:
+ bool operator()(const value_type& x,const value_type& y)
+ {
+ if(kcomp(x.first,y.first))return true;
+ if(kcomp(y.first,x.first))return false;
+ return fcomp(x.second,y.second);
+ }
+ protected:
+ value_compare(key_compare kcomp,from_compare fcomp):kcomp(kcomp),fcomp(fcomp){}
+ key_compare kcomp;
+ from_compare fcomp;
+ };
+
+ typedef typename allocator_type_::size_type size_type;
+ typedef typename allocator_type_::difference_type difference_type;
+ typedef value_type * pointer;
+ typedef const value_type * const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+
+ /* Iterators */
+
+ class const_iterator;
+ class iterator:public std::iterator<std::bidirectional_iterator_tag,const value_type>
+ {
+ friend class to_impl;
+ friend class const_iterator;
+ friend class prebimap<from_type,to_type,from_compare,to_compare,allocator_type>;
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+ /* MSVC++ 6.0 fails to define reference in std::iterator */
+
+ typedef const value_type& reference;
+#endif
+ public:
+ iterator(){}
+
+#ifdef __MWERKS__
+ /* strange bug */
+
+ typename reference operator*()const{return *element_by_to(*tit);}
+ typename value_type * operator->()const{return &operator*();}
+#else
+ typename iterator::reference operator*()const{return *element_by_to(*tit);}
+ typename iterator::value_type * operator->()const{return &operator*();}
+#endif
+
+ iterator& operator++(){++tit;return *this;}
+ const iterator operator++(int){const iterator tmp=*this;++*this;return tmp;}
+ iterator& operator--(){--tit;return *this;}
+ const iterator operator--(int){const iterator tmp=*this;--*this;return tmp;}
+ bool operator==(const iterator& it)const{return tit==it.tit;}
+ bool operator!=(const iterator& it)const{return !(*this==it);}
+ private:
+ iterator(const tset_iterator& tit):tit(tit){}
+ tset_iterator tit;
+ };
+
+ class const_iterator:public std::iterator<std::bidirectional_iterator_tag,const value_type>
+ {
+ friend class to_impl;
+ friend class prebimap<from_type,to_type,from_compare,to_compare,allocator_type>;
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+ /* MSVC++ 6.0 fails to define reference in std::iterator */
+
+ typedef const value_type& reference;
+#endif
+
+ public:
+ const_iterator(){}
+ const_iterator(const iterator& it):tit(it.tit){}
+
+#ifdef __MWERKS__
+ /* strange bug */
+
+ typename reference operator*()const{return *element_by_to(*tit);}
+ const typename value_type * operator->()const{return &operator*();}
+#else
+ typename const_iterator::reference operator*()const{return *element_by_to(*tit);}
+ const typename const_iterator::value_type * operator->()const{return &operator*();}
+#endif
+
+ const_iterator& operator++(){++tit;return *this;}
+ const const_iterator operator++(int){const const_iterator tmp=*this;++*this;return tmp;}
+ const_iterator& operator--(){--tit;return *this;}
+ const const_iterator operator--(int){const const_iterator tmp=*this;--*this;return tmp;}
+ bool operator==(const const_iterator& it)const{return tit==it.tit;}
+ bool operator!=(const const_iterator& it)const{return !(*this==it);}
+ private:
+ const_iterator(const const_tset_iterator& tit):tit(tit){}
+ const_tset_iterator tit;
+ };
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+ typedef
+ std::reverse_bidirectional_iterator<
+ const_iterator,
+ const value_type,
+ const_reference,
+ const value_type *,
+ difference_type> reverse_iterator;
+#else
+ typedef std::reverse_iterator<const_iterator> reverse_iterator;
+#endif
+
+ typedef reverse_iterator const_reverse_iterator;
+
+ /* Iterator retrieval methods */
+
+ iterator begin(){return iterator(owner().tset.begin());}
+ const_iterator begin()const{return const_iterator(owner().tset.begin());}
+ iterator end(){return iterator(owner().tset.end());}
+ const_iterator end()const{return const_iterator(owner().tset.end());}
+
+ reverse_iterator rbegin(){return reverse_iterator(end());}
+ const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}
+ reverse_iterator rend(){return reverse_iterator(begin());}
+ const_reverse_iterator rend()const{return const_reverse_iterator(begin());}
+
+ /* Utility standard methods */
+
+ size_type size()const{return owner().tset.size();}
+ size_type max_size()const{return owner().tset.max_size();}
+ bool empty()const{return owner().tset.empty();}
+ allocator_type get_allocator()const{return owner().allocator;}
+
+ /* operator []. Uses wrapper classes to_binding and const_to_binding. */
+
+ to_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ operator[](const to_type_& t)
+ {
+ return
+ to_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ (owner(),t);
+ }
+
+ const_to_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ operator[](const to_type_& t)const
+ {
+ return
+ const_to_binding<prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> >
+ (owner(),t);
+ }
+
+ /* Insertion and erasing */
+
+ std::pair<iterator,bool> insert(const value_type& x)
+ {
+ tset_iterator tit=owner().tset.find(&x.first);
+ if(tit!=owner().tset.end()){
+ return std::make_pair(iterator(tit),false);
+ }
+ fset_iterator fit=owner().fset.find(&x.second);
+ if(fit!=owner().fset.end())throw duplicate_value();
+
+ element * pe=0;
+ fset_iterator fnit=owner().fset.end();
+ tset_iterator tnit=owner().tset.end();
+ try{
+ pe=owner().new_element(x);
+ fnit=owner().fset.insert(&pe->first).first;
+ tnit=owner().tset.insert(&pe->second).first;
+ }catch(...){
+ if(fnit!=owner().fset.end())owner().fset.erase(fnit);
+ if(pe)owner().delete_element(pe);
+ throw;
+ }
+ return std::make_pair(iterator(tnit),true);
+ }
+
+ iterator insert(iterator it,const value_type& x)
+ {
+ if(!adjacent(it.tit,x.first))return insert(x).first;
+
+ fset_iterator fit=owner().fset.find(&x.second);
+ if(fit!=owner().fset.end())throw duplicate_value();
+
+ element * pe=0;
+ fset_iterator fnit=owner().fset.end();
+ tset_iterator tnit=owner().tset.end();
+ try{
+ pe=owner().new_element(x);
+ fnit=owner().fset.insert(&pe->first).first;
+ tnit=owner().tset.insert(it.tit,&pe->second);
+ }catch(...){
+ if(fnit!=owner().fset.end())owner().fset.erase(fnit);
+ if(pe)owner().delete_element(pe);
+ throw;
+ }
+ return iterator(tnit);
+ }
+
+ template<typename it_type>
+ void insert(it_type first,it_type last)
+ {
+ while(first!=last){
+ insert(*first);
+ ++first;
+ }
+ }
+
+
+#ifdef _MSC_VER
+ /* see note in from::erase */
+
+ iterator erase(iterator it)
+ {
+ tset_iterator& tit=it.tit;
+ element * pe=element_by_to(*tit);
+ fset_iterator fit=owner().fset.find(&pe->first);
+ owner().delete_element(pe);
+ owner().fset.erase(fit);
+ return(iterator(owner().tset.erase(tit)));
+ }
+#else
+ void erase(iterator it)
+ {
+ tset_iterator& tit=it.tit;
+ element * pe=element_by_to(*tit);
+ fset_iterator fit=owner().fset.find(&pe->first);
+ owner().delete_element(pe);
+ owner().fset.erase(fit);
+ owner().tset.erase(tit);
+ }
+#endif
+
+ void erase(iterator first,iterator last)
+ {
+ while(first!=last)erase(first++);
+ }
+
+ size_type erase(const key_type& key)
+ {
+ tset_iterator tit=owner().tset.find(&key);
+ if(tit==owner().tset.end())return 0;
+ element * pe=element_by_to(*tit);
+ owner().fset.erase(owner().fset.find(&pe->first));
+ owner().tset.erase(tit);
+ owner().delete_element(pe);
+ return 1;
+ }
+
+ void clear()
+ {
+ erase(begin(),end());
+ }
+
+ void swap(to_impl& x)
+ {
+ /* assumes allocator equivalence */
+
+ owner().tset.swap(x.owner().tset);
+ owner().fset.swap(x.owner().fset);
+ }
+
+ /* Search methods */
+
+ key_compare key_comp()const
+ {
+ return owner().tset.key_comp().get_compare();
+ }
+
+ value_compare value_comp()const
+ {
+ return
+ value_compare(
+ owner().tset.key_comp().get_compare(),
+ owner().fset.key_comp().get_compare());
+ }
+
+ iterator find(const key_type& key)
+ {
+ return iterator(owner().tset.find(&key));
+ }
+
+ const_iterator find(const key_type& key)const
+ {
+ return const_iterator(owner().tset.find(&key));
+ }
+
+ size_type count(const key_type& key)const
+ {
+ return owner().tset.count(&key);
+ }
+
+ iterator lower_bound(const key_type& key)
+ {
+ return iterator(owner().tset.lower_bound(&key));
+ }
+
+ const_iterator lower_bound(const key_type& key)const
+ {
+ return const_iterator(owner().tset.lower_bound(&key));
+ }
+
+ iterator upper_bound(const key_type& key)
+ {
+ return iterator(owner().tset.upper_bound(&key));
+ }
+
+ const_iterator upper_bound(const key_type& key)const
+ {
+ return const_iterator(owner().tset.upper_bound(&key));
+ }
+
+ std::pair<iterator,iterator> equal_range(const key_type& key)
+ {
+ return std::make_pair(lower_bound(key),upper_bound(key));
+ }
+
+ std::pair<const_iterator,const_iterator> equal_range(const key_type& key)const
+ {
+ return std::make_pair(lower_bound(key),upper_bound(key));
+ }
+
+ protected:
+ to_impl(){}
+ to_impl(const to_impl&);
+
+ prebimap& owner()
+ {
+ return *reinterpret_cast<prebimap*>(
+ reinterpret_cast<char*>(this)-
+ BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(prebimap,to));
+ };
+ const prebimap& owner()const
+ {
+ return *reinterpret_cast<const prebimap*>(
+ reinterpret_cast<const char*>(this)-
+ BIMAP_OFFSETOF_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761(prebimap,to));
+ };
+
+ bool adjacent(const_tset_iterator tit,const to_type_& t)const
+ {
+ if(tit==owner().tset.end()){
+ if(owner().tset.size()==0)return true;
+ const_tset_iterator tit2=tit;
+ --tit2;
+ return owner().tset.key_comp()(*tit2,&t);
+ }
+ else if(owner().tset.key_comp()(&t,*tit)){
+ if(tit==owner().tset.begin())return true;
+ const_tset_iterator tit2=tit;
+ --tit2;
+ return owner().tset.key_comp()(*tit2,&t);
+
+ }
+ else if(owner().tset.key_comp()(*tit,&t)){
+ const_tset_iterator tit2=tit;
+ ++tit2;
+ if(tit2==owner().tset.end())return true;
+ return owner().tset.key_comp()(&t,*tit2);
+ }
+ else return false;
+ }
+ };
+
+ friend class to_impl;
+
+ class to:public to_impl
+ {
+ friend class prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_>;
+
+ public:
+ friend void swap(to& x,to& y)
+ {
+ x.swap(y);
+ }
+ }to; /* to memberspace */
+
+#ifdef __MWERKS__
+ /* strange bug */
+
+ friend class to_impl::iterator;
+ friend class to_impl::const_iterator;
+#elif defined(_MSC_VER)
+ friend typename to::iterator;
+ friend typename to::const_iterator;
+#endif
+
+ friend class to_binding<prebimap>;
+ friend class const_to_binding<prebimap>;
+
+ /* Double-hint insertion. This does not naturally belong into any
+ * memberspace.
+ */
+
+ std::pair<typename from_impl::iterator,typename to_impl::iterator>
+ insert(
+ typename from_impl::iterator fit,typename to_impl::iterator tit,
+ const typename from_impl::value_type& x)
+ {
+ typedef typename from_impl::iterator from_iterator;
+ typedef typename to_impl::iterator to_iterator;
+
+ if(!from.adjacent(fit.fit,x.first)){
+ fit=fset.find(&x.first);
+ if(fit!=fset.end()){ /* small chance x is already inserted */
+ tset_iterator tnit=tset.find(&x.second);
+ if(tnit!=tset.end()&&element_by_from(*(fit.fit))==element_by_to(*tnit)){
+ return std::make_pair(fit,to_iterator(tnit));
+ }
+ else throw duplicate_value();
+ }
+ }
+
+ if(!to.adjacent(tit.tit,x.second)){
+ tit=tset.find(&x.second);
+ if(tit!=tset.end()) throw duplicate_value();
+ /* no need to check for x being inserted (already done above) */
+ }
+
+ element * pe=0;
+ tset_iterator tnit=tset.begin();
+ fset_iterator fnit=fset.begin();
+ try{
+ pe=new_element(x);
+ tnit=tset.insert(tit.tit,&pe->second);
+ fnit=fset.insert(fit.fit,&pe->first);
+ }catch(...){
+ if(tnit!=tset.end())tset.erase(tnit);
+ if(pe)delete_element(pe);
+ throw;
+ }
+ return std::make_pair(from_iterator(fnit),to_iterator(tnit));
+ }
+
+protected:
+ prebimap(
+ const from_compare& from_comp,
+ const to_compare& to_comp,
+ const allocator_type_& al):
+ allocator(al),
+ fset(p_compare<from_type,from_compare>(from_comp),fset_allocator_type(allocator)),
+ tset(p_compare<to_type,to_compare>(to_comp),tset_allocator_type(allocator))
+ {}
+
+ prebimap(const prebimap& r):
+ allocator(r.allocator),
+ fset(r.fset.key_comp(),fset_allocator_type(allocator)),
+ tset(r.tset.key_comp(),tset_allocator_type(allocator))
+ {
+ try{
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+/* Amortized constant insertion in VC++ 6.0 happens if hint iterator is
+ * right *after* the insertion point, in disagreement with the standard.
+ */
+
+ typename from::iterator fhint=from.end();
+ typename to::iterator thint=to.end();
+ for(typename from::const_iterator it=r.from.begin();it!=r.from.end();++it){
+ insert(fhint,thint,*it);
+ }
+#else
+ typename from_impl::iterator fhint=from.end();
+ typename to_impl::iterator thint=to.end();
+ for(typename from_impl::const_iterator it=r.from.begin();it!=r.from.end();++it){
+ std::pair<typename from_impl::iterator,typename to_impl::iterator>
+ p=insert(fhint,thint,*it);
+ fhint=p.first;
+ thint=p.second;
+ }
+#endif
+
+ }catch(...){
+ from.clear();
+ throw;
+ }
+ }
+
+ ~prebimap()
+ {
+ for(fset_iterator it=fset.begin();it!=fset.end();++it){
+ delete_element(element_by_from(*it));
+ }
+ }
+};
+
+#ifdef __GNUC__
+/* GCC chokes when trying to derive from a template class with memberspaces.
+ * See http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=9159
+ * for details. prebimap_identity is nothing but compiler sugar to workaround
+ * the problem.
+ */
+
+template<
+ typename from_type,typename to_type,
+ typename from_compare,typename to_compare,
+ typename allocator_type>
+struct prebimap_identity
+{
+ typedef prebimap<from_type,to_type,from_compare,to_compare,allocator_type> type;
+};
+#endif
+
+/* When from_type and to_type are equal, we promote only the from memberspace
+ * to the global memberspace ans members of the to space posing no ambiguity.
+ */
+template<
+ typename from_type_,typename to_type_,
+ typename from_compare,typename to_compare,
+ typename allocator_type_>
+class bimap_equal_types:
+
+#ifdef __GNUC__
+ public prebimap_identity<from_type_,to_type_,from_compare,to_compare,allocator_type_>::type
+#else
+ public prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_>
+#endif
+
+{
+ typedef
+ prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> super;
+ typedef typename super::template from_binding<super> from_binding_t;
+ typedef typename super::template const_from_binding<super> const_from_binding_t;
+ typedef typename super::to::value_type to_value_type;
+ typedef typename super::to::iterator to_iterator;
+
+public:
+ typedef typename super::from::key_type key_type;
+ typedef typename super::from::mapped_type mapped_type;
+ typedef typename super::from::referent_type referent_type;
+ typedef typename super::from::data_type data_type;
+ typedef typename super::from::key_compare key_compare;
+ typedef typename super::from::allocator_type allocator_type;
+ typedef typename super::from::value_type value_type;
+ typedef typename super::from::value_compare value_compare;
+ typedef typename super::from::size_type size_type;
+ typedef typename super::from::difference_type difference_type;
+ typedef typename super::from::pointer pointer;
+ typedef typename super::from::const_pointer const_pointer;
+ typedef typename super::from::reference reference;
+ typedef typename super::from::const_reference const_reference;
+ typedef typename super::from::iterator iterator;
+ typedef typename super::from::const_iterator const_iterator;
+ typedef typename super::from::reverse_iterator reverse_iterator;
+ typedef typename super::from::const_reverse_iterator const_reverse_iterator;
+
+ iterator begin(){return this->from.begin();}
+ const_iterator begin()const{return this->from.begin();}
+ iterator end(){return this->from.end();}
+ const_iterator end()const{return this->from.end();}
+ reverse_iterator rbegin(){return this->from.rbegin();}
+ const_reverse_iterator rbegin()const{return this->from.rbegin();}
+ reverse_iterator rend(){return this->from.rend();}
+ const_reverse_iterator rend()const{return this->from.rend();}
+ size_type size()const{return this->from.size();}
+ size_type max_size()const{return this->from.max_size();}
+ bool empty()const{return this->from.empty();}
+ allocator_type get_allocator()const{return this->from.get_allocator();}
+ from_binding_t operator[](const key_type& key){return this->from[key];}
+ const_from_binding_t operator[](const key_type& key)const{return this->from[key];}
+ using super::insert;
+ std::pair<iterator,bool> insert(const value_type& x){return this->from.insert(x);}
+ iterator insert(iterator it,const value_type& x){return this->from.insert(it,x);}
+ template<
+ typename it_type>
+ void insert(it_type first,it_type last){this->from.insert(first,last);}
+
+#ifdef _MSC_VER /* see note in from::erase */
+ iterator erase(iterator it){return this->from.erase(it);}
+#else
+ void erase(iterator it){this->from.erase(it);}
+#endif
+
+ void erase(iterator first,iterator last){this->from.erase(first,last);}
+ size_type erase(const key_type& key){return this->from.erase(key);}
+ void clear(){this->from.clear();}
+ void swap(bimap_equal_types& x){this->from.swap(x.from);}
+ friend void swap(bimap_equal_types& x,bimap_equal_types& y){x.swap(y);}
+ key_compare key_comp()const{return this->from.key_comp();}
+ value_compare value_comp()const{return this->from.value_comp();}
+ iterator find(const key_type& key){return this->from.find(key);}
+ const_iterator find(const key_type& key)const{return this->from.find(key);}
+ size_type count(const key_type& key)const{return this->from.count(key);}
+ iterator lower_bound(const key_type& key){return this->from.lower_bound(key);}
+ const_iterator lower_bound(const key_type& key)const{return this->from.lower_bound(key);}
+ iterator upper_bound(const key_type& key){return this->from.upper_bound(key);}
+ const_iterator upper_bound(const key_type& key)const{return this->from.upper_bound(key);}
+ std::pair<
+ iterator,
+ iterator> equal_range(const key_type& key){return this->from.equal_range(key);}
+ std::pair<
+ const_iterator,
+ const_iterator> equal_range(const key_type& key)const{return this->from.equal_range(key);}
+
+ /* Promotion of unambiguous parts of the to memberspace */
+
+ std::pair<
+ to_iterator,
+ bool> insert(const to_value_type& x){return this->to.insert(x);}
+ to_iterator insert(to_iterator it,const to_value_type& x){return this->to.insert(it,x);}
+ void insert(const to_value_type *first,const to_value_type *last)
+ {this->to.insert(first,last);}
+
+#ifdef _MSC_VER /* see note in from::erase */
+ to_iterator erase(to_iterator it){return this->to.erase(it);}
+#else
+ void erase(to_iterator it){this->to.erase(it);}
+#endif
+
+ void erase(to_iterator first,to_iterator last){this->to.erase(first,last);}
+
+protected:
+ bimap_equal_types(
+ const from_compare& from_comp,
+ const to_compare& to_comp,
+ const allocator_type_& al):
+ super(from_comp,to_comp,al)
+ {
+ }
+
+ /* default copy ctor serves well */
+};
+
+/* If from_type and to_type are distinct, some more members of the to
+ * memberspace can be promoted to the global memberspace without
+ * ambiguity (notably operator[]).
+ */
+template<
+ typename from_type_,typename to_type_,
+ typename from_compare,typename to_compare,
+ typename allocator_type_>
+class bimap_different_types:
+
+#ifdef __GNUC__
+ public prebimap_identity<from_type_,to_type_,from_compare,to_compare,allocator_type_>::type
+#else
+ public prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_>
+#endif
+
+{
+ typedef
+ prebimap<from_type_,to_type_,from_compare,to_compare,allocator_type_> super;
+ typedef typename super::template from_binding<super> from_binding_t;
+ typedef typename super::template const_from_binding<super> const_from_binding_t;
+ typedef typename super::template to_binding<super> to_binding_t;
+ typedef typename super::template const_to_binding<super> const_to_binding_t;
+ typedef typename super::to::key_type to_key_type;
+ typedef typename super::to::value_type to_value_type;
+ typedef typename super::to::iterator to_iterator;
+ typedef typename super::to::const_iterator const_to_iterator;
+
+public:
+ typedef typename super::from::key_type key_type;
+ typedef typename super::from::mapped_type mapped_type;
+ typedef typename super::from::referent_type referent_type;
+ typedef typename super::from::data_type data_type;
+ typedef typename super::from::key_compare key_compare;
+ typedef typename super::from::allocator_type allocator_type;
+ typedef typename super::from::value_type value_type;
+ typedef typename super::from::value_compare value_compare;
+ typedef typename super::from::size_type size_type;
+ typedef typename super::from::difference_type difference_type;
+ typedef typename super::from::pointer pointer;
+ typedef typename super::from::const_pointer const_pointer;
+ typedef typename super::from::reference reference;
+ typedef typename super::from::const_reference const_reference;
+ typedef typename super::from::iterator iterator;
+ typedef typename super::from::const_iterator const_iterator;
+ typedef typename super::from::reverse_iterator reverse_iterator;
+ typedef typename super::from::const_reverse_iterator const_reverse_iterator;
+
+ iterator begin(){return this->from.begin();}
+ const_iterator begin()const{return this->from.begin();}
+ iterator end(){return this->from.end();}
+ const_iterator end()const{return this->from.end();}
+ reverse_iterator rbegin(){return this->from.rbegin();}
+ const_reverse_iterator rbegin()const{return this->from.rbegin();}
+ reverse_iterator rend(){return this->from.rend();}
+ const_reverse_iterator rend()const{return this->from.rend();}
+ size_type size()const{return this->from.size();}
+ size_type max_size()const{return this->from.max_size();}
+ bool empty()const{return this->from.empty();}
+ allocator_type get_allocator()const{return this->from.get_allocator();}
+ from_binding_t operator[](const key_type& key){return this->from[key];}
+ const_from_binding_t operator[](const key_type& key)const{return this->from[key];}
+ using super::insert;
+ std::pair<iterator,bool> insert(const value_type& x){return this->from.insert(x);}
+ iterator insert(iterator it,const value_type& x){return this->from.insert(it,x);}
+ template<
+ typename it_type>
+ void insert(it_type first,it_type last){this->from.insert(first,last);}
+
+#ifdef _MSC_VER /* see note in from::erase */
+ iterator erase(iterator it){return this->from.erase(it);}
+#else
+ void erase(iterator it){this->from.erase(it);}
+#endif
+
+ void erase(iterator first,iterator last){this->from.erase(first,last);}
+ size_type erase(const key_type& key){return this->from.erase(key);}
+ void clear(){this->from.clear();}
+ void swap(bimap_different_types& x){this->from.swap(x.from);}
+ friend void swap(bimap_different_types& x,bimap_different_types& y)
+ {x.swap(y);}
+ key_compare key_comp()const{return this->from.key_comp();}
+ value_compare value_comp()const{return this->from.value_comp();}
+ iterator find(const key_type& key){return this->from.find(key);}
+ const_iterator find(const key_type& key)const{return this->from.find(key);}
+ size_type count(const key_type& key)const{return this->from.count(key);}
+ iterator lower_bound(const key_type& key){return this->from.lower_bound(key);}
+ const_iterator lower_bound(const key_type& key)const{return this->from.lower_bound(key);}
+ iterator upper_bound(const key_type& key){return this->from.upper_bound(key);}
+ const_iterator upper_bound(const key_type& key)const{return this->from.upper_bound(key);}
+ std::pair<
+ iterator,
+ iterator> equal_range(const key_type& key){return this->from.equal_range(key);}
+ std::pair<
+ const_iterator,
+ const_iterator> equal_range(const key_type& key)const{return this->from.equal_range(key);}
+
+ /* Promotion of unambiguous parts of the to memberspace */
+
+ to_binding_t operator[](const to_key_type& key){return this->to[key];}
+ const_to_binding_t operator[](const to_key_type& key)const{return this->to[key];}
+ std::pair<
+ to_iterator,
+ bool> insert(const to_value_type& x){return this->to.insert(x);}
+ to_iterator insert(to_iterator it,const to_value_type& x){return this->to.insert(it,x);}
+ void insert(const to_value_type *first,const to_value_type *last)
+ {this->to.insert(first,last);}
+
+#ifdef _MSC_VER /* see note in this->from.erase */
+ to_iterator erase(to_iterator it){return this->to.erase(it);}
+#else
+ void erase(to_iterator it){this->to.erase(it);}
+#endif
+
+ void erase(to_iterator first,to_iterator last){this->to.erase(first,last);}
+ size_type erase(const to_key_type& key){return this->to.erase(key);}
+ to_iterator find(const to_key_type& key){return this->to.find(key);}
+ const_to_iterator find(const to_key_type& key)const{return this->to.find(key);}
+ size_type count(const to_key_type& key)const{return this->to.count(key);}
+ to_iterator lower_bound(const to_key_type& key){return this->to.lower_bound(key);}
+ const_to_iterator lower_bound(const to_key_type& key)const{return this->to.lower_bound(key);}
+ to_iterator upper_bound(const to_key_type& key){return this->to.upper_bound(key);}
+ const_to_iterator upper_bound(const to_key_type& key)const{return this->to.upper_bound(key);}
+ std::pair<
+ to_iterator,
+ to_iterator> equal_range(const to_key_type& key){return this->to.equal_range(key);}
+ std::pair<
+ const_to_iterator,
+ const_to_iterator> equal_range(const to_key_type& key)const{return this->to.equal_range(key);}
+
+protected:
+ bimap_different_types(
+ const from_compare& from_comp,
+ const to_compare& to_comp,
+ const allocator_type_& al):
+ super(from_comp,to_comp,al)
+ {
+ }
+
+ /* default copy ctor serves well */
+};
+
+/* bimap finally inherits from bimap_equal_types or bimap_different_types
+ * depending on the equality of from_type and to_type, as a way to
+ * simulate PTS.
+ */
+template<
+ typename from_type_,typename to_type_,
+ typename from_compare=std::less<from_type_>,
+ typename to_compare=std::less<to_type_>,
+ typename allocator_type=std::allocator<direct_pair<const from_type_,const to_type_> > >
+class bimap:
+ public
+ bimap_detail::select<
+ bimap_detail::equal_types<from_type_,to_type_>::value,
+ bimap_equal_types<
+ from_type_,to_type_,
+ from_compare,to_compare,allocator_type>,
+ bimap_different_types<
+ from_type_,to_type_,
+ from_compare,to_compare,allocator_type>
+ >::result
+{
+protected:
+ typedef typename
+ bimap_detail::select<
+ bimap_detail::equal_types<from_type_,to_type_>::value,
+ bimap_equal_types<
+ from_type_,to_type_,
+ from_compare,to_compare,allocator_type>,
+ bimap_different_types<
+ from_type_,to_type_,
+ from_compare,to_compare,allocator_type>
+ >::result
+ super;
+
+public:
+ explicit bimap(
+ const from_compare& from_comp=from_compare(),
+ const to_compare& to_comp=to_compare(),
+ const allocator_type& al=allocator_type()):
+ super(from_comp,to_comp,al)
+ {
+ }
+
+ /* default copy ctor serves well */
+
+ bimap& operator=(const bimap& r)
+ {
+ bimap tmp(r);
+ this->swap(tmp);
+ return *this;
+ }
+
+ /* inverse copy ctor (from a bimap<to_type,from_type>) */
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+ /* no allocator::rebind, assume allocator_type==std::allocator */
+
+ typedef
+ bimap<
+ to_type_,from_type_,
+ to_compare,from_compare,
+ std::allocator<direct_pair<const to_type_,const from_type_> > >
+ inv_bimap;
+
+ explicit bimap(const inv_bimap& r):
+ super(r.to.key_comp(),r.from.key_comp(),allocator_type())
+#else
+ typedef
+ bimap<
+ to_type_,from_type_,
+ to_compare,from_compare,
+ typename allocator_type::template rebind<
+ direct_pair<const to_type_,const from_type_> >::other>
+ inv_bimap;
+
+ explicit bimap(const inv_bimap& r):
+ super(r.to.key_comp(),r.from.key_comp(),r.get_allocator())
+#endif
+
+/* body of bimap(const inv_bimap& r) follows */
+
+ {
+ try{
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+/* Amortized constant insertion in VC++ 6.0 happens if hint iterator is
+ * right *after* the insertion point, in disagreement with the standard.
+ */
+ typename super::from::iterator fhint=from.end();
+ typename super::to::iterator thint=to.end();
+ for(typename inv_bimap::to::const_iterator it=r.to.begin();it!=r.to.end();++it){
+ insert(fhint,thint,*it);
+ }
+#else
+ typename super::from::iterator fhint=this->from.end();
+ typename super::to::iterator thint=this->to.end();
+ for(typename inv_bimap::to::const_iterator it=r.to.begin();it!=r.to.end();++it){
+ std::pair<typename super::from::iterator,typename super::to::iterator>
+ p=this->insert(fhint,thint,*it);
+ fhint=p.first;
+ thint=p.second;
+ }
+#endif
+
+ }catch(...){
+ this->clear();
+ throw;
+ }
+ }
+
+ template<typename it_type>
+ bimap(
+ it_type first,it_type last,
+ const from_compare& from_comp=from_compare(),
+ const to_compare& to_comp=to_compare(),
+ const allocator_type& al=allocator_type()):
+ super(from_comp,to_comp,al)
+ {
+ try{
+
+#if defined(_MSC_VER)&&_MSC_VER==1200 /* MSVC++ 6.0 */
+/* Amortized constant insertion in VC++ 6.0 happens if hint iterator is
+ * right *after* the insertion point, in disagreement with the standard.
+ */
+
+ typename super::from::iterator fhint=from.end();
+ typename super::to::iterator thint=to.end();
+ while(first!=last){
+ insert(fhint,thint,first++);
+ }
+#else
+ typename super::from::iterator fhint=this->from.end();
+ typename super::to::iterator thint=this->to.end();
+ while(first!=last){
+ std::pair<typename super::from::iterator,typename super::to::iterator>
+ p=this->insert(fhint,thint,first++);
+ fhint=p.first;
+ thint=p.second;
+ }
+#endif
+
+ }catch(...){
+ this->clear();
+ throw;
+ }
+ }
+
+ /* Comparison: we simply forward to from */
+
+ bool operator==(const bimap& r)const{return this->from==r.from;}
+ bool operator!=(const bimap& r)const{return this->from!=r.from;}
+ bool operator< (const bimap& r)const{return this->from<r.from;}
+ bool operator> (const bimap& r)const{return this->from>r.from;}
+ bool operator<=(const bimap& r)const{return this->from<=r.from;}
+ bool operator>=(const bimap& r)const{return this->from>=r.from;}
+};
+
+} /* namespace codeproject */
+
+#elif VERSION_BIMAP_9B698EF9_C6E9_4BC4_A7D2_5B4D71155761!=0x00010003
+#error You have included two BIMAP.H with different version numbers
+#endif
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/channel/autojoinchanneldialog.cpp b/src/channel/autojoinchanneldialog.cpp
new file mode 100644
index 0000000..3de774a
--- /dev/null
+++ b/src/channel/autojoinchanneldialog.cpp
@@ -0,0 +1,85 @@
+#include "autojoinchanneldialog.h"
+
+
+#include <wx/intl.h>
+#include <wx/datetime.h>
+#include <wx/textctrl.h>
+#include <wx/sizer.h>
+#include <wx/splitter.h>
+#include <wx/button.h>
+#include <wx/tokenzr.h>
+#include <wx/event.h>
+#include <wx/statline.h>
+#include <wx/stattext.h>
+#include "../settings.h"
+
+BEGIN_EVENT_TABLE( AutojoinChannelDialog, wxDialog )
+
+ EVT_BUTTON( wxID_OK, AutojoinChannelDialog::OnOk )
+ EVT_BUTTON( wxID_CANCEL, AutojoinChannelDialog::OnCancel )
+
+
+END_EVENT_TABLE()
+
+AutojoinChannelDialog::AutojoinChannelDialog( wxWindow* parent )
+ : wxDialog( parent, -1, _( "Edit auto-joined channels" ), wxDefaultPosition, wxSize( 400, 500 ),
+ wxDEFAULT_DIALOG_STYLE | wxCLIP_CHILDREN )
+{
+ wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
+ wxBoxSizer* textSizer = new wxBoxSizer( wxVERTICAL );
+ m_channel_list = new wxTextCtrl( this, wxID_ANY, _T( "" ), wxDefaultPosition, wxDefaultSize,
+ wxTE_MULTILINE | wxTE_DONTWRAP );
+ wxSizer *buttonSizer= CreateButtonSizer( wxOK|wxCANCEL|wxALIGN_CENTRE );
+ wxStaticLine* seperator = new wxStaticLine( this );
+ wxStaticText* hint = new wxStaticText( this, -1, _( "Add one channel per line like this:\n"
+ "channelname password\n(passwords for existing channels are not displayed)" ) );
+ textSizer->Add( hint, 0, wxEXPAND|wxALL|wxALIGN_CENTRE, 10 );
+ textSizer->Add( seperator );
+ textSizer->Add( m_channel_list, 1, wxEXPAND|wxALL|wxALIGN_CENTRE, 10 );
+ mainSizer->Add( textSizer,1, wxEXPAND|wxALL|wxALIGN_CENTRE, 10 );
+ mainSizer->Add( seperator );
+ mainSizer->Add( buttonSizer, 0, wxALL|wxALIGN_CENTRE, 10 );
+ SetSizer( mainSizer );
+ wxString channels;
+ std::vector<ChannelJoinInfo> chanlist = sett().GetChannelsJoin();
+ for ( int i = 0; i < chanlist.size(); i++ )
+ {
+ ChannelJoinInfo info = chanlist[i];
+ channels << info.name + _T(" ") + info.password + _T("\n");
+ }
+ m_channel_list->SetValue( channels );
+}
+
+AutojoinChannelDialog::~AutojoinChannelDialog()
+{
+ //dtor
+}
+
+
+void AutojoinChannelDialog::OnOk( wxCommandEvent& /*unused*/ )
+{
+ wxString newChannels = m_channel_list->GetValue();
+
+ sett().RemoveAllChannelsJoin();
+
+ //add new channels
+ wxStringTokenizer tokenList( newChannels, _T( "\n" ) );
+ while ( tokenList.HasMoreTokens() )
+ {
+ wxString line = tokenList.GetNextToken();
+ wxString chan;
+ if ( line.Contains( _T(" ") ) ) chan = line.BeforeFirst( _T(' ') );
+ else chan = line;
+ wxString key = line.AfterFirst( _T(' ') );
+ sett().AddChannelJoin( chan, key );
+ }
+
+ this->Show( false );
+}
+
+void AutojoinChannelDialog::OnCancel( wxCommandEvent& /*unused*/ )
+{
+ this->Show( false );
+}
+
+
diff --git a/src/channel/autojoinchanneldialog.h b/src/channel/autojoinchanneldialog.h
new file mode 100644
index 0000000..0c304b1
--- /dev/null
+++ b/src/channel/autojoinchanneldialog.h
@@ -0,0 +1,48 @@
+#ifndef AUTOJOINCHANNELDIALOG_H
+#define AUTOJOINCHANNELDIALOG_H
+
+#include <wx/dialog.h>
+#include <wx/string.h>
+class wxCommandEvent;
+class wxTextCtrl;
+class wxWindow;
+
+/** \brief A dialog that lets the user manullay edit his list of channels to join on startup (possibly with passwords)
+ * Passwords for existing channels aren't displayed. The dialog expects a [chanName|password] pair per line.
+ * \todo See that parsing input doesn't crap out when user enters rubbish
+ */
+class AutojoinChannelDialog : public wxDialog
+{
+ public:
+ /** Default constructor */
+ AutojoinChannelDialog( wxWindow* parent );
+ /** Default destructor */
+ virtual ~AutojoinChannelDialog();
+ protected:
+
+ wxTextCtrl* m_channel_list;
+
+ void OnOk( wxCommandEvent& event );
+ void OnCancel( wxCommandEvent& event );
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // AUTOJOINCHANNELDIALOG_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/channel/channel.cpp b/src/channel/channel.cpp
new file mode 100644
index 0000000..91733af
--- /dev/null
+++ b/src/channel/channel.cpp
@@ -0,0 +1,226 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: Channel
+//
+
+#include "channel.h"
+#include "../ui.h"
+#include "../server.h"
+#include "../user.h"
+#include "../utils/tasutil.h"
+#include "../utils/debug.h"
+#include "../utils/platform.h"
+#include <wx/regex.h>
+#include <wx/log.h>
+#include "../chatpanel.h"
+
+Channel::~Channel() {
+ if(uidata.panel)uidata.panel->SetChannel(NULL);
+}
+
+void Channel::SetName( const wxString& name )
+{
+ m_name = name;
+}
+
+
+wxString Channel::GetName()
+{
+ return m_name;
+}
+
+
+User& Channel::GetMe()
+{
+ return m_serv.GetMe();
+}
+
+
+void Channel::Said( User& who, const wxString& message )
+{
+ m_ui.OnChannelSaid( *this , who, message );
+}
+
+
+void Channel::Say( const wxString& message )
+{
+ wxLogDebugFunc( _T("") );
+ m_serv.SayChannel( m_name, message );
+}
+
+
+void Channel::DidAction( User& who, const wxString& action )
+{
+ m_ui.OnChannelDidAction( *this, who, action );
+}
+
+
+void Channel::DoAction( const wxString& action )
+{
+ wxLogDebugFunc( _T("") );
+ m_serv.DoActionChannel( m_name, action );
+}
+
+
+void Channel::Left( User& who, const wxString& reason )
+{
+ RemoveUser( who.GetNick() );
+ m_ui.OnUserLeftChannel( *this, who, reason );
+}
+
+
+void Channel::Leave()
+{
+ m_serv.PartChannel( m_name );
+}
+
+
+
+void Channel::Joined( User& who )
+{
+ AddUser( who );
+ m_ui.OnUserJoinedChannel( *this, who );
+}
+
+
+void Channel::OnChannelJoin( User& who )
+{
+ AddUser( who );
+ m_ui.OnChannelJoin( *this, who );
+}
+
+
+void Channel::SetTopic( const wxString& topic, const wxString& who )
+{
+ m_topic = topic;
+ m_topic_nick = who;
+
+ m_ui.OnChannelTopic( *this, who, topic );
+}
+
+wxString Channel::GetTopicSetBy()
+{
+ return m_topic_nick;
+}
+
+
+wxString Channel::GetTopic()
+{
+ return m_topic;
+}
+
+
+void Channel::AddUser( User& user )
+{
+ UserList::AddUser( user );
+ CheckBanned(user.GetNick());
+}
+
+void Channel::CheckBanned(const wxString& name){
+ if(name==_T("ChanServ"))return;
+ if(m_banned_users.count(name)>0){
+ m_serv.SayPrivate(_T("ChanServ"),_T("!kick #")+GetName()+_T(" ")+name);
+ }
+ if(m_do_ban_regex&&m_ban_regex.IsValid()){
+ if(m_ban_regex.Matches(name)&&!(m_do_unban_regex&&m_unban_regex.IsValid()&&m_unban_regex.Matches(name))){
+ m_serv.SayPrivate(_T("ChanServ"),_T("!kick #")+GetName()+_T(" ")+name);
+ if(!m_ban_regex_msg.empty())m_serv.SayPrivate(name,m_ban_regex_msg);
+ }
+ }
+};
+bool Channel::IsBanned(const wxString& name){
+ if(name==_T("ChanServ"))return false;
+ if(m_banned_users.count(name)>0)return true;
+ if(m_do_ban_regex&&m_ban_regex.IsValid()){
+ if(m_ban_regex.Matches(name)&&!(m_do_unban_regex&&m_unban_regex.IsValid()&&m_unban_regex.Matches(name)))return true;
+ }
+ return false;
+};
+
+
+void Channel::RemoveUser( const wxString& nick )
+{
+ UserList::RemoveUser( nick );
+}
+
+
+bool Channel::ExecuteSayCommand( const wxString& in )
+{
+ if ( in.length() == 0 ) return true;
+
+ if ( in[0] != '/' ) return false;
+
+ wxString subcmd = in.BeforeFirst(' ').Lower();
+ wxString params = in.AfterFirst( ' ' );
+
+ wxString cmdline = in;
+ wxString param = GetWordParam( cmdline );
+ if ( param == _T("/me") ) {
+ DoAction( cmdline );
+ return true;
+ } else if ( in == _T("/part") || in == _T("/p") ) {
+ Leave();
+ uidata.panel = 0;
+ return true;
+ } else if ( param == _T("/sayver") ) {
+ DoAction( _T("is using SpringLobby v") + GetSpringLobbyVersion() );
+ return true;
+ } else if(subcmd==_T("/userban")){
+ m_banned_users.insert(params);
+ m_serv.SayPrivate(_T("ChanServ"),_T("!kick #")+GetName()+_T(" ")+params);
+ return true;
+ } else if(subcmd==_T("/userunban")){
+ m_banned_users.erase(params);
+ return true;
+ } else if(subcmd==_T("/banregex")){
+ m_ui.OnChannelMessage(m_name,_T("/banregex ")+params);
+ m_do_ban_regex=!params.empty();
+ if(m_do_ban_regex){
+ #ifdef wxHAS_REGEX_ADVANCED
+ m_ban_regex.Compile(params, wxRE_ADVANCED);
+ #else
+ m_ban_regex.Compile(params, wxRE_EXTENDED);
+ #endif
+ if(!m_ban_regex.IsValid())m_ui.OnChannelMessage(m_name,_T("Invalid regular expression"));
+ }
+ return true;
+ } else if(subcmd==_T("/unbanregex")){
+ m_ui.OnChannelMessage(m_name,_T("/unbanregex ")+params);
+ m_do_unban_regex=!params.empty();
+ if(m_do_unban_regex){
+ #ifdef wxHAS_REGEX_ADVANCED
+ m_unban_regex.Compile(params, wxRE_ADVANCED);
+ #else
+ m_unban_regex.Compile(params, wxRE_EXTENDED);
+ #endif
+ if(!m_unban_regex.IsValid())m_ui.OnChannelMessage(m_name,_T("Invalid regular expression"));
+ }
+ return true;
+ } else if (subcmd==_T("/checkban")) {
+ if(IsBanned(params)){
+ m_ui.OnChannelMessage(m_name,params+_T(" is banned"));
+ } else {
+ m_ui.OnChannelMessage(m_name,params+_T(" is not banned"));
+ }
+ return true;
+ } else if (subcmd==_T("/banregexmsg")) {
+ m_ui.OnChannelMessage(m_name,_T("/banregexmsg ")+params);
+ m_ban_regex_msg=params;
+ return true;
+ }
+
+ return false;
+}
+
+
+wxString Channel::GetPassword()
+{
+ return m_password;
+}
+
+
+void Channel::SetPassword( const wxString& pw )
+{
+ m_password = pw;
+}
+
diff --git a/src/channel/channel.h b/src/channel/channel.h
new file mode 100644
index 0000000..3555062
--- /dev/null
+++ b/src/channel/channel.h
@@ -0,0 +1,107 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CHANNEL_H
+#define SPRINGLOBBY_HEADERGUARD_CHANNEL_H
+
+#include "../userlist.h"
+#include <set>
+#include <wx/regex.h>
+
+class Channel;
+class Server;
+class Ui;
+class ChatPanel;
+
+struct UiChannelData {
+ UiChannelData(): panel(0) {}
+
+ ChatPanel* panel;
+};
+
+class Channel : public UserList
+{
+ public:
+
+ UiChannelData uidata;
+
+ //Channel(): m_serv(0),m_userdata(0) {}
+ Channel( Server& serv, Ui& ui ): m_serv(serv),m_ui(ui),m_do_ban_regex(false), m_do_unban_regex(false) {}
+ virtual ~Channel();
+
+ Server& GetServer() { return m_serv; }
+
+ void SetName( const wxString& name );
+ wxString GetName();
+ User& GetMe();
+
+ // filtering functions
+ void CheckBanned(const wxString& name);
+ bool IsBanned(const wxString& name);
+
+ // Channel Functions
+ void Say( const wxString& message );
+ void DoAction( const wxString& action );
+ void Leave();
+
+ void Said( User& who, const wxString& message );
+
+ void DidAction( User& who, const wxString& action );
+
+ void Left( User& who, const wxString& reason );
+ void Joined( User& who );
+
+ void OnChannelJoin( User& who );
+
+ void SetTopic( const wxString& topic, const wxString& who );
+ wxString GetTopic();
+ wxString GetTopicSetBy();
+
+ bool ExecuteSayCommand( const wxString& in );
+
+ wxString GetPassword();
+ void SetPassword( const wxString& pw );
+
+ protected:
+ Server& m_serv;
+
+ Ui& m_ui;
+
+ std::set<wxString> m_banned_users;
+
+ bool m_do_ban_regex;
+ wxRegEx m_ban_regex;
+
+ bool m_do_unban_regex;
+ wxRegEx m_unban_regex;
+
+ wxString m_ban_regex_msg;
+
+ wxString m_topic;
+ wxString m_topic_nick;
+ wxString m_name;
+
+ void* m_userdata;
+
+ wxString m_password;
+
+ void AddUser( User& user );
+ void RemoveUser( const wxString& nick );
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_CHANNEL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/channel/channelchooser.cpp b/src/channel/channelchooser.cpp
new file mode 100644
index 0000000..a63a1c2
--- /dev/null
+++ b/src/channel/channelchooser.cpp
@@ -0,0 +1,65 @@
+#include "channelchooser.h"
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/statline.h>
+#include <wx/stattext.h>
+#include <wx/textctrl.h>
+
+#include "channellistctrl.h"
+#include "../server.h"
+#include "../ui.h"
+#include "channel.h"
+
+BEGIN_EVENT_TABLE( ChannelChooserPanel, wxScrolledWindow )
+ EVT_TEXT( ID_SEARCH_TEXT , ChannelChooserPanel::OnSearch )
+END_EVENT_TABLE()
+
+ChannelChooserPanel::ChannelChooserPanel(wxWindow* parent, wxWindowID id, const wxString& /*unused*/,
+ const wxPoint& pos , const wxSize& size , long style , const wxString& name)
+ : wxScrolledWindow (parent, id, pos, size, style, name)
+{
+ m_main_sizer = new wxBoxSizer ( wxVERTICAL );
+
+ wxStaticText* join_label = new wxStaticText( this, -1, _("Double click to join") );
+ m_main_sizer->Add( join_label, 0, wxALL | wxEXPAND, 5 );
+
+ m_channellist = new ChannelListctrl ( this, -1, _T("channellistctrl") );
+ m_main_sizer->Add ( m_channellist, 1, wxALL|wxEXPAND, 5 );
+
+ wxBoxSizer* search_sizer = new wxBoxSizer( wxHORIZONTAL );
+ wxStaticText* search_label = new wxStaticText( this, -1, _("Find channel:") );
+ m_search_text = new wxTextCtrl ( this, ID_SEARCH_TEXT );
+ search_sizer->Add( search_label, 0, wxALIGN_CENTER_VERTICAL | wxALL , 0 );
+ search_sizer->Add( m_search_text, 1, wxLEFT | wxEXPAND, 5 );
+ m_main_sizer->Add( search_sizer, 0, wxALL | wxEXPAND, 5 );
+
+ m_info_label = new wxStaticText( this, -1, m_channellist->GetInfo() );
+ m_main_sizer->Add( m_info_label, 0, wxALL , 5 );
+
+ SetSizer( m_main_sizer );
+}
+
+ChannelChooserPanel::~ChannelChooserPanel()
+{
+ //dtor
+}
+
+void ChannelChooserPanel::AddChannel( const wxString& name, int usercount, const wxString& topic )
+{
+ m_channellist->AddChannel( name, usercount, topic );
+ m_info_label->SetLabel( m_channellist->GetInfo() );
+ Layout();
+}
+
+void ChannelChooserPanel::ClearChannels()
+{
+ m_channellist->ClearChannels();
+ m_info_label->SetLabel( m_channellist->GetInfo() );
+ m_search_text->SetValue( _T("") );
+}
+
+void ChannelChooserPanel::OnSearch( wxCommandEvent& /*unused*/ )
+{
+ m_channellist->FilterChannel( m_search_text->GetValue() );
+ m_info_label->SetLabel( m_channellist->GetInfo() );
+}
diff --git a/src/channel/channelchooser.h b/src/channel/channelchooser.h
new file mode 100644
index 0000000..7175d14
--- /dev/null
+++ b/src/channel/channelchooser.h
@@ -0,0 +1,58 @@
+#ifndef CHANNELCHOOSERPANEL_H
+#define CHANNELCHOOSERPANEL_H
+
+#include <wx/scrolwin.h>
+
+class ChannelListctrl;
+class wxBoxSizer;
+class wxButton;
+class wxTextCtrl;
+class wxStaticText;
+
+class ChannelChooserPanel : public wxScrolledWindow
+{
+ public:
+ ChannelChooserPanel(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = wxHSCROLL | wxVSCROLL ,
+ const wxString& name = _T("dialogBox") );
+ virtual ~ChannelChooserPanel();
+
+ void AddChannel( const wxString& name, int usercount, const wxString& topic = wxEmptyString );
+ void ClearChannels();
+ void OnSearch( wxCommandEvent& event );
+
+ protected:
+ wxButton* m_join_channels;
+ wxButton* m_mark_autojoin;
+ wxBoxSizer* m_main_sizer;
+ ChannelListctrl* m_channellist;
+ wxTextCtrl* m_search_text;
+ wxStaticText* m_info_label;
+
+ enum {
+ ID_SEARCH_TEXT
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // CHANNELCHOOSER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/channel/channelchooserdialog.cpp b/src/channel/channelchooserdialog.cpp
new file mode 100644
index 0000000..ee51618
--- /dev/null
+++ b/src/channel/channelchooserdialog.cpp
@@ -0,0 +1,43 @@
+#include "channelchooserdialog.h"
+
+#include <wx/sizer.h>
+#include "channelchooser.h"
+#include "../settings.h"
+
+ChannelChooserDialog::ChannelChooserDialog(wxWindow* parent, wxWindowID id,
+ const wxString& title, long style )
+ : wxDialog ( parent, id, title, wxDefaultPosition, wxDefaultSize, style )
+{
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_chooser_panel = new ChannelChooserPanel( this, -1, _("Choose channels to join") );
+ m_main_sizer->Add( m_chooser_panel, 1, wxALL | wxEXPAND, 5 );
+
+ SetSizer( m_main_sizer );
+
+ wxString name = _T("CHANNELCHOOSER");
+ wxPoint pos = sett().GetWindowPos( name, wxDefaultPosition );
+ wxSize size = sett().GetWindowSize( name, wxSize( 470, 400 ) );
+ SetSize( pos.x , pos.y, size.GetWidth(), size.GetHeight() );
+ Layout();
+}
+
+ChannelChooserDialog::~ChannelChooserDialog()
+{
+ wxString name = _T("CHANNELCHOOSER");
+ sett().SetWindowSize( name, GetSize() );
+ sett().SetWindowPos( name, GetPosition() );
+ sett().SaveSettings();
+}
+
+void ChannelChooserDialog::AddChannel( const wxString& name, int usercount, const wxString& topic )
+{
+ m_chooser_panel->AddChannel( name, usercount, topic );
+ m_main_sizer->FitInside( this );
+ Layout();
+}
+
+void ChannelChooserDialog::ClearChannels()
+{
+ m_chooser_panel->ClearChannels();
+}
diff --git a/src/channel/channelchooserdialog.h b/src/channel/channelchooserdialog.h
new file mode 100644
index 0000000..2998339
--- /dev/null
+++ b/src/channel/channelchooserdialog.h
@@ -0,0 +1,43 @@
+#ifndef SPRINGLOBBY_CHANNELCHOOSERDIALOG_H_INCLUDED
+#define SPRINGLOBBY_CHANNELCHOOSERDIALOG_H_INCLUDED
+
+#include <wx/dialog.h>
+
+class ChannelChooserPanel;
+class wxBoxSizer;
+
+class ChannelChooserDialog : public wxDialog
+{
+ public:
+ ChannelChooserDialog(wxWindow* parent, wxWindowID id, const wxString& title,
+ long style = wxCAPTION | wxRESIZE_BORDER | wxCLOSE_BOX | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxDEFAULT_DIALOG_STYLE );
+ virtual ~ChannelChooserDialog();
+
+ void AddChannel( const wxString& name, int usercount, const wxString& topic = wxEmptyString );
+ void ClearChannels();
+
+ protected:
+ ChannelChooserPanel* m_chooser_panel;
+ wxBoxSizer* m_main_sizer;
+
+};
+
+#endif // SPRINGLOBBY_CHANNELCHOOSERDIALOG_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/channel/channellist.cpp b/src/channel/channellist.cpp
new file mode 100644
index 0000000..82c5809
--- /dev/null
+++ b/src/channel/channellist.cpp
@@ -0,0 +1,55 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+#include <iterator>
+#include <stdexcept>
+#include <wx/log.h>
+
+#include "channellist.h"
+#include "channel.h"
+#include "../utils/debug.h"
+#include "../utils/conversion.h"
+
+const UserList::user_map_t::size_type SEEKPOS_INVALID = UserList::user_map_t::size_type(-1);
+
+ChannelList::ChannelList() : m_seek(m_chans.end()), m_seekpos(SEEKPOS_INVALID)
+{ }
+
+void ChannelList::AddChannel( Channel& channel )
+{
+ m_chans[channel.GetName()] = &channel;
+ m_seekpos = SEEKPOS_INVALID;
+}
+
+void ChannelList::RemoveChannel( const wxString& name )
+{
+ m_chans.erase( name );
+ m_seekpos = SEEKPOS_INVALID;
+}
+
+Channel& ChannelList::GetChannel( const wxString& name )
+{
+ channel_iter_t u = m_chans.find(name);
+ ASSERT_LOGIC( u != m_chans.end(), _T("ChannelList::GetChannel(\"") + name + _T("\"): no such channel"));
+ return *u->second;
+}
+
+Channel& ChannelList::GetChannel( channel_map_t::size_type index )
+{
+ if (m_seekpos == SEEKPOS_INVALID || m_seekpos > index) {
+ m_seek = m_chans.begin();
+ m_seekpos = 0;
+ }
+ std::advance( m_seek, index - m_seekpos );
+ m_seekpos = index;
+ return *m_seek->second;
+}
+
+bool ChannelList::ChannelExists( const wxString& name )
+{
+ return m_chans.find( name ) != m_chans.end();
+}
+
+channel_map_t::size_type ChannelList::GetNumChannels()
+{
+ return m_chans.size();
+}
+
diff --git a/src/channel/channellist.h b/src/channel/channellist.h
new file mode 100644
index 0000000..94cee90
--- /dev/null
+++ b/src/channel/channellist.h
@@ -0,0 +1,52 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CHANNELLIST_H
+#define SPRINGLOBBY_HEADERGUARD_CHANNELLIST_H
+
+#include <map>
+#include <wx/string.h>
+
+class Channel;
+
+//! @brief mapping from channel name to channel object
+typedef std::map<wxString, Channel*> channel_map_t;
+//! @brief iterator for channel map
+typedef channel_map_t::iterator channel_iter_t;
+
+//! @brief List of Channel objects
+class ChannelList
+{
+ public:
+ ChannelList();
+ void AddChannel( Channel& channel );
+ void RemoveChannel( const wxString& name );
+ Channel& GetChannel( const wxString& name );
+ Channel& GetChannel( channel_map_t::size_type index );
+ bool ChannelExists( const wxString& name );
+ channel_map_t::size_type GetNumChannels();
+
+ private:
+ channel_map_t m_chans;
+ // The following are used as internal cache to speed up random access:
+ mutable channel_iter_t m_seek;
+ mutable channel_map_t::size_type m_seekpos;
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_CHANNELLIST_H
+
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/channel/channellistctrl.cpp b/src/channel/channellistctrl.cpp
new file mode 100644
index 0000000..79b7e90
--- /dev/null
+++ b/src/channel/channellistctrl.cpp
@@ -0,0 +1,184 @@
+#include "channellistctrl.h"
+#include "../iconimagelist.h"
+#include "../utils/conversion.h"
+#include "../ui.h"
+#include <algorithm>
+#include "../Helper/sortutil.h"
+
+template<> SortOrder CustomVirtListCtrl<ChannelInfo,ChannelListctrl>::m_sortorder = SortOrder();
+
+BEGIN_EVENT_TABLE( ChannelListctrl, ChannelListctrl::BaseType )
+ EVT_LIST_ITEM_ACTIVATED( CHANNELLIST, ChannelListctrl::OnActivateItem )
+END_EVENT_TABLE()
+
+
+ChannelListctrl::ChannelListctrl(wxWindow* parent, wxWindowID /*unused*/, const wxString& /*unused*/,
+ long /*unused*/, const wxPoint& /*unused*/, const wxSize& /*unused*/)
+ :CustomVirtListCtrl<ChannelInfo,ChannelListctrl>(parent, CHANNELLIST, wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_ALIGN_LEFT, _T("ChannelListCtrl"), 3, 3, &CompareOneCrit)
+{
+#if defined(__WXMSW__)
+ const int widths [3] = { wxLIST_AUTOSIZE, wxLIST_AUTOSIZE, wxLIST_AUTOSIZE };
+#elif defined(__WXMAC__)
+ const int widths [3] = { wxLIST_AUTOSIZE, wxLIST_AUTOSIZE, wxLIST_AUTOSIZE };
+#else
+ const int widths [3] = { wxLIST_AUTOSIZE, wxLIST_AUTOSIZE, wxLIST_AUTOSIZE };
+#endif
+
+ AddColumn( 0, widths[0], _("Channel"), _T("Channelname") );
+ AddColumn( 1, widths[1], _("# users"), _T("Users") );
+ AddColumn( 2, widths[2], _T("Topic"), _T("Topic") );
+
+ if ( m_sortorder.size() == 0 ) {
+ m_sortorder[2].col = 2;
+ m_sortorder[2].direction = 1;
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = 1;
+ m_sortorder[1].col = 1;
+ m_sortorder[1].direction = 1;
+ }
+}
+
+ChannelListctrl::~ChannelListctrl()
+{
+ //dtor
+}
+
+void ChannelListctrl::HighlightItem( long item ){}
+
+/** @brief AddChannel
+ *
+ * @todo: document this function
+ */
+void ChannelListctrl::AddChannel(const wxString& channel, unsigned int num_users, const wxString& topic )
+{
+ ChannelInfo data ( channel, num_users, topic );
+ m_data.push_back( data );
+ m_visible_idxs[m_data.size() -1] = ( m_data.size() -1 );
+ SetItemCount( m_visible_idxs.size() );
+
+ RefreshItem( m_visible_idxs.size() - 1);
+ SetColumnWidth( 0, wxLIST_AUTOSIZE );
+ SetColumnWidth( 1, wxLIST_AUTOSIZE );
+ SetColumnWidth( 2, wxLIST_AUTOSIZE );
+}
+
+int ChannelListctrl::CompareOneCrit( DataType u1, DataType u2, int col, int dir )
+{
+ switch ( col ) {
+ case 0: return dir * u1.name.CmpNoCase( u2.name );
+ case 1: return dir * compareSimple( u1.usercount, u2.usercount );
+ case 2: return dir * u1.topic.CmpNoCase( u2.topic );
+ default: return 0;
+ }
+}
+
+int ChannelListctrl::GetIndexFromData( const DataType& data ) const
+{
+ DataCIter it = m_data.begin();
+ for ( int i = 0; it != m_data.end(); ++it , ++i) {
+ if ( it->name == data.name )
+ return i;
+ }
+ return -1;
+}
+
+void ChannelListctrl::Sort()
+{
+ SaveSelection();
+ SLInsertionSort( m_data, m_comparator );
+ FilterChannel( m_last_filter_value );
+ RestoreSelection();
+}
+
+/** @brief OnActivateItem
+ *
+ * @todo: document this function
+ */
+void ChannelListctrl::OnActivateItem(wxListEvent& event)
+{
+ int index = event.GetIndex();
+ if ( index == -1 ) return;
+ wxString chan_name = m_data[ m_visible_idxs[index] ].name;
+ ui().JoinChannel( chan_name, _T("") );
+}
+
+void ChannelListctrl::ClearChannels()
+{
+ m_visible_idxs.clear();
+ Clear();
+}
+
+wxString ChannelListctrl::GetInfo()
+{
+ int displayed = GetItemCount();
+ int total = m_data.size();
+ return wxString::Format( _("Displaying %d out of %d channels"), displayed, total );
+}
+
+void ChannelListctrl::FilterChannel( const wxString& partial )
+{
+ m_visible_idxs.clear();
+ unsigned int idx = 0;
+ for ( unsigned int i = 0; i < m_data.size() ; ++i ) {
+ const ChannelInfo& data = m_data[i];
+ if ( data.name.Contains( partial ) ) {
+ m_visible_idxs[idx] = i;
+ idx++;
+ }
+ }
+ SelectNone();
+ m_last_filter_value = partial;
+ SetItemCount( m_visible_idxs.size() );
+ RefreshVisibleItems( );
+}
+
+
+int ChannelListctrl::GetItemColumnImage(long /*unused*/, long column) const
+{
+ return -1;
+}
+
+int ChannelListctrl::GetItemImage(long /*unused*/) const
+{
+ return -1;
+}
+
+wxString ChannelListctrl::GetItemText(long item, long column) const
+{
+ int idx = m_visible_idxs.find(item)->second;
+ const DataType& chan = m_data[ idx ];
+
+ switch ( column ) {
+ case 0: return chan.name;
+ case 1: return TowxString( chan.usercount );
+ case 2: return chan.topic;
+ default: return wxEmptyString;
+ }
+}
+
+void ChannelListctrl::SetTipWindowText(const long item_hit, const wxPoint& position)
+{
+ int column = getColumnFromPosition(position);
+ if (column > (int)m_colinfovec.size() || column < 0 || item_hit < 0 || item_hit > (long)m_data.size() )
+ {
+ m_tiptext = _T("");
+ }
+ else
+ {
+ const DataType& channel = m_data[item_hit];
+ {
+ switch (column)
+ {
+ case 2: // status
+ m_tiptext = channel.topic;
+ break;
+
+ default:
+ m_tiptext = _T("");
+ break;
+ }
+ }
+ }
+}
+
diff --git a/src/channel/channellistctrl.h b/src/channel/channellistctrl.h
new file mode 100644
index 0000000..9093a2e
--- /dev/null
+++ b/src/channel/channellistctrl.h
@@ -0,0 +1,78 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CHANNELLISTCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_CHANNELLISTCTRL_H
+
+#include "../customvirtlistctrl.h"
+
+struct ChannelInfo
+{
+ ChannelInfo()
+ : name(_T("")), usercount(0),topic(_T("")) {}
+ ChannelInfo( const wxString& name_, int usercount_, const wxString& topic_ = wxEmptyString )
+ : name(name_), usercount(usercount_),topic(topic_) {}
+
+ wxString name;
+ int usercount;
+ wxString topic;
+};
+
+class ChannelListctrl : public CustomVirtListCtrl< ChannelInfo, ChannelListctrl >
+{
+ public:
+ ChannelListctrl(wxWindow* parent, wxWindowID id, const wxString& name = _T("ChannelListCtrl"),
+ long style = wxSUNKEN_BORDER | wxLC_REPORT | wxLC_ALIGN_LEFT, const wxPoint& pt = wxDefaultPosition,
+ const wxSize& sz = wxDefaultSize);
+ virtual ~ChannelListctrl();
+
+ void AddChannel( const wxString& channel, unsigned int num_users, const wxString& topic);
+ void ClearChannels();
+ wxString GetInfo();
+ void FilterChannel( const wxString& partial );
+
+ //these are overloaded to use list in virtual style
+ wxString GetItemText(long item, long column) const;
+ int GetItemImage(long item) const;
+ int GetItemColumnImage(long item, long column) const;
+ wxListItemAttr* GetItemAttr(long /*unused*/) const {return 0;}
+
+ protected:
+ void Sort();
+ void SetTipWindowText( const long item_hit, const wxPoint& position);
+
+ void OnActivateItem( wxListEvent& event );
+
+ void HighlightItem( long item );
+
+ enum {
+ CHANNELLIST = wxID_HIGHEST
+
+ };
+
+ int GetIndexFromData( const DataType& data ) const;
+
+ //! passed as callback to generic ItemComparator, returns -1,0,1 as per defined ordering
+ static int CompareOneCrit( DataType u1, DataType u2, int col, int dir ) ;
+
+ wxString m_last_filter_value;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_CHANNELLISTCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/chatlog.cpp b/src/chatlog.cpp
new file mode 100644
index 0000000..afa7a0d
--- /dev/null
+++ b/src/chatlog.cpp
@@ -0,0 +1,170 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: ChatLog
+//
+#include <wx/string.h>
+#include <wx/file.h>
+#include <wx/filefn.h>
+#include <wx/dir.h>
+#include <wx/datetime.h>
+#include <wx/intl.h>
+#include <wx/filename.h>
+#include <wx/log.h>
+#include <stdexcept>
+
+#include "chatlog.h"
+#include "settings.h"
+#include "utils/conversion.h"
+#include "ui.h"
+
+#include "settings++/custom_dialogs.h"
+
+bool ChatLog::m_parent_dir_exists = true;
+
+ChatLog::ChatLog( const wxString& server, const wxString& room ):
+// m_logfile( 0 ),
+ m_server( server ),
+ m_room( room )
+
+{
+#ifdef __WXMSW__
+ m_server.Replace( wxT( ":" ), wxT( "_" ) ) ;
+#endif
+ // testing.
+ // m_active = OpenLogFile(m_server,m_room) ;
+ wxLogMessage( _T( "ChatLog::ChatLog( %s, %s )" ), m_server.c_str(), m_room.c_str() ) ;
+ m_active = OpenLogFile( m_server, m_room );
+}
+
+
+ChatLog::~ChatLog()
+{
+ wxLogMessage( _T( "%s -- ChatLog::~ChatLog()" ), m_room.c_str() );
+ if ( m_active && m_logfile.IsOpened() ) {
+ wxDateTime now = wxDateTime::Now();
+ WriteLine( _( "### Session Closed at [" ) + now.Format( _T( "%Y-%m-%d %H:%M" ) ) + _( "]" ) );
+#ifndef __WXMSW__
+ WriteLine( _T( " \n \n \n" ) );
+#else
+ WriteLine( _T( " \r\n \r\n \r\n" ) );
+#endif
+ // crashes right there on close.
+ m_logfile.Flush();
+ m_logfile.Close();
+ }
+ // it is safe to delete a null pointer.
+// delete m_logfile;
+// m_logfile = 0;
+}
+
+
+bool ChatLog::AddMessage( const wxString& text )
+{
+ if ( !LogEnabled() ) {
+ return true;
+ }
+ else if ( !m_logfile.IsOpened() ) {
+ m_active = OpenLogFile( m_server, m_room );
+ }
+ if ( m_active )
+ {
+ wxString line = LogTime() + _T( " " ) + text;
+#ifdef __WXMSW__
+ line << _T( "\r" );
+#endif
+ line << _T( "\n" );
+ return WriteLine( line );
+ }
+ else return false;
+}
+
+
+bool ChatLog::LogEnabled()
+{
+ return sett().GetChatLogEnable();
+}
+
+
+wxString ChatLog::_GetPath()
+{
+ return sett().GetChatLogLoc();
+}
+
+
+bool ChatLog::CreateFolder( const wxString& server )
+{
+ if ( !( wxDirExists( _GetPath() ) || wxMkdir( _GetPath(), 0777 ) ) ) {
+ wxLogWarning( _T( "can't create logging folder: %s" ), _GetPath().c_str() );
+ customMessageBox( SL_MAIN_ICON, _( "Couldn't create folder. \nBe sure that there isn't a write protection.\n" ) + _GetPath() + _( "Log function is disabled until restart SpringLobby." ), _( "Log Warning" ) );
+ m_parent_dir_exists = false;
+ return false;
+ }
+ if ( !( wxDirExists( _GetPath() + wxFileName::GetPathSeparator() + server ) || wxMkdir( _GetPath() + wxFileName::GetPathSeparator() + server, 0777 ) ) ) {
+ wxLogWarning( _T( "can't create logging folder: %s" ), wxString( _GetPath() + wxFileName::GetPathSeparator() + server ).c_str() );
+ customMessageBox( SL_MAIN_ICON, _( "Couldn't create folder. \nBe sure that there isn't a write protection.\n" ) + _GetPath() + wxFileName::GetPathSeparator() + server + _( "Log function is disabled until restart SpringLobby." ), _T( "Log Warning" ) );
+ m_parent_dir_exists = false;
+ return false;
+ }
+ return true;
+}
+
+
+bool ChatLog::WriteLine( const wxString& text )
+{
+// try
+// {
+// ASSERT_LOGIC( m_logfile, _T("m_logfile = 0") );
+// } catch(...) {return false;}
+ if ( !m_logfile.Write( text, wxConvUTF8 ) ) {
+ m_active = false;
+ wxLogWarning( _T( "can't write message to log (%s)" ), wxString( m_server + _T( "::" ) + m_room ).c_str() );
+ customMessageBox( SL_MAIN_ICON, _( "Couldn't write message to log.\nLogging will be disabled for room " ) + m_server + _T( "::" ) + m_room + _( ".\n\nRejoin room to reactivate logging." ), _( "Log Warning" ) );
+ return false;
+ }
+ return true;
+}
+
+bool ChatLog::OpenLogFile( const wxString& server, const wxString& room )
+{
+ m_current_logfile_path = _GetPath() + wxFileName::GetPathSeparator() + server + wxFileName::GetPathSeparator() + room + _T( ".txt" );
+ wxLogMessage( _T( "OpenLogFile( %s, %s )" ), server.c_str(), room.c_str() ) ;
+
+// delete m_logfile;
+// m_logfile = 0;
+
+ if ( m_parent_dir_exists && LogEnabled() && CreateFolder( server ) ) {
+ if ( wxFileExists( m_current_logfile_path ) ) {
+ m_logfile.Open( m_current_logfile_path, wxFile::write_append );
+ } else {
+ m_logfile.Open( m_current_logfile_path, wxFile::write );
+ }
+ if ( !m_logfile.IsOpened() ) {
+ wxLogWarning( _T( "Can't open log file %s" ), m_current_logfile_path.c_str() ) ;
+ customMessageBox( SL_MAIN_ICON, _( "Can't open log file. \nBe sure that there isn't a write protection.\n" ) + m_current_logfile_path, _( "Log Warning" ) ) ;
+
+ }
+ else {
+ wxDateTime now = wxDateTime::Now();
+ wxString text = _T( "### Session Start at [" ) + now.Format( _T( "%Y-%m-%d %H:%M" ) ) + _T( "]" );
+#ifdef __WXMSW__
+ text << _T( "\r" );
+#endif
+ text << _T( "\n" );
+ return WriteLine( text );
+
+ }
+ }
+ return false;
+}
+
+
+wxString ChatLog::LogTime()
+{
+ wxDateTime now = wxDateTime::Now();
+ return _T( "[" ) + now.Format( _T( "%H:%M" ) ) + _T( "]" );
+}
+
+void ChatLog::OpenInEditor()
+{
+ ui().OpenFileInEditor( m_current_logfile_path );
+}
diff --git a/src/chatlog.h b/src/chatlog.h
new file mode 100644
index 0000000..dbef361
--- /dev/null
+++ b/src/chatlog.h
@@ -0,0 +1,51 @@
+#ifndef CHATLOG_H_INCLUDED
+#define CHATLOG_H_INCLUDED
+
+#include <wx/string.h>
+#include <wx/file.h>
+
+
+class ChatLog
+{
+ public:
+ ChatLog(const wxString& server,const wxString& room);
+ ~ChatLog();
+ bool AddMessage(const wxString& text);
+ bool LogEnabled();
+ wxString LogTime();
+ void OpenInEditor();
+// void SetTarget( const wxString& server,const wxString& room );
+ protected:
+ bool CreateFolder(const wxString& server);
+ bool WriteLine(const wxString& text);
+ bool OpenLogFile(const wxString& server,const wxString& room);
+ wxString _GetPath();
+ wxFile m_logfile;
+ wxString m_server;
+ wxString m_room;
+ wxString m_current_logfile_path;
+ bool m_active;
+ static bool m_parent_dir_exists;
+
+
+};
+
+#endif // CHATLOG_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/chatoptionstab.cpp b/src/chatoptionstab.cpp
new file mode 100644
index 0000000..b2f9bc2
--- /dev/null
+++ b/src/chatoptionstab.cpp
@@ -0,0 +1,560 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: ChatOptionsTab
+//
+
+#include <wx/filedlg.h>
+#include <wx/dirdlg.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/intl.h>
+#include <wx/textctrl.h>
+#include <wx/radiobut.h>
+#include <wx/stattext.h>
+#include <wx/button.h>
+#include <wx/msgdlg.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/stdpaths.h>
+#include <wx/dir.h>
+#include <wx/file.h>
+#include <wx/stdpaths.h>
+#include <wx/settings.h>
+#include <wx/colordlg.h>
+#include <wx/fontdlg.h>
+#include <wx/checkbox.h>
+#include <wx/tokenzr.h>
+
+#ifdef __WXMSW__
+#include <wx/msw/registry.h>
+#endif
+
+#include "nonportable.h"
+#include "chatoptionstab.h"
+#include "ui.h"
+#include "iunitsync.h"
+#include "utils/controls.h"
+#include "uiutils.h"
+#include "settings.h"
+#include "spring.h"
+#include "mainwindow.h"
+#include "Helper/colorbutton.h"
+#include "aui/auimanager.h"
+
+BEGIN_EVENT_TABLE( ChatOptionsTab, wxPanel )
+
+ EVT_BUTTON( ID_SELFONT, ChatOptionsTab::OnSelectFont )
+ EVT_CHECKBOX( ID_SYSCOLS, ChatOptionsTab::OnUseSystemColors )
+ EVT_BUTTON( ID_NORMAL, ChatOptionsTab::OnNormalSelect )
+ EVT_BUTTON( ID_BG, ChatOptionsTab::OnBGSelect )
+ EVT_BUTTON( ID_ACTION, ChatOptionsTab::OnActionSelect )
+ EVT_BUTTON( ID_HIGHLIGHT, ChatOptionsTab::OnHighlightSelect )
+ EVT_BUTTON( ID_JOINLEAVE, ChatOptionsTab::OnJoinLeaveSelect )
+ EVT_BUTTON( ID_NOTIFICATION, ChatOptionsTab::OnNotificationSelect )
+ EVT_BUTTON( ID_MYMESS, ChatOptionsTab::OnMyMessSelect )
+ EVT_BUTTON( ID_SERVER, ChatOptionsTab::OnServerSelect )
+ EVT_BUTTON( ID_CLIENT, ChatOptionsTab::OnClientSelect )
+ EVT_BUTTON( ID_ERROR, ChatOptionsTab::OnErrorSelect )
+ EVT_BUTTON( ID_TIMESTAMP, ChatOptionsTab::OnTimestampSelect )
+
+END_EVENT_TABLE()
+
+
+ChatOptionsTab::ChatOptionsTab( wxWindow* parent, Ui& ui )
+ : wxScrolledWindow( parent, -1 ),
+ m_ui( ui )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "chatoptionstab" ) );
+
+ wxBoxSizer* bMainSizerV;
+ bMainSizerV = new wxBoxSizer( wxVERTICAL );
+
+ wxStaticBoxSizer* sbColorsSizer;
+ sbColorsSizer = new wxStaticBoxSizer( new wxStaticBox( this, -1, _( "Colors and font" ) ), wxHORIZONTAL );
+
+ wxBoxSizer* bColorsVSizer;
+ bColorsVSizer = new wxBoxSizer( wxVERTICAL );
+
+ m_use_sys_colors = new wxCheckBox( this, ID_SYSCOLS, _( "Use system colors" ), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_use_sys_colors->Enable( false );
+
+ bColorsVSizer->Add( m_use_sys_colors, 0, wxALL, 5 );
+
+ m_custom_colors = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxTAB_TRAVERSAL );
+ m_custom_colors->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_MENU ) );
+
+ wxBoxSizer* bCustomColorsSizer;
+ bCustomColorsSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* bColorSizer;
+ bColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* bColorsSizer1;
+ bColorsSizer1 = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* bNormlColorSizer;
+ bNormlColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_normal_color = new ColorButton( m_custom_colors, ID_NORMAL, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_normal_color->SetColor( wxColour( 0, 0, 0 ) );
+
+ bNormlColorSizer->Add( m_normal_color, 0, wxALL, 5 );
+
+ m_normal_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Normal" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_normal_label->Wrap( -1 );
+ bNormlColorSizer->Add( m_normal_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorsSizer1->Add( bNormlColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bBGColorSizer;
+ bBGColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_bg_color = new ColorButton( m_custom_colors, ID_BG, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_bg_color->SetColor( wxColour( 255, 255, 255 ) );
+
+ bBGColorSizer->Add( m_bg_color, 0, wxALL, 5 );
+
+ m_bg_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Background" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_bg_label->Wrap( -1 );
+ bBGColorSizer->Add( m_bg_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorsSizer1->Add( bBGColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bActionColorSizer;
+ bActionColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_action_color = new ColorButton( m_custom_colors, ID_ACTION, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_action_color->SetColor( wxColour( 255, 0, 249 ) );
+
+ bActionColorSizer->Add( m_action_color, 0, wxALL, 5 );
+
+ m_action_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Action" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_action_label->Wrap( -1 );
+ bActionColorSizer->Add( m_action_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorsSizer1->Add( bActionColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bHighlightColorSizer;
+ bHighlightColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_highlight_color = new ColorButton( m_custom_colors, ID_HIGHLIGHT, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_highlight_color->SetColor( wxColour( 255, 0, 44 ) );
+
+ bHighlightColorSizer->Add( m_highlight_color, 0, wxALL, 5 );
+
+ m_highlight_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Highlight" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_highlight_label->Wrap( -1 );
+ bHighlightColorSizer->Add( m_highlight_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorsSizer1->Add( bHighlightColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bJoinLeaveColorSizer;
+ bJoinLeaveColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_joinleave_color = new ColorButton( m_custom_colors, ID_JOINLEAVE, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_joinleave_color->SetColor( wxColour( 24, 255, 0 ) );
+
+ bJoinLeaveColorSizer->Add( m_joinleave_color, 0, wxALL, 5 );
+
+ m_joinleave_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Join/Leave" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_joinleave_label->Wrap( -1 );
+ bJoinLeaveColorSizer->Add( m_joinleave_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorsSizer1->Add( bJoinLeaveColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bMyColorSizer;
+ bMyColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_my_color = new ColorButton( m_custom_colors, ID_MYMESS, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_my_color->SetColor( wxColour( 160, 160, 160 ) );
+
+ bMyColorSizer->Add( m_my_color, 0, wxALL, 5 );
+
+ m_my_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "My messages" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_my_label->Wrap( -1 );
+ bMyColorSizer->Add( m_my_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorsSizer1->Add( bMyColorSizer, 1, wxEXPAND, 5 );
+
+ bColorSizer->Add( bColorsSizer1, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* bColorSizer2;
+ bColorSizer2 = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* bServerColorSizer;
+ bServerColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_server_color = new ColorButton( m_custom_colors, ID_SERVER, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_server_color->SetColor( wxColour( 255, 189, 0 ) );
+
+ bServerColorSizer->Add( m_server_color, 0, wxALL, 5 );
+
+ m_server_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Server" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_server_label->Wrap( -1 );
+ bServerColorSizer->Add( m_server_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorSizer2->Add( bServerColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bClientolorSizer;
+ bClientolorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_client_color = new ColorButton( m_custom_colors, ID_CLIENT, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_client_color->SetColor( wxColour( 255, 189, 0 ) );
+
+ bClientolorSizer->Add( m_client_color, 0, wxALL, 5 );
+
+ m_client_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Client" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_client_label->Wrap( -1 );
+ bClientolorSizer->Add( m_client_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorSizer2->Add( bClientolorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bErrorColorSizer;
+ bErrorColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_error_color = new ColorButton( m_custom_colors, ID_ERROR, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_error_color->SetColor( wxColour( 255, 0, 0 ) );
+
+ bErrorColorSizer->Add( m_error_color, 0, wxALL, 5 );
+
+ m_error_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Error" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_error_label->Wrap( -1 );
+ bErrorColorSizer->Add( m_error_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorSizer2->Add( bErrorColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bTSColorSizer;
+ bTSColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_ts_color = new ColorButton( m_custom_colors, ID_TIMESTAMP, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_ts_color->SetColor( wxColour( 160, 160, 160 ) );
+
+ bTSColorSizer->Add( m_ts_color, 0, wxALL, 5 );
+
+ m_ts_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Timestamp" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_ts_label->Wrap( -1 );
+ bTSColorSizer->Add( m_ts_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorSizer2->Add( bTSColorSizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bNoteColorSizer;
+ bNoteColorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_note_color = new ColorButton( m_custom_colors, ID_NOTIFICATION, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_note_color->SetColor( wxColour( 255, 191, 0 ) );
+
+ bNoteColorSizer->Add( m_note_color, 0, wxALL, 5 );
+
+ m_note_label = new wxStaticText( m_custom_colors, wxID_ANY, _( "Notification" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_note_label->Wrap( -1 );
+ bNoteColorSizer->Add( m_note_label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ bColorSizer2->Add( bNoteColorSizer, 0, wxEXPAND, 5 );
+
+ bColorSizer->Add( bColorSizer2, 1, wxEXPAND, 5 );
+
+ bCustomColorsSizer->Add( bColorSizer, 1, wxEXPAND, 5 );
+
+ m_test_text = new wxTextCtrl( m_custom_colors, wxID_ANY, _( "[19:35] ** Server ** Connected to Server.\n[22:30] <Dude> hi everyone\n[22:30] ** Dude2 joined the channel.\n[22:30] * Dude2 thinks his colors looks nice\n[22:45] <Dude> Dude2: orl?\n[22:46] <Dude2> But could be better, should tweak them some more...\n" ), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH );
+ bCustomColorsSizer->Add( m_test_text, 1, wxALL | wxEXPAND, 5 );
+
+ m_custom_colors->SetSizer( bCustomColorsSizer );
+ m_custom_colors->Layout();
+ bCustomColorsSizer->Fit( m_custom_colors );
+ bColorsVSizer->Add( m_custom_colors, 1, wxEXPAND | wxALL, 0 );
+
+ wxBoxSizer* bFontNameSizer;
+ bFontNameSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_font_label = new wxStaticText( this, wxID_ANY, _( "Font:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_font_label->Wrap( -1 );
+ bFontNameSizer->Add( m_font_label, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_fontname = new wxStaticText( this, wxID_ANY, _( "default" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_fontname->Wrap( -1 );
+ bFontNameSizer->Add( m_fontname, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_select_font = new wxButton( this, ID_SELFONT, _( "Select..." ), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ bFontNameSizer->Add( m_select_font, 0, wxALL, 5 );
+
+ bColorsVSizer->Add( bFontNameSizer, 0, wxEXPAND, 5 );
+
+ sbColorsSizer->Add( bColorsVSizer, 1, wxEXPAND, 5 );
+
+ bMainSizerV->Add( sbColorsSizer, 0, wxEXPAND | wxBOTTOM | wxRIGHT | wxLEFT | wxTOP, 5 );
+
+
+ wxStaticBoxSizer* sbBehaviorSizer;
+ sbBehaviorSizer = new wxStaticBoxSizer( new wxStaticBox( this, -1, _( "Behavior" ) ), wxHORIZONTAL );
+
+ m_irc_colors = new wxCheckBox( this, wxID_ANY, _( "Enable Irc colors in chat messages" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_irc_colors->SetValue( sett().GetUseIrcColors() );
+
+ sbBehaviorSizer->Add( m_irc_colors, 0, wxALL, 5 );
+#ifndef DISABLE_SOUND
+ m_play_sounds = new wxCheckBox( this, ID_PLAY_SOUNDS, _( "Play notification sounds" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_play_sounds->SetValue( sett().GetChatPMSoundNotificationEnabled() );
+ sbBehaviorSizer->Add( m_play_sounds, 0, wxALL, 5 );
+#endif
+
+ bMainSizerV->Add( sbBehaviorSizer, 0, wxEXPAND | wxBOTTOM | wxRIGHT | wxLEFT, 5 );
+
+ wxBoxSizer* bBotomSizer;
+ bBotomSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxStaticBoxSizer* sbChatLogSizer;
+ wxStaticBox* sbChatLog = new wxStaticBox( this, -1, _( "Chat logs" ) );
+ sbChatLogSizer = new wxStaticBoxSizer( sbChatLog, wxVERTICAL );
+
+ m_save_logs = new wxCheckBox( this, wxID_ANY, _( "Save chat logs" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_save_logs->SetValue( sett().GetChatLogEnable() );
+
+ sbChatLogSizer->Add( m_save_logs, 0, wxALL, 5 );
+
+ bBotomSizer->Add( sbChatLogSizer, 1, wxEXPAND | wxRIGHT, 5 );
+
+ wxStaticBoxSizer* sbHighlightSizer;
+ sbHighlightSizer = new wxStaticBoxSizer( new wxStaticBox( this, -1, _( "Highlight words" ) ), wxVERTICAL );
+
+ m_hilight_words_label = new wxStaticText( this, wxID_ANY, _( "Words to highlight in chat:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_hilight_words_label->Wrap( -1 );
+
+ sbHighlightSizer->Add( m_hilight_words_label, 0, wxALL, 5 );
+
+
+ sbHighlightSizer->Add( 0, 0, 1, wxEXPAND, 5 );
+
+ m_highlight_words = new wxTextCtrl( this, ID_HIWORDS, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_highlight_words->SetToolTip ( TE( _( "enter a ; seperated list" ) ) );
+
+ sbHighlightSizer->Add( m_highlight_words, 0, wxALL | wxEXPAND, 5 );
+
+ m_highlight_req = new wxCheckBox( this, ID_HL_REQ, _( "Additionally play sound/flash titlebar " ), wxDefaultPosition, wxDefaultSize, 0 );
+ sbHighlightSizer->Add( m_highlight_req , 0, wxALL | wxEXPAND, 5 );
+
+ bBotomSizer->Add( sbHighlightSizer, 1, wxEXPAND, 5 );
+
+ bMainSizerV->Add( bBotomSizer, 0, wxEXPAND | wxBOTTOM | wxRIGHT | wxLEFT, 5 );
+
+
+ bMainSizerV->Add( 0, 0, 1, wxEXPAND | wxALL, 5 );
+
+ SetScrollRate( 3, 3 );
+
+ SetSizer( bMainSizerV );
+ Layout();
+
+ if ( sett().IsPortableMode() ) sbChatLog->Disable();
+
+ DoRestore();
+ UpdateTextSample();
+}
+
+
+ChatOptionsTab::~ChatOptionsTab()
+{
+
+}
+
+
+void ChatOptionsTab::UpdateTextSample()
+{
+ m_test_text->Clear();
+ m_test_text->SetFont( m_chat_font );
+ m_test_text->SetBackgroundColour( m_bg_color->GetColor() );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[19:35]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_server_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " ** Server ** Connected to Server.\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:30]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_normal_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " <Dude> hi everyone\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:30]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_joinleave_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " ** Dude2 joined the channel.\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:31]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_action_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " * Dude2 thinks his colors looks nice\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:33]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_note_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "<Dude> Dude2: orl?\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:33]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_my_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " <Dude2> Yeah, but could be better, should tweak them some more...\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:33]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_highlight_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " <Dude> bla bla bla Highlighted word bla bla.\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:33]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_error_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " !! Error error.\n" ) );
+
+ m_test_text->SetDefaultStyle( wxTextAttr( m_ts_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( "[22:33]" ) );
+ m_test_text->SetDefaultStyle( wxTextAttr( m_client_color->GetColor(), m_bg_color->GetColor(), m_chat_font ) );
+ m_test_text->AppendText( _T( " ** Client message." ) );
+
+}
+
+
+void ChatOptionsTab::DoRestore()
+{
+ m_normal_color->SetColor( sett().GetChatColorNormal() );
+ m_bg_color->SetColor( sett().GetChatColorBackground() );
+ m_action_color->SetColor( sett().GetChatColorAction() );
+ m_highlight_color->SetColor( sett().GetChatColorHighlight() );
+ m_joinleave_color->SetColor( sett().GetChatColorJoinPart() );
+ m_note_color->SetColor( sett().GetChatColorNotification() );
+ m_my_color->SetColor( sett().GetChatColorMine() );
+ m_server_color->SetColor( sett().GetChatColorServer() );
+ m_client_color->SetColor( sett().GetChatColorClient() );
+ m_error_color->SetColor( sett().GetChatColorError() );
+ m_ts_color->SetColor( sett().GetChatColorTime() );
+ m_chat_font = sett().GetChatFont();
+ m_fontname->SetLabel( m_chat_font.GetFaceName() );
+ m_save_logs->SetValue( sett().GetChatLogEnable() );
+ m_irc_colors->SetValue( sett().GetUseIrcColors() );
+ wxString highlightstring;
+ wxArrayString highlights = sett().GetHighlightedWords();
+ for ( unsigned int i = 0; i < highlights.GetCount(); i++ ) highlightstring << highlights[i] << _T( ";" );
+ m_highlight_words->SetValue( highlightstring );
+ m_highlight_req->SetValue( sett().GetRequestAttOnHighlight() );
+#ifndef DISABLE_SOUND
+ m_play_sounds->SetValue( sett().GetChatPMSoundNotificationEnabled() );
+#endif
+}
+
+void ChatOptionsTab::OnApply( wxCommandEvent& /*unused*/ )
+{
+ sett().SetChatColorNormal ( m_normal_color->GetColor() );
+ sett().SetChatColorBackground( m_bg_color->GetColor() );
+ sett().SetChatColorAction( m_action_color->GetColor() );
+ sett().SetChatColorHighlight( m_highlight_color->GetColor() );
+ sett().SetChatColorJoinPart( m_joinleave_color->GetColor() );
+ sett().SetChatColorNotification( m_note_color->GetColor() );
+ sett().SetChatColorMine( m_my_color->GetColor() );
+ sett().SetChatColorServer( m_server_color->GetColor() );
+ sett().SetChatColorClient( m_client_color->GetColor() );
+ sett().SetChatColorError( m_error_color->GetColor() );
+ sett().SetChatColorTime( m_ts_color->GetColor() );
+ sett().SetChatFont( m_chat_font );
+ sett().SetUseIrcColors( m_irc_colors->IsChecked() );
+ //m_ui.mw().GetChatTab().ChangeUnreadChannelColour( m_note_color->GetBackgroundColour() );
+ //m_ui.mw().GetChatTab().ChangeUnreadPMColour( m_note_color->GetBackgroundColour() );
+ sett().SetHighlightedWords( wxStringTokenize( m_highlight_words->GetValue(), _T( ";" ) ) );
+ sett().SetRequestAttOnHighlight( m_highlight_req->IsChecked() );
+
+ //Chat Log
+ sett().SetChatLogEnable( m_save_logs->GetValue() );
+
+ // Behavior
+#ifndef DISABLE_SOUND
+ sett().SetChatPMSoundNotificationEnabled( m_play_sounds->IsChecked() );
+#endif
+
+}
+
+
+void ChatOptionsTab::OnRestore( wxCommandEvent& /*unused*/ )
+{
+ DoRestore();
+}
+
+
+void ChatOptionsTab::OnSelectFont( wxCommandEvent& /*unused*/ )
+{
+ wxFontData data;
+ data.SetChosenFont( m_chat_font );
+ wxFontDialog dlg( ( wxWindow* ) &ui().mw(), data );
+ if ( dlg.ShowModal() == wxID_OK ) {
+ m_chat_font = dlg.GetFontData().GetChosenFont();
+ m_fontname->SetLabel( m_chat_font.GetFaceName() );
+ this->Layout();
+ UpdateTextSample();
+ }
+}
+
+
+void ChatOptionsTab::OnUseSystemColors( wxCommandEvent& /*unused*/ )
+{
+}
+
+void ChatOptionsTab::OnColorChange( ColorButton* button )
+{
+ wxColour c = GetColourFromUser( this, button->GetColor() );
+ if ( c.IsOk() ) {
+ button->SetColor( c );
+ }
+ UpdateTextSample();
+}
+
+void ChatOptionsTab::OnNormalSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_normal_color );
+}
+
+void ChatOptionsTab::OnBGSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_bg_color );
+}
+
+void ChatOptionsTab::OnActionSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_action_color );
+}
+
+void ChatOptionsTab::OnHighlightSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_highlight_color );
+}
+
+void ChatOptionsTab::OnJoinLeaveSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_joinleave_color );
+}
+
+void ChatOptionsTab::OnNotificationSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_note_color );
+}
+
+void ChatOptionsTab::OnMyMessSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_my_color );
+}
+
+void ChatOptionsTab::OnServerSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_server_color );
+}
+
+void ChatOptionsTab::OnClientSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_client_color );
+}
+
+void ChatOptionsTab::OnErrorSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_error_color );
+}
+
+void ChatOptionsTab::OnTimestampSelect( wxCommandEvent& /*unused*/ )
+{
+ OnColorChange( m_ts_color );
+}
+
diff --git a/src/chatoptionstab.h b/src/chatoptionstab.h
new file mode 100644
index 0000000..0bccd4f
--- /dev/null
+++ b/src/chatoptionstab.h
@@ -0,0 +1,156 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CHATOPTIONSTAB_H
+#define SPRINGLOBBY_HEADERGUARD_CHATOPTIONSTAB_H
+
+#include <wx/scrolwin.h>
+
+class wxStaticBoxSizer;
+class wxStaticBox;
+class wxStaticText;
+class wxRadioButton;
+class wxButton;
+class wxTextCtrl;
+class wxBoxSizer;
+class wxCheckBox;
+class Ui;
+class ColorButton;
+
+
+class ChatOptionsTab : public wxScrolledWindow
+{
+ public:
+ ChatOptionsTab( wxWindow* parent, Ui& ui );
+ ~ChatOptionsTab();
+
+ void UpdateTextSample();
+
+ void DoRestore();
+
+ void OnApply( wxCommandEvent& event );
+ void OnRestore( wxCommandEvent& event );
+
+ void OnSelectFont( wxCommandEvent& event );
+ void OnUseSystemColors( wxCommandEvent& event );
+ void OnNormalSelect( wxCommandEvent& event );
+ void OnBGSelect( wxCommandEvent& event );
+ void OnActionSelect( wxCommandEvent& event );
+ void OnHighlightSelect( wxCommandEvent& event );
+ void OnJoinLeaveSelect( wxCommandEvent& event );
+ void OnNotificationSelect( wxCommandEvent& event );
+ void OnMyMessSelect( wxCommandEvent& event );
+ void OnServerSelect( wxCommandEvent& event );
+ void OnClientSelect( wxCommandEvent& event );
+ void OnErrorSelect( wxCommandEvent& event );
+ void OnTimestampSelect( wxCommandEvent& event );
+ void OnSaveLogs( wxCommandEvent& event );
+
+ protected:
+
+ enum
+ {
+ ID_SELFONT = 1000,
+ ID_SYSCOLS,
+ ID_NORMAL,
+ ID_BG,
+ ID_ACTION,
+ ID_HIGHLIGHT,
+ ID_JOINLEAVE,
+ ID_NOTIFICATION,
+ ID_MYMESS,
+ ID_SERVER,
+ ID_CLIENT,
+ ID_ERROR,
+ ID_TIMESTAMP,
+ ID_HIWORDS,
+ ID_PLAY_SOUNDS,
+ ID_HL_REQ
+ };
+
+ wxStaticText* m_text_sample;
+ wxStaticText* m_fontname;
+ wxStaticText* m_font_label;
+ wxButton* m_select_font;
+ wxCheckBox* m_use_sys_colors;
+ wxPanel* m_custom_colors;
+ ColorButton* m_normal_color;
+ wxStaticText* m_normal_label;
+ ColorButton* m_bg_color;
+ wxStaticText* m_bg_label;
+ ColorButton* m_action_color;
+ wxStaticText* m_action_label;
+ ColorButton* m_highlight_color;
+ wxStaticText* m_highlight_label;
+ ColorButton* m_joinleave_color;
+ wxStaticText* m_joinleave_label;
+ ColorButton* m_note_color;
+ wxStaticText* m_note_label;
+ ColorButton* m_my_color;
+ wxStaticText* m_my_label;
+ ColorButton* m_server_color;
+ wxStaticText* m_server_label;
+ ColorButton* m_client_color;
+ wxStaticText* m_client_label;
+ ColorButton* m_error_color;
+ wxStaticText* m_error_label;
+ ColorButton* m_ts_color;
+ wxStaticText* m_ts_label;
+ wxTextCtrl* m_test_text;
+ wxCheckBox* m_save_logs;
+ wxStaticText* m_chat_save_label;
+ wxTextCtrl* m_log_save;
+ wxButton* m_browse_log;
+ wxStaticText* m_hilight_words_label;
+ wxCheckBox* m_play_sounds;
+ wxCheckBox* m_highlight_req;
+
+ wxTextCtrl* m_highlight_words;
+
+ wxCheckBox* m_irc_colors;
+
+ wxFont m_chat_font;
+
+ Ui& m_ui;
+
+ /// generic func used in all handlers
+ void OnColorChange( ColorButton* button );
+
+ DECLARE_EVENT_TABLE()
+};
+
+// enum
+// {
+// SPRING_DIRBROWSE = wxID_HIGHEST,
+// SPRING_EXECBROWSE,
+// SPRING_SYNCBROWSE,
+// SPRING_WEBBROWSE,
+// SPRING_DEFEXE,
+// SPRING_DEFUSYNC,
+// SPRING_DEFWEB,
+// SPRING_AUTOCONF,
+// SPRING_DIRFIND,
+// SPRING_EXECFIND,
+// SPRING_SYNCFIND,
+//
+// //Chat Log
+// CHATLOG_ENABLE,
+//
+// };
+
+#endif // SPRINGLOBBY_HEADERGUARD_CHATOPTIONSTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/chatpanel.cpp b/src/chatpanel.cpp
new file mode 100644
index 0000000..6e4fb93
--- /dev/null
+++ b/src/chatpanel.cpp
@@ -0,0 +1,1942 @@
+// Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: ChatPanel
+//
+
+
+#include <stdexcept>
+
+#include <wx/intl.h>
+#include <wx/datetime.h>
+#include <wx/sizer.h>
+#include <wx/splitter.h>
+#include <wx/combobox.h>
+#include <wx/button.h>
+#include <wx/tokenzr.h>
+#include <wx/msgdlg.h>
+#include <wx/menu.h>
+#include <wx/log.h>
+#include <wx/utils.h>
+#include <wx/event.h>
+#include <wx/app.h>
+#include <wx/clipbrd.h>
+#include <wx/dataobj.h>
+#include <wx/imaglist.h>
+#include <wx/wupdlock.h>
+#include <wx/bmpbuttn.h>
+#include <wx/stattext.h>
+
+#include "aui/auimanager.h"
+#include "aui/slbook.h"
+#include "channel/channel.h"
+#include "chatpanel.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "utils/platform.h"
+#include "ui.h"
+#include "server.h"
+#include "user.h"
+#include "battle.h"
+#include "nicklistctrl.h"
+#include "mainwindow.h"
+#include "chatlog.h"
+#include "settings++/custom_dialogs.h"
+#include "settings.h"
+#include "uiutils.h"
+#include "Helper/wxtextctrlhist.h"
+
+#ifndef DISABLE_SOUND
+#include "sdlsound.h"
+#endif
+#include "useractions.h"
+#include "usermenu.h"
+
+/*
+BEGIN_EVENT_TABLE(MyTextCtrl, wxTextCtrl)
+EVT_PAINT(MyTextCtrl::OnPaint)
+END_EVENT_TABLE()
+*/
+
+BEGIN_EVENT_TABLE( ChatPanel, wxPanel )
+
+ EVT_TEXT_ENTER( CHAT_TEXT, ChatPanel::OnSay )
+ EVT_TEXT_PASTE( CHAT_TEXT, ChatPanel::OnPaste )
+ EVT_BUTTON( CHAT_CHAN_OPTS, ChatPanel::OnChanOpts )
+ EVT_BUTTON( CHAT_SEND, ChatPanel::OnSay )
+ EVT_TEXT_URL( CHAT_LOG, ChatPanel::OnLinkEvent )
+
+ EVT_MENU( CHAT_MENU_DISABLE_APPEND, ChatPanel::OnMenuToggleAppend )
+
+ EVT_MENU( CHAT_MENU_CH_LEAVE, ChatPanel::OnChannelMenuLeave )
+ EVT_MENU( CHAT_MENU_CH_DISPLAYJOIN, ChatPanel::OnChannelMenuDisplayJoinLeave )
+ EVT_MENU( CHAT_MENU_CH_AUTOJOIN, ChatPanel::OnChannelAutoJoin )
+ EVT_MENU( CHAT_MENU_CH_INFO, ChatPanel::OnChannelMenuInfo )
+ EVT_MENU( CHAT_MENU_CH_TOPIC, ChatPanel::OnChannelMenuTopic )
+ EVT_MENU( CHAT_MENU_CH_MSG, ChatPanel::OnChannelMenuMessage )
+ EVT_MENU( CHAT_MENU_CH_LOCK, ChatPanel::OnChannelMenuLock )
+ EVT_MENU( CHAT_MENU_CH_UNLOCK, ChatPanel::OnChannelMenuUnlock )
+ EVT_MENU( CHAT_MENU_CH_REG, ChatPanel::OnChannelMenuRegister )
+ EVT_MENU( CHAT_MENU_CH_UNREG, ChatPanel::OnChannelMenuUnregister )
+ EVT_MENU( CHAT_MENU_CH_SPAM_ON, ChatPanel::OnChannelMenuSpamOn )
+ EVT_MENU( CHAT_MENU_CH_SPAM_OFF, ChatPanel::OnChannelMenuSpanOff )
+ EVT_MENU( CHAT_MENU_CH_SPAM_ISON, ChatPanel::OnChannelMenuSpamIsOn )
+ EVT_MENU( CHAT_MENU_CH_CLEAR, ChatPanel::ClearContents )
+
+ EVT_MENU( CHAT_MENU_SV_DISCON, ChatPanel::OnServerMenuDisconnect )
+ EVT_MENU( CHAT_MENU_SV_RECON, ChatPanel::OnServerMenuReconnect )
+ EVT_MENU( CHAT_MENU_SV_REMOVE, ChatPanel::OnServerMenuRemove )
+ EVT_MENU( CHAT_MENU_SV_CHPWD, ChatPanel::OnServerMenuChangePassword )
+ EVT_MENU( CHAT_MENU_SV_ACCESS, ChatPanel::OnServerMenuSetAccess )
+ EVT_MENU( CHAT_MENU_SV_BROADCAST, ChatPanel::OnServerMenuBroadcast )
+
+ EVT_MENU( CHAT_MENU_US_CHAT, ChatPanel::OnUserMenuOpenChat )
+ EVT_MENU( CHAT_MENU_US_JOIN, ChatPanel::OnUserMenuJoinSame )
+ EVT_MENU( CHAT_MENU_US_SLAP, ChatPanel::OnUserMenuSlap )
+ EVT_MENU( CHAT_MENU_US_ADD_TO_GROUP, ChatPanel::OnUserMenuAddToGroup )
+ EVT_MENU( CHAT_MENU_US_MUTE, ChatPanel::OnUserMenuMute )
+ EVT_MENU( CHAT_MENU_US_UNMUTE, ChatPanel::OnUserMenuUnmute )
+ EVT_MENU( CHAT_MENU_US_KICK, ChatPanel::OnUserMenuKick )
+ EVT_MENU( CHAT_MENU_US_OP, ChatPanel::OnUserMenuOp )
+ EVT_MENU( CHAT_MENU_US_DEOP, ChatPanel::OnUserMenuDeop )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_INGAME, ChatPanel::OnUserMenuModeratorIngame )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_CURIP, ChatPanel::OnUserMenuModeratorCurrentIP )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_KICK, ChatPanel::OnUserMenuModeratorKick )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_BAN, ChatPanel::OnUserMenuModeratorBan )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_UNBAN, ChatPanel::OnUserMenuModeratorUnban )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_MUTE, ChatPanel::OnUserMenuModeratorMute )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_MUTE_5, ChatPanel::OnUserMenuModeratorMute5 )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_MUTE_10, ChatPanel::OnUserMenuModeratorMute10 )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_MUTE_30, ChatPanel::OnUserMenuModeratorMute30 )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_MUTE_120, ChatPanel::OnUserMenuModeratorMute120 )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_MUTE_1440, ChatPanel::OnUserMenuModeratorMute1440 )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_UNMUTE, ChatPanel::OnUserMenuModeratorUnmute )
+ EVT_MENU( CHAT_MENU_US_MODERATOR_RING, ChatPanel::OnUserMenuModeratorRing )
+
+ EVT_MENU( CHAT_MENU_COPYLINK, ChatPanel::OnUserMenuCopyLink )
+
+ EVT_MENU( CHAT_MENU_LOG_OPEN, ChatPanel::OnChatMenuOpenLog )
+
+ EVT_MENU( CHAT_MENU_SHOW_MUTELIST, ChatPanel::OnChannelMenuShowMutelist )
+
+END_EVENT_TABLE()
+
+ #ifdef __WXMSW__
+ wxString chan_prefix = _("channel_");
+ #else
+ wxString chan_prefix = _("#");
+ #endif
+
+/// table for irc colors
+static wxColor m_irc_colors[16] =
+{
+ wxColor(204,204,204),
+ wxColor(0,0,0),
+ wxColor(54,54,178),
+ wxColor(42,140,42),
+ wxColor(195,59,59),
+ wxColor(199,50,50),
+ wxColor(128,38,127),
+ wxColor(102,54,31),
+ wxColor(217,166,65),
+ wxColor(61,204,61),
+ wxColor(26,85,85),
+ wxColor(47,140,116),
+ wxColor(69,69,230),
+ wxColor(176,55,176),
+ wxColor(76,76,76),
+ wxColor(149,149,149)
+};
+
+ChatPanel::ChatPanel( wxWindow* parent, Ui& ui, Channel& chan, wxImageList* imaglist ):
+ wxPanel( parent, -1 ),
+ m_show_nick_list( true ),
+ m_nicklist(0),
+ m_chat_tabs(( SLNotebook* )parent ),
+ m_ui( ui ),
+ m_channel( &chan ),
+ m_server( 0 ),
+ m_user( 0 ),
+ m_battle( 0 ),
+ m_type( CPT_Channel ),
+ m_popup_menu( 0 ),
+ m_chat_log(sett().GetDefaultServer(), chan_prefix + chan.GetName()),
+ m_usermenu( 0 ),
+ m_icon_index( 2 ),
+ m_imagelist( imaglist ),
+ m_disable_append( false )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("chatpanel-channel-") + chan.GetName() );
+ wxLogDebugFunc( _T( "wxWindow* parent, Channel& chan" ) );
+ CreateControls( );
+ _SetChannel( &chan );
+ m_chatlog_text->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ChatPanel::OnMouseDown ), 0, this );
+
+
+}
+
+
+ChatPanel::ChatPanel( wxWindow* parent, Ui& ui, const User& user, wxImageList* imaglist ):
+ wxPanel( parent, -1 ),
+ m_show_nick_list( false ),
+ m_nicklist(0),
+ m_chat_tabs(( SLNotebook* )parent ),
+ m_ui( ui ),
+ m_channel( 0 ),
+ m_server( 0 ),
+ m_user( &user ),
+ m_battle( 0 ),
+ m_type( CPT_User ),
+ m_popup_menu( 0 ),
+ m_chat_log(sett().GetDefaultServer(), user.GetNick()),
+ m_usermenu( 0 ),
+ m_icon_index( 3 ),
+ m_imagelist( imaglist ),
+ m_disable_append( false )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("chatpanel-pm-") + user.GetNick() );
+ CreateControls( );
+ m_chatlog_text->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ChatPanel::OnMouseDown ), 0, this );
+ user.uidata.panel = this;
+
+}
+
+
+ChatPanel::ChatPanel( wxWindow* parent, Ui& ui, Server& serv, wxImageList* imaglist ):
+ wxPanel( parent, -1 ),
+ m_show_nick_list( false ),
+ m_nicklist(0),
+ m_chat_tabs(( SLNotebook* )parent ),
+ m_ui( ui ),
+ m_channel( 0 ),
+ m_server( &serv ),
+ m_user( 0 ),
+ m_battle( 0 ),
+ m_type( CPT_Server ),
+ m_popup_menu( 0 ),
+ m_chat_log(sett().GetDefaultServer(), _T( "_SERVER" )),
+ m_usermenu( 0 ),
+ m_icon_index( 1 ),
+ m_imagelist( imaglist ),
+ m_disable_append( false )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("chatpanel-server") );
+ wxLogDebugFunc( _T( "wxWindow* parent, Server& serv" ) );
+ CreateControls( );
+ m_chatlog_text->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ChatPanel::OnMouseDown ), 0, this );
+ serv.uidata.panel = this;
+
+ m_chatlog_text->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ChatPanel::OnMouseDown ), 0, this );
+}
+
+
+ChatPanel::ChatPanel( wxWindow* parent, Ui& ui, Battle& battle ):
+ wxPanel( parent, -1 ),
+ m_show_nick_list( false ),
+ m_nicklist( 0 ),
+ m_chat_tabs( 0 ),
+ m_ui( ui ),
+ m_channel( 0 ),
+ m_server( 0 ),
+ m_user( 0 ),
+ m_battle( &battle ),
+ m_type( CPT_Battle ),
+ m_popup_menu( 0 ),
+ m_chat_log(sett().GetDefaultServer(), _T( "_BATTLE_" ) + wxDateTime::Now().Format( _T( "%Y_%m_%d__%H_%M_%S" ) )),
+ m_usermenu( 0 ),
+ m_disable_append( false )
+{
+ wxLogDebugFunc( _T( "wxWindow* parent, Battle& battle" ) );
+ for (unsigned int i = 0; i < battle.GetNumUsers();++i)
+ {
+ textcompletiondatabase.Insert_Mapping( battle.GetUser(i).GetNick(), battle.GetUser(i).GetNick() );
+ }
+ CreateControls( );
+ m_chatlog_text->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ChatPanel::OnMouseDown ), 0, this );
+
+}
+
+
+//! @brief ChatPanel destructor.
+ChatPanel::~ChatPanel()
+{
+ if ( m_server != 0 ) {
+ if ( m_server->uidata.panel == this ) m_server->uidata.panel = 0;
+ }
+ if ( m_user != 0 ) {
+ if ( m_user->uidata.panel == this ) m_user->uidata.panel = 0;
+ }
+ if ( m_channel != 0 ) {
+ if ( m_channel->uidata.panel == this ) m_channel->uidata.panel = 0;
+ }
+
+ if ( m_type == CPT_Channel )
+ {
+ m_chatlog_text->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ChatPanel::OnMouseDown ), 0, 0 );
+ if(GetAui().manager)GetAui().manager->DetachPane( this );
+ }
+ else if ( m_type == CPT_Server )
+ {
+ m_chatlog_text->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ChatPanel::OnMouseDown ), 0, 0 );
+ if(GetAui().manager)GetAui().manager->DetachPane( this );
+ }
+ else if ( m_type == CPT_User )
+ {
+ if(GetAui().manager)GetAui().manager->DetachPane( this );
+ }
+}
+
+
+void ChatPanel::CreateControls( )
+{
+ wxLogDebugFunc( _T( "" ) );
+
+ m_autorejoin = 0;
+ // Creating sizers
+ m_main_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_chat_sizer = new wxBoxSizer( wxVERTICAL );
+ m_say_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ if ( m_show_nick_list ) {
+
+ m_splitter = new wxSplitterWindow( this, -1, wxDefaultPosition, wxDefaultSize, wxSP_3D );
+ m_splitter->SetSashGravity( 0.9 );
+ m_nick_panel = new wxPanel( m_splitter, -1 );
+ m_chat_panel = new wxPanel( m_splitter, -1 );
+
+ m_nick_sizer = new wxBoxSizer( wxVERTICAL );
+ m_usercount_label = new wxStaticText( m_nick_panel, wxID_ANY, wxString::Format( _("%d users"), GetChannel()->GetNumUsers() ) );
+ m_usermenu = CreateNickListMenu();
+ m_nicklist = new NickListCtrl( m_nick_panel, true, m_usermenu );
+
+ // m_nick_filter = new wxComboBox( m_nick_panel, -1, _("Show all"), wxDefaultPosition, wxSize(80,CONTROL_HEIGHT), 0, 0, wxCB_READONLY );
+ // m_nick_filter->Disable();
+
+ m_nick_sizer->Add( m_usercount_label, 0 );
+ m_nick_sizer->Add( m_nicklist, 1, wxEXPAND );
+ // m_nick_sizer->Add( m_nick_filter, 0, wxEXPAND | wxTOP, 2 );
+
+ m_nick_panel->SetSizer( m_nick_sizer );
+
+ } else {
+
+ m_chat_panel = this;
+ m_nick_sizer = 0;
+ m_nicklist = 0;
+ m_nick_filter = 0;
+ m_splitter = 0;
+
+ }
+
+ // Creating ui elements
+
+ m_chatlog_text = new wxTextCtrl( m_chat_panel, CHAT_LOG, _T( "" ), wxDefaultPosition, wxDefaultSize,
+ wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH | wxTE_AUTO_URL );
+ if ( m_type == CPT_Channel ) {
+ m_chatlog_text->SetToolTip( TE(_("right click for options (like autojoin)" ) ) );
+ m_chan_opts_button = new wxBitmapButton(m_chat_panel, CHAT_CHAN_OPTS, icons().GetBitmap(icons().ICON_CHANNEL_OPTIONS), wxDefaultPosition , wxSize( CONTROL_HEIGHT, CONTROL_HEIGHT ) );
+ } else {
+ m_chan_opts_button = 0;
+ }
+
+
+ m_say_text = new wxTextCtrlHist( textcompletiondatabase, m_chat_panel, CHAT_TEXT, _T( "" ), wxDefaultPosition, wxSize( 100, CONTROL_HEIGHT ), wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB );
+ m_say_button = new wxButton( m_chat_panel, CHAT_SEND, _( "Send" ), wxDefaultPosition, wxSize( 80, CONTROL_HEIGHT ) );
+
+ // Adding elements to sizers
+ if ( m_type == CPT_Channel )
+ m_say_sizer->Add( m_chan_opts_button );
+ m_say_sizer->Add( m_say_text, 1, wxEXPAND );
+ m_say_sizer->Add( m_say_button );
+ m_chat_sizer->Add( m_chatlog_text, 1, wxEXPAND );
+ m_chat_sizer->Add( m_say_sizer, 0, wxEXPAND | wxTOP, 2 );
+ if ( m_show_nick_list )
+ {
+ m_chat_panel->SetSizer( m_chat_sizer );
+ m_splitter->SplitVertically( m_chat_panel, m_nick_panel, 100 );
+ m_splitter->SetMinimumPaneSize( 30 );
+ m_main_sizer->Add( m_splitter, 1, wxEXPAND | wxALL, 2 );
+ } else
+ {
+ m_main_sizer->Add( m_chat_sizer, 4, wxEXPAND | wxALL, 2 );
+ }
+
+ // Assign sizer to panel
+ SetSizer( m_main_sizer );
+
+ if ( m_show_nick_list ) {
+ wxSize s = m_splitter->GetSize();
+ m_splitter->SetSashPosition( s.GetWidth() - 238, true );
+ }
+
+ m_chatlog_text->SetBackgroundColour( sett().GetChatColorBackground() );
+ m_chatlog_text->SetFont( sett().GetChatFont() );
+
+ m_say_text->SetBackgroundColour( sett().GetChatColorBackground() );
+ m_say_text->SetFont( sett().GetChatFont() );
+ m_say_text->SetForegroundColour(sett().GetChatColorNormal());
+
+ // Fill up TextCompletionDatabase
+ textcompletiondatabase.Insert_Mapping( _T("DLDK"), _T("Der Lockruf des Kaos") );
+ textcompletiondatabase.Insert_Mapping( _T("lol"), _T("Laughing out loud") );
+ textcompletiondatabase.Insert_Mapping( _T("wb"), _T("Welcome back") );
+ textcompletiondatabase.Insert_Mapping( _T("hf"), _T("Have Fun!") );
+ textcompletiondatabase.Insert_Mapping( _T("glhf"), _T("Good luck, have Fun!") );
+ textcompletiondatabase.Insert_Mapping( _T("kaot"), _T("Have Fun!") );
+ textcompletiondatabase.Insert_Mapping( _T("kaot_H"), _T("Der Kaot aus der HÄÅlle.") );
+
+}
+
+
+void ChatPanel::CreatePopup()
+{
+ if ( m_popup_menu != 0 ) return;
+ wxLogDebugFunc( _T( "" ) );
+
+ m_popup_menu = new wxMenu();
+
+ m_append_menu = new wxMenuItem( m_popup_menu, CHAT_MENU_DISABLE_APPEND, _( "Disable text appending (workaround for autoscroll)" ), wxEmptyString, wxITEM_CHECK );
+ m_popup_menu->Append( m_append_menu );
+ m_append_menu->Check( m_disable_append );
+
+ wxMenuItem* copy = new wxMenuItem( m_popup_menu, wxID_COPY, _( "Copy" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( copy );
+ // eventID, eventType, member function pointer to be called userData instance on which member function is called
+ Connect( wxID_COPY, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTextCtrl::OnCopy, (wxObject*) NULL, (wxEvtHandler*)m_chatlog_text );
+
+ if ( m_url_at_pos != _T("") ) {
+ wxMenuItem* copylink = new wxMenuItem( m_popup_menu, CHAT_MENU_COPYLINK, _( "Copy link location" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( copylink );
+ }
+
+ wxMenuItem* clear = new wxMenuItem( m_popup_menu, CHAT_MENU_CH_CLEAR, _( "Clear" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( clear );
+
+ if ( m_type == CPT_Channel ) {
+
+ wxLogMessage( _T( "channel" ) );
+ m_autorejoin = new wxMenuItem( m_popup_menu, CHAT_MENU_CH_AUTOJOIN, _( "Auto join this channel" ), wxEmptyString, wxITEM_CHECK );
+ m_popup_menu->Append( m_autorejoin );
+ if ( m_channel ) {
+ bool isautojoin = sett().GetChannelJoinIndex(m_channel->GetName()) >= 0;
+ m_autorejoin->Check( isautojoin );
+ }
+
+ wxMenuItem* leaveitem = new wxMenuItem( m_popup_menu, CHAT_MENU_CH_LEAVE, _( "Leave" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( leaveitem );
+
+ displayjoinitem = new wxMenuItem( m_popup_menu, CHAT_MENU_CH_DISPLAYJOIN, _( "Display Join/Leave Messages" ), wxEmptyString, wxITEM_CHECK );
+ if ( m_channel && m_type == CPT_Channel ) {
+ m_popup_menu->Append( displayjoinitem );
+ displayjoinitem->Check( sett().GetDisplayJoinLeave( m_channel->GetName() ) );
+ }
+
+ wxMenuItem* mutelistitem = new wxMenuItem( m_popup_menu, CHAT_MENU_SHOW_MUTELIST, _( "Show mute list" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( mutelistitem );
+
+ m_popup_menu->AppendSeparator();
+ wxMenu* m_chanserv;
+ m_chanserv = new wxMenu();
+ wxMenuItem* infoitem = new wxMenuItem( m_chanserv, CHAT_MENU_CH_INFO, _( "Channel info" ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( infoitem );
+
+ m_chanserv->AppendSeparator();
+ wxMenuItem* chtopicitem = new wxMenuItem( m_chanserv, CHAT_MENU_CH_TOPIC, _( "Set topic..." ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chtopicitem );
+ wxMenuItem* chmessageitem = new wxMenuItem( m_chanserv, CHAT_MENU_CH_MSG, _( "Channel message..." ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chmessageitem );
+
+ m_chanserv->AppendSeparator();
+ wxMenuItem* chlockitem = new wxMenuItem( m_chanserv, CHAT_MENU_CH_LOCK, _( "Lock..." ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chlockitem );
+ wxMenuItem* chunlockitem = new wxMenuItem( m_chanserv, CHAT_MENU_CH_UNLOCK, _( "Unlock" ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chunlockitem );
+
+ m_chanserv->AppendSeparator();
+ wxMenuItem* chregisteritem = new wxMenuItem( m_chanserv, CHAT_MENU_CH_REG, _( "Register..." ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chregisteritem );
+ wxMenuItem* chunregisteritem = new wxMenuItem( m_chanserv, CHAT_MENU_CH_UNREG, _( "Unregister" ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chunregisteritem );
+
+ m_chanserv->AppendSeparator();
+ wxMenu* m_spam;
+ m_spam = new wxMenu();
+ wxMenuItem* spamprotonitem = new wxMenuItem( m_spam, CHAT_MENU_CH_SPAM_ON, _( "On" ), wxEmptyString, wxITEM_NORMAL );
+ m_spam->Append( spamprotonitem );
+ wxMenuItem* spamprotoffitem = new wxMenuItem( m_spam, CHAT_MENU_CH_SPAM_OFF, _( "Off" ), wxEmptyString, wxITEM_NORMAL );
+ m_spam->Append( spamprotoffitem );
+
+ m_spam->AppendSeparator();
+ wxMenuItem* spamprotisonitem = new wxMenuItem( m_spam, CHAT_MENU_CH_SPAM_ISON, _( "Is on?" ), wxEmptyString, wxITEM_NORMAL );
+ m_spam->Append( spamprotisonitem );
+ m_chanserv->Append( -1, _( "Spam protection" ), m_spam );
+ m_popup_menu->Append( -1, _( "ChanServ" ), m_chanserv );
+
+ }
+ else if ( m_type == CPT_Server ) {
+
+ wxLogMessage( _T( "server" ) );
+
+ wxMenuItem* disconnectitem = new wxMenuItem( m_popup_menu, CHAT_MENU_SV_DISCON, _( "Disconnect" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( disconnectitem );
+ wxMenuItem* reconnectitem = new wxMenuItem( m_popup_menu, CHAT_MENU_SV_RECON, _( "Reconnect" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( reconnectitem );
+
+ m_popup_menu->AppendSeparator();
+ wxMenu* m_user_menu;
+
+ m_user_menu = new wxMenu();
+ wxMenu* m_accounts;
+ m_accounts = new wxMenu();
+ wxMenuItem* removeitem = new wxMenuItem( m_accounts, CHAT_MENU_SV_REMOVE, _( "Remove..." ), wxEmptyString, wxITEM_NORMAL );
+ m_accounts->Append( removeitem );
+ wxMenuItem* chpwditem = new wxMenuItem( m_accounts, CHAT_MENU_SV_CHPWD, _( "Change password..." ), wxEmptyString, wxITEM_NORMAL );
+ m_accounts->Append( chpwditem );
+ wxMenuItem* setaccessitem = new wxMenuItem( m_accounts, CHAT_MENU_SV_ACCESS, _( "Set access..." ), wxEmptyString, wxITEM_NORMAL );
+ m_accounts->Append( setaccessitem );
+ m_user_menu->Append( -1, _( "Accounts" ), m_accounts );
+
+ m_user_menu->AppendSeparator();
+ wxMenuItem* broadcastitem = new wxMenuItem( m_user_menu, CHAT_MENU_SV_BROADCAST, _( "Broadcast..." ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( broadcastitem );
+ m_popup_menu->Append( -1, _( "Admin" ), m_user_menu );
+ }
+ else if ( m_type == CPT_User ) {
+ if ( m_usermenu )
+ delete m_usermenu ;
+
+ m_usermenu = CreateNickListMenu();
+ if ( m_user )
+ m_usermenu->EnableItems( true, m_user->GetNick() );
+ m_popup_menu->AppendSubMenu( m_usermenu, _("User") );
+ }
+
+ if ( m_chat_log.LogEnabled() ) {
+ wxMenuItem* open_extern = new wxMenuItem( m_popup_menu, CHAT_MENU_LOG_OPEN, _( "Open log in editor" ), wxEmptyString, wxITEM_NORMAL );
+ m_popup_menu->Append( open_extern );
+ }
+}
+
+
+ChatPanel::UserMenu* ChatPanel::CreateNickListMenu()
+{
+ ChatPanel::UserMenu* m_user_menu;
+ m_user_menu = new ChatPanel::UserMenu( this );
+ if ( m_type != CPT_User ) {
+ wxMenuItem* chatitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_CHAT, _( "Open Chat" ) , wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( chatitem );
+ }
+ wxMenuItem* joinbattleitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_JOIN, _( "Join same battle" ) , wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( joinbattleitem );
+
+ m_user_menu->AppendSeparator();
+
+ if ( ui().GetServer().GetMe().GetStatus().moderator ) {
+ wxMenuItem* modingameitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_MODERATOR_INGAME, _( "Ingame time" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( modingameitem );
+ wxMenuItem* modipitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_MODERATOR_CURIP, _( "Retrieve IP and Smurfs" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( modipitem );
+
+ m_user_menu->AppendSeparator();
+
+ wxMenu* m_user_menu_mute;
+ m_user_menu_mute = new wxMenu();
+ wxMenuItem* modmuteitem = new wxMenuItem( m_user_menu_mute, CHAT_MENU_US_MODERATOR_MUTE, _( "Mute..." ) , wxEmptyString, wxITEM_NORMAL );
+ m_user_menu_mute->Append( modmuteitem );
+ wxMenuItem* modmute5item = new wxMenuItem( m_user_menu_mute, CHAT_MENU_US_MODERATOR_MUTE_5, _( "Mute for 5 minutes" ) , wxEmptyString, wxITEM_NORMAL );
+ m_user_menu_mute->Append( modmute5item );
+ wxMenuItem* modmute10item = new wxMenuItem( m_user_menu_mute, CHAT_MENU_US_MODERATOR_MUTE_10, _( "Mute for 10 minutes" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu_mute->Append( modmute10item );
+ wxMenuItem* modmute30item = new wxMenuItem( m_user_menu_mute, CHAT_MENU_US_MODERATOR_MUTE_30, _( "Mute for 30 minutes" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu_mute->Append( modmute30item );
+ wxMenuItem* modmute120item = new wxMenuItem( m_user_menu_mute, CHAT_MENU_US_MODERATOR_MUTE_120, _( "Mute for 2 hours" ) , wxEmptyString, wxITEM_NORMAL );
+ m_user_menu_mute->Append( modmute120item );
+ wxMenuItem* modmute1440item = new wxMenuItem( m_user_menu_mute, CHAT_MENU_US_MODERATOR_MUTE_1440, _( "Mute for 1 day" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu_mute->Append( modmute1440item );
+ m_user_menu_mute->AppendSeparator();
+ wxMenuItem* modunmuteitem = new wxMenuItem( m_user_menu_mute, CHAT_MENU_US_MODERATOR_UNMUTE, _( "Unmute" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu_mute->Append( modunmuteitem );
+ m_user_menu->Append( -1, _( "Mute" ), m_user_menu_mute );
+
+ wxMenuItem* modkickitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_MODERATOR_KICK, _( "Kick..." ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( modkickitem );
+
+ m_user_menu->AppendSeparator();
+ wxMenuItem* modbanitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_MODERATOR_BAN, _( "Ban..." ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( modbanitem );
+ wxMenuItem* modunbanitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_MODERATOR_UNBAN, _( "Unban" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( modunbanitem );
+
+ m_user_menu->AppendSeparator();
+ wxMenuItem* modringitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_MODERATOR_RING, _( "Ring" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( modringitem );
+ //m_user_menu->Append( -1, _("Moderator"), m_user_menu );
+ } else {
+ wxMenuItem* slapitem = new wxMenuItem( m_user_menu, CHAT_MENU_US_SLAP, _( "Slap!" ), wxEmptyString, wxITEM_NORMAL );
+ m_user_menu->Append( slapitem );
+ }
+
+ if ( m_type != CPT_User ) {
+ m_user_menu->AppendSeparator();
+ wxMenu* m_chanserv;
+ m_chanserv = new wxMenu();
+ wxMenuItem* chmuteitem = new wxMenuItem( m_chanserv, CHAT_MENU_US_MUTE, _( "Mute..." ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chmuteitem );
+ wxMenuItem* chunmuteitem = new wxMenuItem( m_chanserv, CHAT_MENU_US_UNMUTE, _( "Unmute" ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chunmuteitem );
+ m_chanserv->AppendSeparator();
+ wxMenuItem* chkickitem = new wxMenuItem( m_chanserv, CHAT_MENU_US_KICK, _( "Kick..." ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chkickitem );
+
+ m_chanserv->AppendSeparator();
+ wxMenuItem* chopitem = new wxMenuItem( m_chanserv, CHAT_MENU_US_OP, _( "Op" ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chopitem );
+ wxMenuItem* chdeopitem = new wxMenuItem( m_chanserv, CHAT_MENU_US_DEOP, _( "DeOp" ), wxEmptyString, wxITEM_NORMAL );
+ m_chanserv->Append( chdeopitem );
+ m_user_menu->Append( -1, _( "ChanServ" ), m_chanserv );
+ }
+
+ return m_user_menu;
+}
+
+
+const User* ChatPanel::GetSelectedUser() const
+{
+ if ( m_type == CPT_User ) {
+ return m_user;
+ }
+ if ( !m_show_nick_list || ( m_nicklist == 0 ) ) return 0;
+
+ return m_nicklist->GetSelectedData();
+}
+
+
+const User& ChatPanel::GetMe() const
+{
+ return m_ui.GetServer().GetMe();
+}
+
+void ChatPanel::OutputLine( const wxString& message, const wxColour& col, const wxFont& fon )
+{
+
+ if ( ! m_chatlog_text ) return;
+
+ wxDateTime now = wxDateTime::Now();
+ wxTextAttr timestyle( sett().GetChatColorTime(), sett().GetChatColorBackground(), sett().GetChatFont() );
+ wxTextAttr chatstyle( col, sett().GetChatColorBackground(), fon );
+
+ ChatLine newline;
+#ifdef __WXMSW__
+ newline.chat = wxString( message.c_str() );
+#else
+ newline.chat = message;
+#endif
+ newline.time = _T( "[" ) + now.Format( _T( "%H:%M:%S" ) ) + _T( "]" );
+ newline.chatstyle = chatstyle;
+ newline.timestyle = timestyle;
+
+ if ( m_disable_append )
+ {
+ m_buffer.push_back( newline );
+ }
+ else
+ {
+ OutputLine( newline );
+ }
+
+ m_chat_log.AddMessage( message );
+
+}
+
+
+void ChatPanel::OutputLine( const ChatLine& line )
+{
+ #ifdef __WXMSW__
+ wxWindowUpdateLocker noUpdates(m_chatlog_text);
+ #endif
+
+ m_chatlog_text->SetDefaultStyle( line.timestyle );
+ m_chatlog_text->AppendText( line.time );
+
+ m_chatlog_text->SetDefaultStyle( line.chatstyle );
+
+
+ if ( sett().GetUseIrcColors() )
+ {
+ wxString m1;
+ wxString m2;
+ wxString m3;
+ wxTextAttr at;
+ int oldweight;
+ char c;
+ int color;
+ m1 = line.chat;
+ bool _2chars = false;
+ bool bold = false;
+ wxFont font;
+ wxColor curcolor(0,0,0);
+ wxColor oldcolor(0,0,0);
+ curcolor = line.chatstyle.GetTextColour();
+ at = m_chatlog_text->GetDefaultStyle();
+ font = at.GetFont();
+ oldweight = font.GetWeight();
+ oldcolor = line.chatstyle.GetTextColour();
+ while ( m1.Len() > 0 )
+ {
+ c = m1.GetChar(0);
+ if (c == 3 && m1.Len() > 1 && (m1.GetChar(1) >= 48 && m1.GetChar(1) <= 58)) // Color
+ {
+ if (m1.Len() > 2 && (m1.GetChar(2) >= 48 && m1.GetChar(2) <= 58))
+ {
+ color = (m1.GetChar(1) - 48)*10+(m1.GetChar(2) - 48);
+ _2chars = true;
+ m1 = m1.Mid(3);
+ }
+ else
+ {
+ color = m1.GetChar(1) -48;
+ _2chars = false;
+ m1 = m1.Mid(2);
+ }
+
+ wxColor dummy(0,0,0);
+ if ( ( color > -1 ) && ( color < ( sizeof( m_irc_colors ) / sizeof( dummy ) ) ) )
+ {
+
+ curcolor = m_irc_colors[color];
+ }
+
+ }else if(c == 2)//Bold
+ {
+ bold = not bold;
+ m1 = m1.Mid(1);
+ }else if(c == 0x0F) //Reset formatting
+ {
+ bold = false;
+ curcolor = oldcolor;
+ m1 = m1.Mid(1);
+ }else{
+
+ at = m_chatlog_text->GetDefaultStyle();
+ at.SetFlags(wxTEXT_ATTR_TEXT_COLOUR | wxTEXT_ATTR_FONT_WEIGHT);
+ font = at.GetFont();
+ if (bold)
+ font.SetWeight(wxFONTWEIGHT_BOLD);
+ else
+ font.SetWeight(oldweight);
+ at.SetFont(font);
+ at.SetTextColour(curcolor);
+
+ m_chatlog_text->SetDefaultStyle(at);
+ m_chatlog_text->AppendText( m1.Mid(0,1) );
+ m1 = m1.Mid(1);
+ }
+ }
+ if (bold)
+ {
+ font = at.GetFont();
+ font.SetWeight(oldweight);
+ at.SetFont(font);
+ m_chatlog_text->SetDefaultStyle(at);
+ }
+
+ }
+ else
+ {
+ m_chatlog_text->AppendText( line.chat );
+ }
+
+ m_chatlog_text->AppendText( _T( "\n" ) );
+
+ // crop lines from history that exceeds limit
+ int maxlenght = sett().GetChatHistoryLenght();
+ if ( ( maxlenght > 0 ) && ( m_chatlog_text->GetNumberOfLines() > sett().GetChatHistoryLenght() ) )
+ {
+ int end = 0;
+ for ( int i = 0; i < 20; i++ ) end += m_chatlog_text->GetLineLength( i ) + 1;
+ m_chatlog_text->Remove( 0, end );
+ }
+ #ifdef __WXMSW__
+ m_chatlog_text->ScrollLines( 10 ); // to prevent for weird empty space appended
+ m_chatlog_text->ShowPosition( m_chatlog_text->GetLastPosition() );// scroll to the bottom
+ #endif
+ this->Refresh();
+}
+
+
+void ChatPanel::OnLinkEvent( wxTextUrlEvent& event )
+{
+ if ( !event.GetMouseEvent().LeftDown() )
+ return;
+
+ wxString url = m_chatlog_text->GetRange( event.GetURLStart(), event.GetURLEnd());
+ m_ui.OpenWebBrowser( url );
+}
+
+void ChatPanel::OnUserMenuCopyLink( wxCommandEvent& /*unused*/ )
+{
+ CopyToClipboard( m_url_at_pos );
+ m_url_at_pos = _T("");
+}
+
+void ChatPanel::OnChanOpts( wxCommandEvent& /*unused*/ )
+{
+ CreatePopup();
+ if ( (m_chan_opts_button == 0) || (m_popup_menu == 0)) return;
+ m_chan_opts_button->PopupMenu(m_popup_menu);
+}
+
+
+void ChatPanel::OnSay( wxCommandEvent& /*unused*/ )
+{
+ Say( m_say_text->GetValue() );
+ m_say_text->SetValue( _T( "" ) );
+}
+
+void ChatPanel::OnPaste( wxClipboardTextEvent& event )
+{
+ // Read some text
+ if (wxTheClipboard->Open())
+ {
+ wxTextDataObject data;
+ if ( wxTheClipboard->GetData( data ) )
+ {
+ wxString converted = data.GetText();
+ converted.Replace( _T("\r\n"), _T("\n") );
+ converted.Replace( _T("\r"), _T("\n") );
+ m_say_text->WriteText( converted );
+ }
+ else event.Skip();
+ }
+ else event.Skip();
+ wxTheClipboard->Close();
+
+
+}
+
+
+//! @brief Output a message said in the channel.
+//!
+//! @param who nick of the person who said something.
+//! @param message the message to be outputted.
+void ChatPanel::Said( const wxString& who, const wxString& message )
+{
+ wxString me = GetMe().GetNick();
+ wxColour col;
+ bool req_user = false;
+ if ( who.Upper() == me.Upper() )
+ {
+ col = sett().GetChatColorMine();
+ } else
+ {
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_say );
+ if ( m_type == CPT_User ) req_user = true;
+ //process logic for custom word highlights
+ if ( ContainsWordToHighlight( message ) )
+ {
+ req_user = sett().GetRequestAttOnHighlight();
+ col = sett().GetChatColorHighlight();
+ }
+ else
+ col = sett().GetChatColorNormal();
+ }
+
+ if ( ( who == _T( "MelBot" ) || who == _T( "[BOT]tizbacbridgebot" ) )
+ && message.StartsWith( _T( "<" ) ) && message.Contains( _T( ">" ) ) )
+ {
+ wxString who2;
+ wxString message2;
+ who2 = message.BeforeFirst( '>' ).AfterFirst( '<' );
+ if ( who != _T( "[BOT]tizbacbridgebot" ) ) who2 += _T( "@IRC" );
+ //don't highlight if i'm talking from irc to channel
+ if ( who2.Upper().BeforeLast(_T('@')) == me.Upper() )
+ {
+ req_user = false;
+ col = sett().GetChatColorNormal();
+ }
+ message2 = message.AfterFirst( '>' );
+ OutputLine( _T( " <" ) + who2 + _T( "> " ) + message2, col, sett().GetChatFont() );
+ } else {
+ OutputLine( _T( " <" ) + who + _T( "> " ) + message, col, sett().GetChatFont() );
+ }
+
+
+ if ( req_user ) {
+ m_ui.mw().RequestUserAttention();
+ #ifndef DISABLE_SOUND
+ if ( sett().GetChatPMSoundNotificationEnabled() && ( m_ui.GetActiveChatPanel() != this || !wxTheApp->IsActive() ) )
+ sound().pm();
+ #endif
+ }
+}
+
+
+bool ChatPanel::ContainsWordToHighlight( const wxString& message ) const
+{
+ //get list of words to highlight
+ wxArrayString words = sett().GetHighlightedWords();
+ for ( unsigned int i = 0; i < words.GetCount(); i++ )
+ {
+ if ( message.Contains( words[i] ) )
+ return true;
+ }
+ return false;
+
+}
+
+
+void ChatPanel::DidAction( const wxString& who, const wxString& action )
+{
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_say );
+ OutputLine( _T( " * " ) + who + _T( " " ) + action, sett().GetChatColorAction(), sett().GetChatFont() );
+}
+
+
+//! @brief Output motd sent by server
+//!
+//! @param message The MOTD message to output
+void ChatPanel::Motd( const wxString& message )
+{
+ wxFont f = m_chatlog_text->GetFont();
+ f.SetFamily( wxFONTFAMILY_MODERN );
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_say );
+ OutputLine( _T( " ** motd ** " ) + message, sett().GetChatColorServer(), f );
+}
+
+
+void ChatPanel::StatusMessage( const wxString& message )
+{
+ if ( m_chatlog_text == 0 ) {
+ wxLogMessage( _T( "m_chatlog_text is NULL" ) );
+ } else {
+ wxFont f = m_chatlog_text->GetFont();
+ f.SetFamily( wxFONTFAMILY_MODERN );
+ if( CPT_Server == m_type ) SetIconHighlight( highlight_important );
+ OutputLine( _T( " ** Server ** " ) + message, sett().GetChatColorServer(), f );
+ }
+}
+
+
+void ChatPanel::ClientMessage( const wxString& message )
+{
+ wxFont f = m_chatlog_text->GetFont();
+ f.SetFamily( wxFONTFAMILY_MODERN );
+ OutputLine( _T( " ** " ) + message, sett().GetChatColorClient(), f );
+}
+
+
+void ChatPanel::UnknownCommand( const wxString& command, const wxString& params )
+{
+ wxFont f = m_chatlog_text->GetFont();
+ f.SetFamily( wxFONTFAMILY_MODERN );
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_important );
+ OutputLine( _( " !! Command: \"" ) + command + _( "\" params: \"" ) + params + _T( "\"." ), sett().GetChatColorError(), f );
+}
+
+
+wxString ChatPanel::GetChatTypeStr() const
+{
+ if ( m_type == CPT_Channel ) return _( "channel" );
+ else if ( m_type == CPT_Battle ) return _( "battle" );
+ else if ( m_type == CPT_Server ) return _( "server" );
+
+ return _T( "ROOMTYPE FIXME" );
+}
+
+
+void ChatPanel::Joined( User& who )
+{
+ if ( m_type == CPT_Channel ) {
+ if ( sett().GetDisplayJoinLeave( m_channel->GetName() ) ) {
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_join_leave );
+ OutputLine( _T( " ** " ) + who.GetNick() + _( " joined the " ) + GetChatTypeStr() + _T( "." ), sett().GetChatColorJoinPart(), sett().GetChatFont() );
+ }
+ if ( m_show_nick_list && ( m_nicklist != 0 ) )
+ {
+ m_usercount_label->SetLabel( wxString::Format( _("%d users"), GetChannel()->GetNumUsers() ) );
+ m_nicklist->AddUser( who );
+ }
+ } else if ( m_type == CPT_Battle ) {
+ if ( sett().GetDisplayJoinLeave( _T( "game/battle" ) ) ) { OutputLine( _T( " ** " ) + who.GetNick() + _( " joined the " ) + GetChatTypeStr() + _T( "." ), sett().GetChatColorJoinPart(), sett().GetChatFont() ); }
+ }
+
+ // Also add the User to the TextCompletionDatabase
+ textcompletiondatabase.Insert_Mapping( who.GetNick(), who.GetNick() );
+}
+
+
+void ChatPanel::OnChannelJoin( User& who )
+{
+ if ( m_type == CPT_Channel && m_show_nick_list && (m_nicklist != 0) )
+ {
+ m_usercount_label->SetLabel( wxString::Format( _("%d users"), GetChannel()->GetNumUsers() ) );
+ m_nicklist->AddUser( who );
+ }
+
+ // Also add the User to the TextCompletionDatabase
+ textcompletiondatabase.Insert_Mapping( who.GetNick(), who.GetNick() );
+}
+
+
+void ChatPanel::Parted( User& who, const wxString& message )
+{
+ if ( m_type == CPT_Channel ) {
+ if ( m_channel == 0 ) return;
+ if ( &who == &m_channel->GetMe() ) {
+ m_channel->uidata.panel = 0;
+ SetChannel( 0 );
+ return;
+ }
+ if ( sett().GetDisplayJoinLeave( m_channel->GetName() ) ) {
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_join_leave );
+ OutputLine( _T( " ** " ) + who.GetNick() + _( " left the " ) + GetChatTypeStr() + _T( "( " ) + message + _T( " )." ), sett().GetChatColorJoinPart(), sett().GetChatFont() );
+ }
+ if ( m_show_nick_list && ( m_nicklist != 0 ) )
+ {
+ m_usercount_label->SetLabel( wxString::Format( _("%d users"), GetChannel()->GetNumUsers() ) );
+ m_nicklist->RemoveUser( who );
+ }
+
+ } else if ( m_type == CPT_Battle ) {
+ if ( sett().GetDisplayJoinLeave( _T( "game/battle" ) ) ) { OutputLine( _T( " ** " ) + who.GetNick() + _( " left the " ) + GetChatTypeStr() + _T( "( " ) + message + _T( " )." ), sett().GetChatColorJoinPart(), sett().GetChatFont() ); }
+ }
+
+ // Also remove the User from the TextCompletionDatabase
+ textcompletiondatabase.Delete_Mapping( who.GetNick() );
+}
+
+
+void ChatPanel::SetTopic( const wxString& who, const wxString& message )
+{
+ /*
+ int pos = refined.Find( _T("\\n") ); // serch for the \n string
+ while ( pos != -1 )
+ {
+ if ( refined.Mid( pos - 1, 3 ) == _T("\\\n") ) continue; // the string \\n means escaped \n
+ refined = refined.Left ( pos -1 ) + _T("\n") + refined.Right( pos +1 ); // replace the /n string with the carriage return char
+ pos = refined.Find( _T("\\n") );
+ }
+ */
+ wxFont f = m_chatlog_text->GetFont();
+ f.SetFamily( wxFONTFAMILY_MODERN );
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_say );
+ OutputLine( _( " ** Channel topic:" ), sett().GetChatColorServer(), f );
+ wxStringTokenizer tkz( message, _T("\n") );
+ while ( tkz.HasMoreTokens() )
+ {
+ wxString msg = tkz.GetNextToken().Strip();
+ OutputLine( _T(" ") + msg, sett().GetChatColorServer(), f );
+ }
+ OutputLine( _( " ** Set by " ) + who, sett().GetChatColorServer(), f );
+}
+
+
+void ChatPanel::UserStatusUpdated( User& who )
+{
+ if ( !m_show_nick_list || ( m_nicklist == 0 ) ) return;
+ try
+ {
+ m_nicklist->UserUpdated( who );
+ } catch (...) { return; }
+}
+
+
+const Channel* ChatPanel::GetChannel() const
+{
+ return m_channel;
+}
+
+
+void ChatPanel::SetChannel( Channel* chan )
+{
+ ASSERT_LOGIC( this, _T( "this==null" ) );
+ ASSERT_LOGIC( m_type == CPT_Channel, _T( "Not of type channel" ) );
+
+ if (( chan == 0 ) && ( m_channel != 0 ) ) {
+ // causes weird crash.
+ StatusMessage( _( "Chat closed." ) );
+
+ m_channel->uidata.panel = 0;
+ if ( m_show_nick_list && (m_nicklist != 0) ) {
+ m_nicklist->ClearUsers();
+ }
+ }
+
+ if ( chan != 0 ) {
+ chan->uidata.panel = this;
+// m_chat_log.SetTarget( sett().GetDefaultServer(), chan->GetName() );
+ }
+ m_channel = chan;
+}
+
+const Server* ChatPanel::GetServer() const
+{
+ return m_server;
+}
+
+
+void ChatPanel::SetServer( Server* serv )
+{
+ ASSERT_LOGIC( m_type == CPT_Server, _T( "Not of type server" ) );
+ if (( serv == 0 ) && ( m_server != 0 ) ){
+ StatusMessage( _( "Chat closed." ) );
+ m_server->uidata.panel = 0;
+ }
+ else if ( serv != 0 ){
+ serv->uidata.panel = this;
+ }
+ m_server = serv;
+
+// if ( m_server ){
+// m_chat_log.SetTarget( sett().GetDefaultServer(), _( "_SERVER" ) );
+// }
+}
+
+
+const User* ChatPanel::GetUser() const
+{
+ return m_user;
+}
+
+
+void ChatPanel::SetUser( const User* usr )
+{
+ ASSERT_LOGIC( m_type == CPT_User, _T( "Not of type user" ) );
+
+ if (( usr == 0 ) && ( m_user != 0 ) )
+ {
+ StatusMessage( _( "Chat closed." ) );
+ m_user->uidata.panel = 0;
+ }
+ else if ( usr != 0 ) usr->uidata.panel = this;
+
+ m_user = usr;
+
+// if ( m_user )
+// m_chat_log.SetTarget( sett().GetDefaultServer(), usr->GetNick() );
+}
+
+
+bool ChatPanel::IsServerPanel() const
+{
+ return ( m_type == CPT_Server );
+}
+
+
+int ChatPanel::GetPanelType() const
+{
+ return m_type;
+}
+
+
+//! @brief Set the Channel object
+//!
+//! @param channel the Channel object.
+void ChatPanel::_SetChannel( Channel* channel )
+{
+ if ( m_channel != 0 ) {
+ m_channel->uidata.panel = 0;
+ }
+
+ m_channel = channel;
+
+ if ( m_channel != 0 ) {
+ m_channel->uidata.panel = this;
+ }
+
+}
+
+
+void ChatPanel::Say( const wxString& message )
+{
+ wxLogDebugFunc( message );
+ wxStringTokenizer lines( message, _T( '\n' ) );
+ if ( lines.CountTokens() > 5 ) {
+ int answer = customMessageBox ( SL_MAIN_ICON, wxString::Format( _( "Are you sure you want to paste %d lines?" ), lines.CountTokens() ), _( "Flood warning" ), wxYES_NO );
+ if ( answer == wxNO ) return;
+ }
+ while ( lines.HasMoreTokens() ) {
+ wxString line = lines.GetNextToken();
+ wxLogMessage( _T( "line: %s" ), line.c_str() );
+
+ if ( line.Find( '/' ) == 0 ) {
+ if ( m_ui.ExecuteSayCommand( line ) ) return;
+ }
+
+ if ( line == _T( "/ver" ) ) {
+ OutputLine( _( " You have SpringLobby v" ) + GetSpringLobbyVersion(), sett().GetChatColorNormal() , sett().GetChatFont() );
+ return;
+ }
+
+ if ( line == _T( "/clear" ) ) {
+ wxCommandEvent dummy;
+ ClearContents( dummy );
+ return;
+ }
+
+ if ( m_type == CPT_Channel ) {
+
+ if ( m_channel == 0 ) {
+ OutputLine( _( " You are not in channel or channel does not exist." ), sett().GetChatColorError(), sett().GetChatFont() );
+ return;
+ }
+ if ( line.StartsWith( _T( "/" ) ) ) {
+ if ( m_channel->ExecuteSayCommand( line ) ) return;
+ if ( m_channel->GetServer().ExecuteSayCommand( line ) ) return;
+ OutputLine( wxString::Format( _( " Error: Command (%s) does not exist, use /help for a list of available commands." ), line.c_str() ), sett().GetChatColorError(), sett().GetChatFont() );
+ return;
+ }
+ m_channel->Say( line );
+
+ } else if ( m_type == CPT_Battle ) {
+
+ if ( m_battle == 0 ) {
+ OutputLine( _( " You are not in battle or battle does not exist, use /help for a list of available commands." ), sett().GetChatColorError(), sett().GetChatFont() );
+ return;
+ }
+ if ( line.StartsWith( _T( "/" ) ) ) {
+ if ( m_battle->ExecuteSayCommand( line ) ) return;
+ if ( m_battle->GetServer().ExecuteSayCommand( line ) ) return;
+ OutputLine( wxString::Format( _( " Error: Command (%s) does not exist, use /help for a list of available commands." ), line.c_str() ), sett().GetChatColorError(), sett().GetChatFont() );
+ return;
+ }
+ m_battle->Say( line );
+
+ } else if ( m_type == CPT_User ) {
+
+ if ( m_user == 0 ) {
+ OutputLine( _( " User is offline." ), sett().GetChatColorError(), sett().GetChatFont() );
+ return;
+ }
+ if ( line.StartsWith( _T( "/" ) ) ) {
+ if ( m_user->ExecuteSayCommand( line ) ) return;
+ if ( m_user->GetServer().ExecuteSayCommand( line ) ) return;
+ OutputLine( wxString::Format( _( " Error: Command (%s) does not exist, use /help for a list of available commands." ), line.c_str() ), sett().GetChatColorError(), sett().GetChatFont() );
+ return;
+ }
+ m_user->Say( line );
+
+ } else if ( m_type == CPT_Server ) {
+ if ( m_server == 0 ) return;
+
+ if ( line.StartsWith( _T( "/" ) ) ) {
+ if ( m_server->ExecuteSayCommand( line ) ) return;
+ OutputLine( wxString::Format( _( " Error: Command (%s) does not exist, use /help for a list of available commands." ), line.c_str() ), sett().GetChatColorError(), sett().GetChatFont() );
+ return;
+ }
+
+ //we need to disable the channel tab if leaving manually
+ if (line.Upper().StartsWith( _T( "LEAVE" ) ) )
+ {
+ wxString channame = line.AfterFirst(' ').BeforeFirst(' ');
+ try
+ {
+ Channel& chan = m_server->GetChannel( channame );
+ chan.Leave();
+ chan.uidata.panel = 0;
+ }
+ catch( assert_exception ) {}
+ }
+
+ m_server->SendRaw( line );
+ OutputLine( _( " Sent: \"" ) + line + _( "\"" ), sett().GetChatColorNormal(), sett().GetChatFont() );
+ }
+
+ }
+}
+
+
+void ChatPanel::Part()
+{
+ wxLogDebugFunc( _T( "" ) );
+ if ( m_type == CPT_Channel )
+ {
+ if ( m_channel == 0 ) return;
+ m_channel->Leave();
+ m_channel->uidata.panel = 0;
+ }
+}
+
+
+bool ChatPanel::IsOk() const
+{
+ if ( m_type == CPT_Channel ) return ( m_channel != 0 );
+ if ( m_type == CPT_Server ) return ( m_server != 0 );
+ if ( m_type == CPT_User ) return ( m_user != 0 );
+ if ( m_type == CPT_Battle ) return ( m_battle != 0 );
+ return false;
+}
+
+
+
+void ChatPanel::OnUserDisconnected()
+{
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_join_leave );
+ OutputLine( _T( " ** User is now offline." ), sett().GetChatColorJoinPart(), sett().GetChatFont() );
+}
+
+
+void ChatPanel::OnUserConnected()
+{
+ // change the image of the tab to show new events
+ SetIconHighlight( highlight_join_leave );
+ OutputLine( _T( " ** User just got online." ), sett().GetChatColorJoinPart(), sett().GetChatFont() );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// Menu Events
+//////////////////////////////////////////////////////////////////////////////////////
+
+
+
+void ChatPanel::OnChannelMenuLeave( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ Part();
+ SetChannel( 0 );
+}
+
+
+void ChatPanel::OnChannelMenuDisplayJoinLeave( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !displayjoinitem->IsChecked() ) {
+ sett().SetDisplayJoinLeave( false, m_channel->GetName() );
+ displayjoinitem->Check( false );
+ } else {
+ sett().SetDisplayJoinLeave( true, m_channel->GetName() );
+ displayjoinitem->Check( true );
+ }
+}
+
+
+void ChatPanel::OnChannelAutoJoin( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( m_autorejoin == 0 ) return;
+
+ if ( m_autorejoin->IsChecked() ) {
+ sett().AddChannelJoin( m_channel->GetName(), m_channel->GetPassword() );
+ m_autorejoin->Check( true );
+ } else {
+ sett().RemoveChannelJoin( m_channel->GetName() );
+ m_autorejoin->Check( false );
+ }
+}
+
+
+void ChatPanel::OnChannelMenuInfo( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ cs.Say( _T( "!INFO #" ) + m_channel->GetName() );
+ //INFO /<channame>/
+}
+
+
+void ChatPanel::OnChannelMenuTopic( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ wxString topic = m_channel->GetTopic();
+ if ( !m_ui.AskText( _( "Set topic..." ), _( "What should be the new topic?" ), topic, wxOK | wxCANCEL | wxCENTRE | wxTE_MULTILINE ) ) return;
+ topic.Replace( _T("\n"), _T("\\n") );
+ cs.Say( _T( "!TOPIC #" ) + m_channel->GetName() + _T( " " ) + topic );
+ //TOPIC /<channame>/ {topic}
+}
+
+
+void ChatPanel::OnChannelMenuMessage( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ wxString text;
+if ( !m_ui.AskText( _( "Channel message..." ), _( "Message:" ), text ) ) return;
+
+ cs.Say( _T( "!CHANMSG #" ) + m_channel->GetName() + _T( " " ) + text );
+ //CHANMSG /<channame>/ {message}
+}
+
+
+void ChatPanel::OnChannelMenuLock( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ wxString text;
+ if ( !m_ui.AskText( _( "Lock channel..." ), _( "What should the new password be?" ), text ) ) return;
+
+ cs.Say( _T( "!LOCK #" ) + m_channel->GetName() + _T( " " ) + text );
+ //LOCK /<channame>/ <key>
+}
+
+
+void ChatPanel::OnChannelMenuUnlock( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ if ( !m_ui.Ask( _( "Unlock Channel" ), _( "Are you sure you want to unlock this channel?" ) ) ) return;
+
+ cs.Say( _T( "!UNLOCK #" ) + m_channel->GetName() );
+ //UNLOCK /<channame>/
+}
+
+
+void ChatPanel::OnChannelMenuRegister( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->GetServer().UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not on this server." ) );
+ return;
+ }
+ User& cs = m_channel->GetServer().GetUser( _T( "ChanServ" ) );
+
+ wxString text = m_channel->GetMe().GetNick();
+ if ( !m_ui.AskText( _( "Register Channel" ), _( "Who should be appointed founder of this channel?" ), text ) ) return;
+
+ cs.Say( _T( "!REGISTER #" ) + m_channel->GetName() + _T( " " ) + text );
+ //REGISTER <channame> <founder>
+}
+
+
+void ChatPanel::OnChannelMenuUnregister( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->GetServer().UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not on this server." ) );
+ return;
+ }
+ User& cs = m_channel->GetServer().GetUser( _T( "ChanServ" ) );
+
+ if ( !m_ui.Ask( _( "Unregister Channel" ), _( "Are you sure you want to unregister this channel?" ) ) ) return;
+
+ cs.Say( _T( "!UNREGISTER #" ) + m_channel->GetName() );
+ //UNREGISTER <channame>
+}
+
+
+void ChatPanel::OnChannelMenuSpamOn( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ cs.Say( _T( "!SPAMPROTECTION #" ) + m_channel->GetName() + _T( " on" ) );
+ //SPAMPROTECTION /<channame>/ <on|off>
+}
+
+
+void ChatPanel::OnChannelMenuSpanOff( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ cs.Say( _T( "!SPAMPROTECTION #" ) + m_channel->GetName() + _T( " off" ) );
+ //SPAMPROTECTION /<channame>/ <on|off>
+}
+
+
+void ChatPanel::OnChannelMenuSpamIsOn( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ cs.Say( _T( "!SPAMPROTECTION #" ) + m_channel->GetName() );
+ //SPAMPROTECTION /<channame>/
+}
+
+
+void ChatPanel::OnServerMenuDisconnect( wxCommandEvent& /*unused*/ )
+{
+ m_ui.Disconnect();
+}
+
+
+void ChatPanel::OnServerMenuReconnect( wxCommandEvent& /*unused*/ )
+{
+ m_ui.Reconnect();
+}
+
+
+void ChatPanel::OnServerMenuRemove( wxCommandEvent& /*unused*/ )
+{
+ wxString user;
+ if ( !m_ui.AskText( _( "Remove User Acount" ), _( "What user account do you want to remove today?" ), user ) ) return;
+ if ( !m_ui.Ask( _( "Remove Account" ), _( "Are you sure you want to remove the account " ) + user + _T( "?" ) ) ) return;
+ Say( _T( "removeaccount " ) + user );
+}
+
+
+void ChatPanel::OnServerMenuChangePassword( wxCommandEvent& /*unused*/ )
+{
+ wxString user, password;
+ if ( !m_ui.AskText( _( "Change User Acount Password" ), _( "What user account do you want to change the password for?" ), user ) ) return;
+ if ( !m_ui.AskPassword( _( "Change User Acount Password" ), _( "What would be the new password?" ), password ) ) return;
+ Say( _T( "changeaccountpass " ) + user + _T( " " ) + password );
+}
+
+
+void ChatPanel::OnServerMenuSetAccess( wxCommandEvent& /*unused*/ )
+{
+ m_ui.ShowMessage( _( "Error" ), _( "Not Implemented" ) );
+}
+
+
+void ChatPanel::OnServerMenuBroadcast( wxCommandEvent& /*unused*/ )
+{
+ wxString msg;
+ if ( !m_ui.AskText( _( "Broadcast Message" ), _( "Message to be broadcasted:" ), msg ) ) return;
+ Say( _T( "broadcast " ) + msg );
+}
+
+
+void ChatPanel::OnUserMenuOpenChat( wxCommandEvent& /*unused*/ )
+{
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+
+ m_ui.mw().OpenPrivateChat( *user );
+}
+
+
+void ChatPanel::OnUserMenuJoinSame( wxCommandEvent& /*unused*/ )
+{
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+ Battle* battle = user->GetBattle();
+ if ( battle == 0 ) return;
+
+ if ( !usync().ModExists( battle->GetHostModName() ) ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "You don't have the mod " ) + battle->GetHostModName()
+ + _( " . Please download it first" ), _( "Mod unavailable" ) );
+ return;
+ }
+
+ wxString password;
+ if ( battle->IsPassworded() ) {
+ if ( !m_ui.AskPassword( _( "Battle password" ), _( "This battle is password protected, enter the password." ), password ) ) return;
+ }
+ battle->Join( password );
+}
+
+
+void ChatPanel::OnUserMenuSlap( wxCommandEvent& /*unused*/ )
+{
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+
+ if ( m_type == CPT_Channel ) {
+ if ( m_channel == 0 ) return;
+ m_channel->DoAction( _T( "Slaps " ) + user->GetNick() + _T( " around with a large PeeWee!" ) );
+ } else if ( m_type == CPT_User ) {
+ if ( m_user == 0 ) return;
+ m_user->DoAction( _T( "slaps " ) + user->GetNick() + _T( " around with a large PeeWee!" ) );
+ }
+}
+
+
+void ChatPanel::OnUserMenuMute( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+
+ wxString mutetime = _T( "5" );
+ if ( !m_ui.AskText( _( "Mute User" ), _( "For how many minutes should the user be muted?" ), mutetime ) ) return;
+
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+
+ cs.Say( _T( "!MUTE #" ) + m_channel->GetName() + _T( " " ) + user->GetNick() + _T( " " ) + mutetime );
+ //MUTE /<channame>/ <username> [<duration>]
+
+}
+
+
+void ChatPanel::OnUserMenuUnmute( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+
+ cs.Say( _T( "!UNMUTE #" ) + m_channel->GetName() + _T( " " ) + user->GetNick() );
+ //UNMUTE /<channame>/ <username>
+}
+
+
+void ChatPanel::OnUserMenuKick( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+
+ wxString msg;
+ if ( !m_ui.AskText( _( "Kick User" ), _( "Reason:" ), msg ) ) return;
+
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ if ( msg != wxEmptyString ) msg = _T( " " ) + msg;
+ cs.Say( _T( "!KICK #" ) + m_channel->GetName() + _T( " " ) + user->GetNick() + msg );
+ //KICK /<channame>/ <username> [{reason}]
+}
+
+
+void ChatPanel::OnUserMenuOp( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ cs.Say( _T( "!OP #" ) + m_channel->GetName() + _T( " " ) + user->GetNick() );
+ //OP /<channame>/ <username>
+}
+
+
+void ChatPanel::OnUserMenuDeop( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel == 0 ) return;
+ if ( !m_channel->UserExists( _T( "ChanServ" ) ) ) {
+ m_ui.ShowMessage( _( "ChanServ error" ), _( "ChanServ is not in this channel." ) );
+ return;
+ }
+
+ const User* user = GetSelectedUser();
+ if ( user == 0 ) return;
+ User& cs = m_channel->GetUser( _T( "ChanServ" ) );
+
+ cs.Say( _T( "!DEOP #" ) + m_channel->GetName() + _T( " " ) + user->GetNick() );
+ //DEOP /<channame>/ <username>
+}
+
+
+void ChatPanel::OnUserMenuModeratorIngame( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().RequestInGameTime( GetSelectedUser()->GetNick() );
+}
+
+
+void ChatPanel::OnUserMenuModeratorCurrentIP( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().ModeratorGetIP( GetSelectedUser()->GetNick() );
+}
+
+
+void ChatPanel::OnUserMenuModeratorKick( wxCommandEvent& /*unused*/ )
+{
+ wxString reason;
+ if ( !m_ui.AskText( _( "Kick user" ), _( "Reason:" ), reason ) ) return;
+ m_ui.GetServer().ModeratorKick( GetSelectedUser()->GetNick(), reason );
+}
+
+
+void ChatPanel::OnUserMenuModeratorBan( wxCommandEvent& /*unused*/ )
+{
+ m_ui.ShowMessage( _( "Error" ), _( "Not Implemented" ) );
+}
+
+
+void ChatPanel::OnUserMenuModeratorUnban( wxCommandEvent& /*unused*/ )
+{
+ m_ui.ShowMessage( _( "Error" ), _( "Not Implemented" ) );
+}
+
+
+void ChatPanel::OnUserMenuModeratorMute( wxCommandEvent& /*unused*/ )
+{
+ wxString duration;
+ if ( !m_ui.AskText( _( "Mute user" ), _( "Duration:" ), duration ) ) return;
+ long int dur = 0;
+ duration.ToLong( &dur, dur );
+ m_ui.GetServer().ModeratorMute( m_channel->GetName(), GetSelectedUser()->GetNick(), ( int ) dur, true );
+}
+
+
+void ChatPanel::OnUserMenuModeratorMute5( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().ModeratorMute( m_channel->GetName(), GetSelectedUser()->GetNick(), 5, true );
+}
+
+
+void ChatPanel::OnUserMenuModeratorMute10( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().ModeratorMute( m_channel->GetName(), GetSelectedUser()->GetNick(), 10, true );
+}
+
+
+void ChatPanel::OnUserMenuModeratorMute30( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().ModeratorMute( m_channel->GetName(), GetSelectedUser()->GetNick(), 30, true );
+}
+
+
+void ChatPanel::OnUserMenuModeratorMute120( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().ModeratorMute( m_channel->GetName(), GetSelectedUser()->GetNick(), 120, true );
+}
+
+
+void ChatPanel::OnUserMenuModeratorMute1440( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().ModeratorMute( m_channel->GetName(), GetSelectedUser()->GetNick(), 1440, true );
+}
+
+
+
+void ChatPanel::OnUserMenuModeratorUnmute( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().ModeratorUnmute( m_channel->GetName(), GetSelectedUser()->GetNick() );
+}
+
+
+void ChatPanel::OnUserMenuModeratorRing( wxCommandEvent& /*unused*/ )
+{
+ m_ui.GetServer().Ring( GetSelectedUser()->GetNick() );
+}
+
+void ChatPanel::FocusInputBox()
+{
+ m_say_text->SetFocus();
+}
+
+
+void ChatPanel::OnUserMenuAddToGroup( wxCommandEvent& event )
+{
+ int id = event.GetId() - GROUP_ID;
+ wxString groupname = m_usermenu->GetGroupByEvtID(id);
+ const User* user = GetSelectedUser();
+ if ( user )
+ useractions().AddUserToGroup( groupname, user->GetNick() );
+}
+
+
+void ChatPanel::OnUserMenuDeleteFromGroup( wxCommandEvent& /*unused*/ )
+{
+ const User* user = GetSelectedUser();
+ if ( user )
+ useractions().RemoveUser( user->GetNick() );
+}
+
+
+void ChatPanel::OnUserMenuCreateGroup( wxCommandEvent& /*unused*/ )
+{
+ wxString name;
+ if ( ui().AskText( _("Enter name"),
+ _("Please enter the name for the new group.\nAfter clicking ok you will be taken to adjust its settings."), name ) )
+ {
+ const User* user = GetSelectedUser();
+ if ( user ) {
+ useractions().AddGroup( name );
+ useractions().AddUserToGroup( name, user->GetNick() );
+ ui().mw().ShowConfigure( MainWindow::OPT_PAGE_GROUPS );
+ }
+ else
+ customMessageBoxNoModal( SL_MAIN_ICON, _("couldn't add user"), _("Error") );
+ }
+}
+
+wxString ChatPanel::FindUrl( const long pos ) const
+{
+ long last = m_chatlog_text->GetLastPosition();
+
+ long start = pos;
+ while ( start > 0 && m_chatlog_text->GetRange( start-1, start ) != _T(" ") )
+ start--;
+
+ long end = pos;
+ //the last bit prevents topic links from being copied with next line's timestamp appended
+ //checking for newline isn't possible, cause links may well span multiple lines
+ while ( end < last && m_chatlog_text->GetRange( end, end+1 ) != _T(" ") && m_chatlog_text->GetRange( end, end+1 ) != _T("[") )
+ end++;
+
+ wxString ret = m_chatlog_text->GetRange( start, end );
+ if ( ret.StartsWith( _T("http://") ) )
+ return ret;
+ else
+ return _T("");
+}
+
+void ChatPanel::OnMouseDown( wxMouseEvent& event )
+{
+ wxLogDebugFunc( _T( "" ) );
+ wxTextCoord row;
+ wxTextCoord col;
+ wxTextCtrlHitTestResult ht = m_chatlog_text->HitTest( event.GetPosition(), &col, &row);
+ if ( ht != wxTE_HT_UNKNOWN ) {
+ long pos = m_chatlog_text->XYToPosition( col, row );
+ m_url_at_pos = FindUrl( pos );
+ }
+ CreatePopup();
+ if ( m_popup_menu != 0 ) PopupMenu( m_popup_menu );
+ else event.Skip();
+}
+
+
+void ChatPanel::OnMenuToggleAppend( wxCommandEvent& /*unused*/ )
+{
+ m_disable_append = m_append_menu->IsChecked();
+ if ( !m_disable_append )
+ {
+ for ( std::vector<ChatLine>::iterator iter = m_buffer.begin(); iter < m_buffer.end() ; iter++ ) OutputLine( *iter );
+ m_buffer.clear();
+ }
+}
+
+void ChatPanel::UpdateNicklistHighlights()
+{
+ if ( m_show_nick_list && (m_nicklist != 0) ) {
+ m_nicklist->RefreshVisibleItems();
+ }
+}
+
+
+void ChatPanel::SortNickList()
+{
+ if ( m_show_nick_list && (m_nicklist != 0 ) ) m_nicklist->SortList();
+}
+
+
+
+void ChatPanel::SetIconHighlight( HighlightType highlight )
+{
+ if ( m_ui.GetActiveChatPanel() != this && m_chat_tabs && !IsShownOnScreen() )
+ {
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount( ); ++i )
+ {
+ if ( m_chat_tabs->GetPage( i ) == this )//!TODO: return afterwards?
+ {
+ switch ( highlight )
+ {
+ case highlight_say :
+ {
+ if ( m_type == CPT_Channel && m_icon_index < 6 )
+ {
+ m_icon_index = 6;
+ m_chat_tabs->SetPageBitmap( i, m_imagelist->GetBitmap(m_icon_index));
+ }
+ else if ( m_type == CPT_User && m_icon_index < 7 )
+ {
+ m_icon_index = 7;
+ m_chat_tabs->SetPageBitmap( i, m_imagelist->GetBitmap(m_icon_index));
+ }
+ break;
+ }
+ case highlight_join_leave :
+ {
+ if ( m_type == CPT_Channel && m_icon_index < 4 )
+ {
+ m_icon_index = 4;
+ m_chat_tabs->SetPageBitmap( i, m_imagelist->GetBitmap(m_icon_index));
+ }
+ else if ( m_type == CPT_User && m_icon_index < 5 )
+ {
+ m_icon_index = 5;
+ m_chat_tabs->SetPageBitmap( i, m_imagelist->GetBitmap(m_icon_index));
+ }
+ break;
+ }
+ case highlight_important :
+ {
+ if ( m_type == CPT_Channel && m_icon_index < 8 )
+ {
+ m_icon_index = 8;
+ m_chat_tabs->SetPageBitmap( i, m_imagelist->GetBitmap(m_icon_index));
+ }
+ else if ( m_type == CPT_User && m_icon_index < 9 )
+ {
+ m_icon_index = 9;
+ m_chat_tabs->SetPageBitmap( i, m_imagelist->GetBitmap(m_icon_index));
+ }
+ else if ( m_type == CPT_Server && m_icon_index < 10 )
+ {
+ m_icon_index = 10;
+ m_chat_tabs->SetPageBitmap( i, m_imagelist->GetBitmap(m_icon_index));
+ }
+ break;
+ }
+ default: break;
+ }
+ }
+ }
+ }
+}
+
+void ChatPanel::OnChannelMenuShowMutelist( wxCommandEvent& /*unused*/ )
+{
+ if ( m_channel && ( m_type == CPT_Channel ) ) {
+ m_channel->GetServer().SendRaw( _T("MUTELIST ") + m_channel->GetName() );
+ }
+}
+
+void ChatPanel::ClearContents( wxCommandEvent& /*unused*/ )
+{
+ m_chatlog_text->SetValue( _T("") );
+}
+
+void ChatPanel::OnChatMenuOpenLog( wxCommandEvent& event )
+{
+ m_chat_log.OpenInEditor();
+}
diff --git a/src/chatpanel.h b/src/chatpanel.h
new file mode 100644
index 0000000..5e0f1b5
--- /dev/null
+++ b/src/chatpanel.h
@@ -0,0 +1,340 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CHATPANEL_H
+#define SPRINGLOBBY_HEADERGUARD_CHATPANEL_H
+
+#include <wx/panel.h>
+#include <wx/textctrl.h>
+#include <vector>
+
+#include "usermenu.h"
+#include "chatlog.h"
+#include "Helper/TextCompletionDatabase.hpp"
+
+class wxCommandEvent;
+class wxSizeEvent;
+class wxBoxSizer;
+class wxSplitterWindow;
+class wxTextCtrl;
+class wxTextCtrlHist;
+class wxTextUrlEvent;
+class wxComboBox;
+class wxButton;
+class wxBitmapButton;
+class NickListCtrl;
+class Channel;
+class User;
+class ChatLog;
+class Server;
+class Battle;
+class Ui;
+class wxStaticText;
+
+class wxMouseEvent;
+class SLNotebook;
+class wxNotebook;
+class wxImageList;
+
+enum ChatPanelType {
+ CPT_Channel,
+ CPT_Server,
+ CPT_User,
+ CPT_Battle
+};
+
+enum HighlightType
+{
+ highlight_say,
+ highlight_join_leave,
+ highlight_important
+};
+
+struct ChatLine
+{
+ wxString chat;
+ wxString time;
+ wxTextAttr timestyle;
+ wxTextAttr chatstyle;
+};
+
+/*! @brief wxPanel that contains a chat.
+ *
+ * This panel contains a chat with a multiline TextCtrl for the messages, a
+ * signle line TextCtrl for messages to send, a send button and a nick list.
+ *
+ * The nick list is optional and can be removed by setting show_nick_list in the
+ * constructor to false.
+ */
+class ChatPanel : public wxPanel
+{
+ public:
+
+ ChatPanel( wxWindow* parent, Ui& ui, Channel& chan, wxImageList* imaglist );
+ ChatPanel( wxWindow* parent, Ui& ui, const User& user, wxImageList* imaglist );
+ ChatPanel( wxWindow* parent, Ui& ui, Server& serv, wxImageList* imaglist );
+ ChatPanel( wxWindow* parent, Ui& ui, Battle& battle );
+ ~ChatPanel();
+
+ void Said( const wxString& who, const wxString& message );
+ void DidAction( const wxString& who, const wxString& action );
+ void Motd( const wxString& message );
+ void StatusMessage( const wxString& message );
+ void ClientMessage( const wxString& message );
+
+ void UnknownCommand( const wxString& command, const wxString& params );
+
+ void Joined( User& who );
+ void Parted( User& who, const wxString& message );
+ void SetTopic( const wxString& who, const wxString& message );
+ void UserStatusUpdated( User& who );
+ void OnChannelJoin( User& who );
+
+ const Channel* GetChannel() const;
+ void SetChannel( Channel* chan );
+
+ const Server* GetServer() const;
+ void SetServer( Server* serv );
+
+ const User* GetUser() const ;
+ void SetUser( const User* usr );
+
+ bool IsServerPanel() const;
+ int GetPanelType() const;
+
+ void Say( const wxString& message );
+ void Part();
+ void FocusInputBox();
+
+ wxString GetChatTypeStr() const;
+
+ size_t GetIconIndex() const { return m_icon_index; }
+ void SetIconIndex( size_t index ) { m_icon_index = index; }
+
+ const User& GetMe() const;
+ const User* GetSelectedUser() const;
+
+ bool IsOk() const;
+
+ void OnUserDisconnected();
+ void OnUserConnected();
+
+ void OnChanOpts( wxCommandEvent& event );
+ void OnSay( wxCommandEvent& event );
+ void OnPaste( wxClipboardTextEvent& event );
+
+ void OnLinkEvent( wxTextUrlEvent& event );
+ void OnMouseDown( wxMouseEvent& event );
+
+ void OnMenuToggleAppend( wxCommandEvent& event );
+
+ void OnChannelMenuLeave( wxCommandEvent& event );
+ void OnChannelMenuDisplayJoinLeave( wxCommandEvent& event );
+ void OnChannelAutoJoin( wxCommandEvent& event );
+ void OnChannelMenuInfo( wxCommandEvent& event );
+ void OnChannelMenuTopic( wxCommandEvent& event );
+ void OnChannelMenuMessage( wxCommandEvent& event );
+ void OnChannelMenuLock( wxCommandEvent& event );
+ void OnChannelMenuUnlock( wxCommandEvent& event );
+ void OnChannelMenuRegister( wxCommandEvent& event );
+ void OnChannelMenuUnregister( wxCommandEvent& event );
+ void OnChannelMenuSpamOn( wxCommandEvent& event );
+ void OnChannelMenuSpanOff( wxCommandEvent& event );
+ void OnChannelMenuSpamIsOn( wxCommandEvent& event );
+ void OnChannelMenuShowMutelist( wxCommandEvent& event );
+
+ void OnServerMenuDisconnect( wxCommandEvent& event );
+ void OnServerMenuReconnect( wxCommandEvent& event );
+ void OnServerMenuRemove( wxCommandEvent& event );
+ void OnServerMenuChangePassword( wxCommandEvent& event );
+ void OnServerMenuSetAccess( wxCommandEvent& event );
+ void OnServerMenuBroadcast( wxCommandEvent& event );
+
+ void OnUserMenuOpenChat( wxCommandEvent& event );
+ void OnUserMenuJoinSame( wxCommandEvent& event );
+ void OnUserMenuSlap( wxCommandEvent& event );
+ void OnUserMenuMute( wxCommandEvent& event );
+ void OnUserMenuUnmute( wxCommandEvent& event );
+ void OnUserMenuKick( wxCommandEvent& event );
+ void OnUserMenuOp( wxCommandEvent& event );
+ void OnUserMenuDeop( wxCommandEvent& event );
+ void OnUserMenuModeratorIngame( wxCommandEvent& event );
+ void OnUserMenuModeratorCurrentIP( wxCommandEvent& event );
+ void OnUserMenuModeratorKick( wxCommandEvent& event );
+ void OnUserMenuModeratorBan( wxCommandEvent& event );
+ void OnUserMenuModeratorUnban( wxCommandEvent& event );
+ void OnUserMenuModeratorMute( wxCommandEvent& event );
+ void OnUserMenuModeratorMute5( wxCommandEvent& event );
+ void OnUserMenuModeratorMute10( wxCommandEvent& event );
+ void OnUserMenuModeratorMute30( wxCommandEvent& event );
+ void OnUserMenuModeratorMute120( wxCommandEvent& event );
+ void OnUserMenuModeratorMute1440( wxCommandEvent& event );
+ void OnUserMenuModeratorUnmute( wxCommandEvent& event );
+ void OnUserMenuModeratorRing( wxCommandEvent& event );
+
+ void OnUserMenuCopyLink( wxCommandEvent& event );
+
+ void OnChatMenuOpenLog( wxCommandEvent& event );
+
+ void OnKeyPressed( wxKeyEvent& keyevent );
+ void OnKeyReleased( wxKeyEvent& keyevent );
+
+ void OnUserMenuAddToGroup( wxCommandEvent& event );
+ void OnUserMenuDeleteFromGroup( wxCommandEvent& event );
+ void OnUserMenuCreateGroup( wxCommandEvent& event );
+ void UpdateNicklistHighlights();
+
+ void SortNickList();
+
+ void ClearContents( wxCommandEvent& event );
+
+ protected:
+
+ void _SetChannel( Channel* channel );
+ void OutputLine( const wxString& message, const wxColour& col, const wxFont& fon );
+ void OutputLine( const ChatLine& line );
+ void SetIconHighlight( HighlightType highlight );
+ wxString FindUrl( const long pos ) const ;
+
+ bool ContainsWordToHighlight( const wxString& message ) const;
+
+ bool m_show_nick_list; //!< If the nicklist should be shown or not.
+
+ wxBoxSizer* m_main_sizer; //!< Main sizer containing all other sizers.
+ wxBoxSizer* m_chat_sizer; //!< Sizer containing the chat messages, and send input and button.
+ wxBoxSizer* m_say_sizer; //!< Sizer containing send input and button.
+ wxBoxSizer* m_nick_sizer; //!< Sizer containing the nicklist.
+
+ wxSplitterWindow* m_splitter; //!< The splitter.
+ wxPanel* m_chat_panel; //!< Panel containing the chat. Only used when nicklist is visible.
+ wxPanel* m_nick_panel; //!< Panel containing the nicklist.
+
+ wxTextCtrl* m_chatlog_text; //!< The chat log textcontrol.
+ wxTextCtrlHist* m_say_text; //!< The say textcontrol.
+ wxBitmapButton* m_chan_opts_button; //!< The channel options button.
+
+ NickListCtrl* m_nicklist; //!< The nicklist.
+ wxComboBox* m_nick_filter; //!< The filter combo.
+
+ wxButton* m_say_button; //!< The say button.
+ SLNotebook* m_chat_tabs;
+ Ui& m_ui;
+ Channel* m_channel; //!< Channel object.
+ Server* m_server; //!< Server object.
+ const User* m_user; //!< User object.
+ Battle* m_battle; //!< User object.
+
+ wxStaticText* m_usercount_label;
+
+ int m_type; //!< Channel object.
+
+ wxString m_chan_pass;
+
+ wxMenu* m_popup_menu;
+ wxMenuItem* m_autorejoin;
+ wxMenuItem* m_append_menu;
+ ChatLog m_chat_log;
+ wxMenuItem* displayjoinitem;
+ typedef SL_GENERIC::UserMenu<ChatPanel> UserMenu;
+ UserMenu* m_usermenu;
+
+ void LogTime();
+ void CreateControls( );
+ void CreatePopup();
+
+ size_t m_icon_index;
+
+ wxImageList* m_imagelist;
+
+ UserMenu* CreateNickListMenu();
+
+
+ static const int m_groupMenu_baseID = 6798;
+ TextCompletionDatabase textcompletiondatabase;
+
+ std::vector<ChatLine> m_buffer;
+ bool m_disable_append;
+
+ wxString m_url_at_pos; //! the mouse event sink sets this
+
+ DECLARE_EVENT_TABLE();
+};
+
+enum
+{
+ CHAT_SEND = wxID_HIGHEST,
+ CHAT_TEXT,
+ CHAT_LOG,
+ CHAT_CHAN_OPTS,
+
+ CHAT_MENU_DISABLE_APPEND,
+
+ CHAT_MENU_CH_CLEAR,
+ CHAT_MENU_CH_LEAVE,
+ CHAT_MENU_CH_DISPLAYJOIN,
+ CHAT_MENU_CH_AUTOJOIN,
+ CHAT_MENU_CH_INFO,
+ CHAT_MENU_CH_TOPIC,
+ CHAT_MENU_CH_MSG,
+ CHAT_MENU_CH_LOCK,
+ CHAT_MENU_CH_UNLOCK,
+ CHAT_MENU_CH_REG,
+ CHAT_MENU_CH_UNREG,
+ CHAT_MENU_CH_SPAM_ON,
+ CHAT_MENU_CH_SPAM_OFF,
+ CHAT_MENU_CH_SPAM_ISON,
+
+ CHAT_MENU_SV_DISCON,
+ CHAT_MENU_SV_RECON,
+ CHAT_MENU_SV_REMOVE,
+ CHAT_MENU_SV_CHPWD,
+ CHAT_MENU_SV_ACCESS,
+ CHAT_MENU_SV_BROADCAST,
+
+ CHAT_MENU_US_CHAT,
+ CHAT_MENU_US_JOIN,
+ CHAT_MENU_US_SLAP,
+ CHAT_MENU_US_MUTE,
+ CHAT_MENU_US_UNMUTE,
+ CHAT_MENU_US_KICK,
+ CHAT_MENU_US_ADD_TO_GROUP,
+ CHAT_MENU_US_OP,
+ CHAT_MENU_US_DEOP,
+ CHAT_MENU_US_MODERATOR_INGAME,
+ CHAT_MENU_US_MODERATOR_CURIP,
+ CHAT_MENU_US_MODERATOR_KICK,
+ CHAT_MENU_US_MODERATOR_BAN,
+ CHAT_MENU_US_MODERATOR_UNBAN,
+ CHAT_MENU_US_MODERATOR_MUTE,
+ CHAT_MENU_US_MODERATOR_MUTE_5,
+ CHAT_MENU_US_MODERATOR_MUTE_10,
+ CHAT_MENU_US_MODERATOR_MUTE_30,
+ CHAT_MENU_US_MODERATOR_MUTE_120,
+ CHAT_MENU_US_MODERATOR_MUTE_1440,
+ CHAT_MENU_US_MODERATOR_UNMUTE,
+ CHAT_MENU_US_MODERATOR_RING,
+
+ CHAT_MENU_COPYLINK,
+
+ CHAT_MENU_SHOW_MUTELIST,
+
+ CHAT_MENU_LOG_OPEN
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_CHATPANEL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/connectwindow.cpp b/src/connectwindow.cpp
new file mode 100644
index 0000000..bed4019
--- /dev/null
+++ b/src/connectwindow.cpp
@@ -0,0 +1,322 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: ConnectWindow
+//
+
+#include <wx/notebook.h>
+#include <wx/panel.h>
+#include <wx/tokenzr.h>
+#include <wx/stattext.h>
+#include <wx/combobox.h>
+#include <wx/checkbox.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/statline.h>
+#include <wx/intl.h>
+#include <wx/settings.h>
+#include <wx/icon.h>
+#include <wx/tooltip.h>
+#include <wx/log.h>
+
+#include "connectwindow.h"
+#include "settings.h"
+#include "ui.h"
+#include "images/connect.xpm"
+#include "utils/controls.h"
+#include "utils/tasutil.h"
+
+#include "settings++/custom_dialogs.h"
+
+// Define events.
+BEGIN_EVENT_TABLE(ConnectWindow, wxDialog)
+
+ EVT_BUTTON ( wxID_OK, ConnectWindow::OnOk )
+ EVT_BUTTON ( wxID_CANCEL, ConnectWindow::OnCancel )
+ EVT_COMBOBOX ( CON_SERV_SEL , ConnectWindow::OnServerChange )
+
+END_EVENT_TABLE()
+
+//! @brief Constructor
+//!
+//! @param parent Parent window
+ConnectWindow::ConnectWindow( wxWindow* parent, Ui& ui )
+ : wxDialog( parent, -1, _("Connect to lobby server"), wxDefaultPosition, wxSize(300, 300),
+ wxDEFAULT_DIALOG_STYLE | wxCLIP_CHILDREN ), m_ui(ui)
+{
+ wxString server;
+ wxString username;
+ wxString password;
+ bool savepass;
+ bool autoconnect;
+
+ SetIcon( wxIcon(connect_xpm) );
+
+ server = sett().GetDefaultServer();
+ username = sett().GetServerAccountNick( sett().GetDefaultServer() );
+ password = sett().GetServerAccountPass( sett().GetDefaultServer() );
+ savepass = sett().GetServerAccountSavePass( sett().GetDefaultServer() );
+ autoconnect = sett().GetAutoConnect();
+ // Create all UI elements.
+ m_tabs = new wxNotebook( this , -1 );
+ m_login_tab = new wxPanel ( m_tabs, -1 );
+ m_register_tab = new wxPanel ( m_tabs, -1 );
+
+ m_server_lbl = new wxStaticText( m_login_tab, -1, _("Server") );
+ m_server_combo = new wxComboBox ( m_login_tab, CON_SERV_SEL, server );
+ m_server_combo->SetToolTip( TE(_("Server to connect to. You can connect to any server you like by typing in hostaddress:port format.")) );
+
+ m_ser_acc_line = new wxStaticLine( m_login_tab );
+
+ m_nick_lbl = new wxStaticText( m_login_tab, -1, _("Nickname") );
+ m_nick_text = new wxTextCtrl ( m_login_tab, -1, username );
+ m_pass_lbl = new wxStaticText( m_login_tab, -1, _("Password") );
+ m_pass_text = new wxTextCtrl ( m_login_tab, -1, password, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD );
+ m_rpass_check = new wxCheckBox ( m_login_tab, -1, _("Remember password") );
+ m_autoconnect_check = new wxCheckBox ( m_login_tab, -1, _("Autoconnect next time") );
+ m_autoconnect_check->SetToolTip( TE(_("remember connection details and automatically connect to server on next lobby startup")) );
+ wxToolTip::Enable( false );
+
+ m_rpass_check->SetValue( savepass );
+ m_autoconnect_check->SetValue( autoconnect );
+
+ m_acc_note_line = new wxStaticLine( m_login_tab );
+
+ m_note_lbl = new wxStaticText( m_login_tab, -1, _("Note: If you do not have an account, you\n can register one for free under the\n\"Register\" tab.") );
+
+ m_ok_btn = new wxButton( this, wxID_OK, _("Ok") );
+ m_cancel_btn = new wxButton( this, wxID_CANCEL, _("Cancel") );
+
+ // Add tabs to tab control.
+ m_tabs->AddPage( m_login_tab, _("Login"), true );
+ m_tabs->AddPage( m_register_tab, _("Register"), false );
+
+ // Create sizers.
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+ m_login_main_sizer = new wxBoxSizer( wxVERTICAL );
+ m_server_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_nick_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_pass_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_rpass_sizer = new wxBoxSizer( wxVERTICAL );
+ wxBoxSizer* m_check_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_buttons_sizer = new wxStdDialogButtonSizer();
+
+ // Add UI elements to sizers.
+ m_buttons_sizer->Add( m_ok_btn );
+ m_buttons_sizer->AddStretchSpacer();
+ m_buttons_sizer->Add( m_cancel_btn );
+
+
+ m_rpass_sizer->Add( m_rpass_check, 2, wxEXPAND | wxALL | wxALIGN_RIGHT, 4 );
+ m_rpass_sizer->Add( m_autoconnect_check, 2, wxEXPAND | wxALL | wxALIGN_RIGHT, 4 );
+
+ m_pass_sizer->Add( m_pass_lbl, 1, wxALL | wxALIGN_CENTER_VERTICAL, 4 );
+ m_pass_sizer->Add( m_pass_text, 2, wxEXPAND | wxALL, 4 );
+
+ //FIXME was lazy, absoulte positioning isn't that nice
+ int pos1 = (m_pass_lbl->GetSize()).GetWidth() + 40;
+ m_check_sizer->Add(pos1,0,0);
+ m_check_sizer->Add( m_rpass_sizer, 0, wxEXPAND | wxALIGN_RIGHT);
+
+ m_nick_sizer->Add( m_nick_lbl, 1, wxALL | wxALIGN_CENTER_VERTICAL, 4 );
+ m_nick_sizer->Add( m_nick_text, 2, wxEXPAND | wxALL, 4 );
+
+ m_server_sizer->Add( m_server_lbl, 1, wxALL | wxALIGN_CENTER_VERTICAL, 4 );
+ m_server_sizer->Add( m_server_combo, 2, wxEXPAND | wxALL, 4 );
+
+ m_login_main_sizer->Add( m_server_sizer, 0, wxEXPAND | wxALL, 0 );
+ m_login_main_sizer->Add( m_ser_acc_line, 0, wxEXPAND | wxALL, 4 );
+ m_login_main_sizer->Add( m_nick_sizer, 0, wxEXPAND );
+ m_login_main_sizer->Add( m_pass_sizer, 0, wxEXPAND );
+ m_login_main_sizer->Add( m_check_sizer, 0, wxEXPAND );
+ m_login_main_sizer->Add( m_acc_note_line, 0, wxEXPAND | wxALL, 4 );
+ m_login_main_sizer->Add( m_note_lbl, 0, wxEXPAND | wxALL, 4 );
+ m_login_main_sizer->AddStretchSpacer();
+
+ m_login_tab->SetSizer( m_login_main_sizer );
+
+ m_main_sizer->Add( m_tabs, 1, wxEXPAND );
+ m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND );
+
+
+ // Register page
+ wxBoxSizer* m_register_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* m_regnick_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_regnick_lbl = new wxStaticText( m_register_tab, wxID_ANY, _("Nick"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_regnick_sizer->Add( m_regnick_lbl, 1, wxALL | wxALIGN_CENTER_VERTICAL, 4 );
+
+ m_regnick_text = new wxTextCtrl( m_register_tab, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_regnick_sizer->Add( m_regnick_text, 1, wxALL, 4 );
+
+ m_register_sizer->Add( m_regnick_sizer, 0, wxEXPAND, 4 );
+
+ m_regpass_sep = new wxStaticLine( m_register_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ m_register_sizer->Add( m_regpass_sep, 0, wxALL|wxEXPAND, 4 );
+
+ wxBoxSizer* m_regpass1_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_regpass1_lbl = new wxStaticText( m_register_tab, wxID_ANY, _("Password"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_regpass1_sizer->Add( m_regpass1_lbl, 1, wxALL | wxALIGN_CENTER_VERTICAL, 4 );
+
+ m_regpass1_text = new wxTextCtrl( m_register_tab, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD );
+ m_regpass1_sizer->Add( m_regpass1_text, 1, wxALL, 4 );
+
+ m_register_sizer->Add( m_regpass1_sizer, 0, wxEXPAND, 4 );
+
+ wxBoxSizer* m_regpass1_sizer1 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_regpass2_lbl = new wxStaticText( m_register_tab, wxID_ANY, wxT("Retype password"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_regpass1_sizer1->Add( m_regpass2_lbl, 1, wxALL | wxALIGN_CENTER_VERTICAL, 4 );
+
+ m_regpass2_text = new wxTextCtrl( m_register_tab, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD );
+ m_regpass1_sizer1->Add( m_regpass2_text, 1, wxALL, 4 );
+
+ m_register_sizer->Add( m_regpass1_sizer1, 0, wxEXPAND, 4 );
+
+ m_register_tab->SetSizer( m_register_sizer );
+ m_register_tab->Layout();
+ m_register_sizer->Fit( m_register_tab );
+
+
+ // Set sizer.
+ SetSizer( m_main_sizer );
+
+ if ( !username.empty() )
+ {
+ m_ok_btn->SetFocus();
+ }
+ else
+ {
+ m_nick_text->SetFocus();
+ }
+
+ m_ok_btn->SetDefault();
+
+ Layout();
+ m_main_sizer->SetSizeHints( this );
+#ifdef __WXMSW__
+ SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
+#endif
+
+ ReloadServerList();
+
+}
+
+
+//! @brief Destructor
+ConnectWindow::~ConnectWindow()
+{
+
+}
+
+
+void ConnectWindow::ReloadServerList()
+{
+ m_server_combo->Clear();
+ m_server_combo->Append( sett().GetServers() );
+ m_server_combo->SetValue( sett().GetDefaultServer() );
+}
+
+void ConnectWindow::OnServerChange( wxCommandEvent& event )
+{
+ wxString HostAddress = m_server_combo->GetValue();
+ if ( !HostAddress.Contains( _T(":") ) )
+ {
+ if ( !sett().ServerExists( HostAddress ) )
+ {
+ HostAddress+= _T(":") + wxString::Format(_T("%d"), DEFSETT_DEFAULT_SERVER_PORT );
+ }
+ }
+ m_nick_text->SetValue( sett().GetServerAccountNick( HostAddress ) );
+ if ( sett().GetServerAccountSavePass( HostAddress ) ) m_pass_text->SetValue( sett().GetServerAccountPass( HostAddress ) );
+}
+
+
+void ConnectWindow::OnOk(wxCommandEvent& event)
+{
+ Hide();
+ wxString HostAddress = m_server_combo->GetValue();
+ if ( !HostAddress.Contains( _T(":") ) )
+ {
+ if ( !sett().ServerExists( HostAddress ) )
+ {
+ HostAddress += _T(":") + wxString::Format(_T("%d"), DEFSETT_DEFAULT_SERVER_PORT );
+ }
+ }
+ if ( m_tabs->GetSelection() <= 0 )
+ {
+ sett().SetServerAccountNick( HostAddress,m_nick_text->GetValue() );
+ sett().SetServerAccountSavePass( HostAddress, m_rpass_check->GetValue() );
+
+ // We assume that the server is given as : "host:port" so we split based on ":"
+ wxArrayString serverString = wxStringTokenize( HostAddress ,_T(":") );
+ if ( serverString.GetCount() == 2 )
+ {
+ long port;
+ if ( !serverString[1].ToLong( &port ) )
+ {
+ wxLogWarning( _T("Invalid port.") );
+ customMessageBox(SL_MAIN_ICON, _("Invalid port."), _("Invalid port"), wxOK );
+ return;
+ }
+ if ( port < 1 || port > 65535)
+ {
+ wxLogWarning( _T("port number out of range") );
+ customMessageBox(SL_MAIN_ICON, _("Port number out of range.\n\nIt must be an integer between 1 and 65535"), _("Invalid port"), wxOK );
+ return;
+ }
+ sett().SetServer( HostAddress, serverString[0], port );
+ }
+
+ if ( serverString.GetCount() > 2 )
+ {
+ wxLogWarning( _T("invalid host/port.") );
+ customMessageBox(SL_MAIN_ICON, _("Invalid host/port."), _("Invalid host"), wxOK );
+ return;
+ }
+ sett().SetAutoConnect( m_autoconnect_check->IsChecked() );
+
+ //if autoconnect enabled force saving of pw, actual saving is done in Ui::DoConnect
+ if ( m_autoconnect_check->IsChecked() ) sett().SetServerAccountSavePass( HostAddress, true );
+
+ sett().SaveSettings();
+ ReloadServerList();
+
+ m_ui.DoConnect( HostAddress, m_nick_text->GetValue(), m_pass_text->GetValue() );
+ }
+ else
+ {
+ wxString reason;
+ if ( !IsValidNickname( m_regnick_text->GetValue() ) )
+ {
+ customMessageBox(SL_MAIN_ICON,_("The entered nickname contains invalid characters like )? &%.\n Please try again") , _("Invalid nickname"), wxOK );
+ Show();
+ }
+ else if ( m_regpass2_text->GetValue()!= m_regpass1_text->GetValue() || m_regpass1_text->GetValue().IsEmpty() )
+ {
+ Show();
+ wxLogWarning( _T("registration failed, reason: password/confirmation mismatch") );
+ customMessageBox(SL_MAIN_ICON,_("Registration failed, the reason was:\nPassword / confirmation mismatch (or empty passwort)") , _("Registration failed."), wxOK );
+ }
+ else if ( m_ui.DoRegister( HostAddress, m_regnick_text->GetValue(), m_regpass1_text->GetValue(),reason ) )
+ {
+ m_tabs->SetSelection( 0 );
+ m_nick_text->SetValue(m_regnick_text->GetValue());
+ m_pass_text->SetValue(m_regpass1_text->GetValue());
+ Show();
+ }
+ else
+ {
+ Show();
+ }
+
+ }
+}
+
+void ConnectWindow::OnCancel(wxCommandEvent& event)
+{
+ Hide();
+}
+
+
diff --git a/src/connectwindow.h b/src/connectwindow.h
new file mode 100644
index 0000000..a6b32f7
--- /dev/null
+++ b/src/connectwindow.h
@@ -0,0 +1,105 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CONNECTWINDOW_H
+#define SPRINGLOBBY_HEADERGUARD_CONNECTWINDOW_H
+
+#include <wx/dialog.h>
+
+class wxPanel;
+class wxComboBox;
+class wxBoxSizer;
+class wxStdDialogButtonSizer;
+class wxButton;
+class wxTextCtrl;
+class wxStaticText;
+class wxNotebook;
+class wxCheckBox;
+class wxStaticLine;
+class Ui;
+
+//! @brief wxFrame with a connection dialog used to specify username, password, and server. It can also register a new acount.
+class ConnectWindow : public wxDialog
+{
+ public:
+ ConnectWindow( wxWindow* parent, Ui& ui );
+ ~ConnectWindow();
+
+ // ConnectWindow interface
+
+ void ReloadServerList();
+
+ void OnServerChange( wxCommandEvent& event );
+
+ void OnOk(wxCommandEvent& event);
+ void OnCancel(wxCommandEvent& event);
+
+ protected:
+ // ConnectWindow variables
+
+ wxNotebook* m_tabs; //!< Notebook containing the login and register tabs
+ wxPanel* m_login_tab; //!< The login tab
+ wxPanel* m_register_tab; //!< The register tab
+
+ wxStaticText* m_server_lbl; //!< Label saying "Server"
+ wxComboBox* m_server_combo; //!< Combobox where user can select server
+
+ wxStaticLine* m_ser_acc_line; //!< Line that separates the server setting and the acount settings
+
+ wxStaticText* m_nick_lbl; //!< Label saying "Nickname"
+ wxTextCtrl* m_nick_text; //!< Textbox where user can input nickname
+ wxStaticText* m_pass_lbl; //!< Label saying "Password"
+ wxTextCtrl* m_pass_text; //!< Textbox where user can input password
+ wxCheckBox* m_rpass_check; //!< Checkbox where user can chose if he wants his password to be saved.
+ wxCheckBox* m_autoconnect_check; //!< Checkbox where user can chose if he wants to autoconnect.
+
+ wxStaticLine* m_acc_note_line; //!< Line that separates the account settings from the note
+
+ wxStaticText* m_note_lbl; //!< Label saying something about register
+
+ wxButton* m_ok_btn; //!< The ok button
+ wxButton* m_cancel_btn; //!< The cancel button
+
+ wxBoxSizer* m_main_sizer; //!< The main sizer connecting it all together
+ wxBoxSizer* m_login_main_sizer; //!< Login tab main sizer
+ wxBoxSizer* m_server_sizer; //!< Sizer connecting server label and combo
+ wxBoxSizer* m_nick_sizer; //!< Sizer connecting nick label and input
+ wxBoxSizer* m_pass_sizer; //!< Sizer connecting password label and input
+ wxBoxSizer* m_rpass_sizer; //!< Sizer spacing the remember password setting
+ wxStdDialogButtonSizer* m_buttons_sizer; //!< Sizer connecting the ok and cancel buttons
+
+ wxStaticText* m_regnick_lbl;
+ wxTextCtrl* m_regnick_text;
+ wxStaticLine* m_regpass_sep;
+ wxStaticText* m_regpass1_lbl;
+ wxTextCtrl* m_regpass1_text;
+ wxStaticText* m_regpass2_lbl;
+ wxTextCtrl* m_regpass2_text;
+
+ Ui& m_ui;
+
+ enum {
+ CON_SERV_SEL = wxID_HIGHEST
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_CONNECTWINDOW_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/countrycodes.cpp b/src/countrycodes.cpp
new file mode 100644
index 0000000..e5eca9c
--- /dev/null
+++ b/src/countrycodes.cpp
@@ -0,0 +1,262 @@
+#include "countrycodes.h"
+
+#include <wx/intl.h>
+#include <map>
+
+static std::map<wxString,wxString> m_cc_table;
+
+void InitTable()
+{
+ if (!m_cc_table.empty()) return;
+ m_cc_table[_T("AD")] = _(" Andorra");
+m_cc_table[_T("AE")] = _("United Arab Emirates");
+m_cc_table[_T("AF")] = _("Afghanistan");
+m_cc_table[_T("AG")] = _("Antigua and Barbuda");
+m_cc_table[_T("AI")] = _("Anguilla");
+m_cc_table[_T("AL")] = _("Albania");
+m_cc_table[_T("AM")] = _("Armenia");
+m_cc_table[_T("AN")] = _("Netherlands Antilles");
+m_cc_table[_T("AO")] = _("Angola");
+m_cc_table[_T("AQ")] = _("Antarctica");
+m_cc_table[_T("AR")] = _("Argentina");
+m_cc_table[_T("AS")] = _("American Samoa");
+m_cc_table[_T("AT")] = _("Austria");
+m_cc_table[_T("AU")] = _("Australia");
+m_cc_table[_T("AW")] = _("Aruba");
+m_cc_table[_T("AZ")] = _("Azerbaijan");
+m_cc_table[_T("BA")] = _("Bosnia and Herzegovina");
+m_cc_table[_T("BB")] = _("Barbados");
+m_cc_table[_T("BD")] = _("Bangladesh");
+m_cc_table[_T("BE")] = _("Belgium");
+m_cc_table[_T("BF")] = _("Burkina Faso");
+m_cc_table[_T("BG")] = _("Bulgaria");
+m_cc_table[_T("BH")] = _("Bahrain");
+m_cc_table[_T("BI")] = _("Burundi");
+m_cc_table[_T("BJ")] = _("Benin");
+m_cc_table[_T("BM")] = _("Bermuda");
+m_cc_table[_T("BN")] = _("Brunei Darussalam");
+m_cc_table[_T("BO")] = _("Bolivia");
+m_cc_table[_T("BR")] = _("Brazil");
+m_cc_table[_T("BS")] = _("Bahamas");
+m_cc_table[_T("BT")] = _("Bhutan");
+m_cc_table[_T("BV")] = _("Bouvet Island");
+m_cc_table[_T("BW")] = _("Botswana");
+m_cc_table[_T("BY")] = _("Belarus");
+m_cc_table[_T("BZ")] = _("Belize");
+m_cc_table[_T("CA")] = _("Canada");
+m_cc_table[_T("CC")] = _("Cocos (Keeling Islands)");
+m_cc_table[_T("CF")] = _("Central African Republic");
+m_cc_table[_T("CG")] = _("Congo");
+m_cc_table[_T("CH")] = _("Switzerland");
+m_cc_table[_T("CI")] = _("Cote D'Ivoire (Ivory Coast)");
+m_cc_table[_T("CK")] = _("Cook Islands");
+m_cc_table[_T("CL")] = _("Chile");
+m_cc_table[_T("CM")] = _("Cameroon");
+m_cc_table[_T("CN")] = _("China");
+m_cc_table[_T("CO")] = _("Colombia");
+m_cc_table[_T("CR")] = _("Costa Rica");
+m_cc_table[_T("CU")] = _("Cuba");
+m_cc_table[_T("CV")] = _("Cape Verde");
+m_cc_table[_T("CX")] = _("Christmas Island");
+m_cc_table[_T("CY")] = _("Cyprus");
+m_cc_table[_T("CZ")] = _("Czech Republic");
+m_cc_table[_T("DE")] = _("Germany");
+m_cc_table[_T("DJ")] = _("Djibouti");
+m_cc_table[_T("DK")] = _("Denmark");
+m_cc_table[_T("DM")] = _("Dominica");
+m_cc_table[_T("DO")] = _("Dominican Republic");
+m_cc_table[_T("DZ")] = _("Algeria");
+m_cc_table[_T("EC")] = _("Ecuador");
+m_cc_table[_T("EE")] = _("Estonia");
+m_cc_table[_T("EG")] = _("Egypt");
+m_cc_table[_T("EH")] = _("Western Sahara");
+m_cc_table[_T("ER")] = _("Eritrea");
+m_cc_table[_T("ES")] = _("Spain");
+m_cc_table[_T("ET")] = _("Ethiopia");
+m_cc_table[_T("FI")] = _("Finland");
+m_cc_table[_T("FJ")] = _("Fiji");
+m_cc_table[_T("FK")] = _("Falkland Islands (Malvinas)");
+m_cc_table[_T("FM")] = _("Micronesia");
+m_cc_table[_T("FO")] = _("Faroe Islands");
+m_cc_table[_T("FR")] = _("France");
+m_cc_table[_T("FX")] = _("France, Metropolitan");
+m_cc_table[_T("GA")] = _("Gabon");
+m_cc_table[_T("GD")] = _("Grenada");
+m_cc_table[_T("GE")] = _("Georgia");
+m_cc_table[_T("GF")] = _("French Guiana");
+m_cc_table[_T("GH")] = _("Ghana");
+m_cc_table[_T("GI")] = _("Gibraltar");
+m_cc_table[_T("GL")] = _("Greenland");
+m_cc_table[_T("GM")] = _("Gambia");
+m_cc_table[_T("GN")] = _("Guinea");
+m_cc_table[_T("GP")] = _("Guadeloupe");
+m_cc_table[_T("GQ")] = _("Equatorial Guinea");
+m_cc_table[_T("GR")] = _("Greece");
+m_cc_table[_T("GS")] = _("S. Georgia and S. Sandwich Isls.");
+m_cc_table[_T("GT")] = _("Guatemala");
+m_cc_table[_T("GU")] = _("Guam");
+m_cc_table[_T("GW")] = _("Guinea-Bissau");
+m_cc_table[_T("GY")] = _("Guyana");
+m_cc_table[_T("HK")] = _("Hong Kong");
+m_cc_table[_T("HM")] = _("Heard and McDonald Islands");
+m_cc_table[_T("HN")] = _("Honduras");
+m_cc_table[_T("HR")] = _("Croatia (Hrvatska)");
+m_cc_table[_T("HT")] = _("Haiti");
+m_cc_table[_T("HU")] = _("Hungary");
+m_cc_table[_T("ID")] = _("Indonesia");
+m_cc_table[_T("IE")] = _("Ireland");
+m_cc_table[_T("IL")] = _("Israel");
+m_cc_table[_T("IN")] = _("India");
+m_cc_table[_T("IO")] = _("British Indian Ocean Territory");
+m_cc_table[_T("IQ")] = _("Iraq");
+m_cc_table[_T("IR")] = _("Iran");
+m_cc_table[_T("IS")] = _("Iceland");
+m_cc_table[_T("IT")] = _("Italy");
+m_cc_table[_T("JM")] = _("Jamaica");
+m_cc_table[_T("JO")] = _("Jordan");
+m_cc_table[_T("JP")] = _("Japan");
+m_cc_table[_T("KE")] = _("Kenya");
+m_cc_table[_T("KG")] = _("Kyrgyzstan (Kyrgyz Republic)");
+m_cc_table[_T("KH")] = _("Cambodia");
+m_cc_table[_T("KI")] = _("Kiribati");
+m_cc_table[_T("KM")] = _("Comoros");
+m_cc_table[_T("KN")] = _("Saint Kitts and Nevis");
+m_cc_table[_T("KP")] = _("Korea (North) (People's Republic)");
+m_cc_table[_T("KR")] = _("Korea (South) (Republic)");
+m_cc_table[_T("KW")] = _("Kuwait");
+m_cc_table[_T("KY")] = _("Cayman Islands");
+m_cc_table[_T("KZ")] = _("Kazakhstan");
+m_cc_table[_T("LA")] = _("Laos");
+m_cc_table[_T("LB")] = _("Lebanon");
+m_cc_table[_T("LC")] = _("Saint Lucia");
+m_cc_table[_T("LI")] = _("Liechtenstein");
+m_cc_table[_T("LK")] = _("Sri Lanka");
+m_cc_table[_T("LR")] = _("Liberia");
+m_cc_table[_T("LS")] = _("Lesotho");
+m_cc_table[_T("LT")] = _("Lithuania");
+m_cc_table[_T("LU")] = _("Luxembourg");
+m_cc_table[_T("LV")] = _("Latvia");
+m_cc_table[_T("LY")] = _("Libya");
+m_cc_table[_T("MA")] = _("Morocco");
+m_cc_table[_T("MC")] = _("Monaco");
+m_cc_table[_T("MD")] = _("Moldova");
+m_cc_table[_T("ME")] = _("Montenegro");
+m_cc_table[_T("MG")] = _("Madagascar");
+m_cc_table[_T("MH")] = _("Marshall Islands");
+m_cc_table[_T("MK")] = _("Macedonia");
+m_cc_table[_T("ML")] = _("Mali");
+m_cc_table[_T("MM")] = _("Myanmar");
+m_cc_table[_T("MN")] = _("Mongolia");
+m_cc_table[_T("MO")] = _("Macau");
+m_cc_table[_T("MP")] = _("Northern Mariana Islands");
+m_cc_table[_T("MQ")] = _("Martinique");
+m_cc_table[_T("MR")] = _("Mauritania");
+m_cc_table[_T("MS")] = _("Montserrat");
+m_cc_table[_T("MT")] = _("Malta");
+m_cc_table[_T("MU")] = _("Mauritius");
+m_cc_table[_T("MV")] = _("Maldives");
+m_cc_table[_T("MW")] = _("Malawi");
+m_cc_table[_T("MX")] = _("Mexico");
+m_cc_table[_T("MY")] = _("Malaysia");
+m_cc_table[_T("MZ")] = _("Mozambique");
+m_cc_table[_T("NA")] = _("Namibia");
+m_cc_table[_T("NC")] = _("New Caledonia");
+m_cc_table[_T("NE")] = _("Niger");
+m_cc_table[_T("NF")] = _("Norfolk Island");
+m_cc_table[_T("NG")] = _("Nigeria");
+m_cc_table[_T("NI")] = _("Nicaragua");
+m_cc_table[_T("NL")] = _("Netherlands");
+m_cc_table[_T("NO")] = _("Norway");
+m_cc_table[_T("NP")] = _("Nepal");
+m_cc_table[_T("NR")] = _("Nauru");
+m_cc_table[_T("NT")] = _("Neutral Zone (Saudia Arabia/Iraq)");
+m_cc_table[_T("NU")] = _("Niue");
+m_cc_table[_T("NZ")] = _("New Zealand");
+m_cc_table[_T("OM")] = _("Oman");
+m_cc_table[_T("PA")] = _("Panama");
+m_cc_table[_T("PE")] = _("Peru");
+m_cc_table[_T("PF")] = _("French Polynesia");
+m_cc_table[_T("PG")] = _("Papua New Guinea");
+m_cc_table[_T("PH")] = _("Philippines");
+m_cc_table[_T("PK")] = _("Pakistan");
+m_cc_table[_T("PL")] = _("Poland");
+m_cc_table[_T("PM")] = _("St. Pierre and Miquelon");
+m_cc_table[_T("PN")] = _("Pitcairn");
+m_cc_table[_T("PR")] = _("Puerto Rico");
+m_cc_table[_T("PT")] = _("Portugal");
+m_cc_table[_T("PW")] = _("Palau");
+m_cc_table[_T("PY")] = _("Paraguay");
+m_cc_table[_T("QA")] = _("Qatar");
+m_cc_table[_T("RE")] = _("Reunion");
+m_cc_table[_T("RO")] = _("Romania");
+m_cc_table[_T("RS")] = _("Serbia");
+m_cc_table[_T("RU")] = _("Russian Federation");
+m_cc_table[_T("RW")] = _("Rwanda");
+m_cc_table[_T("SA")] = _("Saudi Arabia");
+m_cc_table[_T("SB")] = _("Solomon Islands");
+m_cc_table[_T("SC")] = _("Seychelles");
+m_cc_table[_T("SD")] = _("Sudan");
+m_cc_table[_T("SE")] = _("Sweden");
+m_cc_table[_T("SG")] = _("Singapore");
+m_cc_table[_T("SH")] = _("St. Helena");
+m_cc_table[_T("SI")] = _("Slovenia");
+m_cc_table[_T("SJ")] = _("Svalbard and Jan Mayen Islands");
+m_cc_table[_T("SK")] = _("Slovakia (Slovak Republic)");
+m_cc_table[_T("SL")] = _("Sierra Leone");
+m_cc_table[_T("SM")] = _("San Marino");
+m_cc_table[_T("SN")] = _("Senegal");
+m_cc_table[_T("SO")] = _("Somalia");
+m_cc_table[_T("SR")] = _("Suriname");
+m_cc_table[_T("ST")] = _("Sao Tome and Principe");
+m_cc_table[_T("SU")] = _("Soviet Union (former)");
+m_cc_table[_T("SV")] = _("El Salvador");
+m_cc_table[_T("SY")] = _("Syria");
+m_cc_table[_T("SZ")] = _("Swaziland");
+m_cc_table[_T("TC")] = _("Turks and Caicos Islands");
+m_cc_table[_T("TD")] = _("Chad");
+m_cc_table[_T("TF")] = _("French Southern Territories");
+m_cc_table[_T("TG")] = _("Togo");
+m_cc_table[_T("TH")] = _("Thailand");
+m_cc_table[_T("TJ")] = _("Tajikistan");
+m_cc_table[_T("TK")] = _("Tokelau");
+m_cc_table[_T("TM")] = _("Turkmenistan");
+m_cc_table[_T("TN")] = _("Tunisia");
+m_cc_table[_T("TO")] = _("Tonga");
+m_cc_table[_T("TP")] = _("East Timor");
+m_cc_table[_T("TR")] = _("Turkey");
+m_cc_table[_T("TT")] = _("Trinidad and Tobago");
+m_cc_table[_T("TV")] = _("Tuvalu");
+m_cc_table[_T("TW")] = _("Taiwan");
+m_cc_table[_T("TZ")] = _("Tanzania");
+m_cc_table[_T("UA")] = _("Ukraine");
+m_cc_table[_T("UG")] = _("Uganda");
+m_cc_table[_T("GB")] = _("United Kingdom (Great Britain)");
+m_cc_table[_T("UM")] = _("US Minor Outlying Islands");
+m_cc_table[_T("US")] = _("United States");
+m_cc_table[_T("UY")] = _("Uruguay");
+m_cc_table[_T("UZ")] = _("Uzbekistan");
+m_cc_table[_T("VA")] = _("Vatican City State (Holy See)");
+m_cc_table[_T("VC")] = _("Saint Vincent and The Grenadines");
+m_cc_table[_T("VE")] = _("Venezuela");
+m_cc_table[_T("VG")] = _("Virgin Islands (British)");
+m_cc_table[_T("VI")] = _("Virgin Islands (US)");
+m_cc_table[_T("VN")] = _("Viet Nam");
+m_cc_table[_T("VU")] = _("Vanuatu");
+m_cc_table[_T("WF")] = _("Wallis and Futuna Islands");
+m_cc_table[_T("WS")] = _("Samoa");
+m_cc_table[_T("YE")] = _("Yemen");
+m_cc_table[_T("YT")] = _("Mayotte");
+m_cc_table[_T("YU")] = _("Yugoslavia");
+m_cc_table[_T("ZA")] = _("South Africa");
+m_cc_table[_T("ZM")] = _("Zambia");
+m_cc_table[_T("ZR")] = _("Zaire");
+m_cc_table[_T("ZW")] = _("Zimbabwe");
+}
+
+wxString GetFlagNameFromCountryCode( const wxString& cc )
+{
+ InitTable();
+ wxString ret = m_cc_table[ cc ];
+ if ( ret.IsEmpty() ) return cc + _T(" ") + _("(Full country name not found)");
+ else return ret;
+}
diff --git a/src/countrycodes.h b/src/countrycodes.h
new file mode 100644
index 0000000..2081914
--- /dev/null
+++ b/src/countrycodes.h
@@ -0,0 +1,26 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_COUNTRYCODES_H
+#define SPRINGLOBBY_HEADERGUARD_COUNTRYCODES_H
+
+class wxString;
+
+wxString GetFlagNameFromCountryCode( const wxString& cc );
+
+#endif // SPRINGLOBBY_HEADERGUARD_COUNTRYCODES_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/crashreport.cpp b/src/crashreport.cpp
new file mode 100644
index 0000000..cb4e023
--- /dev/null
+++ b/src/crashreport.cpp
@@ -0,0 +1,100 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Classes: NetDebugReport CrashReport
+//
+
+
+#if wxUSE_DEBUGREPORT && defined(ENABLE_DEBUG_REPORT)
+#include "utils.h"
+#include "crashreport.h"
+#include <wx/intl.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/stdpaths.h>
+#include <wx/dir.h>
+#include <wx/file.h>
+
+
+
+
+NetDebugReport::NetDebugReport() : wxDebugReportUpload ( _T("http://www.hd.chalmers.se/~tc/trace/"), _T("trace"), _T("upload.php") )
+{
+}
+
+bool NetDebugReport::OnServerReply(const wxArrayString& reply)
+{
+ if ( reply.IsEmpty() )
+ {
+ wxLogError(_T("Didn't receive the expected server reply."));
+ return false;
+ }
+
+ wxString s(_T("Server replied:\n"));
+
+ const size_t count = reply.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ s << _T('\t') << reply[n] << _T('\n');
+ }
+
+ wxLogMessage(_T("%s"), s.c_str());
+
+ return true;
+}
+
+void CrashReport::GenerateReport(wxDebugReport::Context ctx)
+{
+ wxSetWorkingDirectory( wxFileName::GetTempDir() );
+
+ bool online = true; // TODO (BrainDamage#1#): check if being online
+
+ wxDebugReportCompress *report = online ? new NetDebugReport
+ : new wxDebugReportCompress;
+
+ // add all standard files: currently this means just a minidump and an
+ // XML file with system info and stack trace
+ report->AddAll(ctx);
+
+ wxString dir = report->GetDirectory();
+
+ wxString SystemInfos;
+#ifdef VERSION
+ SystemInfos += _T("SpringLobby version ") + GetSpringLobbyVersion() +_T("\n") ;
+#endif
+ SystemInfos += _T("Built from ") + wxString(wxVERSION_STRING) + _T("\n") ;
+
+ report->AddText( _T("SystemInfos.txt"), SystemInfos, _("System informations") );
+#if wxUSE_STD_IOSTREAM
+ report->AddText( _T("AppLog.txt"), WX_STRING( crashlog.str() ), _("Application verbose log") );
+#endif
+ report->AddFile( wxStandardPaths::Get().GetUserDataDir() + wxFileName::GetPathSeparator() + _T("script_debug.txt"), _("Last generated spring launching script") );
+
+ // calling Show() is not mandatory, but is more polite
+ if ( wxDebugReportPreviewStd().Show(*report) )
+ {
+ if ( report->Process() )
+ {
+ if ( online )
+ {
+ wxLogMessage(_T("Report successfully uploaded."));
+ }
+ else
+ {
+ wxLogMessage(_T("Report generated in \"%s\"."),
+ report->GetCompressedFileName().c_str());
+ report->Reset();
+ }
+ }
+ }
+ //else: user cancelled the report
+
+ delete report;
+}
+
+CrashReport& crashreport()
+{
+ static CrashReport c;
+ return c;
+}
+
+#endif // wxUSE_DEBUGREPORT
diff --git a/src/crashreport.h b/src/crashreport.h
new file mode 100644
index 0000000..24b4cf6
--- /dev/null
+++ b/src/crashreport.h
@@ -0,0 +1,60 @@
+#ifndef CRASHREPORT_H_INCLUDED
+#define CRASHREPORT_H_INCLUDED
+
+#ifdef ENABLE_DEBUG_REPORT
+
+#include <wx/debugrpt.h>
+#include "utils.h"
+#if wxUSE_DEBUGREPORT
+
+#include <sstream>
+#include <wx/arrstr.h>
+
+//! @brief uploads zipped stacktraces using curl
+class NetDebugReport : public wxDebugReportUpload
+{
+ public:
+ //! @brief class contructor that sets curl arguments
+ NetDebugReport();
+
+ protected:
+ //! @brief gets called after server answered to the upload attempt
+ bool OnServerReply(const wxArrayString& reply);
+};
+
+//! @brief dumps various infos to the zipped debug info package and calls NetDebugReport if network is present
+class CrashReport
+{
+ public:
+
+ CrashReport(){}
+ void GenerateReport(wxDebugReport::Context ctx);
+ //! @brief is the container for the stream logging target
+ std::ostringstream crashlog;
+};
+
+CrashReport& crashreport();
+
+#endif // wxUSE_DEBUGREPORT
+
+#endif //ENABLE_DEBUG_REPORT
+
+#endif // SPRINGLOBBY_HEADERGUARD_CRASHREPORT_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/crc.cpp b/src/crc.cpp
new file mode 100644
index 0000000..6d65a69
--- /dev/null
+++ b/src/crc.cpp
@@ -0,0 +1,79 @@
+#include "crc.h"
+
+#include <stdio.h>
+
+
+unsigned int CRC::crcTable[256];
+
+
+/** @brief Generate the lookup table used for CRC calculation.
+ Code taken from http://paul.rutgers.edu/~rhoads/Code/crc-32b.c */
+void CRC::GenerateCRCTable()
+{
+ unsigned int crc, poly;
+ int i, j;
+
+ poly = 0xEDB88320L;
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 8; j > 0; j--) {
+ if (crc & 1)
+ crc = (crc >> 1) ^ poly;
+ else
+ crc >>= 1;
+ }
+ crcTable[i] = crc;
+ }
+}
+
+
+/** @brief Construct a new CRC object.
+ This generates the CRC table if it is the first CRC object being
+ constructed. */
+CRC::CRC() : crc(0xFFFFFFFF)
+{
+ if (crcTable[1] == 0)
+ GenerateCRCTable();
+}
+
+
+/** @brief Update CRC over the data in buf. */
+void CRC::UpdateData(const unsigned char* buf, unsigned bytes)
+{
+ for (size_t i = 0; i < bytes; ++i)
+ crc = (crc>>8) ^ crcTable[ (crc^(buf[i])) & 0xFF ];
+}
+
+/** @brief Resets CRC data to original state. */
+void CRC::ResetCRC()
+{
+ crc = 0xFFFFFFFF; // reset crc
+}
+
+
+/** @brief Update CRC over the data in buf. */
+void CRC::UpdateData(const std::string& buf)
+{
+ UpdateData((const unsigned char*) buf.c_str(), buf.size());
+}
+
+
+/** @brief Update CRC over the data in the specified file.
+ @return true on success, false if file could not be opened. */
+bool CRC::UpdateFile(const std::string& filename)
+{
+ FILE* fp = fopen(filename.c_str(), "rb");
+ if (!fp)
+ return false;
+
+ unsigned char buf[100000];
+ size_t bytes;
+ do {
+ bytes = fread((void*)buf, 1, 100000, fp);
+ UpdateData(buf, bytes);
+ } while (bytes == 100000);
+
+ fclose(fp);
+
+ return true;
+}
diff --git a/src/crc.h b/src/crc.h
new file mode 100644
index 0000000..54cd6b7
--- /dev/null
+++ b/src/crc.h
@@ -0,0 +1,45 @@
+#ifndef CRC_H
+#define CRC_H
+
+#include <string>
+
+/** @brief Object representing an updateable CRC-32 checksum. */
+class CRC
+{
+public:
+ CRC();
+
+ void UpdateData(const unsigned char* buf, unsigned bytes);
+ void UpdateData(const std::string& buf);
+ bool UpdateFile(const std::string& filename);
+
+ void ResetCRC();
+
+ unsigned int GetCRC() const { return crc ^ 0xFFFFFFFF; }
+
+private:
+ static unsigned int crcTable[256];
+ static void GenerateCRCTable();
+
+ unsigned int crc;
+};
+
+#endif // !CRC_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/customlistctrl.cpp b/src/customlistctrl.cpp
new file mode 100644
index 0000000..787b1e2
--- /dev/null
+++ b/src/customlistctrl.cpp
@@ -0,0 +1,353 @@
+
+#include <wx/wupdlock.h>
+#include <wx/colour.h>
+#include <wx/log.h>
+
+#include "customlistctrl.h"
+#include "utils/sltipwin.h"
+#include "utils/controls.h"
+#include "settings.h"
+#include "iconimagelist.h"
+#include "settings++/custom_dialogs.h"
+#include "uiutils.h"
+
+
+BEGIN_EVENT_TABLE(CustomListCtrl, ListBaseType)
+#if wxUSE_TIPWINDOW
+ EVT_MOTION(CustomListCtrl::OnMouseMotion)
+ EVT_TIMER(IDD_TIP_TIMER, CustomListCtrl::OnTimer)
+#endif
+ EVT_LIST_COL_BEGIN_DRAG(wxID_ANY, CustomListCtrl::OnStartResizeCol)
+ EVT_LIST_COL_END_DRAG(wxID_ANY, CustomListCtrl::OnEndResizeCol)
+ EVT_LEAVE_WINDOW(CustomListCtrl::noOp)
+ EVT_LIST_ITEM_SELECTED ( wxID_ANY, CustomListCtrl::OnSelected )
+ EVT_LIST_ITEM_DESELECTED ( wxID_ANY, CustomListCtrl::OnDeselected )
+ EVT_LIST_DELETE_ITEM ( wxID_ANY, CustomListCtrl::OnDeselected )
+END_EVENT_TABLE()
+
+
+//wxTipWindow* CustomListCtrl::m_tipwindow = 0;
+CustomListCtrl::CustomListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pt, const wxSize& sz,long style,wxString name,
+ unsigned int column_count, bool highlight, UserActions::ActionType hlaction ):
+ ListBaseType(parent, id, pt, sz, style),
+ m_tiptimer(this, IDD_TIP_TIMER),
+ m_tiptext(_T("")),
+#if wxUSE_TIPWINDOW
+ m_tipwindow( 0 ),
+ m_controlPointer( 0 ),
+#endif
+ m_columnCount( column_count ),
+ m_selected(-1),
+ m_selected_index(-1),
+ m_prev_selected(-1),
+ m_prev_selected_index(-1),
+ m_last_mouse_pos( wxPoint(-1,-1) ),
+ m_name(name),
+ m_highlight(highlight),
+ m_highlightAction(hlaction),
+ m_bg_color( GetBackgroundColour() ),
+ m_dirty_sort(false)
+{
+ //dummy init , will later be replaced with loading from settings
+ for ( unsigned int i = 0; i < m_columnCount; ++i) {
+ m_column_map[i] = i;
+
+ }
+
+ SetImageList( &icons(), wxIMAGE_LIST_NORMAL );
+ SetImageList( &icons(), wxIMAGE_LIST_SMALL );
+ SetImageList( &icons(), wxIMAGE_LIST_STATE );
+}
+
+void CustomListCtrl::InsertColumn(long i, wxListItem item, wxString tip, bool modifiable)
+{
+//#ifdef __WXMSW__ //this fixes header text misalignement
+// item.m_mask = wxLIST_MASK_FORMAT | wxLIST_MASK_TEXT;
+// if ( item.m_image != icons().ICON_EMPTY || item.m_image != -1 )
+// item.m_mask = item.m_mask | wxLIST_MASK_IMAGE;
+//
+// item.m_format = wxLIST_FORMAT_LEFT;
+//#endif
+ ListBaseType::InsertColumn(i,item);
+ colInfo temp(tip,modifiable);
+ m_colinfovec.push_back(temp);
+}
+
+void CustomListCtrl::AddColumn(long i, int width, const wxString& label, const wxString& tip, bool modifiable)
+{
+ ListBaseType::InsertColumn( i, label, wxLIST_FORMAT_LEFT, width);
+ colInfo temp(tip,modifiable);
+ m_colinfovec.push_back(temp);
+}
+
+void CustomListCtrl::SetSelectionRestorePoint()
+{
+ m_prev_selected = m_selected;
+ m_prev_selected_index = m_selected_index;
+}
+
+void CustomListCtrl::RestoreSelection()
+{
+ if ( m_prev_selected_index> -1)
+ {
+ SetItemState( GetIndexFromData( m_prev_selected ), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
+ }
+}
+
+void CustomListCtrl::ResetSelection()
+{
+ m_selected = m_prev_selected = m_prev_selected_index = m_selected_index = -1;
+}
+
+void CustomListCtrl::OnSelected( wxListEvent& event )
+{
+ m_selected = GetItemData( event.GetIndex() );
+ m_selected_index = event.GetIndex();
+ event.Skip();
+}
+
+
+void CustomListCtrl::OnDeselected( wxListEvent& event )
+{
+ if ( m_selected == (int)GetItemData( event.GetIndex() ) ) m_selected = m_selected_index = -1;
+}
+
+long CustomListCtrl::GetIndexFromData( const unsigned long data )
+{
+ for (int i = 0; i < GetItemCount() ; i++ )
+ {
+ if ( data == GetItemData( i ) )
+ return i;
+ }
+ return -1;
+}
+
+long CustomListCtrl::GetSelectedIndex()
+{
+ return m_selected_index ;
+}
+
+void CustomListCtrl::SelectAll()
+{
+ for (long i = 0; i < GetItemCount() ; i++ )
+ {
+ SetItemState( i, wxLIST_STATE_SELECTED, -1 );
+ }
+}
+
+void CustomListCtrl::SelectNone()
+{
+ for (long i = 0; i < GetItemCount() ; i++ )
+ {
+ SetItemState( i, wxLIST_STATE_DONTCARE, -1 );
+ }
+}
+
+void CustomListCtrl::SelectInverse()
+{
+ for (long i = 0; i < GetItemCount() ; i++ )
+ {
+ int state = GetItemState( i, -1 );
+ state = ( state == wxLIST_STATE_DONTCARE ? wxLIST_STATE_SELECTED : wxLIST_STATE_DONTCARE );
+ SetItemState( i, state, -1 );
+ }
+}
+
+void CustomListCtrl::SetSelectedIndex(const long newindex)
+{
+ m_selected_index = newindex;
+}
+
+long CustomListCtrl::GetSelectedData()
+{
+ return m_selected ;
+}
+
+void CustomListCtrl::OnTimer(wxTimerEvent& /*unused*/)
+{
+#if wxUSE_TIPWINDOW
+
+ if (!m_tiptext.empty())
+ {
+ m_tipwindow = new SLTipWindow(this, m_tiptext);
+ m_controlPointer = &m_tipwindow;
+ m_tipwindow->SetTipWindowPtr((wxTipWindow**)m_controlPointer);
+#ifndef __WXMSW__
+ m_tipwindow->SetBoundingRect(wxRect(1,1,50,50));
+#endif
+ m_tiptext = wxEmptyString;
+ m_tiptimer.Start(m_tooltip_duration, wxTIMER_ONE_SHOT);
+ }
+ else
+ {
+ m_tiptext = wxEmptyString;
+ m_tiptimer.Stop();
+ if (m_controlPointer!= 0 && *m_controlPointer!= 0)
+ {
+ m_tipwindow->Close();
+ m_tipwindow = 0;
+ }
+ }
+
+#endif
+}
+
+void CustomListCtrl::OnMouseMotion(wxMouseEvent& event)
+{
+#if wxUSE_TIPWINDOW
+ //we don't want to display the tooltip again until mouse has moved
+ if ( m_last_mouse_pos == event.GetPosition() )
+ return;
+
+ m_last_mouse_pos = event.GetPosition();
+
+ if (event.Leaving())
+ {
+ m_tiptext = _T("");
+ if (m_tipwindow)
+ {
+ m_tipwindow->Close();
+ m_tipwindow = 0;
+ }
+ m_tiptimer.Stop();
+ }
+ else
+ {
+ if ( m_tiptimer.IsRunning() )
+ {
+ m_tiptimer.Stop();
+ }
+
+ wxPoint position = event.GetPosition();
+
+ int flag = wxLIST_HITTEST_ONITEM;
+
+ long subItem;
+ long item_hit = HitTest(position, flag, &subItem);
+ if (item_hit != wxNOT_FOUND && item_hit>=0 && item_hit<GetItemCount())
+ {
+ // we don't really need to recover from this if it fails
+ try
+ {
+ SetTipWindowText(item_hit,m_last_mouse_pos);
+ m_tiptimer.Start(m_tooltip_delay, wxTIMER_ONE_SHOT);
+ }
+ catch ( ... ) {
+ wxLogWarning( _T("Exception setting tooltip") );
+ }
+ }
+ }
+#endif
+}
+
+void CustomListCtrl::SetTipWindowText( const long /*unused*/, const wxPoint position)
+{
+ int column = getColumnFromPosition(position);
+ if (column >= int(m_colinfovec.size()) || column < 0)
+ {
+ m_tiptext = _T("");
+ }
+ else
+ {
+ m_tiptimer.Start(m_tooltip_delay, wxTIMER_ONE_SHOT);
+ m_tiptext = TE(m_colinfovec[column].first);
+ }
+}
+
+int CustomListCtrl::getColumnFromPosition(wxPoint pos)
+{
+ int x_pos = 0;
+ for (int i = 0; i < int(m_colinfovec.size());++i)
+ {
+ x_pos += GetColumnWidth(i);
+ if (pos.x < x_pos)
+ return i;
+ }
+ return -1;
+}
+
+void CustomListCtrl::OnStartResizeCol(wxListEvent& event)
+{
+ if (!m_colinfovec[event.GetColumn()].second)
+ event.Veto();
+}
+
+void CustomListCtrl::OnEndResizeCol(wxListEvent& event)
+{
+ int column = event.GetColumn();
+ int new_size = GetColumnWidth( column );
+ sett().SetColumnWidth( m_name, column, new_size );
+
+ //let the event go further
+ event.Skip();
+}
+
+bool CustomListCtrl::SetColumnWidth(int col, int width)
+{
+ if ( sett().GetColumnWidth( m_name, col) != Settings::columnWidthUnset)
+ {
+ return ListBaseType::SetColumnWidth( col, sett().GetColumnWidth( m_name, col) );
+ }
+ else
+ {
+ sett().SetColumnWidth( m_name, col, width );
+ return ListBaseType::SetColumnWidth( col, width );
+ }
+}
+
+void CustomListCtrl::noOp(wxMouseEvent& event)
+{
+ m_tiptext = wxEmptyString;
+// m_tiptimer.Stop();
+// if (m_controlPointer!= 0 && *m_controlPointer!= 0)
+// {
+// m_tipwindow->Close();
+// m_tipwindow = 0;
+// }
+ event.Skip();
+}
+
+void CustomListCtrl::UpdateHighlights()
+{
+ wxWindowUpdateLocker noUpdates(this);
+ try {
+ long item = -1;
+ while ( true ) {
+ item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_DONTCARE);
+ if ( item == -1 )
+ break;
+ HighlightItem( item );
+ }
+ } catch(...) {}
+}
+
+void CustomListCtrl::HighlightItemUser( long item, const wxString& name )
+{
+ if ( m_highlight && useractions().DoActionOnUser( m_highlightAction, name ) ) {
+ wxColour c = sett().GetGroupHLColor( useractions().GetGroupOfUser( name ) );
+ SetItemBackgroundColour( item, c );
+ }
+ else
+ SetItemBackgroundColour( item, m_bg_color );
+}
+
+void CustomListCtrl::SetHighLightAction( UserActions::ActionType action )
+{
+ m_highlightAction = action;
+}
+
+void CustomListCtrl::MarkDirtySort()
+{
+ m_dirty_sort = true;
+}
+
+void CustomListCtrl::CancelTooltipTimer()
+{
+ m_tiptimer.Stop();
+}
+
+bool CustomListCtrl::PopupMenu(wxMenu* menu, const wxPoint& pos )
+{
+ CancelTooltipTimer();
+ return ListBaseType::PopupMenu( menu, pos );
+}
diff --git a/src/customlistctrl.h b/src/customlistctrl.h
new file mode 100644
index 0000000..283c891
--- /dev/null
+++ b/src/customlistctrl.h
@@ -0,0 +1,194 @@
+#ifndef CUSTOMLISTITEM_H_
+#define CUSTOMLISTITEM_H_
+
+#ifndef __WXMSW__
+ #include <wx/listctrl.h>
+ typedef wxListCtrl ListBaseType;
+#else
+//disabled until further fixes
+ #include <wx/msw/winundef.h>
+ // #include "Helper/listctrl.h"
+ // typedef SL_Extern::wxGenericListCtrl ListBaseType;
+ #include <wx/listctrl.h>
+ typedef wxListCtrl ListBaseType;
+#endif
+
+#include <wx/timer.h>
+#define IDD_TIP_TIMER 696
+
+#include <vector>
+#include <utility>
+#include <map>
+
+#include "useractions.h"
+
+class SLTipWindow;
+
+
+/** \brief Used as base class for all ListCtrls throughout SL
+ * Provides generic functionality, such as column tooltips, possiblity to prohibit column resizing and selection modifiers. \n
+ * Some of the provided functionality only makes sense for single-select lists (see grouping) \n
+ * Note: Tooltips are a bitch and anyone shoudl feel to revise them (koshi)
+ */
+class CustomListCtrl : public ListBaseType
+{
+protected:
+ typedef UserActions::ActionType ActionType;
+ //! used to display tooltips for a certain amount of time
+ wxTimer m_tiptimer;
+ //! always set to the currrently displayed tooltip text
+ wxString m_tiptext;
+ #if wxUSE_TIPWINDOW
+ //! some wx implementations do not support this yet
+ SLTipWindow* m_tipwindow;
+ SLTipWindow** m_controlPointer;
+ #endif
+ unsigned int m_columnCount;
+
+ typedef std::pair<wxString,bool> colInfo;
+ typedef std::vector<colInfo> colInfoVec;
+
+ //! maps outward column index to internal
+ typedef std::map<unsigned int,unsigned int> ColumnMap;
+
+ /** global Tooltip thingies (ms)
+ */
+ static const unsigned int m_tooltip_delay = 1000;
+ static const unsigned int m_tooltip_duration = 2000;
+
+/*** these are only meaningful in single selection lists ***/
+ //! curently selected data
+ long m_selected;
+ //! index of curently selected data
+ long m_selected_index;
+ //! previously selected data
+ long m_prev_selected;
+ //! index of previously selected data
+ long m_prev_selected_index;
+/***********************************************************/
+
+ //! stores info about the columns (wxString name,bool isResizable) - pairs
+ colInfoVec m_colinfovec;
+ //! primarily used to get coulumn index in mousevents (from cur. mouse pos)
+ int getColumnFromPosition(wxPoint pos);
+
+ wxPoint m_last_mouse_pos;
+
+ //! used as label for saving column widths
+ wxString m_name;
+
+ //!controls if highlighting should be considered
+ bool m_highlight;
+
+ //! which action should be considered?
+ ActionType m_highlightAction;
+
+ const wxColour m_bg_color;
+
+ //! list should be sorted
+ bool m_dirty_sort;
+
+ virtual void SetTipWindowText( const long item_hit, const wxPoint position);
+
+ ColumnMap m_column_map;
+
+ struct SortOrderItem {
+ int col;
+ int direction;
+ };
+ typedef std::map<int,SortOrderItem> SortOrder;
+ SortOrder m_sortorder;
+
+public:
+ CustomListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pt,
+ const wxSize& sz,long style, wxString name, unsigned int column_count, bool highlight = true,
+ UserActions::ActionType hlaction = UserActions::ActHighlight);
+
+ virtual ~CustomListCtrl(){}
+
+ void OnSelected( wxListEvent& event );
+ void OnDeselected( wxListEvent& event );
+ /** @name Single Selection methods
+ * using these funcs in a multi selection list is meaingless at best, harmful in the worst case
+ * \todo insert debug asserts to catch that
+ * @{
+ */
+ long GetSelectedIndex();
+ void SetSelectedIndex(const long newindex);
+ long GetSelectedData();
+ long GetIndexFromData( const unsigned long data );
+ //! call this before example before sorting, inserting, etc
+ void SetSelectionRestorePoint();
+ void ResetSelection();
+ //! and this afterwards
+ void RestoreSelection();
+ /** @}
+ */
+
+ //! intermediate function to add info to m_colinfovec after calling base class function
+ void InsertColumn(long i, wxListItem item, wxString tip, bool = true);
+ void AddColumn(long i, int width, const wxString& label, const wxString& tip, bool = true);
+ //! this event is triggered when delay timer (set in mousemotion) ended
+ virtual void OnTimer(wxTimerEvent& event);
+ //! prohibits resizin if so set in columnInfo
+ void OnStartResizeCol(wxListEvent& event);
+ //! we use this to automatically save column width after resizin
+ virtual void OnEndResizeCol(wxListEvent& event);
+ //! starts timer, sets tooltiptext
+ virtual void OnMouseMotion(wxMouseEvent& event);
+ //! stop timer (before displaying popup f.e.)
+ void CancelTooltipTimer();
+ //!Override to have tooltip timer cancelled automatically
+ bool PopupMenu(wxMenu* menu, const wxPoint& pos = wxDefaultPosition);
+ //! does nothing
+ void noOp(wxMouseEvent& event);
+ //! automatically get saved column width if already saved, otherwise use parameter and save new width
+ virtual bool SetColumnWidth(int col, int width);
+
+ // funcs that should make things easier for group highlighting
+ ///all that needs to be implemented in child class for UpdateHighlights to work
+ virtual void HighlightItem( long item ) = 0;
+ void HighlightItemUser( long item, const wxString& name );
+ void UpdateHighlights();
+ void SetHighLightAction( UserActions::ActionType action );
+
+
+ /** @name Multi Selection methods
+ * using these funcs in a single selection list is meaingless at best, harmful in the worst case
+ * \todo insert debug asserts to catch that
+ * @{
+ */
+ void SelectAll();
+ void SelectInverse();
+ /** @}
+ */
+
+ //! sets selected index to -1
+ void SelectNone();
+
+ //! marks the items in the control to be sorted
+ void MarkDirtySort();
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+#endif /*CUSTOMLISTITEM_H_*/
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/customvirtlistctrl.cpp b/src/customvirtlistctrl.cpp
new file mode 100644
index 0000000..e084801
--- /dev/null
+++ b/src/customvirtlistctrl.cpp
@@ -0,0 +1,606 @@
+
+#include <wx/colour.h>
+#include <wx/log.h>
+
+#include "nonportable.h" //pulls in the SL_DUMMY_COL define if applicable
+#include "settings.h"
+#include "iconimagelist.h"
+#include "settings++/custom_dialogs.h"
+#include "uiutils.h"
+#include "utils/sltipwin.h"
+#include "utils/math.h"
+#include "utils/controls.h"
+
+#include <algorithm>
+
+
+BEGIN_EVENT_TABLE_TEMPLATE2(CustomVirtListCtrl, ListBaseType, T,L)
+#if wxUSE_TIPWINDOW
+ EVT_MOTION(CustomVirtListCtrl::OnMouseMotion)
+ EVT_TIMER(IDD_TIP_TIMER, CustomVirtListCtrl::OnTimer)
+#endif
+ EVT_LIST_COL_BEGIN_DRAG(wxID_ANY, CustomVirtListCtrl::OnStartResizeCol)
+ EVT_LIST_COL_END_DRAG(wxID_ANY, CustomVirtListCtrl::OnEndResizeCol)
+ EVT_LEAVE_WINDOW(CustomVirtListCtrl::noOp)
+ EVT_LIST_ITEM_SELECTED ( wxID_ANY, CustomVirtListCtrl::OnSelected )
+ EVT_LIST_ITEM_DESELECTED ( wxID_ANY, CustomVirtListCtrl::OnDeselected )
+ EVT_LIST_DELETE_ITEM ( wxID_ANY, CustomVirtListCtrl::OnDeselected )
+ EVT_LIST_COL_CLICK ( wxID_ANY, CustomVirtListCtrl::OnColClick )
+END_EVENT_TABLE()
+
+
+template < class T, class L >
+CustomVirtListCtrl<T,L>::CustomVirtListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pt, const wxSize& sz,
+ long style, const wxString& name, unsigned int column_count, unsigned int sort_criteria_count,
+ CompareFunction func, bool highlight, UserActions::ActionType hlaction, bool periodic_sort, unsigned int periodic_sort_interval )
+ : ListBaseType(parent, id, pt, sz, style | wxLC_VIRTUAL),
+ m_tiptimer(this, IDD_TIP_TIMER),
+ m_sort_timer(this, IDD_SORT_TIMER),
+ m_tiptext(_T("")),
+#if wxUSE_TIPWINDOW
+ m_tipwindow( 0 ),
+ m_controlPointer( 0 ),
+#endif
+#ifndef SL_DUMMY_COL
+ m_columnCount( column_count ),
+#else
+ m_columnCount( column_count + 1 ),
+#endif
+ m_selected_index(-1),
+ m_prev_selected_index(-1),
+ m_last_mouse_pos( wxPoint(-1,-1) ),
+ m_name(name),
+ m_highlight(highlight),
+ m_highlightAction(hlaction),
+ m_bg_color( GetBackgroundColour() ),
+ m_dirty_sort(false),
+ m_sort_criteria_count( sort_criteria_count ),
+ m_comparator( m_sortorder, func ),
+ m_periodic_sort_timer_id( wxNewId() ),
+ m_periodic_sort_timer( this, m_periodic_sort_timer_id ),
+ m_periodic_sort( periodic_sort ),
+ m_periodic_sort_interval( periodic_sort_interval )
+{
+ //dummy init , will later be replaced with loading from settings
+ for ( unsigned int i = 0; i < m_columnCount; ++i) {
+ m_column_map[i] = i;
+
+ }
+
+ SetImageList( &icons(), wxIMAGE_LIST_NORMAL );
+ SetImageList( &icons(), wxIMAGE_LIST_SMALL );
+ SetImageList( &icons(), wxIMAGE_LIST_STATE );
+ m_sortorder = sett().GetSortOrder( name );
+ #ifdef SL_DUMMY_COL //a little duplication here, but the AddColumn method will be altered when this is defined
+ ListBaseType::InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, 0 );
+ ListBaseType::SetColumnWidth( 0, 0 );
+ colInfo temp( 0, wxEmptyString, wxEmptyString, false, 0 );
+ m_colinfovec.push_back( temp );
+ #endif
+
+ if ( m_periodic_sort )
+ {
+ wxTimerEvent a;
+ wxEventType evt_type = a.GetEventType();
+ Connect( m_periodic_sort_timer_id, evt_type, wxTimerEventHandler( ThisType::OnPeriodicSort ) );
+ bool started = m_periodic_sort_timer.Start( m_periodic_sort_interval );
+ assert( started );
+ }
+
+}
+
+template < class T, class L >
+CustomVirtListCtrl<T,L>::~CustomVirtListCtrl()
+{
+ sett().SetSortOrder( m_name, m_sortorder );
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::AddColumn(long i, int width, const wxString& label, const wxString& tip, bool modifiable)
+{
+ #ifdef SL_DUMMY_COL
+ i++;
+ #endif
+ ListBaseType::InsertColumn( i, label, wxLIST_FORMAT_LEFT, width);
+ SetColumnWidth( i, width );
+ colInfo temp( i, label, tip, modifiable, width );
+ m_colinfovec.push_back( temp );
+}
+
+
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SaveSelection()
+{
+ ResetSelection();
+
+ long item = -1;
+ while ( true )
+ {
+ item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+ if ( item == -1 )
+ break;
+ m_selected_data.push_back( m_data[item] );
+ }
+
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::RestoreSelection()
+{
+ while ( m_selected_data.size() > 0 )
+ {
+ SelectedDataType data = m_selected_data.back();
+ m_selected_data.pop_back();
+ int idx = GetIndexFromData( data );
+ SetItemState( idx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
+ }
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::ResetSelection()
+{
+ m_selected_data.clear();
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnSelected( wxListEvent& event )
+{
+ m_selected_index = event.GetIndex();
+ event.Skip();
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnDeselected( wxListEvent& event )
+{
+ if ( m_selected_index == event.GetIndex() )
+ m_selected_index = -1;
+}
+
+template < class T, class L >
+long CustomVirtListCtrl<T,L>::GetSelectedIndex()
+{
+ return m_selected_index ;
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SelectAll()
+{
+ for (long i = 0; i < GetItemCount() ; i++ )
+ {
+ SetItemState( i, wxLIST_STATE_SELECTED, -1 );
+ }
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SelectNone()
+{
+ for (long i = 0; i < GetItemCount() ; i++ )
+ {
+ SetItemState( i, wxLIST_STATE_DONTCARE, -1 );
+ }
+}
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SelectInverse()
+{
+ for (long i = 0; i < GetItemCount() ; i++ )
+ {
+ int state = GetItemState( i, -1 );
+ state = ( state == wxLIST_STATE_DONTCARE ? wxLIST_STATE_SELECTED : wxLIST_STATE_DONTCARE );
+ SetItemState( i, state, -1 );
+ }
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SetSelectedIndex(const long newindex)
+{
+ m_selected_index = newindex;
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::RefreshVisibleItems()
+{
+#ifndef __WXMSW__
+ long topItemIndex = GetTopItem();
+ long range = topItemIndex + GetCountPerPage();
+ //RefreshItems( topItemIndex, clamp( range, topItemIndex, (long) m_data.size() ) );
+ RefreshItems( topItemIndex, range );
+#else
+ RefreshItems( 0, m_data.size() -1 );
+#endif
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnTimer(wxTimerEvent& /*unused*/ )
+{
+#if wxUSE_TIPWINDOW
+
+ if (!m_tiptext.empty())
+ {
+ m_tipwindow = new SLTipWindow(this, m_tiptext);
+ m_controlPointer = &m_tipwindow;
+ m_tipwindow->SetTipWindowPtr((wxTipWindow**)m_controlPointer);
+#ifndef __WXMSW__
+ m_tipwindow->SetBoundingRect(wxRect(1,1,50,50));
+#endif
+ m_tiptext = wxEmptyString;
+ m_tiptimer.Start(m_tooltip_duration, wxTIMER_ONE_SHOT);
+ }
+ else
+ {
+ m_tiptext = wxEmptyString;
+ m_tiptimer.Stop();
+ if (m_controlPointer!= 0 && *m_controlPointer!= 0)
+ {
+ m_tipwindow->Close();
+ m_tipwindow = 0;
+ }
+ }
+
+#endif
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnMouseMotion(wxMouseEvent& event)
+{
+ m_sort_timer.Stop();
+ m_sort_timer.Start( m_sort_block_time , wxTIMER_ONE_SHOT );
+#if wxUSE_TIPWINDOW
+ //we don't want to display the tooltip again until mouse has moved
+ if ( m_last_mouse_pos == event.GetPosition() )
+ return;
+
+ m_last_mouse_pos = event.GetPosition();
+
+ if (event.Leaving())
+ {
+ m_tiptext = _T("");
+ if (m_tipwindow)
+ {
+ m_tipwindow->Close();
+ m_tipwindow = 0;
+ }
+ m_tiptimer.Stop();
+ }
+ else
+ {
+ if ( m_tiptimer.IsRunning() )
+ {
+ m_tiptimer.Stop();
+ }
+
+ wxPoint position = event.GetPosition();
+
+ int flag = wxLIST_HITTEST_ONITEM;
+
+#ifdef HAVE_WX28
+ long subItem;
+ long item_hit = HitTest(position, flag, &subItem);
+#else
+ long item_hit = HitTest(position, flag);
+#endif
+ if (item_hit != wxNOT_FOUND && item_hit>=0 && item_hit<GetItemCount())
+ {
+ // we don't really need to recover from this if it fails
+ try
+ {
+ SetTipWindowText(item_hit,m_last_mouse_pos);
+ m_tiptimer.Start(m_tooltip_delay, wxTIMER_ONE_SHOT);
+ }
+ catch ( ... ) {
+ wxLogWarning( _T("Exception setting tooltip") );
+ }
+ }
+ }
+#endif
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SetTipWindowText( const long /*unused*/ , const wxPoint& position)
+{
+ int column = getColumnFromPosition(position);
+ #ifdef SL_DUMMY_COL
+ column++;
+ #endif
+ if (column >= int(m_colinfovec.size()) || column < 0)
+ {
+ m_tiptext = _T("");
+ }
+ else
+ {
+ m_tiptimer.Start(m_tooltip_delay, wxTIMER_ONE_SHOT);
+ m_tiptext = TE(m_colinfovec[column].tip);
+ }
+}
+
+template < class T, class L >
+int CustomVirtListCtrl<T,L>::getColumnFromPosition(wxPoint pos)
+{
+ int x_pos = 0;
+ for (int i = 0; i < int(m_colinfovec.size());++i)
+ {
+ x_pos += GetColumnWidth(i);
+ if (pos.x < x_pos)
+ #ifdef SL_DUMMY_COL
+ return i-1;
+ #else
+ return i;
+ #endif
+ }
+ return -1;
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnStartResizeCol(wxListEvent& event)
+{
+ if (!m_colinfovec[event.GetColumn()].can_resize)
+ event.Veto();
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnEndResizeCol(wxListEvent& event)
+{
+ int column = event.GetColumn();
+ int new_size = GetColumnWidth( column );
+ sett().SetColumnWidth( m_name, column, new_size );
+ sett().SaveSettings();
+
+ //let the event go further
+ event.Skip();
+}
+
+template < class T, class L >
+bool CustomVirtListCtrl<T,L>::SetColumnWidth(int col, int width)
+{
+ if ( sett().GetColumnWidth( m_name, col) != Settings::columnWidthUnset)
+ {
+ return ListBaseType::SetColumnWidth( col, sett().GetColumnWidth( m_name, col) );
+ }
+ else
+ {
+ sett().SetColumnWidth( m_name, col, width );
+ return ListBaseType::SetColumnWidth( col, width );
+ }
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::noOp(wxMouseEvent& event)
+{
+ m_tiptext = wxEmptyString;
+// m_tiptimer.Stop();
+// if (m_controlPointer!= 0 && *m_controlPointer!= 0)
+// {
+// m_tipwindow->Close();
+// m_tipwindow = 0;
+// }
+ event.Skip();
+}
+
+template < class T, class L >
+wxListItemAttr* CustomVirtListCtrl<T,L>::HighlightItemUser( const wxString& name ) const
+{
+ static wxListItemAttr att;
+ if ( m_highlight && useractions().DoActionOnUser( m_highlightAction, name ) ) {
+ att.SetBackgroundColour( sett().GetGroupHLColor( useractions().GetGroupOfUser( name ) ) );
+ return &att;
+ }
+ else
+ return NULL;
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SetHighLightAction( UserActions::ActionType action )
+{
+ m_highlightAction = action;
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::MarkDirtySort()
+{
+ m_dirty_sort = true;
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::CancelTooltipTimer()
+{
+ m_tiptimer.Stop();
+}
+
+template < class T, class L >
+bool CustomVirtListCtrl<T,L>::PopupMenu(wxMenu* menu, const wxPoint& pos )
+{
+ CancelTooltipTimer();
+ return ListBaseType::PopupMenu( menu, pos );
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::SortList( bool force )
+{
+ if ( ( m_sort_timer.IsRunning() || !m_dirty_sort ) && !force )
+ return;
+ SelectionSaver<ThisType>(*this);
+ Freeze();
+ Sort();
+ Thaw();
+ m_dirty_sort = false;
+ RefreshVisibleItems();
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::Clear()
+{
+ m_data.clear();
+ SetItemCount( 0 );
+ ResetSelection();
+ RefreshVisibleItems();
+}
+
+template < class T, class L >
+typename CustomVirtListCtrl<T,L>::DataType CustomVirtListCtrl<T,L>::GetDataFromIndex ( const long index )
+{
+ return m_data[index];
+}
+
+template < class T, class L >
+const typename CustomVirtListCtrl<T,L>::DataType CustomVirtListCtrl<T,L>::GetDataFromIndex ( const long index ) const
+{
+ return m_data[index];
+}
+
+template < class T, class L >
+typename CustomVirtListCtrl<T,L>::DataType CustomVirtListCtrl<T,L>::GetSelectedData()
+{
+ return GetDataFromIndex( m_selected_index );
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::ResetColumnSizes()
+{
+ typename colInfoVec::const_iterator it = m_colinfovec.begin();
+ for ( ; it != m_colinfovec.end(); ++it )
+ SetColumnWidth( it->col_num, it->size );
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnColClick( wxListEvent& event )
+{
+ if ( event.GetColumn() == -1 )
+ return;
+
+ #ifdef SL_DUMMY_COL
+ if ( event.GetColumn() == 0 )
+ return;
+ const int evt_col = event.GetColumn()-1;
+ #else
+ const int evt_col = event.GetColumn();
+ #endif
+
+ m_sort_timer.Stop();//otherwise sorting will be way delayed
+
+ int old_sort_col = m_sortorder[0].col;
+
+ wxListItem col;
+ GetColumn( m_sortorder[0].col, col );
+ col.SetImage( icons().ICON_NONE );
+ SetColumn( m_sortorder[0].col, col );
+
+ unsigned int i = 0;
+ SortOrder::const_iterator it = m_sortorder.begin();
+ for ( ; it != m_sortorder.begin(); ++i, ++it ) {
+ if ( m_sortorder[i].col == evt_col )
+ break;
+ }
+
+// for ( ; m_sortorder[i].col != event.GetColumn() && i < 4; ++i ) {}
+
+ i = clamp( i, (unsigned int)0, m_sort_criteria_count );
+
+ for ( ; i > 0; i--) {
+ m_sortorder[i] = m_sortorder[i-1];
+ }
+
+ m_sortorder[0].col = evt_col;
+ m_sortorder[0].direction *= -1;
+
+
+ GetColumn( m_sortorder[0].col, col );
+ //col.SetImage( ( m_sortorder[0].direction )?ICON_UP:ICON_DOWN );
+ col.SetImage( ( m_sortorder[0].direction > 0 )?icons().ICON_UP:icons().ICON_DOWN );
+ SetColumn( m_sortorder[0].col, col );
+
+ if ( old_sort_col != m_sortorder[0].col )
+ SortList( true );
+ else { // O(n) instead of guaranteed worst case O(n*n)
+ ReverseOrder();
+ }
+}
+
+template < class T, class L >
+bool CustomVirtListCtrl<T,L>::GetColumn(int col, wxListItem& item) const
+{
+ #ifdef SL_DUMMY_COL
+ col++;
+ #endif
+ return ListBaseType::GetColumn( col, item );
+}
+
+template < class T, class L >
+bool CustomVirtListCtrl<T,L>::SetColumn(int col, wxListItem& item)
+{
+ #ifdef SL_DUMMY_COL
+ col++;
+ #endif
+ return ListBaseType::SetColumn( col, item );
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::ReverseOrder()
+{
+ SaveSelection();
+ std::reverse( m_data.begin(), m_data.end() );
+ RefreshVisibleItems();
+ RestoreSelection();
+}
+
+template < class T, class L >
+bool CustomVirtListCtrl<T,L>::AddItem( const T item )
+{
+ if ( GetIndexFromData( item ) != -1 )
+ return false;
+
+ m_data.push_back( item );
+ SetItemCount( m_data.size() );
+ RefreshItem( m_data.size() - 1 );
+ //SetColumnWidth( 5, wxLIST_AUTOSIZE ); //! TODO does this really work?
+ MarkDirtySort();
+ return true;
+}
+
+template < class T, class L >
+bool CustomVirtListCtrl<T,L>::RemoveItem( const T item )
+{
+ int index = GetIndexFromData( item );
+
+ if ( index != -1 ) {
+ SelectionSaver<ThisType>(*this);
+ m_data.erase( m_data.begin() + index );
+ SetItemCount( m_data.size() );
+ RefreshItems( index, m_data.size() -1 );
+ return true;
+ }
+ return false;
+}
+
+template < class T, class L >
+wxString CustomVirtListCtrl<T,L>::OnGetItemText(long item, long column) const
+{
+ #ifdef SL_DUMMY_COL
+ if ( column < 1 )
+ return wxEmptyString;
+ column--;
+ #endif
+ return asImp().GetItemText(item, column);
+}
+
+template < class T, class L >
+int CustomVirtListCtrl<T,L>::OnGetItemColumnImage(long item, long column) const
+{
+ #ifdef SL_DUMMY_COL
+ if ( column < 1 )
+ return -1;
+ column--;
+ #endif
+ return asImp().GetItemColumnImage(item, column);
+}
+
+template < class T, class L >
+wxListItemAttr* CustomVirtListCtrl<T,L>::OnGetItemAttr(long item) const
+{
+ return asImp().GetItemAttr(item);
+}
+
+template < class T, class L >
+void CustomVirtListCtrl<T,L>::OnPeriodicSort( wxTimerEvent& /*unused*/ )
+{
+ SortList();
+}
diff --git a/src/customvirtlistctrl.h b/src/customvirtlistctrl.h
new file mode 100644
index 0000000..313d778
--- /dev/null
+++ b/src/customvirtlistctrl.h
@@ -0,0 +1,378 @@
+#ifndef CUSTOMVIRTLISTITEM_H_
+#define CUSTOMVIRTLISTITEM_H_
+
+#ifndef __WXMSW__
+ #include <wx/listctrl.h>
+ typedef wxListCtrl ListBaseType;
+#else
+//disabled until further fixes
+// #include "Helper/listctrl.h"
+// typedef SL_Extern::wxGenericListCtrl ListBaseType;
+ #include <wx/listctrl.h>
+ typedef wxListCtrl ListBaseType;
+#endif
+
+#include <wx/timer.h>
+#define IDD_TIP_TIMER 696
+#define IDD_SORT_TIMER 697
+
+#include <vector>
+
+#include <utility>
+#include <map>
+
+#include "useractions.h"
+#include "Helper/sortutil.h"
+
+class SLTipWindow;
+
+/** \brief Used as base class for some ListCtrls throughout SL
+ * Provides generic functionality, such as column tooltips, possiblity to prohibit column resizing and selection modifiers. \n
+ * Some of the provided functionality only makes sense for single-select lists (see grouping) \n
+ * Note: the second template param is actually just a dummy to ensure the compiler generates distinct code in case we have different listctrls with same datatype
+ * Note: Tooltips are a bitch and anyone should feel free to revise them (koshi)
+ * \tparam the type of stored data
+ */
+template < class DataImp, class ListCtrlImp >
+class CustomVirtListCtrl : public ListBaseType
+{
+public:
+ typedef DataImp
+ DataType;
+
+protected:
+ typedef UserActions::ActionType ActionType;
+ //! used to display tooltips for a certain amount of time
+ wxTimer m_tiptimer;
+ //! used to block sorting while mouse is moving
+ wxTimer m_sort_timer;
+ //! always set to the currrently displayed tooltip text
+ wxString m_tiptext;
+ #if wxUSE_TIPWINDOW
+ //! some wx implementations do not support this yet
+ SLTipWindow* m_tipwindow;
+ SLTipWindow** m_controlPointer;
+ #endif
+ unsigned int m_columnCount;
+
+ struct colInfo {
+ colInfo(int n, wxString l, wxString t, bool c, int s):
+ col_num(n),label(l),tip(t),can_resize(c),size(s) {}
+ colInfo(){}
+
+ int col_num;
+ wxString label;
+ wxString tip;
+ bool can_resize;
+ int size;
+ };
+
+ typedef std::vector<colInfo> colInfoVec;
+
+ //! maps outward column index to internal
+ typedef std::map<unsigned int,unsigned int> ColumnMap;
+
+ /** global Tooltip thingies (ms)
+ */
+ static const unsigned int m_tooltip_delay = 1000;
+ static const unsigned int m_tooltip_duration = 2000;
+ static const unsigned int m_sort_block_time = 1500;
+
+/*** these are only meaningful in single selection lists ***/
+ //! index of curently selected data
+ long m_selected_index;
+
+ //! index of previously selected data
+ long m_prev_selected_index;
+/***********************************************************/
+
+ //! stores info about the columns (wxString name,bool isResizable) - pairs
+ colInfoVec m_colinfovec;
+ //! primarily used to get coulumn index in mousevents (from cur. mouse pos)
+ int getColumnFromPosition(wxPoint pos);
+
+ //! map: index in visible list <--> index in data vector
+ typedef std::map<int,int> VisibilityMap;
+ typedef VisibilityMap::iterator VisibilityMapIter;
+ /** \brief list indexes of not-filtered items
+ * use like this: when adding items set identity mapping \n
+ m_visible_idxs[m_data.size() -1] = ( m_data.size() -1 ); \n
+ when filtering clear the map, iterate thru data and only set mapping for matching items in data \n
+ when acessing data (getColoumText etc.) always access data's index thru this map
+ **/
+ VisibilityMap m_visible_idxs;
+
+
+ wxPoint m_last_mouse_pos;
+
+ //! used as label for saving column widths
+ wxString m_name;
+
+ //!controls if highlighting should be considered
+ bool m_highlight;
+
+ //! which action should be considered?
+ ActionType m_highlightAction;
+
+ const wxColour m_bg_color;
+
+ //! list should be sorted
+ bool m_dirty_sort;
+
+ virtual void SetTipWindowText( const long item_hit, const wxPoint& position);
+
+ ColumnMap m_column_map;
+
+ /** @name Sort functionality
+ *
+ * @{
+ */
+
+ static SortOrder m_sortorder;
+ unsigned int m_sort_criteria_count;
+
+ /** generic comparator that gets it's real functionality
+ * in derived classes via comapre callbakc func that
+ * performs the actual comparison of two items **/
+ template < class ObjImp >
+ struct ItemComparator
+ {
+ typedef ObjImp ObjType;
+ SortOrder& m_order;
+ typedef int (*CmpFunc) ( ObjType u1, ObjType u2, int, int );
+ CmpFunc m_cmp_func;
+ const unsigned int m_num_criteria;
+
+ /** \param order SortOrder map that defines which columns should be sorted in what directions
+ * \param func the comparison callback func. Should return -1,0,1 for less,equal,greater
+ * \param num_criteria set to 1,2 to limit sub-ordering
+ * \todo make order const reference to eliminate assumption about existence of entries
+ */
+ ItemComparator( SortOrder& order,CmpFunc func, const unsigned int num_criteria = 3 )
+ :m_order(order),
+ m_cmp_func(func),
+ m_num_criteria(num_criteria)
+ {}
+
+ bool operator () ( ObjType u1, ObjType u2 ) const
+ {
+ int res = m_cmp_func( u1, u2, m_order[0].col, m_order[0].direction );
+ if ( res != 0 )
+ return res < 0;
+
+ if ( m_num_criteria > 1 ) {
+ res = m_cmp_func( u1, u2, m_order[1].col, m_order[1].direction );
+ if ( res != 0 )
+ return res < 0;
+
+ if ( m_num_criteria > 2 ) {
+ res = m_cmp_func( u1, u2, m_order[2].col, m_order[2].direction );
+ if ( res != 0 )
+ return res < 0;
+ }
+ }
+ return false;
+ }
+ };
+
+ typedef typename ItemComparator<DataImp>::CmpFunc CompareFunction;
+
+ //! compare func usable for types with well-defined ordering (and implemented ops <,>)
+ template < typename Type >
+ static inline int compareSimple( Type o1, Type o2 ) {
+ if ( o1 < o2 )
+ return -1;
+ else if ( o1 > o2 )
+ return 1;
+ return 0;
+ }
+
+ //! must be implemented in derived classes, should call the actual sorting on data and refreshitems
+ virtual void Sort( ) = 0;
+
+public:
+ /** only sorts if data is marked dirty, or force is true
+ * calls Freeze(), Sort(), Thaw() */
+ void SortList( bool force = false );
+ /** @}
+ */
+
+public:
+ CustomVirtListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pt,
+ const wxSize& sz,long style, const wxString& name, unsigned int column_count, unsigned int sort_criteria_count, CompareFunction func, bool highlight = true,
+ UserActions::ActionType hlaction = UserActions::ActHighlight, bool periodic_sort = false, unsigned int periodic_sort_interval = 5000 /*miliseconds*/);
+
+ virtual ~CustomVirtListCtrl();
+
+ void OnSelected( wxListEvent& event );
+ void OnDeselected( wxListEvent& event );
+ /** @name Single Selection methods
+ * using these funcs in a multi selection list is meaningless at best, harmful in the worst case
+ * \todo insert debug asserts to catch that
+ * @{
+ */
+ long GetSelectedIndex();
+ void SetSelectedIndex(const long newindex);
+ DataType GetDataFromIndex ( const long index );
+ const DataType GetDataFromIndex ( const long index ) const;
+ DataType GetSelectedData();
+ /** @}
+ */
+
+ /** @name Multi Selection methods
+ * call this before example before sorting, inserting, etc
+ */
+ void SaveSelection();
+ void ResetSelection();
+ //! and this afterwards
+ void RestoreSelection();
+ /** @}
+ */
+
+ //! intermediate function to add info to m_colinfovec after calling base class function
+ void AddColumn(long i, int width, const wxString& label, const wxString& tip, bool = true);
+ //! this event is triggered when delay timer (set in mousemotion) ended
+ virtual void OnTimer(wxTimerEvent& event);
+ //! prohibits resizin if so set in columnInfo
+ void OnStartResizeCol(wxListEvent& event);
+ //! we use this to automatically save column width after resizin
+ virtual void OnEndResizeCol(wxListEvent& event);
+ //! starts timer, sets tooltiptext
+ virtual void OnMouseMotion(wxMouseEvent& event);
+ //! stop timer (before displaying popup f.e.)
+ void CancelTooltipTimer();
+ //!Override to have tooltip timer cancelled automatically
+ bool PopupMenu(wxMenu* menu, const wxPoint& pos = wxDefaultPosition);
+ //! does nothing
+ void noOp(wxMouseEvent& event);
+ //! automatically get saved column width if already saved, otherwise use parameter and save new width
+ virtual bool SetColumnWidth(int col, int width);
+ //! reset columns with current set size (only effects columns with auto-size)
+ void ResetColumnSizes();
+
+ // funcs that should make things easier for group highlighting
+ ///all that needs to be implemented in child class for UpdateHighlights to work
+
+ wxListItemAttr* HighlightItemUser( const wxString& name ) const;
+
+ void SetHighLightAction( UserActions::ActionType action );
+ void RefreshVisibleItems();
+
+ /** @name Multi Selection methods
+ * using these funcs in a single selection list is meaingless at best, harmful in the worst case
+ * \todo insert debug asserts to catch that
+ * @{
+ */
+ void SelectAll();
+ void SelectInverse();
+ /** @}
+ */
+
+ //! sets selected index to -1
+ void SelectNone();
+
+ //! marks the items in the control to be sorted
+ void MarkDirtySort();
+
+ /** @name overloaded wxFunctions
+ * these are used to display items in virtual lists
+ * @{
+ */
+ wxString OnGetItemText(long item, long column) const;
+ int OnGetItemColumnImage(long item, long column) const;
+ wxListItemAttr* OnGetItemAttr(long item) const;
+
+ //! when using the dummy column, we provide diff impl that adjust for that
+ bool GetColumn(int col, wxListItem& item) const;
+ bool SetColumn(int col, wxListItem& item);
+ /** @}
+ */
+
+ //! delete all data, selections, and whatnot
+ virtual void Clear();
+
+ //! handle sort order updates
+ void OnColClick( wxListEvent& event );
+
+ virtual int GetIndexFromData( const DataType& data ) const = 0;
+
+ void ReverseOrder();
+
+protected:
+ typedef CustomVirtListCtrl< DataImp, ListCtrlImp >
+ BaseType;
+ typedef std::vector< DataImp >
+ DataVector;
+ typedef typename DataVector::iterator
+ DataIter;
+ typedef typename DataVector::const_iterator
+ DataCIter;
+ typedef typename DataVector::reverse_iterator
+ DataRevIter;
+ typedef typename DataVector::const_reverse_iterator
+ DataRevCIter;
+ DataVector m_data;
+
+ typedef DataType
+ SelectedDataType;
+ typedef std::vector< SelectedDataType >
+ SelectedDataVector;
+ SelectedDataVector m_selected_data;
+
+ //! the Comparator object passed to the SLInsertionSort function
+ ItemComparator<DataType> m_comparator;
+
+ bool RemoveItem( const DataImp item );
+ bool AddItem( const DataImp item );
+
+ long m_periodic_sort_timer_id;
+ wxTimer m_periodic_sort_timer;
+ bool m_periodic_sort;
+ unsigned int m_periodic_sort_interval;
+ void OnPeriodicSort( wxTimerEvent& evt );
+
+public:
+ DECLARE_EVENT_TABLE()
+
+private:
+ typedef BaseType
+ ThisType;
+
+ ListCtrlImp& asImp() { return static_cast<ListCtrlImp&>(*this); }
+ const ListCtrlImp& asImp() const { return static_cast<const ListCtrlImp&>(*this); }
+};
+
+template < class ListCtrlType >
+class SelectionSaver {
+ ListCtrlType& m_list;
+
+public:
+ SelectionSaver( ListCtrlType& list )
+ : m_list( list )
+ { m_list.SaveSelection(); }
+
+ ~SelectionSaver()
+ { m_list.RestoreSelection(); }
+};
+
+#include "customvirtlistctrl.cpp"
+
+#endif /*CUSTOMLISTITEM_H_*/
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/filelister/filelistctrl.cpp b/src/filelister/filelistctrl.cpp
new file mode 100644
index 0000000..c324917
--- /dev/null
+++ b/src/filelister/filelistctrl.cpp
@@ -0,0 +1,254 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#ifndef NO_TORRENT_SYSTEM
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/intl.h>
+#include <wx/menu.h>
+#include <wx/string.h>
+
+#include "filelistctrl.h"
+#include "filelistdialog.h"
+#include "../utils/conversion.h"
+#include "../iconimagelist.h"
+#include "../uiutils.h"
+
+
+BEGIN_EVENT_TABLE( FileListCtrl, CustomListCtrl )
+
+ EVT_LIST_ITEM_RIGHT_CLICK( FILELIST_COL_CLICK, FileListCtrl::OnListRightClick )
+ EVT_LIST_COL_CLICK( FILELIST_COL_CLICK, FileListCtrl::OnColClick )
+ #if wxUSE_TIPWINDOW
+ #if !defined(__WXMSW__) /* && !defined(__WXMAC__) */ //disables tooltips on msw /* and mac */
+ EVT_MOTION( FileListCtrl::OnMouseMotion )
+ #endif
+ #endif
+END_EVENT_TABLE()
+
+FileListDialog* FileListCtrl::s_parent_dialog = 0;
+
+FileListCtrl::FileListCtrl( wxWindow* parent, FileListDialog* fld ):
+ CustomListCtrl( parent, FILELIST_COL_CLICK, wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT | wxLC_ALIGN_LEFT, _T("FileListCtrl"), 3 ),
+ m_parent_dialog( fld )
+{
+ wxListItem col;
+
+ col.SetText( _( "Name" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 0, col, _( "Name" ) );
+
+ col.SetText( _( "Type" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 1, col, _( "Type" ) );
+
+ col.SetText( _( "Hash" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 2, col, _( "Hash" ) );
+
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = true;
+ m_sortorder[1].col = 1;
+ m_sortorder[1].direction = true;
+ m_sortorder[2].col = 2;
+ m_sortorder[2].direction = true;
+
+ //Sort( );
+
+// m_popup = new wxMenu( _T("") );
+// // &m enables shortcout "alt + m" and underlines m
+// m_popup->Append( BLIST_DLMAP, _("Download &map") );
+// m_popup->Append( BLIST_DLMOD, _("Download m&od") );
+}
+
+void FileListCtrl::SetColumnWidths()
+{
+#if defined(__WXMAC__)
+// on mac, autosize does not work at all
+ SetColumnWidth( 0, 250 );
+ SetColumnWidth( 1, 60 );
+ SetColumnWidth( 2, 150 );
+
+#else
+ SetColumnWidth( 0, wxLIST_AUTOSIZE );
+ SetColumnWidth( 1, wxLIST_AUTOSIZE );
+ SetColumnWidth( 2, wxLIST_AUTOSIZE );
+#endif
+}
+
+FileListCtrl::~FileListCtrl()
+{
+ //delete m_popup;
+}
+
+
+void FileListCtrl::OnListRightClick( wxListEvent& /*unused*/ )
+{
+ //PopupMenu( m_popup );
+}
+
+void FileListCtrl::OnColClick( wxListEvent& event )
+{
+ if ( event.GetColumn() == -1 ) return;
+ wxListItem col;
+ GetColumn( m_sortorder[0].col, col );
+ col.SetImage( icons().ICON_NONE );
+ SetColumn( m_sortorder[0].col, col );
+
+ int i;
+ for ( i = 0; m_sortorder[i].col != event.GetColumn() && i < 3; ++i ) {}
+ if ( i > 2 ) { i = 2; }
+ for ( ; i > 0; i-- ) { m_sortorder[i] = m_sortorder[i-1]; }
+ m_sortorder[0].col = event.GetColumn();
+ m_sortorder[0].direction = !m_sortorder[0].direction;
+
+
+ GetColumn( m_sortorder[0].col, col );
+ col.SetImage( ( m_sortorder[0].direction )?icons().ICON_UP:icons().ICON_DOWN );
+ SetColumn( m_sortorder[0].col, col );
+
+ Sort();
+}
+
+void FileListCtrl::GetSelectedHashes(HashVector& hashes)
+{
+ long item = -1;
+ for ( long i = 0; i < GetSelectedItemCount(); ++i )
+ {
+ item = GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
+ if ( item == -1 ) // means nothing was found
+ return;
+ hashes.push_back( TowxString<unsigned int>( GetItemData(item) ) );
+ }
+}
+
+
+void FileListCtrl::Sort()
+{
+ bool changed = false;
+ s_parent_dialog = m_parent_dialog;
+// if (!m_ui_for_sort || !m_ui_for_sort->GetServerStatus() ) return;
+//SortItems(( true )?&CompareNameUP:&CompareNameDOWN , 0 );
+ for ( int i = 3; i >= 0; i-- )
+ {
+ switch ( m_sortorder[ i ].col )
+ {
+ case 0 :
+ changed = SortItems(( m_sortorder[ i ].direction )?&CompareNameUP:&CompareNameDOWN , 0 );
+ break;
+ case 1 :
+ changed = SortItems(( m_sortorder[ i ].direction )?&CompareTypeUP:&CompareTypeDOWN , 0 );
+ break;
+ case 2 :
+ changed = SortItems(( m_sortorder[ i ].direction )?&CompareHashUP:&CompareHashDOWN , 0 );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+int wxCALLBACK FileListCtrl::CompareNameUP( long item1, long item2, long /*unused*/ )
+{
+ TorrentTable::PRow row1=s_parent_dialog->RowByHash(TowxString<long>(item1));
+ TorrentTable::PRow row2=s_parent_dialog->RowByHash(TowxString<long>(item2));
+ wxString name1 = row1.ok() ? row1->name.Upper() : _T("");
+ wxString name2 = row2.ok() ? row2->name.Upper() : _T("");
+ return name1.CompareTo(name2);
+}
+
+
+int wxCALLBACK FileListCtrl::CompareNameDOWN( long item1, long item2, long /*unused*/ )
+{
+ TorrentTable::PRow row1=s_parent_dialog->RowByHash(TowxString<long>(item1));
+ TorrentTable::PRow row2=s_parent_dialog->RowByHash(TowxString<long>(item2));
+ wxString name1 = row1.ok() ? row1->name.Upper() : _T("");
+ wxString name2 = row2.ok() ? row2->name.Upper() : _T("");
+ return name2.CompareTo(name1);
+}
+
+
+int wxCALLBACK FileListCtrl::CompareTypeUP( long item1, long item2, long /*unused*/ )
+{
+ TorrentTable::PRow row1=s_parent_dialog->RowByHash(TowxString<long>(item1));
+ TorrentTable::PRow row2=s_parent_dialog->RowByHash(TowxString<long>(item2));
+
+ wxString name1 = row1.ok() ? (row1->type == IUnitSync::map ? _("Map") : _("Mod")) : _T("");
+ wxString name2 = row2.ok() ? (row2->type == IUnitSync::map ? _("Map") : _("Mod")) : _T("");
+
+ return name1.CompareTo(name2);
+}
+
+
+int wxCALLBACK FileListCtrl::CompareTypeDOWN( long item1, long item2, long /*unused*/ )
+{
+ TorrentTable::PRow row1=s_parent_dialog->RowByHash(TowxString<long>(item1));
+ TorrentTable::PRow row2=s_parent_dialog->RowByHash(TowxString<long>(item2));
+
+ wxString name1 = row1.ok() ? (row1->type == IUnitSync::map ? _("Map") : _("Mod")) : _T("");
+ wxString name2 = row2.ok() ? (row2->type == IUnitSync::map ? _("Map") : _("Mod")) : _T("");
+
+ return name2.CompareTo(name1);
+}
+
+
+int wxCALLBACK FileListCtrl::CompareHashUP( long item1, long item2, long /*unused*/ )
+{
+ if ( item1 < item2 )
+ return -1;
+ if ( item1 > item2 )
+ return 1;
+
+ return 0;
+}
+
+
+
+int wxCALLBACK FileListCtrl::CompareHashDOWN( long item1, long item2, long /*unused*/ )
+{
+ if ( item1 > item2 )
+ return -1;
+ if ( item1 < item2 )
+ return 1;
+
+ return 0;
+}
+
+void FileListCtrl::SetTipWindowText( const long /*unused*/, const wxPoint position)
+{
+// long item = GetItemData( item_hit );
+// Ui* ui = m_ui_for_sort;
+// Battle& battle = ui->GetServer().battles_iter->GetBattle(item);
+ int column = getColumnFromPosition( position );
+ switch ( column )
+ {
+// case 0: // status
+// m_tiptext = icons().GetBattleStatus(battle);
+// break;
+// case 1: // country
+// m_tiptext = GetFlagNameFromCountryCode(battle.GetFounder().GetCountry());
+// break;
+// case 2: // rank_min
+// m_tiptext = m_colinfovec[column].first;
+// break;
+
+
+ default:
+ m_tiptext = _T( "" );
+ break;
+ }
+}
+
+void FileListCtrl::HighlightItem( long /*unused*/ )
+{
+
+}
+
+#endif
diff --git a/src/filelister/filelistctrl.h b/src/filelister/filelistctrl.h
new file mode 100644
index 0000000..c249f7e
--- /dev/null
+++ b/src/filelister/filelistctrl.h
@@ -0,0 +1,78 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_FILELISTCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_FILELISTCTRL_H
+
+#ifndef NO_TORRENT_SYSTEM
+
+#include "filelistfilter.h"
+
+#include "../customlistctrl.h"
+#include <wx/intl.h>
+
+class wxMenu;
+class wxListEvent;
+class wxCommandEvent;
+class FileListDialog;
+
+/** \brief list currently available torrents on tracker */
+class FileListCtrl : public CustomListCtrl
+{
+ public:
+ FileListCtrl( wxWindow* parent, FileListDialog* fld );
+ ~FileListCtrl();
+
+ typedef std::vector<wxString> HashVector;
+
+ void Sort();
+
+ void OnListRightClick( wxListEvent& event );
+ virtual void SetTipWindowText( const long item_hit, const wxPoint position);
+ void OnColClick( wxListEvent& event );
+ void GetSelectedHashes(HashVector&);
+ void SetColumnWidths();
+ virtual void HighlightItem( long item );
+
+ protected:
+ static int wxCALLBACK CompareNameUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareNameDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareHashUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareHashDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareTypeUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareTypeDOWN(long item1, long item2, long sortData);
+
+ wxMenu* m_popup;
+// Ui& m_ui;
+// static Ui* m_ui_for_sort;
+
+ FileListDialog* m_parent_dialog;
+ static FileListDialog* s_parent_dialog;
+
+ DECLARE_EVENT_TABLE()
+};
+
+enum
+{
+ FILELIST_COL_CLICK = wxID_HIGHEST,
+
+};
+
+#endif
+
+#endif // SPRINGLOBBY_HEADERGUARD_BATTLELISTCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/filelister/filelistdialog.cpp b/src/filelister/filelistdialog.cpp
new file mode 100644
index 0000000..6b6b242
--- /dev/null
+++ b/src/filelister/filelistdialog.cpp
@@ -0,0 +1,172 @@
+#ifndef NO_TORRENT_SYSTEM
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include "filelistdialog.h"
+#include "filelistctrl.h"
+#include "../iunitsync.h"
+#include "../utils/conversion.h"
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/button.h>
+
+BEGIN_EVENT_TABLE(FileListDialog, wxDialog)
+
+ EVT_BUTTON ( BUTTON_DOWNLOAD , FileListDialog::OnDownload )
+ EVT_BUTTON ( BUTTON_REFRESH , FileListDialog::OnRefreshList )
+ EVT_BUTTON ( BUTTON_SELECT_ALL , FileListDialog::OnSelectAll )
+ EVT_BUTTON ( BUTTON_SELECT_NONE, FileListDialog::OnSelectNone )
+ EVT_BUTTON ( BUTTON_SELECT_INV , FileListDialog::OnSelectInv )
+
+
+END_EVENT_TABLE()
+
+FileListDialog::FileListDialog(wxWindow* parent) :
+ wxDialog(parent, -1, _("Search and download files"), wxDefaultPosition, wxSize(800, 600),
+ wxDEFAULT_DIALOG_STYLE | wxCLIP_CHILDREN | wxRESIZE_BORDER)
+{
+ m_filecount = new wxStaticText( this, wxID_ANY, _("Files displayed") );
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* m_list_sizer;
+ m_list_sizer = new wxBoxSizer( wxVERTICAL );
+ m_filelistctrl = new FileListCtrl( this, this );
+ m_list_sizer->Add( m_filelistctrl, 1, wxALL|wxEXPAND, 5 );
+
+ wxBoxSizer* m_select_sizer = new wxBoxSizer( wxHORIZONTAL );
+/*
+ m_selectAll_button = new wxButton( this, BUTTON_SELECT_ALL, _T("Select all") );
+ m_selectNone_button = new wxButton( this, BUTTON_SELECT_NONE, _T("Select none") );
+ m_selectInv_button = new wxButton( this, BUTTON_SELECT_INV, _T("Invert selection") );
+ m_select_sizer->Add( m_selectAll_button );
+ m_select_sizer->Add( m_selectNone_button );
+ m_select_sizer->Add( m_selectInv_button );
+*/
+ wxBoxSizer* m_filter_sizer;
+ m_filter_sizer = new wxBoxSizer( wxVERTICAL );
+ m_filter = new FileListFilter ( this, wxID_ANY, this );
+ m_filter_sizer->Add( m_filter,0, wxALL|wxEXPAND, 5 );
+
+ wxBoxSizer* m_button_sizer;
+ m_button_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_download_button = new wxButton( this, BUTTON_DOWNLOAD, _("Download selected"), wxDefaultPosition, wxSize( -1,28 ), 0 );
+ m_button_sizer->Add( m_download_button );
+
+
+ //SetData( torrent().GetTorrentTable() );
+ m_hash_to_torrent=torrent().GetTorrentTable().RowsByHash();
+ UpdateList();
+
+ m_main_sizer->Add( m_list_sizer,1, wxALL|wxEXPAND, 5 );
+ m_main_sizer->Add( m_select_sizer,0, wxALL|wxEXPAND, 5 );
+ m_main_sizer->Add( m_filter_sizer,0, wxALL|wxEXPAND, 5 );
+ m_main_sizer->Add( m_button_sizer,0, wxALL|wxEXPAND, 5 );
+ m_main_sizer->Add( m_filecount,0, wxALL|wxEXPAND, 5 );
+ SetSizer( m_main_sizer );
+}
+
+FileListDialog::~FileListDialog()
+{
+
+}
+
+FileListCtrl* FileListDialog::GetListCtrl()
+{
+ return m_filelistctrl;
+}
+
+void FileListDialog::UpdateList()
+{
+ m_filelistctrl->DeleteAllItems();
+ unsigned int count = 0;
+ for (std::map<wxString, TorrentTable::PRow>::iterator it = m_hash_to_torrent.begin(); it != m_hash_to_torrent.end(); ++it)
+ {
+ if(!it->second.ok())continue;
+ switch (it->second->type)
+ {
+ case IUnitSync::mod:
+ it->second->SetHasFullFileLocal(usync().ModExists( it->second->name, it->second->hash ));
+ break;
+ case IUnitSync::map:
+ it->second->SetHasFullFileLocal(usync().MapExists( it->second->name, it->second->hash ));
+ break;
+ default: it->second->SetHasFullFileLocal(false);
+ break;
+ }
+ count += AddTorrentRow( it->second );
+ }
+ m_filecount->SetLabel( wxString::Format( _("%u files displayed"), count ) );
+ m_filelistctrl->SetColumnWidths();
+}
+
+TorrentTable::PRow FileListDialog::RowByHash(const wxString& hash )
+{
+ std::map<wxString,TorrentTable::PRow>::iterator i=m_hash_to_torrent.find(hash);
+ return i!=m_hash_to_torrent.end() ? i->second : TorrentTable::PRow(NULL);
+}
+
+bool FileListDialog::AddTorrentRow(TorrentTable::PRow data)
+{
+ if(!data.ok())return false;
+
+ if ( !m_filter->FilterTorrentData( data ) )
+ return false;
+ try
+ {
+ int index = m_filelistctrl->InsertItem( m_filelistctrl->GetItemCount(), data->hash);
+
+ //this enables me to later retrieve the index from itemtext (used in sort funcs)
+ m_filelistctrl->SetItemText( index, data->name );
+
+ //setting hash as item's data means we can retrieve it later for download
+ m_filelistctrl->SetItemData( index, (unsigned int)FromwxString<long>(data->hash) );
+ m_filelistctrl->SetItem( index, 0, data->name );
+ m_filelistctrl->SetItem( index, 1, data->type == IUnitSync::map ? _("Map") : _("Mod") );
+ m_filelistctrl->SetItem( index, 2, data->hash );
+
+ } catch (...) { return false; }
+ return true;
+}
+
+void FileListDialog::OnDownload( wxCommandEvent& /*unused*/ )
+{
+ typedef FileListCtrl::HashVector HashVector;
+ HashVector hashs;
+ m_filelistctrl->GetSelectedHashes(hashs);
+ for ( HashVector::const_iterator it = hashs.begin(); it != hashs.end(); ++it)
+ {
+ wxString hash = *it;
+ if (torrent().RequestFileByHash(hash) != TorrentWrapper::success)
+ wxLogError(_("unknown hash ") + hash );
+
+ }
+
+}
+
+void FileListDialog::OnRefreshList( wxCommandEvent& /*unused*/ )
+{
+
+}
+
+void FileListDialog::OnSelectAll( wxCommandEvent& /*unused*/ )
+{
+ m_filelistctrl->SelectAll();
+}
+
+void FileListDialog::OnSelectNone( wxCommandEvent& /*unused*/ )
+{
+ m_filelistctrl->SelectNone();
+}
+
+void FileListDialog::OnSelectInv( wxCommandEvent& /*unused*/ )
+{
+ m_filelistctrl->SelectInverse();
+}
+
+#endif
diff --git a/src/filelister/filelistdialog.h b/src/filelister/filelistdialog.h
new file mode 100644
index 0000000..cbb10b6
--- /dev/null
+++ b/src/filelister/filelistdialog.h
@@ -0,0 +1,86 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_FILELISTDIALOG_H
+#define SPRINGLOBBY_HEADERGUARD_FILELISTDIALOG_H
+
+#ifndef NO_TORRENT_SYSTEM
+
+#include <wx/dialog.h>
+#include "../torrentwrapper.h"
+
+class wxBoxSizer;
+class wxButton;
+class FileListCtrl;
+class FileListFilter;
+class wxStaticText;
+class wxCommandEvent;
+
+
+class FileListDialog : public wxDialog
+{
+ public:
+ FileListDialog(wxWindow* parent);
+ ~FileListDialog();
+
+ void UpdateList();
+ FileListCtrl* GetListCtrl();
+
+ //void SetData(const TorrentTable& data);
+ //TorrentTable &GetData();
+ TorrentTable::PRow RowByHash(const wxString& hash );
+
+ protected:
+ wxBoxSizer* m_main_sizer;
+ FileListCtrl* m_filelistctrl;
+
+
+ // TorrentTable m_torrent_table;
+ std::map<wxString, TorrentTable::PRow> m_hash_to_torrent;
+
+ FileListFilter* m_filter;
+ wxStaticText* m_filecount;
+ wxButton* m_download_button;
+ wxButton* m_selectAll_button;
+ wxButton* m_selectNone_button;
+ wxButton* m_selectInv_button;
+
+ bool AddTorrentRow(TorrentTable::PRow row);
+
+ void OnDownload( wxCommandEvent& event );
+ void OnRefreshList( wxCommandEvent& event );
+
+ void OnSelectAll( wxCommandEvent& event );
+ void OnSelectNone( wxCommandEvent& event );
+ void OnSelectInv( wxCommandEvent& event );
+
+ enum {
+ BUTTON_DOWNLOAD = wxID_HIGHEST,
+ BUTTON_REFRESH,
+ BUTTON_SELECT_ALL,
+ BUTTON_SELECT_NONE,
+ BUTTON_SELECT_INV
+ };
+
+ private:
+ DECLARE_EVENT_TABLE();
+};
+
+#endif
+
+#endif // SPRINGLOBBY_HEADERGUARD_FILELISTDIALOG_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/filelister/filelistfilter.cpp b/src/filelister/filelistfilter.cpp
new file mode 100644
index 0000000..90835d5
--- /dev/null
+++ b/src/filelister/filelistfilter.cpp
@@ -0,0 +1,150 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+
+#ifndef NO_TORRENT_SYSTEM
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/stattext.h>
+#include <wx/sizer.h>
+#include <wx/textctrl.h>
+#include <wx/intl.h>
+#include <wx/choice.h>
+#include <wx/statbox.h>
+#include <wx/event.h>
+#include <wx/regex.h>
+#include <wx/checkbox.h>
+
+#include "filelistfilter.h"
+#include "filelistctrl.h"
+#include "filelistdialog.h"
+#include "../uiutils.h"
+//#include "../utils.h"
+#include "../torrentwrapper.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+BEGIN_EVENT_TABLE( FileListFilter, wxPanel )
+ EVT_CHOICE( FILE_FILTER_TYPE_CHOICE, FileListFilter::OnChangeType )
+ EVT_TEXT( FILE_FILTER_NAME_EDIT , FileListFilter::OnChangeName )
+ EVT_CHECKBOX( FILE_FILTER_ONDISK , FileListFilter::OnChangeOndisk )
+END_EVENT_TABLE()
+
+
+FileListFilter::FileListFilter( wxWindow* parent, wxWindowID id, FileListDialog* parentBattleListTab, const wxPoint& pos, const wxSize& size, long style )
+ : wxPanel( parent, id, pos, size, style ),
+ m_parent_filelistdialog( parentBattleListTab )
+{
+ wxBoxSizer* m_filter_sizer;
+ m_filter_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxStaticBoxSizer* m_filter_body_sizer;
+ m_filter_body_sizer = new wxStaticBoxSizer( new wxStaticBox( this, -1, wxEmptyString ), wxVERTICAL );
+
+ wxBoxSizer* m_filter_body_row1_sizer;
+ m_filter_body_row1_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_name_text = new wxStaticText( this, wxID_ANY, _T( "Filename:" ), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_name_text->Wrap( -1 );
+ m_filter_name_text->SetMinSize( wxSize( 90,-1 ) );
+
+
+ m_filter_body_row1_sizer->Add( m_filter_name_text, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_name_edit = new wxTextCtrl( this, FILE_FILTER_NAME_EDIT, _T( "" ), wxDefaultPosition, wxSize( -1,-1 ), 0|wxSIMPLE_BORDER );
+ m_filter_name_edit->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
+ m_filter_name_edit->SetMinSize( wxSize( 220,-1 ) );
+ m_filter_name_expression = new wxRegEx( m_filter_name_edit->GetValue(),wxRE_ICASE );
+
+ m_filter_body_row1_sizer->Add( m_filter_name_edit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxBoxSizer* m_filter_type_sizer;
+ m_filter_type_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_type_text = new wxStaticText( this, wxID_ANY, _T( "Filetype:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_type_text->Wrap( -1 );
+ m_filter_type_sizer->Add( m_filter_type_text, 0, wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxBoxSizer* m_filter_ondisk_sizer;
+ m_filter_ondisk_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_filter_ondisk = new wxCheckBox( this, FILE_FILTER_ONDISK, _T( "Filter files already on disk" ) );
+ m_filter_ondisk_sizer->Add( m_filter_ondisk, 0, wxALIGN_CENTER_VERTICAL );
+
+ wxString firstChoice = _T( "Any" );
+
+ wxArrayString m_filter_type_choiceChoices;
+
+ m_filter_type_choiceChoices.Add( firstChoice );
+ m_filter_type_choiceChoices.Add( _T( "Map" ) );
+ m_filter_type_choiceChoices.Add( _T( "Mod" ) );
+
+ m_filter_type_choice = new wxChoice( this, FILE_FILTER_TYPE_CHOICE, wxDefaultPosition, wxDefaultSize, m_filter_type_choiceChoices, wxSIMPLE_BORDER );
+
+ m_filter_type_sizer->Add( m_filter_type_choice, 0, wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row1_sizer->Add( m_filter_type_sizer, 0, wxEXPAND, 5 );
+ m_filter_body_row1_sizer->Add( m_filter_ondisk_sizer, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_sizer->Add( m_filter_body_row1_sizer, 1, wxEXPAND, 5 );
+
+
+ m_filter_sizer->Add( m_filter_body_sizer, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ this->SetSizer( m_filter_sizer );
+ this->Layout();
+ m_filter_sizer->Fit( this );
+
+
+ if ( m_filter_name_expression != NULL ) { delete m_filter_name_expression; }
+ m_filter_name_expression = new wxRegEx( m_filter_name_edit->GetValue(),wxRE_ICASE );
+ m_filter_type_choice_value = -1;
+ wxCommandEvent dummy;
+ OnChange( dummy );
+
+}
+
+bool FileListFilter::FilterTorrentData( const TorrentTable::PRow& data )
+{
+ if(!data.ok())return false;
+ if ( !data->name.Upper().Contains( m_filter_name_edit->GetValue().Upper() )
+ && !m_filter_name_expression->Matches( data->name ) )
+ return false;
+ if ( m_filter_type_choice_value == 0 && data->type != IUnitSync::map ) return false;
+
+ if ( m_filter_type_choice_value == 1 && data->type != IUnitSync::mod ) return false;
+
+ if ( m_filter_ondisk->IsChecked() && data->HasFullFileLocal() )
+ return false;
+
+ return true;
+}
+
+void FileListFilter::OnChange( wxCommandEvent& event )
+{
+ m_parent_filelistdialog->UpdateList();
+}
+
+void FileListFilter::OnChangeName( wxCommandEvent& event )
+{
+ if ( m_filter_name_expression != NULL ) { delete m_filter_name_expression; }
+ m_filter_name_expression = new wxRegEx( m_filter_name_edit->GetValue(),wxRE_ICASE );
+ OnChange( event );
+}
+
+void FileListFilter::OnChangeType( wxCommandEvent& event )
+{
+ m_filter_type_choice_value = m_filter_type_choice->GetSelection()-1;
+ OnChange( event );
+}
+
+void FileListFilter::OnChangeOndisk( wxCommandEvent& event )
+{
+ OnChange( event );
+}
+
+#endif
diff --git a/src/filelister/filelistfilter.h b/src/filelister/filelistfilter.h
new file mode 100644
index 0000000..3266629
--- /dev/null
+++ b/src/filelister/filelistfilter.h
@@ -0,0 +1,94 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_FILELISTFILTER_H
+#define SPRINGLOBBY_HEADERGUARD_FILELISTFILTER_H
+
+#ifndef NO_TORRENT_SYSTEM
+
+#include <wx/panel.h>
+
+#include "filelistdialog.h"
+
+
+///////////////////////////////////////////////////////////////////////////
+
+class FileListDialog;
+class wxToggleButton;
+class wxCheckBox;
+class wxStaticText;
+class wxTextCtrl;
+class wxChoice;
+class wxButton;
+class wxRegEx;
+class wxStaticText;
+class Battle;
+struct TorrentData;
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Class FileListFilter
+///////////////////////////////////////////////////////////////////////////////
+class FileListFilter : public wxPanel
+{
+ public:
+ FileListFilter( wxWindow* parent, wxWindowID id, FileListDialog* parentBattleListTab, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxEXPAND );
+
+ void OnActivate ( wxCommandEvent& event );
+
+ void SetActiv ( bool state );
+
+ void OnChange ( wxCommandEvent& event );
+ void OnChangeName ( wxCommandEvent& event );
+ void OnChangeType ( wxCommandEvent& event );
+ void OnChangeOndisk ( wxCommandEvent& event );
+
+ bool FilterTorrentData(const TorrentTable::PRow& data);
+ bool GetActiv() const;
+
+ protected:
+
+ FileListDialog* m_parent_filelistdialog;
+ wxStaticText* m_filter_text;
+
+ //filename
+ wxStaticText* m_filter_name_text;
+ wxTextCtrl* m_filter_name_edit;
+ wxRegEx* m_filter_name_expression;
+
+ //filetype
+ wxStaticText* m_filter_type_text;
+ wxChoice* m_filter_type_choice;
+ int m_filter_type_choice_value;
+
+ wxCheckBox* m_filter_ondisk;
+
+
+ DECLARE_EVENT_TABLE();
+};
+
+enum
+{
+ FILE_FILTER_NAME_EDIT,
+ FILE_FILTER_TYPE_CHOICE,
+ FILE_FILTER_ONDISK
+};
+
+#endif
+
+#endif //SPRINGLOBBY_HEADERGUARD_BATTLELISTFILTER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/flagimagedata.h b/src/flagimagedata.h
new file mode 100644
index 0000000..39da8f8
--- /dev/null
+++ b/src/flagimagedata.h
@@ -0,0 +1,754 @@
+// this header file is automatically generated with a script
+#include "images/flags/AD.xpm"
+#include "images/flags/AE.xpm"
+#include "images/flags/AF.xpm"
+#include "images/flags/AG.xpm"
+#include "images/flags/AI.xpm"
+#include "images/flags/AL.xpm"
+#include "images/flags/AM.xpm"
+#include "images/flags/AN.xpm"
+#include "images/flags/AO.xpm"
+#include "images/flags/AR.xpm"
+#include "images/flags/AS.xpm"
+#include "images/flags/AT.xpm"
+#include "images/flags/AU.xpm"
+#include "images/flags/AW.xpm"
+#include "images/flags/AX.xpm"
+#include "images/flags/AZ.xpm"
+#include "images/flags/BA.xpm"
+#include "images/flags/BB.xpm"
+#include "images/flags/BD.xpm"
+#include "images/flags/BE.xpm"
+#include "images/flags/BF.xpm"
+#include "images/flags/BG.xpm"
+#include "images/flags/BH.xpm"
+#include "images/flags/BI.xpm"
+#include "images/flags/BJ.xpm"
+#include "images/flags/BM.xpm"
+#include "images/flags/BN.xpm"
+#include "images/flags/BO.xpm"
+#include "images/flags/BR.xpm"
+#include "images/flags/BS.xpm"
+#include "images/flags/BT.xpm"
+#include "images/flags/BV.xpm"
+#include "images/flags/BW.xpm"
+#include "images/flags/BY.xpm"
+#include "images/flags/BZ.xpm"
+#include "images/flags/CA.xpm"
+#include "images/flags/CC.xpm"
+#include "images/flags/CD.xpm"
+#include "images/flags/CF.xpm"
+#include "images/flags/CG.xpm"
+#include "images/flags/CH.xpm"
+#include "images/flags/CI.xpm"
+#include "images/flags/CK.xpm"
+#include "images/flags/CL.xpm"
+#include "images/flags/CM.xpm"
+#include "images/flags/CN.xpm"
+#include "images/flags/CO.xpm"
+#include "images/flags/CR.xpm"
+#include "images/flags/CS.xpm"
+#include "images/flags/CU.xpm"
+#include "images/flags/CV.xpm"
+#include "images/flags/CX.xpm"
+#include "images/flags/CY.xpm"
+#include "images/flags/CZ.xpm"
+#include "images/flags/DE.xpm"
+#include "images/flags/DJ.xpm"
+#include "images/flags/DK.xpm"
+#include "images/flags/DM.xpm"
+#include "images/flags/DO.xpm"
+#include "images/flags/DZ.xpm"
+#include "images/flags/EC.xpm"
+#include "images/flags/EE.xpm"
+#include "images/flags/EG.xpm"
+#include "images/flags/EH.xpm"
+#include "images/flags/ER.xpm"
+#include "images/flags/ES.xpm"
+#include "images/flags/ET.xpm"
+#include "images/flags/FAM.xpm"
+#include "images/flags/FI.xpm"
+#include "images/flags/FJ.xpm"
+#include "images/flags/FK.xpm"
+#include "images/flags/FM.xpm"
+#include "images/flags/FO.xpm"
+#include "images/flags/FR.xpm"
+#include "images/flags/GA.xpm"
+#include "images/flags/GB.xpm"
+#include "images/flags/GD.xpm"
+#include "images/flags/GE.xpm"
+#include "images/flags/GF.xpm"
+#include "images/flags/GH.xpm"
+#include "images/flags/GI.xpm"
+#include "images/flags/GL.xpm"
+#include "images/flags/GM.xpm"
+#include "images/flags/GN.xpm"
+#include "images/flags/GP.xpm"
+#include "images/flags/GQ.xpm"
+#include "images/flags/GR.xpm"
+#include "images/flags/GS.xpm"
+#include "images/flags/GT.xpm"
+#include "images/flags/GU.xpm"
+#include "images/flags/GW.xpm"
+#include "images/flags/GY.xpm"
+#include "images/flags/HK.xpm"
+#include "images/flags/HM.xpm"
+#include "images/flags/HN.xpm"
+#include "images/flags/HR.xpm"
+#include "images/flags/HT.xpm"
+#include "images/flags/HU.xpm"
+#include "images/flags/ID.xpm"
+#include "images/flags/IE.xpm"
+#include "images/flags/IL.xpm"
+#include "images/flags/IN.xpm"
+#include "images/flags/IO.xpm"
+#include "images/flags/IQ.xpm"
+#include "images/flags/IR.xpm"
+#include "images/flags/IS.xpm"
+#include "images/flags/IT.xpm"
+#include "images/flags/JM.xpm"
+#include "images/flags/JO.xpm"
+#include "images/flags/JP.xpm"
+#include "images/flags/KE.xpm"
+#include "images/flags/KG.xpm"
+#include "images/flags/KH.xpm"
+#include "images/flags/KI.xpm"
+#include "images/flags/KM.xpm"
+#include "images/flags/KN.xpm"
+#include "images/flags/KP.xpm"
+#include "images/flags/KR.xpm"
+#include "images/flags/KW.xpm"
+#include "images/flags/KY.xpm"
+#include "images/flags/KZ.xpm"
+#include "images/flags/LA.xpm"
+#include "images/flags/LB.xpm"
+#include "images/flags/LC.xpm"
+#include "images/flags/LI.xpm"
+#include "images/flags/LK.xpm"
+#include "images/flags/LR.xpm"
+#include "images/flags/LS.xpm"
+#include "images/flags/LT.xpm"
+#include "images/flags/LU.xpm"
+#include "images/flags/LV.xpm"
+#include "images/flags/LY.xpm"
+#include "images/flags/MA.xpm"
+#include "images/flags/MC.xpm"
+#include "images/flags/MD.xpm"
+#include "images/flags/ME.xpm"
+#include "images/flags/MG.xpm"
+#include "images/flags/MH.xpm"
+#include "images/flags/MK.xpm"
+#include "images/flags/ML.xpm"
+#include "images/flags/MM.xpm"
+#include "images/flags/MN.xpm"
+#include "images/flags/MO.xpm"
+#include "images/flags/MP.xpm"
+#include "images/flags/MQ.xpm"
+#include "images/flags/MR.xpm"
+#include "images/flags/MS.xpm"
+#include "images/flags/MT.xpm"
+#include "images/flags/MU.xpm"
+#include "images/flags/MV.xpm"
+#include "images/flags/MW.xpm"
+#include "images/flags/MX.xpm"
+#include "images/flags/MY.xpm"
+#include "images/flags/MZ.xpm"
+#include "images/flags/NA.xpm"
+#include "images/flags/NC.xpm"
+#include "images/flags/NE.xpm"
+#include "images/flags/NF.xpm"
+#include "images/flags/NG.xpm"
+#include "images/flags/NI.xpm"
+#include "images/flags/NL.xpm"
+#include "images/flags/NO.xpm"
+#include "images/flags/NP.xpm"
+#include "images/flags/NR.xpm"
+#include "images/flags/NU.xpm"
+#include "images/flags/NZ.xpm"
+#include "images/flags/OM.xpm"
+#include "images/flags/PA.xpm"
+#include "images/flags/PE.xpm"
+#include "images/flags/PF.xpm"
+#include "images/flags/PG.xpm"
+#include "images/flags/PH.xpm"
+#include "images/flags/PK.xpm"
+#include "images/flags/PL.xpm"
+#include "images/flags/PM.xpm"
+#include "images/flags/PN.xpm"
+#include "images/flags/PR.xpm"
+#include "images/flags/PS.xpm"
+#include "images/flags/PT.xpm"
+#include "images/flags/PW.xpm"
+#include "images/flags/PY.xpm"
+#include "images/flags/QA.xpm"
+#include "images/flags/RE.xpm"
+#include "images/flags/RO.xpm"
+#include "images/flags/RS.xpm"
+#include "images/flags/RU.xpm"
+#include "images/flags/RW.xpm"
+#include "images/flags/SA.xpm"
+#include "images/flags/SB.xpm"
+#include "images/flags/SC.xpm"
+#include "images/flags/SD.xpm"
+#include "images/flags/SE.xpm"
+#include "images/flags/SG.xpm"
+#include "images/flags/SH.xpm"
+#include "images/flags/SI.xpm"
+#include "images/flags/SJ.xpm"
+#include "images/flags/SK.xpm"
+#include "images/flags/SL.xpm"
+#include "images/flags/SM.xpm"
+#include "images/flags/SN.xpm"
+#include "images/flags/SO.xpm"
+#include "images/flags/SR.xpm"
+#include "images/flags/ST.xpm"
+#include "images/flags/SV.xpm"
+#include "images/flags/SY.xpm"
+#include "images/flags/SZ.xpm"
+#include "images/flags/TC.xpm"
+#include "images/flags/TD.xpm"
+#include "images/flags/TF.xpm"
+#include "images/flags/TG.xpm"
+#include "images/flags/TH.xpm"
+#include "images/flags/TJ.xpm"
+#include "images/flags/TK.xpm"
+#include "images/flags/TL.xpm"
+#include "images/flags/TM.xpm"
+#include "images/flags/TN.xpm"
+#include "images/flags/TO.xpm"
+#include "images/flags/TR.xpm"
+#include "images/flags/TT.xpm"
+#include "images/flags/TV.xpm"
+#include "images/flags/TW.xpm"
+#include "images/flags/TZ.xpm"
+#include "images/flags/UA.xpm"
+#include "images/flags/UG.xpm"
+#include "images/flags/UM.xpm"
+#include "images/flags/US.xpm"
+#include "images/flags/UY.xpm"
+#include "images/flags/UZ.xpm"
+#include "images/flags/VA.xpm"
+#include "images/flags/VC.xpm"
+#include "images/flags/VE.xpm"
+#include "images/flags/VG.xpm"
+#include "images/flags/VI.xpm"
+#include "images/flags/VN.xpm"
+#include "images/flags/VU.xpm"
+#include "images/flags/WF.xpm"
+#include "images/flags/WS.xpm"
+#include "images/flags/YE.xpm"
+#include "images/flags/YT.xpm"
+#include "images/flags/ZA.xpm"
+#include "images/flags/ZM.xpm"
+#include "images/flags/ZW.xpm"
+
+const char* flag_str[] = {
+"AD",
+"AE",
+"AF",
+"AG",
+"AI",
+"AL",
+"AM",
+"AN",
+"AO",
+"AR",
+"AS",
+"AT",
+"AU",
+"AW",
+"AX",
+"AZ",
+"BA",
+"BB",
+"BD",
+"BE",
+"BF",
+"BG",
+"BH",
+"BI",
+"BJ",
+"BM",
+"BN",
+"BO",
+"BR",
+"BS",
+"BT",
+"BV",
+"BW",
+"BY",
+"BZ",
+"CA",
+"CC",
+"CD",
+"CF",
+"CG",
+"CH",
+"CI",
+"CK",
+"CL",
+"CM",
+"CN",
+"CO",
+"CR",
+"CS",
+"CU",
+"CV",
+"CX",
+"CY",
+"CZ",
+"DE",
+"DJ",
+"DK",
+"DM",
+"DO",
+"DZ",
+"EC",
+"EE",
+"EG",
+"EH",
+"ER",
+"ES",
+"ET",
+"FAM",
+"FI",
+"FJ",
+"FK",
+"FM",
+"FO",
+"FR",
+"GA",
+"GB",
+"GD",
+"GE",
+"GF",
+"GH",
+"GI",
+"GL",
+"GM",
+"GN",
+"GP",
+"GQ",
+"GR",
+"GS",
+"GT",
+"GU",
+"GW",
+"GY",
+"HK",
+"HM",
+"HN",
+"HR",
+"HT",
+"HU",
+"ID",
+"IE",
+"IL",
+"IN",
+"IO",
+"IQ",
+"IR",
+"IS",
+"IT",
+"JM",
+"JO",
+"JP",
+"KE",
+"KG",
+"KH",
+"KI",
+"KM",
+"KN",
+"KP",
+"KR",
+"KW",
+"KY",
+"KZ",
+"LA",
+"LB",
+"LC",
+"LI",
+"LK",
+"LR",
+"LS",
+"LT",
+"LU",
+"LV",
+"LY",
+"MA",
+"MC",
+"MD",
+"ME",
+"MG",
+"MH",
+"MK",
+"ML",
+"MM",
+"MN",
+"MO",
+"MP",
+"MQ",
+"MR",
+"MS",
+"MT",
+"MU",
+"MV",
+"MW",
+"MX",
+"MY",
+"MZ",
+"NA",
+"NC",
+"NE",
+"NF",
+"NG",
+"NI",
+"NL",
+"NO",
+"NP",
+"NR",
+"NU",
+"NZ",
+"OM",
+"PA",
+"PE",
+"PF",
+"PG",
+"PH",
+"PK",
+"PL",
+"PM",
+"PN",
+"PR",
+"PS",
+"PT",
+"PW",
+"PY",
+"QA",
+"RE",
+"RO",
+"RS",
+"RU",
+"RW",
+"SA",
+"SB",
+"SC",
+"SD",
+"SE",
+"SG",
+"SH",
+"SI",
+"SJ",
+"SK",
+"SL",
+"SM",
+"SN",
+"SO",
+"SR",
+"ST",
+"SV",
+"SY",
+"SZ",
+"TC",
+"TD",
+"TF",
+"TG",
+"TH",
+"TJ",
+"TK",
+"TL",
+"TM",
+"TN",
+"TO",
+"TR",
+"TT",
+"TV",
+"TW",
+"TZ",
+"UA",
+"UG",
+"UM",
+"US",
+"UY",
+"UZ",
+"VA",
+"VC",
+"VE",
+"VG",
+"VI",
+"VN",
+"VU",
+"WF",
+"WS",
+"YE",
+"YT",
+"ZA",
+"ZM",
+"ZW",
+0
+};
+
+const char* const* flag_xpm[] = {
+AD_xpm,
+AE_xpm,
+AF_xpm,
+AG_xpm,
+AI_xpm,
+AL_xpm,
+AM_xpm,
+AN_xpm,
+AO_xpm,
+AR_xpm,
+AS_xpm,
+AT_xpm,
+AU_xpm,
+AW_xpm,
+AX_xpm,
+AZ_xpm,
+BA_xpm,
+BB_xpm,
+BD_xpm,
+BE_xpm,
+BF_xpm,
+BG_xpm,
+BH_xpm,
+BI_xpm,
+BJ_xpm,
+BM_xpm,
+BN_xpm,
+BO_xpm,
+BR_xpm,
+BS_xpm,
+BT_xpm,
+BV_xpm,
+BW_xpm,
+BY_xpm,
+BZ_xpm,
+CA_xpm,
+CC_xpm,
+CD_xpm,
+CF_xpm,
+CG_xpm,
+CH_xpm,
+CI_xpm,
+CK_xpm,
+CL_xpm,
+CM_xpm,
+CN_xpm,
+CO_xpm,
+CR_xpm,
+CS_xpm,
+CU_xpm,
+CV_xpm,
+CX_xpm,
+CY_xpm,
+CZ_xpm,
+DE_xpm,
+DJ_xpm,
+DK_xpm,
+DM_xpm,
+DO_xpm,
+DZ_xpm,
+EC_xpm,
+EE_xpm,
+EG_xpm,
+EH_xpm,
+ER_xpm,
+ES_xpm,
+ET_xpm,
+FAM_xpm,
+FI_xpm,
+FJ_xpm,
+FK_xpm,
+FM_xpm,
+FO_xpm,
+FR_xpm,
+GA_xpm,
+GB_xpm,
+GD_xpm,
+GE_xpm,
+GF_xpm,
+GH_xpm,
+GI_xpm,
+GL_xpm,
+GM_xpm,
+GN_xpm,
+GP_xpm,
+GQ_xpm,
+GR_xpm,
+GS_xpm,
+GT_xpm,
+GU_xpm,
+GW_xpm,
+GY_xpm,
+HK_xpm,
+HM_xpm,
+HN_xpm,
+HR_xpm,
+HT_xpm,
+HU_xpm,
+ID_xpm,
+IE_xpm,
+IL_xpm,
+IN_xpm,
+IO_xpm,
+IQ_xpm,
+IR_xpm,
+IS_xpm,
+IT_xpm,
+JM_xpm,
+JO_xpm,
+JP_xpm,
+KE_xpm,
+KG_xpm,
+KH_xpm,
+KI_xpm,
+KM_xpm,
+KN_xpm,
+KP_xpm,
+KR_xpm,
+KW_xpm,
+KY_xpm,
+KZ_xpm,
+LA_xpm,
+LB_xpm,
+LC_xpm,
+LI_xpm,
+LK_xpm,
+LR_xpm,
+LS_xpm,
+LT_xpm,
+LU_xpm,
+LV_xpm,
+LY_xpm,
+MA_xpm,
+MC_xpm,
+MD_xpm,
+ME_xpm,
+MG_xpm,
+MH_xpm,
+MK_xpm,
+ML_xpm,
+MM_xpm,
+MN_xpm,
+MO_xpm,
+MP_xpm,
+MQ_xpm,
+MR_xpm,
+MS_xpm,
+MT_xpm,
+MU_xpm,
+MV_xpm,
+MW_xpm,
+MX_xpm,
+MY_xpm,
+MZ_xpm,
+NA_xpm,
+NC_xpm,
+NE_xpm,
+NF_xpm,
+NG_xpm,
+NI_xpm,
+NL_xpm,
+NO_xpm,
+NP_xpm,
+NR_xpm,
+NU_xpm,
+NZ_xpm,
+OM_xpm,
+PA_xpm,
+PE_xpm,
+PF_xpm,
+PG_xpm,
+PH_xpm,
+PK_xpm,
+PL_xpm,
+PM_xpm,
+PN_xpm,
+PR_xpm,
+PS_xpm,
+PT_xpm,
+PW_xpm,
+PY_xpm,
+QA_xpm,
+RE_xpm,
+RO_xpm,
+RS_xpm,
+RU_xpm,
+RW_xpm,
+SA_xpm,
+SB_xpm,
+SC_xpm,
+SD_xpm,
+SE_xpm,
+SG_xpm,
+SH_xpm,
+SI_xpm,
+SJ_xpm,
+SK_xpm,
+SL_xpm,
+SM_xpm,
+SN_xpm,
+SO_xpm,
+SR_xpm,
+ST_xpm,
+SV_xpm,
+SY_xpm,
+SZ_xpm,
+TC_xpm,
+TD_xpm,
+TF_xpm,
+TG_xpm,
+TH_xpm,
+TJ_xpm,
+TK_xpm,
+TL_xpm,
+TM_xpm,
+TN_xpm,
+TO_xpm,
+TR_xpm,
+TT_xpm,
+TV_xpm,
+TW_xpm,
+TZ_xpm,
+UA_xpm,
+UG_xpm,
+UM_xpm,
+US_xpm,
+UY_xpm,
+UZ_xpm,
+VA_xpm,
+VC_xpm,
+VE_xpm,
+VG_xpm,
+VI_xpm,
+VN_xpm,
+VU_xpm,
+WF_xpm,
+WS_xpm,
+YE_xpm,
+YT_xpm,
+ZA_xpm,
+ZM_xpm,
+ZW_xpm,
+0
+};
+
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/flagimages.cpp b/src/flagimages.cpp
new file mode 100644
index 0000000..eea236b
--- /dev/null
+++ b/src/flagimages.cpp
@@ -0,0 +1,39 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+#ifdef __WXMAC__
+ #include <wx/bitmap.h>
+#endif
+
+#include "flagimages.h"
+#include "flagimagedata.h"
+
+#include <wx/imaglist.h>
+#include <wx/log.h>
+
+#include "utils/conversion.h"
+
+int GetFlagIndex( const wxString& flag )
+{
+ if ( flag.IsEmpty() )
+ return FLAG_NONE;
+
+ for ( int i = 0; flag_str[i]; ++i ) {
+ if ( flag == TowxString( flag_str[i] ) ) {
+ return i;
+ }
+ }
+ wxLogMessage( _T( "%s flag not found!" ), flag.c_str() );
+ return FLAG_NONE;
+}
+
+int AddFlagImages( wxImageList& imgs )
+{
+ int index, poszero;
+ index = poszero = 0;
+ for ( int i = 0; flag_xpm[i]; ++i )
+ {
+ index = imgs.Add( wxBitmap( const_cast<const char**>( flag_xpm[i] ) ) );
+ if ( i == 0 ) poszero = index;
+ }
+ return poszero;
+}
+
diff --git a/src/flagimages.h b/src/flagimages.h
new file mode 100644
index 0000000..a238ab3
--- /dev/null
+++ b/src/flagimages.h
@@ -0,0 +1,32 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_FLAGIMAGES_H
+#define SPRINGLOBBY_HEADERGUARD_FLAGIMAGES_H
+
+class wxImageList;
+class wxString;
+
+int GetFlagIndex( const wxString& flag );
+int AddFlagImages( wxImageList& imgs );
+
+enum {
+ FLAG_NONE = -1
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_FLAGIMAGES_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/globalevents.cpp b/src/globalevents.cpp
new file mode 100644
index 0000000..308d7fc
--- /dev/null
+++ b/src/globalevents.cpp
@@ -0,0 +1,30 @@
+#include "globalevents.h"
+#include "settings++/custom_dialogs.h"
+#include "ui.h"
+#include "updater/updater.h"
+#include <wx/intl.h>
+
+#include "globalsmanager.h"
+
+const wxEventType UnitSyncReloadRequest = wxNewEventType();
+const wxEventType ExeDownloadEvt = wxNewEventType();
+
+BEGIN_EVENT_TABLE(SL_GlobalEvtHandler, wxEvtHandler)
+ EVT_COMMAND(wxID_ANY, UnitSyncReloadRequest, SL_GlobalEvtHandler::OnUnitSyncReload)
+END_EVENT_TABLE()
+
+SL_GlobalEvtHandler& SL_GlobalEvtHandler::GetSL_GlobalEvtHandler()
+{
+ static GlobalObjectHolder<SL_GlobalEvtHandler> slGlobalEvtHandler;
+ return slGlobalEvtHandler;
+}
+
+SL_GlobalEvtHandler::SL_GlobalEvtHandler()
+{
+}
+
+
+void SL_GlobalEvtHandler::OnUnitSyncReload(wxCommandEvent& event)
+{
+ ui().ReloadUnitSync();
+}
diff --git a/src/globalevents.h b/src/globalevents.h
new file mode 100644
index 0000000..cc69503
--- /dev/null
+++ b/src/globalevents.h
@@ -0,0 +1,47 @@
+#ifndef SPRINGLOBBY_GLOBALEVENTS_H_INCLUDED
+#define SPRINGLOBBY_GLOBALEVENTS_H_INCLUDED
+
+#include <wx/event.h>
+class wxCommandEvent;
+
+extern const wxEventType UnitSyncReloadRequest;
+extern const wxEventType ExeDownloadEvt;
+
+class IGlobalObjectHolder;
+template <class T>
+class GlobalObjectHolder;
+
+class SL_GlobalEvtHandler : public wxEvtHandler
+{
+protected:
+ friend class IGlobalObjectHolder;
+ friend class GlobalObjectHolder<SL_GlobalEvtHandler>;
+ SL_GlobalEvtHandler();
+
+ DECLARE_EVENT_TABLE()
+
+public:
+ static SL_GlobalEvtHandler& GetSL_GlobalEvtHandler();
+ void OnUnitSyncReload(wxCommandEvent& event);
+
+};
+
+#endif // SPRINGLOBBY_GLOBALEVENTS_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/globalsmanager.cpp b/src/globalsmanager.cpp
new file mode 100644
index 0000000..db520fd
--- /dev/null
+++ b/src/globalsmanager.cpp
@@ -0,0 +1,102 @@
+#include "globalsmanager.h"
+#include <assert.h>
+#include <vector>
+#include <wx/log.h>
+
+#include "utils/conversion.h"
+#include "utils/debug.h"
+
+class GlobalsManager
+{
+ std::vector<IGlobalObjectHolder *> globals;
+ bool de_initialized;
+
+public:
+ GlobalsManager();
+ bool RegisterGlobal(IGlobalObjectHolder *obj);
+ void DestroyAll();
+ virtual ~GlobalsManager();
+
+protected:
+
+private:
+
+};
+
+GlobalsManager *mgr=NULL;
+bool destroyed=false;
+
+GlobalsManager *globals()
+{
+ if ( destroyed ) return NULL;
+ if ( !mgr )
+ {
+ mgr = new GlobalsManager;
+ }
+ return mgr;
+}
+
+void DestroyGlobals()
+{
+ if ( mgr )
+ {
+ mgr->DestroyAll();
+ delete mgr;
+ }
+ destroyed = true;
+}
+
+bool IGlobalObjectHolder::RegisterSelf()
+{
+ if ( !globals() ) return false;
+ return globals()->RegisterGlobal( this );
+}
+
+GlobalsManager::GlobalsManager():
+de_initialized( false )
+{
+ wxLogMessage( _T("GlobalsManager::GlobalsManager()") );
+ //ctor
+}
+
+bool GlobalsManager::RegisterGlobal( IGlobalObjectHolder *obj )
+{
+ wxLogDebugFunc( _T("") );
+ if ( de_initialized )
+ {
+ return false;
+ }
+ globals.push_back( obj );
+ return true;
+}
+
+void GlobalsManager::DestroyAll()
+{
+ wxLogMessage( _T("GlobalsManager::DestroyAll()") );
+ for ( std::vector<IGlobalObjectHolder *>::iterator i = globals.begin(); i != globals.end(); ++i )
+ {
+ (*i)->Nullify();
+ }
+
+ for ( std::vector<IGlobalObjectHolder *>::iterator i = globals.begin(); i != globals.end(); ++i )
+ {
+ try
+ {
+ (*i)->Destroy();
+ }
+ catch ( std::runtime_error e )
+ {
+ wxLogMessage( _T("GlobalsManager::DestroyAll(), runtume_error '%s' when destroying"), TowxString( e.what() ).c_str() );
+ }
+ }
+
+ globals.clear();
+ de_initialized = true;
+ wxLogMessage( _T("GlobalsManager::DestroyAll() done") );
+}
+
+GlobalsManager::~GlobalsManager()
+{
+ assert(globals.empty());
+}
+
diff --git a/src/globalsmanager.h b/src/globalsmanager.h
new file mode 100644
index 0000000..b4b1c0e
--- /dev/null
+++ b/src/globalsmanager.h
@@ -0,0 +1,93 @@
+#ifndef GLOBALSMANAGER_H
+#define GLOBALSMANAGER_H
+
+#include <stdexcept>
+
+class GlobalDestroyedError: public std::runtime_error
+{
+public:
+ GlobalDestroyedError(): std::runtime_error( "trying to access global during or after DestroyAll" )
+ {
+
+ }
+};
+
+class GlobalRecursiveError: public std::runtime_error
+{
+ public:
+ GlobalRecursiveError(): std::runtime_error( "trying to access global during its construction" )
+ {
+
+ }
+};
+
+class IGlobalObjectHolder
+{
+ public:
+ bool RegisterSelf();
+ virtual void Nullify() = 0;
+ virtual void Destroy() = 0;
+};
+
+void DestroyGlobals();
+
+template<class T>
+class GlobalObjectHolder: public IGlobalObjectHolder
+{
+ T *private_ptr;
+ T *public_ptr;
+ bool constructing;
+public:
+ GlobalObjectHolder():
+ private_ptr( NULL ),
+ public_ptr( NULL ),
+ constructing( true )
+ {
+ if ( RegisterSelf() )
+ {
+ private_ptr = new T;
+ public_ptr = private_ptr;
+ }
+ constructing = false;
+ }
+ virtual void Nullify()
+ {
+ public_ptr = NULL;
+ };
+ virtual void Destroy()
+ {
+ public_ptr = NULL;
+ delete private_ptr;
+ private_ptr = NULL;
+ };
+ T &GetInstance()
+ {
+ if ( constructing ) throw GlobalRecursiveError();
+ if ( !public_ptr ) throw GlobalDestroyedError();
+ return *public_ptr;
+ }
+ operator T&()
+ {
+ return GetInstance();
+ }
+};
+
+#endif // GLOBALSMANAGER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/groupoptionspanel.cpp b/src/groupoptionspanel.cpp
new file mode 100644
index 0000000..3fa1ab2
--- /dev/null
+++ b/src/groupoptionspanel.cpp
@@ -0,0 +1,345 @@
+
+#include "groupoptionspanel.h"
+
+#include <wx/textdlg.h>
+#include <wx/colour.h>
+#include <wx/textctrl.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+#include <wx/settings.h>
+#include <wx/sizer.h>
+#include <wx/listbox.h>
+#include <wx/checkbox.h>
+#include <wx/stattext.h>
+#include <wx/statbox.h>
+
+#include "useractions.h"
+#include "settings.h"
+#include "uiutils.h"
+#include "utils/controls.h"
+#include "Helper/colorbutton.h"
+#include "selectusersdialog.h"
+
+BEGIN_EVENT_TABLE( GroupOptionsPanel, wxPanel )
+ EVT_BUTTON( REMOVE_GROUP, GroupOptionsPanel::OnRemoveGroup )
+ EVT_BUTTON( RENAME_GROUP, GroupOptionsPanel::OnRenameGroup )
+ EVT_BUTTON( ADD_GROUP, GroupOptionsPanel::OnAddNewGroup )
+ EVT_LISTBOX( GROUPS_LIST, GroupOptionsPanel::OnGroupListSelectionChange )
+ EVT_CHECKBOX( NOTIFY_LOGIN, GroupOptionsPanel::OnGroupActionsChange )
+ EVT_CHECKBOX( IGNORE_CHAT, GroupOptionsPanel::OnGroupActionsChange )
+ EVT_CHECKBOX( NOTIFY_HOST, GroupOptionsPanel::OnGroupActionsChange )
+ EVT_CHECKBOX( IGNORE_PM, GroupOptionsPanel::OnGroupActionsChange )
+ EVT_CHECKBOX( NOTIFY_STATUS, GroupOptionsPanel::OnGroupActionsChange )
+ EVT_CHECKBOX( AUTOCKICK, GroupOptionsPanel::OnGroupActionsChange )
+ EVT_CHECKBOX( NOTIFY_HIGHLIGHT, GroupOptionsPanel::OnGroupActionsChange )
+ EVT_BUTTON( HIGHLIGHT_COLOR, GroupOptionsPanel::OnHighlightColorClick )
+ EVT_LISTBOX( USERS_LIST, GroupOptionsPanel::OnUsersListSelectionChange )
+ EVT_BUTTON( ADD_USER, GroupOptionsPanel::OnAddUsers )
+ EVT_BUTTON( REMOVE_USER, GroupOptionsPanel::OnRemoveUser )
+END_EVENT_TABLE()
+
+GroupOptionsPanel::GroupOptionsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style )
+{
+ wxBoxSizer* mainSizer;
+ mainSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* groupListSizer;
+ groupListSizer = new wxBoxSizer( wxVERTICAL );
+
+ m_group_list = new wxListBox( this, GROUPS_LIST, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_ALWAYS_SB|wxLB_SINGLE|wxLB_SORT );
+ groupListSizer->Add( m_group_list, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ wxBoxSizer* groupListButtonsSizer;
+ groupListButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_remove_group_button = new wxButton( this, REMOVE_GROUP, _("Remove"), wxDefaultPosition, wxSize( -1,-1 ), wxBU_EXACTFIT );
+ m_remove_group_button->Enable( false );
+ m_remove_group_button->SetToolTip( _("Remove an existing group") );
+
+ groupListButtonsSizer->Add( m_remove_group_button, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ m_rename_group_button = new wxButton( this, RENAME_GROUP, _("Rename.."), wxDefaultPosition, wxSize( -1,-1 ), wxBU_EXACTFIT );
+ m_rename_group_button->Enable( false );
+ m_rename_group_button->SetToolTip( _("Rename an existing group") );
+
+ groupListButtonsSizer->Add( m_rename_group_button, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+
+ groupListButtonsSizer->Add( 0, 0, 1, wxEXPAND, 5 );
+
+ m_add_group_button = new wxButton( this, ADD_GROUP, _("Add New.."), wxDefaultPosition, wxSize( -1,-1 ), wxBU_EXACTFIT );
+ m_add_group_button->SetToolTip( _("Add new group") );
+
+ groupListButtonsSizer->Add( m_add_group_button, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ groupListSizer->Add( groupListButtonsSizer, 0, wxEXPAND|wxBOTTOM, 5 );
+
+ mainSizer->Add( groupListSizer, 2, wxEXPAND, 5 );
+
+ m_group_panel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL );
+ wxBoxSizer* mainGroupPanelSizer;
+ mainGroupPanelSizer = new wxBoxSizer( wxVERTICAL );
+
+ wxStaticBoxSizer* actionsSizer;
+ actionsSizer = new wxStaticBoxSizer( new wxStaticBox( m_group_panel, wxID_ANY, _("Group Actions") ), wxVERTICAL );
+
+ wxGridSizer* actionCheckSizer;
+ actionCheckSizer = new wxGridSizer( 2, 2, 0, 0 );
+
+ m_login_notify_check = new wxCheckBox( m_group_panel, NOTIFY_LOGIN, _("Notify login/logout"), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_login_notify_check->SetToolTip( _("Notify when users of this group go online or offline") );
+
+ actionCheckSizer->Add( m_login_notify_check, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ m_ignore_chat_check = new wxCheckBox( m_group_panel, IGNORE_CHAT, _("Ignore Chat"), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_ignore_chat_check->SetToolTip( _("Ignore anything said in channel by any of the users in this group") );
+
+ actionCheckSizer->Add( m_ignore_chat_check, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ m_notify_host_check = new wxCheckBox( m_group_panel, NOTIFY_HOST, _("Notify Hosted Battles"), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_notify_host_check->SetToolTip( _("Notify when users of this group hosts a battle") );
+
+ actionCheckSizer->Add( m_notify_host_check, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ m_ignore_pm_check = new wxCheckBox( m_group_panel, IGNORE_PM, _("Ignore PM"), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_ignore_pm_check->SetToolTip( _("Ignore anything said in private chat by any of the users in this group") );
+
+ actionCheckSizer->Add( m_ignore_pm_check, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ m_notify_status_check = new wxCheckBox( m_group_panel, NOTIFY_STATUS, _("Notify Status Change"), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_notify_status_check->SetToolTip( _("Notify when the status of a users in this group changes") );
+
+ actionCheckSizer->Add( m_notify_status_check, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ m_autokick_check = new wxCheckBox( m_group_panel, AUTOCKICK, _("Autokick"), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_autokick_check->SetToolTip( _("Auto kick any of the users in this group from battles hosted") );
+
+ actionCheckSizer->Add( m_autokick_check, 0, wxALL, 5 );
+
+ m_highlight_check = new wxCheckBox( m_group_panel, NOTIFY_HIGHLIGHT, _("Highlight"), wxDefaultPosition, wxDefaultSize, 0 );
+
+ m_highlight_check->SetToolTip( _("Highlight battles and the names of users in this group") );
+
+ actionCheckSizer->Add( m_highlight_check, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ wxBoxSizer* colorSizer;
+ colorSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_highlight_colorstaticText = new wxStaticText( m_group_panel, wxID_ANY, _("Highlight Color"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_highlight_colorstaticText->Wrap( -1 );
+ colorSizer->Add( m_highlight_colorstaticText, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ m_highlight_color_button = new ColorButton( m_group_panel, HIGHLIGHT_COLOR, wxColour(0,0,0), wxDefaultPosition, wxSize( 20,20 ) );
+ m_highlight_color_button->SetToolTip( _("Select highlight color") );
+
+ m_highlight_color_button->SetToolTip( _("Select highlight color") );
+
+ colorSizer->Add( m_highlight_color_button, 0, wxALL, 5 );
+
+ actionCheckSizer->Add( colorSizer, 1, wxEXPAND, 5 );
+
+ actionsSizer->Add( actionCheckSizer, 1, wxEXPAND, 5 );
+
+ mainGroupPanelSizer->Add( actionsSizer, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+
+ wxStaticBoxSizer* usersSizer;
+ usersSizer = new wxStaticBoxSizer( new wxStaticBox( m_group_panel, wxID_ANY, _("Users in group") ), wxVERTICAL );
+
+ wxBoxSizer* userListSizer;
+ userListSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_user_list = new wxListBox( m_group_panel, USERS_LIST, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE );
+ userListSizer->Add( m_user_list, 1, wxALL|wxEXPAND, 5 );
+
+ wxBoxSizer* userButtonSizer;
+ userButtonSizer = new wxBoxSizer( wxVERTICAL );
+
+ m_add_user_button = new wxButton( m_group_panel, ADD_USER, _("Add.."), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ m_add_user_button->SetToolTip( _("Add users to group") );
+
+ userButtonSizer->Add( m_add_user_button, 0, wxEXPAND|wxTOP|wxRIGHT, 5 );
+
+ m_remove_user_button = new wxButton( m_group_panel, REMOVE_USER, _("Remove"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ m_remove_user_button->Enable( false );
+ m_remove_user_button->SetToolTip( _("Remove users from group") );
+
+ userButtonSizer->Add( m_remove_user_button, 0, wxEXPAND|wxTOP|wxRIGHT, 5 );
+
+ userListSizer->Add( userButtonSizer, 0, wxEXPAND, 5 );
+
+ usersSizer->Add( userListSizer, 1, wxEXPAND, 5 );
+
+ mainGroupPanelSizer->Add( usersSizer, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+
+ m_group_panel->SetSizer( mainGroupPanelSizer );
+ m_group_panel->Layout();
+ mainGroupPanelSizer->Fit( m_group_panel );
+ mainSizer->Add( m_group_panel, 3, wxALL|wxEXPAND, 5 );
+
+ this->SetSizer( mainSizer );
+ this->Layout();
+
+ Initialize();
+}
+
+void GroupOptionsPanel::Initialize()
+{
+ m_user_dialog = 0;
+ ReloadGroupsList();
+ ShowGroup( wxEmptyString );
+}
+
+GroupOptionsPanel::~GroupOptionsPanel()
+{
+}
+
+void GroupOptionsPanel::ShowGroup( const wxString& group )
+{
+ if ( group == wxEmptyString ) m_current_group = GetFirstGroupName();
+ else m_current_group = group;
+
+ m_group_list->SetStringSelection(m_current_group);
+
+ UserActions::ActionType act = useractions().GetGroupAction( m_current_group );
+
+ m_login_notify_check->SetValue( (act & UserActions::ActNotifLogin) != 0 );
+ m_ignore_chat_check->SetValue( (act & UserActions::ActIgnoreChat) != 0 );
+ m_notify_host_check->SetValue( (act & UserActions::ActNotifBattle) != 0 );
+ m_ignore_pm_check->SetValue( (act & UserActions::ActIgnorePM) != 0 );
+ m_notify_status_check->SetValue( (act & UserActions::ActNotifStatus) != 0 );
+ m_autokick_check->SetValue( (act & UserActions::ActAutokick) != 0 );
+ m_highlight_check->SetValue( (act & UserActions::ActHighlight) != 0 );
+
+ m_highlight_color_button->SetColor( useractions().GetGroupColor(m_current_group) );
+
+ ReloadUsersList();
+ m_remove_group_button->Enable( m_group_list->GetStringSelection() != wxEmptyString );
+}
+
+void GroupOptionsPanel::ReloadUsersList()
+{
+ wxSortedArrayString groupuser = sett().GetPeopleList( m_current_group );
+ m_user_list->Clear();
+ m_user_list->InsertItems(groupuser, 0);
+ m_remove_user_button->Enable( false );
+}
+
+void GroupOptionsPanel::ReloadGroupsList()
+{
+ wxSortedArrayString groupnames = useractions().GetGroupNames();
+ m_group_list->Clear();
+ m_group_list->InsertItems(groupnames, 0);
+ m_group_list->SetStringSelection(m_current_group);
+}
+
+wxString GroupOptionsPanel::GetFirstGroupName()
+{
+ wxSortedArrayString groupnames = useractions().GetGroupNames();
+ if (groupnames.Count() <= 0) return wxEmptyString;
+ return groupnames[0];
+}
+
+void GroupOptionsPanel::OnRemoveGroup( wxCommandEvent& /*unused*/ )
+{
+ if (m_current_group == _T("Default")) return;
+ useractions().DeleteGroup( m_current_group );
+ ReloadGroupsList();
+ ShowGroup(wxEmptyString);
+}
+
+
+void GroupOptionsPanel::OnRenameGroup( wxCommandEvent& /*unused*/ )
+{
+}
+
+
+void GroupOptionsPanel::OnAddNewGroup( wxCommandEvent& /*unused*/ )
+{
+ wxTextEntryDialog* ted = new wxTextEntryDialog(this, _("Name of new group:"), _("Add New Group"));
+ if ( ted->ShowModal() == wxID_OK ) {
+ wxString newgroup = ted->GetValue();
+ //!TODO: Check if group exists already.
+ if ( newgroup != wxEmptyString ) useractions().AddGroup( newgroup );
+ ReloadGroupsList();
+ ShowGroup(newgroup);
+ }
+ delete ted;
+}
+
+
+void GroupOptionsPanel::OnGroupListSelectionChange( wxCommandEvent& /*unused*/ )
+{
+ wxString newgroup = m_group_list->GetStringSelection();
+ wxSortedArrayString groupnames = useractions().GetGroupNames();
+ if ( groupnames.Index(newgroup) == wxNOT_FOUND ) {
+ return;
+ }
+ ShowGroup(newgroup);
+}
+
+
+void GroupOptionsPanel::OnGroupActionsChange( wxCommandEvent& event )
+{
+ useractions().ChangeAction( m_current_group, UserActions::ActNotifLogin, m_login_notify_check->GetValue() );
+ useractions().ChangeAction( m_current_group, UserActions::ActIgnoreChat, m_ignore_chat_check->GetValue() );
+ useractions().ChangeAction( m_current_group, UserActions::ActNotifBattle, m_notify_host_check->GetValue() );
+ useractions().ChangeAction( m_current_group, UserActions::ActIgnorePM, m_ignore_pm_check->GetValue() );
+ useractions().ChangeAction( m_current_group, UserActions::ActNotifStatus, m_notify_status_check->GetValue() );
+ useractions().ChangeAction( m_current_group, UserActions::ActAutokick, m_autokick_check->GetValue() );
+ useractions().ChangeAction( m_current_group, UserActions::ActHighlight, m_highlight_check->GetValue() );
+}
+
+
+void GroupOptionsPanel::OnHighlightColorClick( wxCommandEvent& event )
+{
+ ColorButton* origin = (ColorButton*) event.GetEventObject();
+ wxColour c = GetColourFromUser( this, origin->GetColor(), m_current_group );
+ if ( c.IsOk() )
+ {
+ origin->SetColor( c );
+ useractions().SetGroupColor( m_current_group, c );
+ }
+}
+
+
+void GroupOptionsPanel::OnUsersListSelectionChange( wxCommandEvent& /*unused*/ )
+{
+ wxArrayInt sel;
+ m_user_list->GetSelections( sel );
+ m_remove_user_button->Enable( sel.Count() > 0 );
+}
+
+
+void GroupOptionsPanel::OnAddUsers( wxCommandEvent& /*unused*/ )
+{
+ wxSortedArrayString users = SelectUsersDialog::GetUsers(this);
+ for ( unsigned int i = 0; i < users.Count(); i++ ) {
+ useractions().AddUserToGroup( m_current_group, users[i] );
+ }
+ if ( users.Count() > 0 ) ReloadUsersList();
+}
+
+
+void GroupOptionsPanel::OnRemoveUser( wxCommandEvent& /*unused*/ )
+{
+ wxArrayInt sel;
+ int num = m_user_list->GetSelections( sel );
+ for ( int i = 0; i < num; i++ ) {
+ wxString name = m_user_list->GetString(sel[i]);
+ useractions().RemoveUser( name );
+ }
+ ReloadUsersList();
+}
+
+
+void GroupOptionsPanel::Update()
+{
+ ReloadGroupsList();
+ ReloadUsersList();
+}
diff --git a/src/groupoptionspanel.h b/src/groupoptionspanel.h
new file mode 100644
index 0000000..35bb458
--- /dev/null
+++ b/src/groupoptionspanel.h
@@ -0,0 +1,103 @@
+
+#ifndef SPRINGLOBBY_HEADERGUARD_GROUPOPTIONSPANEL_H
+#define SPRINGLOBBY_HEADERGUARD_GROUPOPTIONSPANEL_H
+
+#include <wx/panel.h>
+#include <wx/string.h>
+
+
+class ColorButton;
+class GroupUserDialog;
+class wxCheckBox;
+class wxStaticText;
+class wxListBox;
+class wxButton;
+
+class GroupOptionsPanel : public wxPanel
+{
+ DECLARE_EVENT_TABLE()
+
+ protected:
+ enum
+ {
+ REMOVE_GROUP = 1000,
+ RENAME_GROUP,
+ ADD_GROUP,
+ GROUPS_LIST,
+ NOTIFY_LOGIN,
+ IGNORE_CHAT,
+ NOTIFY_HOST,
+ IGNORE_PM,
+ NOTIFY_STATUS,
+ AUTOCKICK,
+ NOTIFY_HIGHLIGHT,
+ HIGHLIGHT_COLOR,
+ USERS_LIST,
+ ADD_USER,
+ REMOVE_USER,
+ };
+
+ wxListBox* m_group_list;
+ wxButton* m_remove_group_button;
+ wxButton* m_rename_group_button;
+
+ wxButton* m_add_group_button;
+ wxPanel* m_group_panel;
+ wxCheckBox* m_login_notify_check;
+ wxCheckBox* m_ignore_chat_check;
+ wxCheckBox* m_notify_host_check;
+ wxCheckBox* m_ignore_pm_check;
+ wxCheckBox* m_notify_status_check;
+ wxCheckBox* m_autokick_check;
+ wxCheckBox* m_highlight_check;
+ wxStaticText* m_highlight_colorstaticText;
+ ColorButton* m_highlight_color_button;
+ wxListBox* m_user_list;
+ wxButton* m_add_user_button;
+ wxButton* m_remove_user_button;
+
+ wxString m_current_group;
+ GroupUserDialog* m_user_dialog;
+
+ void OnRemoveGroup( wxCommandEvent& event );
+ void OnRenameGroup( wxCommandEvent& event );
+ void OnAddNewGroup( wxCommandEvent& event );
+ void OnGroupListSelectionChange( wxCommandEvent& event );
+ void OnGroupActionsChange( wxCommandEvent& event );
+ void OnHighlightColorClick( wxCommandEvent& event );
+ void OnUsersListSelectionChange( wxCommandEvent& event );
+ void OnAddUsers( wxCommandEvent& event );
+ void OnRemoveUser( wxCommandEvent& event );
+
+ void Initialize();
+
+ void ShowGroup( const wxString& group );
+ void ReloadUsersList();
+ void ReloadGroupsList();
+ wxString GetFirstGroupName();
+
+ public:
+ GroupOptionsPanel( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 656,537 ), long style = wxTAB_TRAVERSAL );
+ ~GroupOptionsPanel();
+ void Update();
+};
+
+#endif
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/hostbattledialog.cpp b/src/hostbattledialog.cpp
new file mode 100644
index 0000000..a23ebcb
--- /dev/null
+++ b/src/hostbattledialog.cpp
@@ -0,0 +1,363 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: HostBattleDialog
+//
+
+#include "hostbattledialog.h"
+
+#include <wx/intl.h>
+#include <wx/string.h>
+#include <wx/sizer.h>
+#include <wx/choice.h>
+#include <wx/slider.h>
+#include <wx/statline.h>
+#include <wx/button.h>
+#include <wx/stattext.h>
+#include <wx/statline.h>
+#include <wx/statbox.h>
+#include <wx/radiobox.h>
+#include <wx/radiobut.h>
+#include <wx/textctrl.h>
+#include <wx/statbmp.h>
+#include <wx/checkbox.h>
+#include <wx/log.h>
+#include <wx/menu.h>
+#include <wx/image.h>
+#include <wx/bmpbuttn.h>
+
+
+#include "settings.h"
+#include "iunitsync.h"
+#include "user.h"
+#include "uiutils.h"
+#include "utils/controls.h"
+#include "settings++/custom_dialogs.h"
+#include "ui.h"
+#include "server.h"
+
+#include "images/rank0.xpm"
+#include "images/rank1.xpm"
+#include "images/rank2.xpm"
+#include "images/rank3.xpm"
+#include "images/rank4.xpm"
+#include "images/rank5.xpm"
+#include "images/rank6.xpm"
+#include "images/arrow_refresh.png.h"
+
+BEGIN_EVENT_TABLE( HostBattleDialog, wxDialog )
+
+ EVT_BUTTON ( HOST_CANCEL, HostBattleDialog::OnCancel )
+ EVT_BUTTON ( HOST_OK, HostBattleDialog::OnOk )
+ EVT_BUTTON ( BTN_REFRESH, HostBattleDialog::OnReloadMods )
+ EVT_BUTTON ( PICK_RELAYHOST, HostBattleDialog::OnPickRelayHost )
+ EVT_MENU ( wxID_ANY, HostBattleDialog::OnRelayChoice )
+ EVT_RADIOBOX ( CHOSE_NAT, HostBattleDialog::OnNatChange )
+ EVT_CHECKBOX ( CHK_USE_RELAY, HostBattleDialog::OnUseRelay )
+
+END_EVENT_TABLE()
+
+HostBattleDialog::HostBattleDialog( wxWindow* parent )
+ : wxDialog( parent, -1, _( "Host new battle" ), wxDefaultPosition, wxSize( 410, 441 ), wxDEFAULT_DIALOG_STYLE ),
+ m_last_relayhost( sett().GetLastRelayedHost() )
+{
+ this->SetSizeHints( wxDefaultSize, wxDefaultSize );
+
+ wxFlexGridSizer* topsizer = new wxFlexGridSizer( 2, 0, 10);
+// topsizer->AddGrowableCol( 1, 1 );
+
+ SetSizeHints( wxDefaultSize, wxDefaultSize );
+ wxBoxSizer* m_main_sizer;
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_desc_lbl = new wxStaticText( this, wxID_ANY, _( "Description" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_desc_lbl->Wrap( -1 );
+ topsizer->Add( m_desc_lbl, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+// wxBoxSizer* desc_sizer = new wxBoxSizer( wxVERTICAL );
+ m_desc_text = new wxTextCtrl( this, wxID_ANY, sett().GetLastHostDescription(), wxDefaultPosition, wxDefaultSize, 0 );
+ m_desc_text->SetToolTip( TE( _( "A short description of the game, this will show up in the battle list." ) ) );
+ topsizer ->Add( m_desc_text, 1, wxALL | wxEXPAND, 5 );
+
+ m_desc_check = new wxCheckBox( this, wxID_ANY, _( "Autopaste description" ) );
+ m_desc_check->SetValue( sett().GetBattleLastAutoAnnounceDescription() );
+ m_desc_check->SetToolTip( TE( _( "Automatically write the battle description when a user joins." ) ) );
+
+ topsizer->AddStretchSpacer();
+ topsizer->Add( m_desc_check, 0, wxLEFT, 5 );
+// topsizer->Add( desc_sizer , 0, wxEXPAND | wxALL, 0 );
+
+ m_mod_lbl = new wxStaticText( this, wxID_ANY, _( "Mod" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_mod_lbl->Wrap( -1 );
+ topsizer->Add( m_mod_lbl, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxArrayString m_mod_picChoices;
+ wxBoxSizer* mod_choice_button_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_mod_pic = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_mod_picChoices, 0 );
+ m_mod_pic->SetToolTip( TE( _( "Select the mod to play with." ) ) );
+ mod_choice_button_sizer->Add( m_mod_pic, 0, wxALL , 5 );
+
+ wxBitmap mp = charArr2wxBitmap( arrow_refresh_png, sizeof( arrow_refresh_png ) );
+ m_refresh_btn = new wxBitmapButton( this, BTN_REFRESH, mp );
+ mod_choice_button_sizer->Add( m_refresh_btn, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );
+
+ topsizer->Add( mod_choice_button_sizer, 0, wxEXPAND|wxALL ,1 );
+
+ m_pwd_lbl = new wxStaticText( this, wxID_ANY, _( "Password" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_pwd_lbl->Wrap( -1 );
+ topsizer->Add( m_pwd_lbl, 1, wxALL| wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_pwd_text = new wxTextCtrl( this, wxID_ANY, sett().GetLastHostPassword(), wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD );
+ m_pwd_text->SetToolTip( TE( _( "Password needed to join game. Keep empty for no password" ) ) );
+ topsizer->Add( m_pwd_text, 1, wxALL| wxEXPAND, 5 );
+
+ m_port_lbl = new wxStaticText( this, wxID_ANY, _( "Port" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_port_lbl->Wrap( -1 );
+ topsizer->Add( m_port_lbl, 1, wxALL| wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_port_text = new wxTextCtrl( this, wxID_ANY, wxString::Format( _T( "%d" ), sett().GetLastHostPort() ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_port_text->SetToolTip( TE( _( "UDP port to host game on. Default is 8452." ) ) );
+ topsizer->Add( m_port_text, 1, wxALL| wxEXPAND, 5 );
+
+// m_port_test_check = new wxCheckBox( this, wxID_ANY, _("Test firewall"), wxDefaultPosition, wxDefaultSize, 0 );
+// m_port_test_check->SetValue( sett().GetTestHostPort() );
+// m_port_sizer->Add( m_port_test_check, 1, wxALL|wxEXPAND, 5 );
+
+
+
+ m_relayed_host_check = new wxCheckBox( this, CHK_USE_RELAY, _( "Use relayhost" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_relayed_host_check->SetToolTip( TE( _( "host and control game on remote server, helps if you have trouble hosting" ) ) );
+ m_relayed_host_pick = new wxButton( this, PICK_RELAYHOST, _( "" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_relayed_host_pick->SetLabel( m_last_relayhost.IsEmpty() ? _T("automatic") : m_last_relayhost );
+
+ m_relayhost_list = new wxMenu();
+ wxMenuItem* automatic_pick = new wxMenuItem( m_relayhost_list, AUTO_PICK_HOST, _("Chose automatically"), _("Randomly picks an available one"), wxITEM_RADIO );
+ m_relayhost_list->Append( automatic_pick );
+ automatic_pick->Check( m_last_relayhost.IsEmpty() );
+ m_relayhost_list->AppendSeparator();
+ wxMenuItem* manual_pick_relay = new wxMenuItem( m_relayhost_list, MANUAL_PICK_HOST, _("Manually enter the manager name"), _("You'll get prompted for the exact manager name"), wxITEM_RADIO );
+ m_relayhost_list->Append( manual_pick_relay );
+ m_relayhost_list->AppendSeparator();
+ m_relayhost_array_list = ui().GetServer().GetRelayHostList();
+ for ( unsigned int i = 0; i < m_relayhost_array_list.GetCount(); i++ )
+ {
+ wxMenuItem* newitem = new wxMenuItem( m_relayhost_list, MANUAL_PICK_HOST + 1 + i, m_relayhost_array_list[i], _T("") , wxITEM_RADIO );
+ m_relayhost_list->Append( newitem );
+ newitem->Check( m_last_relayhost == m_relayhost_array_list[i] );
+ }
+
+ m_relayed_host_check->SetValue( sett().GetLastHostRelayedMode() );
+ m_relayed_host_pick->Show( m_relayed_host_check->IsChecked() );
+
+ topsizer->Add( m_relayed_host_check, 1, wxALL | wxEXPAND, 5 );
+ topsizer->Add( m_relayed_host_pick, 0, wxALL | wxEXPAND, 5);
+
+ m_main_sizer->Add( topsizer, 0, wxEXPAND, 0 );
+
+ wxStaticBoxSizer* m_players_box;
+ m_players_box = new wxStaticBoxSizer( new wxStaticBox( this, -1, _( "Number of players" ) ), wxVERTICAL );
+
+ m_players_box->SetMinSize( wxSize( -1, 60 ) );
+ m_players_slide = new wxSlider( this, wxID_ANY, sett().GetLastHostPlayerNum(), 2, SPRING_MAX_USERS, wxDefaultPosition, wxDefaultSize, wxSL_AUTOTICKS | wxSL_BOTH | wxSL_HORIZONTAL | wxSL_LABELS );
+ m_players_slide->SetToolTip( TE( _( "The maximum number of players to allow in the battle." ) ) );
+ m_players_box->Add( m_players_slide, 0, wxALL | wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_players_box, 0, wxALL | wxEXPAND, 5 );
+
+ wxBoxSizer* m_pl_nat_sizer;
+ m_pl_nat_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxString m_nat_radiosChoices[] = { _( "None" ), _( "Hole punching" )/*, _("Fixed source ports")*/ };
+ int m_nat_radiosNChoices = sizeof( m_nat_radiosChoices ) / sizeof( wxString );
+ m_nat_radios = new wxRadioBox( this, CHOSE_NAT, _( "NAT traversal" ), wxDefaultPosition, wxDefaultSize, m_nat_radiosNChoices, m_nat_radiosChoices, 1, wxRA_SPECIFY_COLS );
+ m_nat_radios->SetSelection( sett().GetLastHostNATSetting() );
+
+ //m_nat_radios->Enable( false );
+ m_nat_radios->Enable( true );
+
+ m_nat_radios->SetToolTip( TE( _( "NAT traversal to use." ) ) );
+
+ m_pl_nat_sizer->Add( m_nat_radios, 1, wxALL | wxEXPAND, 5 );
+
+ wxStaticBoxSizer* m_rank_box;
+ m_rank_box = new wxStaticBoxSizer( new wxStaticBox( this, -1, _( "Minimum Rank needed" ) ), wxVERTICAL );
+
+ wxFlexGridSizer* m_rank_sizer;
+ m_rank_sizer = new wxFlexGridSizer( 2, 6, 0, 0 );
+ m_rank_sizer->SetFlexibleDirection( wxBOTH );
+
+ m_rank0_radio = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
+ m_rank_sizer->Add( m_rank0_radio, 0, wxALL, 5 );
+
+ m_rank0_img = new wxStaticBitmap( this, wxID_ANY, wxBitmap( rank0_xpm ), wxDefaultPosition, wxSize( 16, 16 ), 0 );
+ m_rank_sizer->Add( m_rank0_img, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ m_rank1_radio = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_rank_sizer->Add( m_rank1_radio, 0, wxALL, 5 );
+
+ m_rank1_img = new wxStaticBitmap( this, wxID_ANY, wxBitmap( rank1_xpm ), wxDefaultPosition, wxSize( 16, 16 ), 0 );
+ m_rank_sizer->Add( m_rank1_img, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL | wxALL, 2 );
+
+ m_rank2_radio = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_rank_sizer->Add( m_rank2_radio, 0, wxALL, 5 );
+
+ m_rank2_img = new wxStaticBitmap( this, wxID_ANY, wxBitmap( rank2_xpm ), wxDefaultPosition, wxSize( 16, 16 ), 0 );
+ m_rank_sizer->Add( m_rank2_img, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 2 );
+
+ m_rank3_radio = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_rank_sizer->Add( m_rank3_radio, 0, wxALL, 5 );
+
+ m_rank3_img = new wxStaticBitmap( this, wxID_ANY, wxBitmap( rank3_xpm ), wxDefaultPosition, wxSize( 16, 16 ), 0 );
+ m_rank_sizer->Add( m_rank3_img, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 2 );
+
+ m_rank4_radio = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_rank_sizer->Add( m_rank4_radio, 0, wxALL, 5 );
+
+ m_rank4_img = new wxStaticBitmap( this, wxID_ANY, wxBitmap( rank4_xpm ), wxDefaultPosition, wxSize( 16, 16 ), 0 );
+ m_rank_sizer->Add( m_rank4_img, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 2 );
+
+ m_rank5_radio = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_rank_sizer->Add( m_rank5_radio, 0, wxALL, 5 );
+
+ m_rank5_img = new wxStaticBitmap( this, wxID_ANY, wxBitmap( rank5_xpm ), wxDefaultPosition, wxSize( 16, 16 ), 0 );
+ m_rank_sizer->Add( m_rank5_img, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ m_rank6_radio = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_rank_sizer->Add( m_rank6_radio, 0, wxALL, 5 );
+
+ m_rank6_img = new wxStaticBitmap( this, wxID_ANY, wxBitmap( rank6_xpm ), wxDefaultPosition, wxSize( 16, 16 ), 0 );
+ m_rank_sizer->Add( m_rank6_img, 0, wxALL, 5 );
+
+ m_rank_box->Add( m_rank_sizer, 1, wxEXPAND, 5 );
+
+ m_pl_nat_sizer->Add( m_rank_box, 1, wxALL | wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_pl_nat_sizer, 0, wxEXPAND, 5 );
+ m_main_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+ m_buttons_sep = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ m_main_sizer->Add( m_buttons_sep, 0, wxALL | wxEXPAND, 2 );
+
+ wxBoxSizer* m_buttons_sizer;
+ m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_cancel_btn = new wxButton( this, HOST_CANCEL, _( "Cancel" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_buttons_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+ m_buttons_sizer->Add( m_cancel_btn, 0, wxALL, 5 );
+
+ m_host_btn = new wxButton( this, HOST_OK, _( "Host" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_host_btn->SetToolTip( TE( _( "Start hosting the battle." ) ) );
+
+ m_buttons_sizer->Add( m_host_btn, 0, wxALL, 5 );
+
+ m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND, 5 );
+
+ this->SetSizer( m_main_sizer );
+ this->Layout();
+
+ m_host_btn->SetFocus();
+
+ ReloadModList();
+}
+
+
+void HostBattleDialog::ReloadModList()
+{
+ m_mod_pic->Clear();
+
+ wxArrayString modlist = usync().GetModList();
+ //modlist.Sort(CompareStringIgnoreCase);
+
+ size_t nummods = modlist.Count();
+ for ( size_t i = 0; i < nummods; i++ ) m_mod_pic->Insert( modlist[i], i );
+
+ wxString last = sett().GetLastHostMod();
+ if ( last != wxEmptyString )
+ m_mod_pic->SetSelection( m_mod_pic->FindString( last ) );
+
+ if ( m_mod_pic->GetSelection() == wxNOT_FOUND )
+ m_mod_pic->SetSelection( 0 );
+}
+
+
+void HostBattleDialog::OnOk( wxCommandEvent& /*unused*/ )
+{
+ if ( m_mod_pic->GetSelection() == wxNOT_FOUND ) {
+ wxLogWarning( _T( "no mod selected" ) );
+ customMessageBox( SL_MAIN_ICON, _( "You have to select a mod first." ), _( "No mod selected." ), wxOK );
+ return;
+ }
+ if ( m_desc_text->GetValue().IsEmpty() ) m_desc_text->SetValue( _T( "(none)" ) );
+ sett().SetLastHostDescription( m_desc_text->GetValue() );
+ sett().SetLastHostMod( m_mod_pic->GetString( m_mod_pic->GetSelection() ) );
+ sett().SetLastHostPassword( m_pwd_text->GetValue() );
+ long tmp = DEFSETT_SPRING_PORT;
+ m_port_text->GetValue().ToLong( &tmp );
+ sett().SetLastHostPort( tmp );
+// sett().SetTestHostPort( m_port_test_check->GetValue() );
+ sett().SetTestHostPort( false );
+ sett().SetLastHostPlayerNum( m_players_slide->GetValue() );
+ sett().SetLastHostNATSetting( m_nat_radios->GetSelection() );
+ sett().SetLastRankLimit( GetSelectedRank() );
+ sett().SetLastHostRelayedMode( m_relayed_host_check->GetValue() );
+ sett().SetBattleLastAutoAnnounceDescription( m_desc_check->GetValue() );
+ sett().SetLastRelayedHost( m_last_relayhost );
+ sett().SaveSettings();
+ EndModal( wxID_OK );
+}
+
+
+void HostBattleDialog::OnCancel( wxCommandEvent& /*unused*/ )
+{
+ EndModal( wxID_CANCEL );
+}
+
+
+int HostBattleDialog::GetSelectedRank()
+{
+ if ( m_rank0_radio->GetValue() ) return 0;
+ if ( m_rank1_radio->GetValue() ) return 1;
+ if ( m_rank2_radio->GetValue() ) return 2;
+ if ( m_rank3_radio->GetValue() ) return 3;
+ if ( m_rank4_radio->GetValue() ) return 4;
+ if ( m_rank5_radio->GetValue() ) return 5;
+ if ( m_rank6_radio->GetValue() ) return 6;
+ return 000;
+}
+
+void HostBattleDialog::OnNatChange( wxCommandEvent& /*unused*/ )
+{
+// m_port_test_check->Enable( m_nat_radios->GetSelection() == 0 );
+ m_port_text->Enable( m_nat_radios->GetSelection() == 0 );
+}
+
+void HostBattleDialog::OnPickRelayHost( wxCommandEvent& event )
+{
+ PopupMenu( m_relayhost_list );
+}
+
+void HostBattleDialog::OnRelayChoice( wxCommandEvent& event )
+{
+ int index = event.GetId();
+ if ( index == AUTO_PICK_HOST )
+ m_last_relayhost = _T("");
+ else if ( index == MANUAL_PICK_HOST ) {
+ ui().AskText( _("Manually chose a manager"), _("Please type the nick of the manager you want to use ( case sensitive )"), m_last_relayhost );
+ }
+ else if ( !(index - MANUAL_PICK_HOST - 1 > m_relayhost_array_list.GetCount()) ){
+ index = index - MANUAL_PICK_HOST - 1;
+ m_last_relayhost = m_relayhost_array_list[index];
+ }
+ m_relayed_host_pick->SetLabel( m_last_relayhost.IsEmpty() ? _T("automatic") : m_last_relayhost );
+}
+
+void HostBattleDialog::OnUseRelay( wxCommandEvent& event )
+{
+ m_relayed_host_pick->Show( m_relayed_host_check->IsChecked() );
+ Layout();
+}
+
+void HostBattleDialog::OnReloadMods( wxCommandEvent& event )
+{
+ usync().ReloadUnitSyncLib();
+ ReloadModList();
+}
diff --git a/src/hostbattledialog.h b/src/hostbattledialog.h
new file mode 100644
index 0000000..a139ad3
--- /dev/null
+++ b/src/hostbattledialog.h
@@ -0,0 +1,118 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_HOSTBATTLEDIALOG_H
+#define SPRINGLOBBY_HEADERGUARD_HOSTBATTLEDIALOG_H
+
+
+#include <wx/dialog.h>
+
+class wxStaticText;
+class wxTextCtrl;
+class wxChoice;
+class wxSlider;
+class wxRadioBox;
+class wxRadioButton;
+class wxStaticBitmap;
+class wxStaticLine;
+class wxButton;
+class wxBitmapButton;
+class wxCheckBox;
+class wxMenu;
+
+class HostBattleDialog : public wxDialog
+{
+ public:
+ HostBattleDialog( wxWindow* parent );
+
+ void ReloadModList();
+
+
+ protected:
+
+ void OnOk ( wxCommandEvent& event );
+ void OnCancel ( wxCommandEvent& event );
+ void OnNatChange ( wxCommandEvent& event );
+ void OnReloadMods ( wxCommandEvent& event );
+ void OnRelayChoice ( wxCommandEvent& event );
+ void OnUseRelay ( wxCommandEvent& event );
+ void OnPickRelayHost( wxCommandEvent& event );
+
+ int GetSelectedRank();
+
+ wxStaticText* m_desc_lbl;
+ wxTextCtrl* m_desc_text;
+ wxStaticText* m_mod_lbl;
+ wxChoice* m_mod_pic;
+ wxStaticText* m_pwd_lbl;
+ wxTextCtrl* m_pwd_text;
+
+ wxStaticText* m_port_lbl;
+ wxTextCtrl* m_port_text;
+ wxTextCtrl* m_relayhost_name;
+// entirely disabled until functionality is in server
+// wxCheckBox* m_port_test_check;
+ wxCheckBox* m_relayed_host_check;
+ wxCheckBox* m_desc_check;
+ wxSlider* m_players_slide;
+ wxRadioBox* m_nat_radios;
+ wxRadioButton* m_rank0_radio;
+ wxStaticBitmap* m_rank0_img;
+ wxRadioButton* m_rank1_radio;
+ wxStaticBitmap* m_rank1_img;
+ wxRadioButton* m_rank2_radio;
+ wxStaticBitmap* m_rank2_img;
+ wxRadioButton* m_rank3_radio;
+ wxStaticBitmap* m_rank3_img;
+ wxRadioButton* m_rank4_radio;
+ wxStaticBitmap* m_rank4_img;
+ wxRadioButton* m_rank5_radio;
+ wxStaticBitmap* m_rank5_img;
+ wxRadioButton* m_rank6_radio;
+ wxStaticBitmap* m_rank6_img;
+
+ wxStaticLine* m_buttons_sep;
+ wxButton* m_cancel_btn;
+
+ wxButton* m_host_btn;
+
+ wxMenu* m_relayhost_list;
+ wxButton* m_relayed_host_pick;
+
+ wxBitmapButton* m_refresh_btn;
+
+
+ enum {
+ HOST_CANCEL = wxID_HIGHEST,
+ HOST_OK,
+ CHOSE_NAT,
+ PICK_RELAYHOST,
+ AUTO_PICK_HOST,
+ MANUAL_PICK_HOST,
+ BTN_REFRESH,
+ CHK_USE_RELAY
+ };
+
+ wxString m_last_relayhost;
+ wxArrayString m_relayhost_array_list;
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_HOSTBATTLEDIALOG_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/httpdownloader.cpp b/src/httpdownloader.cpp
new file mode 100644
index 0000000..3c2aad1
--- /dev/null
+++ b/src/httpdownloader.cpp
@@ -0,0 +1,163 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: HttpDownloader
+//
+
+#include <wx/file.h>
+#include <wx/intl.h>
+#include <wx/protocol/http.h>
+#include <wx/string.h>
+#include <wx/zipstrm.h>
+#include <wx/sstream.h>
+#include <wx/wfstream.h>
+#include <wx/app.h>
+#include <wx/log.h>
+#include <memory>
+
+
+#include "utils/conversion.h"
+#include "globalevents.h"
+
+template <class ParentClass>
+HttpDownloaderThread<ParentClass>::HttpDownloaderThread( const wxString& FileUrl, const wxString& DestPath,
+ ParentClass& parent, int code, const bool notify, const bool unzip,
+ const wxString& noticeErr, const wxString& noticeOk )
+ : m_destroy( false ),
+ m_destpath( DestPath ),
+ m_fileurl( FileUrl ),
+ m_do_unzip( unzip ),
+ m_notifyOnDownloadEvent( notify ),
+ m_noticeErr( noticeErr ),
+ m_noticeOk( noticeOk ),
+ m_id_code( code ),
+ m_parent( parent )
+{
+ Init();
+}
+
+template <class ParentClass>
+HttpDownloaderThread<ParentClass>::~HttpDownloaderThread()
+{
+}
+
+template <class ParentClass>
+void HttpDownloaderThread<ParentClass>::Init()
+{
+ Create();
+ Run();
+}
+
+template <class ParentClass>
+void* HttpDownloaderThread<ParentClass>::Entry()
+{
+ wxHTTP FileDownloading;
+ // normal timeout is 10 minutes.. set to 10 secs.
+ FileDownloading.SetTimeout( 60 );
+ FileDownloading.Connect( m_fileurl.BeforeFirst( _T( '/' ) ), 80 );
+ wxInputStream* m_httpstream = FileDownloading.GetInputStream( _T( "/" ) + m_fileurl.AfterFirst( _T( '/' ) ) );
+
+ if ( m_httpstream )
+ {
+ try
+ {
+ wxFileOutputStream outs( m_destpath );
+ m_httpstream->Read( outs );
+ outs.Close();
+ delete m_httpstream;
+ m_httpstream = 0;
+ //download success
+ if ( m_notifyOnDownloadEvent )
+ {
+ wxCommandEvent notice( httpDownloadEvtComplete, m_id_code );
+ notice.SetString( m_fileurl + _( "\nsuccessfully saved to:\n" ) + m_destpath );
+ if ( m_do_unzip )
+ {
+ bool unzipOk = Unzip();
+ if ( m_noticeOk == wxEmptyString )
+ {
+ if ( unzipOk ) notice.SetString( m_fileurl + _( "\nsuccessfully unzipped in:\n" ) + m_destpath );
+ else notice.SetString( notice.GetString() + _( "\n unzipping failed, please correct manually" ) );
+ }
+ }
+ if ( m_noticeOk != wxEmptyString ) notice.SetString( m_noticeOk );
+ notice.SetInt( FileDownloading.GetError() );
+ wxPostEvent( &m_parent, notice );
+ }
+ return NULL;
+ }
+ catch ( ... )
+ {
+ wxLogMessage( _T( "exception on download of" ) + m_fileurl );
+ }
+ }
+
+ //download failed
+ if ( m_notifyOnDownloadEvent )
+ {
+ wxCommandEvent notice( httpDownloadEvtFailed, m_id_code );
+ if ( m_noticeErr == wxEmptyString )
+ notice.SetString( _( "Could not save\n" ) + m_fileurl + _( "\nto:\n" ) + m_destpath );
+ else
+ notice.SetString( m_noticeErr );
+ notice.SetString( notice.GetString() + _( "\nError number: " ) + TowxString( FileDownloading.GetError() ) );
+ notice.SetInt( FileDownloading.GetError() );
+ wxPostEvent( &m_parent, notice );
+ }
+
+ return NULL;
+}
+
+template <class ParentClass>
+bool HttpDownloaderThread<ParentClass>::Unzip()
+{
+ try
+ {
+ std::auto_ptr<wxZipEntry> entry;
+
+ wxString base = wxPathOnly( m_destpath ) + wxFileName::GetPathSeparator();
+ wxFFileInputStream in( m_destpath );
+ wxZipInputStream zip( in );
+
+ while ( entry.reset( zip.GetNextEntry() ), entry.get() != NULL )
+ {
+ // access meta-data
+ wxString name = entry->GetInternalName();
+// name.Replace( wxT("/") , wxT("\\") );
+ // read 'zip' to access the entry's data
+ using namespace std;
+ wxString file = base + name;
+ wxString path = wxPathOnly( file );
+ if ( ( entry->IsDir() ) )
+ {
+ if ( !wxDirExists( file ) )
+ wxFileName::Mkdir( file, 0775, wxPATH_MKDIR_FULL );
+ wxLogWarning( path );
+ }
+ else
+ {
+ wxFFileOutputStream out( file );
+ out.Write( zip );
+ out.Close();
+ }
+ }
+ }
+ catch ( ... )
+ {
+ return false;
+ }
+
+ return true;
+
+}
+
+template <class ParentClass>
+bool HttpDownloaderThread<ParentClass>::TestDestroy()
+{
+ return m_destroy;
+}
+
+template <class ParentClass>
+void HttpDownloaderThread<ParentClass>::CloseThread()
+{
+ m_destroy = true;
+}
diff --git a/src/httpdownloader.h b/src/httpdownloader.h
new file mode 100644
index 0000000..aaa0e66
--- /dev/null
+++ b/src/httpdownloader.h
@@ -0,0 +1,58 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_HTTPDOWNLOADER
+#define SPRINGLOBBY_HEADERGUARD_HTTPDOWNLOADER
+
+#include "thread.h"
+#include <wx/event.h>
+
+const wxEventType httpDownloadEvtComplete = wxNewEventType();
+const wxEventType httpDownloadEvtFailed = wxNewEventType();
+
+template < class ParentClass >
+class HttpDownloaderThread : public Thread
+{
+ public:
+ HttpDownloaderThread( const wxString& FileUrl, const wxString& DestPath, ParentClass& parent, int code = 0, const bool notify = true, const bool unzip = true, const wxString& noticeErr = wxEmptyString, const wxString& noticeOk = wxEmptyString );
+ ~HttpDownloaderThread();
+ void Init();
+ void* Entry();
+ void CloseThread();
+ bool TestDestroy();
+ private:
+ bool m_destroy;
+
+ wxString m_destpath;
+ wxString m_fileurl;
+ bool Unzip();
+ bool m_do_unzip;
+ bool m_notifyOnDownloadEvent;
+
+ wxString m_noticeErr;
+ wxString m_noticeOk;
+
+ int m_id_code;
+
+ ParentClass& m_parent;
+
+};
+
+#include "httpdownloader.cpp"
+
+#endif // SPRINGLOBBY_HEADERGUARD_HTTPDOWNLOADER
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/ibattle.cpp b/src/ibattle.cpp
new file mode 100644
index 0000000..fd326bd
--- /dev/null
+++ b/src/ibattle.cpp
@@ -0,0 +1,1332 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include <wx/tokenzr.h>
+#include <wx/image.h>
+#include <sstream>
+#include <wx/timer.h>
+
+#include "ibattle.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "utils/math.h"
+#include "uiutils.h"
+#include "settings.h"
+#include "ui.h"
+#include "springunitsynclib.h"
+#include "images/fixcolours_palette.xpm"
+
+#include <list>
+#include <algorithm>
+#include <cmath>
+#include <set>
+
+const unsigned int TIMER_ID = 102;
+
+IBattle::IBattle():
+ m_map_loaded(false),
+ m_mod_loaded(false),
+ m_map_exists(false),
+ m_mod_exists(false),
+ m_ingame(false),
+ m_generating_script(false),
+ m_players_ready(0),
+ m_players_sync(0),
+ m_is_self_in(false),
+ m_timer ( 0 )
+{
+}
+
+
+IBattle::~IBattle()
+{
+ if ( m_timer ) m_timer->Stop();
+ delete m_timer;
+}
+
+bool IBattle::IsSynced()
+{
+ LoadMod();
+ LoadMap();
+ bool synced = true;
+ if ( !m_host_map.hash.IsEmpty() ) synced = synced && (m_local_map.hash == m_host_map.hash);
+ if ( !m_host_map.name.IsEmpty() ) synced = synced && (m_local_map.name == m_host_map.name);
+ if ( !m_host_mod.hash.IsEmpty() ) synced = synced && (m_local_mod.hash == m_host_mod.hash);
+ if ( !m_host_mod.name.IsEmpty() ) synced = synced && (m_local_mod.name == m_host_mod.name);
+ return synced;
+}
+
+
+
+
+
+std::vector<wxColour> &IBattle::GetFixColoursPalette( int numteams )
+{
+ static std::vector<wxColour> result;
+ if (result.empty())
+ {
+ wxImage image(fixcolours_palette_xpm);
+ unsigned char* data=image.GetData();
+ size_t len=image.GetWidth()*image.GetHeight();
+ for (size_t i=0;i<len;++i)
+ {
+ int r=data[i*3];
+ int g=data[i*3+1];
+ int b=data[i*3+2];
+ if (r||g||b)
+ {
+ result.push_back(wxColour(r,g,b));
+ }
+ }
+ }
+ if ( result.size() > numteams ) return result;
+ return GetBigFixColoursPalette( numteams );
+}
+
+wxColour IBattle::GetFixColour(int i)
+{
+ int size = m_teams_sizes.size();
+ std::vector<wxColour> palette = GetFixColoursPalette( size );
+ return palette[i];
+}
+
+int IBattle::GetPlayerNum( const User& user )
+{
+ for (user_map_t::size_type i = 0; i < GetNumUsers(); i++)
+ {
+ if ( &GetUser(i) == &user ) return i;
+ }
+ ASSERT_EXCEPTION(false, _T("The player is not in this game.") );
+ return -1;
+}
+
+#include <algorithm>
+class DismissColor {
+ protected:
+ typedef std::vector<wxColour>
+ ColorVec;
+ const ColorVec& m_other;
+
+ public:
+ DismissColor( const ColorVec& other )
+ : m_other( other )
+ {}
+
+ bool operator() ( wxColor to_check ) {
+ return std::find ( m_other.begin(), m_other.end(), to_check ) != m_other.end();
+ }
+};
+
+class AreColoursSimilarProxy {
+ int m_mindiff;
+
+ public:
+ AreColoursSimilarProxy( int mindiff )
+ : m_mindiff ( mindiff )
+ {}
+
+ bool operator() ( wxColor a, wxColor b ) {
+ return AreColoursSimilar( a, b, m_mindiff );
+ }
+};
+
+wxColour IBattle::GetFreeColour( User *for_whom )
+{
+ typedef std::vector<wxColour>
+ ColorVec;
+
+ ColorVec current_used_colors;
+ for ( user_map_t::size_type i = 0; i < GetNumUsers(); ++i ) {
+ UserBattleStatus& bs = GetUser( i ).BattleStatus();
+ current_used_colors.push_back( bs.colour );
+ }
+
+ int inc = 1;
+ while ( true ) {
+ ColorVec fixcolourspalette = GetFixColoursPalette( m_teams_sizes.size() + inc++ );
+
+ ColorVec::iterator fixcolourspalette_new_end = std::unique( fixcolourspalette.begin(), fixcolourspalette.end(), AreColoursSimilarProxy( 20 ) );
+
+ fixcolourspalette_new_end = std::remove_if( fixcolourspalette.begin(), fixcolourspalette.end(), DismissColor( current_used_colors ) );
+
+ if ( fixcolourspalette_new_end != fixcolourspalette.begin() )
+ return (*fixcolourspalette.begin());
+ }
+}
+
+wxColour IBattle::GetFreeColour( User &for_whom )
+{
+ return GetFreeColour( &for_whom );
+}
+
+
+wxColour IBattle::GetNewColour()
+{
+ return GetFreeColour();
+}
+
+int IBattle::ColourDifference(const wxColour &a, const wxColour &b) // returns max difference of r,g,b.
+{
+ return std::max(abs(a.Red()-b.Red()),std::max(abs(a.Green()-b.Green()),abs(a.Blue()-b.Blue())));
+
+}
+
+int IBattle::GetFreeTeamNum( bool excludeme )
+{
+ int lowest = 0;
+ bool changed = true;
+ while ( changed )
+ {
+ changed = false;
+ for ( user_map_t::size_type i = 0; i < GetNumUsers(); i++ )
+ {
+ if ( ( &GetUser( i ) == &GetMe() ) && excludeme ) continue;
+ //if ( GetUser( i ).BattleStatus().spectator ) continue;
+ if ( GetUser( i ).BattleStatus().team == lowest )
+ {
+ lowest++;
+ changed = true;
+ }
+ }
+ }
+ return lowest;
+}
+
+int IBattle::GetClosestFixColour(const wxColour &col, const std::vector<int> &excludes, int difference)
+{
+ std::vector<wxColour> palette = GetFixColoursPalette( m_teams_sizes.size() + 1 );
+ int result=0;
+ int t1=palette.size();
+ int t2=excludes.size();
+ wxLogMessage(_T("GetClosestFixColour %d %d"),t1,t2);
+ for (size_t i=0;i<palette.size();++i)
+ {
+ if ((i>=excludes.size()) || (!excludes[i]))
+ {
+ if (AreColoursSimilar( palette[i],col, difference ))
+ {
+ return i;
+ }
+ }
+ }
+ return result;
+}
+
+
+void IBattle::SendHostInfo( HostInfo /*unused*/ )
+{
+}
+
+void IBattle::SendHostInfo( const wxString& /*unused*/ )
+{
+}
+
+void IBattle::Update ( const wxString& /*unused*/)
+{
+}
+
+User& IBattle::OnUserAdded( User& user )
+{
+ UserList::AddUser( user );
+ UserBattleStatus& bs = user.BattleStatus();
+ bs.spectator = false;
+ bs.ready = false;
+ bs.sync = SYNC_UNKNOWN;
+ if ( !bs.IsBot() && IsFounderMe() && GetBattleType() == BT_Played )
+ {
+ bs.team = GetFreeTeamNum( &user == &GetMe() );
+ bs.ally = GetFreeAlly( &user == &GetMe() );
+ bs.colour = GetFreeColour( user );
+ }
+ if ( IsFounderMe() && ( ( bs.pos.x < 0 ) || ( bs.pos.y < 0 ) ) )
+ {
+ UserPosition& pos = bs.pos;
+ pos = GetFreePosition();
+ UserPositionChanged( user );
+ }
+ if ( !bs.spectator )
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( bs.team );
+ if ( itor == m_teams_sizes.end() ) m_teams_sizes[bs.team] = 1;
+ else m_teams_sizes[bs.team] = m_teams_sizes[bs.team] + 1;
+ std::map<int, int>::iterator iter = m_ally_sizes.find( bs.ally );
+ if ( iter == m_ally_sizes.end() ) m_ally_sizes[bs.ally] = 1;
+ else m_ally_sizes[bs.ally] = m_ally_sizes[bs.ally] + 1;
+ }
+ if ( bs.spectator ) m_opts.spectators++;
+ if ( bs.ready && !bs.IsBot() ) m_players_ready++;
+ if ( bs.sync && !bs.IsBot() ) m_players_sync++;
+ if ( !bs.spectator && !bs.IsBot() && ( !bs.ready || !bs.sync ) ) m_ready_up_map[user.GetNick()] = time(0);
+ return user;
+}
+
+User& IBattle::OnBotAdded( const wxString& nick, const UserBattleStatus& bs )
+{
+ m_internal_bot_list[nick] = User( nick );
+ User& user = m_internal_bot_list[nick];
+ user.UpdateBattleStatus( bs );
+ User& usr = OnUserAdded( user );
+ return usr;
+}
+
+unsigned int IBattle::GetNumBots() const
+{
+ return m_internal_bot_list.size();
+}
+
+unsigned int IBattle::GetNumPlayers() const
+{
+ return GetNumUsers() - GetNumBots();
+}
+
+void IBattle::OnUserBattleStatusUpdated( User &user, UserBattleStatus status )
+{
+
+ UserBattleStatus previousstatus = user.BattleStatus();
+
+ user.UpdateBattleStatus( status );
+
+ if ( IsFounderMe() )
+ {
+ if ( status.spectator != previousstatus.spectator )
+ {
+ if ( status.spectator )
+ {
+ m_opts.spectators++;
+ }
+ else
+ {
+ m_opts.spectators--;
+ }
+ SendHostInfo( HI_Spectators );
+ }
+ if ( m_opts.lockexternalbalancechanges )
+ {
+ if ( previousstatus.team != status.team ) ForceTeam( user, previousstatus.team );
+ if ( previousstatus.ally != status.ally ) ForceAlly( user, previousstatus.ally );
+ }
+ }
+ if ( status.spectator != previousstatus.spectator )
+ {
+ if ( !status.spectator )
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( status.team );
+ if ( itor == m_teams_sizes.end() ) m_teams_sizes[status.team] = 1;
+ else m_teams_sizes[status.team] = m_teams_sizes[status.team] + 1;
+ std::map<int, int>::iterator iter = m_ally_sizes.find( status.ally );
+ if ( iter == m_ally_sizes.end() ) m_ally_sizes[status.ally] = 1;
+ else m_ally_sizes[status.ally] = m_ally_sizes[status.ally] + 1;
+ }
+ else
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( status.team );
+ if ( itor != m_teams_sizes.end() )
+ {
+ itor->second = itor->second -1;
+ if ( itor->second == 0 )
+ {
+ m_teams_sizes.erase( itor );
+ }
+ }
+ std::map<int, int>::iterator iter = m_ally_sizes.find( status.ally );
+ if ( iter != m_ally_sizes.end() )
+ {
+ iter->second = iter->second - 1;
+ if ( iter->second == 0 )
+ {
+ m_ally_sizes.erase( iter );
+ }
+ }
+ }
+ }
+ else
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( previousstatus.team );
+ if ( itor != m_teams_sizes.end() )
+ {
+ itor->second = itor->second -1;
+ if ( itor->second == 0 )
+ {
+ m_teams_sizes.erase( itor );
+ }
+ }
+ itor = m_teams_sizes.find( status.team );
+ if ( itor != m_teams_sizes.end() ) itor->second = itor->second + 1;
+ else m_teams_sizes[status.team] = 1;
+
+ std::map<int, int>::iterator iter = m_ally_sizes.find( previousstatus.ally );
+ if ( iter != m_ally_sizes.end() )
+ {
+ iter->second = iter->second - 1;
+ if ( iter->second == 0 )
+ {
+ m_ally_sizes.erase( iter );
+ }
+ }
+ iter = m_ally_sizes.find( status.ally );
+ if ( iter != m_ally_sizes.end() ) iter->second = iter->second + 1;
+ else m_ally_sizes[status.ally] = 1;
+ }
+ if ( !status.IsBot() )
+ {
+ if ( ( previousstatus.ready != status.ready ) && !status.spectator && !previousstatus.spectator )
+ {
+ if ( status.ready ) m_players_ready++;
+ else m_players_ready--;
+ }
+ if ( ( previousstatus.sync != status.sync ) && !status.spectator && !previousstatus.spectator )
+ {
+ if ( status.sync ) m_players_sync++;
+ else m_players_sync--;
+ }
+ if ( ( status.ready && status.sync ) || status.spectator )
+ {
+ std::map<wxString, time_t>::iterator itor = m_ready_up_map.find( user.GetNick() );
+ if ( itor != m_ready_up_map.end() )
+ {
+ m_ready_up_map.erase( itor );
+ }
+ }
+ if ( ( !status.ready || !status.sync ) && !status.spectator )
+ {
+ std::map<wxString, time_t>::iterator itor = m_ready_up_map.find( user.GetNick() );
+ if ( itor == m_ready_up_map.end() )
+ {
+ m_ready_up_map[user.GetNick()] = time(0);
+ }
+ }
+ }
+}
+
+bool IBattle::ShouldAutoStart()
+{
+ if ( GetInGame() ) return false;
+ if ( !IsLocked() && ( ( GetNumPlayers() - m_opts.spectators ) ) < m_opts.maxplayers ) return false; // proceed checking for ready players only if the battle is full or locked
+ for ( unsigned int i = 0; i < GetNumUsers(); i++ )
+ {
+ User& usr = GetUser( i );
+ UserBattleStatus& status = usr.BattleStatus();
+ if ( status.IsBot() ) continue;
+ if ( !status.spectator && ( !status.sync || !status.ready ) ) return false;
+ }
+ return true;
+}
+
+void IBattle::OnUserRemoved( User& user )
+{
+ UserBattleStatus& bs = user.BattleStatus();
+ if ( !bs.spectator )
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( bs.team );
+ if ( itor != m_teams_sizes.end() )
+ {
+ itor->second = itor->second -1;
+ if ( itor->second == 0 )
+ {
+ m_teams_sizes.erase( itor );
+ }
+ }
+ std::map<int, int>::iterator iter = m_ally_sizes.find( bs.ally );
+ if ( iter != m_ally_sizes.end() )
+ {
+ iter->second = iter->second - 1;
+ if ( iter->second == 0 )
+ {
+ m_ally_sizes.erase( iter );
+ }
+ }
+ }
+ if ( bs.ready && !bs.IsBot() ) m_players_ready--;
+ if ( bs.sync && !bs.IsBot() ) m_players_sync--;
+ if ( IsFounderMe() && bs.spectator )
+ {
+ m_opts.spectators--;
+ SendHostInfo( HI_Spectators );
+ }
+ if ( &user == &GetMe() )
+ {
+ if ( m_timer ) m_timer->Stop();
+ delete m_timer;
+ m_timer = 0;
+ OnSelfLeftBattle();
+ }
+ UserList::RemoveUser( user.GetNick() );
+ if ( !bs.IsBot() ) user.SetBattle( 0 );
+ else
+ {
+ UserVecIter itor = m_internal_bot_list.find( user.GetNick() );
+ if ( itor != m_internal_bot_list.end() )
+ {
+ m_internal_bot_list.erase( itor );
+ }
+ }
+}
+
+
+bool IBattle::IsEveryoneReady()
+{
+ for (user_map_t::size_type i = 0; i < GetNumUsers(); i++)
+ {
+ User& usr = GetUser(i);
+ if ( usr.BattleStatus().IsBot() ) continue;
+ UserBattleStatus& bs = usr.BattleStatus();
+ if ( !bs.ready && !bs.spectator ) return false;
+ }
+ return true;
+}
+
+
+
+void IBattle::AddStartRect( unsigned int allyno, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom )
+{
+ BattleStartRect sr;
+
+ sr.ally = allyno;
+ sr.left = left;
+ sr.top = top;
+ sr.right = right;
+ sr.bottom = bottom;
+ sr.toadd = true;
+ sr.todelete = false;
+ sr.toresize = false;
+ sr.exist = true;
+
+ m_rects[allyno] = sr;
+}
+
+
+
+void IBattle::RemoveStartRect( unsigned int allyno )
+{
+ std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
+ if( rect_it == m_rects.end() )
+ return;
+
+ rect_it->second.todelete = true;
+ //BattleStartRect sr = m_rects[allyno];
+ //sr.todelete = true;
+ //m_rects[allyno] = sr;
+}
+
+
+void IBattle::ResizeStartRect( unsigned int allyno )
+{
+ std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
+ if( rect_it == m_rects.end() )
+ return;
+
+ rect_it->second.toresize = true;
+ //BattleStartRect sr = m_rects[allyno];
+ //&&sr.toresize = true;
+ //m_rects[allyno] = sr;
+}
+
+
+void IBattle::StartRectRemoved( unsigned int allyno )
+{
+ std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
+ if( rect_it == m_rects.end() )
+ return;
+
+ if ( rect_it->second.todelete ) m_rects.erase(allyno);
+}
+
+
+void IBattle::StartRectResized( unsigned int allyno )
+{
+ std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
+ if( rect_it == m_rects.end() )
+ return;
+
+ rect_it->second.toresize = false;
+ //BattleStartRect sr = m_rects[allyno];
+ //sr.toresize = false;
+ //m_rects[allyno] = sr;
+}
+
+
+void IBattle::StartRectAdded( unsigned int allyno )
+{
+ std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
+ if( rect_it == m_rects.end() )
+ return;
+
+ rect_it->second.toadd = false;
+ //BattleStartRect sr = m_rects[allyno];
+ //sr.toadd = false;
+ //m_rects[allyno] = sr;
+}
+
+
+BattleStartRect IBattle::GetStartRect( unsigned int allyno )
+{
+ std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
+ if( rect_it != m_rects.end() )
+ return (*rect_it).second;
+ return BattleStartRect();
+}
+
+//total number of start rects
+unsigned int IBattle::GetNumRects()
+{
+ return m_rects.size();
+}
+
+//key of last start rect in the map
+unsigned int IBattle::GetLastRectIdx()
+{
+ if(GetNumRects() > 0)
+ return m_rects.rbegin()->first;
+
+ return 0;
+
+}
+
+//return the lowest currently unused key in the map of rects.
+unsigned int IBattle::GetNextFreeRectIdx()
+{
+ //check for unused allyno keys
+ for(unsigned int i = 0; i <= GetLastRectIdx(); i++)
+ {
+ if(!GetStartRect(i).IsOk())
+ return i;
+ }
+ return GetNumRects(); //if all rects are in use, or no elements exist, return first possible available allyno.
+}
+
+void IBattle::ClearStartRects()
+{
+ m_rects.clear();
+}
+
+void IBattle::ForceSide( User& user, int side )
+{
+ if ( IsFounderMe() || user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().side = side;
+ }
+}
+
+void IBattle::ForceTeam( User& user, int team )
+{
+ if ( IsFounderMe() || user.BattleStatus().IsBot() )
+ {
+ if ( !user.BattleStatus().spectator )
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( user.BattleStatus().ally );
+ if ( itor != m_teams_sizes.end() )
+ {
+ itor->second = itor->second -1;
+ if ( itor->second == 0 )
+ {
+ m_teams_sizes.erase( itor );
+ }
+ }
+ itor = m_teams_sizes.find( team );
+ if ( itor != m_teams_sizes.end() ) itor->second = itor->second + 1;
+ else m_teams_sizes[team] = 1;
+ }
+ user.BattleStatus().team = team;
+ }
+}
+
+
+void IBattle::ForceAlly( User& user, int ally )
+{
+
+ if ( IsFounderMe() || user.BattleStatus().IsBot() )
+ {
+ if ( !user.BattleStatus().spectator )
+ {
+ std::map<int, int>::iterator itor = m_ally_sizes.find( user.BattleStatus().ally );
+ if ( itor != m_ally_sizes.end() )
+ {
+ itor->second = itor->second -1;
+ if ( itor->second == 0 )
+ {
+ m_ally_sizes.erase( itor );
+ }
+ }
+ itor = m_ally_sizes.find( ally );
+ if ( itor != m_ally_sizes.end() ) itor->second = itor->second + 1;
+ else m_ally_sizes[ally] = 1;
+ }
+ user.BattleStatus().ally = ally;
+ }
+
+}
+
+
+void IBattle::ForceColour( User& user, const wxColour& col )
+{
+ if ( IsFounderMe() || user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().colour = col;
+ }
+
+}
+
+
+void IBattle::ForceSpectator( User& user, bool spectator )
+{
+ if ( IsFounderMe() || user.BattleStatus().IsBot() )
+ {
+ UserBattleStatus& status = user.BattleStatus();
+ if ( status.spectator != spectator )
+ {
+ if ( !spectator )
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( status.team );
+ if ( itor == m_teams_sizes.end() ) m_teams_sizes[status.team] = 1;
+ else m_teams_sizes[status.team] = m_teams_sizes[status.team] + 1;
+ std::map<int, int>::iterator iter = m_ally_sizes.find( status.ally );
+ if ( iter == m_ally_sizes.end() ) m_ally_sizes[status.ally] = 1;
+ else m_ally_sizes[status.ally] = m_ally_sizes[status.ally] + 1;
+ }
+ else
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( status.team );
+ if ( itor != m_teams_sizes.end() )
+ {
+ itor->second = itor->second -1;
+ if ( itor->second == 0 )
+ {
+ m_teams_sizes.erase( itor );
+ }
+ }
+ std::map<int, int>::iterator iter = m_ally_sizes.find( status.ally );
+ if ( iter != m_ally_sizes.end() )
+ {
+ iter->second = iter->second - 1;
+ if ( iter->second == 0 )
+ {
+ m_ally_sizes.erase( iter );
+ }
+ }
+ }
+ if ( IsFounderMe() )
+ {
+ if ( spectator )
+ {
+ m_opts.spectators++;
+ }
+ else
+ {
+ m_opts.spectators--;
+ }
+ SendHostInfo( HI_Spectators );
+ }
+ }
+
+ user.BattleStatus().spectator = spectator;
+ }
+}
+
+void IBattle::SetHandicap( User& user, int handicap)
+{
+ if ( IsFounderMe() || user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().handicap = handicap;
+ }
+}
+
+
+void IBattle::KickPlayer( User& user )
+{
+ if ( IsFounderMe() || user.BattleStatus().IsBot() )
+ {
+ OnUserRemoved( user );
+ }
+}
+
+int IBattle::GetFreeAlly( bool excludeme )
+{
+ int lowest = 0;
+ bool changed = true;
+ while ( changed )
+ {
+ changed = false;
+ for ( unsigned int i = 0; i < GetNumUsers(); i++ )
+ {
+ User& user = GetUser( i );
+ if ( ( &GetUser( i ) == &GetMe() ) && excludeme ) continue;
+ if ( user.BattleStatus().ally == lowest )
+ {
+ lowest++;
+ changed = true;
+ }
+ }
+ }
+ return lowest;
+}
+
+UserPosition IBattle::GetFreePosition()
+{
+ UserPosition ret;
+ UnitSyncMap map = LoadMap();
+ for ( int i = 0; i < map.info.posCount; i++ )
+ {
+ bool taken = false;
+ for ( unsigned int bi = 0; bi < GetNumUsers(); bi++ )
+ {
+ User& user = GetUser( bi );
+ UserBattleStatus& status = user.BattleStatus();
+ if ( status.spectator ) continue;
+ if ( ( map.info.positions[i].x == status.pos.x ) && ( map.info.positions[i].y == status.pos.y ) )
+ {
+ taken = true;
+ break;
+ }
+ }
+ if ( !taken )
+ {
+ ret.x = clamp(map.info.positions[i].x, 0, map.info.width);
+ ret.y = clamp(map.info.positions[i].y, 0, map.info.height);
+ return ret;
+ }
+ }
+ ret.x = map.info.width / 2;
+ ret.y = map.info.height / 2;
+ return ret;
+}
+
+
+void IBattle::SetHostMap(const wxString& mapname, const wxString& hash)
+{
+ if ( mapname != m_host_map.name || hash != m_host_map.hash )
+ {
+ m_map_loaded = false;
+ m_host_map.name = mapname;
+ m_host_map.hash = hash;
+ if ( !m_host_map.hash.IsEmpty() ) m_map_exists = usync().MapExists( m_host_map.name, m_host_map.hash );
+ else m_map_exists = usync().MapExists( m_host_map.name );
+ #ifndef __WXMSW__
+ if ( m_map_exists && !ui().IsSpringRunning() ) usync().PrefetchMap( m_host_map.name );
+ #endif
+ }
+}
+
+
+void IBattle::SetLocalMap(const UnitSyncMap& map)
+{
+ if ( map.name != m_local_map.name || map.hash != m_local_map.hash ) {
+ m_local_map = map;
+ m_map_loaded = true;
+ if ( !m_host_map.hash.IsEmpty() ) m_map_exists = usync().MapExists( m_host_map.name, m_host_map.hash );
+ else m_map_exists = usync().MapExists( m_host_map.name );
+ #ifndef __WXMSW__
+ if ( m_map_exists && !ui().IsSpringRunning() ) usync().PrefetchMap( m_host_map.name );
+ #endif
+ if ( IsFounderMe() ) // save all rects infos
+ {
+
+ }
+ }
+}
+
+
+const UnitSyncMap& IBattle::LoadMap()
+{
+
+ if ( !m_map_loaded ) {
+ try {
+ ASSERT_EXCEPTION( m_map_exists, _T("Map does not exist.") );
+ m_local_map = usync().GetMapEx( m_host_map.name );
+ m_map_loaded = true;
+
+ } catch (...) {}
+ }
+ return m_local_map;
+}
+
+
+wxString IBattle::GetHostMapName() const
+{
+ return m_host_map.name;
+}
+
+
+wxString IBattle::GetHostMapHash() const
+{
+ return m_host_map.hash;
+}
+
+
+void IBattle::SetHostMod( const wxString& modname, const wxString& hash )
+{
+ if ( m_host_mod.name != modname || m_host_mod.hash != hash )
+ {
+ m_mod_loaded = false;
+ m_host_mod.name = modname;
+ m_host_mod.hash = hash;
+ if ( !m_host_mod.hash.IsEmpty() ) m_mod_exists = usync().ModExists( m_host_mod.name, m_host_mod.hash );
+ else m_mod_exists = usync().ModExists( m_host_mod.name );
+ }
+}
+
+
+void IBattle::SetLocalMod( const UnitSyncMod& mod )
+{
+ if ( mod.name != m_local_mod.name || mod.hash != m_local_mod.hash )
+ {
+ m_local_mod = mod;
+ m_mod_loaded = true;
+ if ( !m_host_mod.hash.IsEmpty() ) m_mod_exists = usync().ModExists( m_host_mod.name, m_host_mod.hash );
+ else m_mod_exists = usync().ModExists( m_host_mod.name );
+ }
+}
+
+
+const UnitSyncMod& IBattle::LoadMod()
+{
+ if ( !m_mod_loaded )
+ {
+ try {
+ ASSERT_EXCEPTION( m_mod_exists, _T("Mod does not exist.") );
+ m_local_mod = usync().GetMod( m_host_mod.name );
+ m_mod_loaded = true;
+ } catch (...) {}
+ }
+ return m_local_mod;
+}
+
+
+wxString IBattle::GetHostModName() const
+{
+ return m_host_mod.name;
+}
+
+
+wxString IBattle::GetHostModHash() const
+{
+ return m_host_mod.hash;
+}
+
+
+bool IBattle::MapExists() const
+{
+ return m_map_exists;
+ //return usync().MapExists( m_map_name, m_map.hash );
+}
+
+
+bool IBattle::ModExists() const
+{
+ return m_mod_exists;
+ //return usync().ModExists( m_mod_name );
+}
+
+
+
+void IBattle::RestrictUnit( const wxString& unitname, int count )
+{
+ m_restricted_units[ unitname ] = count;
+}
+
+
+void IBattle::UnrestrictUnit( const wxString& unitname )
+{
+ std::map<wxString,int>::iterator pos = m_restricted_units.find( unitname );
+ if ( pos == m_restricted_units.end() ) return;
+ m_restricted_units.erase( pos );
+}
+
+
+void IBattle::UnrestrictAllUnits()
+{
+ m_restricted_units.clear();
+}
+
+
+std::map<wxString,int> IBattle::RestrictedUnits()
+{
+ return m_restricted_units;
+}
+
+void IBattle::OnSelfLeftBattle()
+{
+ susynclib().UnSetCurrentMod(); //left battle
+ m_is_self_in = false;
+ ClearStartRects();
+}
+
+void IBattle::OnUnitSyncReloaded()
+{
+ if ( !m_host_mod.hash.IsEmpty() ) m_mod_exists = usync().ModExists( m_host_mod.name, m_host_mod.hash);
+ else m_mod_exists = usync().ModExists( m_host_mod.name );
+ if ( !m_host_map.hash.IsEmpty() ) m_map_exists = usync().MapExists( m_host_map.name, m_host_map.hash );
+ else m_map_exists = usync().MapExists( m_host_map.name );
+}
+
+
+
+static wxString FixPresetName( const wxString& name )
+{
+ // look name up case-insensitively
+ const wxArrayString& presetList = sett().GetPresetList();
+ int index = presetList.Index( name, false /*case insensitive*/ );
+ if ( index == -1 ) return _T("");
+
+ // set preset to the actual name, with correct case
+ return presetList[index];
+}
+
+
+bool IBattle::LoadOptionsPreset( const wxString& name )
+{
+ wxString preset = FixPresetName(name);
+ if (preset == _T("")) return false; //preset not found
+ m_preset = preset;
+
+ for ( unsigned int i = 0; i < OptionsWrapper::LastOption; i++)
+ {
+ std::map<wxString,wxString> options = sett().GetHostingPreset( m_preset, i );
+ if ( (OptionsWrapper::GameOption)i != OptionsWrapper::PrivateOptions )
+ {
+ for ( std::map<wxString,wxString>::iterator itor = options.begin(); itor != options.end(); itor++ )
+ {
+ wxLogWarning( itor->first + _T(" ::: ") + itor->second );
+ CustomBattleOptions().setSingleOption( itor->first, itor->second, (OptionsWrapper::GameOption)i );
+ }
+ }
+ else
+ {
+ if ( !options[_T("mapname")].IsEmpty() )
+ {
+ if ( usync().MapExists( options[_T("mapname")] ) ) {
+ UnitSyncMap map = usync().GetMapEx( options[_T("mapname")] );
+ SetLocalMap( map );
+ SendHostInfo( HI_Map );
+ }
+ else if ( !ui().OnPresetRequiringMap( options[_T("mapname")] ) ) {
+ //user didn't want to download the missing map, so set to empty to not have it tried to be loaded again
+ options[_T("mapname")] = _T("");
+ sett().SetHostingPreset( m_preset, i, options );
+ }
+ }
+
+ for( unsigned int i = 0; i <= GetLastRectIdx(); ++i ) if ( GetStartRect( i ).IsOk() ) RemoveStartRect(i); // remove all rects that might come from map presets
+ SendHostInfo( IBattle::HI_StartRects );
+
+ unsigned int rectcount = s2l( options[_T("numrects")] );
+ for ( unsigned int loadrect = 0; loadrect < rectcount; loadrect++)
+ {
+ int ally = s2l(options[_T("rect_") + TowxString(loadrect) + _T("_ally")]);
+ if ( ally == 0 ) continue;
+ AddStartRect( ally - 1, s2l(options[_T("rect_") + TowxString(loadrect) + _T("_left")]), s2l(options[_T("rect_") + TowxString(loadrect) + _T("_top")]), s2l(options[_T("rect_") + TowxString(loadrect) + _T("_right")]), s2l(options[_T("rect_") + TowxString(loadrect) + _T("_bottom")]) );
+ }
+ SendHostInfo( HI_StartRects );
+
+ wxStringTokenizer tkr( options[_T("restrictions")], _T('\t') );
+ m_restricted_units.clear();
+ while( tkr.HasMoreTokens() )
+ {
+ wxString unitinfo = tkr.GetNextToken();
+ RestrictUnit( unitinfo.BeforeLast(_T('=')), s2l( unitinfo.AfterLast(_T('=')) ) );
+ }
+ SendHostInfo( HI_Restrictions );
+ Update( wxString::Format( _T("%d_restrictions"), OptionsWrapper::PrivateOptions ) );
+
+ }
+ }
+ SendHostInfo( HI_Send_All_opts );
+ ui().ReloadPresetList();
+ return true;
+}
+
+
+void IBattle::SaveOptionsPreset( const wxString& name )
+{
+ m_preset = FixPresetName(name);
+ if (m_preset == _T("")) m_preset = name; //new preset
+
+ for ( int i = 0; i < (int)OptionsWrapper::LastOption; i++)
+ {
+ if ( (OptionsWrapper::GameOption)i != OptionsWrapper::PrivateOptions )
+ {
+ sett().SetHostingPreset( m_preset, (OptionsWrapper::GameOption)i, CustomBattleOptions().getOptionsMap( (OptionsWrapper::GameOption)i ) );
+ }
+ else
+ {
+ std::map<wxString,wxString> opts;
+ opts[_T("mapname")] = GetHostMapName();
+ unsigned int validrectcount = 0;
+ if ( s2l (CustomBattleOptions().getSingleValue( _T("startpostype"), OptionsWrapper::EngineOption ) ) == ST_Choose )
+ {
+ unsigned int boxcount = GetLastRectIdx();
+ for ( unsigned int boxnum = 0; boxnum <= boxcount; boxnum++ )
+ {
+ BattleStartRect rect = GetStartRect( boxnum );
+ if ( rect.IsOk() )
+ {
+ opts[_T("rect_") + TowxString(validrectcount) + _T("_ally")] = TowxString( rect.ally + 1 );
+ opts[_T("rect_") + TowxString(validrectcount) + _T("_left")] = TowxString( rect.left );
+ opts[_T("rect_") + TowxString(validrectcount) + _T("_top")] = TowxString( rect.top );
+ opts[_T("rect_") + TowxString(validrectcount) + _T("_bottom")] = TowxString( rect.bottom );
+ opts[_T("rect_") + TowxString(validrectcount) + _T("_right")] = TowxString( rect.right );
+ validrectcount++;
+ }
+ }
+ }
+ opts[_T("numrects")] = TowxString( validrectcount );
+
+ wxString restrictionsstring;
+ for ( std::map<wxString, int>::iterator itor = m_restricted_units.begin(); itor != m_restricted_units.end(); itor++ )
+ {
+ restrictionsstring << itor->first << _T('=') << TowxString(itor->second) << _T('\t');
+ }
+ opts[_T("restrictions")] = restrictionsstring;
+
+ sett().SetHostingPreset( m_preset, (OptionsWrapper::GameOption)i, opts );
+ }
+ }
+ sett().SaveSettings();
+ ui().ReloadPresetList();
+}
+
+
+wxString IBattle::GetCurrentPreset()
+{
+ return m_preset;
+}
+
+
+void IBattle::DeletePreset( const wxString& name )
+{
+ wxString preset = FixPresetName(name);
+ if ( m_preset == preset ) m_preset = _T("");
+ sett().DeletePreset( preset );
+ ui().ReloadPresetList();
+}
+
+wxArrayString IBattle::GetPresetList()
+{
+ return sett().GetPresetList();
+}
+
+void IBattle::UserPositionChanged( const User& /*unused*/ )
+{
+}
+
+void IBattle::AddUserFromDemo( User& user )
+{
+ user.BattleStatus().isfromdemo = true;
+ m_internal_user_list[user.GetNick()] = user;
+ UserList::AddUser( m_internal_user_list[user.GetNick()] );
+}
+
+void IBattle::SetIsProxy( bool value )
+{
+ m_opts.isproxy = value;
+}
+
+bool IBattle::IsProxy()
+{
+ return m_opts.isproxy;
+}
+
+bool IBattle::IsFounderMe()
+{
+ return ( ( m_opts.founder == GetMe().GetNick() ) || ( m_opts.isproxy && !m_generating_script ) );
+}
+
+bool IBattle::IsFounder( const User& user ) const
+{
+ if ( UserExists( m_opts.founder ) ) {
+ try
+ {
+ return &GetFounder() == &user;
+ }catch(...){return false;}
+ }
+ else
+ return false;
+}
+
+int IBattle::GetMyPlayerNum()
+{
+ return GetPlayerNum( GetMe() );
+}
+
+
+void IBattle::LoadScriptMMOpts( const wxString& sectionname, const PDataList& node )
+{
+ if ( !node.ok() ) return;
+ PDataList section ( node->Find(sectionname) );
+ if ( !section.ok() ) return;
+ OptionsWrapper& opts = CustomBattleOptions();
+ for ( PNode n = section->First(); n != section->Last(); n = section->Next( n ) )
+ {
+ if ( !n.ok() ) continue;
+ opts.setSingleOption( n->Name(), section->GetString( n->Name() ) );
+ }
+}
+
+void IBattle::LoadScriptMMOpts( const PDataList& node )
+{
+ if ( !node.ok() ) return;
+ OptionsWrapper& opts = CustomBattleOptions();
+ typedef std::map<wxString,wxString> optMap;
+ optMap options = opts.getOptionsMap(OptionsWrapper::EngineOption);
+ for ( optMap::const_iterator i = options.begin(); i != options.end(); ++i)
+ {
+ opts.setSingleOption( i->first, node->GetString( i->first, i->second ) );
+ }
+}
+
+//! (koshi) don't delete commented things please, they might be need in the future and i'm lazy
+void IBattle::GetBattleFromScript( bool loadmapmod )
+{
+
+ BattleOptions opts;
+ std::stringstream ss ( (const char *)GetScript().mb_str(wxConvUTF8) );// no need to convert wxstring-->std::string-->std::stringstream, convert directly.
+ PDataList script( ParseTDF(ss) );
+
+ PDataList replayNode ( script->Find(_T("GAME") ) );
+ if ( replayNode.ok() )
+ {
+
+ wxString modname = replayNode->GetString( _T("GameType") );
+ wxString modhash = replayNode->GetString( _T("ModHash") );
+ if ( !modhash.IsEmpty() ) modhash = MakeHashUnsigned( modhash );
+ SetHostMod( modname, modhash );
+
+ //don't have the maphash, what to do?
+ //ui download function works with mapname if hash is empty, so works for now
+ wxString mapname = replayNode->GetString( _T("MapName") );
+ wxString maphash = replayNode->GetString( _T("MapHash") );
+ if ( !maphash.IsEmpty() ) maphash = MakeHashUnsigned( maphash );
+ SetHostMap( mapname, maphash );
+
+// opts.ip = replayNode->GetString( _T("HostIP") );
+// opts.port = replayNode->GetInt ( _T("HostPort"), DEFAULT_EXTERNAL_UDP_SOURCE_PORT );
+ opts.spectators = 0;
+
+ int playernum = replayNode->GetInt ( _T("NumPlayers"), 0);
+ int usersnum = replayNode->GetInt ( _T("NumUsers"), 0);
+ if ( usersnum > 0 ) playernum = usersnum;
+// int allynum = replayNode->GetInt ( _T("NumAllyTeams"), 1);
+// int teamnum = replayNode->GetInt ( _T("NumTeams"), 1);
+
+
+
+ wxArrayString sides;
+ if ( loadmapmod )
+ {
+ sides = usync().GetSides( modname );
+ }
+
+ IBattle::TeamVec parsed_teams = GetParsedTeamsVec();
+ IBattle::AllyVec parsed_allies = GetParsedAlliesVec();
+
+ //[PLAYERX] sections
+ for ( int i = 0; i < playernum ; ++i )
+ {
+ PDataList player ( replayNode->Find( _T("PLAYER") + TowxString(i) ) );
+ PDataList bot ( replayNode->Find( _T("AI") + TowxString(i) ) );
+ if ( player.ok() || bot.ok() )
+ {
+ if ( bot.ok() ) player = bot;
+ User user ( player->GetString( _T("Name") ), (player->GetString( _T("CountryCode")).Upper() ), 0);
+ UserBattleStatus& status = user.BattleStatus();
+ status.isfromdemo = true;
+ status.spectator = player->GetInt( _T("Spectator"), 0 );
+ opts.spectators += user.BattleStatus().spectator;
+ status.team = player->GetInt( _T("Team") );
+ if ( !status.spectator )
+ {
+ std::map<int, int>::iterator itor = m_teams_sizes.find( status.team );
+ if ( itor == m_teams_sizes.end() ) m_teams_sizes[status.team] = 1;
+ else m_teams_sizes[status.team] = m_teams_sizes[status.team] + 1;
+ }
+ status.sync = true;
+ status.ready = true;
+ if ( status.spectator ) m_opts.spectators++;
+ if ( status.ready && !bot.ok() ) m_players_ready++;
+ if ( status.sync && !bot.ok() ) m_players_sync++;
+
+ //! (koshi) changed this from ServerRankContainer to RankContainer
+ user.Status().rank = (UserStatus::RankContainer)player->GetInt( _T("Rank"), -1 );
+
+ if ( bot.ok() )
+ {
+ status.aishortname = bot->GetString( _T("ShortName" ) );
+ status.aiversion = bot->GetString( _T("Version" ) );
+ int ownerindex = bot->GetInt( _T("Host" ) );
+ PDataList aiowner ( replayNode->Find( _T("PLAYER") + TowxString(ownerindex) ) );
+ if ( aiowner.ok() )
+ {
+ status.owner = aiowner->GetString( _T("Name") );
+ }
+ }
+
+ IBattle::TeamInfoContainer teaminfos = parsed_teams[user.BattleStatus().team];
+ if ( !teaminfos.exist )
+ {
+ PDataList team( replayNode->Find( _T("TEAM") + TowxString( user.BattleStatus().team ) ) );
+ if ( team.ok() )
+ {
+ teaminfos.exist = true;
+ teaminfos.TeamLeader = team->GetInt( _T("TeamLeader"), 0 );
+ teaminfos.StartPosX = team->GetInt( _T("StartPosX"), -1 );
+ teaminfos.StartPosY = team->GetInt( _T("StartPosY"), -1 );
+ teaminfos.AllyTeam = team->GetInt( _T("AllyTeam"), 0 );
+ teaminfos.RGBColor = GetColorFromFloatStrng( team->GetString( _T("RGBColor") ) );
+ teaminfos.SideName = team->GetString( _T("Side"), _T("") );
+ teaminfos.Handicap = team->GetInt( _T("Handicap"), 0 );
+ int sidepos = sides.Index( teaminfos.SideName );
+ teaminfos.SideNum = sidepos;
+ parsed_teams[ user.BattleStatus().team ] = teaminfos;
+ }
+ }
+ if ( teaminfos.exist )
+ {
+ status.ally = teaminfos.AllyTeam;
+ status.pos.x = teaminfos.StartPosX;
+ status.pos.y = teaminfos.StartPosY;
+ status.colour = teaminfos.RGBColor;
+ status.handicap = teaminfos.Handicap;
+ if ( !status.spectator )
+ {
+ std::map<int, int>::iterator iter = m_ally_sizes.find(status.ally );
+ if ( iter == m_ally_sizes.end() ) m_ally_sizes[status.ally] = 1;
+ else m_ally_sizes[status.ally] = m_ally_sizes[status.ally] + 1;
+ }
+ if ( teaminfos.SideNum >= 0 ) status.side = teaminfos.SideNum;
+ IBattle::AllyInfoContainer allyinfos = parsed_allies[user.BattleStatus().ally];
+ if ( !allyinfos.exist )
+ {
+ PDataList ally( replayNode->Find( _T("ALLYTEAM") + TowxString( user.BattleStatus().ally ) ) );
+ if ( ally.ok() )
+ {
+ allyinfos.exist = true;
+ allyinfos.NumAllies = ally->GetInt( _T("NumAllies"), 0 );
+ allyinfos.StartRectLeft = ally->GetInt( _T("StartRectLeft"), 0 );
+ allyinfos.StartRectTop = ally->GetInt( _T("StartRectTop"), 0 );
+ allyinfos.StartRectRight = ally->GetInt( _T("StartRectRight"), 0 );
+ allyinfos.StartRectBottom = ally->GetInt( _T("StartRectBottom"), 0 );
+ parsed_allies[ user.BattleStatus().ally ] = allyinfos;
+ AddStartRect( user.BattleStatus().ally, allyinfos.StartRectTop, allyinfos.StartRectTop, allyinfos.StartRectRight, allyinfos.StartRectBottom );
+ }
+ }
+ }
+
+ AddUserFromDemo( user );
+ }
+
+ }
+ SetParsedTeamsVec( parsed_teams );
+ SetParsedAlliesVec( parsed_allies );
+
+ //MMoptions, this'll fail unless loading map/mod into wrapper first
+ if ( loadmapmod )
+ {
+ LoadScriptMMOpts( _T("mapoptions"), replayNode );
+ LoadScriptMMOpts( _T("modoptions"), replayNode );
+ }
+
+ opts.maxplayers = playernum ;
+
+ }
+ SetBattleOptions( opts );
+}
+
+
diff --git a/src/ibattle.h b/src/ibattle.h
new file mode 100644
index 0000000..e8427d9
--- /dev/null
+++ b/src/ibattle.h
@@ -0,0 +1,453 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_IBATTLE_H
+#define SPRINGLOBBY_HEADERGUARD_IBATTLE_H
+
+
+#include <wx/string.h>
+#include <wx/event.h>
+
+#include "iunitsync.h"
+#include "user.h"
+#include "mmoptionswrapper.h"
+#include "userlist.h"
+#include "tdfcontainer.h"
+
+
+const unsigned int DEFAULT_SERVER_PORT = 8452;
+const unsigned int DEFAULT_EXTERNAL_UDP_SOURCE_PORT = 16941;
+
+class IBattle;
+class wxTimer;
+
+struct BattleStartRect
+{
+ BattleStartRect()
+ {
+ toadd = false;
+ todelete = false;
+ exist = false;
+ toresize = false;
+ }
+ bool toadd;
+ bool todelete;
+ bool toresize;
+ bool exist;
+
+ bool IsOk()
+ {
+ return exist && !todelete;
+ }
+
+ int ally;
+ int top;
+ int left;
+ int right;
+ int bottom;
+};
+
+
+enum NatType
+{
+ NAT_None = 0,
+ NAT_Hole_punching,
+ NAT_Fixed_source_ports
+};
+
+enum RankLimitType
+{
+ rank_limit_none = 0,
+ rank_limit_autospec,
+ rank_limit_autokick
+};
+
+
+enum BattleType
+{
+ BT_Played,
+ BT_Replay,
+ BT_Savegame
+};
+
+
+struct BattleOptions
+{
+ BattleOptions() :
+ battleid(-1),islocked(false),battletype(BT_Played),ispassworded(false),rankneeded(0),isproxy(false),lockexternalbalancechanges(false),ranklimittype(rank_limit_autospec),
+ nattype(NAT_None),port(DEFAULT_SERVER_PORT),externaludpsourceport(DEFAULT_EXTERNAL_UDP_SOURCE_PORT),internaludpsourceport(DEFAULT_EXTERNAL_UDP_SOURCE_PORT),maxplayers(0),spectators(0),
+ guilistactiv(false) {}
+
+ int battleid;
+ bool islocked;
+ BattleType battletype;
+ bool ispassworded;
+ int rankneeded;
+ bool isproxy;
+ bool lockexternalbalancechanges;
+ bool ranklimittype;
+
+ wxString founder;
+
+ NatType nattype;
+ unsigned int port;
+ wxString ip;
+ unsigned int externaludpsourceport;
+ unsigned int internaludpsourceport;
+
+ unsigned int maxplayers;
+ unsigned int spectators;
+ wxString relayhost;
+ wxString maphash;
+ wxString modhash;
+
+ wxString description;
+ wxString mapname;
+ wxString modname;
+
+ bool guilistactiv;
+};
+
+class IBattle: public UserList, public wxEvtHandler
+{
+public:
+
+ IBattle();
+ virtual ~IBattle();
+
+ /** @name Constants
+ * @{
+ */
+ enum HostInfo
+ {
+ HI_None = 0,
+ HI_Map = 1,
+ HI_Locked = 2,
+ HI_Spectators = 4,
+ HI_StartResources = 8,
+ HI_MaxUnits = 16,
+ HI_StartType = 32,
+ HI_GameType = 64,
+ HI_Options = 128,
+ HI_StartRects = 256,
+ HI_Restrictions = 512,
+ HI_Map_Changed = 1024,
+ HI_Mod_Changed = 2048,
+ HI_User_Positions = 4096,
+ HI_Send_All_opts = 8192
+ };
+
+ /**@}*/
+
+ /** @name Enums
+ * @{
+ */
+
+
+ enum BalanceType
+ {
+ balance_divide,
+ balance_random
+ };
+
+ enum StartType
+ {
+ ST_Fixed = 0,
+ ST_Random = 1,
+ ST_Choose = 2,
+ ST_Pick = 3
+ };
+
+ enum GameType
+ {
+ GT_ComContinue = 0,
+ GT_ComEnds = 1,
+ GT_Lineage = 2
+ };
+
+
+ struct TeamInfoContainer
+ {
+ bool exist;
+ int TeamLeader;
+ int StartPosX;
+ int StartPosY;
+ int AllyTeam;
+ wxColour RGBColor;
+ wxString SideName;
+ int Handicap;
+ int SideNum;
+ };
+
+ struct AllyInfoContainer
+ {
+ bool exist;
+ int NumAllies;
+ int StartRectLeft;
+ int StartRectTop;
+ int StartRectRight;
+ int StartRectBottom;
+ };
+
+
+ /**@}*/
+
+ virtual void SetHostMap( const wxString& mapname, const wxString& hash );
+ virtual void SetLocalMap( const UnitSyncMap& map );
+ virtual const UnitSyncMap& LoadMap();
+ virtual wxString GetHostMapName() const;
+ virtual wxString GetHostMapHash() const;
+
+ virtual void SetIsProxy( bool value );
+ virtual bool IsProxy();
+
+ virtual bool IsSynced();
+
+ virtual bool IsFounderMe();
+ virtual bool IsFounder( const User& user ) const;
+
+ virtual int GetMyPlayerNum();
+
+ virtual int GetPlayerNum( const User& user );
+
+ virtual void SetHostMod( const wxString& modname, const wxString& hash );
+ virtual void SetLocalMod( const UnitSyncMod& mod );
+ virtual const UnitSyncMod& LoadMod();
+ virtual wxString GetHostModName() const;
+ virtual wxString GetHostModHash() const;
+
+ virtual bool MapExists() const;
+ virtual bool ModExists() const;
+
+ virtual BattleStartRect GetStartRect( unsigned int allyno );
+ User& OnUserAdded( User& user );
+ void OnUserBattleStatusUpdated( User &user, UserBattleStatus status );
+ void OnUserRemoved( User& user );
+
+ bool IsEveryoneReady();
+
+ void ForceSide( User& user, int side );
+ void ForceAlly( User& user, int ally );
+ void ForceTeam( User& user, int team );
+ void ForceColour( User& user, const wxColour& col );
+ void ForceSpectator( User& user, bool spectator );
+ void SetHandicap( User& user, int handicap);
+ void KickPlayer( User& user );
+
+
+ virtual void AddStartRect( unsigned int allyno, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom );
+ virtual void RemoveStartRect( unsigned int allyno );
+ virtual void ResizeStartRect( unsigned int allyno );
+ virtual void StartRectRemoved( unsigned int allyno );
+ virtual void StartRectResized( unsigned int allyno );
+ virtual void StartRectAdded( unsigned int allyno );
+ virtual void ClearStartRects();
+ virtual unsigned int GetNumRects();
+ virtual unsigned int GetLastRectIdx();
+ virtual unsigned int GetNextFreeRectIdx();
+
+ virtual int GetFreeTeamNum( bool excludeme = false );
+
+ virtual User& GetMe() = 0;
+
+ virtual void SendHostInfo( HostInfo update );
+ virtual void SendHostInfo( const wxString& Tag );
+ virtual void Update ( const wxString& Tag );
+
+ virtual unsigned int GetNumBots() const;
+ virtual User& OnBotAdded( const wxString& nick, const UserBattleStatus& bs );
+
+ virtual UserPosition GetFreePosition();
+ virtual int GetFreeAlly( bool excludeme = false );
+
+ virtual void RestrictUnit( const wxString& unitname, int count = 0 );
+ virtual void UnrestrictUnit( const wxString& unitname );
+ virtual void UnrestrictAllUnits();
+ virtual std::map<wxString,int> RestrictedUnits();
+
+ virtual void OnUnitSyncReloaded();
+
+ virtual OptionsWrapper& CustomBattleOptions()
+ {
+ return m_opt_wrap;
+ }
+
+ virtual bool LoadOptionsPreset( const wxString& name );
+ virtual void SaveOptionsPreset( const wxString& name );
+ virtual wxString GetCurrentPreset();
+ virtual void DeletePreset( const wxString& name );
+ virtual wxArrayString GetPresetList();
+
+ virtual std::vector<wxColour> &GetFixColoursPalette( int numteams );
+ virtual int GetClosestFixColour(const wxColour &col, const std::vector<int> &excludes, int difference);
+ virtual wxColour GetFixColour(int i);
+ virtual wxColour GetFreeColour( User &for_whom );
+ wxColour GetFreeColour( User *for_whom = NULL );
+ wxColour GetNewColour();
+
+ virtual int ColourDifference(const wxColour &a, const wxColour &b);
+
+ User& GetFounder() const { return GetUser( m_opts.founder ); }
+
+ bool IsFull() const { return GetMaxPlayers() == ( GetNumUsers() - GetSpectators() ); }
+
+ virtual unsigned int GetNumPlayers() const;
+
+ virtual int GetBattleId() const { return m_opts.battleid; }
+
+ virtual bool GetGUIListActiv() const { return m_opts.guilistactiv; }
+ virtual void SetGUIListActiv(bool Activ) { m_opts.guilistactiv = Activ; }
+
+ virtual void SetInGame( bool ingame ) { m_ingame = ingame; }
+ virtual bool GetInGame() const { return m_ingame; }
+
+ virtual void SetBattleType( BattleType type ) { m_opts.battletype = type; }
+ virtual BattleType GetBattleType() { return m_opts.battletype; }
+
+ virtual void SetIsLocked( const bool islocked ) { m_opts.islocked = islocked; }
+ virtual bool IsLocked() const { return m_opts.islocked; }
+ virtual void SetIsPassworded( const bool ispassworded ) { m_opts.ispassworded = ispassworded; }
+ virtual bool IsPassworded() const { return m_opts.ispassworded; }
+
+ virtual void SetNatType( const NatType nattype ) { m_opts.nattype = nattype; }
+ virtual NatType GetNatType() const { return m_opts.nattype; }
+ virtual void SetHostPort( unsigned int port) { m_opts.port = port; }
+
+ virtual void SetMyExternalUdpSourcePort(unsigned int port){m_opts.externaludpsourceport=port;}
+ virtual unsigned int GetMyExternalUdpSourcePort(){return m_opts.externaludpsourceport;}
+
+ virtual void SetMyInternalUdpSourcePort(unsigned int port){m_opts.internaludpsourceport=port;}
+ virtual unsigned int GetMyInternalUdpSourcePort(){return m_opts.internaludpsourceport;}
+
+ virtual int GetHostPort() const { return m_opts.port; }
+ virtual void SetFounder( const wxString& nick ) { m_opts.founder = nick; }
+ virtual void SetHostIp( const wxString& ip ) { m_opts.ip = ip; }
+ virtual wxString GetHostIp() const { return m_opts.ip; }
+
+ virtual void SetMaxPlayers( const int& maxplayers ) { m_opts.maxplayers = maxplayers; }
+ virtual unsigned int GetMaxPlayers() const { return m_opts.maxplayers; }
+ virtual void SetSpectators( const int& spectators ) { m_opts.spectators = spectators; }
+ virtual int GetSpectators() const { return m_opts.spectators; }
+
+ virtual void SetRankNeeded( const int& rankneeded ) { m_opts.rankneeded = rankneeded; }
+ virtual int GetRankNeeded() const { return m_opts.rankneeded; }
+
+ // virtual void SetMapHash( const wxString& maphash ) { m_opts.maphash = maphash; }
+ // virtual void SetMapname( const wxString& map ) { m_opts.mapname = map; }
+ virtual void SetDescription( const wxString& desc ) { m_opts.description = desc; }
+ virtual wxString GetDescription() const { return m_opts.description; }
+ // virtual void SetModname( const wxString& mod ) { m_opts.modname = mod; }
+
+
+ typedef std::map<wxString, User> UserVec;
+ typedef UserVec::const_iterator UserVecCIter;
+ typedef UserVec::iterator UserVecIter;
+
+ void SetBattleOptions( const BattleOptions& options ) { m_opts = options; }
+
+ virtual void OnSelfLeftBattle();
+
+ /// replay&savegame parsing stuff
+ typedef std::map<int, TeamInfoContainer> TeamVec;
+ typedef TeamVec::const_iterator TeamVecCIter;
+ typedef TeamVec::iterator TeamVecIter;
+
+ typedef std::map<int, AllyInfoContainer> AllyVec;
+ typedef AllyVec::const_iterator AllyVecCIter;
+ typedef AllyVec::iterator AllyVecIter;
+
+ TeamVec GetParsedTeamsVec() { return m_parsed_teams; }
+ AllyVec GetParsedAlliesVec() { return m_parsed_allies; }
+
+ void SetParsedTeamsVec( const TeamVec& t ) { m_parsed_teams = t; }
+ void SetParsedAlliesVec( const AllyVec& a ) { m_parsed_allies = a; }
+
+ const BattleOptions& GetBattleOptions() const { return m_opts; }
+
+ bool Equals( const IBattle& other ) const { return m_opts.battleid == other.GetBattleOptions().battleid; }
+
+ virtual void DisableHostStatusInProxyMode( bool value ) { m_generating_script = value; }
+
+ virtual void UserPositionChanged( const User& usr );
+
+ virtual void SetScript( const wxString& script ) { m_script = script; }
+ virtual void AppendScriptLine( const wxString& line ) { m_script << line; }
+ virtual void ClearScript() { m_script.Clear(); }
+ virtual wxString GetScript() { return m_script; }
+
+ virtual void SetPlayBackFilePath( const wxString& path ) { m_playback_file_path = path; }
+ virtual wxString GetPlayBackFilePath() { return m_playback_file_path; }
+
+ virtual void AddUserFromDemo( User& user );
+
+ virtual void GetBattleFromScript( bool loadmapmod );
+
+ virtual bool ShouldAutoStart();
+
+ virtual void StartSpring() = 0;
+
+protected:
+
+ void LoadScriptMMOpts( const wxString& sectionname, const PDataList& node );
+ void LoadScriptMMOpts( const PDataList& node );
+
+
+ bool m_map_loaded;
+ bool m_mod_loaded;
+ bool m_map_exists;
+ bool m_mod_exists;
+ UnitSyncMap m_local_map;
+ UnitSyncMod m_local_mod;
+ UnitSyncMap m_host_map;
+ UnitSyncMod m_host_mod;
+
+ std::map<wxString, int> m_restricted_units;
+
+ OptionsWrapper m_opt_wrap;
+
+ BattleOptions m_opts;
+
+ bool m_ingame;
+
+ bool m_generating_script;
+
+ std::map<unsigned int,BattleStartRect> m_rects;
+
+ std::map<wxString, time_t> m_ready_up_map; // player name -> time counting from join/unspect
+
+ int m_players_ready;
+ int m_players_sync;
+ std::map<int, int> m_teams_sizes; // controlteam -> number of people in
+ std::map<int, int> m_ally_sizes; // allyteam -> number of people in
+
+ wxString m_preset;
+
+ bool m_is_self_in;
+ UserVec m_internal_bot_list;
+
+ /// replay&savegame stuff
+ wxString m_script;
+ wxString m_playback_file_path;
+ TeamVec m_parsed_teams;
+ AllyVec m_parsed_allies;
+ UserVec m_internal_user_list; /// to store users from savegame/replay
+
+ wxTimer* m_timer;
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_IBATTLE_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/iconimagelist.cpp b/src/iconimagelist.cpp
new file mode 100644
index 0000000..e989eb3
--- /dev/null
+++ b/src/iconimagelist.cpp
@@ -0,0 +1,391 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: IconImageList
+//
+
+#include <stdexcept>
+
+#include <wx/image.h>
+#include <wx/settings.h>
+#include <wx/dc.h>
+#include <wx/icon.h>
+
+#include "iconimagelist.h"
+#include "user.h"
+#include "battle.h"
+//#include "utils.h"
+#include "iunitsync.h"
+
+#include "images/bot.xpm"
+#include "images/bot_broom.png.h"
+#include "images/bot_ingame.png.h"
+#include "images/bot_away.xpm"
+
+#include "images/admin.png.h"
+#include "images/admin_away.png.h"
+#include "images/admin_broom.png.h"
+#include "images/admin_ingame.png.h"
+
+#include "images/chanop.xpm"
+#include "images/chanop_away.xpm"
+#include "images/chanop_broom.xpm"
+#include "images/chanop_ingame.xpm"
+
+#include "images/away.png.h"
+#include "images/broom.png.h"
+#include "images/ingame.png.h"
+
+#include "images/up.xpm"
+#include "images/down.xpm"
+#include "images/rank0.xpm"
+#include "images/rank1.xpm"
+#include "images/rank2.xpm"
+#include "images/rank3.xpm"
+#include "images/rank4.xpm"
+#include "images/rank5.xpm"
+#include "images/rank6.xpm"
+#include "images/rank_unknown.xpm"
+
+#include "images/open_game.png.h"
+#include "images/open_pw_game.png.h"
+#include "images/open_full_pw_game.png.h"
+#include "images/open_full_game.png.h"
+#include "images/closed_game.png.h"
+#include "images/closed_pw_game.png.h"
+#include "images/closed_full_pw_game.png.h"
+#include "images/closed_full_game.png.h"
+
+
+#include "images/nexists.xpm"
+#include "images/exists.xpm"
+
+#include "images/ready_unsync.xpm"
+#include "images/ready_q.xpm"
+#include "images/nready_unsync.xpm"
+#include "images/nready_q.xpm"
+
+#include "images/spectator.png.h"
+#include "images/host.xpm"
+#include "images/host_spectator.xpm"
+
+#include "images/no1_icon.png.h"
+#include "images/no2_icon.png.h"
+#include "images/warning_small.png.h"
+
+#include "images/colourbox.xpm"
+
+#include "images/unknown_flag.xpm"
+
+#include "images/channel_options.xpm"
+
+#include "flagimages.h"
+
+#include "images/empty.xpm"
+#include "uiutils.h"
+
+IconImageList::IconImageList() : wxImageList(16,16,true)
+{
+ ICON_ADMIN = Add( charArr2wxBitmap( admin_png, sizeof(admin_png) ) );
+ ICON_ADMIN_AWAY = Add( charArr2wxBitmap( admin_away_png, sizeof(admin_away_png) ) );
+ ICON_ADMIN_BROOM = Add( charArr2wxBitmap( admin_broom_png, sizeof(admin_broom_png) ) );
+ ICON_ADMIN_INGAME = Add( charArr2wxBitmap( admin_ingame_png, sizeof(admin_ingame_png) ) );
+
+ ICON_BOT = Add( wxBitmap(bot_xpm) );
+ ICON_BOT_BROOM = Add( charArr2wxBitmap( bot_broom_png, sizeof( bot_broom_png ) ) );
+ ICON_BOT_INGAME = Add( charArr2wxBitmap( bot_ingame_png, sizeof( bot_ingame_png ) ) );
+ ICON_BOT_AWAY = Add( wxBitmap(bot_away_xpm) );
+
+ ICON_AWAY = Add( charArr2wxBitmap( away_png, sizeof( away_png ) ) );
+ ICON_BROOM = Add( charArr2wxBitmap(broom_png, sizeof(broom_png) ) );
+ ICON_INGAME = Add( charArr2wxBitmap(ingame_png, sizeof(ingame_png) ) );
+
+ ICON_OP = Add( wxBitmap(chanop_xpm) );
+ ICON_OP_AWAY = Add( wxBitmap(chanop_away_xpm) );
+ ICON_OP_BROOM = Add( wxBitmap(chanop_broom_xpm) );
+ ICON_OP_INGAME = Add( wxBitmap(chanop_ingame_xpm) );
+
+ ICON_UP = Add( wxBitmap(up_xpm) );
+ ICON_DOWN = Add( wxBitmap(down_xpm) );
+
+ ICON_RANK_UNKNOWN = Add( wxBitmap(rank_unknown_xpm) );
+ ICON_RANK1 = Add( wxBitmap(rank0_xpm) );
+ ICON_RANK2 = Add( wxBitmap(rank1_xpm) );
+ ICON_RANK3 = Add( wxBitmap(rank2_xpm) );
+ ICON_RANK4 = Add( wxBitmap(rank3_xpm) );
+ ICON_RANK5 = Add( wxBitmap(rank4_xpm) );
+ ICON_RANK6 = Add( wxBitmap(rank5_xpm) );
+ ICON_RANK7 = Add( wxBitmap(rank6_xpm) );
+
+ ICON_READY = ICON_OPEN_GAME = Add( charArr2wxBitmap(open_game_png, sizeof(open_game_png) ) );
+ ICON_OPEN_PW_GAME = Add( charArr2wxBitmap(open_pw_game_png, sizeof(open_pw_game_png) ) );
+ ICON_OPEN_FULL_PW_GAME = Add( charArr2wxBitmap(open_full_pw_game_png, sizeof(open_full_pw_game_png) ) );
+ ICON_OPEN_FULL_GAME = Add( charArr2wxBitmap(open_full_game_png, sizeof(open_full_game_png) ) );
+ ICON_NREADY = ICON_CLOSED_GAME = Add( charArr2wxBitmap(closed_game_png, sizeof(closed_game_png) ) );
+ ICON_CLOSED_PW_GAME = Add( charArr2wxBitmap(closed_pw_game_png, sizeof(closed_pw_game_png) ) );
+ ICON_CLOSED_FULL_PW_GAME = Add( charArr2wxBitmap(closed_full_pw_game_png, sizeof(closed_full_pw_game_png) ) );
+ ICON_CLOSED_FULL_GAME = Add( charArr2wxBitmap(closed_full_game_png, sizeof(closed_full_game_png) ) );
+ ICON_STARTED_GAME = Add( charArr2wxBitmap(ingame_png, sizeof(ingame_png) ) );
+
+ ICON_STARTED_GAME_LOCKED = Add( charArr2wxBitmapWithBlending( closed_game_png, sizeof(closed_game_png), ingame_png, sizeof(ingame_png) ) );
+
+
+ ICON_READY_UNSYNC = Add( wxBitmap(ready_unsync_xpm) );
+ ICON_NREADY_UNSYNC = Add( wxBitmap(nready_unsync_xpm) );
+ ICON_READY_QSYNC = Add( wxBitmap(ready_q_xpm) );
+ ICON_NREADY_QSYNC = Add( wxBitmap(nready_q_xpm) );
+
+ ICON_NEXISTS = Add( wxBitmap(nexists_xpm) );
+ ICON_EXISTS = Add( wxBitmap(exists_xpm) );
+
+ ICON_SPECTATOR = Add( charArr2wxBitmap(spectator_png, sizeof(spectator_png) ) );
+ ICON_HOST = Add( wxBitmap(host_xpm) );
+ ICON_HOST_SPECTATOR = Add( wxBitmap(host_spectator_xpm) );
+
+ ICON_SIDEPIC_0 = Add( charArr2wxBitmap(no1_icon_png, sizeof(no1_icon_png) ) );
+ ICON_SIDEPIC_1 = Add( charArr2wxBitmap(no2_icon_png, sizeof(no2_icon_png) ) );
+
+ ICON_CHANNEL_OPTIONS = Add( wxBitmap(channel_options_xpm) );
+
+ SetColourIcon( 0, wxColour( 255, 0, 0 ) );
+ SetColourIcon( 1, wxColour( 0, 255, 0 ) );
+ SetColourIcon( 2, wxColour( 0, 0, 255 ) );
+
+
+ //ICON_FIXCOLOURS_PALETTE = Add( wxBitmap(fixcolours_palette_xpm) );
+
+ ICON_UNK_FLAG = Add( wxBitmap(unknown_flag_xpm) );
+
+ ICON_FLAGS_BASE = AddFlagImages( *this );
+
+ ICON_EMPTY = Add( wxBitmap(empty_xpm) );
+
+#ifdef __WXMSW__
+ ICON_NONE = ICON_NOSTATE = ICON_RANK_NONE = ICON_GAME_UNKNOWN = ICON_EMPTY;
+#else
+ ICON_NONE = ICON_NOSTATE = ICON_RANK_NONE = ICON_GAME_UNKNOWN = -1;
+#endif
+
+ ICON_WARNING_OVERLAY = Add(charArr2wxBitmap(warning_small_png, sizeof(warning_small_png) ));
+
+}
+
+
+IconImageList& icons()
+{
+ static IconImageList m_icons;
+ return m_icons;
+}
+
+
+int IconImageList::GetUserListStateIcon( const UserStatus& us, bool chanop, bool inbroom )
+{
+ if ( us.bot )
+ {
+ if ( us.in_game ) return ICON_BOT_INGAME;
+ if ( inbroom ) return ICON_BOT_BROOM;
+ if ( us.away ) return ICON_BOT_AWAY;
+ return ICON_BOT;
+ }
+ if (us.moderator )
+ {
+ if ( us.in_game ) return ICON_ADMIN_INGAME;
+ if ( us.away ) return ICON_ADMIN_AWAY;
+ if ( inbroom ) return ICON_ADMIN_BROOM;
+ return ICON_ADMIN;
+ }
+ if ( chanop )
+ {
+ if ( us.in_game ) return ICON_OP_INGAME;
+ if ( us.away ) return ICON_OP_AWAY;
+ if ( inbroom ) return ICON_OP_BROOM;
+ return ICON_OP;
+ }
+
+ if ( us.in_game ) return ICON_INGAME;
+ if ( us.away ) return ICON_AWAY;
+ if ( inbroom ) return ICON_BROOM;
+
+ return ICON_NOSTATE;
+}
+
+
+int IconImageList::GetUserBattleStateIcon( const UserStatus& us )
+{
+ if ( us.bot ) return ICON_BOT;
+ if (us.moderator )
+ {
+ if ( us.in_game ) return ICON_ADMIN_INGAME;
+ if ( us.away ) return ICON_ADMIN_AWAY;
+ return ICON_ADMIN;
+ }
+
+ if ( us.in_game ) return ICON_INGAME;
+ if ( us.away ) return ICON_AWAY;
+
+ return ICON_NOSTATE;
+}
+
+
+int IconImageList::GetRankIcon( const unsigned int& rank, const bool& showlowest )
+{
+ if ( !showlowest && rank == UserStatus::RANK_1 )
+ return ICON_RANK_NONE;
+ switch (rank)
+ {
+ case UserStatus::RANK_1: return ICON_RANK1;
+ case UserStatus::RANK_2: return ICON_RANK2;
+ case UserStatus::RANK_3: return ICON_RANK3;
+ case UserStatus::RANK_4: return ICON_RANK4;
+ case UserStatus::RANK_5: return ICON_RANK5;
+ case UserStatus::RANK_6: return ICON_RANK6;
+ case UserStatus::RANK_7: return ICON_RANK7;
+ default: return ICON_RANK_UNKNOWN;
+ }
+}
+
+
+int IconImageList::GetFlagIcon( const wxString& flagname )
+{
+ return ICON_FLAGS_BASE + GetFlagIndex( flagname );
+}
+
+
+int IconImageList::GetBattleStatusIcon( const IBattle& battle ) const
+{
+ unsigned idx = battle.GetInGame() << 3 | battle.IsLocked() << 2 | battle.IsFull() << 1 | battle.IsPassworded() << 0;
+ static const int icons[16] = {
+ /* - */ ICON_OPEN_GAME,
+ /* passworded */ ICON_OPEN_PW_GAME,
+ /* full */ ICON_OPEN_FULL_GAME,
+ /* full, passworded */ ICON_OPEN_FULL_PW_GAME,
+ /* locked */ ICON_CLOSED_GAME,
+ /* locked, passworded */ ICON_CLOSED_PW_GAME,
+ /* locked, full */ ICON_CLOSED_FULL_GAME,
+ /* locked, full, passworded */ ICON_CLOSED_FULL_PW_GAME,
+ /* in game */ ICON_STARTED_GAME,
+ /* in game, passworded */ ICON_STARTED_GAME,
+ /* in game, full */ ICON_STARTED_GAME,
+ /* in game, full, passworded */ ICON_STARTED_GAME,
+ /* in game, locked */ ICON_STARTED_GAME_LOCKED,
+ /* in game, locked, passworded */ ICON_STARTED_GAME_LOCKED,
+ /* in game, locked, full */ ICON_STARTED_GAME_LOCKED,
+ /* in game, locked, full, passworded */ ICON_STARTED_GAME_LOCKED,
+ };
+ return icons[idx];
+ // return ICON_GAME_UNKNOWN;
+}
+
+wxString IconImageList::GetBattleStatus( const IBattle& battle ) const
+{
+ unsigned idx = battle.GetInGame() << 3 | battle.IsLocked() << 2 | battle.IsFull() << 1 | battle.IsPassworded() << 0;
+ static const wxString states[16] = {
+ /* - */ _("Game is open."),
+ /* passworded */ _("Game is password-protected."),
+ /* full */ _("Game is full."),
+ /* full, passworded */ _("Game is full and password-protected."),
+ /* locked */ _("Game is closed."),
+ /* locked, passworded */ _("Game is closed and password-protected."),
+ /* locked, full */ _("Game is closed and full."),
+ /* locked, full, passworded */ _("Game is closed, full and password-protected."),
+ /* in game */ _("Game is in progress."),
+ /* in game, passworded */ _("Game is in progress and password-protected."),
+ /* in game, full */ _("Game is in progress and full."),
+ /* in game, full, passworded */ _("Game is in progress, full and password-protected."),
+ /* in game, locked */ _("Game is in progress and closed."),
+ /* in game, locked, passworded */ _("Game is in progress, closed and password-protected."),
+ /* in game, locked, full */ _("Game is in progress, closed and full."),
+ /* in game, locked, full, passworded */ _("Game is in progress, closed, full and password-protected."),
+ };
+ return states[idx];
+ // return _T("Game has unknown status");
+}
+
+
+int IconImageList::GetColourIcon( const int& num )
+{
+ if ( m_player_colour_icons[num] != 0 ) return m_player_colour_icons[num];
+ else return -1;
+}
+
+
+int IconImageList::GetHostIcon( const bool& spectator )
+{
+ return spectator?ICON_HOST_SPECTATOR:ICON_HOST;
+}
+
+
+void IconImageList::SetColourIcon( const int& num, const wxColour& colour )
+{
+ wxImage img( colourbox_xpm );
+
+ img.Replace( 1, 1, 1, colour.Red(), colour.Green(), colour.Blue() );
+
+ int r,g,b;
+ r = colour.Red()+80;
+ g = colour.Green()+80;
+ b = colour.Blue()+80;
+ img.Replace( 2, 2, 2, r>255?255:r, g>255?255:g, b>255?255:b );
+
+ /*r = colour.Red()-60; g = colour.Green()-60; b = colour.Blue()-60;
+ img.Replace( 200, 200, 200, r<0?0:r, g<0?0:g, b<0?0:b );*/
+ if ( m_player_colour_icons[num] != 0 ) Replace( m_player_colour_icons[num], wxBitmap( img ) );
+ else m_player_colour_icons[num] = Add( wxBitmap( img ) );
+}
+
+
+int IconImageList::GetSideIcon( const wxString& modname, int side )
+{
+ wxArrayString sides = usync().GetSides( modname );
+ wxString sidename;
+ if( side < (int)sides.GetCount() ) sidename = sides[side];
+ wxString cachestring = modname + _T("_") + sidename;
+ if (m_cached_side_icons.find(cachestring) == m_cached_side_icons.end()){
+ try
+ {
+ int IconPosition = Add(wxBitmap( usync().GetSidePicture( modname , sidename ) ), wxNullBitmap);
+ m_cached_side_icons[cachestring] = IconPosition;
+ return IconPosition;
+ } catch (...)
+ {
+ if ( side == 0 ) m_cached_side_icons[cachestring] = ICON_SIDEPIC_0;
+ else m_cached_side_icons[cachestring] = ICON_SIDEPIC_1;
+ }
+ }
+ return m_cached_side_icons[cachestring];
+}
+
+int IconImageList::GetReadyIcon( const bool& spectator,const bool& ready, const unsigned int& sync, const bool& bot )
+{
+ int index;
+ if ( bot )
+ index = ICON_BOT;
+ else if ( spectator )
+ index = ICON_SPECTATOR;
+ else if ( ready )
+ index = ICON_READY;
+ else
+ index = ICON_NREADY;
+
+ if ( sync == SYNC_SYNCED ) //could this cause #674 ??
+ return index;
+
+ else
+ {
+ if ( m_state_index_map.find(index) == m_state_index_map.end() )
+ {
+ wxBitmap bg;
+ if ( index == ICON_NREADY )
+ bg = charArr2wxBitmap(closed_game_png, sizeof(closed_game_png) ); // ICON_NREADY
+ else if ( index == ICON_READY )
+ bg = charArr2wxBitmap(open_game_png, sizeof(open_game_png) ); // ICON_READY
+ else if ( index == ICON_SPECTATOR )
+ bg = charArr2wxBitmap( spectator_png, sizeof(spectator_png) ); // ICON_SPECTATOR
+ else
+ bg = wxBitmap(bot_xpm); // ICON_BOT
+
+ m_state_index_map[index] = Add( BlendBitmaps( bg, charArr2wxBitmap(warning_small_png, sizeof(warning_small_png) ) ) );
+ }
+ return m_state_index_map[index];
+ }
+}
+
diff --git a/src/iconimagelist.h b/src/iconimagelist.h
new file mode 100644
index 0000000..616a16f
--- /dev/null
+++ b/src/iconimagelist.h
@@ -0,0 +1,134 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_ICONIMAGELIST_H
+#define SPRINGLOBBY_HEADERGUARD_ICONIMAGELIST_H
+
+
+#include <wx/imaglist.h>
+#include <map>
+
+class IBattle;
+class wxColour;
+struct UserStatus;
+
+class IconImageList : public wxImageList
+{
+ public:
+ IconImageList();
+
+ int GetUserListStateIcon( const UserStatus& us, bool chanop, bool inbroom );
+ int GetUserBattleStateIcon( const UserStatus& us );
+
+ int GetRankIcon( const unsigned int& rank, const bool& showlowest = true );
+ int GetFlagIcon( const wxString& flagname );
+ int GetBattleStatusIcon( const IBattle& battle ) const;
+ wxString GetBattleStatus(const IBattle& battle) const;
+ int GetHostIcon( const bool& spectator = false );
+ int GetColourIcon( const int& num );
+ void SetColourIcon( const int& num, const wxColour& colour );
+ int GetSideIcon( const wxString& modname, int side );
+ int GetReadyIcon( const bool& spectator, const bool& ready, const unsigned int& sync, const bool& bot );
+
+ int ICON_NONE;
+
+ int ICON_ADMIN;
+ int ICON_ADMIN_AWAY;
+ int ICON_ADMIN_BROOM;
+ int ICON_ADMIN_INGAME;
+
+ int ICON_BOT;
+ int ICON_BOT_BROOM;
+ int ICON_BOT_INGAME;
+ int ICON_BOT_AWAY;
+
+ int ICON_NOSTATE;
+ int ICON_AWAY;
+ int ICON_BROOM;
+ int ICON_INGAME;
+
+ int ICON_OP;
+ int ICON_OP_AWAY;
+ int ICON_OP_BROOM;
+ int ICON_OP_INGAME;
+
+ int ICON_UP;
+ int ICON_DOWN;
+
+ int ICON_RANK_NONE;
+ int ICON_RANK_UNKNOWN;
+ int ICON_RANK1;
+ int ICON_RANK2;
+ int ICON_RANK3;
+ int ICON_RANK4;
+ int ICON_RANK5;
+ int ICON_RANK6;
+ int ICON_RANK7;
+
+ int ICON_GAME_UNKNOWN;
+ int ICON_OPEN_GAME;
+ int ICON_OPEN_PW_GAME;
+ int ICON_OPEN_FULL_PW_GAME;
+ int ICON_OPEN_FULL_GAME;
+ int ICON_CLOSED_GAME;
+ int ICON_CLOSED_PW_GAME;
+ int ICON_CLOSED_FULL_PW_GAME;
+ int ICON_CLOSED_FULL_GAME;
+ int ICON_STARTED_GAME;
+ int ICON_STARTED_GAME_LOCKED;
+
+ int ICON_READY_UNSYNC;
+ int ICON_NREADY_UNSYNC;
+ int ICON_READY_QSYNC;
+ int ICON_NREADY_QSYNC;
+ int ICON_NREADY;
+ int ICON_READY;
+
+ int ICON_NEXISTS;
+ int ICON_EXISTS;
+
+ int ICON_SPECTATOR;
+ int ICON_HOST;
+ int ICON_HOST_SPECTATOR;
+
+ int ICON_SIDEPIC_0;
+ int ICON_SIDEPIC_1;
+
+ //int ICON_FIXCOLOURS_PALETTE;
+
+ int ICON_UNK_FLAG;
+ int ICON_FLAGS_BASE;
+
+ int ICON_WARNING_OVERLAY;
+
+ int ICON_CHANNEL_OPTIONS;
+
+ int ICON_EMPTY;
+
+ protected:
+ std::map<wxString, int> m_cached_side_icons;
+ // why map? because i already included and didn't want to include more stuff, it's not time-critical code anyway
+ std::map<unsigned int, unsigned int> m_player_colour_icons;
+
+ typedef std::map<int,int> IndexMap;
+ IndexMap m_state_index_map;
+};
+
+IconImageList& icons();
+
+#endif // SPRINGLOBBY_HEADERGUARD_ICONIMAGELIST_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/images/admin.png.h b/src/images/admin.png.h
new file mode 100644
index 0000000..28ae47b
--- /dev/null
+++ b/src/images/admin.png.h
@@ -0,0 +1,87 @@
+/* admin.png - 665 bytes */
+ static const unsigned char admin_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x13, 0x13, 0x28, 0x3d, 0xc5, 0x46, 0xcf,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x01,
+ 0xf4, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x8d,
+ 0x53, 0x4b, 0x68, 0x13, 0x51, 0x14, 0x3d, 0x23,
+ 0x5d, 0xcc, 0x0b, 0x3a, 0x3c, 0x41, 0x27, 0x66,
+ 0x0c, 0x7e, 0xa0, 0xd8, 0x14, 0x82, 0xf5, 0x83,
+ 0xd8, 0xce, 0xc2, 0xa4, 0x76, 0xa7, 0x6d, 0x15,
+ 0x75, 0x61, 0xa1, 0xb8, 0x14, 0x09, 0x34, 0x15,
+ 0x1b, 0xba, 0x90, 0x42, 0x45, 0xba, 0x9c, 0x42,
+ 0x75, 0x11, 0xd3, 0x2e, 0x94, 0x8a, 0xa0, 0x58,
+ 0x15, 0xcd, 0x60, 0xc0, 0x8d, 0x89, 0x56, 0x6a,
+ 0x15, 0x42, 0xc6, 0xd0, 0x36, 0x8d, 0x86, 0xa0,
+ 0xa0, 0x1d, 0x1b, 0x04, 0x9f, 0x29, 0xe4, 0x4d,
+ 0x11, 0x89, 0x1b, 0x33, 0xa8, 0xd0, 0x74, 0xde,
+ 0xf6, 0xde, 0x73, 0xee, 0x3d, 0xe7, 0xdc, 0x27,
+ 0xc0, 0xe1, 0xd3, 0xa3, 0xda, 0x52, 0xe2, 0xee,
+ 0x6d, 0x0f, 0xb7, 0x38, 0x88, 0x48, 0x70, 0x63,
+ 0x3a, 0x2b, 0x00, 0xc0, 0x06, 0x27, 0xe0, 0x97,
+ 0xf7, 0x27, 0x63, 0x0f, 0x6f, 0x8d, 0xe3, 0x50,
+ 0xe0, 0x28, 0x88, 0x48, 0xb0, 0x7d, 0xe7, 0x2e,
+ 0xbb, 0x26, 0x38, 0x21, 0x18, 0xe9, 0xed, 0xae,
+ 0x02, 0x40, 0x21, 0x9f, 0x43, 0x63, 0x53, 0x73,
+ 0x6a, 0xe8, 0x4e, 0xbc, 0x7d, 0xa4, 0xb7, 0xbb,
+ 0x5a, 0x66, 0x0c, 0x0d, 0x4e, 0x08, 0x44, 0x97,
+ 0x0b, 0x56, 0xa5, 0x02, 0x00, 0xd8, 0xb3, 0x77,
+ 0x3f, 0x06, 0x3b, 0x59, 0xb2, 0x90, 0xcf, 0x39,
+ 0xdb, 0xe0, 0xf3, 0xe2, 0xdc, 0x95, 0xeb, 0x91,
+ 0xd0, 0xb0, 0x44, 0x29, 0x6a, 0x5b, 0x00, 0x00,
+ 0x11, 0x09, 0xd6, 0xf5, 0x60, 0x56, 0x9f, 0x4a,
+ 0xf6, 0x9f, 0x39, 0x36, 0x2c, 0x51, 0x0a, 0xd1,
+ 0xe5, 0x42, 0x99, 0x31, 0xbb, 0xc6, 0x2d, 0x6e,
+ 0xf6, 0xf4, 0x0d, 0x8c, 0x0b, 0x75, 0x5c, 0x4f,
+ 0x4e, 0x27, 0xe2, 0x41, 0x59, 0x51, 0x00, 0x00,
+ 0x73, 0x99, 0x34, 0x56, 0xf8, 0x2a, 0x8e, 0x9f,
+ 0x3c, 0x95, 0xd9, 0xaa, 0x78, 0xdf, 0x77, 0x85,
+ 0x22, 0x67, 0xd7, 0x94, 0x70, 0x73, 0xe8, 0x62,
+ 0xf2, 0xe9, 0xe3, 0x47, 0xc1, 0x36, 0x55, 0xb5,
+ 0xc1, 0xb2, 0xdb, 0x93, 0x0a, 0x6b, 0xd1, 0xf3,
+ 0x5e, 0x9f, 0xff, 0xc3, 0xdf, 0xbd, 0xc2, 0x1f,
+ 0x9d, 0x07, 0x8a, 0xd9, 0xf4, 0x28, 0x00, 0x63,
+ 0xe1, 0xed, 0xeb, 0x7d, 0xef, 0xde, 0xcc, 0x04,
+ 0x5b, 0x0e, 0xab, 0xf8, 0xf6, 0x75, 0x09, 0x85,
+ 0x7c, 0x0e, 0xb2, 0xdb, 0x63, 0x86, 0xb5, 0xe8,
+ 0x6e, 0xaf, 0xcf, 0xbf, 0xfa, 0xff, 0x30, 0x61,
+ 0x56, 0x9f, 0x3a, 0x17, 0xbb, 0x7a, 0x79, 0x92,
+ 0x88, 0x04, 0xa5, 0xef, 0x0c, 0xf2, 0x66, 0x8a,
+ 0x1a, 0x38, 0x63, 0x18, 0x68, 0x53, 0x55, 0x33,
+ 0x32, 0x71, 0x4f, 0x59, 0x4b, 0xaa, 0x30, 0xd8,
+ 0x79, 0xa4, 0x5a, 0xd3, 0x69, 0x55, 0x2a, 0xd8,
+ 0xb2, 0x4d, 0x41, 0x71, 0x71, 0x01, 0xa5, 0x65,
+ 0x13, 0xad, 0x81, 0x8e, 0xd4, 0x05, 0x2d, 0xd6,
+ 0x5e, 0xcf, 0xe8, 0x86, 0x95, 0x1f, 0x0c, 0x12,
+ 0xa5, 0x28, 0x33, 0x86, 0xd2, 0xb2, 0x89, 0x2f,
+ 0x9f, 0x3e, 0x82, 0x5b, 0x1c, 0x8d, 0x4d, 0xcd,
+ 0xeb, 0x82, 0xed, 0x18, 0x33, 0x86, 0x81, 0xb0,
+ 0x16, 0x1d, 0x6b, 0x0d, 0x74, 0x8c, 0x71, 0x8b,
+ 0x03, 0xc0, 0x3f, 0x91, 0xd5, 0x25, 0xe8, 0xe9,
+ 0x1b, 0xc0, 0xb5, 0x07, 0x89, 0x83, 0xc5, 0x6c,
+ 0x1a, 0x71, 0x5d, 0x87, 0xec, 0xf6, 0x00, 0x00,
+ 0x24, 0x4a, 0x25, 0x27, 0x04, 0x76, 0x8c, 0xa7,
+ 0xfd, 0x3b, 0xaa, 0xf6, 0x91, 0xfc, 0xfc, 0x85,
+ 0x89, 0x27, 0xcf, 0x4e, 0x78, 0x7d, 0xfe, 0xb8,
+ 0x63, 0x82, 0xf9, 0x57, 0xcf, 0x2f, 0xcd, 0xcf,
+ 0xbc, 0x18, 0x25, 0x1b, 0x37, 0xa1, 0x2b, 0x14,
+ 0x11, 0x9c, 0x7e, 0xf3, 0xdf, 0x58, 0xac, 0xbe,
+ 0x71, 0x01, 0xfa, 0xb1, 0x2f, 0x00, 0x00, 0x00,
+ 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
+ 0x82};
+/* End Of File */
diff --git a/src/images/admin_away.png.h b/src/images/admin_away.png.h
new file mode 100644
index 0000000..f4b59ff
--- /dev/null
+++ b/src/images/admin_away.png.h
@@ -0,0 +1,130 @@
+/* admin_away.png - 1008 bytes */
+ static const unsigned char admin_away_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x13, 0x13, 0x38, 0x20, 0x72, 0x56, 0xab,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x03,
+ 0x4b, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x8d,
+ 0x93, 0xdd, 0x6f, 0x53, 0x75, 0x1c, 0xc6, 0x9f,
+ 0xf3, 0xb2, 0x9d, 0x97, 0x76, 0xed, 0x69, 0xbb,
+ 0x32, 0xd6, 0x53, 0x28, 0x43, 0x99, 0x50, 0xa6,
+ 0x23, 0xce, 0xa0, 0x10, 0x0a, 0x13, 0x30, 0x18,
+ 0x0c, 0xa6, 0x89, 0xa8, 0xb0, 0x88, 0xbb, 0xc2,
+ 0x18, 0x09, 0x51, 0xc4, 0x3f, 0x41, 0x50, 0x89,
+ 0xde, 0x68, 0x82, 0x77, 0x9a, 0x60, 0x36, 0xeb,
+ 0x8c, 0x62, 0x32, 0x20, 0xdb, 0x90, 0x22, 0x9b,
+ 0x9b, 0x65, 0xac, 0x59, 0xe9, 0xc6, 0x9b, 0x65,
+ 0xac, 0xed, 0x68, 0x9d, 0xb4, 0x5b, 0x5f, 0xd6,
+ 0x9e, 0xd3, 0xb7, 0x73, 0x7e, 0x5e, 0x18, 0x07,
+ 0xf1, 0x8a, 0xe7, 0xfa, 0xfb, 0x7c, 0x92, 0xef,
+ 0xf7, 0xfb, 0x3c, 0x14, 0x1e, 0x53, 0xfd, 0xa7,
+ 0x3f, 0x4f, 0x5e, 0xf8, 0xfe, 0x4c, 0xb3, 0x5a,
+ 0x52, 0x21, 0xf0, 0x02, 0xbe, 0x1e, 0x09, 0x53,
+ 0x00, 0xc0, 0xfe, 0x7f, 0xf0, 0xb2, 0xef, 0x54,
+ 0x2b, 0xc7, 0x14, 0x5e, 0xe6, 0xf8, 0x8a, 0x93,
+ 0xa9, 0x63, 0x38, 0xad, 0x46, 0xa0, 0x14, 0xb9,
+ 0xed, 0xc3, 0x03, 0x83, 0xe2, 0xf3, 0x3b, 0x77,
+ 0xe1, 0xaa, 0xff, 0x12, 0x64, 0xd7, 0x1a, 0x60,
+ 0x24, 0x0c, 0x00, 0xa0, 0x1e, 0x35, 0x0f, 0xf7,
+ 0x9d, 0x7c, 0x53, 0x92, 0xf2, 0x5b, 0x2d, 0x2e,
+ 0x2f, 0xc3, 0x99, 0xec, 0xe0, 0x44, 0x0b, 0x08,
+ 0xd1, 0x71, 0x6d, 0xe0, 0xe7, 0x23, 0x4a, 0x76,
+ 0x1e, 0xd1, 0x9b, 0x7f, 0x80, 0x10, 0x73, 0xf8,
+ 0x83, 0xaf, 0x7c, 0xed, 0x1f, 0xbf, 0xf5, 0x2a,
+ 0xc9, 0x67, 0xb3, 0x0f, 0x01, 0xbf, 0xf9, 0x4e,
+ 0xec, 0x77, 0x3e, 0x69, 0xed, 0xb4, 0xba, 0xf6,
+ 0x22, 0xa5, 0x34, 0x60, 0x6a, 0x26, 0x87, 0x07,
+ 0x19, 0x05, 0x35, 0x8d, 0x80, 0x4b, 0x85, 0x8e,
+ 0xd8, 0x25, 0x06, 0xd5, 0x4c, 0x04, 0x3c, 0xb5,
+ 0x98, 0x08, 0x5f, 0xfd, 0x33, 0x3d, 0x73, 0x2b,
+ 0xd2, 0xbe, 0xbc, 0xc2, 0xe0, 0x77, 0x9f, 0x3e,
+ 0x61, 0x34, 0xa4, 0x3d, 0xd2, 0xaa, 0x2e, 0x4c,
+ 0xdf, 0xaf, 0x43, 0x3a, 0x9b, 0xc3, 0xa6, 0x75,
+ 0x56, 0x48, 0xa6, 0x46, 0x68, 0xe5, 0xd2, 0xe6,
+ 0xb1, 0x41, 0x0a, 0xc9, 0x85, 0x32, 0x38, 0xd6,
+ 0x85, 0x5a, 0x49, 0x95, 0x69, 0x5a, 0x95, 0x4d,
+ 0x92, 0x19, 0xd5, 0x52, 0xe5, 0x5f, 0x00, 0xa3,
+ 0x67, 0xf6, 0x98, 0x9d, 0xbb, 0x98, 0x94, 0x6a,
+ 0xc2, 0xfc, 0x62, 0x0e, 0xaf, 0xef, 0x6c, 0x41,
+ 0x26, 0x97, 0x43, 0x22, 0x7e, 0xcf, 0x3b, 0x3b,
+ 0x35, 0x29, 0x37, 0x35, 0x35, 0x62, 0xa5, 0xcc,
+ 0x62, 0x78, 0x3c, 0x06, 0x0b, 0xd7, 0x0c, 0xb3,
+ 0xdd, 0x82, 0x5c, 0xae, 0x94, 0xdd, 0x7f, 0xf8,
+ 0xe8, 0x0f, 0x34, 0x00, 0xd0, 0x94, 0xe2, 0x34,
+ 0x58, 0x9d, 0x08, 0xde, 0x59, 0x44, 0x5b, 0xab,
+ 0x0d, 0x4a, 0x8d, 0x60, 0x71, 0x2e, 0xea, 0x3d,
+ 0xe7, 0xeb, 0x91, 0xcd, 0x92, 0x04, 0x0a, 0xc0,
+ 0xe8, 0xc8, 0x28, 0x44, 0x5e, 0x87, 0xca, 0xcb,
+ 0xa9, 0xe7, 0x76, 0xef, 0x8b, 0xac, 0x73, 0x3b,
+ 0xbe, 0xdc, 0xfe, 0x46, 0xf7, 0xbb, 0x34, 0x00,
+ 0x10, 0x42, 0x04, 0xde, 0x60, 0x41, 0x32, 0xad,
+ 0xc0, 0x66, 0x13, 0x70, 0xf7, 0x7a, 0xd0, 0x7b,
+ 0x6b, 0x2a, 0x24, 0x97, 0x2b, 0x65, 0xdc, 0xbe,
+ 0x13, 0x41, 0x6f, 0x4f, 0x2f, 0x56, 0x38, 0xe4,
+ 0xc4, 0x8b, 0x87, 0xba, 0x7b, 0x62, 0xba, 0xb3,
+ 0xcf, 0xd1, 0xea, 0x1e, 0x62, 0x40, 0x99, 0x1e,
+ 0xbe, 0x91, 0x12, 0x56, 0x64, 0xfe, 0x9a, 0xdb,
+ 0x21, 0x68, 0x95, 0xf4, 0x6c, 0x68, 0xa2, 0x31,
+ 0x15, 0x8f, 0xca, 0x92, 0x7d, 0x25, 0x58, 0x9a,
+ 0xc1, 0x74, 0x68, 0x12, 0x9b, 0xb7, 0x79, 0x94,
+ 0x3d, 0xdd, 0xef, 0xf4, 0xc7, 0xf3, 0x35, 0xad,
+ 0x5a, 0xd5, 0x41, 0xf4, 0x0a, 0x88, 0x4e, 0x00,
+ 0x00, 0x6c, 0xa0, 0xff, 0xc7, 0xb7, 0xfd, 0x67,
+ 0x4f, 0x77, 0x65, 0xf2, 0x3c, 0xe6, 0x62, 0xbc,
+ 0x2c, 0x28, 0xcd, 0xd8, 0xb0, 0xbe, 0x05, 0xca,
+ 0x52, 0x1e, 0xbc, 0x68, 0x84, 0xf7, 0x40, 0x97,
+ 0xb2, 0xf1, 0xa5, 0x57, 0xbe, 0x2d, 0x96, 0x81,
+ 0xb9, 0xf9, 0x22, 0x4c, 0x06, 0x1a, 0x99, 0xc4,
+ 0x75, 0x94, 0x6a, 0x5a, 0x01, 0x00, 0x18, 0xeb,
+ 0xd2, 0xdf, 0x21, 0xbb, 0x43, 0x86, 0x41, 0x24,
+ 0x70, 0xb8, 0xd6, 0x23, 0x55, 0x32, 0x40, 0x12,
+ 0x2b, 0x28, 0x15, 0x0a, 0xe8, 0x78, 0x61, 0x6b,
+ 0x62, 0xa3, 0xa7, 0xd3, 0x47, 0x13, 0x80, 0xad,
+ 0x03, 0x7e, 0xba, 0x18, 0xc7, 0x8e, 0xa7, 0x2a,
+ 0x58, 0x08, 0xf5, 0x61, 0x21, 0x8b, 0xdb, 0x03,
+ 0x63, 0x37, 0x27, 0xd9, 0xa5, 0x5c, 0x16, 0x4b,
+ 0x19, 0x1b, 0xaa, 0xe5, 0x3c, 0x9a, 0xc0, 0x40,
+ 0x53, 0x57, 0xc1, 0x3f, 0x4a, 0xc3, 0xb3, 0xc5,
+ 0x9d, 0x68, 0x71, 0x6f, 0xfa, 0x05, 0x6a, 0x15,
+ 0xf1, 0x07, 0x45, 0x9c, 0x0b, 0xcc, 0x63, 0xb5,
+ 0x90, 0x86, 0x5d, 0xbd, 0x8c, 0xb1, 0x99, 0x62,
+ 0x95, 0x12, 0xed, 0xbf, 0x2e, 0xdf, 0x20, 0x38,
+ 0x11, 0xc4, 0xf1, 0xcf, 0x3e, 0x39, 0x1b, 0x09,
+ 0x9e, 0x5f, 0xdb, 0xcc, 0x97, 0xdb, 0x8d, 0xbc,
+ 0x0b, 0x13, 0xa1, 0x18, 0x86, 0x63, 0xd7, 0xa0,
+ 0xe9, 0x04, 0x0d, 0x22, 0xb0, 0xc5, 0x4d, 0xd0,
+ 0x58, 0x1e, 0xc2, 0xf8, 0xd0, 0x38, 0xaa, 0xf5,
+ 0xb6, 0x8b, 0xc7, 0x4e, 0x7c, 0x13, 0x03, 0x00,
+ 0xf6, 0xe0, 0xd1, 0xe3, 0x58, 0xfb, 0x4c, 0x47,
+ 0xc7, 0xbd, 0x70, 0xf0, 0x50, 0x20, 0x70, 0x97,
+ 0x5a, 0xe3, 0xb0, 0xb4, 0xd7, 0x0b, 0x33, 0x78,
+ 0xb6, 0xed, 0xe9, 0xfa, 0x36, 0x4f, 0x03, 0x40,
+ 0x6a, 0x58, 0xb8, 0x1f, 0x41, 0x34, 0x30, 0x8d,
+ 0x48, 0x52, 0xaf, 0x54, 0x59, 0xeb, 0xa5, 0x63,
+ 0xa7, 0x7a, 0x2f, 0xfc, 0x97, 0xe0, 0xe5, 0x28,
+ 0xbf, 0xd6, 0xb6, 0x9a, 0x00, 0x00, 0x2f, 0xf0,
+ 0x10, 0xcd, 0x22, 0x3a, 0x77, 0x6f, 0xeb, 0xcb,
+ 0xa7, 0x63, 0x49, 0x00, 0xa8, 0xe9, 0x54, 0x41,
+ 0xa3, 0xd9, 0x59, 0xaa, 0xde, 0xe8, 0x7f, 0xff,
+ 0xe4, 0x99, 0xe8, 0xa3, 0xfd, 0x59, 0x06, 0xdc,
+ 0xf8, 0xdd, 0xff, 0xe1, 0x8d, 0xb1, 0x2b, 0x5f,
+ 0x08, 0xc6, 0x06, 0xec, 0x7b, 0xef, 0x23, 0xea,
+ 0x71, 0x6b, 0xfe, 0x0f, 0x0d, 0x4d, 0x69, 0x00,
+ 0x68, 0x29, 0x4a, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+/* End Of File */
diff --git a/src/images/admin_broom.png.h b/src/images/admin_broom.png.h
new file mode 100644
index 0000000..98ee254
--- /dev/null
+++ b/src/images/admin_broom.png.h
@@ -0,0 +1,131 @@
+/* admin_broom.png - 1018 bytes */
+ static const unsigned char admin_broom_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x13, 0x14, 0x24, 0x7b, 0x32, 0x9c, 0x23,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x03,
+ 0x55, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x75,
+ 0x92, 0x7b, 0x50, 0x13, 0x04, 0x1c, 0xc7, 0x3f,
+ 0x7b, 0xc5, 0xc6, 0x81, 0x4d, 0xdd, 0x06, 0xcc,
+ 0x01, 0x43, 0x60, 0x24, 0x78, 0xc5, 0x6b, 0x48,
+ 0xb6, 0xf3, 0x91, 0x5c, 0x70, 0x05, 0x64, 0x12,
+ 0x9d, 0x85, 0x8f, 0xbb, 0x8e, 0x3f, 0xcc, 0xea,
+ 0x0f, 0x09, 0xbc, 0xe5, 0x51, 0x47, 0x57, 0xd7,
+ 0x5b, 0xcf, 0xbc, 0x53, 0xb3, 0xb3, 0x33, 0x3c,
+ 0x4f, 0x4d, 0xa4, 0x12, 0x3a, 0x4e, 0x3b, 0xdd,
+ 0x94, 0x60, 0x0a, 0x44, 0x3c, 0x8a, 0x0d, 0x26,
+ 0x20, 0x95, 0x30, 0x36, 0x09, 0xb7, 0x60, 0x0f,
+ 0x71, 0xb0, 0xfe, 0x28, 0x88, 0xeb, 0xea, 0xfb,
+ 0xd7, 0xef, 0xee, 0xf7, 0xfa, 0xfc, 0x1e, 0x82,
+ 0x6d, 0x2f, 0x96, 0x9b, 0x94, 0x31, 0x2b, 0x08,
+ 0x93, 0x86, 0x01, 0x54, 0xbc, 0xff, 0xc6, 0xbe,
+ 0x6e, 0xfe, 0x43, 0x8d, 0x47, 0x3e, 0x1e, 0x6b,
+ 0x3a, 0x73, 0x32, 0xc6, 0x1f, 0xf0, 0x23, 0x93,
+ 0xca, 0x38, 0xfa, 0x7d, 0xaf, 0x00, 0x40, 0xe8,
+ 0xf6, 0x78, 0xa8, 0xac, 0xaa, 0xa2, 0xb8, 0xb8,
+ 0x08, 0xe0, 0x80, 0xf1, 0xed, 0x77, 0xd3, 0xff,
+ 0x9d, 0xdc, 0x7c, 0xae, 0xf6, 0xd3, 0xfa, 0x13,
+ 0xc7, 0xd0, 0xaf, 0x7f, 0x1c, 0x99, 0x54, 0xc6,
+ 0x8a, 0x78, 0xed, 0x82, 0x4f, 0xa4, 0x4b, 0x4d,
+ 0xdb, 0x99, 0x9d, 0x93, 0x8b, 0x46, 0x13, 0x8b,
+ 0x4a, 0xa5, 0x60, 0x60, 0xc0, 0x9e, 0x6f, 0xd8,
+ 0xb8, 0x69, 0xb2, 0xd5, 0x6c, 0xb2, 0xcf, 0x07,
+ 0x25, 0x86, 0xcd, 0x35, 0x2e, 0x53, 0x28, 0x23,
+ 0xbb, 0xda, 0x2c, 0x68, 0x13, 0x93, 0xaf, 0x56,
+ 0x9f, 0x6a, 0x48, 0x78, 0x67, 0x5b, 0x71, 0x28,
+ 0x3b, 0x2e, 0xaa, 0x46, 0x08, 0x54, 0xd4, 0x54,
+ 0xbf, 0xce, 0xed, 0xd1, 0x51, 0x12, 0x12, 0x12,
+ 0xd9, 0xfe, 0x42, 0x19, 0x02, 0x81, 0x60, 0xcf,
+ 0x62, 0x12, 0x69, 0x78, 0xf8, 0x42, 0x47, 0xdd,
+ 0xc3, 0x19, 0xec, 0x2d, 0x5c, 0x67, 0x1e, 0x1c,
+ 0xb0, 0xe1, 0x72, 0x3a, 0x10, 0xd9, 0x6d, 0xd6,
+ 0x71, 0x5d, 0x6a, 0xda, 0x64, 0xb3, 0xd9, 0xf4,
+ 0xa8, 0x36, 0x29, 0x99, 0x78, 0xad, 0x96, 0x80,
+ 0xcf, 0xcb, 0xb8, 0xd3, 0x99, 0x6f, 0xd8, 0xb8,
+ 0xa9, 0xe7, 0xcb, 0xa3, 0x87, 0x76, 0x99, 0xea,
+ 0xcf, 0x6e, 0x08, 0x93, 0x4a, 0x59, 0xa6, 0x50,
+ 0xd2, 0xd6, 0x6c, 0xd6, 0x7a, 0xbd, 0xd3, 0x5a,
+ 0x99, 0x54, 0x86, 0x44, 0x2c, 0x41, 0x04, 0x60,
+ 0xb7, 0x59, 0xed, 0xba, 0xd4, 0xb4, 0x9e, 0xf6,
+ 0xeb, 0x96, 0x7c, 0x6d, 0x52, 0x32, 0x39, 0x39,
+ 0x6b, 0xf0, 0xfb, 0x7d, 0xdc, 0x9b, 0xf2, 0x18,
+ 0x4f, 0x7d, 0xf8, 0x56, 0x41, 0x6c, 0x74, 0x14,
+ 0xd2, 0xf0, 0x70, 0x26, 0xef, 0xdc, 0xc1, 0xeb,
+ 0x9d, 0x06, 0x20, 0x18, 0x0c, 0x3a, 0x76, 0xec,
+ 0x31, 0x9e, 0x16, 0x2c, 0x5e, 0x56, 0x61, 0x49,
+ 0x69, 0x3a, 0x70, 0xe0, 0x95, 0x8a, 0x4a, 0x56,
+ 0x46, 0x2b, 0x33, 0xae, 0x5c, 0xfc, 0x56, 0x3e,
+ 0x3a, 0xea, 0x20, 0xc2, 0xe3, 0xa0, 0xbf, 0xbd,
+ 0x95, 0x29, 0xff, 0x3d, 0x9e, 0xda, 0xbc, 0xa5,
+ 0x4b, 0xa9, 0xd6, 0xd8, 0x8b, 0x76, 0x57, 0x6e,
+ 0x05, 0xfe, 0x22, 0x98, 0xd7, 0xdf, 0xe3, 0xf4,
+ 0xd8, 0xbb, 0x3a, 0x8c, 0x22, 0xa1, 0x40, 0x9e,
+ 0x9d, 0xa5, 0xc7, 0xef, 0xf7, 0x71, 0xeb, 0x77,
+ 0x0f, 0x11, 0x72, 0x85, 0xdd, 0x1b, 0xfc, 0xe1,
+ 0xa6, 0x6d, 0xa8, 0x65, 0xba, 0xc3, 0xf5, 0xe0,
+ 0x17, 0x76, 0x9b, 0xd5, 0x06, 0x20, 0x06, 0xb8,
+ 0xdd, 0xff, 0x73, 0xe6, 0x70, 0x6f, 0xe7, 0x7e,
+ 0xa0, 0xdb, 0xda, 0x7e, 0x3d, 0xbd, 0xa3, 0xb3,
+ 0x53, 0x7e, 0xed, 0x4a, 0x08, 0x42, 0x21, 0x52,
+ 0x74, 0x29, 0x48, 0x44, 0x0f, 0xcc, 0xfc, 0x38,
+ 0x38, 0xec, 0x38, 0x56, 0xe5, 0x9f, 0x73, 0x3a,
+ 0xc0, 0xf8, 0x66, 0xdd, 0xcb, 0x40, 0x3d, 0x80,
+ 0xf8, 0x46, 0x63, 0xdd, 0x8e, 0xea, 0xed, 0xcf,
+ 0xd4, 0xca, 0xa4, 0x32, 0x5c, 0x77, 0xdd, 0x1b,
+ 0x54, 0x4b, 0xe5, 0xe8, 0xd7, 0xac, 0xa5, 0xf7,
+ 0x37, 0x27, 0x5f, 0x9f, 0x3f, 0xc7, 0xb3, 0x5b,
+ 0xcb, 0x66, 0x92, 0x1f, 0xc9, 0x6c, 0x8d, 0x54,
+ 0xc7, 0xde, 0xdf, 0xf5, 0xd1, 0xb8, 0xa4, 0xa6,
+ 0xec, 0x38, 0xc1, 0xd9, 0x7f, 0xa8, 0x05, 0x7b,
+ 0x0b, 0xd7, 0x85, 0x54, 0x6a, 0x35, 0x00, 0x01,
+ 0x9f, 0x0f, 0x45, 0xb4, 0x9a, 0xe1, 0x7e, 0x2b,
+ 0x2e, 0xa7, 0x03, 0x4d, 0xa6, 0xe1, 0xa7, 0xee,
+ 0x89, 0xe9, 0x09, 0x75, 0x5c, 0x02, 0x05, 0xf9,
+ 0x4f, 0xf0, 0x98, 0xe6, 0x49, 0xca, 0xcb, 0x67,
+ 0x90, 0x88, 0xf9, 0xe6, 0xab, 0x16, 0x0e, 0x01,
+ 0x08, 0xa7, 0x3c, 0x6e, 0x02, 0x3e, 0x1f, 0xae,
+ 0xb1, 0x31, 0x06, 0x07, 0x6c, 0xf4, 0xb4, 0x59,
+ 0x70, 0x39, 0x1d, 0x24, 0xa5, 0xac, 0xba, 0x7a,
+ 0xd1, 0x7c, 0x62, 0x62, 0xe7, 0xda, 0x3a, 0xc6,
+ 0x7e, 0xbd, 0x85, 0xea, 0x8f, 0x3c, 0x02, 0xde,
+ 0x19, 0x4e, 0x7e, 0x0e, 0xc1, 0x59, 0x36, 0x6f,
+ 0x31, 0x50, 0x02, 0x20, 0xd2, 0xc7, 0x47, 0xd5,
+ 0x0c, 0x8d, 0x8c, 0x50, 0x73, 0xfc, 0xf4, 0x41,
+ 0xdf, 0xe4, 0xc4, 0x8d, 0x91, 0x21, 0x7b, 0x2e,
+ 0x80, 0x58, 0x2c, 0x19, 0xb9, 0xe9, 0xfa, 0x85,
+ 0xd8, 0xe5, 0x90, 0xb4, 0xdc, 0xca, 0x07, 0x87,
+ 0xc1, 0x33, 0x06, 0x7a, 0x83, 0x94, 0xf5, 0xb9,
+ 0x41, 0x2e, 0x9b, 0xc9, 0x59, 0x15, 0x87, 0x4c,
+ 0xf8, 0xfc, 0xab, 0xaf, 0xf1, 0xc9, 0xf9, 0xa6,
+ 0xac, 0xe1, 0xde, 0x4e, 0x1a, 0x1a, 0x1b, 0x51,
+ 0x45, 0xc5, 0x00, 0xb0, 0x44, 0x2e, 0x5f, 0xa2,
+ 0x5e, 0xca, 0xe5, 0xb3, 0x97, 0xa0, 0xf6, 0x02,
+ 0x28, 0xe4, 0x7c, 0xd7, 0x64, 0x81, 0x83, 0xef,
+ 0x05, 0x98, 0x13, 0x42, 0x7a, 0x32, 0x00, 0xcf,
+ 0x2d, 0xfc, 0x41, 0xc9, 0xea, 0xb8, 0xd0, 0xbc,
+ 0xed, 0xbf, 0x3f, 0xcb, 0x67, 0x17, 0x2e, 0x3d,
+ 0xad, 0x79, 0x68, 0x75, 0xc3, 0xe2, 0x33, 0xe7,
+ 0x65, 0xf2, 0xd2, 0x84, 0x9b, 0xd2, 0x22, 0x03,
+ 0xf4, 0x0d, 0x83, 0x7b, 0x0a, 0x16, 0x0a, 0xf4,
+ 0xb5, 0x98, 0x2a, 0xfa, 0x2c, 0xd7, 0xf6, 0xcb,
+ 0x22, 0x22, 0x29, 0xda, 0x5d, 0x29, 0xe0, 0x7f,
+ 0x54, 0x90, 0xc5, 0xbe, 0xf1, 0xbb, 0xe4, 0x01,
+ 0xc4, 0x66, 0x94, 0x1e, 0xfe, 0x13, 0xb7, 0xec,
+ 0x55, 0x5c, 0x9e, 0xfc, 0x29, 0x3e, 0x00, 0x00,
+ 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+ 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/admin_ingame.png.h b/src/images/admin_ingame.png.h
new file mode 100644
index 0000000..cf67b25
--- /dev/null
+++ b/src/images/admin_ingame.png.h
@@ -0,0 +1,137 @@
+/* admin_ingame.png - 1067 bytes */
+ static const unsigned char admin_ingame_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x13, 0x23, 0x35, 0x81, 0x85, 0x1c, 0xe5,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x03,
+ 0x86, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x7d,
+ 0x93, 0x5b, 0x4c, 0x5b, 0x75, 0x00, 0x87, 0x7f,
+ 0xe7, 0x52, 0x4e, 0x69, 0x8b, 0xf4, 0x7e, 0x61,
+ 0xc5, 0x13, 0xca, 0x45, 0x58, 0xcb, 0x06, 0x38,
+ 0x2d, 0x8e, 0xb9, 0xe9, 0xc4, 0x39, 0x33, 0x20,
+ 0x6a, 0x24, 0x46, 0xeb, 0x25, 0x59, 0x4c, 0x96,
+ 0xc5, 0x64, 0xf1, 0x01, 0x32, 0x43, 0x24, 0x66,
+ 0x17, 0xd4, 0x19, 0x12, 0x35, 0x4e, 0xcd, 0x5e,
+ 0x8c, 0x2f, 0xfa, 0x64, 0x7c, 0x21, 0x0a, 0xc1,
+ 0x35, 0xf3, 0x32, 0x5a, 0x46, 0x64, 0x61, 0xb2,
+ 0x96, 0x41, 0xd3, 0x8d, 0x4b, 0x4b, 0xdb, 0xb5,
+ 0xa4, 0x3d, 0x1c, 0x4a, 0x2f, 0xe7, 0xf4, 0xfc,
+ 0x7d, 0xf1, 0x69, 0x89, 0xfb, 0x9e, 0xbf, 0xef,
+ 0xf1, 0xa3, 0xde, 0x3c, 0xf9, 0xee, 0x88, 0xc5,
+ 0xb1, 0x07, 0x9c, 0x9a, 0x03, 0x80, 0x1f, 0x3e,
+ 0x1d, 0x1d, 0x59, 0xc3, 0x43, 0xf8, 0xe0, 0xc2,
+ 0xc7, 0x3c, 0x00, 0x5f, 0xa9, 0x58, 0x42, 0x3a,
+ 0x11, 0x07, 0x9d, 0x13, 0x04, 0x0c, 0x0d, 0x0f,
+ 0x63, 0x60, 0xa0, 0x1f, 0x00, 0x7c, 0xff, 0x09,
+ 0x0f, 0x8d, 0x07, 0x06, 0xfa, 0x31, 0x34, 0x3c,
+ 0x8c, 0x9c, 0x20, 0x80, 0x06, 0x80, 0x44, 0x22,
+ 0x09, 0x9e, 0x6f, 0x40, 0x5f, 0xdf, 0x09, 0x10,
+ 0x42, 0x7c, 0x67, 0xcf, 0x8f, 0x75, 0x3e, 0x18,
+ 0x9f, 0x3d, 0x3f, 0xd6, 0x49, 0x08, 0xf1, 0xf5,
+ 0xf5, 0x9d, 0x00, 0xcf, 0x37, 0x20, 0x91, 0x48,
+ 0x02, 0x00, 0xc5, 0xb4, 0xec, 0x75, 0xaf, 0x87,
+ 0x6e, 0xcc, 0xbc, 0xc6, 0xd7, 0x3b, 0x1d, 0xae,
+ 0xa6, 0x16, 0x3c, 0xe6, 0x72, 0x71, 0xff, 0x84,
+ 0xc3, 0xce, 0x43, 0x47, 0x9f, 0x5b, 0xbf, 0x7e,
+ 0xcd, 0x2f, 0x4c, 0x7c, 0x33, 0x4e, 0xf1, 0xdd,
+ 0xcf, 0xf0, 0x14, 0x45, 0xbd, 0xf2, 0xd6, 0x1b,
+ 0x3e, 0x38, 0xf6, 0x38, 0x11, 0x8b, 0xc7, 0x71,
+ 0xf1, 0xa3, 0x51, 0xfa, 0x68, 0xa7, 0x27, 0xc8,
+ 0x3c, 0x6f, 0xab, 0x1a, 0xd2, 0xd0, 0x78, 0x75,
+ 0x36, 0x30, 0xd3, 0x5e, 0xc8, 0x66, 0xda, 0xcc,
+ 0x26, 0xa3, 0x9e, 0xe3, 0x38, 0x31, 0x71, 0x3f,
+ 0xdd, 0x78, 0xec, 0xf0, 0xe1, 0x54, 0xba, 0x04,
+ 0xab, 0x04, 0xe2, 0xdb, 0xe7, 0x69, 0xa7, 0x5a,
+ 0xdd, 0x6e, 0xb2, 0x18, 0x0a, 0xe1, 0xc7, 0x2f,
+ 0x3e, 0xe9, 0x6f, 0xd4, 0x55, 0xd5, 0x6b, 0x0a,
+ 0xc2, 0x0b, 0xac, 0xa2, 0x90, 0xf7, 0xb4, 0x34,
+ 0xa9, 0xd5, 0x72, 0x0c, 0x7d, 0xfd, 0x9a, 0x5f,
+ 0x5b, 0x96, 0x25, 0xa6, 0x7d, 0x7f, 0x17, 0x23,
+ 0x9a, 0x6a, 0xb2, 0xeb, 0xb1, 0xd8, 0xb3, 0x34,
+ 0x64, 0xec, 0x6b, 0x6e, 0x46, 0x2b, 0xef, 0x2c,
+ 0x25, 0x36, 0xd6, 0x76, 0x7e, 0xbe, 0x3c, 0xde,
+ 0x6e, 0xa3, 0xcb, 0x2d, 0x72, 0x3a, 0x9d, 0xcf,
+ 0x69, 0x34, 0x2a, 0x56, 0x67, 0xb2, 0xac, 0xe8,
+ 0x8c, 0x66, 0xfd, 0x76, 0x26, 0xe5, 0xb4, 0x56,
+ 0xb1, 0xda, 0xf9, 0xe0, 0x8c, 0x41, 0xc5, 0x30,
+ 0xda, 0x6a, 0x8e, 0x53, 0x8a, 0xd9, 0x0c, 0x65,
+ 0xac, 0x73, 0x50, 0x3a, 0x06, 0x64, 0xd6, 0x3f,
+ 0x55, 0x99, 0x9f, 0x9b, 0x53, 0xcc, 0x54, 0x59,
+ 0x47, 0x24, 0x19, 0xdb, 0xdb, 0x39, 0x95, 0x56,
+ 0x96, 0x72, 0xcc, 0xe9, 0x93, 0x6f, 0xf3, 0x0e,
+ 0xde, 0x95, 0xbc, 0x13, 0x89, 0x9a, 0xb7, 0x85,
+ 0x25, 0x23, 0x47, 0x89, 0x94, 0x50, 0x50, 0x31,
+ 0x3b, 0xf9, 0x3c, 0x63, 0xb3, 0x5a, 0xd9, 0xd6,
+ 0xd6, 0x36, 0x26, 0x9b, 0xcd, 0xb2, 0x73, 0x81,
+ 0x19, 0x96, 0x2d, 0xad, 0x71, 0x52, 0x39, 0x0d,
+ 0x99, 0xaa, 0x55, 0x6a, 0x34, 0xea, 0x94, 0x5e,
+ 0x6f, 0x98, 0x62, 0x0c, 0xc5, 0xec, 0xe5, 0xd5,
+ 0x95, 0xe5, 0xca, 0x4e, 0x7e, 0xb9, 0xad, 0xa7,
+ 0xbb, 0xac, 0x71, 0xef, 0x95, 0x4b, 0xab, 0x29,
+ 0xbe, 0x68, 0xb7, 0x39, 0x88, 0xdd, 0x6e, 0x27,
+ 0xd1, 0x68, 0x54, 0x0a, 0xfc, 0xf9, 0x07, 0xe1,
+ 0xd4, 0xd5, 0x52, 0x6f, 0xf7, 0x1d, 0xc5, 0x66,
+ 0xa9, 0xd0, 0xe1, 0xa5, 0x14, 0x4d, 0x4b, 0x2a,
+ 0xa9, 0x54, 0x2c, 0x49, 0x6c, 0xad, 0xde, 0xe0,
+ 0x4a, 0xc6, 0x63, 0xf5, 0xe0, 0x48, 0x0d, 0xcb,
+ 0xd0, 0xc5, 0xc9, 0xbf, 0x9f, 0x5a, 0x3f, 0x78,
+ 0xa4, 0x27, 0x62, 0x36, 0x99, 0xa9, 0x64, 0x26,
+ 0xcd, 0x2d, 0xdc, 0x0e, 0x2b, 0xf5, 0xae, 0x26,
+ 0xc6, 0xd5, 0xd8, 0x2c, 0x4d, 0x04, 0xf0, 0xc8,
+ 0xf1, 0xce, 0xb9, 0x06, 0x85, 0x10, 0xbd, 0x90,
+ 0x13, 0x0c, 0x2a, 0xd5, 0xae, 0x97, 0xf5, 0x74,
+ 0x74, 0xcd, 0x8a, 0xf9, 0xbc, 0x79, 0xb7, 0x58,
+ 0x36, 0xfc, 0x1e, 0xac, 0x88, 0x67, 0xde, 0xff,
+ 0x6b, 0x7e, 0x95, 0x39, 0xb5, 0xfc, 0xeb, 0x55,
+ 0x3f, 0xb5, 0xb9, 0x71, 0x0f, 0x84, 0x56, 0xcb,
+ 0x5a, 0x5a, 0xa3, 0x7a, 0xa2, 0xa9, 0x8d, 0x1e,
+ 0x3b, 0x72, 0x8e, 0xfe, 0x70, 0xa4, 0xc6, 0xe5,
+ 0xa8, 0xe3, 0x4d, 0xb9, 0x98, 0xc8, 0x55, 0x57,
+ 0x6b, 0x5a, 0x58, 0xbb, 0xb5, 0xee, 0x54, 0x99,
+ 0xde, 0x7c, 0x9c, 0xd2, 0x55, 0x8e, 0x5d, 0x3c,
+ 0xa7, 0xe4, 0x65, 0xb2, 0x95, 0x2a, 0xc6, 0x8e,
+ 0x57, 0xe2, 0x1b, 0x83, 0x78, 0xe7, 0xe0, 0x4f,
+ 0xb8, 0x74, 0x05, 0x00, 0x06, 0x25, 0xdb, 0xee,
+ 0x8b, 0x90, 0xcb, 0xc0, 0xf8, 0x67, 0xe2, 0xd2,
+ 0xe9, 0x33, 0x59, 0x8d, 0x56, 0x5d, 0x1b, 0xf2,
+ 0x76, 0xf7, 0x6a, 0x99, 0xa2, 0x38, 0xdd, 0x51,
+ 0x96, 0x45, 0xcf, 0x85, 0xd1, 0x42, 0x4e, 0x67,
+ 0x54, 0xc4, 0x6f, 0x3f, 0x97, 0x94, 0xaf, 0xbe,
+ 0x07, 0x5e, 0xf2, 0x86, 0xb1, 0x95, 0x01, 0x6e,
+ 0x45, 0x80, 0x97, 0xbd, 0x61, 0x5c, 0xfa, 0x1a,
+ 0x10, 0x36, 0x81, 0x27, 0x9f, 0xe6, 0x48, 0xcf,
+ 0x81, 0x42, 0xf9, 0x97, 0xdf, 0x44, 0x7d, 0x2c,
+ 0x19, 0x5e, 0x61, 0xda, 0x1e, 0xc5, 0xeb, 0x1d,
+ 0xcd, 0x80, 0xbb, 0x93, 0x90, 0x2b, 0x5f, 0x4a,
+ 0x98, 0x0c, 0x02, 0x16, 0x03, 0x16, 0x03, 0xb7,
+ 0x60, 0x0b, 0x45, 0x01, 0xbd, 0x16, 0x98, 0x5d,
+ 0x04, 0x2c, 0x7a, 0x2c, 0x2e, 0x44, 0x60, 0xdb,
+ 0x5a, 0x95, 0xb1, 0xff, 0x00, 0xb0, 0xb5, 0x01,
+ 0xc4, 0xee, 0x97, 0xec, 0x6c, 0x4e, 0x04, 0x16,
+ 0x22, 0x80, 0xf4, 0x1d, 0x30, 0x19, 0x04, 0xcc,
+ 0x7a, 0xdc, 0x98, 0x9e, 0x87, 0x1f, 0xc0, 0xc4,
+ 0x83, 0x3f, 0xf4, 0x76, 0x61, 0x77, 0x32, 0x08,
+ 0x2f, 0xcb, 0x00, 0xa1, 0xbb, 0x40, 0x4e, 0x04,
+ 0x18, 0xcf, 0xa1, 0xc1, 0xd2, 0x5a, 0x24, 0xec,
+ 0x5a, 0x59, 0x07, 0xec, 0x06, 0xdc, 0x9e, 0xbe,
+ 0x89, 0xa9, 0xff, 0xbb, 0xf1, 0x6e, 0x02, 0xf7,
+ 0x3a, 0x5c, 0x30, 0xdc, 0x5c, 0x81, 0x35, 0x2b,
+ 0x02, 0x66, 0xf7, 0xe0, 0xd5, 0x7f, 0x01, 0x9a,
+ 0xad, 0x8c, 0xd2, 0x70, 0x90, 0xfe, 0xf7, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/arrow_refresh.png.h b/src/images/arrow_refresh.png.h
new file mode 100644
index 0000000..4ede606
--- /dev/null
+++ b/src/images/arrow_refresh.png.h
@@ -0,0 +1,89 @@
+/* arrow_refresh.png - 685 bytes */
+ static const unsigned char arrow_refresh_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d,
+ 0x41, 0x00, 0x00, 0xaf, 0xc8, 0x37, 0x05, 0x8a,
+ 0xe9, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58,
+ 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72,
+ 0x65, 0x00, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20,
+ 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61,
+ 0x64, 0x79, 0x71, 0xc9, 0x65, 0x3c, 0x00, 0x00,
+ 0x02, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb,
+ 0x8d, 0x93, 0xdb, 0x4b, 0xd3, 0x61, 0x1c, 0xc6,
+ 0x07, 0xfb, 0x33, 0x62, 0x76, 0xd0, 0x92, 0x42,
+ 0xba, 0xb0, 0x42, 0xd6, 0x39, 0xcb, 0x64, 0x2d,
+ 0x4f, 0x64, 0x06, 0xad, 0x36, 0x5f, 0xd7, 0x74,
+ 0xe4, 0xa1, 0x81, 0x65, 0xce, 0xc5, 0x9a, 0xfe,
+ 0xdc, 0xdc, 0xa1, 0x1d, 0xdc, 0x49, 0xcd, 0xb1,
+ 0x61, 0x49, 0x46, 0x25, 0xfc, 0xc0, 0x68, 0x84,
+ 0x65, 0xb5, 0x8d, 0x0d, 0xd7, 0x61, 0xf9, 0x23,
+ 0xe8, 0xda, 0x3b, 0x11, 0xbc, 0x0d, 0xef, 0x9e,
+ 0xbe, 0x1b, 0x5d, 0x38, 0xfd, 0x61, 0xbb, 0x78,
+ 0x6f, 0xde, 0xc3, 0xf3, 0x3c, 0xef, 0xf3, 0xe1,
+ 0x2b, 0x01, 0x20, 0xf9, 0xdf, 0xba, 0xf1, 0xbc,
+ 0x71, 0xb0, 0x65, 0x5a, 0x21, 0x15, 0x3b, 0x93,
+ 0x94, 0x22, 0xd0, 0x34, 0x55, 0x2f, 0x28, 0xc6,
+ 0x2f, 0x44, 0x76, 0x15, 0xe8, 0xfb, 0xac, 0x95,
+ 0xdd, 0x5d, 0xd4, 0x18, 0x74, 0x6f, 0x55, 0x71,
+ 0xcd, 0x7c, 0xdb, 0xfa, 0xcd, 0x17, 0xcd, 0xb8,
+ 0x16, 0x55, 0xa2, 0x21, 0x5c, 0x07, 0xfd, 0xcb,
+ 0x76, 0x74, 0x3c, 0x53, 0xe1, 0xa4, 0xf9, 0xb8,
+ 0x4f, 0x54, 0xa0, 0x77, 0xa9, 0x43, 0xae, 0x7f,
+ 0xaf, 0xe6, 0xb9, 0xa4, 0x11, 0xfe, 0xac, 0x03,
+ 0x91, 0x9f, 0x41, 0x44, 0x57, 0x42, 0x98, 0xca,
+ 0xf9, 0x10, 0xfc, 0xfa, 0x04, 0xde, 0xe5, 0x31,
+ 0x8c, 0xa5, 0x2c, 0x68, 0x0d, 0x35, 0xa2, 0xaa,
+ 0xb7, 0x72, 0xb4, 0x48, 0xa0, 0xe7, 0x43, 0xbb,
+ 0xac, 0xeb, 0xdd, 0x2d, 0xde, 0xb3, 0x6c, 0xc5,
+ 0xec, 0xaf, 0x69, 0x4c, 0xfe, 0xf0, 0xe2, 0x69,
+ 0xce, 0x8f, 0xd0, 0x37, 0x37, 0x7c, 0x59, 0x3b,
+ 0x5c, 0x69, 0x0e, 0xd6, 0x94, 0x19, 0x8f, 0xbf,
+ 0x18, 0x71, 0xd5, 0x5d, 0x8f, 0x83, 0xba, 0x03,
+ 0xce, 0x22, 0x01, 0x8a, 0x6c, 0x30, 0x7f, 0x7a,
+ 0x80, 0x19, 0x61, 0x12, 0x91, 0x5c, 0x10, 0xee,
+ 0x8c, 0x0d, 0xba, 0x39, 0x35, 0xce, 0xdb, 0xe4,
+ 0xf9, 0xc8, 0x38, 0x36, 0x70, 0x14, 0x4d, 0x3e,
+ 0x05, 0xae, 0xb8, 0xea, 0x50, 0xa1, 0xdd, 0x17,
+ 0xd8, 0xf1, 0x05, 0xf5, 0xeb, 0xd6, 0xb8, 0x23,
+ 0x69, 0x29, 0x38, 0x3a, 0x53, 0x1c, 0x2e, 0xb9,
+ 0xce, 0xac, 0x9e, 0xe5, 0x6a, 0xdc, 0x5b, 0x2f,
+ 0x55, 0x76, 0x96, 0x0b, 0xe5, 0x6c, 0x6f, 0x4c,
+ 0xb4, 0xc4, 0xeb, 0x33, 0x0d, 0x6b, 0xd4, 0xf2,
+ 0x26, 0xb5, 0xfc, 0xa7, 0xd6, 0x7e, 0x6a, 0xe3,
+ 0xb4, 0xe5, 0x04, 0xb7, 0xfd, 0xd2, 0x7e, 0x4d,
+ 0x99, 0xa9, 0x4c, 0xb5, 0x47, 0x4a, 0x66, 0x8c,
+ 0x90, 0x32, 0x42, 0xca, 0x94, 0x81, 0x8b, 0x8c,
+ 0xcc, 0x98, 0x84, 0x5a, 0x66, 0x97, 0x3d, 0xe7,
+ 0x18, 0x45, 0x66, 0x14, 0x99, 0x51, 0x64, 0xd6,
+ 0x9f, 0xee, 0x92, 0x1a, 0x12, 0x77, 0x4c, 0xdb,
+ 0x85, 0xc8, 0x8c, 0x23, 0xb3, 0x8d, 0x7f, 0x66,
+ 0x9b, 0x64, 0xb6, 0x26, 0xca, 0x9d, 0x90, 0xc6,
+ 0x08, 0xa9, 0xb0, 0x75, 0x8f, 0x90, 0xba, 0xc9,
+ 0x6c, 0xd5, 0x93, 0xb6, 0x11, 0x15, 0x3b, 0x06,
+ 0x16, 0xee, 0xe5, 0xfb, 0x89, 0xef, 0x78, 0x4c,
+ 0x48, 0x03, 0xd6, 0x8c, 0x09, 0xc3, 0x89, 0x87,
+ 0xa0, 0xc8, 0xa0, 0xc8, 0xa0, 0xc8, 0xe8, 0x7e,
+ 0xa3, 0x85, 0x2b, 0xc9, 0x15, 0x90, 0x3a, 0xd2,
+ 0x23, 0x68, 0x9b, 0x68, 0xce, 0x23, 0x35, 0x14,
+ 0x3d, 0x26, 0xa4, 0x4e, 0x2e, 0x65, 0xc4, 0xdc,
+ 0xef, 0x68, 0x01, 0x69, 0x4c, 0x98, 0x28, 0x42,
+ 0x3a, 0x92, 0x18, 0x2a, 0x20, 0xd5, 0xce, 0xde,
+ 0xc6, 0x91, 0xee, 0x43, 0x3c, 0x21, 0x95, 0x15,
+ 0x09, 0x10, 0xd2, 0xd1, 0x47, 0x1f, 0xfb, 0x11,
+ 0x5b, 0x09, 0x17, 0x90, 0x86, 0xbf, 0x7b, 0x31,
+ 0x9e, 0x75, 0xc2, 0x95, 0xb1, 0x62, 0x78, 0x69,
+ 0x08, 0x3d, 0xf3, 0x3a, 0xb4, 0xf8, 0x95, 0x38,
+ 0xac, 0xaf, 0xe0, 0x09, 0xa9, 0x5c, 0x74, 0x16,
+ 0x28, 0xb2, 0xaf, 0x8f, 0xef, 0x84, 0xfe, 0x15,
+ 0xcb, 0x23, 0x05, 0x21, 0x45, 0x8d, 0xa9, 0x1a,
+ 0xd5, 0xf7, 0xab, 0xd6, 0x29, 0x72, 0x9c, 0x90,
+ 0x1a, 0x08, 0xa9, 0x6c, 0xd7, 0x61, 0xca, 0x0f,
+ 0x0e, 0xb5, 0x2c, 0x94, 0x32, 0x68, 0xa2, 0x9b,
+ 0x84, 0x54, 0x4a, 0x48, 0x07, 0x4b, 0x11, 0xf8,
+ 0x0b, 0x84, 0xac, 0x88, 0x99, 0xe8, 0xea, 0x8c,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
+ 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/away.png.h b/src/images/away.png.h
new file mode 100644
index 0000000..750f8a4
--- /dev/null
+++ b/src/images/away.png.h
@@ -0,0 +1,110 @@
+/* away.png - 855 bytes */
+ static const unsigned char away_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1b, 0x11, 0x3a, 0x20, 0x43, 0x02, 0x75, 0x4a,
+ 0x00, 0x00, 0x02, 0xd7, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0xa5, 0x93, 0x4d, 0x6c, 0x14, 0x75,
+ 0x1c, 0x86, 0x9f, 0x99, 0xdd, 0xe9, 0x6c, 0x77,
+ 0x67, 0x66, 0xbf, 0x5a, 0xea, 0x47, 0x4b, 0x4b,
+ 0xc0, 0xaa, 0x2d, 0x1a, 0x20, 0xba, 0x51, 0x52,
+ 0x0c, 0x0a, 0x27, 0x38, 0x50, 0x2e, 0x1c, 0x09,
+ 0x01, 0xe3, 0xc5, 0x84, 0x54, 0x0f, 0x44, 0x31,
+ 0x10, 0x3f, 0x52, 0xeb, 0xa6, 0x09, 0x09, 0x31,
+ 0xf6, 0x20, 0x89, 0x09, 0x46, 0x4d, 0x50, 0x8f,
+ 0x24, 0x6a, 0x9b, 0x80, 0x95, 0x84, 0x96, 0x0f,
+ 0x53, 0xa1, 0x5a, 0x5a, 0x08, 0x22, 0x6d, 0x59,
+ 0xba, 0xdb, 0x75, 0xbb, 0xdb, 0x9d, 0xdd, 0xd9,
+ 0xe9, 0x7c, 0xfc, 0xbd, 0xad, 0x28, 0x7a, 0x81,
+ 0xf7, 0xf8, 0xcb, 0x2f, 0x4f, 0xde, 0xc3, 0xf3,
+ 0x4a, 0x42, 0x08, 0x1e, 0x26, 0xc1, 0x7f, 0x1f,
+ 0x7e, 0x3c, 0x35, 0xf8, 0x8a, 0x1a, 0x30, 0xdf,
+ 0x51, 0x43, 0x2b, 0x1b, 0x02, 0x4a, 0x40, 0xf7,
+ 0x5c, 0x81, 0x55, 0xb1, 0x0a, 0x15, 0x93, 0x71,
+ 0xcb, 0x6d, 0x4c, 0xef, 0x7a, 0xad, 0x7f, 0xec,
+ 0xde, 0x7f, 0xe9, 0xde, 0x06, 0xe7, 0xbe, 0x19,
+ 0x18, 0x8a, 0xc5, 0x96, 0x0f, 0xc4, 0xdb, 0x7b,
+ 0x1b, 0x54, 0xa3, 0x19, 0x35, 0x1c, 0x47, 0x08,
+ 0x1f, 0xb3, 0x98, 0xa1, 0x30, 0x3f, 0x45, 0x66,
+ 0xfa, 0x6c, 0xa5, 0x54, 0x56, 0xd2, 0x7b, 0xfa,
+ 0x3e, 0xfe, 0xe0, 0x3e, 0xc0, 0xe8, 0xa9, 0x0f,
+ 0x8f, 0xb7, 0xae, 0x4b, 0x1c, 0x4c, 0xb4, 0xef,
+ 0x60, 0xb1, 0xaa, 0x33, 0x79, 0xb3, 0x44, 0x6e,
+ 0xa9, 0x8a, 0xeb, 0x09, 0xe2, 0x7a, 0x88, 0xee,
+ 0xb5, 0x1a, 0x71, 0xf1, 0x3b, 0xd7, 0x7e, 0xfa,
+ 0x9c, 0x6c, 0xce, 0x3d, 0xb4, 0xef, 0xf0, 0x89,
+ 0xc1, 0x3a, 0x60, 0xf8, 0x8b, 0x74, 0x4f, 0x32,
+ 0x96, 0x3f, 0xd3, 0x91, 0x7a, 0x5d, 0x99, 0xca,
+ 0xa8, 0xe4, 0x8b, 0x36, 0xcf, 0xae, 0x4b, 0x10,
+ 0x33, 0x64, 0x04, 0x12, 0x85, 0x92, 0xc7, 0xc5,
+ 0xe9, 0x45, 0x34, 0x55, 0xe6, 0x69, 0x63, 0x86,
+ 0xcb, 0xa7, 0x4f, 0x56, 0xad, 0x40, 0xa2, 0xe7,
+ 0xd5, 0xb7, 0x3f, 0x99, 0x90, 0x01, 0x02, 0xfe,
+ 0xd2, 0xe1, 0x68, 0xeb, 0x36, 0x65, 0xd1, 0x32,
+ 0x58, 0x28, 0xd4, 0xd8, 0xbd, 0xb5, 0x83, 0x84,
+ 0x2e, 0x28, 0x98, 0x26, 0x9a, 0x11, 0x61, 0x75,
+ 0x9b, 0x41, 0xef, 0xf6, 0xb5, 0x64, 0xcb, 0x3e,
+ 0x79, 0xb9, 0x8b, 0x96, 0x35, 0x8f, 0x87, 0xbd,
+ 0xea, 0xd2, 0x9b, 0x00, 0x32, 0x80, 0x2c, 0x55,
+ 0x37, 0x46, 0x12, 0xad, 0xfc, 0x3c, 0x53, 0x60,
+ 0x7d, 0x67, 0x92, 0xaa, 0x2b, 0x50, 0x14, 0x85,
+ 0x91, 0x1f, 0xbe, 0x67, 0xb9, 0x54, 0xc2, 0xb1,
+ 0x6d, 0x86, 0x47, 0xce, 0xd2, 0xd5, 0xd9, 0xc4,
+ 0xd8, 0x54, 0x91, 0x47, 0x3a, 0x53, 0x04, 0xc4,
+ 0x4a, 0x4f, 0x1d, 0x20, 0x84, 0x88, 0x85, 0x22,
+ 0x71, 0x32, 0xf9, 0x2a, 0xc9, 0x64, 0x23, 0xb6,
+ 0x27, 0x68, 0x08, 0x87, 0x99, 0x9f, 0x9d, 0x65,
+ 0xe4, 0xcc, 0x28, 0xfd, 0x03, 0x69, 0x74, 0x3d,
+ 0x42, 0x7c, 0x55, 0x98, 0xbb, 0x85, 0x1a, 0xd1,
+ 0xe6, 0x0e, 0x02, 0x48, 0x2d, 0x75, 0x80, 0x63,
+ 0x3b, 0xf8, 0xbe, 0x8d, 0xb5, 0xe2, 0x63, 0x7b,
+ 0xe0, 0xf8, 0x90, 0x2b, 0x95, 0x89, 0x68, 0x1a,
+ 0x93, 0x57, 0x7e, 0x61, 0x67, 0xef, 0x6e, 0x36,
+ 0x3e, 0x9f, 0xc2, 0x76, 0xc1, 0x71, 0x7c, 0x84,
+ 0x5f, 0x43, 0xf8, 0xe2, 0x6f, 0x0f, 0x2a, 0xa6,
+ 0x75, 0xb7, 0x94, 0xbd, 0xbe, 0x26, 0x1a, 0x79,
+ 0x8c, 0x5b, 0x0b, 0x55, 0x9e, 0x68, 0x8d, 0x82,
+ 0x1c, 0x62, 0xd3, 0x73, 0x2f, 0xf0, 0xd4, 0x33,
+ 0xeb, 0x09, 0x47, 0x0d, 0x4c, 0x1b, 0xe6, 0x16,
+ 0x2a, 0x18, 0x11, 0x99, 0xa5, 0x3b, 0x57, 0xa8,
+ 0xb9, 0x5e, 0xbe, 0xde, 0xa0, 0x6c, 0x31, 0x3a,
+ 0x37, 0x35, 0x4a, 0xea, 0xc9, 0x46, 0xc6, 0x26,
+ 0xb2, 0x28, 0x2a, 0x44, 0x42, 0x0a, 0x3d, 0x5b,
+ 0x36, 0xd3, 0x14, 0x37, 0x50, 0x01, 0x2d, 0x04,
+ 0x97, 0x26, 0x72, 0xbc, 0xd4, 0x2d, 0x73, 0xfb,
+ 0xea, 0x79, 0x1c, 0x11, 0x1c, 0xaf, 0x03, 0x3c,
+ 0x59, 0x3f, 0x3e, 0x3b, 0x73, 0xcb, 0x4a, 0x38,
+ 0xe3, 0xb4, 0xe9, 0x26, 0x9f, 0x7d, 0x3b, 0xc3,
+ 0xed, 0x3b, 0x45, 0x24, 0xdb, 0x41, 0xb2, 0x1c,
+ 0x66, 0xe7, 0x8a, 0x7c, 0xfa, 0xf5, 0x34, 0xab,
+ 0x1b, 0x73, 0x34, 0x5b, 0xdf, 0x31, 0x77, 0xb3,
+ 0x52, 0x93, 0x54, 0x63, 0xf0, 0x1f, 0x22, 0x9d,
+ 0x78, 0x7f, 0xff, 0x5b, 0x9a, 0x6a, 0x0e, 0x6c,
+ 0xd8, 0xfa, 0x32, 0x59, 0x39, 0xc5, 0xd8, 0x6f,
+ 0x2e, 0xc5, 0xb2, 0x87, 0xe7, 0x0b, 0xf4, 0x30,
+ 0xbc, 0xd8, 0x25, 0x68, 0xb2, 0x87, 0xb9, 0x34,
+ 0x7c, 0x11, 0x8b, 0xe4, 0x7b, 0x7d, 0x1f, 0x7d,
+ 0xf9, 0xee, 0x7d, 0x2a, 0x0f, 0x1d, 0xd9, 0x7b,
+ 0x44, 0x71, 0xcb, 0x87, 0x5a, 0xda, 0xc3, 0x5a,
+ 0x5b, 0x67, 0x37, 0xb1, 0x47, 0xdb, 0x41, 0xb8,
+ 0xfc, 0x39, 0x7f, 0x83, 0x3f, 0x26, 0x7f, 0x25,
+ 0x9b, 0xf1, 0x2b, 0x4e, 0x50, 0x3b, 0xd6, 0x97,
+ 0xfe, 0xea, 0xe8, 0x7f, 0x6e, 0x01, 0x60, 0xe8,
+ 0xe8, 0xfe, 0x94, 0x5b, 0x5b, 0x7e, 0x43, 0xf6,
+ 0x9c, 0xcd, 0x41, 0x59, 0x34, 0x03, 0xb8, 0xbe,
+ 0xb4, 0xe8, 0xc9, 0xc1, 0x71, 0xa9, 0x41, 0x3b,
+ 0x76, 0xb0, 0xff, 0xe4, 0x85, 0xff, 0x1d, 0xd3,
+ 0x83, 0xe4, 0x2f, 0x44, 0x57, 0x4d, 0x98, 0x66,
+ 0xab, 0x75, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/battle.xpm b/src/images/battle.xpm
new file mode 100644
index 0000000..1bfe8c9
--- /dev/null
+++ b/src/images/battle.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static const char * battle_xpm[] = {
+"12 12 9 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #BCBCBC",
+"# c #7E7E7E",
+"$ c #FFEAAC",
+"% c #BC8E00",
+"& c #705400",
+"* c #FFD75F",
+".... ....",
+".+++. .+++.",
+".@#@+..+@#@.",
+".#@#@+.@#@#.",
+" .#@#@+.@#. ",
+" ..#@#@+... ",
+".$..#@#@+.$.",
+".%$@.#@#@$%.",
+" .%@@.#@@%. ",
+".&&%*..*%&&.",
+"&&&.%**%.&&&",
+"*&. .... .&*"};
diff --git a/src/images/battle_list.xpm b/src/images/battle_list.xpm
new file mode 100644
index 0000000..7f309c6
--- /dev/null
+++ b/src/images/battle_list.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static const char * battle_list_xpm[] = {
+"12 12 9 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #BCBCBC",
+"# c #7E7E7E",
+"$ c #FFEAAC",
+"% c #BC8E00",
+"& c #FFD75F",
+"* c #705400",
+" .+@#@#. ...",
+".+@#@#. +++.",
+"+@#@#. +@#@.",
+"@#@#. +@#@#.",
+"#@#. +@#@#..",
+"@#. +@#@#..+",
+"#$ +@#@#..+@",
+".%$@#@#$.+@#",
+"&.%@@#.%$@#@",
+".**%&. .%@@#",
+"***.%&.**%&.",
+"&*. ..***.%&"};
diff --git a/src/images/battle_map.xpm b/src/images/battle_map.xpm
new file mode 100644
index 0000000..cae79a3
--- /dev/null
+++ b/src/images/battle_map.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static const char * battle_map_xpm[] = {
+"12 12 3 1",
+" c None",
+". c #000000",
+"+ c #FF0000",
+" ",
+" .. ",
+" .. ",
+" .. ",
+".. .. ",
+".. .. .. ",
+" .++..++.",
+" .++++. ",
+".. .++. ",
+".. .++++. ",
+" .++..++.",
+" .. .. "};
diff --git a/src/images/battle_settings.xpm b/src/images/battle_settings.xpm
new file mode 100644
index 0000000..7f8dcc8
--- /dev/null
+++ b/src/images/battle_settings.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static const char * battle_settings_xpm[] = {
+"12 12 7 1",
+" c None",
+". c #161616",
+"+ c #C8C6C6",
+"@ c #949493",
+"# c #464646",
+"$ c #000000",
+"% c #7C7A7A",
+" ...... ",
+" .+@@@@@. ",
+" .+@@@@@@@..",
+".+@@@@......",
+"+@@@@@. ",
+"@...@@. ",
+".#++$@. ",
+".#..$@. ",
+".#++$@......",
+".#..$@.@@@%.",
+".#++. at .@%%. ",
+"@...@@.%.. "};
diff --git a/src/images/bot.xpm b/src/images/bot.xpm
new file mode 100644
index 0000000..c83d9c0
--- /dev/null
+++ b/src/images/bot.xpm
@@ -0,0 +1,188 @@
+/* XPM */
+static const char * bot_xpm[] = {
+"16 16 169 2",
+" c None",
+". c #41423C",
+"+ c #52544B",
+"@ c #6C6D61",
+"# c #6E6B5C",
+"$ c #66685C",
+"% c #EAEED2",
+"& c #C4C8AE",
+"* c #363733",
+"= c #C1C5B4",
+"- c #DEE3CD",
+"; c #44433A",
+"> c #6B6451",
+", c #B8AF90",
+"' c #615D4C",
+") c #191712",
+"! c #807654",
+"~ c #B0A170",
+"{ c #ABA074",
+"] c #7A7866",
+"^ c #717277",
+"/ c #7A7B81",
+"( c #484843",
+"_ c #514027",
+": c #40321E",
+"< c #A49E90",
+"[ c #675E50",
+"} c #2E2723",
+"| c #AA9C6C",
+"1 c #F6E29D",
+"2 c #8E8462",
+"3 c #B4B5BE",
+"4 c #B7B9C2",
+"5 c #919399",
+"6 c #534128",
+"7 c #302619",
+"8 c #65655C",
+"9 c #B0B39F",
+"0 c #65675C",
+"a c #44423E",
+"b c #554E36",
+"c c #D7C589",
+"d c #7F7556",
+"e c #5B554A",
+"f c #555656",
+"g c #8A8C92",
+"h c #8F9097",
+"i c #211C12",
+"j c #4B4639",
+"k c #8A866F",
+"l c #A7A995",
+"m c #AAAC98",
+"n c #232321",
+"o c #3C3A38",
+"p c #B8B4B3",
+"q c #7C7B78",
+"r c #A6AFAA",
+"s c #959D9A",
+"t c #6F7573",
+"u c #373936",
+"v c #948A65",
+"w c #D3C387",
+"x c #2E2112",
+"y c #1B1812",
+"z c #5E5C5E",
+"A c #B7B4B8",
+"B c #545556",
+"C c #AFB9B4",
+"D c #ADB7B3",
+"E c #B6C0BC",
+"F c #515653",
+"G c #AAA17C",
+"H c #F6E29E",
+"I c #F4E09E",
+"J c #2B2217",
+"K c #0B0906",
+"L c #9F9CA0",
+"M c #636163",
+"N c #404241",
+"O c #A4ACA8",
+"P c #AEB7B3",
+"Q c #B5BEBA",
+"R c #525755",
+"S c #393935",
+"T c #574A3C",
+"U c #787368",
+"V c #333232",
+"W c #A4A0A4",
+"X c #474546",
+"Y c #7D7D71",
+"Z c #5D5F56",
+"` c #5F6461",
+" . c #929996",
+".. c #303331",
+"+. c #272322",
+"@. c #332E2F",
+"#. c #CAC5C6",
+"$. c #817E80",
+"%. c #A8A4A8",
+"&. c #454444",
+"*. c #6C6D60",
+"=. c #494940",
+"-. c #262521",
+";. c #505049",
+">. c #53544B",
+",. c #262722",
+"'. c #9B9B99",
+"). c #BBB9BA",
+"!. c #6D6A6D",
+"~. c #A5A1A5",
+"{. c #494747",
+"]. c #606155",
+"^. c #3C3D34",
+"/. c #0B0A09",
+"(. c #66675C",
+"_. c #7C7C6E",
+":. c #31312E",
+"<. c #BAB9B9",
+"[. c #807C7F",
+"}. c #545254",
+"|. c #6A696A",
+"1. c #242322",
+"2. c #777869",
+"3. c #6E6E61",
+"4. c #0B0B09",
+"5. c #262621",
+"6. c #4C4D43",
+"7. c #555551",
+"8. c #A1A0A1",
+"9. c #7F7B7F",
+"0. c #565356",
+"a. c #C8C8C8",
+"b. c #2E2D2A",
+"c. c #595A50",
+"d. c #535449",
+"e. c #080806",
+"f. c #3A3A33",
+"g. c #6F7062",
+"h. c #6E6E67",
+"i. c #A09EA0",
+"j. c #7E7B7E",
+"k. c #514F51",
+"l. c #717170",
+"m. c #DCDCDA",
+"n. c #A3A3A0",
+"o. c #030302",
+"p. c #282823",
+"q. c #59594E",
+"r. c #595851",
+"s. c #959394",
+"t. c #605D5F",
+"u. c #121212",
+"v. c #CCCCCB",
+"w. c #E0E0DF",
+"x. c #4B4B4B",
+"y. c #010101",
+"z. c #6E6E6D",
+"A. c #CACAC9",
+"B. c #2A2828",
+"C. c #807D7E",
+"D. c #201E1F",
+"E. c #666666",
+"F. c #6F6F6F",
+"G. c #282828",
+"H. c #131313",
+"I. c #8D8D8C",
+"J. c #787878",
+"K. c #0B0B0B",
+"L. c #0C0C0C",
+" . + @ # ",
+" $ % & * = - ; > , ' ) ",
+" ! ~ { ] ^ / ( _ : < [ } ",
+" | 1 1 2 3 4 5 6 7 8 9 0 a ",
+" b c d e f g h i j k l m n ",
+" o p q r s t u v 1 w x y ",
+" z A B C D E F G H I J K ",
+" L M N O P Q R S T U V ",
+" W X Y Z ` ...+. at .#.$. ",
+" %.&.*.=.-.;.>.,.'.).!. ",
+" ~.{.].^./.(._.:.<.[.}. ",
+" |.1.2.3.4.5.6.7.8.9.0.a. ",
+" b.c.d.e.f.g.h.i.j.k.a.a. ",
+" l.m.n.o.p.q.r.s.t.u.a.a. ",
+" v.w.x.y.z.A.B.C.D.a.a. ",
+" E.F.G.H.I.J.K.L.a.a. "};
diff --git a/src/images/bot_away.xpm b/src/images/bot_away.xpm
new file mode 100644
index 0000000..fc9a470
--- /dev/null
+++ b/src/images/bot_away.xpm
@@ -0,0 +1,157 @@
+/* XPM */
+static const char * bot_away_xpm[] = {
+"16 16 138 2",
+" c None",
+". c #41423C",
+"+ c #52544B",
+"@ c #6C6D61",
+"# c #6E6B5C",
+"$ c #66685C",
+"% c #EAEED2",
+"& c #C4C8AE",
+"* c #363733",
+"= c #C1C5B4",
+"- c #DEE3CD",
+"; c #44433A",
+"> c #6B6451",
+", c #B8AF90",
+"' c #615D4C",
+") c #191712",
+"! c #807654",
+"~ c #B0A170",
+"{ c #ABA074",
+"] c #7A7866",
+"^ c #717277",
+"/ c #7A7B81",
+"( c #484843",
+"_ c #514027",
+": c #40321E",
+"< c #A49E90",
+"[ c #675E50",
+"} c #2E2723",
+"| c #AA9C6C",
+"1 c #F6E29D",
+"2 c #8E8462",
+"3 c #B4B5BE",
+"4 c #B7B9C2",
+"5 c #919399",
+"6 c #534128",
+"7 c #302619",
+"8 c #65655C",
+"9 c #B0B39F",
+"0 c #65675C",
+"a c #44423E",
+"b c #554E36",
+"c c #D7C589",
+"d c #7F7556",
+"e c #5B554A",
+"f c #555656",
+"g c #8A8C92",
+"h c #8F9097",
+"i c #211C12",
+"j c #4B4639",
+"k c #8A866F",
+"l c #A7A995",
+"m c #AAAC98",
+"n c #232321",
+"o c #3C3A38",
+"p c #B8B4B3",
+"q c #7C7B78",
+"r c #A6AFAA",
+"s c #959D9A",
+"t c #6F7573",
+"u c #373936",
+"v c #948A65",
+"w c #D3C387",
+"x c #2E2112",
+"y c #1B1812",
+"z c #5E5C5E",
+"A c #B7B4B8",
+"B c #545556",
+"C c #AFB9B4",
+"D c #ADB7B3",
+"E c #B6C0BC",
+"F c #475A49",
+"G c #A7A17A",
+"H c #F6E29E",
+"I c #F4E09E",
+"J c #282A15",
+"K c #0B0906",
+"L c #9F9CA0",
+"M c #636163",
+"N c #404241",
+"O c #A4ACA8",
+"P c #AEB7B3",
+"Q c #B5BEBA",
+"R c #525755",
+"S c #20201E",
+"T c #453F38",
+"U c #121210",
+"V c #353535",
+"W c #767676",
+"X c #A4A0A4",
+"Y c #474546",
+"Z c #7D7D71",
+"` c #5D5F56",
+" . c #5F6461",
+".. c #B0B5B3",
+"+. c #343434",
+"@. c #5F5E5E",
+"#. c #CAC4C5",
+"$. c #000000",
+"%. c #EDE7E7",
+"&. c #7B7B7B",
+"*. c #A8A4A8",
+"=. c #454444",
+"-. c #6C6D60",
+";. c #494940",
+">. c #262521",
+",. c #30302C",
+"'. c #A5A1A5",
+"). c #494747",
+"!. c #606155",
+"~. c #3C3D34",
+"{. c #0B0A09",
+"]. c #353630",
+"^. c #6A696A",
+"/. c #242322",
+"(. c #777869",
+"_. c #6E6E61",
+":. c #0B0B09",
+"<. c #2E2D2A",
+"[. c #595A50",
+"}. c #535449",
+"|. c #080806",
+"1. c #363634",
+"2. c #717170",
+"3. c #DCDCDA",
+"4. c #A3A3A0",
+"5. c #030302",
+"6. c #747474",
+"7. c #CCCCCB",
+"8. c #E0E0DF",
+"9. c #4B4B4B",
+"0. c #010101",
+"a. c #6E6E6D",
+"b. c #666666",
+"c. c #6F6F6F",
+"d. c #282828",
+"e. c #131313",
+"f. c #8D8D8C",
+"g. c #787878",
+" . + @ # ",
+" $ % & * = - ; > , ' ) ",
+" ! ~ { ] ^ / ( _ : < [ } ",
+" | 1 1 2 3 4 5 6 7 8 9 0 a ",
+" b c d e f g h i j k l m n ",
+" o p q r s t u v 1 w x y ",
+" z A B C D E F G H I J K ",
+" L M N O P Q R S T U V W ",
+" X Y Z ` ...+. at .#.$.%.&.V ",
+" *.=.-.;.>.,.&.%.%.$.%.%.&.W ",
+" '.).!.~.{.].%.%.%.$.%.%.%.V ",
+" ^./.(._.:.:.%.%.%.$.$.$.%.$.",
+" <.[.}.|.1.%.%.%.%.%.%.%.V ",
+" 2.3.4.5.6.&.%.%.%.%.%.&. ",
+" 7.8.9.0.a.V &.%.%.%.&.V ",
+" b.c.d.e.f.g.W V $.V "};
diff --git a/src/images/bot_broom.png.h b/src/images/bot_broom.png.h
new file mode 100644
index 0000000..40ff016
--- /dev/null
+++ b/src/images/bot_broom.png.h
@@ -0,0 +1,127 @@
+/* bot_broom.png - 986 bytes */
+ static const unsigned char bot_broom_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x12, 0x21, 0x0c, 0xed, 0x74, 0x9c, 0x58,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x03,
+ 0x35, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x6d,
+ 0x92, 0x5b, 0x4c, 0x93, 0x07, 0x18, 0x86, 0x9f,
+ 0xf6, 0xff, 0x4b, 0x0b, 0x43, 0x69, 0x6b, 0x1d,
+ 0xad, 0x58, 0xa1, 0x21, 0x25, 0xb3, 0xac, 0xc6,
+ 0x41, 0x86, 0x88, 0x24, 0x86, 0x0d, 0xe6, 0x24,
+ 0x10, 0x0f, 0x3b, 0x25, 0x63, 0x5e, 0x6c, 0x59,
+ 0xe2, 0xb2, 0x25, 0xc4, 0x2d, 0x92, 0x38, 0x93,
+ 0x2d, 0x45, 0x6e, 0x8c, 0x31, 0x71, 0x5b, 0x82,
+ 0x9b, 0x71, 0x4b, 0xe6, 0x32, 0x89, 0x59, 0x63,
+ 0xf4, 0x02, 0x88, 0x93, 0x4d, 0xf0, 0x80, 0x6b,
+ 0xc0, 0x76, 0x05, 0x23, 0x20, 0xb0, 0xb1, 0x02,
+ 0xb3, 0xb3, 0x0d, 0xb6, 0xd8, 0xd2, 0xc3, 0xdf,
+ 0xc3, 0xbf, 0x8b, 0x45, 0x06, 0xd9, 0xde, 0xab,
+ 0xef, 0xea, 0xc9, 0x9b, 0xf7, 0x7b, 0x14, 0x6f,
+ 0xbd, 0xf3, 0xee, 0xb5, 0xf5, 0xa6, 0x22, 0xd4,
+ 0x1a, 0x35, 0xc0, 0x47, 0xc7, 0x3f, 0x39, 0xea,
+ 0x05, 0xa8, 0x7b, 0xa1, 0x56, 0xd6, 0xe9, 0x0b,
+ 0xd8, 0x60, 0x7a, 0x1a, 0x65, 0x36, 0xc5, 0x17,
+ 0x9d, 0xdf, 0x2b, 0xf8, 0x9f, 0x28, 0xc3, 0x8b,
+ 0x8b, 0x1c, 0x6e, 0x6b, 0xe3, 0xf9, 0xca, 0x2d,
+ 0x75, 0xe6, 0xa2, 0x75, 0xbf, 0xf6, 0xf4, 0x75,
+ 0xc9, 0x55, 0xdb, 0x2a, 0x65, 0x47, 0xc7, 0x11,
+ 0x4e, 0x9e, 0x3a, 0xc6, 0xc4, 0xd8, 0x7d, 0x32,
+ 0xc9, 0x25, 0xae, 0x5c, 0xfa, 0x4c, 0x7e, 0xfb,
+ 0x40, 0x93, 0x6c, 0x2a, 0xd4, 0xcb, 0x2b, 0x01,
+ 0x22, 0xc0, 0x5d, 0xcf, 0x60, 0x9d, 0xcd, 0xba,
+ 0x09, 0xed, 0x1a, 0x15, 0x57, 0x7f, 0xba, 0x45,
+ 0xed, 0xce, 0x97, 0xf9, 0xb1, 0xd7, 0x8d, 0xc7,
+ 0x7d, 0x83, 0x35, 0x99, 0x05, 0xee, 0x79, 0xe6,
+ 0xd9, 0x5e, 0xb3, 0x93, 0x1c, 0x85, 0xc8, 0x7a,
+ 0xad, 0x0e, 0xff, 0xc3, 0x47, 0xcb, 0x00, 0xa1,
+ 0xcc, 0x56, 0x3e, 0xe2, 0xfb, 0xed, 0xee, 0x7b,
+ 0xdb, 0xaa, 0x2b, 0xb1, 0x14, 0x6f, 0x44, 0xaf,
+ 0xd5, 0xb3, 0xf0, 0x38, 0x4e, 0xf9, 0xe6, 0x67,
+ 0x31, 0x1a, 0xcd, 0xcc, 0x4e, 0xb8, 0xf0, 0x2f,
+ 0xc4, 0x48, 0x09, 0x1a, 0x1a, 0xf7, 0xef, 0x26,
+ 0x26, 0xa5, 0xd0, 0x17, 0x68, 0x1d, 0xbf, 0xcf,
+ 0xf8, 0xda, 0x01, 0x94, 0xdd, 0x17, 0x9d, 0xde,
+ 0x50, 0xe0, 0x4f, 0xce, 0x7e, 0x75, 0x86, 0x81,
+ 0x5b, 0x1e, 0x64, 0x21, 0x97, 0xbc, 0xdc, 0x1c,
+ 0xbc, 0x63, 0xa3, 0x24, 0x25, 0x09, 0xcf, 0x54,
+ 0x80, 0xa2, 0x92, 0x12, 0xac, 0x96, 0x75, 0xc4,
+ 0x63, 0x31, 0x1a, 0x1a, 0x6a, 0x99, 0xf1, 0xcd,
+ 0xfd, 0xdb, 0x00, 0x60, 0xfc, 0xbe, 0xaf, 0x5d,
+ 0x93, 0x93, 0xef, 0x88, 0x44, 0x13, 0x18, 0x4c,
+ 0x1b, 0xa8, 0xae, 0xa9, 0x21, 0x29, 0xc5, 0x99,
+ 0x99, 0xf5, 0x91, 0x4c, 0xa6, 0x69, 0xae, 0x2f,
+ 0xe3, 0xe0, 0x9b, 0x95, 0xa8, 0xb2, 0x8f, 0x38,
+ 0xf4, 0x7e, 0x07, 0x91, 0x58, 0x92, 0x48, 0x34,
+ 0xde, 0xbe, 0xbc, 0x01, 0x40, 0xf1, 0x26, 0x0b,
+ 0x3b, 0xaa, 0xb6, 0xd3, 0x75, 0xee, 0x1c, 0x07,
+ 0x5b, 0x5b, 0xa9, 0xaa, 0xaa, 0x46, 0xad, 0xd6,
+ 0x90, 0x4c, 0x24, 0xc8, 0xd7, 0xa9, 0x00, 0x05,
+ 0x16, 0x73, 0x21, 0x19, 0x85, 0x8a, 0xf0, 0x62,
+ 0x68, 0x75, 0x03, 0x80, 0x43, 0xad, 0x1f, 0x3a,
+ 0x6e, 0xde, 0xbc, 0x4e, 0x20, 0xf8, 0x17, 0xfe,
+ 0x07, 0x7e, 0x4c, 0x1b, 0xcd, 0xd8, 0x6c, 0x36,
+ 0x82, 0xc1, 0x00, 0x23, 0xe3, 0x7e, 0xba, 0x7b,
+ 0xbc, 0x5c, 0x76, 0x7e, 0x8b, 0x5a, 0x88, 0x52,
+ 0x5a, 0xd1, 0xf4, 0xea, 0xe4, 0xf8, 0xd8, 0x38,
+ 0x80, 0xf2, 0x09, 0x40, 0x25, 0x8a, 0xcc, 0xcf,
+ 0xcf, 0xb1, 0xa3, 0xda, 0x4e, 0x3c, 0x12, 0xe4,
+ 0xec, 0xe9, 0x4e, 0x86, 0x86, 0x86, 0xd8, 0xfc,
+ 0x8c, 0x0d, 0xab, 0xa5, 0x94, 0xb4, 0x5a, 0xc7,
+ 0xc9, 0xe3, 0x46, 0x3e, 0x3e, 0x6c, 0x40, 0xf5,
+ 0xd0, 0xf9, 0xc1, 0xb2, 0x07, 0xcb, 0xff, 0x14,
+ 0x45, 0xb2, 0x72, 0x96, 0x50, 0x38, 0x44, 0x78,
+ 0x21, 0xc8, 0x83, 0xd9, 0x3f, 0x70, 0x9e, 0xff,
+ 0x8e, 0xe9, 0xe9, 0x49, 0x74, 0xda, 0x02, 0x1a,
+ 0x1b, 0x77, 0x73, 0xa2, 0x6b, 0x17, 0x92, 0x94,
+ 0x22, 0x9d, 0x59, 0x21, 0xd2, 0x93, 0x23, 0x93,
+ 0xc9, 0x20, 0x0a, 0x02, 0xd1, 0xe8, 0x12, 0x91,
+ 0x68, 0x94, 0x7b, 0x23, 0x23, 0xe8, 0xd6, 0x6a,
+ 0xb8, 0x7d, 0xa3, 0x9f, 0xbe, 0xfe, 0x01, 0x72,
+ 0x73, 0xf3, 0x38, 0xd0, 0xe0, 0xe4, 0xf3, 0x2f,
+ 0x25, 0x44, 0x81, 0xcb, 0xff, 0x01, 0x0c, 0xba,
+ 0x06, 0x99, 0x9a, 0x9e, 0xa2, 0xb0, 0xd0, 0x40,
+ 0xc5, 0x73, 0x76, 0x50, 0xc0, 0xe8, 0xed, 0x4b,
+ 0xd4, 0x14, 0xf7, 0x12, 0x8b, 0x84, 0xc9, 0x0b,
+ 0xb5, 0x22, 0x25, 0xd2, 0x1c, 0x6d, 0x83, 0x74,
+ 0x86, 0xbd, 0xfb, 0x6b, 0x79, 0x05, 0x60, 0x95,
+ 0xdf, 0x5b, 0xec, 0x36, 0xb9, 0xdc, 0x5e, 0x86,
+ 0x24, 0x25, 0xe9, 0xe9, 0xfe, 0x19, 0x5b, 0x89,
+ 0x9a, 0x7d, 0xf5, 0x4f, 0x21, 0x88, 0x4a, 0x5c,
+ 0xa3, 0x6b, 0xb1, 0x5b, 0x12, 0xec, 0xda, 0x23,
+ 0x61, 0xcc, 0xf7, 0x0f, 0x1c, 0xf9, 0x54, 0x96,
+ 0x81, 0x1f, 0x94, 0x2b, 0x01, 0x2f, 0xd6, 0xbf,
+ 0x44, 0xc7, 0xb1, 0x13, 0xec, 0xdd, 0xf3, 0x06,
+ 0xa9, 0x54, 0x9a, 0x1c, 0x95, 0x8a, 0x2b, 0x83,
+ 0x29, 0xba, 0x07, 0x24, 0x2c, 0xa5, 0x65, 0x5c,
+ 0xf7, 0x24, 0xf8, 0xfa, 0x74, 0x80, 0xac, 0x20,
+ 0x0a, 0x5b, 0xad, 0x00, 0xbc, 0xbe, 0x0a, 0xd0,
+ 0xd2, 0xd2, 0x82, 0x28, 0xaa, 0xb8, 0x70, 0xc1,
+ 0x49, 0x36, 0x2b, 0x53, 0x55, 0xd7, 0xc2, 0xa9,
+ 0x33, 0xbd, 0x84, 0x13, 0x06, 0x74, 0xc6, 0xad,
+ 0x3c, 0x5e, 0x92, 0x18, 0x9d, 0x4c, 0xf7, 0x9f,
+ 0xff, 0x26, 0x95, 0xf6, 0x4e, 0x41, 0x38, 0xb2,
+ 0xc2, 0x83, 0x7f, 0xa2, 0x70, 0xdc, 0xb9, 0xe3,
+ 0x66, 0x78, 0x78, 0x18, 0x59, 0x96, 0x69, 0x6e,
+ 0x6e, 0xc2, 0xed, 0xf6, 0x70, 0xb5, 0xaf, 0x8f,
+ 0x5f, 0x5c, 0x2e, 0xe6, 0xfc, 0x8b, 0x8a, 0x0a,
+ 0xab, 0x68, 0x76, 0x4f, 0x64, 0x2d, 0xa1, 0x08,
+ 0x18, 0xca, 0x5f, 0xeb, 0xfc, 0x1b, 0xeb, 0xa3,
+ 0x4e, 0x7f, 0x82, 0x92, 0xfe, 0xfd, 0x00, 0x00,
+ 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+ 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/bot_ingame.png.h b/src/images/bot_ingame.png.h
new file mode 100644
index 0000000..c825054
--- /dev/null
+++ b/src/images/bot_ingame.png.h
@@ -0,0 +1,135 @@
+/* bot_ingame.png - 1052 bytes */
+ static const unsigned char bot_ingame_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x12, 0x22, 0x2d, 0x8a, 0x30, 0xdf, 0xc5,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x03,
+ 0x77, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x55,
+ 0x90, 0x5b, 0x4c, 0x9b, 0x05, 0x00, 0x85, 0xbf,
+ 0x5e, 0xa0, 0x14, 0xcb, 0x1c, 0xb4, 0x20, 0x65,
+ 0x40, 0xf7, 0xcb, 0x9d, 0x22, 0xe2, 0x90, 0x8b,
+ 0xac, 0x93, 0x30, 0x2f, 0xb8, 0x65, 0x4c, 0x45,
+ 0x47, 0x96, 0x45, 0x4d, 0x34, 0x5b, 0x9c, 0xd9,
+ 0x83, 0xc9, 0x02, 0xc9, 0x34, 0xd1, 0xa0, 0x64,
+ 0x53, 0xe7, 0x65, 0x6c, 0xba, 0xe9, 0x83, 0x33,
+ 0xd9, 0x02, 0xbc, 0x34, 0x88, 0x4e, 0x18, 0x0c,
+ 0xc6, 0x18, 0xc8, 0xa4, 0x81, 0xd0, 0x81, 0x28,
+ 0xf7, 0x8e, 0xb6, 0x0e, 0x5b, 0x70, 0xcd, 0x0a,
+ 0x94, 0xb5, 0xb4, 0xb4, 0xbf, 0x0f, 0xca, 0x8c,
+ 0xe7, 0xfd, 0xfb, 0x72, 0xce, 0x91, 0xbc, 0xf2,
+ 0xc6, 0xc1, 0x6b, 0xb1, 0xda, 0x2d, 0x28, 0x22,
+ 0x14, 0x00, 0x47, 0x3f, 0x7e, 0xef, 0xdd, 0x11,
+ 0x80, 0xb2, 0x9d, 0x06, 0x31, 0x3a, 0xe6, 0x41,
+ 0x12, 0xb4, 0x71, 0x48, 0x43, 0x01, 0xce, 0x9c,
+ 0x6d, 0x90, 0x00, 0x1c, 0xab, 0x3b, 0x91, 0x07,
+ 0x7c, 0xb1, 0xe6, 0x5b, 0xe3, 0x2f, 0xc7, 0x3c,
+ 0x52, 0xf7, 0xd2, 0x12, 0xd5, 0x35, 0x35, 0x14,
+ 0xe4, 0xe7, 0x96, 0x25, 0x6d, 0x51, 0xdf, 0x6c,
+ 0xeb, 0x6a, 0x12, 0x0b, 0x8b, 0xf2, 0xc5, 0xda,
+ 0xba, 0x63, 0x7c, 0x76, 0xea, 0x43, 0x26, 0xc7,
+ 0xa7, 0x08, 0xae, 0xad, 0xd2, 0xd1, 0x52, 0x2f,
+ 0x1e, 0x3a, 0x58, 0x25, 0x3a, 0x6e, 0xdb, 0x6f,
+ 0xee, 0xdd, 0x5b, 0x41, 0x75, 0x4d, 0x0d, 0xee,
+ 0xa5, 0x25, 0xe4, 0x00, 0x63, 0xe6, 0x1b, 0x65,
+ 0xd9, 0x69, 0xc9, 0x6c, 0x8e, 0x0a, 0xa3, 0xf3,
+ 0x6a, 0x3f, 0x86, 0xd2, 0xe7, 0xb8, 0x72, 0x79,
+ 0x18, 0xf3, 0x70, 0x1f, 0x51, 0x41, 0x17, 0xbf,
+ 0x9b, 0x6f, 0xa3, 0x7f, 0x6c, 0x3b, 0x51, 0x1a,
+ 0x01, 0x7d, 0xce, 0x23, 0xe8, 0x74, 0x02, 0x0e,
+ 0x87, 0x13, 0x00, 0x59, 0x7a, 0xb6, 0x7e, 0xd4,
+ 0x66, 0x19, 0x3b, 0x5c, 0x54, 0x9c, 0x8f, 0xa0,
+ 0x4b, 0x24, 0x66, 0x73, 0x0c, 0xae, 0x65, 0x2f,
+ 0xfa, 0xac, 0x1c, 0xe2, 0xe3, 0x93, 0xb0, 0x4f,
+ 0x9a, 0xf0, 0x84, 0x22, 0x89, 0x8c, 0xd5, 0xb1,
+ 0x7f, 0x7f, 0x15, 0xd1, 0x6a, 0x0d, 0x63, 0xa3,
+ 0xa3, 0xc2, 0x97, 0xf5, 0xa7, 0xac, 0xc0, 0x51,
+ 0xd9, 0xf4, 0xc4, 0xb8, 0x53, 0x48, 0x8a, 0xa9,
+ 0x9d, 0xb5, 0xdc, 0x22, 0x28, 0x55, 0xa1, 0xda,
+ 0xa4, 0xc6, 0xe5, 0xba, 0x83, 0xc5, 0x66, 0x45,
+ 0x2e, 0x95, 0xf1, 0xb3, 0x69, 0x90, 0xc7, 0x4b,
+ 0xcb, 0x79, 0x34, 0x37, 0x1b, 0x21, 0x25, 0x15,
+ 0xe7, 0x82, 0x93, 0xaf, 0xea, 0x4f, 0x13, 0xae,
+ 0x50, 0xbc, 0xdd, 0xda, 0x6c, 0xec, 0x93, 0x01,
+ 0x4c, 0x4c, 0xd9, 0x3e, 0x88, 0x08, 0x57, 0xd5,
+ 0xae, 0x78, 0x7c, 0x68, 0xb4, 0x09, 0x14, 0x97,
+ 0x94, 0xb0, 0xe6, 0xf7, 0x32, 0x67, 0xb7, 0xa1,
+ 0xd1, 0x26, 0x51, 0x5c, 0x98, 0xcb, 0xee, 0xf2,
+ 0x27, 0x99, 0xb3, 0xce, 0xf2, 0xe9, 0xf1, 0x4f,
+ 0xb0, 0x5b, 0xa6, 0x30, 0xdd, 0x18, 0x38, 0x00,
+ 0x20, 0xe5, 0xdf, 0xe8, 0x92, 0x05, 0xb6, 0x17,
+ 0x3e, 0x41, 0xd3, 0x85, 0x0b, 0xd8, 0xec, 0x76,
+ 0x04, 0x21, 0x05, 0xb5, 0x5a, 0x4d, 0x66, 0x66,
+ 0x26, 0x05, 0x05, 0x45, 0xdc, 0xb2, 0xda, 0xe8,
+ 0xb8, 0xd4, 0x82, 0x6b, 0x7e, 0x0e, 0xc7, 0x9f,
+ 0xce, 0x0d, 0xec, 0x9f, 0x13, 0x01, 0xd2, 0x33,
+ 0xb3, 0x68, 0x6d, 0xa8, 0x46, 0xf4, 0x79, 0xe9,
+ 0xbe, 0x92, 0x8e, 0x3a, 0x2e, 0x0e, 0x41, 0xd8,
+ 0x8a, 0x36, 0x3e, 0x81, 0xbe, 0x5f, 0xcc, 0xb4,
+ 0xb7, 0x18, 0x51, 0x05, 0x67, 0xd1, 0x6e, 0x5a,
+ 0x24, 0x71, 0xf7, 0xf3, 0x2f, 0xff, 0xd4, 0x6c,
+ 0xe4, 0x7f, 0x0d, 0xec, 0xa3, 0x17, 0x79, 0xed,
+ 0x80, 0x8f, 0x13, 0x75, 0x2a, 0xbc, 0x5e, 0x2f,
+ 0xb1, 0xd1, 0x6a, 0xb2, 0x32, 0xf5, 0x0c, 0x0e,
+ 0x0e, 0x62, 0x6c, 0x6c, 0x24, 0x32, 0x2a, 0x86,
+ 0xcf, 0x8f, 0x47, 0xf0, 0x4e, 0xb5, 0x86, 0xb0,
+ 0x05, 0xe3, 0x91, 0x0d, 0xee, 0xbe, 0x20, 0x24,
+ 0x4a, 0x10, 0x45, 0x38, 0xd9, 0xf0, 0x2c, 0x59,
+ 0x19, 0x19, 0xc8, 0x10, 0xe9, 0xeb, 0xed, 0xa1,
+ 0xff, 0x7a, 0x37, 0xa9, 0x69, 0xa9, 0xbc, 0x50,
+ 0xf9, 0x22, 0x27, 0x9b, 0xca, 0xf1, 0xfb, 0x03,
+ 0xac, 0x07, 0xef, 0x2f, 0xf8, 0x4f, 0x90, 0x24,
+ 0xe4, 0xf3, 0xcd, 0x79, 0x09, 0x6f, 0x55, 0x76,
+ 0x10, 0x02, 0x7e, 0x6c, 0x6b, 0xa7, 0xf7, 0x5a,
+ 0x17, 0x0f, 0x44, 0x2a, 0x59, 0x5e, 0xf5, 0xa2,
+ 0x54, 0x46, 0xf2, 0xea, 0x33, 0x46, 0x4e, 0x7f,
+ 0xed, 0x47, 0x2e, 0xe3, 0x87, 0x0d, 0x4e, 0x06,
+ 0x50, 0x69, 0xe0, 0xa5, 0x3b, 0x2e, 0x57, 0xd5,
+ 0x91, 0x37, 0x97, 0x09, 0x0b, 0x57, 0x22, 0xf7,
+ 0xf4, 0xd0, 0x6d, 0x8a, 0xe0, 0xa9, 0xf4, 0x6e,
+ 0x06, 0x4d, 0x56, 0xc2, 0x54, 0x5a, 0x0c, 0x0f,
+ 0x5f, 0x44, 0x2e, 0xf3, 0xb3, 0xa3, 0x24, 0x40,
+ 0x6f, 0xdf, 0xbd, 0x08, 0xfd, 0x56, 0x3c, 0x13,
+ 0x76, 0x26, 0x64, 0x95, 0x06, 0x0e, 0x03, 0xaf,
+ 0x7f, 0xf4, 0xfe, 0x8a, 0xf5, 0xae, 0x57, 0x25,
+ 0x5c, 0x6a, 0x16, 0x31, 0xb6, 0xad, 0xb3, 0x4d,
+ 0x37, 0x49, 0xc0, 0xaf, 0x64, 0xc1, 0xad, 0xa4,
+ 0x34, 0x67, 0x9e, 0xef, 0xdb, 0x15, 0xb8, 0x9d,
+ 0xeb, 0x08, 0x19, 0x50, 0xb9, 0xcb, 0x63, 0xbb,
+ 0xda, 0x43, 0x41, 0x56, 0x32, 0x4a, 0x29, 0x50,
+ 0x95, 0x97, 0x06, 0x21, 0x29, 0x74, 0xb7, 0xab,
+ 0x58, 0xbc, 0x97, 0xc2, 0x8e, 0xd2, 0x9d, 0x74,
+ 0xf4, 0x8b, 0x74, 0x0e, 0x04, 0x50, 0x48, 0x03,
+ 0xb4, 0x5e, 0xf7, 0x23, 0xa4, 0xa4, 0xd3, 0x6b,
+ 0xf6, 0xf1, 0xed, 0xb9, 0x45, 0x42, 0x32, 0xb9,
+ 0x2c, 0x2f, 0x0d, 0x80, 0x2a, 0xa9, 0x7b, 0x05,
+ 0x46, 0x66, 0xa0, 0xf1, 0x3b, 0xb0, 0xb9, 0x1e,
+ 0xe2, 0xe9, 0xf2, 0x3d, 0xfc, 0x66, 0xf1, 0x62,
+ 0x71, 0x48, 0x28, 0xdd, 0x75, 0x88, 0xba, 0x33,
+ 0x97, 0x71, 0xfb, 0x34, 0x44, 0xc7, 0xe7, 0xb1,
+ 0xbc, 0xea, 0xe7, 0xd7, 0xe9, 0xf5, 0x9e, 0xc6,
+ 0xf3, 0x81, 0xf5, 0x91, 0x19, 0x70, 0xaf, 0x80,
+ 0x2c, 0xc7, 0xb0, 0xcf, 0x63, 0x9b, 0x19, 0x2f,
+ 0x9c, 0xb6, 0x83, 0x26, 0x2e, 0x51, 0xf0, 0x04,
+ 0xd5, 0x0c, 0x0d, 0x0d, 0x21, 0x8a, 0x22, 0x15,
+ 0x15, 0x7b, 0x18, 0x1e, 0x36, 0xd3, 0xd9, 0xd5,
+ 0xc5, 0x80, 0xc9, 0xc4, 0x1f, 0x8e, 0x25, 0xc9,
+ 0xb6, 0x34, 0x79, 0xd2, 0xf0, 0x64, 0x48, 0xb8,
+ 0xbb, 0x02, 0x1a, 0xfd, 0xbe, 0xb3, 0x7f, 0x03,
+ 0x88, 0x4d, 0x68, 0xa3, 0x57, 0x39, 0x38, 0x90,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+ 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/broom.png.h b/src/images/broom.png.h
new file mode 100644
index 0000000..b3f693d
--- /dev/null
+++ b/src/images/broom.png.h
@@ -0,0 +1,87 @@
+/* broom.png - 668 bytes */
+ static const unsigned char broom_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xa6,
+ 0x00, 0xb0, 0x00, 0xb5, 0x78, 0x71, 0x68, 0x5a,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x12, 0x1a, 0x1c, 0xcc, 0x71, 0x63, 0x04,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x01,
+ 0xf7, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x95,
+ 0x93, 0x4f, 0x48, 0xd3, 0x71, 0x18, 0x87, 0x9f,
+ 0xa5, 0x31, 0x0f, 0x11, 0x83, 0x39, 0x43, 0xcd,
+ 0xfd, 0xc1, 0x6d, 0xa0, 0x52, 0x92, 0x7f, 0xb6,
+ 0x65, 0x8b, 0xb6, 0x92, 0x1a, 0xf5, 0x73, 0x07,
+ 0xc7, 0x2e, 0x59, 0x30, 0x62, 0xe0, 0x25, 0xa2,
+ 0x22, 0xc9, 0xc2, 0x60, 0x15, 0x45, 0x05, 0x1e,
+ 0x05, 0xa1, 0x5b, 0x74, 0x88, 0x82, 0xba, 0x04,
+ 0x25, 0xe8, 0x7e, 0x2d, 0x56, 0x59, 0x50, 0x8d,
+ 0x60, 0x5b, 0x2d, 0x88, 0x45, 0x2e, 0xb7, 0x31,
+ 0x73, 0xc3, 0x4d, 0x2b, 0x84, 0x6f, 0x97, 0x02,
+ 0x11, 0x9d, 0xed, 0x73, 0x7b, 0x2f, 0x0f, 0xcf,
+ 0xe7, 0x7d, 0x79, 0x15, 0xc7, 0x4e, 0xf8, 0x85,
+ 0xa6, 0xbe, 0x11, 0x65, 0x8d, 0x12, 0xc0, 0x79,
+ 0xe3, 0xd2, 0xc5, 0x67, 0x54, 0x90, 0x4d, 0xf9,
+ 0x42, 0x81, 0x73, 0x43, 0x43, 0xb8, 0xdd, 0x7d,
+ 0x00, 0xf2, 0xf0, 0xd5, 0xeb, 0x8e, 0x8a, 0x00,
+ 0x00, 0xb3, 0xb3, 0x69, 0x74, 0x3a, 0x03, 0x92,
+ 0x74, 0x04, 0x21, 0x84, 0x7c, 0xfe, 0xca, 0xb5,
+ 0xc1, 0x4a, 0x00, 0xce, 0xc0, 0xc8, 0x05, 0x66,
+ 0x52, 0x29, 0x0c, 0x86, 0x66, 0x8e, 0x1f, 0x1d,
+ 0x40, 0xa1, 0x50, 0x8c, 0xff, 0xaf, 0x49, 0x55,
+ 0x22, 0x1e, 0x4b, 0x9a, 0x5b, 0xdb, 0xd2, 0xcf,
+ 0xe5, 0xa0, 0xa4, 0x37, 0x9a, 0xd0, 0xe9, 0xf5,
+ 0xfc, 0x5c, 0x2c, 0x91, 0xce, 0x64, 0x7c, 0x76,
+ 0xe7, 0x81, 0xd0, 0x0b, 0x39, 0x98, 0x2c, 0x0b,
+ 0x00, 0x48, 0xc4, 0x63, 0x6f, 0xcd, 0xad, 0x6d,
+ 0xa1, 0x37, 0xaf, 0x5e, 0xfa, 0xf4, 0x46, 0x13,
+ 0x16, 0x8b, 0x95, 0xa5, 0xa5, 0x45, 0x32, 0x99,
+ 0xac, 0x6f, 0xef, 0xfe, 0xde, 0x50, 0x58, 0x9e,
+ 0x4a, 0x96, 0x05, 0xfc, 0x85, 0x24, 0x57, 0x42,
+ 0xac, 0x16, 0x2b, 0xa5, 0x52, 0x91, 0x6c, 0x36,
+ 0x5b, 0xd6, 0xa4, 0x6a, 0xe5, 0xb0, 0x1a, 0x62,
+ 0xb3, 0xda, 0x28, 0x16, 0x17, 0xc8, 0xe5, 0x72,
+ 0x3e, 0x4b, 0x8f, 0x7d, 0x6b, 0xbd, 0x08, 0x4d,
+ 0xb4, 0x68, 0x09, 0x18, 0xbb, 0xbd, 0x85, 0x44,
+ 0x3c, 0x36, 0xbd, 0x6e, 0x2f, 0xc9, 0xe3, 0x75,
+ 0x48, 0x1e, 0xaf, 0xb8, 0xf7, 0xf8, 0xa9, 0x48,
+ 0xe5, 0x8b, 0xe2, 0xd1, 0x93, 0x49, 0x71, 0x6a,
+ 0x78, 0x44, 0x14, 0xe2, 0x88, 0x44, 0x10, 0xd1,
+ 0x6f, 0x47, 0xac, 0x69, 0xb0, 0xca, 0xa4, 0xe1,
+ 0x43, 0xe4, 0x7d, 0xa7, 0x4a, 0x5d, 0x4b, 0xe3,
+ 0xb6, 0x3a, 0x6a, 0x35, 0x9a, 0x5f, 0xb7, 0x6e,
+ 0x2b, 0xab, 0x1d, 0x3b, 0xde, 0x31, 0x31, 0x05,
+ 0x9f, 0x66, 0xb8, 0x0c, 0xa0, 0x28, 0xb7, 0x61,
+ 0xc9, 0xe3, 0x1d, 0x04, 0xc6, 0x1b, 0xb4, 0x06,
+ 0x5c, 0x87, 0x0e, 0xb2, 0x67, 0xfb, 0x61, 0xfc,
+ 0xfe, 0xdf, 0x6c, 0xae, 0x66, 0xec, 0x61, 0x98,
+ 0x93, 0x1b, 0xde, 0xb8, 0xcb, 0x8c, 0x78, 0x30,
+ 0x8a, 0x90, 0x3c, 0x5e, 0x11, 0xbe, 0x8f, 0xf8,
+ 0xfa, 0x1a, 0x31, 0x1f, 0x45, 0xb8, 0x77, 0x23,
+ 0xfa, 0xed, 0x9c, 0x5e, 0xb7, 0xc2, 0xbf, 0xd4,
+ 0xa9, 0x08, 0x34, 0xa9, 0xc1, 0xa8, 0x8e, 0x71,
+ 0x73, 0x0c, 0x0a, 0xdf, 0xa1, 0xdb, 0x5e, 0xc3,
+ 0x3e, 0xdb, 0x32, 0x93, 0x32, 0xae, 0x16, 0x2d,
+ 0x5b, 0xca, 0x02, 0x3a, 0x9a, 0x31, 0x4d, 0x47,
+ 0xd9, 0x19, 0xf9, 0x08, 0x1a, 0x15, 0x77, 0x22,
+ 0x9f, 0x69, 0x9f, 0x4b, 0x2e, 0xd3, 0xde, 0x05,
+ 0x73, 0xdf, 0x20, 0xfd, 0x83, 0x1e, 0x45, 0x25,
+ 0x8f, 0xd3, 0xdb, 0xc1, 0x68, 0x2e, 0xcf, 0xd9,
+ 0x3e, 0x3b, 0x44, 0xbf, 0x40, 0x7e, 0x61, 0x83,
+ 0x25, 0xae, 0x15, 0x57, 0x27, 0x77, 0xd3, 0xf3,
+ 0x0c, 0x00, 0x34, 0xed, 0xf2, 0x9e, 0xf9, 0x03,
+ 0x16, 0x81, 0xcd, 0xba, 0x2e, 0xbb, 0x34, 0xc2,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+ 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/channel.xpm b/src/images/channel.xpm
new file mode 100644
index 0000000..4896fc8
--- /dev/null
+++ b/src/images/channel.xpm
@@ -0,0 +1,20 @@
+/* XPM */
+static const char * channel_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #000000",
+"+ c #FFFDEA",
+"@ c #A49300",
+"# c #FFE400",
+" .. .. ",
+" .++..++. ",
+" ..+ at ..#@.. ",
+".++##++###@.",
+".+##@@@#@@@.",
+" ..+ at ..+@.. ",
+" ..+ at ..+@.. ",
+".+###++####.",
+".+##@@@#@@@.",
+" ..+ at ..+@.. ",
+" .+ at ..+@. ",
+" .. .. "};
diff --git a/src/images/channel_options.xpm b/src/images/channel_options.xpm
new file mode 100644
index 0000000..d45f798
--- /dev/null
+++ b/src/images/channel_options.xpm
@@ -0,0 +1,35 @@
+/* XPM */
+static const char* channel_options_xpm[] = {
+"16 16 16 1",
+" c None",
+". c #000000",
+"+ c #FFFDEA",
+"@ c #A49300",
+"# c #FFE400",
+"$ c #BABABA",
+"% c #514800",
+"& c #949494",
+"* c #A9A9A9",
+"= c #7E7000",
+"- c #767676",
+"; c #878787",
+"> c #BBBBBB",
+", c #7E7D73",
+"' c #5E5E5E",
+") c #696969",
+" .. .. ",
+" .++..++. ",
+" ..+ at ..#@.. ",
+".++##++###@. ",
+".+##@@@#..... ",
+" ..+ at ..+.$$$... ",
+" ..+ at ..+%.&*$$..",
+".+###++##=.&&*&.",
+".+##..%#@@%.-&;.",
+" ..+.>., at ...-&'.",
+" .+.$$.%...-&'.",
+" ..&*$...*-&'.",
+" ..&*$$$*&&&.",
+" .-&&&&&&&&)",
+" ..'''''&&&&",
+" .......)&&"};
diff --git a/src/images/chanop.xpm b/src/images/chanop.xpm
new file mode 100644
index 0000000..1d3e03d
--- /dev/null
+++ b/src/images/chanop.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static const char * chanop_xpm[] = {
+"16 16 8 1",
+" c None",
+". c #C5FFC5",
+"+ c #A8FFA8",
+"@ c #3CFF3C",
+"# c #00DB00",
+"$ c #00AB00",
+"% c #005C00",
+"& c #008000",
+" ",
+" ",
+" .+@####### ",
+" .$%%%%%%%%#& ",
+" +% #& ",
+" @% .@###& #& ",
+" #% @&&&$& #& ",
+" #% #& $& #& ",
+" #% #$$$$& #& ",
+" #% &&&&&###& ",
+" #% &&& ",
+" #$#### ",
+" &&&&& ",
+" ",
+" ",
+" "};
diff --git a/src/images/chanop_away.xpm b/src/images/chanop_away.xpm
new file mode 100644
index 0000000..5f86a0d
--- /dev/null
+++ b/src/images/chanop_away.xpm
@@ -0,0 +1,32 @@
+/* XPM */
+static const char * chanop_away_xpm[] = {
+"16 16 13 1",
+" c None",
+". c #C5FFC5",
+"+ c #A8FFA8",
+"@ c #3CFF3C",
+"# c #00DB00",
+"$ c #00AB00",
+"% c #005C00",
+"& c #008000",
+"* c #767676",
+"= c #353535",
+"- c #000000",
+"; c #7B7B7B",
+"> c #EDE7E7",
+" ",
+" ",
+" .+@####### ",
+" .$%%%%%%%%#& ",
+" +% #& ",
+" @% .@###& #& ",
+" #% @&&&$& #& ",
+" #% #& *=-=* ",
+" #% #$$=;>->;= ",
+" #% &&*;>>->>;*",
+" #% =>>>->>>=",
+" #$###->>>--->-",
+" &&&&=>>>>>>>=",
+" *;>>>>>; ",
+" =;>>>;= ",
+" *=-= "};
diff --git a/src/images/chanop_broom.xpm b/src/images/chanop_broom.xpm
new file mode 100644
index 0000000..aa4dcf3
--- /dev/null
+++ b/src/images/chanop_broom.xpm
@@ -0,0 +1,32 @@
+/* XPM */
+static const char * chanop_broom_xpm[] = {
+"16 16 13 1",
+" c None",
+". c #7E7E7E",
+"+ c #000000",
+"@ c #FFFFFF",
+"# c #00DB00",
+"$ c #BCBCBC",
+"% c #005C00",
+"& c #008000",
+"* c #FFEAAC",
+"= c #BC8E00",
+"- c #00AB00",
+"; c #FFD75F",
+"> c #705400",
+" ",
+" .+++ ",
+" +.@@+####### ",
+" +$.$@+%%%%%#& ",
+" +.$.$@+ #& ",
+" +.$.$@+#& #& ",
+" #+.$.$@+& #& ",
+" #%+.$.$@+ +& ",
+" #% +.$.$@+*+ ",
+" #% &+.$.$*=+ ",
+" #% +.$$=+ ",
+" #-####+;=>>+ ",
+" &&&&+;=+>>>+ ",
+" ++ +>>> ",
+" +>; ",
+" "};
diff --git a/src/images/chanop_ingame.xpm b/src/images/chanop_ingame.xpm
new file mode 100644
index 0000000..9e0329e
--- /dev/null
+++ b/src/images/chanop_ingame.xpm
@@ -0,0 +1,35 @@
+/* XPM */
+static const char * chanop_ingame_xpm[] = {
+"16 16 16 1",
+" c None",
+". c #C5FFC5",
+"+ c #A8FFA8",
+"@ c #3CFF3C",
+"# c #00DB00",
+"$ c #00AB00",
+"% c #005C00",
+"& c #008000",
+"* c #7E7E7E",
+"= c #000000",
+"- c #FFFFFF",
+"; c #BCBCBC",
+"> c #FFEAAC",
+", c #BC8E00",
+"' c #705400",
+") c #FFD75F",
+" .+@####### ",
+" .$%%%%%%%%#&",
+"*===+% ===*#&",
+"=*--=% .@=--*=#&",
+"=;*;-= @=-;*;=#&",
+"=*;*;-==-;*;*=#&",
+" =*;*;-=;*;*= #&",
+" =*;*;-=;*=###&",
+" ==*;*;-===&&& ",
+" =>==*;*;-=>= ",
+" =,>;=*;*;>,= ",
+" =,;;=*;;,= ",
+" ='',)==),''= ",
+"='''=,)),='''= ",
+"'''= ==== =''' ",
+")'= =') "};
diff --git a/src/images/chat_icon.png.h b/src/images/chat_icon.png.h
new file mode 100644
index 0000000..94ed35f
--- /dev/null
+++ b/src/images/chat_icon.png.h
@@ -0,0 +1,537 @@
+/* chat_icon.png - 4267 bytes */
+ static const unsigned char chat_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x0a,
+ 0x07, 0x15, 0x29, 0x2e, 0x67, 0xa3, 0xe7, 0x45,
+ 0x00, 0x00, 0x10, 0x2b, 0x49, 0x44, 0x41, 0x54,
+ 0x58, 0x09, 0x01, 0x20, 0x10, 0xdf, 0xef, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x78, 0x78,
+ 0x29, 0x31, 0x31, 0x31, 0x06, 0x1f, 0x1f, 0x1f,
+ 0xfb, 0xd6, 0xd6, 0xd6, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x73, 0x73, 0x73, 0x4e, 0x5b, 0x5b,
+ 0x5b, 0xa7, 0xf9, 0xf9, 0xf9, 0x05, 0xe5, 0xe5,
+ 0xe5, 0xd1, 0xe7, 0xe7, 0xe7, 0xd3, 0xde, 0xde,
+ 0xde, 0xc0, 0xf8, 0xf8, 0xf8, 0xbf, 0xf3, 0xf3,
+ 0xf3, 0xe9, 0xa4, 0xa4, 0xa4, 0xfa, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0x4a, 0x25,
+ 0x25, 0x25, 0x0a, 0x03, 0x03, 0x03, 0x00, 0x33,
+ 0x33, 0x33, 0x34, 0xfb, 0xfb, 0xfb, 0x34, 0xf6,
+ 0xf6, 0xf6, 0x60, 0xe0, 0xe0, 0xe0, 0xff, 0xe4,
+ 0xe4, 0xe4, 0xd9, 0x35, 0x35, 0x35, 0xc9, 0xeb,
+ 0xeb, 0xeb, 0xbf, 0xe2, 0xe2, 0xe2, 0xd2, 0xeb,
+ 0xeb, 0xeb, 0xd1, 0xb7, 0xb7, 0xb7, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x69, 0x69, 0x69, 0x0e, 0x0a, 0x0a, 0x0a, 0xf8,
+ 0xf2, 0xf2, 0xf2, 0xfc, 0x9b, 0x9b, 0x9b, 0xfe,
+ 0x52, 0x52, 0x52, 0x06, 0x53, 0x53, 0x53, 0xc0,
+ 0x54, 0x54, 0x54, 0x39, 0xfc, 0xfc, 0xfc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x04, 0x04, 0x00, 0xfe, 0xfe, 0xfe, 0x00,
+ 0xf0, 0xf0, 0xf0, 0x00, 0xeb, 0xeb, 0xeb, 0xf7,
+ 0xe0, 0xe0, 0xe0, 0xef, 0xe1, 0xe1, 0xe1, 0xbc,
+ 0xeb, 0xeb, 0xeb, 0x8b, 0x83, 0x83, 0x83, 0xd4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x7a, 0x7a,
+ 0x24, 0x3c, 0x3c, 0x3c, 0xc0, 0x03, 0x03, 0x03,
+ 0x08, 0xe4, 0xe4, 0xe4, 0xc2, 0x26, 0x26, 0x26,
+ 0xc6, 0xe2, 0xe2, 0xe2, 0xda, 0x1c, 0x1c, 0x1c,
+ 0x34, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xfa, 0xfa, 0xfa, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x0b, 0x0b, 0x0b, 0x00, 0x0c, 0x0c, 0x0c,
+ 0x09, 0x22, 0x22, 0x22, 0x09, 0x06, 0x06, 0x06,
+ 0x5d, 0xa9, 0xa9, 0xa9, 0xfe, 0x00, 0x00, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x4f, 0x3e, 0x3e, 0x3e, 0x1b, 0x04, 0x04,
+ 0x04, 0x00, 0x02, 0x02, 0x02, 0x51, 0xf2, 0xf2,
+ 0xf2, 0x51, 0xf0, 0xf0, 0xf0, 0xfd, 0xe2, 0xe2,
+ 0xe2, 0x03, 0xbe, 0xbe, 0xbe, 0x00, 0x0a, 0x0a,
+ 0x0a, 0x00, 0x19, 0x19, 0x19, 0x00, 0x10, 0x10,
+ 0x10, 0x00, 0x0c, 0x0c, 0x0c, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
+ 0x03, 0x01, 0xec, 0xec, 0xec, 0xe9, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22,
+ 0x22, 0x22, 0x41, 0x04, 0x04, 0x04, 0x00, 0xfd,
+ 0xfd, 0xfd, 0x00, 0xfd, 0xfd, 0xfd, 0x00, 0x08,
+ 0x08, 0x08, 0x00, 0x1a, 0x1a, 0x1a, 0x03, 0x1b,
+ 0x1b, 0x1b, 0x00, 0x02, 0x02, 0x02, 0x00, 0xf8,
+ 0xf8, 0xf8, 0x00, 0xe5, 0xe5, 0xe5, 0x00, 0xdb,
+ 0xdb, 0xdb, 0x00, 0xf4, 0xf4, 0xf4, 0x00, 0x03,
+ 0x03, 0x03, 0x00, 0x2f, 0x2f, 0x2f, 0x00, 0x06,
+ 0x06, 0x06, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea,
+ 0xea, 0xea, 0x00, 0xf3, 0xf3, 0xf3, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x0b,
+ 0x1b, 0x1b, 0x1b, 0x2f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0xfe, 0xfe, 0xfe, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x1c, 0x1c, 0x1c, 0x00,
+ 0x20, 0x20, 0x20, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xef, 0xef, 0xef, 0x00, 0xe2, 0xe2, 0xe2, 0x00,
+ 0x25, 0x25, 0x25, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x03, 0x03, 0x03, 0x00,
+ 0xeb, 0xeb, 0xeb, 0xef, 0xe1, 0xe1, 0xe1, 0xda,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12,
+ 0x2a, 0x1e, 0x1e, 0x1e, 0x17, 0xfe, 0xfe, 0xfe,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xfb, 0xfb, 0xfb, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xf8, 0xf8, 0xf8, 0x00, 0x06, 0x06, 0x06,
+ 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0xfe, 0xfe, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02,
+ 0x00, 0xe5, 0xe5, 0xe5, 0xe0, 0xd8, 0xd8, 0xd8,
+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x81, 0x70, 0x00, 0x07, 0x07, 0x06,
+ 0x00, 0x0e, 0xf9, 0xfa, 0x00, 0xf7, 0x7f, 0x90,
+ 0x00, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x1a,
+ 0x1a, 0x35, 0x15, 0x15, 0x15, 0x05, 0xfd, 0xfd,
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x02, 0x02,
+ 0x02, 0x00, 0xe8, 0xe8, 0xe8, 0x00, 0x22, 0x22,
+ 0x22, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe3, 0xe3, 0xe3, 0xc3, 0xc6, 0xc6,
+ 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x8d,
+ 0x80, 0x09, 0x01, 0x19, 0x16, 0x13, 0x52, 0x26,
+ 0x2b, 0x4d, 0x6d, 0x10, 0x11, 0x1a, 0x29, 0x0a,
+ 0x09, 0x08, 0x06, 0xf9, 0xf9, 0xf6, 0xfb, 0x4e,
+ 0x52, 0xe9, 0xe6, 0xdd, 0xd8, 0xbc, 0x9d, 0xe8,
+ 0xf9, 0x12, 0x39, 0x0f, 0x0f, 0x0f, 0x00, 0xf9,
+ 0xf9, 0xf9, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x03, 0x03, 0x00, 0xf4, 0xf4, 0xf4, 0x00, 0x05,
+ 0x05, 0x05, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3,
+ 0xf3, 0xf3, 0xff, 0xed, 0xeb, 0xda, 0xd1, 0xa4,
+ 0x94, 0x24, 0x12, 0xd3, 0xcd, 0xdc, 0xf3, 0x89,
+ 0x9f, 0x00, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0xcb, 0xc0, 0x68, 0xbd, 0x25, 0x28, 0x36, 0x42,
+ 0x0a, 0x08, 0xfc, 0x00, 0xfe, 0xfd, 0xf4, 0x00,
+ 0x00, 0xff, 0xfa, 0x00, 0xff, 0xfe, 0xf2, 0x00,
+ 0x00, 0xfd, 0xf7, 0x00, 0xfb, 0xf7, 0x11, 0x00,
+ 0xc4, 0xd6, 0x2b, 0xfd, 0x3d, 0x3f, 0x46, 0x03,
+ 0xfd, 0xfd, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x03, 0x03, 0x00, 0xc5, 0xc5, 0xc5, 0x00,
+ 0x3b, 0x3b, 0x3b, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x03, 0x03, 0x03, 0x00, 0xfd, 0xfd, 0xfd, 0x00,
+ 0xdb, 0xdb, 0xd9, 0xff, 0x14, 0x0b, 0xbd, 0xec,
+ 0x0c, 0x09, 0xfa, 0xf9, 0xf4, 0xf1, 0xf7, 0xdb,
+ 0xde, 0xdd, 0xd1, 0x9f, 0xca, 0xcb, 0xba, 0xa6,
+ 0x04, 0x2e, 0x2e, 0x33, 0x42, 0x00, 0x02, 0x00,
+ 0x00, 0x01, 0x02, 0x0e, 0x00, 0x03, 0x02, 0x0e,
+ 0x00, 0xff, 0xfe, 0xf6, 0x00, 0xff, 0xfd, 0x06,
+ 0x00, 0xfc, 0xfe, 0xeb, 0x00, 0xe7, 0xeb, 0xe0,
+ 0x00, 0x19, 0x19, 0x45, 0x03, 0x04, 0x04, 0x04,
+ 0x00, 0xfd, 0xfd, 0xfd, 0x00, 0xfe, 0xfe, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xf0, 0xf0, 0xf0, 0xff, 0xc0, 0xc0, 0xc0,
+ 0xa2, 0x2e, 0x2e, 0x2e, 0x59, 0x01, 0x01, 0x01,
+ 0x05, 0xcb, 0xca, 0xc3, 0xfe, 0x1c, 0x1d, 0x22,
+ 0x03, 0xe5, 0xe2, 0xcc, 0x01, 0x2a, 0x3f, 0x10,
+ 0x15, 0xe6, 0xe5, 0xe0, 0x00, 0xfe, 0xfa, 0xec,
+ 0x1c, 0x37, 0x2c, 0x2a, 0x38, 0x14, 0x0e, 0x11,
+ 0x33, 0x04, 0x00, 0x01, 0xfe, 0x00, 0xf6, 0xf8,
+ 0x0c, 0x00, 0xcc, 0xd0, 0xec, 0x00, 0x02, 0x02,
+ 0x02, 0x00, 0x3d, 0x38, 0x19, 0x00, 0xd0, 0xd3,
+ 0xe8, 0x00, 0xee, 0xee, 0xf7, 0x00, 0x12, 0x0c,
+ 0xfe, 0x00, 0xe9, 0xe7, 0xab, 0x00, 0xe2, 0xdc,
+ 0xd1, 0x00, 0x2e, 0x36, 0x46, 0x00, 0x12, 0x12,
+ 0x13, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x00, 0xfd, 0xfd,
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04,
+ 0x04, 0x00, 0xe6, 0xe6, 0xe6, 0xe9, 0xcc, 0xcc,
+ 0xcc, 0x8b, 0xb3, 0xb2, 0xa9, 0x09, 0x27, 0x28,
+ 0x2d, 0x54, 0x1c, 0x16, 0xde, 0x03, 0xb2, 0xaf,
+ 0xb2, 0x00, 0xc1, 0xc3, 0xd6, 0x00, 0x40, 0x40,
+ 0x7b, 0x00, 0x82, 0x8a, 0xa7, 0x00, 0x01, 0xfd,
+ 0xf0, 0x00, 0x9e, 0x88, 0x35, 0x09, 0x26, 0x12,
+ 0x08, 0x69, 0x04, 0x01, 0x01, 0x06, 0x00, 0xfc,
+ 0xfc, 0x06, 0x00, 0x3e, 0x3d, 0x38, 0x00, 0xf2,
+ 0xf3, 0xf8, 0x00, 0xfb, 0xfd, 0xf0, 0x00, 0x1e,
+ 0x1c, 0x11, 0x00, 0x2e, 0x28, 0x02, 0x00, 0xe4,
+ 0xe4, 0xf9, 0x00, 0x23, 0x12, 0xe5, 0x00, 0xd9,
+ 0xd4, 0xe2, 0x00, 0x01, 0x00, 0x45, 0x00, 0xed,
+ 0xed, 0xed, 0xff, 0xc0, 0xc0, 0xc0, 0xd2, 0x05,
+ 0x05, 0x05, 0x0c, 0x22, 0x22, 0x22, 0x1a, 0x19,
+ 0x19, 0x19, 0x09, 0x15, 0x15, 0x15, 0x00, 0xfc,
+ 0xfc, 0xfc, 0x00, 0xfd, 0xfd, 0xfd, 0x00, 0x02,
+ 0x02, 0x02, 0x00, 0xe5, 0xe5, 0xe5, 0xe3, 0xc0,
+ 0xc0, 0xc0, 0xe9, 0x73, 0x69, 0x1f, 0xe6, 0xf4,
+ 0xef, 0xf5, 0x01, 0x08, 0x13, 0x0c, 0x00, 0x09,
+ 0x08, 0x0a, 0x00, 0xfc, 0xfd, 0x02, 0x00, 0x00,
+ 0x02, 0x0c, 0x00, 0xfd, 0xfe, 0x03, 0x00, 0x02,
+ 0x00, 0x03, 0x00, 0x00, 0x03, 0x03, 0x00, 0x06,
+ 0xfd, 0xe7, 0x06, 0x04, 0x00, 0x00, 0xfc, 0x00,
+ 0x10, 0x10, 0x04, 0x00, 0x01, 0x01, 0xf8, 0x00,
+ 0x11, 0x0f, 0x00, 0x00, 0xff, 0xfd, 0xfe, 0x00,
+ 0x13, 0x11, 0x06, 0x00, 0xfe, 0xfc, 0xfd, 0x00,
+ 0x1b, 0x18, 0x05, 0x00, 0xed, 0xe1, 0x07, 0x00,
+ 0xd9, 0xee, 0x16, 0x00, 0xf9, 0xca, 0xa4, 0x00,
+ 0xe4, 0xed, 0xdf, 0xc2, 0x64, 0x6c, 0xa2, 0x53,
+ 0x02, 0x02, 0x02, 0x08, 0x38, 0x38, 0x38, 0x1f,
+ 0x1f, 0x1f, 0x1f, 0x2c, 0x1c, 0x1c, 0x1c, 0x3b,
+ 0x2a, 0x2a, 0x2a, 0x3d, 0x22, 0x22, 0x22, 0x15,
+ 0x18, 0x18, 0x18, 0x08, 0xd1, 0xd1, 0xd1, 0xba,
+ 0x14, 0x10, 0x00, 0xff, 0x1c, 0x19, 0x09, 0x32,
+ 0x1f, 0x1e, 0xf4, 0x01, 0x00, 0x04, 0x0f, 0x00,
+ 0x1b, 0x1a, 0x3b, 0x00, 0x4e, 0x4d, 0x3c, 0x00,
+ 0x0e, 0x07, 0xfb, 0x00, 0x85, 0x7d, 0x4c, 0x00,
+ 0xfe, 0xfb, 0xe5, 0x00, 0xfe, 0xfa, 0xef, 0x00,
+ 0x04, 0xfd, 0xfc, 0x00, 0x04, 0xd6, 0xa9, 0xc9,
+ 0x00, 0x17, 0x2a, 0x22, 0x00, 0x09, 0x13, 0x14,
+ 0x00, 0x00, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0xf8,
+ 0x00, 0xff, 0xff, 0xf3, 0x00, 0x00, 0x00, 0xf2,
+ 0x00, 0xf7, 0xec, 0xf0, 0x00, 0xf1, 0xd1, 0xe6,
+ 0x00, 0x36, 0xf3, 0xd7, 0x00, 0x28, 0x26, 0x07,
+ 0x00, 0xd8, 0x0e, 0x1d, 0x1f, 0xfe, 0xfe, 0xfe,
+ 0xf0, 0xfe, 0xfe, 0xfe, 0x03, 0xc4, 0xc4, 0xc4,
+ 0xf1, 0xc4, 0xc4, 0xc4, 0xd6, 0x01, 0x01, 0x01,
+ 0xb0, 0xff, 0xff, 0xff, 0x01, 0x35, 0x35, 0x35,
+ 0x1e, 0x21, 0x21, 0x21, 0x1b, 0xd6, 0xd6, 0xd6,
+ 0xc9, 0x59, 0x52, 0x05, 0xf7, 0x13, 0x0a, 0x00,
+ 0x0c, 0x05, 0x01, 0xf5, 0x00, 0x01, 0x04, 0xf1,
+ 0x00, 0x18, 0x14, 0x04, 0x00, 0x03, 0x06, 0x0a,
+ 0x00, 0xfb, 0xf8, 0xe4, 0x00, 0x1a, 0x17, 0xf9,
+ 0x00, 0x01, 0xfa, 0xfd, 0x00, 0x01, 0xee, 0xf7,
+ 0x00, 0x01, 0xf9, 0xf9, 0x00, 0x04, 0xc3, 0xb8,
+ 0xea, 0x00, 0x1d, 0xc7, 0xfd, 0x00, 0x16, 0x06,
+ 0xe2, 0x00, 0x10, 0x0c, 0x0a, 0x00, 0x02, 0x04,
+ 0x02, 0x00, 0x01, 0x02, 0x06, 0x00, 0x01, 0x06,
+ 0x0c, 0x00, 0xe6, 0xf1, 0xfd, 0x00, 0xd7, 0xe2,
+ 0xf4, 0x00, 0x3e, 0x28, 0xe8, 0x00, 0x03, 0x01,
+ 0x04, 0x00, 0x02, 0x01, 0x02, 0x0d, 0x00, 0x00,
+ 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00,
+ 0x00, 0xfa, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff,
+ 0xff, 0x02, 0x00, 0x00, 0x00, 0x03, 0xcb, 0xcb,
+ 0xcb, 0xf3, 0xcb, 0xcb, 0xcb, 0xd4, 0x00, 0x00,
+ 0x00, 0xf9, 0x53, 0x44, 0x00, 0x01, 0x01, 0xfb,
+ 0xfd, 0xf4, 0x05, 0xf6, 0xf6, 0x00, 0xff, 0x03,
+ 0x01, 0x00, 0xe3, 0xe6, 0xed, 0x00, 0xac, 0xb3,
+ 0xe3, 0x00, 0xdd, 0xdf, 0xef, 0x00, 0x0d, 0x0a,
+ 0x00, 0x00, 0x47, 0x38, 0x0b, 0x00, 0x40, 0x21,
+ 0xfd, 0x00, 0x02, 0xfb, 0xfb, 0x00, 0x04, 0x4f,
+ 0x5c, 0x00, 0x00, 0xe2, 0x7c, 0xb2, 0x00, 0x02,
+ 0xd7, 0xed, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xf8,
+ 0x00, 0x00, 0x00, 0x04, 0x17, 0x08, 0x00, 0x45,
+ 0x60, 0x20, 0x00, 0x23, 0x3f, 0x11, 0x00, 0x00,
+ 0x03, 0x09, 0x00, 0xfc, 0xfc, 0xfd, 0xd9, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00,
+ 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x81, 0x90, 0x00, 0x00, 0x58,
+ 0x4e, 0x02, 0xcd, 0x17, 0x01, 0xf7, 0x3d, 0xf1,
+ 0xef, 0xf5, 0x01, 0x77, 0x86, 0xe1, 0x00, 0xd8,
+ 0xdd, 0xf9, 0x00, 0x06, 0x06, 0x05, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xc1, 0xc5, 0xec, 0x00, 0x82,
+ 0x59, 0x0a, 0x00, 0x4c, 0x30, 0x05, 0x00, 0x04,
+ 0x17, 0x2a, 0x0b, 0x00, 0x13, 0xb0, 0x4b, 0x00,
+ 0xf1, 0xda, 0xf1, 0x00, 0xf3, 0xc6, 0xe6, 0x00,
+ 0xfd, 0xf0, 0xf7, 0x00, 0x05, 0x05, 0x01, 0x00,
+ 0x15, 0x2e, 0x0f, 0x00, 0x13, 0x1e, 0x05, 0x00,
+ 0x06, 0xff, 0xf9, 0x00, 0x00, 0xfe, 0xfe, 0x00,
+ 0xff, 0x07, 0x15, 0x00, 0xeb, 0xee, 0xe8, 0xb7,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xce, 0xd3, 0xb6, 0x9e, 0x13, 0x30, 0x42, 0x55,
+ 0xf9, 0xed, 0xe2, 0x1c, 0xf6, 0xf5, 0x04, 0x00,
+ 0x13, 0x13, 0x0b, 0x00, 0x07, 0x07, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0xf9, 0xf9, 0x00,
+ 0xe8, 0xf2, 0x01, 0x00, 0xfa, 0x07, 0x0f, 0xfc,
+ 0x01, 0xfc, 0xc6, 0x48, 0xff, 0xfe, 0x06, 0x06,
+ 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0xfd, 0xfd, 0x00, 0x01, 0xfa, 0xfa,
+ 0x00, 0x02, 0xf8, 0xf7, 0x00, 0x02, 0xf9, 0xf9,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xea, 0x0c, 0x30, 0xf5, 0xb8, 0xce, 0xaa,
+ 0x2b, 0x5f, 0x70, 0xef, 0xe1, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0xa4, 0x91, 0x37,
+ 0x5d, 0x46, 0x2d, 0x28, 0x8b, 0xd1, 0xd9, 0xf4,
+ 0x12, 0xac, 0xc9, 0xff, 0x00, 0xf9, 0xfd, 0x06,
+ 0x00, 0x04, 0x03, 0x00, 0x00, 0x2b, 0x1c, 0x00,
+ 0x00, 0x59, 0x3c, 0xff, 0xfc, 0xdf, 0xf3, 0xfb,
+ 0xb5, 0x01, 0xff, 0xb8, 0x3a, 0xff, 0xff, 0x02,
+ 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe,
+ 0xfe, 0x00, 0x01, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x12,
+ 0x33, 0x00, 0xbd, 0xdb, 0xca, 0x89, 0x47, 0x5c,
+ 0xcb, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x16, 0x72, 0x66, 0x25, 0x42, 0x55, 0x45,
+ 0x2e, 0x63, 0x1b, 0x12, 0x13, 0x2d, 0xfe, 0xfe,
+ 0x0a, 0x06, 0x02, 0x02, 0xfd, 0xfe, 0xf6, 0xfa,
+ 0xef, 0xeb, 0xc3, 0xd3, 0xe7, 0xb2, 0x87, 0x94,
+ 0xbf, 0xa4, 0x01, 0xee, 0xc5, 0x6c, 0xfd, 0x11,
+ 0xf6, 0xd6, 0x02, 0x00, 0xfc, 0xf5, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x03, 0x00, 0xf7, 0x0f, 0x2f, 0x00, 0xba,
+ 0xd5, 0xd5, 0xb3, 0x50, 0x64, 0xc1, 0x65, 0x00,
+ 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x0d,
+ 0x0b, 0x00, 0x0f, 0x33, 0x30, 0x0e, 0x18, 0x2b,
+ 0x25, 0x0d, 0x18, 0xee, 0xf0, 0xfb, 0xf6, 0xc7,
+ 0xcc, 0xec, 0xe5, 0xe0, 0xe4, 0xfe, 0xf0, 0x00,
+ 0x00, 0x00, 0xf2, 0x03, 0xf5, 0xff, 0xdb, 0xf3,
+ 0x14, 0x24, 0x31, 0x2e, 0x13, 0x16, 0x2a, 0x0c,
+ 0x03, 0x02, 0x03, 0x01, 0x00, 0x02, 0x04, 0x00,
+ 0x00, 0x07, 0x12, 0x00, 0xfc, 0x0d, 0x29, 0xff,
+ 0xda, 0xfb, 0x10, 0xf4, 0x99, 0xb1, 0xb7, 0x95,
+ 0x6e, 0x7d, 0xd2, 0x95, 0xfe, 0xfe, 0x00, 0xfd,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfa,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf6,
+ 0xfa, 0xfb, 0x00, 0xef, 0xe0, 0xe3, 0xf9, 0xe4,
+ 0xcb, 0xd0, 0xf3, 0xd8, 0xd4, 0xd8, 0xf5, 0xdd,
+ 0xf0, 0xf2, 0xff, 0xe9, 0x00, 0x00, 0x00, 0xf1,
+ 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00,
+ 0x26, 0x09, 0x08, 0x00, 0x0e, 0x5a, 0x4f, 0x03,
+ 0x39, 0x33, 0x30, 0x38, 0x29, 0x14, 0x12, 0x12,
+ 0x14, 0xf3, 0xf4, 0xf5, 0xf2, 0xcd, 0xd1, 0xcb,
+ 0xdb, 0xb2, 0xba, 0xf3, 0xc8, 0xe4, 0xe8, 0x00,
+ 0xee, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00,
+ 0xf1, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00,
+ 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00,
+ 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e,
+ 0x0c, 0xa5, 0x36, 0x6f, 0x37, 0xa6, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/chat_icon_text.png.h b/src/images/chat_icon_text.png.h
new file mode 100644
index 0000000..ee1e6cc
--- /dev/null
+++ b/src/images/chat_icon_text.png.h
@@ -0,0 +1,537 @@
+/* chat_icon_text.png - 4267 bytes */
+ static const unsigned char chat_icon_text_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x0a,
+ 0x07, 0x15, 0x13, 0x11, 0xf4, 0x6c, 0x14, 0x01,
+ 0x00, 0x00, 0x10, 0x2b, 0x49, 0x44, 0x41, 0x54,
+ 0x58, 0x09, 0x01, 0x20, 0x10, 0xdf, 0xef, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x01, 0x01,
+ 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91,
+ 0xc1, 0x5a, 0x21, 0xa5, 0x2f, 0x49, 0x8b, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/close.xpm b/src/images/close.xpm
new file mode 100644
index 0000000..b98274a
--- /dev/null
+++ b/src/images/close.xpm
@@ -0,0 +1,20 @@
+/* XPM */
+static const char * close_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #000000",
+"+ c #FFB6AA",
+"@ c #FF2400",
+"# c #B00000",
+" ",
+" . . ",
+" .+. .+.",
+" .++. .+ at .",
+" . at +.+@. ",
+" .@@@. ",
+" .@@@. ",
+" .+ at .#@. ",
+" .+ at . .#@.",
+" . at . .#.",
+" . . ",
+" "};
diff --git a/src/images/close_hi.xpm b/src/images/close_hi.xpm
new file mode 100644
index 0000000..ca99fcf
--- /dev/null
+++ b/src/images/close_hi.xpm
@@ -0,0 +1,20 @@
+/* XPM */
+static const char * close_hi_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #FFFFFF",
+"+ c #FFB6AA",
+"@ c #FF2400",
+"# c #B00000",
+" ",
+" . . ",
+" .+. .+.",
+" .++. .+ at .",
+" . at +.+@. ",
+" .@@@. ",
+" .@@@. ",
+" .+ at .#@. ",
+" .+ at . .#@.",
+" . at . .#.",
+" . . ",
+" "};
diff --git a/src/images/closed_full_game.png.h b/src/images/closed_full_game.png.h
new file mode 100644
index 0000000..f86df73
--- /dev/null
+++ b/src/images/closed_full_game.png.h
@@ -0,0 +1,111 @@
+/* closed_full_game.png - 857 bytes */
+ static const unsigned char closed_full_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1b, 0x15, 0x3b, 0x23, 0xc4, 0x19, 0xbd, 0x6d,
+ 0x00, 0x00, 0x02, 0xd9, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x8d, 0x93, 0x4d, 0x68, 0x5c, 0x65,
+ 0x14, 0x86, 0x9f, 0xef, 0xbb, 0xf7, 0xce, 0x5f,
+ 0x32, 0x9d, 0xa4, 0x49, 0xcb, 0xf4, 0x66, 0x9a,
+ 0x50, 0x63, 0x85, 0x49, 0x63, 0xb5, 0x0b, 0x6d,
+ 0x88, 0xb4, 0xd8, 0xa8, 0x1b, 0x77, 0xe2, 0xa2,
+ 0x14, 0xed, 0xa6, 0x2b, 0x37, 0x52, 0x28, 0xf4,
+ 0x67, 0x21, 0x28, 0x08, 0x0a, 0x2e, 0x0a, 0xa2,
+ 0xb8, 0x72, 0xd3, 0x8d, 0x20, 0xdd, 0x08, 0xa5,
+ 0x88, 0x9b, 0x41, 0x8a, 0xa0, 0x48, 0x14, 0x44,
+ 0x1a, 0xd1, 0xa9, 0x58, 0x4a, 0x32, 0x93, 0x74,
+ 0x26, 0xce, 0xdc, 0xe9, 0xcc, 0xdc, 0xb9, 0xdf,
+ 0xfd, 0x7e, 0x5c, 0xc4, 0x14, 0x14, 0x15, 0x5f,
+ 0x38, 0xab, 0x73, 0x9e, 0x97, 0x03, 0xe7, 0x3d,
+ 0x82, 0x7f, 0xd1, 0x6f, 0xf5, 0x5f, 0x4e, 0x7a,
+ 0x7a, 0xf0, 0xa6, 0x97, 0x6c, 0xaf, 0x08, 0xab,
+ 0xc1, 0x68, 0x84, 0x23, 0x61, 0x6c, 0x6a, 0xd5,
+ 0x4e, 0xcc, 0x5e, 0x99, 0x99, 0x99, 0xf9, 0x0a,
+ 0xc0, 0xff, 0x3b, 0x58, 0x5b, 0x08, 0x8f, 0xcf,
+ 0x7d, 0x78, 0xed, 0xd3, 0x8c, 0x89, 0xe6, 0x3c,
+ 0xdd, 0x41, 0x38, 0x4d, 0xb7, 0xdb, 0x41, 0x2b,
+ 0x45, 0x65, 0x62, 0x2c, 0x6b, 0x7e, 0xef, 0x3c,
+ 0xa3, 0xdb, 0xf5, 0x5b, 0x80, 0x04, 0x10, 0x0f,
+ 0xc1, 0x6a, 0x28, 0x0a, 0x73, 0x87, 0xde, 0xa9,
+ 0xbc, 0x7c, 0xe6, 0x92, 0x5c, 0x5a, 0x94, 0x19,
+ 0x52, 0xd6, 0x1b, 0x0d, 0xea, 0x9b, 0x8a, 0x34,
+ 0x5b, 0x26, 0x35, 0x82, 0x60, 0xd4, 0x24, 0xa4,
+ 0xc1, 0xe2, 0xc1, 0x29, 0x28, 0x1f, 0xf9, 0x71,
+ 0xfa, 0xe8, 0xa9, 0xa3, 0x0f, 0x0d, 0xbe, 0x7e,
+ 0x61, 0xe9, 0xdd, 0xf9, 0x73, 0xaf, 0x5d, 0x49,
+ 0x8f, 0x3d, 0x49, 0xd4, 0xdb, 0xe6, 0xf0, 0xb1,
+ 0x93, 0x7c, 0xfe, 0xfd, 0x90, 0xad, 0xc8, 0x70,
+ 0xf1, 0x95, 0x27, 0x70, 0xce, 0xf2, 0xfa, 0xfb,
+ 0xdf, 0x91, 0x0b, 0x04, 0x97, 0x5f, 0xda, 0xcb,
+ 0xfd, 0xeb, 0x6f, 0xd1, 0xee, 0x6b, 0x2d, 0x77,
+ 0xd7, 0x2e, 0x3f, 0xfb, 0xfc, 0xa5, 0xbc, 0x27,
+ 0x51, 0xd1, 0x5d, 0x0e, 0x3d, 0xbe, 0x0c, 0x40,
+ 0x92, 0x3a, 0x86, 0xca, 0xe2, 0xec, 0x4e, 0xc5,
+ 0x23, 0x43, 0xa2, 0x2c, 0x00, 0xd9, 0xa7, 0x4f,
+ 0x93, 0x0e, 0x22, 0xdf, 0x07, 0x28, 0xce, 0x3f,
+ 0x76, 0xb1, 0x38, 0x35, 0x2d, 0x83, 0xa8, 0x4b,
+ 0xb0, 0x7f, 0x19, 0x63, 0x0c, 0x52, 0x4a, 0xa6,
+ 0x8a, 0x50, 0x6f, 0xa6, 0x9c, 0xff, 0xe0, 0x5b,
+ 0x12, 0xe5, 0x88, 0x86, 0x9a, 0x23, 0xb3, 0x05,
+ 0xac, 0xb5, 0xc8, 0xbd, 0x15, 0x26, 0x1f, 0x59,
+ 0x74, 0x5e, 0xad, 0x1a, 0x7a, 0xa5, 0xf9, 0xc3,
+ 0x1f, 0x4f, 0x14, 0x8b, 0x99, 0x7c, 0x3a, 0xc2,
+ 0xe4, 0xb3, 0x28, 0xd5, 0x46, 0xe3, 0x13, 0x4e,
+ 0x67, 0x69, 0xb6, 0x87, 0x6c, 0x6e, 0xc7, 0x28,
+ 0xa5, 0x38, 0x7b, 0x62, 0x8c, 0x13, 0xd5, 0x2c,
+ 0x6a, 0xd0, 0xa3, 0x7f, 0xfd, 0x0d, 0x9a, 0x23,
+ 0xff, 0x1b, 0x51, 0x5b, 0x08, 0xc3, 0xf2, 0x53,
+ 0x4b, 0x1b, 0xe1, 0x81, 0x90, 0xa2, 0xef, 0x21,
+ 0xf3, 0x79, 0xd6, 0x8f, 0x3f, 0x4a, 0xde, 0x17,
+ 0x30, 0x5e, 0x41, 0x94, 0x66, 0xc1, 0x0b, 0x00,
+ 0x70, 0xd6, 0x61, 0xbb, 0x1b, 0x98, 0xe6, 0x0f,
+ 0xdc, 0x5e, 0xfb, 0x15, 0xf1, 0xc9, 0x67, 0xe3,
+ 0x3e, 0xe0, 0xe2, 0xfa, 0xcf, 0x68, 0xad, 0x60,
+ 0x72, 0x12, 0x54, 0x81, 0xb8, 0x93, 0xe1, 0x9e,
+ 0x89, 0x28, 0xcb, 0x55, 0xc6, 0x27, 0xef, 0x61,
+ 0x83, 0x02, 0xce, 0x81, 0xe9, 0xb5, 0x60, 0xeb,
+ 0x0e, 0x77, 0x5b, 0x0f, 0x28, 0xdd, 0x5c, 0xa5,
+ 0xaf, 0xb4, 0x15, 0xb5, 0x6a, 0x28, 0x73, 0x52,
+ 0x74, 0x2a, 0x19, 0x6f, 0x4f, 0x39, 0x9f, 0x23,
+ 0xd8, 0xb7, 0x1f, 0xf6, 0x94, 0x20, 0x93, 0x03,
+ 0xe9, 0xed, 0x9c, 0xc8, 0x1a, 0x50, 0x23, 0xe8,
+ 0x75, 0x49, 0xee, 0xb7, 0xd8, 0x8a, 0x47, 0x6c,
+ 0xa4, 0x66, 0x7d, 0xf9, 0xf6, 0xc6, 0x41, 0x7f,
+ 0xe5, 0xa7, 0x86, 0xbd, 0xb5, 0x10, 0xde, 0x1c,
+ 0x1a, 0x77, 0x26, 0x56, 0x0a, 0x7f, 0xbb, 0x8d,
+ 0x18, 0xc5, 0xe0, 0x07, 0x20, 0xe5, 0x9f, 0x06,
+ 0x16, 0x52, 0x85, 0x1b, 0x0c, 0x88, 0x95, 0x62,
+ 0x60, 0x1d, 0xa9, 0x73, 0x37, 0xd8, 0x4d, 0x93,
+ 0x86, 0xf7, 0x22, 0x63, 0x4d, 0x57, 0x5b, 0xe2,
+ 0x24, 0xc1, 0x0d, 0xfa, 0x30, 0x1a, 0x42, 0x12,
+ 0xc3, 0x28, 0x86, 0x78, 0x88, 0x1b, 0x0c, 0x18,
+ 0x2a, 0x45, 0x64, 0x2c, 0x3d, 0x63, 0x13, 0x03,
+ 0x57, 0x01, 0x3c, 0x80, 0x6b, 0xad, 0x07, 0x9b,
+ 0xaf, 0xee, 0x2b, 0xa6, 0xda, 0xf1, 0x9c, 0x00,
+ 0x84, 0xb1, 0xc8, 0x34, 0x05, 0x95, 0xe2, 0x94,
+ 0x22, 0x4d, 0x12, 0xfa, 0xa9, 0xa6, 0xa3, 0x2d,
+ 0x2d, 0x6d, 0x18, 0x3a, 0x77, 0x7e, 0x65, 0xad,
+ 0xf1, 0xc5, 0x5f, 0xa2, 0x0c, 0xf0, 0xe5, 0x42,
+ 0x78, 0x39, 0x27, 0xc4, 0xdb, 0x25, 0x4f, 0x06,
+ 0x05, 0x29, 0x08, 0xc4, 0x4e, 0x3b, 0x75, 0x8e,
+ 0x81, 0x75, 0xf4, 0x8c, 0x4d, 0x62, 0xe7, 0x2e,
+ 0x9c, 0x5a, 0x6b, 0x7c, 0xb4, 0xcb, 0x88, 0x7f,
+ 0x78, 0xa6, 0x05, 0x0f, 0x2e, 0x04, 0x42, 0xbc,
+ 0xe8, 0xc1, 0x01, 0x07, 0x58, 0x58, 0x4f, 0x9d,
+ 0xbb, 0x61, 0xe0, 0xea, 0xca, 0x5a, 0xe3, 0x0e,
+ 0xff, 0x57, 0xb5, 0x6a, 0x58, 0xa8, 0x55, 0xc3,
+ 0xfc, 0x7f, 0xcd, 0xfc, 0x01, 0xcb, 0xd2, 0x67,
+ 0x2c, 0xb2, 0x82, 0x6b, 0x22, 0x00, 0x00, 0x00,
+ 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
+ 0x82};
+/* End Of File */
diff --git a/src/images/closed_full_pw_game.png.h b/src/images/closed_full_pw_game.png.h
new file mode 100644
index 0000000..6646f8f
--- /dev/null
+++ b/src/images/closed_full_pw_game.png.h
@@ -0,0 +1,115 @@
+/* closed_full_pw_game.png - 892 bytes */
+ static const unsigned char closed_full_pw_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1b, 0x11, 0x29, 0x0f, 0x89, 0x3c, 0x09, 0x81,
+ 0x00, 0x00, 0x02, 0xfc, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x75, 0x93, 0x4f, 0x68, 0x5c, 0x55,
+ 0x14, 0xc6, 0x7f, 0xf7, 0xcd, 0x7b, 0xf3, 0x32,
+ 0xff, 0xf2, 0x77, 0x2c, 0xe3, 0x64, 0x92, 0x10,
+ 0xd3, 0x0a, 0x69, 0x62, 0x6a, 0x85, 0x98, 0x10,
+ 0x49, 0x69, 0x8b, 0x45, 0x77, 0x22, 0x2e, 0x44,
+ 0xc4, 0x8d, 0x2b, 0x37, 0xa5, 0x50, 0x68, 0xed,
+ 0xa2, 0xa0, 0x2b, 0x5d, 0x59, 0x10, 0xc5, 0x95,
+ 0x9b, 0xba, 0x10, 0xa4, 0x20, 0xc5, 0x2a, 0x2e,
+ 0x84, 0x2c, 0x44, 0x54, 0x24, 0x6a, 0x8b, 0x34,
+ 0xa0, 0xd3, 0x62, 0x89, 0x99, 0x99, 0x24, 0x33,
+ 0xd3, 0xcc, 0x4c, 0xe6, 0xbd, 0x37, 0xef, 0xbe,
+ 0x77, 0xef, 0x75, 0x51, 0x33, 0xa2, 0xd0, 0x03,
+ 0x67, 0xf9, 0xfd, 0xce, 0x77, 0x0e, 0xdf, 0x11,
+ 0x3c, 0xa4, 0xfe, 0x2c, 0xff, 0x71, 0x22, 0x11,
+ 0x7b, 0x6f, 0x25, 0xc2, 0xe6, 0x69, 0xa1, 0x63,
+ 0x50, 0x31, 0xc2, 0x10, 0x92, 0x19, 0x5b, 0xd7,
+ 0xc3, 0x93, 0x97, 0xc6, 0xc7, 0xc7, 0xbf, 0x03,
+ 0xb0, 0xff, 0x2f, 0x5c, 0x3b, 0x5a, 0x5c, 0x9a,
+ 0xfa, 0xf0, 0xea, 0x67, 0x49, 0xd5, 0x9e, 0x4a,
+ 0xc4, 0x7b, 0x08, 0x13, 0xd3, 0x6a, 0xed, 0x11,
+ 0x4b, 0x49, 0x69, 0x38, 0xe3, 0xaa, 0xfb, 0x7b,
+ 0xcf, 0xc4, 0x8d, 0xf2, 0xb7, 0x80, 0x05, 0x20,
+ 0xfa, 0xc2, 0xd9, 0xa2, 0x48, 0x4f, 0x4d, 0xbf,
+ 0x53, 0x7a, 0xe9, 0x95, 0x8b, 0xd6, 0xf2, 0xbc,
+ 0x95, 0x24, 0x62, 0xab, 0x5a, 0xa5, 0xbc, 0x2d,
+ 0x89, 0xdc, 0x02, 0x91, 0x12, 0x38, 0xbd, 0x1a,
+ 0x45, 0xaa, 0xcc, 0x4f, 0x8c, 0x41, 0x61, 0xee,
+ 0xb7, 0xfc, 0xc2, 0xa9, 0x85, 0x3e, 0xe0, 0x87,
+ 0x33, 0xcb, 0xef, 0xce, 0xbc, 0xfe, 0xc6, 0xa5,
+ 0xe8, 0xf8, 0x93, 0xb4, 0x3b, 0x4d, 0x8e, 0x1c,
+ 0x3f, 0xc1, 0xd7, 0xbf, 0xf8, 0xec, 0xb4, 0x15,
+ 0x17, 0x5e, 0x3d, 0x86, 0x31, 0x9a, 0xb3, 0xef,
+ 0xff, 0xcc, 0x80, 0x23, 0x78, 0xf3, 0xc5, 0x51,
+ 0x76, 0xaf, 0xbd, 0x4d, 0xa3, 0x1b, 0xc7, 0xd6,
+ 0x81, 0xed, 0xc2, 0xc9, 0x67, 0x2f, 0xa6, 0x12,
+ 0x16, 0xb2, 0x7d, 0x8f, 0xe9, 0x27, 0x56, 0x00,
+ 0x08, 0x23, 0x83, 0x2f, 0x35, 0x46, 0x3f, 0xe8,
+ 0xa0, 0xa7, 0x08, 0xa5, 0x06, 0xc0, 0x7d, 0xfa,
+ 0x65, 0x22, 0xaf, 0x6d, 0xdb, 0x00, 0xb9, 0x99,
+ 0xc7, 0x2f, 0xe4, 0xc6, 0xf2, 0x96, 0xd3, 0x6e,
+ 0xe1, 0x1c, 0x5a, 0x41, 0x29, 0x85, 0x65, 0x59,
+ 0x8c, 0xe5, 0xa0, 0x5c, 0x8b, 0x38, 0xf7, 0xc1,
+ 0x4f, 0x84, 0xd2, 0xd0, 0xf6, 0x63, 0xe6, 0x26,
+ 0xd3, 0x68, 0xad, 0xb1, 0x46, 0x4b, 0x8c, 0x3c,
+ 0x36, 0x6f, 0x12, 0x6b, 0xb3, 0xc5, 0xc4, 0xd0,
+ 0xcc, 0x91, 0x8f, 0x87, 0x73, 0xb9, 0x64, 0x2a,
+ 0xea, 0xa1, 0x52, 0x2e, 0x52, 0x36, 0x88, 0xb1,
+ 0x29, 0xe6, 0x5d, 0x6a, 0x0d, 0x9f, 0xed, 0x66,
+ 0x80, 0x94, 0x92, 0xd7, 0x56, 0x33, 0xac, 0xce,
+ 0xba, 0x48, 0xaf, 0x43, 0xf7, 0xda, 0x65, 0x6a,
+ 0x3d, 0xfb, 0x47, 0xb1, 0x76, 0xb4, 0x58, 0x2c,
+ 0x2c, 0x2e, 0x57, 0x8a, 0x8f, 0x16, 0xc9, 0xd9,
+ 0x09, 0xac, 0x54, 0x8a, 0xad, 0xa5, 0xc3, 0xa4,
+ 0x6c, 0x01, 0xd9, 0x12, 0x62, 0x68, 0x12, 0x12,
+ 0x0e, 0x00, 0x46, 0x1b, 0x74, 0xab, 0x82, 0xaa,
+ 0xdd, 0xe2, 0xf6, 0xc6, 0x5d, 0xc4, 0xa7, 0xd7,
+ 0xb3, 0xf6, 0xe0, 0x92, 0x57, 0x8a, 0xfd, 0x5f,
+ 0xf1, 0xd4, 0x26, 0x32, 0xeb, 0x20, 0x93, 0x9a,
+ 0xa6, 0x57, 0xc0, 0x0b, 0x2c, 0x0a, 0xd6, 0x3a,
+ 0xd9, 0x91, 0x4d, 0xb4, 0x93, 0xc6, 0x18, 0x50,
+ 0x9d, 0x3a, 0xec, 0xdc, 0xe1, 0x5e, 0x7d, 0x9f,
+ 0xa1, 0xaf, 0xd6, 0xe9, 0xca, 0x58, 0x8b, 0xf0,
+ 0xfa, 0xa2, 0x0c, 0xb4, 0xed, 0x7c, 0xf2, 0xcd,
+ 0x2e, 0xcf, 0x2d, 0x8e, 0x30, 0x9a, 0x75, 0x88,
+ 0x94, 0x66, 0xdf, 0x57, 0x6c, 0xfe, 0xb5, 0xcf,
+ 0xea, 0xd6, 0x2c, 0xae, 0x49, 0x80, 0xec, 0x41,
+ 0xa7, 0x45, 0xb8, 0x5b, 0x67, 0x27, 0xe8, 0x51,
+ 0x89, 0xd4, 0xd6, 0xca, 0xed, 0xca, 0x84, 0x9d,
+ 0x4c, 0xa5, 0x9c, 0x9b, 0xbf, 0x77, 0xb8, 0xf2,
+ 0x79, 0x85, 0x46, 0x27, 0xe2, 0xec, 0x0b, 0xe3,
+ 0x00, 0x08, 0x01, 0x18, 0x0d, 0xbb, 0x55, 0x50,
+ 0x16, 0x44, 0x12, 0xe3, 0x79, 0x04, 0x52, 0xe2,
+ 0x69, 0x43, 0x64, 0xcc, 0x8d, 0x7e, 0x12, 0x27,
+ 0x1e, 0x71, 0x19, 0xc9, 0xd9, 0x9c, 0x3c, 0x36,
+ 0xfc, 0x9f, 0x54, 0x0a, 0x01, 0xf4, 0x02, 0x88,
+ 0x05, 0x26, 0x0c, 0xf1, 0xa5, 0xa4, 0xad, 0x34,
+ 0x1d, 0xa5, 0x43, 0x05, 0x57, 0xfa, 0x80, 0xfc,
+ 0xa0, 0xc3, 0xdc, 0x54, 0x9a, 0xa7, 0x0e, 0x67,
+ 0x89, 0x62, 0xf3, 0x8f, 0x58, 0x80, 0x31, 0xe8,
+ 0x6e, 0x97, 0x30, 0x16, 0x04, 0x4a, 0xd3, 0x56,
+ 0x9a, 0x7a, 0xac, 0x08, 0x8c, 0x39, 0x7f, 0x7a,
+ 0xa3, 0x7a, 0xa7, 0x0f, 0xf0, 0x43, 0x4d, 0xb9,
+ 0x12, 0x50, 0x6b, 0x4a, 0xf2, 0x43, 0x0f, 0x2e,
+ 0x2e, 0x00, 0x23, 0xa0, 0x1e, 0xc6, 0xa0, 0x04,
+ 0x9e, 0x36, 0x74, 0x94, 0x0e, 0x03, 0x63, 0xce,
+ 0x9f, 0xda, 0xa8, 0x7e, 0x74, 0xe0, 0xd2, 0x56,
+ 0x71, 0xa4, 0x95, 0xc6, 0x5a, 0x98, 0xce, 0x50,
+ 0xbd, 0x1f, 0xfe, 0x0b, 0x10, 0xa0, 0x8d, 0xe1,
+ 0xa6, 0x1f, 0x32, 0x60, 0x12, 0x55, 0x5b, 0xf0,
+ 0x85, 0x10, 0xe2, 0xbd, 0x83, 0xc9, 0xfd, 0x35,
+ 0xbf, 0xbf, 0x9c, 0x79, 0x3e, 0x9d, 0x1b, 0x3c,
+ 0xe3, 0x0e, 0xb8, 0xf3, 0xc6, 0xb2, 0x0f, 0x69,
+ 0x23, 0x72, 0x06, 0x72, 0x7e, 0xa0, 0xf6, 0x36,
+ 0x6b, 0xde, 0xad, 0x2f, 0x6f, 0xb4, 0xcf, 0x5d,
+ 0xbd, 0xdb, 0xdb, 0x7e, 0xd8, 0xdb, 0xff, 0x0d,
+ 0xbb, 0x2b, 0x7b, 0x4e, 0x0d, 0xe0, 0x70, 0x92,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+ 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/closed_game.png.h b/src/images/closed_game.png.h
new file mode 100644
index 0000000..4339d3e
--- /dev/null
+++ b/src/images/closed_game.png.h
@@ -0,0 +1,99 @@
+/* closed_game.png - 763 bytes */
+ static const unsigned char closed_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x14, 0x10, 0x05, 0x03, 0xe0, 0x1a, 0x54, 0x65,
+ 0x00, 0x00, 0x02, 0x7b, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x8d, 0x93, 0x3b, 0x68, 0x54, 0x51,
+ 0x10, 0x86, 0xbf, 0x73, 0x1f, 0x9b, 0x64, 0x71,
+ 0x37, 0x6e, 0x8c, 0x8f, 0xbd, 0x28, 0x22, 0xa2,
+ 0x71, 0x57, 0x41, 0xac, 0x52, 0x58, 0x88, 0x6b,
+ 0x21, 0x58, 0x68, 0x61, 0x25, 0xd8, 0x08, 0x82,
+ 0x76, 0x42, 0x40, 0xb1, 0xb1, 0x12, 0x0c, 0x58,
+ 0x58, 0x5a, 0x89, 0x60, 0x2d, 0x82, 0x20, 0x16,
+ 0x36, 0x2b, 0x08, 0x62, 0xab, 0x82, 0x1b, 0xc4,
+ 0x48, 0x50, 0xf4, 0x6a, 0x5c, 0x35, 0x9b, 0x4d,
+ 0xee, 0xeb, 0x3c, 0x2d, 0xb2, 0x51, 0xd0, 0x28,
+ 0x0e, 0x4c, 0x75, 0xe6, 0xff, 0xcf, 0xcc, 0xfc,
+ 0xff, 0x08, 0xfe, 0x12, 0xed, 0x46, 0xe4, 0x23,
+ 0xd8, 0x0c, 0x38, 0x1c, 0xf3, 0xad, 0x99, 0xd8,
+ 0xae, 0x55, 0x27, 0xfe, 0x00, 0x36, 0xa3, 0xc9,
+ 0xb1, 0xc9, 0x83, 0x17, 0x2b, 0x7b, 0xf6, 0x1d,
+ 0x1d, 0xde, 0x52, 0x5f, 0x07, 0x50, 0xcc, 0x7f,
+ 0xee, 0x2f, 0xbd, 0xee, 0x3c, 0xfc, 0xf6, 0xec,
+ 0xc9, 0xf5, 0x56, 0x27, 0x7e, 0xbe, 0x26, 0x41,
+ 0xbb, 0x11, 0x89, 0xf2, 0xf6, 0x1d, 0xd7, 0xb6,
+ 0x9e, 0x3c, 0x75, 0xa9, 0xb6, 0x6f, 0xbf, 0xe7,
+ 0x8b, 0x5f, 0x8f, 0x16, 0xb0, 0x0e, 0x16, 0x5e,
+ 0xbd, 0x30, 0x1f, 0xef, 0xdf, 0xbd, 0x92, 0xbc,
+ 0x7d, 0x33, 0xdd, 0x9a, 0x89, 0x01, 0xf0, 0x57,
+ 0x09, 0xce, 0x1f, 0xd8, 0x3b, 0xbd, 0xf3, 0xcc,
+ 0xb9, 0xcb, 0xa3, 0xf5, 0xba, 0x28, 0xa9, 0x82,
+ 0x40, 0x49, 0x7c, 0xb9, 0x9a, 0x05, 0x42, 0xe6,
+ 0x94, 0xaa, 0xa3, 0x5e, 0x79, 0xd7, 0xc4, 0x91,
+ 0xe4, 0xdd, 0x5c, 0x7e, 0x6b, 0xf6, 0xfd, 0xd3,
+ 0x9f, 0x04, 0xed, 0x66, 0x34, 0xb9, 0xed, 0xf8,
+ 0xc9, 0xdb, 0xa3, 0xe3, 0xe3, 0x62, 0x48, 0x4a,
+ 0x02, 0xad, 0x10, 0x46, 0x21, 0xb4, 0x46, 0x68,
+ 0x85, 0x50, 0x05, 0x7e, 0x91, 0x23, 0xf2, 0x1c,
+ 0x21, 0x40, 0x54, 0xaa, 0x87, 0x4e, 0x7c, 0x9a,
+ 0xbd, 0x77, 0xa7, 0xbb, 0xd4, 0x0d, 0x00, 0x2a,
+ 0x3b, 0x77, 0x5f, 0xac, 0x6c, 0x18, 0xf7, 0xc2,
+ 0xc5, 0x1e, 0x41, 0xe0, 0x43, 0xa9, 0x04, 0xc2,
+ 0x03, 0x31, 0x18, 0xc2, 0x39, 0xb0, 0x86, 0x40,
+ 0x29, 0x42, 0xad, 0xa9, 0x8c, 0x6d, 0x08, 0xab,
+ 0x13, 0xcd, 0x29, 0x3a, 0xf1, 0xd9, 0xa0, 0xdd,
+ 0x88, 0xfc, 0xe1, 0xda, 0xd8, 0x51, 0xbf, 0xf7,
+ 0x9d, 0x20, 0xf0, 0x60, 0x68, 0x08, 0xc2, 0xd2,
+ 0x00, 0xbc, 0xba, 0x05, 0x07, 0xd6, 0x82, 0x56,
+ 0xf8, 0x45, 0x81, 0xaf, 0x2d, 0x43, 0xeb, 0x6b,
+ 0xc7, 0x00, 0x02, 0x04, 0x9b, 0x7d, 0xc1, 0x3a,
+ 0xd1, 0xfb, 0x8e, 0x08, 0x7c, 0x18, 0x19, 0x81,
+ 0x30, 0x5c, 0x43, 0x20, 0x07, 0x4a, 0xe2, 0x65,
+ 0x39, 0x42, 0x69, 0x3c, 0x63, 0xea, 0x8f, 0x1b,
+ 0x51, 0x39, 0x00, 0x5c, 0xf6, 0xe6, 0x35, 0x5a,
+ 0x4b, 0xa8, 0xd5, 0x40, 0x96, 0x07, 0x1d, 0x78,
+ 0xbf, 0xe1, 0x2d, 0x28, 0x09, 0x69, 0x8a, 0x5e,
+ 0x58, 0x20, 0x9b, 0x9b, 0x03, 0x70, 0x01, 0x8e,
+ 0xf9, 0x62, 0xb1, 0xd7, 0x4f, 0x3b, 0x2f, 0xab,
+ 0xd5, 0x91, 0x61, 0xbc, 0x8d, 0x9b, 0xa0, 0x3a,
+ 0x0a, 0xa5, 0x61, 0xf0, 0x06, 0x22, 0x59, 0x03,
+ 0x32, 0x87, 0x7e, 0x0f, 0xf5, 0xa5, 0x4b, 0x9a,
+ 0xe5, 0x48, 0x65, 0x3e, 0x1c, 0x9e, 0x89, 0xb3,
+ 0xa0, 0x35, 0x13, 0xdb, 0x27, 0xcd, 0xe8, 0x61,
+ 0x6a, 0xdc, 0xa9, 0x4c, 0x4a, 0x82, 0x6f, 0x5f,
+ 0x11, 0x79, 0x06, 0x41, 0x08, 0xde, 0xa0, 0x0b,
+ 0xbb, 0xf2, 0xbb, 0x4b, 0x12, 0x32, 0x29, 0x49,
+ 0xac, 0x43, 0x39, 0xf7, 0x00, 0xc0, 0x03, 0xd0,
+ 0x70, 0x7d, 0xd1, 0x58, 0xd3, 0xd3, 0x96, 0xac,
+ 0x28, 0x70, 0xc9, 0x32, 0xe4, 0x29, 0x14, 0x19,
+ 0xe4, 0x19, 0x64, 0x29, 0x2e, 0x49, 0x48, 0xa5,
+ 0x64, 0xd1, 0x58, 0xfa, 0xc6, 0x16, 0x06, 0x6e,
+ 0xfc, 0xf4, 0xc1, 0x9d, 0xee, 0xd2, 0xe7, 0xd3,
+ 0x1b, 0x2b, 0x4a, 0x3b, 0x8e, 0x08, 0x40, 0x18,
+ 0x8b, 0xa7, 0x14, 0x48, 0x85, 0x93, 0x12, 0x55,
+ 0x14, 0x2c, 0x2b, 0xcd, 0x82, 0xb6, 0x74, 0xb5,
+ 0x21, 0x75, 0xee, 0x42, 0xab, 0x13, 0x3f, 0x5a,
+ 0x51, 0x61, 0xd5, 0xae, 0x8e, 0xe9, 0x65, 0x6b,
+ 0xad, 0x56, 0xee, 0x6a, 0x6a, 0x5d, 0x58, 0x36,
+ 0x96, 0x70, 0xe0, 0x03, 0xe5, 0x1c, 0x89, 0x75,
+ 0xf4, 0x8d, 0x2d, 0x32, 0xe7, 0xa6, 0x0e, 0x77,
+ 0xe2, 0x9b, 0xff, 0x3a, 0xa6, 0xa6, 0x0f, 0x53,
+ 0xa1, 0x10, 0xc7, 0x7c, 0xa8, 0xbb, 0x95, 0x5b,
+ 0xf8, 0xa0, 0x9c, 0x7b, 0x60, 0xe0, 0x46, 0xab,
+ 0x13, 0xcf, 0xf2, 0xbf, 0xd1, 0x6e, 0x44, 0xe5,
+ 0x76, 0x23, 0x1a, 0xf9, 0x57, 0xcd, 0x0f, 0x2e,
+ 0xd8, 0x41, 0xd3, 0xab, 0xee, 0x1b, 0x77, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/closed_pw_game.png.h b/src/images/closed_pw_game.png.h
new file mode 100644
index 0000000..aba82d8
--- /dev/null
+++ b/src/images/closed_pw_game.png.h
@@ -0,0 +1,107 @@
+/* closed_pw_game.png - 825 bytes */
+ static const unsigned char closed_pw_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1b, 0x11, 0x28, 0x1c, 0x14, 0x99, 0x79, 0x1e,
+ 0x00, 0x00, 0x02, 0xb9, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x75, 0x93, 0x4d, 0x68, 0x5c, 0x55,
+ 0x14, 0xc7, 0x7f, 0xe7, 0xbd, 0xfb, 0x66, 0x92,
+ 0xe9, 0xbc, 0x49, 0x27, 0x1d, 0xad, 0x19, 0x5b,
+ 0x4a, 0xa9, 0xb6, 0x4e, 0x1a, 0x2d, 0x0a, 0x32,
+ 0xa0, 0x0b, 0x6d, 0x44, 0x22, 0x2e, 0xcc, 0xa2,
+ 0xdd, 0xb8, 0x14, 0x0a, 0x75, 0x23, 0x42, 0xa0,
+ 0xe2, 0xa2, 0xdd, 0x5a, 0x10, 0xec, 0xd2, 0x95,
+ 0x08, 0x75, 0x2b, 0x8a, 0xd8, 0xba, 0x12, 0x22,
+ 0x8a, 0x1f, 0x4b, 0xd3, 0x85, 0x53, 0x8a, 0x91,
+ 0x42, 0x68, 0x5e, 0xda, 0x4c, 0x9b, 0x4c, 0x26,
+ 0x9d, 0xf7, 0x75, 0xdf, 0xbd, 0xd7, 0x45, 0x32,
+ 0x53, 0xc4, 0xf4, 0xc2, 0x81, 0x0b, 0xf7, 0xfc,
+ 0x7f, 0xe7, 0x9e, 0x73, 0xff, 0x57, 0x78, 0xcc,
+ 0x5a, 0x6c, 0x35, 0x7d, 0x84, 0x83, 0x80, 0xc3,
+ 0x71, 0x6f, 0xf6, 0x66, 0x64, 0xf7, 0xca, 0x93,
+ 0xff, 0x09, 0xa7, 0x9b, 0xed, 0xc9, 0xf6, 0xab,
+ 0x17, 0xc2, 0xe7, 0x66, 0xe6, 0xc6, 0x9e, 0x9a,
+ 0xaa, 0x02, 0x64, 0xf7, 0xee, 0xf6, 0xb7, 0x6f,
+ 0x75, 0x7e, 0x78, 0xf0, 0xc7, 0x2f, 0x9f, 0xce,
+ 0x76, 0xa2, 0xa5, 0x3d, 0x01, 0x8b, 0xad, 0xa6,
+ 0x54, 0x8e, 0x1c, 0xfd, 0xe4, 0xd0, 0x99, 0x77,
+ 0x3f, 0xaa, 0xcf, 0x9c, 0xf2, 0x7c, 0x79, 0x74,
+ 0x68, 0x01, 0xeb, 0x60, 0xf3, 0xaf, 0x1b, 0x66,
+ 0xf5, 0xbb, 0xaf, 0x2f, 0xb5, 0xaf, 0xff, 0x7c,
+ 0x79, 0xa8, 0xf3, 0x87, 0x9b, 0xf7, 0x5f, 0x3c,
+ 0x79, 0xf9, 0xd8, 0x7b, 0xe7, 0x3f, 0x9e, 0x98,
+ 0x9a, 0x92, 0x92, 0xce, 0x50, 0x3a, 0xc7, 0xcf,
+ 0x87, 0x91, 0x21, 0x79, 0x4a, 0xa9, 0x36, 0xe1,
+ 0x55, 0x9e, 0x3d, 0xf1, 0xc6, 0xd9, 0xf8, 0x7e,
+ 0xfa, 0xc5, 0xf2, 0xca, 0x6f, 0x23, 0xc0, 0xe2,
+ 0x74, 0xb3, 0x7d, 0xf8, 0x9d, 0x33, 0x5f, 0x4e,
+ 0x34, 0x1a, 0x52, 0xce, 0x73, 0x54, 0xa1, 0x11,
+ 0xa3, 0x91, 0xa2, 0x40, 0x0a, 0x8d, 0xe8, 0x0c,
+ 0x3f, 0x4b, 0x91, 0x34, 0x45, 0x04, 0x24, 0xac,
+ 0xbd, 0x36, 0xbf, 0xb6, 0xfc, 0xcd, 0xd5, 0xee,
+ 0x76, 0x57, 0x01, 0x84, 0xc7, 0x8e, 0x5f, 0x08,
+ 0x0f, 0x34, 0xbc, 0x60, 0xab, 0x87, 0x52, 0x3e,
+ 0x94, 0x4a, 0x20, 0x1e, 0xc8, 0x6e, 0x13, 0xce,
+ 0x81, 0x35, 0x28, 0xad, 0x09, 0x8a, 0x82, 0x70,
+ 0xf2, 0x40, 0x50, 0x3b, 0x31, 0xbd, 0x40, 0x27,
+ 0x3a, 0xa7, 0x16, 0x5b, 0x4d, 0x7f, 0xac, 0x3e,
+ 0x39, 0xe7, 0xf7, 0x36, 0x50, 0xca, 0x83, 0x72,
+ 0x19, 0x82, 0xd2, 0xae, 0x78, 0x38, 0x05, 0x07,
+ 0xd6, 0x42, 0xa1, 0xf1, 0xb3, 0x0c, 0xbf, 0xb0,
+ 0x94, 0xf7, 0xd7, 0xdf, 0x06, 0x50, 0x08, 0x07,
+ 0x7d, 0xa1, 0x2a, 0xbd, 0x0d, 0x44, 0xf9, 0x30,
+ 0x3e, 0x0e, 0x41, 0xb0, 0xc7, 0x03, 0x39, 0xd0,
+ 0x39, 0x5e, 0x92, 0x22, 0xba, 0xc0, 0x33, 0x66,
+ 0xea, 0xa7, 0x56, 0xb3, 0xa2, 0x6a, 0xed, 0xc1,
+ 0xa1, 0x22, 0xfe, 0x93, 0x81, 0x59, 0x21, 0xaf,
+ 0x06, 0xe4, 0x25, 0x4b, 0xa6, 0x34, 0x71, 0x6a,
+ 0xd9, 0xee, 0x09, 0x2f, 0xab, 0x57, 0x50, 0xa2,
+ 0xc0, 0x59, 0xd0, 0x39, 0xc4, 0x31, 0xc5, 0xe6,
+ 0x26, 0xc9, 0xed, 0xdb, 0x00, 0x4e, 0x3d, 0x3f,
+ 0x7f, 0xfc, 0xd7, 0xc4, 0x2a, 0xbe, 0xfa, 0x71,
+ 0x9d, 0xb9, 0x56, 0x9d, 0xc9, 0x6a, 0x80, 0x67,
+ 0x02, 0x8a, 0xd8, 0x30, 0xc8, 0xb6, 0x31, 0x77,
+ 0x56, 0x51, 0xce, 0x87, 0x3c, 0x85, 0x7e, 0x0f,
+ 0xbd, 0xde, 0x25, 0x4e, 0x52, 0x72, 0x6d, 0xee,
+ 0x9c, 0xbe, 0x19, 0x25, 0xaa, 0x34, 0x3e, 0x1e,
+ 0x2c, 0xdd, 0xea, 0x73, 0xe5, 0xdb, 0x55, 0xee,
+ 0xf7, 0x35, 0x1f, 0xcc, 0x3f, 0xbd, 0x63, 0x10,
+ 0x61, 0xa7, 0xea, 0x7a, 0x04, 0xc6, 0x03, 0x9d,
+ 0xe3, 0x06, 0x03, 0x92, 0x3c, 0x67, 0x60, 0x1d,
+ 0xda, 0xb9, 0x6b, 0x3b, 0x33, 0x00, 0x0e, 0x3f,
+ 0x51, 0xa6, 0x1e, 0x2a, 0x5e, 0x3f, 0xb5, 0xff,
+ 0xbf, 0x36, 0x15, 0x20, 0x4d, 0xa0, 0x10, 0x5c,
+ 0x96, 0x11, 0xe7, 0x39, 0x5b, 0xc6, 0xd2, 0x37,
+ 0x36, 0x33, 0x70, 0x65, 0x04, 0x68, 0xd4, 0x02,
+ 0x4e, 0x1e, 0xa9, 0xf0, 0xd2, 0x33, 0x55, 0x74,
+ 0xe1, 0x76, 0xc5, 0x02, 0xce, 0x61, 0x1f, 0x3e,
+ 0x24, 0x2b, 0x84, 0xc4, 0x58, 0xb6, 0x8c, 0xa5,
+ 0x5b, 0x18, 0x12, 0xe7, 0x16, 0x66, 0x3b, 0xd1,
+ 0xf2, 0x08, 0x10, 0x67, 0x96, 0xbf, 0x57, 0x13,
+ 0xd6, 0x1e, 0xe4, 0x34, 0x26, 0x82, 0x91, 0xc7,
+ 0x9d, 0x40, 0x37, 0x2b, 0xc0, 0x08, 0x03, 0xeb,
+ 0xe8, 0x1b, 0x9b, 0x25, 0xce, 0x2d, 0x9c, 0xee,
+ 0x44, 0x9f, 0x0f, 0x6f, 0xa9, 0x4c, 0xa1, 0xad,
+ 0xb1, 0x78, 0x2f, 0x1c, 0xdd, 0x47, 0xb4, 0x91,
+ 0x3d, 0x02, 0x08, 0x58, 0xe7, 0x58, 0x8a, 0x33,
+ 0xc6, 0x9c, 0x1f, 0x29, 0xe1, 0x7b, 0x11, 0xf9,
+ 0x6c, 0x58, 0x79, 0xd4, 0xe6, 0xef, 0x17, 0xf7,
+ 0xbd, 0x55, 0x09, 0x6b, 0x6f, 0x96, 0xc7, 0xca,
+ 0x33, 0xce, 0x53, 0x4f, 0x5a, 0x27, 0xa1, 0x83,
+ 0x30, 0x4e, 0xcc, 0xe6, 0xca, 0xda, 0xe0, 0xc6,
+ 0xf5, 0x6b, 0x5b, 0x1f, 0x5e, 0xfd, 0x27, 0xbd,
+ 0xfb, 0xb8, 0x6f, 0xff, 0x2f, 0x52, 0x03, 0x45,
+ 0xd6, 0x27, 0x20, 0x8c, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
+ 0x82};
+/* End Of File */
diff --git a/src/images/colourbox.xpm b/src/images/colourbox.xpm
new file mode 100644
index 0000000..d5afa6b
--- /dev/null
+++ b/src/images/colourbox.xpm
@@ -0,0 +1,23 @@
+/* XPM */
+static const char * colourbox_xpm[] = {
+"16 16 4 1",
+" c None",
+". c #000000",
+"+ c #020202",
+"@ c #010101",
+" ",
+" ",
+" .......... ",
+" .++++++++++. ",
+" .+@@@@@@@@+. ",
+" .+@@@@@@@@+. ",
+" .+@@@@@@@@+. ",
+" .+@@@@@@@@+. ",
+" .+@@@@@@@@+. ",
+" .+@@@@@@@@+. ",
+" .+@@@@@@@@+. ",
+" .+@@@@@@@@+. ",
+" .++++++++++. ",
+" .......... ",
+" ",
+" "};
diff --git a/src/images/connect.xpm b/src/images/connect.xpm
new file mode 100644
index 0000000..d4a2503
--- /dev/null
+++ b/src/images/connect.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static const char * connect_xpm[] = {
+"16 16 7 1",
+" c None",
+". c #000000",
+"+ c #FFFAB4",
+"@ c #FFFAB7",
+"# c #FFF435",
+"$ c #5E5A13",
+"% c #9F9821",
+" ",
+" ",
+" ",
+" . .. ",
+" .+. ..@@.",
+" .+#. .@@#$.",
+" .+##..@##$. ",
+" .+###@@##$. ",
+" .+##$$###$. ",
+" .+#%$..##$. ",
+".+#$$. .#$. ",
+".#$.. .$. ",
+" .. . ",
+" ",
+" ",
+" "};
diff --git a/src/images/down.xpm b/src/images/down.xpm
new file mode 100644
index 0000000..b14aec8
--- /dev/null
+++ b/src/images/down.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+static const char * down_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+"....... ",
+" ..... ",
+" ... ",
+" . ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/src/images/download_map.xpm b/src/images/download_map.xpm
new file mode 100644
index 0000000..3e3a0f9
--- /dev/null
+++ b/src/images/download_map.xpm
@@ -0,0 +1,249 @@
+/* XPM */
+static const char * download_map_xpm[] = {
+"22 22 224 2",
+" c None",
+". c #91DE53",
+"+ c #6CCE1E",
+"@ c #61C312",
+"# c #6CCD1E",
+"$ c #90DD53",
+"% c #72D025",
+"& c #50A908",
+"* c #459207",
+"= c #469307",
+"- c #489707",
+"; c #50A808",
+"> c #71CE25",
+", c #A4DF75",
+"' c #56B609",
+") c #479508",
+"! c #50A508",
+"~ c #59A618",
+"{ c #8CB967",
+"] c #8EBA6A",
+"^ c #8FBA6A",
+"/ c #8CB966",
+"( c #59A617",
+"_ c #55B409",
+": c #A3DD75",
+"< c #A7DE7B",
+"[ c #53AE09",
+"} c #4D9D08",
+"| c #59B00A",
+"1 c #59B10A",
+"2 c #62AA24",
+"3 c #E6E9E3",
+"4 c #EEEEEE",
+"5 c #E5E8E2",
+"6 c #62AA22",
+"7 c #5AB10A",
+"8 c #52AD09",
+"9 c #A6DC7B",
+"0 c #58B80B",
+"a c #4FA009",
+"b c #5DB30B",
+"c c #64AB24",
+"d c #64AB23",
+"e c #5DB40B",
+"f c #4F9F09",
+"g c #57B50A",
+"h c #79CD35",
+"i c #4DA008",
+"j c #60B50C",
+"k c #60B60C",
+"l c #66AD25",
+"m c #66AD24",
+"n c #61B60C",
+"o c #4D9F08",
+"p c #76C935",
+"q c #55B309",
+"r c #5AAD0B",
+"s c #64B80D",
+"t c #69AE25",
+"u c #68AE24",
+"v c #65B80D",
+"w c #5BAD0B",
+"x c #54B009",
+"y c #9DD670",
+"z c #51A909",
+"A c #66B90D",
+"B c #67BA0D",
+"C c #68BA0E",
+"D c #69BB0F",
+"E c #6CB028",
+"F c #69BB10",
+"G c #68BB0E",
+"H c #51A809",
+"I c #9CD370",
+"J c #7ECB41",
+"K c #55AA0A",
+"L c #6BBC0E",
+"M c #65B50E",
+"N c #67B01A",
+"O c #69B11D",
+"P c #6BB221",
+"Q c #71AE36",
+"R c #71AE35",
+"S c #6CB322",
+"T c #6AB11E",
+"U c #66B50E",
+"V c #6CBD0F",
+"W c #7CC641",
+"X c #71C32E",
+"Y c #59AF0B",
+"Z c #6EBF0F",
+"` c #6DBC10",
+" . c #85B557",
+".. c #DBE3D5",
+"+. c #DDE4D8",
+"@. c #DEE4D9",
+"#. c #EDEDEC",
+"$. c #DEE4D8",
+"%. c #DAE2D4",
+"&. c #84B554",
+"*. c #6FBD11",
+"=. c #6FBF10",
+"-. c #6FBF2D",
+";. c #73C233",
+">. c #5BB20B",
+",. c #73C111",
+"'. c #77C319",
+"). c #75BC22",
+"!. c #B2CC9B",
+"~. c #AECA95",
+"{. c #78BE24",
+"]. c #79C41B",
+"^. c #74C212",
+"/. c #71BD32",
+"(. c #84C74E",
+"_. c #5AB40B",
+":. c #79C517",
+"<. c #80C823",
+"[. c #86CA2D",
+"}. c #7EBA39",
+"|. c #D3DECA",
+"1. c #CFDCC4",
+"2. c #7FBB39",
+"3. c #88CB30",
+"4. c #82C825",
+"5. c #7BC61A",
+"6. c #82C24E",
+"7. c #ABD489",
+"8. c #56B409",
+"9. c #7BC61C",
+"0. c #88CC2C",
+"a. c #8ECF37",
+"b. c #92D040",
+"c. c #8CBB5A",
+"d. c #E8EAE5",
+"e. c #89BB55",
+"f. c #95D143",
+"g. c #90CF3A",
+"h. c #8ACD2E",
+"i. c #7CC71E",
+"j. c #56B209",
+"k. c #AAD189",
+"l. c #56B20B",
+"m. c #6EC217",
+"n. c #8FD034",
+"o. c #96D240",
+"p. c #9CD54C",
+"q. c #99D04F",
+"r. c #A5C587",
+"s. c #EEEEED",
+"t. c #9FC37D",
+"u. c #9CD252",
+"v. c #9ED64E",
+"w. c #98D343",
+"x. c #91D137",
+"y. c #6FC218",
+"z. c #54AE0B",
+"A. c #8DC560",
+"B. c #5BBA0B",
+"C. c #8CD033",
+"D. c #9DD649",
+"E. c #A3D955",
+"F. c #A9DB5F",
+"G. c #98CA58",
+"H. c #C5D6B7",
+"I. c #BDD2AA",
+"J. c #9CCD5C",
+"K. c #ABDC62",
+"L. c #A5D957",
+"M. c #9FD74C",
+"N. c #8ED036",
+"O. c #5AB80B",
+"P. c #8BC15F",
+"Q. c #60B21E",
+"R. c #66C313",
+"S. c #9ED74A",
+"T. c #AADC5D",
+"U. c #B0DF69",
+"V. c #B5E073",
+"W. c #96C364",
+"X. c #DFE5DA",
+"Y. c #D8E1D1",
+"Z. c #98C563",
+"`. c #B7E175",
+" + c #B2DF6B",
+".+ c #ACDD60",
+"++ c #9FD84D",
+"@+ c #5EAD1D",
+"#+ c #59AE13",
+"$+ c #67C615",
+"%+ c #9FDA52",
+"&+ c #B6E271",
+"*+ c #BDE47D",
+"=+ c #BCE281",
+"-+ c #A0C37C",
+";+ c #9CC274",
+">+ c #BFE485",
+",+ c #BEE57F",
+"'+ c #B8E274",
+")+ c #A0DB54",
+"!+ c #57AB13",
+"~+ c #61AE22",
+"{+ c #5CBD0C",
+"]+ c #82D432",
+"^+ c #A9E065",
+"/+ c #C4E88C",
+"(+ c #B8DC85",
+"_+ c #BEE08B",
+":+ c #C5E88D",
+"<+ c #AAE067",
+"[+ c #82D433",
+"}+ c #5BBC0C",
+"|+ c #60AB22",
+"1+ c #97C373",
+"2+ c #56A912",
+"3+ c #57B60A",
+"4+ c #63C411",
+"5+ c #6DCC1B",
+"6+ c #55A712",
+"7+ c #96C173",
+"8+ c #A9C295",
+"9+ c #83AF61",
+"0+ c #74A84B",
+"a+ c #A8C194",
+" ",
+" . + @ @ # $ ",
+" % & * = - - = * ; > ",
+" , ' ) ! ~ { ] ^ / ( ! ) _ : ",
+" < [ } | 1 2 3 4 4 5 6 7 | } 8 9 ",
+" 0 a b b b c 3 4 4 5 d e e e f g ",
+" h i j k k k l 3 4 4 5 m n n n j o p ",
+" q r s s s s t 3 4 4 5 u s s s v w x ",
+" y z A B B C D E 3 4 4 5 E F G C C A H I ",
+" J K L M N O P Q 3 4 4 5 R S T N U V K W ",
+" X Y Z ` ...+. at .#.4 4 #.$.+.%.&.*.=.Y -. ",
+" ;.>.,.'.).!.4 4 4 4 4 4 4 4 ~.{.].^.>./. ",
+" (._.:.<.[.}.|.4 4 4 4 4 4 1.2.3.4.5._.6. ",
+" 7.8.9.0.a.b.c.d.4 4 4 4 5 e.f.g.h.i.j.k. ",
+" l.m.n.o.p.q.r.s.4 4 #.t.u.v.w.x.y.z. ",
+" A.B.C.D.E.F.G.H.4 4 I.J.K.L.M.N.O.P. ",
+" Q.R.S.T.U.V.W.X.Y.Z.`. +.+++R. at + ",
+" #+$+%+&+*+=+-+;+>+,+'+)+$+!+ ",
+" ~+{+]+^+/+(+_+:+<+[+}+|+ ",
+" 1+2+3+4+5+5+4+g 6+7+ ",
+" 8+9+0+0+9+a+ ",
+" "};
diff --git a/src/images/downloads_icon.png.h b/src/images/downloads_icon.png.h
new file mode 100644
index 0000000..5a42687
--- /dev/null
+++ b/src/images/downloads_icon.png.h
@@ -0,0 +1,296 @@
+/* downloads_icon.png - 2343 bytes */
+ static const unsigned char downloads_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x0a,
+ 0x06, 0x16, 0x03, 0x2d, 0x2b, 0x3b, 0xa3, 0xeb,
+ 0x00, 0x00, 0x08, 0xa7, 0x49, 0x44, 0x41, 0x54,
+ 0x58, 0x47, 0xed, 0x57, 0x6d, 0x4c, 0x5b, 0xd7,
+ 0x19, 0x7e, 0xee, 0xbd, 0xf6, 0xbd, 0x36, 0x60,
+ 0x63, 0x9b, 0x0f, 0x87, 0x94, 0xe0, 0x40, 0xd2,
+ 0xa5, 0x01, 0x92, 0xb5, 0xa3, 0x24, 0x40, 0xb6,
+ 0xa6, 0xea, 0xa2, 0x08, 0x65, 0xe9, 0x94, 0x49,
+ 0x5d, 0x93, 0xa9, 0xf9, 0xd8, 0x47, 0x14, 0x58,
+ 0xbb, 0xa6, 0xaa, 0x96, 0x55, 0x99, 0xb4, 0xfe,
+ 0x59, 0xa4, 0x75, 0xd3, 0xd4, 0x2e, 0x6a, 0xd3,
+ 0x86, 0xee, 0x4f, 0xb4, 0xfd, 0x98, 0xd6, 0x25,
+ 0x8d, 0xa6, 0x69, 0x91, 0xd6, 0x68, 0x5a, 0x51,
+ 0x43, 0x80, 0x42, 0x21, 0x84, 0x04, 0x02, 0x18,
+ 0x82, 0xc1, 0x80, 0xc1, 0x18, 0x7f, 0x81, 0xed,
+ 0x6b, 0xfb, 0xfa, 0xde, 0xbd, 0xe7, 0x06, 0xbc,
+ 0x92, 0x90, 0xf6, 0xe7, 0xfe, 0xf4, 0x95, 0x5e,
+ 0x9f, 0x8f, 0x7b, 0xce, 0xfb, 0x3e, 0xe7, 0x39,
+ 0xef, 0x79, 0xcf, 0x31, 0xf0, 0x95, 0xfc, 0x9f,
+ 0x19, 0xe0, 0xbe, 0xc8, 0xff, 0xfa, 0x9a, 0x13,
+ 0x7c, 0xca, 0xc4, 0x6f, 0xa7, 0x31, 0x4f, 0x00,
+ 0x5c, 0x7b, 0xe0, 0xfa, 0xf9, 0x61, 0x36, 0xbe,
+ 0xbe, 0xfe, 0x45, 0x33, 0xc0, 0xd7, 0x72, 0x1c,
+ 0x36, 0x69, 0x1a, 0x72, 0xa8, 0x6b, 0x9e, 0xb4,
+ 0xbf, 0xa3, 0xe3, 0xdc, 0xd0, 0x17, 0xd9, 0x5b,
+ 0xeb, 0xdb, 0x2a, 0x00, 0xd6, 0xfa, 0x9f, 0x18,
+ 0x44, 0x41, 0xac, 0x81, 0xa6, 0x3d, 0x45, 0x83,
+ 0x99, 0xee, 0x22, 0xbd, 0x4b, 0x8e, 0x9e, 0x9f,
+ 0x6f, 0x6b, 0xb9, 0x5b, 0x5f, 0xff, 0x33, 0x17,
+ 0xb5, 0x5f, 0xaf, 0xae, 0xde, 0x78, 0xc8, 0xe5,
+ 0x5a, 0x97, 0x5b, 0x56, 0x56, 0x0c, 0x9e, 0xe7,
+ 0x30, 0xe3, 0x0b, 0x62, 0xfc, 0xae, 0x0f, 0x23,
+ 0x23, 0x5e, 0x77, 0x3c, 0x9e, 0x3c, 0x2b, 0x49,
+ 0x86, 0x3f, 0xb6, 0xb6, 0x9e, 0x55, 0xdc, 0x6f,
+ 0x3c, 0x6a, 0x28, 0x70, 0x58, 0xe1, 0x68, 0xea,
+ 0x51, 0xd6, 0x72, 0xce, 0xfa, 0xb8, 0xc2, 0x5d,
+ 0x4d, 0x15, 0x54, 0xfc, 0x60, 0xd9, 0x61, 0x03,
+ 0x95, 0xb9, 0xa4, 0x2a, 0x69, 0x9a, 0xb4, 0x9b,
+ 0xe7, 0xf1, 0xac, 0xff, 0x5a, 0x4b, 0x84, 0x9c,
+ 0xff, 0x70, 0xeb, 0xd6, 0xb2, 0x73, 0xc7, 0x8f,
+ 0xef, 0xcb, 0xcd, 0x2f, 0x71, 0xc2, 0x96, 0xc3,
+ 0xa1, 0xa4, 0xc8, 0x81, 0xf9, 0xc0, 0x02, 0x3e,
+ 0x1d, 0x8b, 0x21, 0x99, 0x48, 0x22, 0x1d, 0x5b,
+ 0xc4, 0x48, 0xef, 0x20, 0x5a, 0x3f, 0xbe, 0xd1,
+ 0x23, 0xcb, 0xe9, 0xe7, 0x3b, 0x7e, 0x39, 0x37,
+ 0xee, 0x71, 0xdf, 0xb1, 0x1b, 0x04, 0xf0, 0xa5,
+ 0x25, 0x45, 0x0b, 0xdc, 0xa1, 0x8f, 0xb5, 0xfb,
+ 0x81, 0x70, 0x8c, 0xe6, 0xa4, 0x89, 0x3f, 0x40,
+ 0x54, 0xfc, 0x82, 0x3e, 0x7e, 0x63, 0xd9, 0x71,
+ 0x8a, 0xca, 0x39, 0x0e, 0xda, 0x33, 0xf3, 0xd7,
+ 0xdf, 0xf7, 0x91, 0xf3, 0xd7, 0x0f, 0x1e, 0x7c,
+ 0xfa, 0xd7, 0xdf, 0x3d, 0x50, 0x87, 0x89, 0xb9,
+ 0x30, 0x4c, 0x46, 0x01, 0x2e, 0x57, 0x19, 0x66,
+ 0xa6, 0xbd, 0x08, 0xc5, 0x55, 0x64, 0x04, 0x13,
+ 0x32, 0x9c, 0x88, 0x0d, 0x56, 0x05, 0x56, 0x93,
+ 0x88, 0xe1, 0xe1, 0x49, 0x9c, 0x7f, 0xf7, 0x1f,
+ 0xfe, 0xb9, 0xb9, 0xc8, 0x33, 0xed, 0x27, 0x07,
+ 0x07, 0xbd, 0xbe, 0xf9, 0x0a, 0x55, 0x55, 0x8d,
+ 0x82, 0x39, 0x7f, 0x64, 0xc3, 0x4b, 0x1d, 0x6c,
+ 0x71, 0x59, 0x59, 0xb5, 0x05, 0x45, 0xbb, 0x9a,
+ 0x7f, 0x43, 0x10, 0x8f, 0x31, 0x10, 0x54, 0x9e,
+ 0x5a, 0xb8, 0xde, 0x72, 0x89, 0x9c, 0x3f, 0xd7,
+ 0xd8, 0x58, 0x7b, 0xb1, 0xa9, 0x79, 0x1f, 0xee,
+ 0x86, 0x34, 0x6c, 0x5d, 0x67, 0xc2, 0x5c, 0x34,
+ 0x0d, 0x5e, 0x94, 0xa0, 0x71, 0x06, 0xc8, 0xc9,
+ 0x0c, 0x62, 0xf1, 0x38, 0x96, 0xc2, 0x01, 0x70,
+ 0x4a, 0x1c, 0x5b, 0x37, 0xb9, 0x20, 0x19, 0x34,
+ 0x4c, 0x4c, 0xcc, 0xe2, 0xf4, 0xe9, 0x0b, 0xe3,
+ 0x89, 0x44, 0xfa, 0xf1, 0xcb, 0x87, 0x5a, 0xe5,
+ 0x78, 0x4a, 0xab, 0x27, 0x67, 0x8b, 0x1b, 0x7f,
+ 0x7e, 0xbb, 0xf7, 0xf3, 0x00, 0xf8, 0xcf, 0x37,
+ 0xc8, 0xe9, 0x26, 0x6a, 0x47, 0x49, 0x07, 0xcd,
+ 0xaa, 0xf9, 0x72, 0x5d, 0xdd, 0x8b, 0x39, 0x25,
+ 0x25, 0x8e, 0x77, 0x5e, 0x7b, 0xed, 0x20, 0x8a,
+ 0x8b, 0x0a, 0x50, 0x53, 0x61, 0x43, 0x24, 0x1a,
+ 0x45, 0x8c, 0xa8, 0x36, 0x99, 0x73, 0x21, 0x1a,
+ 0x8d, 0x10, 0x0c, 0x3c, 0x14, 0x25, 0x83, 0x2a,
+ 0x97, 0x03, 0xdf, 0x6e, 0x78, 0x02, 0xeb, 0x9d,
+ 0x0e, 0x18, 0x0c, 0x06, 0x14, 0x14, 0xe4, 0xe1,
+ 0x85, 0x17, 0x9e, 0x2a, 0x57, 0x55, 0xed, 0x57,
+ 0xce, 0x97, 0x6f, 0xa5, 0x34, 0x8d, 0x9b, 0xa1,
+ 0xd8, 0xda, 0xe2, 0x79, 0x6b, 0x1b, 0x6d, 0xf9,
+ 0xff, 0x24, 0x0b, 0xc0, 0xbe, 0xe7, 0x84, 0x81,
+ 0xba, 0x59, 0x90, 0x31, 0x00, 0x1f, 0x4e, 0x75,
+ 0xfc, 0x41, 0xe5, 0x38, 0xfe, 0xf0, 0xe1, 0xc3,
+ 0x7b, 0xd6, 0x49, 0x92, 0xa8, 0xcf, 0xf0, 0x4c,
+ 0xce, 0x20, 0x10, 0xe7, 0x50, 0x50, 0xe2, 0x82,
+ 0xca, 0x76, 0x93, 0xa2, 0x93, 0x7e, 0x50, 0xe2,
+ 0xc8, 0xc1, 0x84, 0x2f, 0x80, 0x8f, 0xda, 0x6e,
+ 0xe2, 0x8e, 0xdb, 0x03, 0x41, 0x10, 0xc8, 0x97,
+ 0x86, 0xba, 0xba, 0x2d, 0x70, 0x3a, 0xf3, 0x9a,
+ 0x77, 0xee, 0xfc, 0x69, 0x1e, 0x27, 0x18, 0xc6,
+ 0x69, 0xa8, 0x89, 0xba, 0x9f, 0xf2, 0xfe, 0x76,
+ 0x43, 0xd6, 0x6f, 0xb6, 0x22, 0x24, 0xf8, 0x75,
+ 0x64, 0x4d, 0x26, 0x8d, 0xd0, 0xe4, 0x6e, 0xe6,
+ 0x50, 0x10, 0xf8, 0xe7, 0xf6, 0xee, 0x7d, 0x92,
+ 0x55, 0x31, 0x39, 0x33, 0x87, 0xa0, 0x9a, 0x87,
+ 0x02, 0xe7, 0x7a, 0x32, 0x4e, 0x1d, 0xa4, 0x99,
+ 0x8c, 0x06, 0x85, 0x34, 0xba, 0x14, 0x47, 0xa9,
+ 0xb3, 0x10, 0x05, 0x0e, 0x1b, 0x06, 0xa7, 0xe3,
+ 0xf8, 0xe7, 0x27, 0x7d, 0xfa, 0x9c, 0x44, 0x22,
+ 0x81, 0x9d, 0x3b, 0xb7, 0x58, 0x78, 0x5e, 0x68,
+ 0x2c, 0x7f, 0xf5, 0x86, 0xa2, 0x81, 0x5b, 0xa0,
+ 0xb8, 0x2a, 0xcd, 0x18, 0xad, 0x5f, 0xd3, 0x07,
+ 0x90, 0xb0, 0x55, 0xeb, 0xc2, 0x81, 0x23, 0x74,
+ 0x5a, 0x84, 0x2a, 0x69, 0x5e, 0xe5, 0x26, 0x6a,
+ 0x6a, 0x4e, 0x70, 0x74, 0xdc, 0x1a, 0x66, 0x03,
+ 0x21, 0xb4, 0x0f, 0xcd, 0xc3, 0x61, 0xb7, 0xc1,
+ 0x5e, 0x64, 0x43, 0x22, 0xad, 0x42, 0x34, 0x70,
+ 0x20, 0x6a, 0x91, 0x4c, 0x29, 0x50, 0xd2, 0x49,
+ 0x54, 0x95, 0xd9, 0x21, 0x89, 0x46, 0x94, 0x96,
+ 0x00, 0x4f, 0x56, 0xd2, 0xfe, 0x0d, 0x8d, 0x22,
+ 0x10, 0x8a, 0xa2, 0xe7, 0xd6, 0x28, 0xf2, 0xac,
+ 0x46, 0x66, 0x9e, 0x9d, 0xae, 0x4b, 0xb4, 0xda,
+ 0x00, 0xf9, 0xb0, 0x12, 0x73, 0x5f, 0xa7, 0xb6,
+ 0x9e, 0x33, 0xb2, 0x0c, 0x68, 0x9c, 0x2a, 0x93,
+ 0x73, 0x46, 0x7f, 0x24, 0x6d, 0x32, 0xc5, 0x44,
+ 0xd1, 0x68, 0x37, 0x9b, 0xc5, 0x5c, 0x55, 0xe3,
+ 0x50, 0x6c, 0xcf, 0x43, 0x02, 0x66, 0x5a, 0xa9,
+ 0x0c, 0x7f, 0x28, 0x81, 0x60, 0x44, 0xa6, 0x7a,
+ 0x12, 0x8b, 0xf1, 0x24, 0x04, 0x2d, 0xa5, 0x3b,
+ 0x5f, 0x11, 0x45, 0x51, 0x50, 0x48, 0x67, 0xbf,
+ 0xdf, 0xed, 0xc5, 0x86, 0x22, 0x0b, 0xa6, 0xe6,
+ 0x18, 0xa9, 0x28, 0x65, 0x3f, 0x14, 0xfe, 0x31,
+ 0x8d, 0xe3, 0x2c, 0xc4, 0xe0, 0x63, 0x2b, 0xe3,
+ 0xb3, 0x0c, 0xa4, 0x32, 0xc2, 0x82, 0xc8, 0x67,
+ 0x88, 0x01, 0x2e, 0x6d, 0x82, 0xc6, 0xfa, 0xb5,
+ 0x70, 0x38, 0x86, 0xf6, 0x5b, 0xd3, 0x28, 0xb2,
+ 0x19, 0x61, 0x16, 0x79, 0x38, 0xe9, 0xec, 0xfb,
+ 0xc2, 0x71, 0x84, 0x20, 0xd2, 0x0e, 0x68, 0x50,
+ 0x15, 0x15, 0x12, 0xe2, 0xd8, 0x5e, 0x5e, 0x48,
+ 0xd8, 0xef, 0x89, 0x2c, 0xcb, 0x48, 0x26, 0x93,
+ 0x28, 0x73, 0xda, 0xf1, 0xf7, 0xd6, 0x01, 0x98,
+ 0x32, 0xd2, 0xb2, 0x6f, 0xc6, 0x32, 0x04, 0x6a,
+ 0x58, 0xa8, 0x92, 0xf5, 0x9b, 0x65, 0x20, 0xda,
+ 0xf1, 0x5e, 0x82, 0x86, 0x8c, 0xd2, 0x06, 0x47,
+ 0xd2, 0x29, 0xd9, 0xd6, 0xd1, 0xf1, 0x6e, 0x28,
+ 0x14, 0x5a, 0x8a, 0xaa, 0x74, 0xbe, 0x6f, 0xcc,
+ 0x0a, 0x28, 0xb2, 0x8a, 0x78, 0xbc, 0xa2, 0x10,
+ 0xb5, 0xe5, 0x79, 0x88, 0x45, 0x42, 0x58, 0x20,
+ 0x20, 0x7e, 0x02, 0xe8, 0xf6, 0xa7, 0x70, 0xe1,
+ 0x4a, 0x2f, 0xce, 0x5d, 0x6a, 0xc7, 0x2d, 0xf7,
+ 0x14, 0x9d, 0x90, 0x98, 0xae, 0x92, 0xa0, 0x62,
+ 0x72, 0x2e, 0x82, 0x4c, 0x52, 0x67, 0x60, 0x92,
+ 0xfd, 0x10, 0x00, 0x3b, 0x15, 0x56, 0xd2, 0x7c,
+ 0xd6, 0x66, 0x92, 0x05, 0xc0, 0x1a, 0x9c, 0xc6,
+ 0xd1, 0x19, 0xe5, 0xa2, 0x1c, 0xc7, 0x39, 0x59,
+ 0xdb, 0xef, 0x0f, 0xb7, 0x29, 0x91, 0x30, 0x22,
+ 0x44, 0x7d, 0x85, 0x33, 0x4f, 0x9f, 0x50, 0x68,
+ 0xb7, 0xe0, 0x40, 0x5d, 0x29, 0xca, 0xac, 0x69,
+ 0x04, 0xa3, 0x09, 0x84, 0x16, 0x65, 0x0c, 0xcd,
+ 0xab, 0xb8, 0xe3, 0x07, 0x7a, 0xdd, 0xb3, 0x88,
+ 0xd2, 0x31, 0x5d, 0x5a, 0x5a, 0xc2, 0xb5, 0xde,
+ 0x51, 0x28, 0x94, 0x54, 0x23, 0x81, 0x08, 0x9b,
+ 0xd6, 0xc6, 0x7e, 0x28, 0x6e, 0x19, 0xf5, 0x0c,
+ 0x40, 0x36, 0x19, 0xad, 0x02, 0x40, 0xd1, 0xd7,
+ 0x4b, 0x30, 0x83, 0x34, 0xe0, 0x11, 0x7d, 0x82,
+ 0xa6, 0x7d, 0x30, 0xda, 0x3f, 0xac, 0xaf, 0xa2,
+ 0x67, 0x78, 0x46, 0xa7, 0x96, 0xed, 0xb1, 0x89,
+ 0x8e, 0xa5, 0x51, 0x25, 0xe7, 0xd1, 0x38, 0xc2,
+ 0x8b, 0x71, 0x44, 0x08, 0x44, 0x24, 0x26, 0x63,
+ 0x78, 0x32, 0x80, 0x48, 0x24, 0xa2, 0x83, 0x60,
+ 0xf1, 0xf2, 0x48, 0x8e, 0x00, 0xaf, 0xd7, 0x1f,
+ 0xd2, 0x34, 0xc3, 0x55, 0x66, 0x8f, 0xe4, 0x5b,
+ 0xa4, 0x0c, 0xc0, 0xec, 0x72, 0x7b, 0x35, 0x03,
+ 0xe1, 0xb6, 0xf7, 0x97, 0x88, 0xa6, 0xcf, 0xc8,
+ 0xb5, 0xd1, 0xf9, 0xcd, 0xa6, 0x02, 0x40, 0xf9,
+ 0xa0, 0xbb, 0x7b, 0x68, 0xa2, 0x84, 0x8b, 0xe1,
+ 0xaf, 0xd7, 0xa7, 0xd1, 0x7d, 0x7b, 0x0c, 0xc1,
+ 0x60, 0x50, 0xd7, 0x91, 0xa9, 0xa8, 0x0e, 0x20,
+ 0xa4, 0xb3, 0x90, 0xd0, 0x1d, 0xca, 0x09, 0x02,
+ 0x42, 0x00, 0x66, 0x67, 0xfd, 0xf0, 0x4c, 0x85,
+ 0xa1, 0x86, 0xa3, 0xa0, 0xcb, 0xe9, 0xed, 0xce,
+ 0xce, 0xb3, 0xf2, 0xf8, 0x9b, 0xdb, 0x58, 0x9a,
+ 0xaf, 0x26, 0xb5, 0x90, 0xf6, 0xaf, 0x09, 0x80,
+ 0x75, 0xe6, 0x5b, 0x8c, 0x83, 0x14, 0xa5, 0x5e,
+ 0x45, 0xe3, 0x5c, 0x3e, 0x49, 0x4e, 0xcb, 0x72,
+ 0xaa, 0xa9, 0xfb, 0x3f, 0x5d, 0x9a, 0xcb, 0xac,
+ 0xe2, 0xb6, 0x27, 0x44, 0xdb, 0xe2, 0xc7, 0xd5,
+ 0x6b, 0x3d, 0xb8, 0xda, 0x3f, 0x4f, 0x5b, 0x70,
+ 0x0f, 0x40, 0x98, 0x00, 0x2c, 0x2d, 0xc6, 0x88,
+ 0x81, 0x10, 0x28, 0x70, 0x30, 0x39, 0x3d, 0x87,
+ 0x62, 0x93, 0x15, 0xee, 0x91, 0xe9, 0x01, 0x55,
+ 0xe5, 0x7f, 0xf7, 0xb7, 0xc3, 0x2c, 0x65, 0x69,
+ 0xa7, 0x96, 0x9d, 0x5b, 0x58, 0x22, 0x19, 0x78,
+ 0xa3, 0x4a, 0x67, 0x9f, 0x45, 0xe5, 0x2a, 0x09,
+ 0x8e, 0x76, 0x69, 0xd2, 0xa6, 0x6d, 0xf3, 0x06,
+ 0x95, 0x37, 0xa7, 0x34, 0x41, 0x1a, 0x69, 0x3f,
+ 0xdf, 0x67, 0xb5, 0x56, 0xf9, 0x33, 0x8b, 0xd1,
+ 0x7d, 0xb5, 0xdb, 0x37, 0x70, 0xa9, 0x64, 0x14,
+ 0x97, 0x3f, 0xf5, 0x61, 0x3e, 0x21, 0x22, 0x21,
+ 0x27, 0x91, 0x94, 0x13, 0x50, 0x12, 0x31, 0xa8,
+ 0xf2, 0x12, 0x92, 0xb1, 0x25, 0x88, 0xe9, 0x28,
+ 0xe8, 0x5a, 0xc0, 0xad, 0x3e, 0xcf, 0x44, 0x3a,
+ 0xad, 0x34, 0x76, 0x76, 0xbe, 0x33, 0xff, 0xfb,
+ 0x63, 0xd5, 0xc7, 0xc9, 0xc9, 0x8f, 0x49, 0xd9,
+ 0xdb, 0x21, 0x97, 0xe0, 0x7c, 0x4f, 0x14, 0xb8,
+ 0xef, 0xbf, 0xb2, 0xb7, 0x38, 0xfe, 0x00, 0x00,
+ 0x86, 0x46, 0xf6, 0xf4, 0xa9, 0xe5, 0xd6, 0x8a,
+ 0xf0, 0x92, 0xc9, 0xcc, 0xe7, 0x95, 0x36, 0x18,
+ 0x86, 0x3b, 0xce, 0xb5, 0x5b, 0xad, 0x95, 0x37,
+ 0x86, 0x06, 0x3d, 0x7b, 0x55, 0x08, 0x39, 0xbc,
+ 0xd1, 0x8a, 0x4c, 0x2a, 0x41, 0x4a, 0xa9, 0x43,
+ 0x49, 0x20, 0x47, 0x4d, 0xd2, 0x8a, 0xe9, 0x22,
+ 0xc9, 0x97, 0x30, 0x37, 0xb9, 0x88, 0xc1, 0x81,
+ 0xa9, 0x7f, 0xa7, 0xd3, 0xea, 0x77, 0x3a, 0x3b,
+ 0xcf, 0x79, 0x3d, 0x6f, 0x56, 0x3f, 0x4b, 0x26,
+ 0xdf, 0x26, 0x65, 0x51, 0xcc, 0xae, 0xfa, 0x24,
+ 0x6d, 0x71, 0x2b, 0x05, 0xfb, 0x15, 0xa2, 0xa5,
+ 0x77, 0xd5, 0x6d, 0xc8, 0x9c, 0xdf, 0x2f, 0x9b,
+ 0x37, 0xbf, 0xcc, 0x8f, 0x8a, 0x14, 0x33, 0x83,
+ 0x17, 0xd5, 0x86, 0x86, 0x97, 0x0a, 0xe9, 0x52,
+ 0x39, 0x65, 0x36, 0x4b, 0x3f, 0xb2, 0x5a, 0xc9,
+ 0xa7, 0x89, 0x92, 0x3b, 0x51, 0xad, 0x28, 0x3c,
+ 0xed, 0x7d, 0x42, 0x0b, 0x06, 0xa3, 0x5d, 0x74,
+ 0xed, 0xbe, 0x25, 0x49, 0x45, 0x17, 0x2f, 0x34,
+ 0xfe, 0x89, 0xe3, 0x8c, 0xb9, 0x27, 0xc9, 0xde,
+ 0x2b, 0xa4, 0xec, 0x06, 0xbc, 0x4e, 0xcc, 0x5f,
+ 0xa3, 0xab, 0xfb, 0xc6, 0xe6, 0x57, 0x3f, 0xcb,
+ 0x3e, 0x50, 0xbe, 0x14, 0xc0, 0x32, 0x20, 0xb6,
+ 0x5f, 0xf4, 0x0c, 0xd3, 0x03, 0xc8, 0xb2, 0x65,
+ 0xcb, 0xd6, 0xda, 0x1d, 0x3b, 0x76, 0xfd, 0xb9,
+ 0xa4, 0xa4, 0x5c, 0x08, 0x06, 0xc3, 0x30, 0x1a,
+ 0x39, 0x8c, 0x8d, 0x0d, 0x0c, 0x5e, 0xbd, 0x7a,
+ 0xe5, 0x10, 0x7d, 0x8f, 0xaf, 0x33, 0x1b, 0x63,
+ 0x7f, 0x39, 0xb9, 0xb1, 0x72, 0xbd, 0xdd, 0x18,
+ 0x90, 0x90, 0xb8, 0x5d, 0x7e, 0x7a, 0x7c, 0xd5,
+ 0x1b, 0x60, 0xd9, 0xa6, 0x5e, 0x7c, 0x19, 0x00,
+ 0xf6, 0x9d, 0x39, 0x2d, 0x24, 0x2d, 0xa8, 0xad,
+ 0xad, 0x6d, 0x32, 0x99, 0x4c, 0xd5, 0x3c, 0xcf,
+ 0x17, 0x55, 0x56, 0x56, 0x96, 0x57, 0x54, 0x54,
+ 0x70, 0x2c, 0xe8, 0x98, 0xdc, 0xbc, 0x79, 0x53,
+ 0xa3, 0x13, 0xd0, 0x93, 0xc9, 0x64, 0x82, 0x03,
+ 0x03, 0x03, 0xef, 0xd1, 0x51, 0xf4, 0x52, 0xf7,
+ 0x02, 0x29, 0x45, 0x04, 0x62, 0xfa, 0xa0, 0x35,
+ 0xe4, 0x01, 0x00, 0x67, 0xce, 0x9c, 0xa9, 0xa1,
+ 0x74, 0x7a, 0x8c, 0xa8, 0x6c, 0x24, 0xcd, 0xa7,
+ 0x5c, 0x20, 0x91, 0x51, 0x03, 0x65, 0x37, 0x43,
+ 0x71, 0x71, 0xb1, 0x74, 0xe4, 0xc8, 0x11, 0x8c,
+ 0x8f, 0x8f, 0x13, 0xf5, 0xb4, 0xe9, 0x6b, 0x48,
+ 0x5f, 0x5f, 0x1f, 0xba, 0xba, 0xba, 0x14, 0x1a,
+ 0x9b, 0x26, 0xa0, 0x2a, 0x29, 0x2b, 0x93, 0x66,
+ 0xb3, 0x79, 0x4c, 0x92, 0xa4, 0x0f, 0x6d, 0x36,
+ 0xdb, 0x85, 0xe6, 0xe6, 0xe6, 0x7b, 0xa8, 0x69,
+ 0x7e, 0x36, 0x27, 0xaf, 0xd8, 0xda, 0xbf, 0x7f,
+ 0xbf, 0x23, 0x87, 0x84, 0x26, 0x24, 0x09, 0x48,
+ 0x26, 0x1e, 0x8f, 0x0b, 0x94, 0x80, 0xcc, 0x5e,
+ 0xaf, 0x97, 0xef, 0xee, 0xee, 0xd6, 0x93, 0x8c,
+ 0xcf, 0xe7, 0x43, 0x6e, 0x2e, 0x8b, 0xa7, 0xd5,
+ 0x42, 0x80, 0xf5, 0x63, 0x58, 0x55, 0x55, 0x65,
+ 0xd8, 0xbd, 0x7b, 0x37, 0xbd, 0x4b, 0x0c, 0x2a,
+ 0x01, 0x55, 0xc9, 0x9c, 0x42, 0xe3, 0xf3, 0xc9,
+ 0x5e, 0x39, 0xd9, 0x63, 0x8c, 0x66, 0x01, 0x3c,
+ 0xc0, 0xc0, 0xd1, 0xa3, 0x47, 0x1f, 0xa3, 0x6c,
+ 0xb7, 0x27, 0x9d, 0x4e, 0xef, 0x20, 0x7d, 0x94,
+ 0x74, 0x03, 0xb5, 0x8b, 0xa9, 0x34, 0x16, 0x16,
+ 0x16, 0xc2, 0xe1, 0x70, 0xdc, 0xef, 0x77, 0x55,
+ 0x9b, 0x65, 0x4b, 0xc6, 0x10, 0xad, 0x9a, 0x62,
+ 0xc3, 0x98, 0x26, 0xf5, 0x11, 0x10, 0x8f, 0x28,
+ 0x8a, 0xfd, 0x54, 0xff, 0xc4, 0x62, 0xb1, 0x7c,
+ 0xd4, 0xd2, 0xd2, 0xc2, 0x6e, 0x5d, 0x5d, 0x1e,
+ 0x60, 0x80, 0x56, 0xb8, 0x40, 0xb4, 0xf7, 0x91,
+ 0x2e, 0x90, 0xe3, 0x36, 0x7a, 0x54, 0x14, 0x90,
+ 0x51, 0x7b, 0x2a, 0x95, 0x22, 0xf6, 0x6c, 0x47,
+ 0xc9, 0xb0, 0x7e, 0xbd, 0x3d, 0x4c, 0x68, 0x8e,
+ 0x46, 0x73, 0xfe, 0x45, 0xdb, 0xe6, 0x21, 0xca,
+ 0xa3, 0xa4, 0x21, 0x62, 0x93, 0xd9, 0x0c, 0x50,
+ 0xdf, 0x18, 0xdd, 0x33, 0xfa, 0xed, 0xb4, 0x22,
+ 0x0f, 0x30, 0xb0, 0x86, 0x61, 0xf6, 0x1e, 0xb3,
+ 0x91, 0x3a, 0x5c, 0x2e, 0x57, 0xb5, 0xd5, 0x6a,
+ 0xad, 0x26, 0x43, 0xec, 0xf1, 0x22, 0x12, 0xe5,
+ 0x2b, 0x0b, 0xd0, 0x08, 0x98, 0x42, 0x4a, 0x38,
+ 0x53, 0x3e, 0xb7, 0xdb, 0xdd, 0x49, 0xe3, 0xc3,
+ 0xa4, 0x2c, 0x08, 0xd9, 0x6d, 0xf4, 0xf0, 0xff,
+ 0x05, 0x6b, 0x38, 0x7c, 0x58, 0x17, 0x4b, 0x5a,
+ 0x6c, 0xf5, 0xec, 0x38, 0xb2, 0x8c, 0xc6, 0xea,
+ 0x0c, 0x00, 0x3b, 0xa2, 0x2b, 0xff, 0x23, 0x28,
+ 0xc9, 0xd0, 0x03, 0xe1, 0xde, 0xd3, 0x8e, 0xad,
+ 0xf4, 0xa1, 0xc7, 0x8f, 0xbe, 0x7d, 0x25, 0x3a,
+ 0x03, 0xff, 0x05, 0xe5, 0x67, 0x0d, 0x81, 0x5d,
+ 0x6d, 0x34, 0x35, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/downloads_icon_text.png.h b/src/images/downloads_icon_text.png.h
new file mode 100644
index 0000000..623219e
--- /dev/null
+++ b/src/images/downloads_icon_text.png.h
@@ -0,0 +1,178 @@
+/* downloads_icon_text.png - 1399 bytes */
+ static const unsigned char downloads_icon_text_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x69, 0x71,
+ 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xe0,
+ 0x00, 0x8d, 0x00, 0x2c, 0x0a, 0xa2, 0x98, 0x90,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x13, 0x0e, 0x26, 0x14, 0x56, 0x0f, 0x10, 0x00,
+ 0x00, 0x00, 0x04, 0xf7, 0x49, 0x44, 0x41, 0x54,
+ 0x78, 0xda, 0xed, 0x98, 0x4d, 0x68, 0x54, 0x57,
+ 0x14, 0xc7, 0xff, 0x6f, 0x48, 0xca, 0xcc, 0x48,
+ 0xd2, 0x36, 0x21, 0xba, 0xb4, 0xd0, 0x88, 0xb3,
+ 0x10, 0xb2, 0x50, 0x57, 0x8d, 0xa2, 0x22, 0x2e,
+ 0x22, 0x9a, 0x8d, 0xc6, 0x0f, 0x0a, 0x82, 0xc1,
+ 0xb6, 0xd0, 0x55, 0x28, 0xb3, 0x12, 0x44, 0x0c,
+ 0x0d, 0x74, 0x53, 0x10, 0x84, 0x28, 0x65, 0x16,
+ 0x06, 0x0c, 0xf4, 0x85, 0x2e, 0xdc, 0xcc, 0x6c,
+ 0xa4, 0x42, 0x4c, 0x70, 0x11, 0x30, 0x44, 0x69,
+ 0x86, 0x96, 0x2c, 0x42, 0x03, 0x31, 0xc9, 0x18,
+ 0x62, 0xe7, 0x23, 0x99, 0xc1, 0x4c, 0x7e, 0x5d,
+ 0x38, 0x2f, 0x3c, 0xe7, 0x23, 0x37, 0x51, 0x62,
+ 0x2d, 0xde, 0x1f, 0x9c, 0xc5, 0xbc, 0x3b, 0xe7,
+ 0x9e, 0xfb, 0xce, 0xbd, 0xef, 0x9e, 0xfb, 0xbf,
+ 0x92, 0xc5, 0x62, 0xb1, 0x58, 0x2c, 0x16, 0x8b,
+ 0xc5, 0x62, 0xb1, 0x58, 0x2c, 0x16, 0x8b, 0xe5,
+ 0xe3, 0xc2, 0xf9, 0x00, 0xc7, 0xc4, 0x36, 0x8f,
+ 0xf1, 0x8d, 0xfe, 0x03, 0xa5, 0x07, 0x7e, 0x7b,
+ 0x25, 0x69, 0x4a, 0xd2, 0x4f, 0x92, 0x3e, 0xfb,
+ 0x4f, 0x32, 0x00, 0x02, 0xde, 0x5b, 0xff, 0x78,
+ 0x14, 0x8b, 0x45, 0x16, 0x17, 0x17, 0x79, 0xf0,
+ 0xe0, 0x41, 0xf1, 0xe8, 0xd1, 0xa3, 0xaf, 0x24,
+ 0x15, 0x24, 0x7d, 0xfe, 0xfe, 0xdf, 0xff, 0x35,
+ 0x55, 0x56, 0xc3, 0xb6, 0xf4, 0xbf, 0xfe, 0xc0,
+ 0x71, 0x1c, 0x22, 0x91, 0xc8, 0xea, 0x93, 0x27,
+ 0x4f, 0x58, 0x5d, 0x5d, 0xe5, 0xd8, 0xb1, 0x63,
+ 0x48, 0xba, 0x55, 0x5a, 0x86, 0x3d, 0x92, 0xe6,
+ 0xca, 0xac, 0xa7, 0xd4, 0xf6, 0x4c, 0x52, 0xd2,
+ 0x67, 0xfe, 0x15, 0xe5, 0x7f, 0x3e, 0x51, 0x65,
+ 0xc5, 0x79, 0xf6, 0x97, 0xa4, 0x2f, 0xab, 0x0c,
+ 0xd0, 0x14, 0x5b, 0x55, 0xfa, 0xfa, 0x47, 0xd2,
+ 0x80, 0xa4, 0x46, 0x49, 0xf5, 0x92, 0x86, 0xfc,
+ 0xed, 0x35, 0x13, 0x50, 0x7a, 0x30, 0xd8, 0xde,
+ 0xde, 0x0e, 0xc0, 0xf0, 0xf0, 0x30, 0x92, 0x16,
+ 0x25, 0xf5, 0x34, 0x35, 0x35, 0xe1, 0xba, 0x2e,
+ 0x99, 0x4c, 0x86, 0x4c, 0x26, 0x83, 0xeb, 0xba,
+ 0x34, 0x35, 0x35, 0x51, 0x1a, 0xc8, 0xb3, 0xb9,
+ 0xb9, 0x39, 0x16, 0x16, 0x16, 0x90, 0x44, 0x34,
+ 0x1a, 0x05, 0x20, 0x1a, 0x8d, 0x22, 0x89, 0x85,
+ 0x85, 0x05, 0x9e, 0x3f, 0x7f, 0x8e, 0x97, 0x80,
+ 0x72, 0x5e, 0xbc, 0x78, 0xc1, 0xa5, 0x4b, 0x97,
+ 0x90, 0xf4, 0x67, 0x95, 0xf1, 0x98, 0x62, 0xbf,
+ 0xf1, 0x0e, 0xf9, 0x7c, 0x9e, 0xb1, 0xb1, 0x31,
+ 0xda, 0xdb, 0xdb, 0x91, 0xf4, 0xbb, 0xa4, 0xde,
+ 0xd6, 0xd6, 0x56, 0x26, 0x26, 0x26, 0x2a, 0xe2,
+ 0xd6, 0x4a, 0x40, 0x63, 0x30, 0x18, 0x04, 0x60,
+ 0x79, 0x79, 0xd9, 0x4b, 0xc0, 0xbc, 0xeb, 0xba,
+ 0x00, 0x9c, 0x39, 0x73, 0x86, 0x73, 0xe7, 0xce,
+ 0x01, 0xe0, 0xba, 0x2e, 0xa5, 0xd9, 0x78, 0x96,
+ 0x48, 0x24, 0x00, 0xd8, 0xb9, 0x73, 0x27, 0x93,
+ 0x93, 0x93, 0x00, 0x24, 0x93, 0x49, 0x76, 0xed,
+ 0xda, 0x05, 0x40, 0x3c, 0x1e, 0xaf, 0x48, 0x40,
+ 0x77, 0x77, 0x37, 0x6d, 0x6d, 0x6d, 0x00, 0xa4,
+ 0x52, 0xa9, 0x5a, 0x33, 0x64, 0x8a, 0xdd, 0xe2,
+ 0x9f, 0xdd, 0xbd, 0x7b, 0xf7, 0x02, 0x30, 0x35,
+ 0x35, 0x85, 0xa4, 0xa2, 0xa4, 0x94, 0x37, 0x36,
+ 0xbf, 0xff, 0x46, 0x09, 0xf8, 0x34, 0x14, 0x0a,
+ 0x01, 0x90, 0xcb, 0xe5, 0xd6, 0x13, 0x90, 0xcd,
+ 0x66, 0x01, 0x08, 0x85, 0x42, 0x84, 0xc3, 0x61,
+ 0x00, 0x32, 0x99, 0x8c, 0x37, 0x88, 0xde, 0xbe,
+ 0xbe, 0x3e, 0x00, 0xae, 0x5e, 0xbd, 0x0a, 0xc0,
+ 0xe0, 0xe0, 0x20, 0x00, 0xd7, 0xae, 0x5d, 0x03,
+ 0xa0, 0xaf, 0xaf, 0x0f, 0x49, 0x37, 0xfc, 0xf1,
+ 0x42, 0xa1, 0x10, 0x81, 0x40, 0xa0, 0x3c, 0x7e,
+ 0x45, 0x02, 0x0c, 0xb1, 0xff, 0xe8, 0xe8, 0xe8,
+ 0x60, 0x62, 0x62, 0x82, 0x42, 0xa1, 0xb0, 0xee,
+ 0xbb, 0xb6, 0xb6, 0xe6, 0xf9, 0xa7, 0x72, 0xb9,
+ 0x5c, 0x85, 0xff, 0x86, 0x9f, 0xc0, 0xa1, 0x43,
+ 0x87, 0xfc, 0x9f, 0x40, 0x6a, 0x13, 0x83, 0x38,
+ 0xd1, 0xd5, 0xd5, 0x05, 0x40, 0x3a, 0x9d, 0x66,
+ 0x66, 0x66, 0x86, 0x60, 0x30, 0xc8, 0xcc, 0xcc,
+ 0x0c, 0x9e, 0xdf, 0xd9, 0xb3, 0x67, 0x91, 0x74,
+ 0xa2, 0x4a, 0xbc, 0x77, 0x4d, 0xc0, 0xd4, 0xfc,
+ 0xfc, 0x3c, 0x00, 0x07, 0x0f, 0x1e, 0xc4, 0x5b,
+ 0xbd, 0x3e, 0xff, 0x0d, 0x13, 0x10, 0x78, 0xa3,
+ 0xe0, 0x3a, 0x8e, 0x22, 0x91, 0x48, 0xd7, 0xcd,
+ 0x9b, 0x37, 0x55, 0x2c, 0x16, 0x75, 0xfd, 0xfa,
+ 0x75, 0x49, 0xfa, 0x55, 0x92, 0xe2, 0xf1, 0xb8,
+ 0x24, 0xe9, 0xe4, 0xc9, 0x93, 0x3a, 0x75, 0xea,
+ 0x94, 0x24, 0x29, 0x91, 0x48, 0x78, 0xae, 0xc9,
+ 0xf1, 0xf1, 0x71, 0x49, 0x52, 0x43, 0x43, 0x83,
+ 0xfa, 0xfb, 0xfb, 0x95, 0xcf, 0xe7, 0xc7, 0x6e,
+ 0xdf, 0xbe, 0xad, 0x1d, 0x3b, 0x76, 0x48, 0x92,
+ 0x4a, 0xed, 0x93, 0x6f, 0xb3, 0x6d, 0x1b, 0x62,
+ 0xab, 0xae, 0xae, 0x4e, 0x92, 0x94, 0xcb, 0xe5,
+ 0x74, 0xf9, 0xf2, 0xe5, 0x0a, 0xff, 0x47, 0x8f,
+ 0x1e, 0x55, 0xf8, 0x57, 0x2d, 0x0b, 0xc5, 0x62,
+ 0x91, 0xa5, 0xa5, 0x25, 0x1e, 0x3e, 0x7c, 0x58,
+ 0x5e, 0x06, 0x7b, 0x9a, 0x9b, 0x9b, 0x71, 0x5d,
+ 0x97, 0x6c, 0x36, 0x4b, 0x36, 0x9b, 0x65, 0x68,
+ 0x68, 0x88, 0xe6, 0xe6, 0x66, 0x6f, 0x23, 0xaa,
+ 0x77, 0x1c, 0x87, 0x74, 0x3a, 0x4d, 0x3e, 0x9f,
+ 0xa7, 0xa5, 0xa5, 0x05, 0x49, 0x5f, 0xb5, 0xb4,
+ 0xb4, 0x90, 0xcf, 0xe7, 0x49, 0xa7, 0xd3, 0x38,
+ 0x8e, 0x43, 0x69, 0x47, 0xde, 0xea, 0x0a, 0x30,
+ 0xc5, 0x9e, 0xba, 0x78, 0xf1, 0x22, 0xa9, 0x54,
+ 0xaa, 0xd6, 0x26, 0xf7, 0xe3, 0x9e, 0x3d, 0x7b,
+ 0x78, 0xfa, 0xf4, 0x69, 0xed, 0x4d, 0xb0, 0xca,
+ 0x41, 0x68, 0x5a, 0xd2, 0xcf, 0xbe, 0x83, 0x90,
+ 0x57, 0x8a, 0xe6, 0xcb, 0xec, 0x07, 0x5f, 0x29,
+ 0x9a, 0x2d, 0x95, 0x1f, 0xcf, 0x02, 0x65, 0xbf,
+ 0x67, 0x6b, 0x94, 0x2c, 0x93, 0x99, 0x62, 0x7f,
+ 0xe1, 0x55, 0x8f, 0x1a, 0x56, 0x2f, 0xe9, 0xb7,
+ 0x0d, 0xda, 0x2d, 0x16, 0x8b, 0xa5, 0x42, 0x2e,
+ 0xfa, 0xed, 0x56, 0xe9, 0x79, 0xff, 0xc7, 0xb2,
+ 0x81, 0xac, 0x97, 0x89, 0xd2, 0x41, 0x08, 0x49,
+ 0x61, 0x49, 0x8c, 0x8c, 0x8c, 0x6c, 0xb7, 0x52,
+ 0xfb, 0xb0, 0x12, 0x00, 0xd0, 0xd6, 0xd6, 0x86,
+ 0xa4, 0x6f, 0xf7, 0xef, 0xdf, 0x5f, 0xb5, 0x86,
+ 0x1a, 0x94, 0x98, 0x49, 0xf9, 0x6d, 0x59, 0xc9,
+ 0x55, 0x29, 0x91, 0xdf, 0x48, 0xfa, 0x5b, 0xd2,
+ 0x92, 0xcf, 0x7a, 0x25, 0xd5, 0xbd, 0x6d, 0xe9,
+ 0x5b, 0x7f, 0xc9, 0xd1, 0xd1, 0x51, 0x62, 0xb1,
+ 0x18, 0x92, 0x32, 0x03, 0x03, 0x03, 0x8c, 0x8e,
+ 0x8e, 0x56, 0x4d, 0xc0, 0x06, 0x4a, 0xcc, 0xa4,
+ 0xfc, 0x4c, 0xfe, 0x37, 0x0c, 0x4a, 0xee, 0xfb,
+ 0xc6, 0xc6, 0x46, 0xee, 0xde, 0xbd, 0xcb, 0xcb,
+ 0x97, 0x2f, 0x59, 0x59, 0x59, 0x21, 0x91, 0x48,
+ 0xb0, 0x7b, 0xf7, 0x6e, 0xbc, 0x4f, 0xb6, 0xd6,
+ 0xe1, 0x67, 0x53, 0x09, 0xe8, 0xec, 0xec, 0x64,
+ 0x65, 0x65, 0x65, 0x6d, 0xdf, 0xbe, 0x7d, 0xb9,
+ 0x42, 0xa1, 0x40, 0x67, 0x67, 0x67, 0x79, 0x47,
+ 0x26, 0x25, 0x66, 0x52, 0x7e, 0x46, 0x25, 0x17,
+ 0x8f, 0xc7, 0x01, 0x38, 0x7f, 0xfe, 0x3c, 0x17,
+ 0x2e, 0x5c, 0x28, 0x8f, 0x3f, 0x77, 0xef, 0xde,
+ 0x3d, 0x00, 0x8e, 0x1f, 0x3f, 0xce, 0x81, 0x03,
+ 0x07, 0x00, 0x18, 0x19, 0x19, 0xa1, 0x74, 0x8a,
+ 0x5d, 0xff, 0xff, 0x95, 0x2b, 0x57, 0xbc, 0xd3,
+ 0xe8, 0xe6, 0x13, 0xe0, 0x38, 0x0e, 0xc9, 0x64,
+ 0x92, 0xe9, 0xe9, 0x69, 0x92, 0xc9, 0x24, 0x8e,
+ 0xe3, 0x94, 0x0f, 0xc0, 0xa4, 0xc4, 0x4c, 0xca,
+ 0x6f, 0xd3, 0x4a, 0x2e, 0x1c, 0x0e, 0x57, 0x53,
+ 0x72, 0x73, 0x99, 0x4c, 0xa6, 0x62, 0x96, 0x57,
+ 0x57, 0x57, 0x2b, 0x12, 0x10, 0x0c, 0x06, 0x91,
+ 0x14, 0xd9, 0xf2, 0x95, 0x51, 0x77, 0x77, 0xf7,
+ 0xfa, 0x0c, 0x56, 0x39, 0xa7, 0x9b, 0x94, 0x98,
+ 0xe9, 0xf7, 0x3b, 0x29, 0x39, 0x49, 0x73, 0xe9,
+ 0x74, 0x1a, 0xc0, 0xbb, 0x20, 0xf1, 0x5b, 0x61,
+ 0x33, 0xd7, 0x6b, 0x01, 0x53, 0x36, 0x62, 0xb1,
+ 0x98, 0x1c, 0xc7, 0x51, 0x2c, 0x16, 0xab, 0xda,
+ 0x6e, 0x52, 0x62, 0x26, 0x4c, 0xfe, 0xc3, 0xc3,
+ 0xc3, 0x92, 0xa4, 0x8e, 0x8e, 0x0e, 0x9d, 0x3e,
+ 0x7d, 0xba, 0xbc, 0x79, 0xed, 0xfe, 0xfd, 0xfb,
+ 0x92, 0xa4, 0x68, 0x34, 0xaa, 0xfa, 0xfa, 0x7a,
+ 0x7f, 0xdb, 0x27, 0xdb, 0x71, 0x29, 0x59, 0x31,
+ 0x83, 0x06, 0x25, 0x66, 0x5c, 0x01, 0x06, 0xff,
+ 0xde, 0xd6, 0xd6, 0xd6, 0x8d, 0x94, 0xdc, 0x77,
+ 0x0d, 0x0d, 0x0d, 0xdc, 0xb9, 0x73, 0xa7, 0xa2,
+ 0x8f, 0x5a, 0xf7, 0x7f, 0x6f, 0x73, 0x10, 0xda,
+ 0xa8, 0xcd, 0xa4, 0xc4, 0x4c, 0xb6, 0x19, 0x25,
+ 0xf7, 0xfa, 0xe2, 0x22, 0x10, 0xe0, 0xc8, 0x91,
+ 0x23, 0x00, 0xcc, 0xce, 0xce, 0xfa, 0xcb, 0xe0,
+ 0xd7, 0x5b, 0x18, 0xc3, 0xff, 0xfb, 0x5c, 0xb2,
+ 0xbc, 0xbc, 0xcc, 0xe3, 0xc7, 0x8f, 0x39, 0x7c,
+ 0xf8, 0x30, 0x92, 0xc6, 0x3f, 0xd6, 0xa3, 0xf9,
+ 0xa2, 0xa4, 0x5f, 0x24, 0x7d, 0x6a, 0x55, 0x8b,
+ 0xc5, 0x62, 0xb1, 0x58, 0x2c, 0x16, 0x8b, 0xc5,
+ 0x62, 0xb1, 0x58, 0x2c, 0x16, 0x8b, 0xc5, 0xb2,
+ 0x65, 0xfe, 0x05, 0x82, 0xca, 0x7e, 0xe3, 0x95,
+ 0x73, 0x66, 0x40, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/empty.xpm b/src/images/empty.xpm
new file mode 100644
index 0000000..97446d5
--- /dev/null
+++ b/src/images/empty.xpm
@@ -0,0 +1,5 @@
+/* XPM */
+static const char * empty_xpm[] = {
+"2 1 1 1",
+" c None",
+" "};
diff --git a/src/images/exists.xpm b/src/images/exists.xpm
new file mode 100644
index 0000000..c06f4e2
--- /dev/null
+++ b/src/images/exists.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static const char * exists_xpm[] = {
+"16 16 3 1",
+" c None",
+". c #00D705",
+"+ c #C6C6C6",
+" ",
+" ",
+" ",
+" ",
+" . ",
+" ..+ ",
+" ..++ ",
+" . ..+ ",
+" .. .++ ",
+" ...+ ",
+" ..+ ",
+" ++ ",
+" ",
+" ",
+" ",
+" "};
diff --git a/src/images/fixcolours_palette.xpm b/src/images/fixcolours_palette.xpm
new file mode 100644
index 0000000..985a212
--- /dev/null
+++ b/src/images/fixcolours_palette.xpm
@@ -0,0 +1,42 @@
+/* XPM */
+static const char * fixcolours_palette_xpm[] = {
+"16 16 23 1",
+" c None",
+". c #FF0000",
+"+ c #FF00EC",
+"@ c #AB59E1",
+"# c #0000FF",
+"$ c #7AB4FF",
+"% c #00FFFF",
+"& c #00FF00",
+"* c #FFFF00",
+"= c #FFB300",
+"- c #000000",
+"; c #A20000",
+"> c #A20096",
+", c #6D398F",
+"' c #0000A2",
+") c #005F85",
+"! c #008C8C",
+"~ c #00A200",
+"{ c #A2A200",
+"] c #A27200",
+"^ c #808080",
+"/ c #B8B8B8",
+"( c #FFBEBE",
+".+@#$%&*=-------",
+";>,')!~{]^/(----",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------",
+"----------------"};
diff --git a/src/images/flags/AD.xpm b/src/images/flags/AD.xpm
new file mode 100644
index 0000000..753e9c6
--- /dev/null
+++ b/src/images/flags/AD.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *AD_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #00001111ADAD",
+"X c #03031F1FADAD",
+"o c #0D0D2B2BB1B1",
+"O c #19193333B7B7",
+"+ c #2B2B4747BDBD",
+"@ c #2F2F4949BFBF",
+"# c #39395151C5C5",
+"$ c #41415B5BC7C7",
+"% c #49496161CBCB",
+"& c #51516767CFCF",
+"* c #55556B6BD7D7",
+"= c #59596D6DD1D1",
+"- c #5B5B7171D3D3",
+"; c #5D5D7171D3D3",
+": c #5D5D7171D5D5",
+"> c #5F5F7373D5D5",
+", c #67677B7BD7D7",
+"< c #7D7D8D8DDADA",
+"1 c #C5C500000000",
+"2 c #C7C700000000",
+"3 c #CBCB00000000",
+"4 c #CDCD00000000",
+"5 c #D3D300000000",
+"6 c #D5D500000000",
+"7 c #DBDB00000000",
+"8 c #DDDD00000000",
+"9 c #E1E100000000",
+"0 c #E5E500000000",
+"q c #E7E700000000",
+"w c #EBEB00000000",
+"e c #EFEF00000000",
+"r c #E6E610101010",
+"t c #E8E815151414",
+"y c #E8E815151515",
+"u c #E9E91B1B1B1B",
+"i c #EAEA1D1D1D1D",
+"p c #EAEA1E1E1E1E",
+"a c #F1F100000000",
+"s c #EBEB25252323",
+"d c #EBEB24242424",
+"f c #ECEC24242525",
+"g c #E8E82D2D2D2D",
+"h c #EEEE2C2C2C2C",
+"j c #EEEE2D2D2D2D",
+"k c #EEEE30302B2B",
+"l c #E9E931313131",
+"z c #EAEA36363636",
+"x c #EFEF37373333",
+"c c #ECEC3A3A3A3A",
+"v c #ECEC3B3B3B3B",
+"b c #F0F033333535",
+"n c #F0F036363535",
+"m c #F1F13C3C3C3C",
+"M c #F2F23D3D3D3D",
+"N c #F1F140403C3C",
+"B c #EDED42424242",
+"V c #EFEF49494949",
+"C c #F3F345454545",
+"Z c #F3F346464444",
+"A c #F5F54D4D4D4D",
+"S c #F1F150504F4F",
+"D c #F4F45C5C4B4B",
+"F c #F2F256565656",
+"G c #F4F45D5D5D5D",
+"H c #F1F162624C4C",
+"J c #F5F564646464",
+"K c #F7F76A6A6A6A",
+"L c #F8F86F6F7070",
+"P c #F3F37D7D6D6D",
+"I c #ACAC94946565",
+"U c #B0B099996B6B",
+"Y c #B1B199996B6B",
+"T c #B5B59D9D7171",
+"R c #B8B8A2A27676",
+"E c #BCBCA7A77D7D",
+"W c #C7C7B7B74F4F",
+"Q c #CBCBBCBC5757",
+"! c #CACAA2A26262",
+"~ c #C2C2AEAE7C7C",
+"^ c #D1D1A4A46A6A",
+"/ c #D0D0AFAF7D7D",
+"( c #D8D8AEAE7474",
+") c #E0E0A9A97A7A",
+"_ c #CFCFCFCF0000",
+"` c #D3D3D3D30000",
+"' c #D7D7D7D70000",
+"] c #DBDBDBDB0000",
+"[ c #DFDFDFDF0000",
+"{ c #E1E1E1E10000",
+"} c #F5F5F5F50000",
+"| c #F9F9F9F90000",
+" . c #FBFBFBFB0505",
+".. c #FDFDFDFD0000",
+"X. c #EBEBEBEB2323",
+"o. c #EDEDEDED2A2A",
+"O. c #EEEEEEEE2B2B",
+"+. c #F1F1F1F13C3C",
+"@. c #CCCCC0C04D4D",
+"#. c #DADACFCF6F6F",
+"$. c #E5E5D0D05252",
+"%. c #E9E9D3D36161",
+"&. c #EDEDEDED4040",
+"*. c #EEEEEEEE4646",
+"=. c #F2F2F2F24040",
+"-. c #F3F3F3F34444",
+";. c #F0F0F0F04B4B",
+":. c #F4F4F4F44848",
+">. c #F5F5F5F54B4B",
+",. c #F2F2F2F25252",
+"<. c #F5F5F5F55050",
+"1. c #F6F6F6F65454",
+"2. c #F2F2F2F25858",
+"3. c #F4F4F4F45F5F",
+"4. c #F7F7F7F75C5C",
+"5. c #F1F1EEEE6969",
+"6. c #F3F3F1F16F6F",
+"7. c #F9F9F9F96060",
+"8. c #FAFAFAFA6868",
+"9. c #FBFBFBFB6F6F",
+"0. c #F9F9F9F97676",
+"q. c #FCFCFCFC7575",
+"w. c #FBFBFBFB7C7C",
+"e. c #86869595DADA",
+"r. c #84849494DDDD",
+"t. c #8B8B9A9ADCDC",
+"y. c #8C8C9A9ADBDB",
+"u. c #8C8C9A9ADDDD",
+"i. c #8C8C9B9BDEDE",
+"p. c #91919F9FDEDE",
+"a. c #91919F9FDFDF",
+"s. c #9494A1A1DDDD",
+"d. c #9999A6A6DFDF",
+"f. c #9191A0A0E0E0",
+"g. c #9696A4A4E0E0",
+"h. c #9696A4A4E1E1",
+"j. c #9797A5A5E2E2",
+"k. c #9999A7A7E5E5",
+"l. c #9B9BA8A8E2E2",
+"z. c #9B9BA8A8E3E3",
+"x. c #9E9EAAAAE1E1",
+"c. c #9F9FACACE4E4",
+"v. c #9F9FACACE5E5",
+"b. c #9E9EAAAAE8E8",
+"n. c #A3A3AEAEE2E2",
+"m. c #A3A3AFAFE6E6",
+"M. c #A7A7B2B2E5E5",
+"N. c #A6A6B3B3E7E7",
+"B. c #ABABB6B6E7E7",
+"V. c #AEAEB9B9E8E8",
+"C. c #B0B0BBBBEDED",
+"Z. c #B2B2BCBCE9E9",
+"A. c #B4B4BEBEEBEB",
+"S. c #B4B4BFBFEBEB",
+"D. c #B7B7C0C0ECEC",
+"F. c #CCCCB9B98B8B",
+"G. c #D3D3B2B28585",
+"H. c #FBFBFBFB8181",
+"J. c #FCFCFCFC8686",
+"K. c #FCFCFCFC8C8C",
+"L. c #FDFDFDFD8F8F",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+", , : : * .. .| | } } a a w q q ",
+"- S.A.A.C.L.K.J.H.w.0.L K J G 9 ",
+", S.N.m.b.q.q.5.5.4.1.A C M F 8 ",
+"= A.m.v.z.0.F.G./ ~ >.C m x S 8 ",
+"= Z.v.z.z.8.( P %.^ -.M x j V 6 ",
+"& V.l.g.f.7.( %.D ! +.x j d B 5 ",
+"$ B.g.p.i.#.E H $.Y @.j s p v 4 ",
+"$ B.p.t.r.<.R T Y I o.d p y z 3 ",
+"# n.i.e.< :.=.Q W o.X.i t r l 2 ",
+"+ d.d.p.i.7.2.,.;.*.+.v z l g 2 ",
+"# O o X . { ] ] ` ` _ 4 3 2 1 2 ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/AE.xpm b/src/images/flags/AE.xpm
new file mode 100644
index 0000000..5899b1c
--- /dev/null
+++ b/src/images/flags/AE.xpm
@@ -0,0 +1,128 @@
+/* XPM */
+static const char * AE_xpm[] = {
+"16 16 109 2",
+" c None",
+". c #FF0000",
+"+ c #FD0000",
+"@ c #007D00",
+"# c #007900",
+"$ c #007500",
+"% c #007300",
+"& c #006D00",
+"* c #006900",
+"= c #006300",
+"- c #005D00",
+"; c #005900",
+"> c #005300",
+", c #004D00",
+"' c #FF7B7B",
+") c #FE7979",
+"! c #FE7777",
+"~ c #74C774",
+"{ c #70C571",
+"] c #6DC36D",
+"^ c #69C269",
+"/ c #65C065",
+"( c #61BE60",
+"_ c #5CBB5C",
+": c #58B957",
+"< c #53B753",
+"[ c #4EB44E",
+"} c #004700",
+"| c #FF7B7A",
+"1 c #FE5F5F",
+"2 c #FE5C5C",
+"3 c #FE5959",
+"4 c #54BA54",
+"5 c #51B751",
+"6 c #4CB64C",
+"7 c #47B347",
+"8 c #42B142",
+"9 c #3DAE3D",
+"0 c #37AB37",
+"a c #31A931",
+"b c #2CA62C",
+"c c #49B249",
+"d c #004100",
+"e c #FD5454",
+"f c #FDFDFD",
+"g c #FCFCFC",
+"h c #FBFBFB",
+"i c #FAFAFA",
+"j c #F9F9F9",
+"k c #F8F8F8",
+"l c #F7F7F7",
+"m c #F6F6F6",
+"n c #F5F5F5",
+"o c #D7D7D7",
+"p c #FE7676",
+"q c #FE5858",
+"r c #FD4F50",
+"s c #F4F4F4",
+"t c #D5D5D5",
+"u c #FE7273",
+"v c #FD5353",
+"w c #FC4F4F",
+"x c #FC4A4B",
+"y c #F3F3F3",
+"z c #F4F5F5",
+"A c #D1D1D1",
+"B c #FD6F6F",
+"C c #FB4A49",
+"D c #FB4545",
+"E c #F2F2F2",
+"F c #FB0000",
+"G c #FC6A6A",
+"H c #FB4949",
+"I c #FA3F3F",
+"J c #CFCFCF",
+"K c #F90000",
+"L c #FC6666",
+"M c #FA4444",
+"N c #F93A3A",
+"O c #343434",
+"P c #2E2E2E",
+"Q c #292929",
+"R c #232323",
+"S c #1E1E1E",
+"T c #181919",
+"U c #131313",
+"V c #0F0F0E",
+"W c #0B0B0B",
+"X c #2F2F2F",
+"Y c #000000",
+"Z c #F70000",
+"` c #FB6162",
+" . c #FA5D5D",
+".. c #F95858",
+"+. c #F95455",
+"@. c #505050",
+"#. c #4B4B4B",
+"$. c #464646",
+"%. c #424242",
+"&. c #3D3D3D",
+"*. c #393939",
+"=. c #353535",
+"-. c #323232",
+";. c #2C2C2C",
+">. c #F50000",
+",. c #F30000",
+"'. c #F10000",
+"). c #EF0000",
+"!. c #ED0000",
+" ",
+" ",
+". . . . + @ # $ % & * = - ; > , ",
+". ' ' ) ! ~ { ] ^ / ( _ : < [ } ",
+". | 1 2 3 4 5 6 7 8 9 0 a b c d ",
+". ) 2 3 e f g h i j k l m n m o ",
+"+ p q e r g h i j k l m n s n t ",
+"+ u v w x h i j k l m n s y z A ",
+"+ B w C D i j k l m n s y E s A ",
+"F G H D I j k l m n s y E E y J ",
+"K L M I N O P Q R S T U V W X Y ",
+"Z ` ...+. at .#.$.%.&.*.=.-.X ;.Y ",
+">.,.'.).!.Y Y Y Y Y Y Y Y Y Y Y ",
+" ",
+" ",
+" "};
diff --git a/src/images/flags/AF.xpm b/src/images/flags/AF.xpm
new file mode 100644
index 0000000..cda69f6
--- /dev/null
+++ b/src/images/flags/AF.xpm
@@ -0,0 +1,174 @@
+/* XPM */
+static const char *AF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 152 2",
+" c black",
+". c #000001010101",
+"X c #0B0B09090909",
+"o c #000017170000",
+"O c #00001B1B0000",
+"+ c #00001F1F0000",
+"@ c #171700000000",
+"# c #131313131313",
+"$ c #151515151515",
+"% c gray9",
+"& c #191919191919",
+"* c #1B1B1B1B1B1B",
+"= c #000021210000",
+"- c #000025250000",
+"; c #000027270000",
+": c #00002D2D0000",
+"> c #000033330000",
+", c #00003B3B0000",
+"< c gray16",
+"1 c #000045450000",
+"2 c #00004D4D0000",
+"3 c #000053530000",
+"4 c #000067670000",
+"5 c #00006D6D0000",
+"6 c #000075750000",
+"7 c #6F6F15150000",
+"8 c #505050505050",
+"9 c gray34",
+"0 c #585858585858",
+"q c #5F5F5F5F5F5F",
+"w c #656565656565",
+"e c gray40",
+"r c gray42",
+"t c #6D6D6D6D6D6D",
+"y c #6D6D6D6D6E6E",
+"u c gray43",
+"i c #717172727272",
+"p c gray45",
+"a c #747474747474",
+"s c #777777777777",
+"d c #787879797979",
+"f c #79797A7A7A7A",
+"g c gray48",
+"h c #7E7E7E7E7E7E",
+"j c #0F0F91911010",
+"k c #151594941515",
+"l c #151595951414",
+"z c #1D1D98981D1D",
+"x c #1E1E98981E1E",
+"c c #24249C9C2525",
+"v c #24249D9D2424",
+"b c #2D2D9E9E2D2D",
+"n c #31319E9E3131",
+"m c #2C2CA1A12C2C",
+"M c #2D2DA1A12D2D",
+"N c #3131A0A03131",
+"B c #3636A2A23636",
+"V c #3636A3A33636",
+"C c #3535A5A53535",
+"Z c #3636A5A53535",
+"A c #3B3BA5A53B3B",
+"S c #3C3CAAAA3C3C",
+"D c #3E3EAAAA3D3D",
+"F c #4242A9A94242",
+"G c #4545AFAF4545",
+"H c #4949ADAD4949",
+"J c #5050B0B04F4F",
+"K c #5656B4B45656",
+"L c #5D5DB8B85D5D",
+"P c #6464BBBB6464",
+"I c #6A6ABEBE6A6A",
+"U c #929257572323",
+"Y c #97975E5E2A2A",
+"T c #9B9B64643232",
+"R c #A0A069693A3A",
+"E c #A0A06E6E4040",
+"W c #A4A471714343",
+"Q c #A9A978784A4A",
+"! c #AEAE7D7D5353",
+"~ c #CFCF00000000",
+"^ c #D3D300000000",
+"/ c #D7D700000000",
+"( c #DBDB00000000",
+") c #DFDF00000000",
+"_ c #E1E100000000",
+"` c #F5F500000000",
+"' c #F9F900000000",
+"] c #FBFB05050505",
+"[ c #FDFD00000000",
+"{ c #EBEB23232323",
+"} c #EDED2A2A2A2A",
+"| c #EEEE2B2B2B2B",
+" . c #EFEF32323232",
+".. c #F1F139393939",
+"X. c #F1F13C3C3C3C",
+"o. c #EDED40404040",
+"O. c #EEEE46464646",
+"+. c #EDED4F4F5151",
+"@. c #F2F240404040",
+"#. c #F3F344444444",
+"$. c #F0F04B4B4B4B",
+"%. c #F4F448484848",
+"&. c #F5F54C4C4B4B",
+"*. c #F2F252525252",
+"=. c #F5F550505050",
+"-. c #F6F654545454",
+";. c #F2F258585858",
+":. c #F7F759595959",
+">. c #F4F45E5E5F5F",
+",. c #F8F85B5B5B5B",
+"<. c #E7E77B7B7A7A",
+"1. c #F3F36A6A6969",
+"2. c #F9F960606060",
+"3. c #F9F962626262",
+"4. c #FAFA68686868",
+"5. c #FAFA68686969",
+"6. c #FAFA6F6F6F6F",
+"7. c #FBFB6F6F6F6F",
+"8. c #F1F177777676",
+"9. c #F9F976767676",
+"0. c #FCFC75757575",
+"q. c #FBFB7C7C7C7C",
+"w. c #BFBF97977575",
+"e. c #E8E880807E7E",
+"r. c #828283838383",
+"t. c #848484848484",
+"y. c #898989898989",
+"u. c #8E8E8E8E8E8E",
+"i. c #929292929292",
+"p. c gray58",
+"a. c gray59",
+"s. c #969697979696",
+"d. c gray60",
+"f. c #F2F287878585",
+"g. c #F6F683838585",
+"h. c #FBFB81818181",
+"j. c #FCFC86868686",
+"k. c #FCFC8B8B8C8C",
+"l. c #FDFD8F8F8F8F",
+"z. c #EEEEA0A0A1A1",
+"x. c #EEEEB4B4B3B3",
+"c. c #EEEEBDBDBBBB",
+"v. c #F4F4B2B2AFAF",
+"b. c #EEEEC8C8C7C7",
+"n. c #F4F4C1C1C3C3",
+"m. c #F7F7C6C6C5C5",
+"M. c #F0F0C9C9C8C8",
+"N. c #F2F2C9C9C9C9",
+"B. c #F8F8C9C9C9C9",
+"V. c #F9F9CACACACA",
+"C. c #F7F7D3D3D2D2",
+"Z. c None",
+/* pixels */
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"< * * * % [ ] ' ' ` ` 7 6 5 4 4 ",
+"% d.d.s.p.l.k.j.h.q.9.w.I P L 3 ",
+"* d.r.h d 0.7.5.3.:.-.! G D K 2 ",
+"* p.h d a 7.7.V.m.g.&.Q D Z J 1 ",
+"# i.d p u 5.V.f.8.n.#.W Z M H , ",
+"X u.p u w 3.C.c.x.N.X.T M v F > ",
+" y.u w q :.v.N.b.z. .T m z A : ",
+" t.w q 9 =.1.e.<.+.| Y x k Z ; ",
+" h q 9 8 %. at ... .} { U k j N = ",
+" a p t w >.;.*.$.O.o.E V n b o ",
+" _ ) ( / ^ ~ @ ; + O ; ",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z."
+};
diff --git a/src/images/flags/AG.xpm b/src/images/flags/AG.xpm
new file mode 100644
index 0000000..ddcf212
--- /dev/null
+++ b/src/images/flags/AG.xpm
@@ -0,0 +1,169 @@
+/* XPM */
+static const char *AG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 147 2",
+" c black",
+". c #393900000000",
+"X c #2B2B2C2C2D2D",
+"o c #30302C2C2C2C",
+"O c #313131313131",
+"+ c #393937373131",
+"@ c #3A3A39393737",
+"# c #7A7A26262626",
+"$ c #7F7F6F6F3636",
+"% c #535353535353",
+"& c #585857575757",
+"* c #5A5A58585454",
+"= c #585859595A5A",
+"- c #5B5B5A5A5959",
+"; c gray36",
+": c #61614E4E4E4E",
+"> c #64645F5F5F5F",
+", c #656565656060",
+"< c #7C7C77776565",
+"1 c #777777777777",
+"2 c #787877777474",
+"3 c #797979797979",
+"4 c #7B7B7B7B7B7B",
+"5 c #46468484CCCC",
+"6 c #42428A8AD9D9",
+"7 c #47478888D9D9",
+"8 c #4D4D8C8CDADA",
+"9 c #51518F8FDCDC",
+"0 c #5E5E9191CBCB",
+"q c #56569292DDDD",
+"w c #5D5D9898D2D2",
+"e c #5E5E9D9DDCDC",
+"r c #5B5B9A9AE1E1",
+"t c #63639E9ED9D9",
+"y c #68689C9CD7D7",
+"u c #6767A1A1DADA",
+"i c #6D6DA3A3D5D5",
+"p c #6B6BA4A4DCDC",
+"a c #7171A6A6D6D6",
+"s c #7070A8A8DEDE",
+"d c #7575A9A9D8D8",
+"f c #7979ACACDADA",
+"g c #7474AAAAE1E1",
+"h c #7C7CAEAEE0E0",
+"j c #818100000000",
+"k c #ABAB00000000",
+"l c #ADAD00000000",
+"z c #B1B100000000",
+"x c #B3B300000000",
+"c c #B5B500000000",
+"v c #B7B700000000",
+"b c #B9B900000000",
+"n c #BBBB00000000",
+"m c #BDBD00000000",
+"M c #B7B72D2D3B3B",
+"N c #94943F3F5A5A",
+"B c #8C8C7F7F5151",
+"V c #8E8E7B7B7B7B",
+"C c #A3A35C5C5C5C",
+"Z c #B1B149494949",
+"A c #ADAD5D5D7272",
+"S c #C3C300000000",
+"D c #C5C500000000",
+"F c #C9C900000000",
+"G c #CBCB00000000",
+"H c #CFCF00000000",
+"J c #D3D300000000",
+"K c #D5D500000000",
+"L c #D7D700000000",
+"P c #D9D900000000",
+"I c #DBDB00000000",
+"U c #DDDD00000000",
+"Y c #DFDF00000000",
+"T c #CACA24242424",
+"R c #D7D72B2B2424",
+"E c #D8D82F2F2828",
+"W c #D8D82F2F2929",
+"Q c #DADA33332C2C",
+"! c #DADA34342C2C",
+"~ c #DADA34342E2E",
+"^ c #DDDD38383131",
+"/ c #DFDF39393232",
+"( c #DEDE3E3E3737",
+") c #E5E500000000",
+"_ c #E0E039393131",
+"` c #DBDB47474141",
+"' c #DBDB44444444",
+"] c #DDDD4B4B4444",
+"[ c #DDDD4D4D4747",
+"{ c #DEDE4D4D4747",
+"} c #DEDE50504B4B",
+"| c #DFDF54544D4D",
+" . c #CDCD59596464",
+".. c #CECE7B7B7A7A",
+"X. c #D8D860606060",
+"o. c #DBDB66666666",
+"O. c #E4E454544D4D",
+"+. c #E4E454544F4F",
+"@. c #E0E055555050",
+"#. c #E2E259595454",
+"$. c #E5E559595454",
+"%. c #E7E75A5A5454",
+"&. c #E7E75E5E5858",
+"*. c #E7E75E5E5959",
+"=. c #E8E862625E5E",
+"-. c #ECEC63635E5E",
+";. c #E6E667676262",
+":. c #E7E76B6B6666",
+">. c #E9E967676161",
+",. c #EDED6C6C6666",
+"<. c #E8E86F6F6A6A",
+"1. c #E9E974746F6F",
+"2. c #EEEE70706A6A",
+"3. c #EAEA77777373",
+"4. c #ECEC7B7B7676",
+"5. c #EAEA79797979",
+"6. c #EDED7F7F7A7A",
+"7. c #848480807171",
+"8. c #AEAE98984242",
+"9. c #B1B19D9D5151",
+"0. c #B5B5B3B36B6B",
+"q. c #DFDFBFBF3D3D",
+"w. c #CCCCB9B96969",
+"e. c #CDCDBBBB6D6D",
+"r. c #EDED83837E7E",
+"t. c #EAEAC8C83C3C",
+"y. c #DBDBC1C15454",
+"u. c #E4E4C5C54747",
+"i. c #E6E6C8C84C4C",
+"p. c #EAEACACA4B4B",
+"a. c #FAFADEDE4242",
+"s. c #FBFBDFDF4747",
+"d. c #8383AFAFDDDD",
+"f. c #C1C1BFBF8080",
+"g. c #EEEE85858282",
+"h. c #E3E399999999",
+"j. c #F0F089898484",
+"k. c #E9E9A0A09F9F",
+"l. c #EDEDCBCBCACA",
+"z. c #F0F0C9C9C9C9",
+"x. c #F5F5ECECECEC",
+"c. c #F4F4EEEEEEEE",
+"v. c gray96",
+"b. c #F6F6F6F6F6F6",
+"n. c gray97",
+"m. c #F8F8F8F8F8F8",
+"M. c None",
+/* pixels */
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+". ",
+"v V 4 4 1 2 7.e.w.< , ; & % : j ",
+") ..> ; * y.9.i.u.8.q.@ O o Z k ",
+"Y 5.C = * B p.s.a.t.$ + X # ' n ",
+"Y j.2.d.h f.f d i i 0.w 0 ( #.n ",
+"Y g.,. .y r q 9 8 7 6 5 M / @.v ",
+"I r.>.-.A g s u u t e N / Q } z ",
+"I 6.=.*.%.k.m.n.m.b.h.^ ! W [ z ",
+"K 4.*.%.O.O.l.b.b.l.T Q W R ] l ",
+"J 3.3.<.:.;.o.x.c.X.| } [ ] ` l ",
+"K H H D D S m n v v v z z l l z ",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M."
+};
diff --git a/src/images/flags/AI.xpm b/src/images/flags/AI.xpm
new file mode 100644
index 0000000..4221365
--- /dev/null
+++ b/src/images/flags/AI.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *AI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000000003636",
+"X c #000000003939",
+"o c #000000003E3E",
+"O c #000000004141",
+"+ c #000000004444",
+"@ c #000000004949",
+"# c #000000004F4F",
+"$ c #000000005252",
+"% c #000000005757",
+"& c #000000005A5A",
+"* c #000000005F5F",
+"= c #000000006868",
+"- c #000000006D6D",
+"; c #000000007070",
+": c #000000007676",
+"> c #000001017E7E",
+", c #00000B0B8484",
+"< c #000012128989",
+"1 c #000016169191",
+"2 c #00001B1B9191",
+"3 c #00001E1E9797",
+"4 c #000022229797",
+"5 c #000025259999",
+"6 c #000027279C9C",
+"7 c #00002E2EA2A2",
+"8 c #00004B4BB4B4",
+"9 c #00005B5BBABA",
+"0 c #00005E5EBBBB",
+"q c #11115B5BB9B9",
+"w c #2B2B6060B7B7",
+"e c #2C2C7676B7B7",
+"r c #29297575BEBE",
+"t c #34347F7FC3C3",
+"y c #5F5F5A5AA6A6",
+"u c #4E4E6464B4B4",
+"i c #5D5D6868B6B6",
+"p c #2D2D8080C4C4",
+"a c #30308181C5C5",
+"s c #33338585C6C6",
+"d c #3A3A8484C2C2",
+"f c #3A3A8686C5C5",
+"g c #3F3F8888C6C6",
+"h c #3F3F8989C7C7",
+"j c #39398B8BC8C8",
+"k c #5A5A8686B8B8",
+"l c #41418989C7C7",
+"z c #44448D8DC8C8",
+"x c #45458E8EC8C8",
+"c c #4A4A8686C4C4",
+"v c #47479191C7C7",
+"b c #46469191C9C9",
+"n c #46469292CACA",
+"m c #48489292CACA",
+"M c #4A4A9191C9C9",
+"N c #4B4B9191C9C9",
+"B c #4C4C9292C8C8",
+"V c #4C4C9595CBCB",
+"C c #4D4D9595CBCB",
+"Z c #4E4E9494C9C9",
+"A c #4F4F9595CACA",
+"S c #4C4C9696CCCC",
+"D c #56569595C7C7",
+"F c #50509696CBCB",
+"G c #52529595CBCB",
+"H c #50509898CCCC",
+"J c #51519999CCCC",
+"K c #52529999CDCD",
+"L c #53539898CCCC",
+"P c #52529898CECE",
+"I c #54549999CECE",
+"U c #54549A9ACCCC",
+"Y c #55559B9BCECE",
+"T c #56569B9BCCCC",
+"R c #57579B9BCECE",
+"E c #55559C9CCECE",
+"W c #56569C9CCECE",
+"Q c #58589D9DCFCF",
+"! c #59599E9ECFCF",
+"~ c #5A5A9D9DCECE",
+"^ c #5B5B9D9DCECE",
+"/ c #5C5C9D9DCECE",
+"( c #5A5A9E9ED0D0",
+") c #5D5DA0A0CFCF",
+"_ c #5F5FA0A0CFCF",
+"` c #5C5CA0A0D1D1",
+"' c #5D5DA0A0D1D1",
+"] c #4A4AB4B4E6E6",
+"[ c #4D4DB6B6E5E5",
+"{ c #5555B5B5E3E3",
+"} c #6666A0A0CFCF",
+"| c #6262A1A1D0D0",
+" . c #6262A2A2D0D0",
+".. c #6262A3A3D3D3",
+"X. c #6565A4A4D2D2",
+"o. c #6666A4A4D2D2",
+"O. c #6868A5A5D3D3",
+"+. c #6A6AA6A6D3D3",
+"@. c #6A6AA7A7D4D4",
+"#. c #6B6BA6A6D4D4",
+"$. c #6E6EA9A9D4D4",
+"%. c #7171A8A8D4D4",
+"&. c #7171ABABD6D6",
+"*. c #7474ACACD6D6",
+"=. c #7575ACACD7D7",
+"-. c #7777ADADD7D7",
+";. c #7979AEAED8D8",
+":. c #7B7BB0B0D9D9",
+">. c #7C7CB1B1D9D9",
+",. c #7D7DB2B2D9D9",
+"<. c #7F7FB0B0D9D9",
+"1. c #6161BBBBE6E6",
+"2. c #6464BDBDE6E6",
+"3. c #6868BFBFE7E7",
+"4. c #D2D254546D6D",
+"5. c #A9A956568181",
+"6. c #B0B059598181",
+"7. c #C9C96C6C8989",
+"8. c #F8F8D8D86B6B",
+"9. c #F9F9DFDF7E7E",
+"0. c #91919B9BBDBD",
+"q. c #ADAD83839E9E",
+"w. c #B0B080809A9A",
+"e. c #B0B09090AAAA",
+"r. c #8888A8A8CECE",
+"t. c #8181B3B3DBDB",
+"y. c #9E9EB1B1D2D2",
+"u. c #9797CDCDEFEF",
+"i. c #9E9EC7C7EAEA",
+"p. c #A7A7CACAEAEA",
+"a. c #AEAED4D4F2F2",
+"s. c #DFDF9494A1A1",
+"d. c #EFEF81818888",
+"f. c #E5E593939D9D",
+"g. c #FEFE81818686",
+"h. c #FFFF87878B8B",
+"j. c #FFFF8A8A8E8E",
+"k. c #F8F888889090",
+"l. c #FBFB91919595",
+"z. c #FCFC90909595",
+"x. c #FFFF94949898",
+"c. c #EAEAA0A0AAAA",
+"v. c #FFFFAAAAAEAE",
+"b. c #FFFFADADB0B0",
+"n. c #F7F7B1B1BABA",
+"m. c #F4F4B4B4BDBD",
+"M. c #FFFFBEBEBFBF",
+"N. c #F5F5BABAC2C2",
+"B. c #F7F7E2E29696",
+"V. c #F5F5E5E5A7A7",
+"C. c #F6F6E6E6A7A7",
+"Z. c #D4D4CACADCDC",
+"A. c #FFFFC5C5CACA",
+"S. c #F9F9DCDCE5E5",
+"D. c #EDEDF3F3F8F8",
+"F. c #FFFFE5E5EFEF",
+"G. c #F9F9EEEEEDED",
+"H. c #F9F9EFEFEFEF",
+"J. c #F0F0F5F5FAFA",
+"K. c #FDFDF6F6F5F5",
+"L. c #FEFEFAFAF9F9",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"i q 0 5.6.9 c 7.5 3 1 < , > : ; ",
+"w S.a.N.n.p.A.i.<.;.-.%.#.O.X.= ",
+"4.v.x.h.g.j.k.d.} W O.>.-.) .* ",
+"y Z.M.z.l.b.c.e./ K J.H.H.D.^ % ",
+"8 F.y.s.f.u.m.k R S C.9.L.B.R $ ",
+"u r.f q.q.e D 0.G b C.K.8.C.K @ ",
+"7 t...` ^ E K V m h 1.3.2.{ G + ",
+"6 ,.( ( R Z S b x g j [ ] t Z o ",
+"4 >.( W K Z b z h f t s t r m X ",
+"2 -.$.$.O.X. .} ^ T K G n m v . ",
+"< , > : - = * & $ # @ O o X . . ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/AL.xpm b/src/images/flags/AL.xpm
new file mode 100644
index 0000000..e58fb3f
--- /dev/null
+++ b/src/images/flags/AL.xpm
@@ -0,0 +1,176 @@
+/* XPM */
+static const char *AL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 154 2",
+" c black",
+". c #2F2F2F2F2F2F",
+"X c #3D3D27272525",
+"o c #373736363636",
+"O c #3F3F37373636",
+"+ c gray24",
+"@ c #3E3E3D3D3E3E",
+"# c #40403F3F3E3E",
+"$ c #47473E3E3D3D",
+"% c #54543C3C3A3A",
+"& c #656531312D2D",
+"* c #64643A3A3434",
+"= c #6E6E3A3A3636",
+"- c #71713A3A3434",
+"; c #727239393535",
+": c #434343434343",
+"> c #444444444444",
+", c gray27",
+"< c gray29",
+"1 c #5B5B46464444",
+"2 c #5F5F4D4D4C4C",
+"3 c #505051515151",
+"4 c #555551515050",
+"5 c #565656565656",
+"6 c #5B5B52525252",
+"7 c #5F5F58585858",
+"8 c #5E5E5D5D5D5D",
+"9 c #707047474343",
+"0 c #797956565454",
+"q c #79795B5B5959",
+"w c #959500000000",
+"e c #9D9D00000000",
+"r c #9F9F00000000",
+"t c #959539393131",
+"y c #A3A300000000",
+"u c #A7A700000000",
+"i c #A9A900000000",
+"p c #ADAD00000000",
+"a c #AFAF00000000",
+"s c #B1B100000000",
+"d c #B7B700000000",
+"f c #B9B900000000",
+"g c #BBBB00000000",
+"h c #BDBD00000000",
+"j c #80804B4B4848",
+"k c #8F8F63635F5F",
+"l c #808070706F6F",
+"z c #8D8D7E7E7C7C",
+"x c #90906C6C6969",
+"c c #ABAB48484141",
+"v c #B7B74A4A4040",
+"b c #B3B35B5B5353",
+"n c #B3B363635C5C",
+"m c #BABA6A6A6363",
+"M c #C1C100000000",
+"N c #C3C300000000",
+"B c #C5C500000000",
+"V c #C7C700000000",
+"C c #C9C900000000",
+"Z c #CDCD00000000",
+"A c #CFCF00000000",
+"S c #D1D100000000",
+"D c #D3D300000000",
+"F c #D5D500000000",
+"G c #D7D700000000",
+"H c #D7D701010000",
+"J c #D5D507070000",
+"K c #D7D707070000",
+"L c #D3D309090000",
+"P c #D7D709090000",
+"I c #DBDB00000000",
+"U c #DBDB05050000",
+"Y c #D4D42B2B1B1B",
+"T c #D5D52E2E1F1F",
+"R c #CFCF3D3D3030",
+"E c #D6D633332424",
+"W c #D5D534342525",
+"Q c #D7D734342525",
+"! c #D6D639392B2B",
+"~ c #D8D839392A2A",
+"^ c #D8D839392B2B",
+"/ c #D9D939392A2A",
+"( c #DADA3F3F3131",
+") c #DBDB3E3E3030",
+"_ c #C8C841413535",
+"` c #CFCF42423535",
+"' c #D9D940403232",
+"] c #D8D846463838",
+"[ c #DADA46463838",
+"{ c #DCDC45453838",
+"} c #D9D949493B3B",
+"| c #D9D949493C3C",
+" . c #DCDC4C4C3F3F",
+".. c #DEDE4C4C3E3E",
+"X. c #C4C45C5C5252",
+"o. c #DBDB4B4B4040",
+"O. c #DBDB4D4D4040",
+"+. c #D3D352524747",
+"@. c #DBDB50504343",
+"#. c #DDDD50504444",
+"$. c #DDDD54544747",
+"%. c #DDDD55554949",
+"&. c #DFDF58584B4B",
+"*. c #DEDE5A5A4E4E",
+"=. c #D3D35D5D5353",
+"-. c #DDDD64645959",
+";. c #C3C36F6F6868",
+":. c #E0E052524545",
+">. c #E1E154544747",
+",. c #E4E450504242",
+"<. c #E3E359594D4D",
+"1. c #E1E15B5B5050",
+"2. c #E3E35C5C5151",
+"3. c #E3E35F5F5353",
+"4. c #E0E060605353",
+"5. c #E2E260605555",
+"6. c #E6E660605353",
+"7. c #E2E264645858",
+"8. c #E2E265655B5B",
+"9. c #E5E565655959",
+"0. c #E3E369695E5E",
+"q. c #E3E36A6A5F5F",
+"w. c #E7E76A6A5F5F",
+"e. c #E5E56E6E6363",
+"r. c #E5E56F6F6565",
+"t. c #E9E96C6C6060",
+"y. c #E8E86F6F6565",
+"u. c #E7E773736868",
+"i. c #E5E575756B6B",
+"p. c #E7E774746A6A",
+"a. c #E6E677776E6E",
+"s. c #ECEC70706666",
+"d. c #E8E874746969",
+"f. c #EDED75756A6A",
+"g. c #E8E879796F6F",
+"h. c #EAEA78786E6E",
+"j. c #EEEE79796F6F",
+"k. c #E9E97B7B7272",
+"l. c #EBEB7D7D7373",
+"z. c #E9E97D7D7474",
+"x. c #EFEF7E7E7373",
+"c. c #E3E384847B7B",
+"v. c #E1E187877E7E",
+"b. c #ECEC80807676",
+"n. c #EAEA82827878",
+"m. c #ECEC85857D7D",
+"M. c #ECEC8A8A8181",
+"N. c #EDED8E8E8585",
+"B. c #EDED92928A8A",
+"V. c #EEEE91918989",
+"C. c #EFEF94948C8C",
+"Z. c #F1F18F8F8787",
+"A. c #F0F097978F8F",
+"S. c None",
+/* pixels */
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"L K P P U H I D D D Z C V M M f ",
+"P A.C.C.C.N.z v.c.l k.a.u.e.0.d ",
+"P A.b.x.x a.m 7 6 b 2.9 :. .7.s ",
+"K C.l.j.;.8 5 4 2 , # c .[ 4.p ",
+"H V.h.f.k q 3 < , @ % - { ' *.p ",
+"I N.p.y.n 0 X.> @ v * t ' ! %.s ",
+"H M.y.t.-.=.j $ O - _ R ^ Q #.i ",
+"Z m.t.9.6.1 +.o . ` X ^ Q T O.r ",
+"Z n.9.3.<.>.,.- & ^ ^ Q T Y | r ",
+"Z z.k.u.r.0.7.5.1.&.$. at .O.} ] r ",
+"V V V M h h d s p u u u y r e w ",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S."
+};
diff --git a/src/images/flags/AM.xpm b/src/images/flags/AM.xpm
new file mode 100644
index 0000000..b75927b
--- /dev/null
+++ b/src/images/flags/AM.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *AM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000000005B5B",
+"X c #000000006363",
+"o c #030303039B9B",
+"O c #090909099B9B",
+"+ c #0F0F0F0F9F9F",
+"@ c #42424242ADAD",
+"# c #46464646AFAF",
+"$ c #47474747AEAE",
+"% c #4B4B4B4BB0B0",
+"& c #4B4B4B4BB1B1",
+"* c #50505050B3B3",
+"= c #50505050B4B4",
+"- c #53535353B6B6",
+"; c #54545555B5B5",
+": c #55555555B6B6",
+"> c #58585858B7B7",
+", c #58585858B8B8",
+"< c #59595959B8B8",
+"1 c #5D5D5D5DB9B9",
+"2 c #5C5C5C5CBBBB",
+"3 c #5D5D5D5DBABA",
+"4 c #5E5E5E5EBABA",
+"5 c #60606060B9B9",
+"6 c #61616161BCBC",
+"7 c #61616161BDBD",
+"8 c #62626262BDBD",
+"9 c #65656565BCBC",
+"0 c #66666666BEBE",
+"q c #66666666BFBF",
+"w c #66666666C0C0",
+"e c #6A6A6A6AC1C1",
+"r c #6B6B6B6BC1C1",
+"t c #6A6A6A6AC2C2",
+"y c #6F6F6E6EC3C3",
+"u c #6E6E6E6EC4C4",
+"i c #6F6F6F6FC4C4",
+"p c #72727272C5C5",
+"a c #72727272C6C6",
+"s c #73737373C6C6",
+"d c #76767676C7C7",
+"f c #77777777C7C7",
+"g c #79797A7AC9C9",
+"h c #E3E300000000",
+"j c #E5E500000000",
+"k c #E9E900000000",
+"l c #EBEB00000000",
+"z c #EDED00000000",
+"x c #EFEF00000000",
+"c c #F1F100000000",
+"v c #F3F300000000",
+"b c #F5F500000000",
+"n c #F7F700000000",
+"m c #F7F703030303",
+"M c #F7F709090909",
+"N c #FBFB05050505",
+"B c #F9F90D0D0D0D",
+"V c #FBFB13131313",
+"C c #FBFB15151515",
+"Z c #FBFB25252525",
+"A c #D7D749490000",
+"S c #D7D74B4B0000",
+"D c #D9D94F4F0000",
+"F c #D7D755550000",
+"G c #D9D951510000",
+"H c #D9D955550000",
+"J c #DDDD55550000",
+"K c #D9D959590000",
+"L c #DFDF59590000",
+"P c #DFDF5D5D0000",
+"I c #E1E161610000",
+"U c #E3E365650000",
+"Y c #E7E76B6B0000",
+"T c #E9E96F6F0000",
+"R c #EBEB73730000",
+"E c #EDED79790000",
+"W c #EFEF7D7D0000",
+"Q c #F4F453535252",
+"! c #F4F457575757",
+"~ c #F5F557575757",
+"^ c #F5F55C5C5B5B",
+"/ c #F5F55C5C5C5C",
+"( c #F6F660605F5F",
+") c #F6F661616161",
+"_ c #F7F764646464",
+"` c #F7F765656565",
+"' c #F4F46A6A6A6A",
+"] c #F6F66F6F6F6F",
+"[ c #F8F868686868",
+"{ c #F9F96D6D6D6D",
+"} c #F7F773737373",
+"| c #F7F776767676",
+" . c #FAFA71717171",
+".. c #FBFB75757575",
+"X. c #F8F87A7A7A7A",
+"o. c #FBFB78787878",
+"O. c #FBFB79797979",
+"+. c #FBFB7B7B7B7B",
+"@. c #FBFB7B7B7C7C",
+"#. c #F8F87E7E7E7E",
+"$. c #FCFC7E7E7E7E",
+"%. c #F1F183830000",
+"&. c #F3F389890000",
+"*. c #F1F18D8D0000",
+"=. c #F5F597970000",
+"-. c #F7F795950000",
+";. c #EEEEACAC3B3B",
+":. c #EFEFAEAE3F3F",
+">. c #EFEFB0B04343",
+",. c #EFEFB1B15555",
+"<. c #EFEFB3B35757",
+"1. c #EFEFB8B85959",
+"2. c #F0F0B0B04343",
+"3. c #F0F0B2B24747",
+"4. c #F0F0B2B24848",
+"5. c #F1F1B4B44B4B",
+"6. c #F3F3B7B74F4F",
+"7. c #F3F3B7B75050",
+"8. c #F1F1B3B35B5B",
+"9. c #F2F2B5B55E5E",
+"0. c #F4F4B9B95454",
+"q. c #F4F4B9B95555",
+"w. c #F1F1B9B95B5B",
+"e. c #F5F5BBBB5959",
+"r. c #F6F6BEBE5E5E",
+"t. c #F2F2B8B86161",
+"y. c #F2F2B9B96464",
+"u. c #F3F3BBBB6767",
+"i. c #F5F5BDBD6B6B",
+"p. c #F6F6BFBF6F6F",
+"a. c #F7F7C0C06262",
+"s. c #F8F8C3C36666",
+"d. c #F8F8C3C36767",
+"f. c #F9F9C5C56B6B",
+"g. c #FAFAC6C66F6F",
+"h. c #F7F7C1C17373",
+"j. c #F7F7C3C37777",
+"k. c #F8F8C5C57B7B",
+"l. c #F9F9C8C87F7F",
+"z. c #8C8C8C8CD0D0",
+"x. c #8F8F8F8FD1D1",
+"c. c #91919191D3D3",
+"v. c #F9F981818181",
+"b. c #FAFA84848484",
+"n. c #FCFC81818181",
+"m. c #FBFB88888888",
+"M. c #FCFC8B8B8B8B",
+"N. c #FCFC8F8F8F8F",
+"B. c #FCFC91919191",
+"V. c #FCFC94949494",
+"C. c #FCFC95959595",
+"Z. c #FDFD97979696",
+"A. c #FDFD97979797",
+"S. c #FAFAC9C98383",
+"D. c #FBFBCFCF8686",
+"F. c #FBFBD1D18A8A",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"Z C C C V B M m m m v v v z z l ",
+"V A.Z.A.V.B.N.M.M.n.v.#.O.| } l ",
+"C A.n.$.O.O... .{ ' ` ) / ! ] h ",
+"N A.$.O.O... .{ [ ) ( ^ ! Q ' h ",
+"+ c.g d s i r q 8 4 < ; * % q X ",
+"O x.d s i r q 8 4 < , - % # 4 . ",
+"o z.s y r w 4 2 , - & % # @ 4 . ",
+"-.F.g.f.d.u.r.e.q.7.5.5.>.:.w.H ",
+"-.D.f.s.a.r.e.q.6.5.>.>.:.;.1.K ",
+"&.S.l.k.j.p.p.p.y.y.t.9.8.<.<.A ",
+"*.%.W E R R Y U I P L J G D A F ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/AN.xpm b/src/images/flags/AN.xpm
new file mode 100644
index 0000000..446d38d
--- /dev/null
+++ b/src/images/flags/AN.xpm
@@ -0,0 +1,136 @@
+/* XPM */
+static const char *AN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 114 2",
+" c black",
+". c #000000002525",
+"X c #000000002D2D",
+"o c #000000003131",
+"O c #000000007373",
+"+ c #000000007777",
+"@ c #000000007979",
+"# c #141414149797",
+"$ c #191919199999",
+"% c #1A1A1A1A9C9C",
+"& c #1F1F1F1F9C9C",
+"* c #1F1F1F1F9E9E",
+"= c #202020209E9E",
+"- c #242424249D9D",
+"; c #25252525A0A0",
+": c #25252525A1A1",
+"> c #2B2B2B2BA4A4",
+", c #36363636A6A6",
+"< c #31313333ABAB",
+"1 c #36363636ABAB",
+"2 c #37373737ABAB",
+"3 c #36363737ACAC",
+"4 c #3B3B3B3BA9A9",
+"5 c #3B3B3B3BADAD",
+"6 c #3F3F3F3FABAB",
+"7 c #40404040ABAB",
+"8 c #43434444B2B2",
+"9 c #45454545B0B0",
+"0 c #46464848B4B4",
+"q c #49494A4AB2B2",
+"w c #4B4B4A4AB4B4",
+"e c #4F4F4F4FB5B5",
+"r c #4F4F4F4FB6B6",
+"t c #50504F4FB6B6",
+"y c #50505050B7B7",
+"u c #53535353B9B9",
+"i c #54545454B8B8",
+"p c #58585858BABA",
+"a c #6F6F6F6FC3C3",
+"s c #72727272C6C6",
+"d c #76767676C7C7",
+"f c #D3D300000000",
+"g c #D7D700000000",
+"h c #D9D900000000",
+"j c #EBEB00000000",
+"k c #EDED00000000",
+"l c #EFEF00000000",
+"z c #F4F41E1E1E1E",
+"x c #F5F523232323",
+"c c #F5F524242424",
+"v c #F6F629292929",
+"b c #F6F62A2A2A2A",
+"n c #F7F72E2E2E2E",
+"m c #F7F72F2F2F2F",
+"M c #F5F53D3D3D3D",
+"N c #F8F834343434",
+"B c #F9F93C3C3C3C",
+"V c #F6F642424242",
+"C c #F7F746464646",
+"Z c #F7F74B4B4B4B",
+"A c #FAFA41414242",
+"S c #FAFA42424242",
+"D c #FBFB47474747",
+"F c #FCFC4B4B4B4B",
+"G c #FCFC4C4C4C4C",
+"H c #FDFD51515151",
+"J c #FCFC65656565",
+"K c #FCFC69696969",
+"L c #FDFD6D6D6D6D",
+"P c #FDFD70707171",
+"I c #83838585CBCB",
+"U c #8C8C8E8ED0D0",
+"Y c #B6B6B6B6DDDD",
+"T c #B9B9BABAE1E1",
+"R c #BBBBBCBCE2E2",
+"E c #CBCBCBCBCBCB",
+"W c #CFCFCDCDCDCD",
+"Q c gray81",
+"! c #D1D1CDCDCDCD",
+"~ c #D7D7D7D7D7D7",
+"^ c gray85",
+"/ c #DDDDDDDDDDDD",
+"( c #DFDFDFDFDFDF",
+") c #CDCDCDCDE7E7",
+"_ c #CFCFD0D0E9E9",
+"` c #D7D7D7D7EDED",
+"' c #E1E1E1E1E1E1",
+"] c gray89",
+"[ c gray90",
+"{ c #E7E7E7E7E7E7",
+"} c #E9E9E7E7E7E7",
+"| c #E9E9E9E9E9E9",
+" . c gray92",
+".. c gray93",
+"X. c #EFEFEFEFF1F1",
+"o. c #F1F1F1F1F1F1",
+"O. c gray95",
+"+. c #F2F2F2F2F3F3",
+"@. c #F3F3F3F3F3F3",
+"#. c #F4F4F2F2F2F2",
+"$. c #F4F4F4F4F4F4",
+"%. c gray96",
+"&. c #F6F6F6F6F6F6",
+"*. c gray97",
+"=. c #F8F8F8F8F8F8",
+"-. c #F9F9F9F9F9F9",
+";. c gray98",
+":. c #FBFBFAFAFAFA",
+">. c #FBFBFBFBFBFB",
+",. c gray99",
+"<. c #FDFDFDFDFDFD",
+"1. c #FEFEFEFEFEFE",
+"2. c gray100",
+"3. c None",
+/* pixels */
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"o.o.o.o.o.o.k k k j } { } ] ' ` ",
+"o.2.2.2.2.2.P L K J :.:.:.*.*./ ",
+"o.2.2.2.2.:.H G D V =.:.*.&.*.^ ",
+"o.2.2.2.>.2.F D V B :.&.&.&.*.~ ",
+"@ d i i e r 9 R T 2 2 > - = 7 X ",
+"O s u e w ` 8 4 2 < Y : & % 4 X ",
+"O a e q 9 7 U _ ) I - & $ # , . ",
+"..2.>.>.>.>.N m b c $.$.o. at .$.Q ",
+"| >.>.>.>.&.m b x z #.o.o.o.o.E ",
+"| >.>.:.:.:.D C V M #. at .@. at .o.E ",
+"{ [ ] ( ` / h g g f ! Q W E E E ",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3."
+};
diff --git a/src/images/flags/AO.xpm b/src/images/flags/AO.xpm
new file mode 100644
index 0000000..ba0b551
--- /dev/null
+++ b/src/images/flags/AO.xpm
@@ -0,0 +1,138 @@
+/* XPM */
+static const char *AO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 116 2",
+" c black",
+". c gray11",
+"X c #1D1D1D1D1D1D",
+"o c #1E1E1E1E1E1E",
+"O c gray12",
+"+ c #202020202020",
+"@ c gray13",
+"# c #222222222222",
+"$ c #232323232323",
+"% c gray15",
+"& c #282828282828",
+"* c #2A2A2A2A2A2A",
+"= c gray17",
+"- c #2C2C2C2C2C2C",
+"; c #2D2D2D2D2D2D",
+": c gray18",
+"> c #2F2F2F2F2F2F",
+", c gray19",
+"< c #313131313131",
+"1 c #323232323232",
+"2 c gray20",
+"3 c #343434343434",
+"4 c #353535353535",
+"5 c gray21",
+"6 c #373737373737",
+"7 c gray22",
+"8 c #393939393939",
+"9 c #3A3A3A3A3A3A",
+"0 c gray23",
+"q c #3C3C3C3C3C3C",
+"w c gray24",
+"e c #3F3F3F3F3F3F",
+"r c #6D6D6D6D2F2F",
+"t c #7F7F7F7F3131",
+"y c gray25",
+"u c #434343434343",
+"i c #888826262626",
+"p c #A3A327272727",
+"a c #A5A527272727",
+"s c #A8A827272727",
+"d c #ABAB27272727",
+"f c #B1B127272727",
+"g c #B5B528282828",
+"h c #B8B828282828",
+"j c #BABA28282828",
+"k c #BEBE28282828",
+"l c #BFBF29292929",
+"z c #80807F7F2B2B",
+"x c #C3C328282828",
+"c c #C4C428282828",
+"v c #C6C628282828",
+"b c #C7C728282828",
+"n c #CCCC29292929",
+"m c #CECE29292929",
+"M c #EBEB27272727",
+"N c #EBEB2B2B2B2B",
+"B c #ECEC31313131",
+"V c #ECEC32323232",
+"C c #ECEC34343434",
+"Z c #EDED38383838",
+"A c #EDED3A3A3A3A",
+"S c #EDED3C3C3C3C",
+"D c #EDED3F3F3F3F",
+"F c #EDED41414141",
+"G c #EEEE45454545",
+"H c #EEEE47474747",
+"J c #EEEE4F4F4747",
+"K c #EEEE48484848",
+"L c #EEEE4C4C4C4C",
+"P c #EFEF5A5A4040",
+"I c #EFEF50505050",
+"U c #EFEF53535353",
+"Y c #EFEF55555555",
+"T c #F0F059595959",
+"R c #F0F05B5B5B5B",
+"E c #F0F05E5E5E5E",
+"W c #F0F064645F5F",
+"Q c #F0F068685959",
+"! c #F0F060606060",
+"~ c #F0F061616060",
+"^ c #F0F062626262",
+"/ c #F1F164646464",
+"( c #F1F166666666",
+") c #F1F169696969",
+"_ c #F1F16D6D6D6D",
+"` c #F2F26F6F6F6F",
+"' c #F2F273737373",
+"] c #F2F276767676",
+"[ c #F3F37C7C7C7C",
+"{ c #F3F37F7F7F7F",
+"} c #838381812D2D",
+"| c #858585853030",
+" . c #ADADADAD2F2F",
+".. c #B9B9B7B72E2E",
+"X. c #F3F3B0B03939",
+"o. c #F1F184844646",
+"O. c #F1F181815151",
+"+. c #C8C8C8C82C2C",
+"@. c #CCCCCCCC2C2C",
+"#. c #D8D8D5D52B2B",
+"$. c #F4F4C1C13131",
+"%. c #F4F4C8C83535",
+"&. c #F4F4D0D02E2E",
+"*. c #F5F5D7D73030",
+"=. c #F5F5D8D83131",
+"-. c #E6E6E3E32C2C",
+";. c #F5F5E6E62E2E",
+":. c #F6F6F1F12B2B",
+">. c #F6F6F2F22B2B",
+",. c #F3F381818181",
+"<. c #F3F383838383",
+"1. c #F4F485858585",
+"2. c #F4F487878787",
+"3. c #F4F489898989",
+"4. c #F4F48A8A8A8A",
+"5. c None",
+/* pixels */
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"m m m m n c c x x l l j h g f f ",
+"m 4.4.2.2.<.{ [ ' ' ' ) ( ^ T d ",
+"n 4._ _ ( ( W O.;.o.K K F S Y d ",
+"n 2._ ) ( ! Q :.%.>.H S A C I p ",
+"v <.( ^ E T =.I J $.A A B N K p ",
+"l { ( E R U X.&.P *.Z B N M H i ",
+"% u 9 9 7 .| ..-.r < ; ; ; 3 + ",
+"+ y 7 4 4 | @.+.z #.; * * & , . ",
+"+ y 4 4 2 < < , > ; t * & & , . ",
+"$ e w 9 9 9 4 6 4 3 < < , ; , . ",
+"+ + + @ + + O . . O . . . . . . ",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5."
+};
diff --git a/src/images/flags/AR.xpm b/src/images/flags/AR.xpm
new file mode 100644
index 0000000..c2322bf
--- /dev/null
+++ b/src/images/flags/AR.xpm
@@ -0,0 +1,173 @@
+/* XPM */
+static const char *AR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 151 2",
+" c black",
+". c #00008181DDDD",
+"X c #00008181DFDF",
+"o c #00008383DDDD",
+"O c #00008787DDDD",
+"+ c #00008787DFDF",
+"@ c #00008989DDDD",
+"# c #00008B8BE1E1",
+"$ c #00008F8FE3E3",
+"% c #00009191E5E5",
+"& c #00009393E7E7",
+"* c #00009797E9E9",
+"= c #00009999E9E9",
+"- c #00009D9DEBEB",
+"; c #03039F9FEDED",
+": c #0B0BA3A3EDED",
+"> c #1313A7A7EFEF",
+", c #1919A9A9EFEF",
+"< c #1919ABABF1F1",
+"1 c #2121AFAFF3F3",
+"2 c #2727B1B1F5F5",
+"3 c #2B2BB3B3F7F7",
+"4 c #2D2DB3B3F7F7",
+"5 c #2929B5B5F9F9",
+"6 c #3333B5B5F5F5",
+"7 c #3535B7B7F9F9",
+"8 c #3939B9B9FBFB",
+"9 c #3F3FBDBDFDFD",
+"0 c #4343BDBDFDFD",
+"q c #4343BFBFFFFF",
+"w c #5F5FBFBFF1F1",
+"e c #4545C1C1FDFD",
+"r c #4B4BC3C3FDFD",
+"t c #4B4BC3C3FFFF",
+"y c #4D4DC3C3FFFF",
+"u c #5959C7C7FFFF",
+"i c #6262C1C1F1F1",
+"p c #6666C3C3F2F2",
+"a c #6969C5C5F3F3",
+"s c #6D6DC7C7F4F4",
+"d c #7171C9C9F5F5",
+"f c #7777C8C8F2F2",
+"g c #7575CBCBF6F6",
+"h c #7777CCCCF6F6",
+"j c #7B7BCACAF2F2",
+"k c #7878CCCCF7F7",
+"l c #7B7BCECEF7F7",
+"z c #7C7CCACAF2F2",
+"x c #7F7FCCCCF3F3",
+"c c #7C7CCECEF8F8",
+"v c #7F7FD0D0F8F8",
+"b c #F5F5E2E24646",
+"n c #F6F6E4E44B4B",
+"m c #F5F5E2E25B5B",
+"M c #F6F6E3E36161",
+"N c #F6F6E5E56868",
+"B c #F7F7E6E66868",
+"V c #F8F8E6E66C6C",
+"C c #FAFAEBEB7575",
+"Z c #9696BDBDCECE",
+"A c #9F9FC2C2D5D5",
+"S c #8282CDCDF3F3",
+"D c #8484CFCFF4F4",
+"F c #8686D0D0F5F5",
+"G c #8080D0D0F9F9",
+"H c #8282D2D2F9F9",
+"J c #8383D2D2FAFA",
+"K c #8686D3D3FAFA",
+"L c #8787D4D4FAFA",
+"P c #8A8AD2D2F6F6",
+"I c #8A8AD3D3F7F7",
+"U c #8D8DD3D3F7F7",
+"Y c #8A8AD5D5FBFB",
+"T c #8E8ED7D7FCFC",
+"R c #9090D5D5F7F7",
+"E c #9393D7D7F7F7",
+"W c #9393D7D7F8F8",
+"Q c #9090D8D8FDFD",
+"! c #9393DADAFDFD",
+"~ c #9696D8D8F8F8",
+"^ c #9696D8D8F9F9",
+"/ c #9696DBDBFEFE",
+"( c #9999D9D9F9F9",
+") c #9999DADAF9F9",
+"_ c #9B9BDBDBFAFA",
+"` c #9898DCDCFEFE",
+"' c #9A9ADDDDFEFE",
+"] c #9C9CDBDBFAFA",
+"[ c #9E9EDDDDFBFB",
+"{ c #9F9FDDDDFBFB",
+"} c #9E9EDDDDFCFC",
+"| c #A1A1DDDDFCFC",
+" . c #A4A4DFDFFCFC",
+".. c #BFBFDADAE7E7",
+"X. c #A7A7E0E0FDFD",
+"o. c #A9A9E2E2FEFE",
+"O. c #ABABE2E2FEFE",
+"+. c #ABABE2E2FFFF",
+"@. c #ADADE3E3FEFE",
+"#. c #AEAEE4E4FEFE",
+"$. c #B0B0E4E4FFFF",
+"%. c #F6F6EEEEABAB",
+"&. c #F8F8F0F0B1B1",
+"*. c #F9F9F1F1B3B3",
+"=. c #FBFBF3F3B9B9",
+"-. c gray82",
+";. c LightGray",
+":. c #D5D5D5D5D5D5",
+">. c #C2C2DCDCEBEB",
+",. c #D2D2E6E6F2F2",
+"<. c #D4D4E8E8F2F2",
+"1. c #D5D5E9E9F3F3",
+"2. c #D6D6EAEAF4F4",
+"3. c #D8D8EAEAF3F3",
+"4. c #D8D8ECECF5F5",
+"5. c #DADAECECF6F6",
+"6. c #DADAEDEDF6F6",
+"7. c #DBDBEEEEF7F7",
+"8. c #DCDCEDEDF7F7",
+"9. c #DDDDEDEDF6F6",
+"0. c #DDDDEFEFF8F8",
+"q. c #DEDEF1F1F9F9",
+"w. c #DFDFF0F0F9F9",
+"e. c #DFDFF1F1FAFA",
+"r. c #E9E9E9E9E9E9",
+"t. c #E0E0F1F1FAFA",
+"y. c #E0E0F2F2FBFB",
+"u. c #E2E2F2F2FBFB",
+"i. c #E3E3F3F3FBFB",
+"p. c #E2E2F4F4FCFC",
+"a. c #E3E3F4F4FDFD",
+"s. c #E5E5F5F5FDFD",
+"d. c #E5E5F6F6FEFE",
+"f. c #E6E6F6F6FEFE",
+"g. c #E9E9F6F6FCFC",
+"h. c #EBEBF8F8FEFE",
+"j. c gray95",
+"k. c #F3F3F3F3F3F3",
+"l. c #F4F4F4F4F4F4",
+"z. c #F4F4F5F5F5F5",
+"x. c gray96",
+"c. c #F6F6F6F6F6F6",
+"v. c gray97",
+"b. c gray98",
+"n. c #FBFBFBFBFBFB",
+"m. c #FBFBFCFCFBFB",
+"M. c gray99",
+"N. c #FDFDFCFCFDFD",
+"B. c #FDFDFDFDFDFD",
+"V. c #FEFEFEFEFEFE",
+"C. c None",
+/* pixels */
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"u y y y t e q 9 8 7 4 2 1 < > , ",
+"t $.$.#. at .+.+. . .| { ' ( ~ E - ",
+"q +.' / / ! ! T Y L H v l h I * ",
+">.h.f.f.f.i.i.e.9.e.9.9.2.2.9.A ",
+"r.V.V.V.V.b.=.V B *.v.v.v.x.x.:.",
+"r.V.V.M.M.n.C n b B c.x.z.k.z.;.",
+"r.V.n.n.n.b.*.M m %.x.x.k.k.k.-.",
+"..g.a.a.0.0.0.0.2.2.2.2.2.,.2.Z ",
+"5 [ K J J c h g d s s p i w f o ",
+"3 [ [ ( ~ W W U I F D S x x f o ",
+"6 1 < > : ; - = % % $ # O O o O ",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C."
+};
diff --git a/src/images/flags/AS.xpm b/src/images/flags/AS.xpm
new file mode 100644
index 0000000..ae79349
--- /dev/null
+++ b/src/images/flags/AS.xpm
@@ -0,0 +1,185 @@
+/* XPM */
+static const char *AS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 163 2",
+" c black",
+". c #030300000000",
+"X c #777700000303",
+"o c #7B7B62624F4F",
+"O c #000000009D9D",
+"+ c #00000000A1A1",
+"@ c #00000000DFDF",
+"# c #00000000E1E1",
+"$ c #00000000E3E3",
+"% c #00000000E7E7",
+"& c #00000000E9E9",
+"* c #00000000EBEB",
+"= c #00000000EDED",
+"- c #00000000EFEF",
+"; c #00000000F3F3",
+": c #00000000F5F5",
+"> c #00000000F7F7",
+", c #04040000F2F2",
+"< c #00000000F9F9",
+"1 c #00000000FBFB",
+"2 c #00000000FCFC",
+"3 c #00000000FDFD",
+"4 c #03030303FDFD",
+"5 c #0B0B0B0BFDFD",
+"6 c #0D0D0B0BFDFD",
+"7 c #0D0D0D0DFFFF",
+"8 c #11111111FFFF",
+"9 c #21212121FFFF",
+"0 c #65650000B6B6",
+"q c #73733939AFAF",
+"w c #40403D3DEDED",
+"e c #45454545F8F8",
+"r c #4C4C4C4CF9F9",
+"t c #56565050ECEC",
+"y c #57575757F7F7",
+"u c #53535353FAFA",
+"i c #5A5A5A5AF5F5",
+"p c #5A5A5A5AFBFB",
+"a c #5F5F5F5FF8F8",
+"s c #77775555CCCC",
+"d c #61616161FCFC",
+"f c #65656565F9F9",
+"g c #6F6F6A6AF6F6",
+"h c #6C6C6C6CF9F9",
+"j c #6F6F6F6FFDFD",
+"k c #74747474FAFA",
+"l c #74747474FEFE",
+"z c #75757474FEFE",
+"x c #79797979FEFE",
+"c c #7C7C7C7CFBFB",
+"v c #7D7D7D7DFEFE",
+"b c #818100000000",
+"n c #9B9B00000000",
+"m c #BBBB00000000",
+"M c #8E8E4D4D3232",
+"N c #989850502A2A",
+"B c #B9B940406565",
+"V c #A0A064644040",
+"C c #B1B17B7B5050",
+"Z c #C1C100000000",
+"A c #D7D745453C3C",
+"S c #DBDB4E4E4242",
+"D c #DFDF5D5D5151",
+"F c #D0D05A5A7373",
+"G c #DEDE60605F5F",
+"H c #D4D46C6C7D7D",
+"J c #E0E05C5C5151",
+"K c #E4E46C6C6666",
+"L c #E7E772726868",
+"P c #E5E578786D6D",
+"I c #E6E677777070",
+"U c #E9E97F7F7979",
+"Y c #EAEA7E7E7B7B",
+"T c #BBBB57578686",
+"R c #A0A05353B0B0",
+"E c #A1A16A6AB6B6",
+"W c #BABA7373AEAE",
+"Q c #95957272CFCF",
+"! c #CDCD75759292",
+"~ c #C4C47D7DAAAA",
+"^ c #E0E07B7B8181",
+"/ c #B5B583835A5A",
+"( c #B5B58D8D6F6F",
+") c #BCBC9B9B7878",
+"_ c #BFBFA6A67272",
+"` c #C4C4A0A07979",
+"' c #C5C5A2A27E7E",
+"] c #E5E58B8B7777",
+"[ c #EAEA81817B7B",
+"{ c #ECEC84847A7A",
+"} c #E9E9CBCB4B4B",
+"| c #EAEACECE5151",
+" . c #E9E9D3D36666",
+".. c #EDEDDCDC7F7F",
+"X. c #88888A8A8C8C",
+"o. c #9E9E9A9A9898",
+"O. c #9D9D9D9D9D9D",
+"+. c #A2A28C8C8181",
+"@. c #A0A0A0A09999",
+"#. c #A0A0A0A09E9E",
+"$. c #BDBDA0A08686",
+"%. c #A2A2A2A2A2A2",
+"&. c #A5A5A5A5A5A5",
+"*. c #83838484FCFC",
+"=. c #8A8A8A8AFDFD",
+"-. c #9A9A8686E9E9",
+";. c #91919191FDFD",
+":. c #95959595FDFD",
+">. c #97979797FDFD",
+",. c #9B9B9191F0F0",
+"<. c #9A9A9A9AFDFD",
+"1. c #9E9E9E9EFDFD",
+"2. c #A1A1A1A1FEFE",
+"3. c #A4A4A4A4FEFE",
+"4. c #A7A7A6A6FEFE",
+"5. c #A7A7A7A7FEFE",
+"6. c #A8A8A8A8FFFF",
+"7. c #A8A8A9A9FFFF",
+"8. c #A9A9A9A9FFFF",
+"9. c #B1B1A4A4F0F0",
+"0. c #C6C69191BCBC",
+"q. c #C3C3A7A78E8E",
+"w. c #CECEB0B09595",
+"e. c #D2D2B5B59E9E",
+"r. c #E5E580808080",
+"t. c #E8E88C8C8080",
+"y. c #EBEB8C8C8181",
+"u. c #E7E793939797",
+"i. c #E9E993939191",
+"p. c #EEEE96969494",
+"a. c #F2F2A1A19A9A",
+"s. c #F1F1ABAB9F9F",
+"d. c #ECECB8B8B0B0",
+"f. c #F3F3AFAFA7A7",
+"g. c #F3F3AAAAA8A8",
+"h. c #F4F4BBBBB2B2",
+"j. c #EEEED9D98080",
+"k. c #F0F0DEDE9393",
+"l. c #F0F0E4E4AFAF",
+"z. c #EDEDD6D6C5C5",
+"x. c #E3E3DADAD3D3",
+"c. c #F3F3C9C9C2C2",
+"v. c #F8F8CFCFC7C7",
+"b. c #F0F0D6D6CECE",
+"n. c #E4E4E4E4C5C5",
+"m. c #EAEAE0E0C2C2",
+"M. c #E9E9E8E8C9C9",
+"N. c #E8E8E9E9CFCF",
+"B. c #F0F0E8E8C2C2",
+"V. c #F9F9E4E4DCDC",
+"C. c #E4E4E0E0E2E2",
+"Z. c #F8F8F1F1E9E9",
+"A. c #F4F4F4F4F0F0",
+"S. c #F4F4F4F4F4F4",
+"D. c #F6F6F6F6F6F6",
+"F. c gray97",
+"G. c #FAFAF1F1F0F0",
+"H. c #F8F8F6F6F6F6",
+"J. c #F8F8F8F8F8F8",
+"K. c #F9F9F9F9F9F9",
+"L. c gray98",
+"P. c #FBFBFBFBFBFB",
+"I. c None",
+/* pixels */
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"9 8 8 8 7 1 1 1 1 1 1 : O X m Z ",
+"7 8.8.8.4.2.1.<.:.,.0.u.i.g.v.+.",
+"8 8.v x l j g E H K U h.z.q.) o ",
+"8 4.x z Q ! P U f.Z.L.w.C M $.o.",
+"6 9.~ ^ [ a.V.L.L.J.e./ ( N ` X.",
+"0 p.{ f.Z.P.P.P.J...A.N.C.V ' O.",
+"- -.W ^ L ] c.Z.D.D.l.j.M._ x.&.",
+"1 <.d i s T K J t.b.S. .| } k.O.",
+"1 ;.p u r r 9 q B A S ] m.n.B.%.",
+"1 =.*.c z h f a p t R F J P d. at .",
+": : : * * * & $ $ @ @ @ + . b n ",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I."
+};
diff --git a/src/images/flags/AT.xpm b/src/images/flags/AT.xpm
new file mode 100644
index 0000000..61c89cd
--- /dev/null
+++ b/src/images/flags/AT.xpm
@@ -0,0 +1,150 @@
+/* XPM */
+static const char *AT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 128 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c red",
+"3 c #F2F213131313",
+"4 c #F3F319191919",
+"5 c #F4F41E1E1E1E",
+"6 c #F5F523232323",
+"7 c #F2F22C2C2C2C",
+"8 c #F2F22F2F2F2F",
+"9 c #F6F629292929",
+"0 c #F6F62C2C2C2C",
+"q c #F7F72E2E2E2E",
+"w c #FBFB2F2F2F2F",
+"e c #F2F232323232",
+"r c #F3F335353535",
+"t c #F7F731313131",
+"y c #F4F439393939",
+"u c #F5F53D3D3D3D",
+"i c #F8F834343434",
+"p c #F8F837373737",
+"a c #FFFF35353535",
+"s c #F9F93A3A3A3A",
+"d c #F9F93C3C3D3D",
+"f c #FAFA3F3F3F3F",
+"g c #F6F642424242",
+"h c #F7F746464646",
+"j c #F7F749494949",
+"k c #F7F74B4B4B4B",
+"l c #F7F74E4E4E4E",
+"z c #FAFA42424242",
+"x c #FAFA44444444",
+"c c #FBFB47474747",
+"v c #FCFC4C4C4C4C",
+"b c #F8F850505050",
+"n c #F8F853535353",
+"m c #F9F954545555",
+"M c #F9F957575757",
+"N c #FDFD51515151",
+"B c #FDFD54545454",
+"V c #F9F958585858",
+"C c #FAFA5C5C5C5C",
+"Z c #FAFA5D5D5D5D",
+"A c #FEFE59595959",
+"S c #FEFE5C5C5C5C",
+"D c #FEFE5F5F5F5F",
+"F c #F2F263636363",
+"G c #F2F266666666",
+"H c #F0F068686868",
+"J c #F3F36A6A6A6A",
+"K c #F4F46E6E6E6E",
+"L c #F6F66E6E6E6E",
+"P c #FBFB60606060",
+"I c #FBFB61616262",
+"U c #FCFC65656565",
+"Y c #FCFC66666666",
+"T c #FCFC69696969",
+"R c #FDFD6D6D6D6D",
+"E c #F5F571717171",
+"W c #F7F772727272",
+"Q c #F6F675757575",
+"! c #F3F37A7A7A7A",
+"~ c #F7F778787979",
+"^ c #F6F67F7F7F7F",
+"/ c #F8F876767676",
+"( c #FDFD70707171",
+") c #FEFE74747474",
+"_ c #FEFE77777777",
+"` c #F9F97A7A7A7A",
+"' c #F8F87C7C7C7C",
+"] c #FAFA7D7D7D7D",
+"[ c #FEFE79797979",
+"{ c #FFFF7B7B7A7A",
+"} c #FFFF7B7B7B7B",
+"| c #F9F980808080",
+" . c #FBFB81818181",
+".. c #FAFA84848484",
+"X. c #FCFC85858585",
+"o. c #FBFB88888888",
+"O. c #FBFB8B8B8B8B",
+"+. c #FDFD88888888",
+"@. c #FDFD8B8B8B8B",
+"#. c #FEFE8F8F8F8F",
+"$. c #FEFE90909191",
+"%. c #FCFCA0A0A0A0",
+"&. c #FEFEA4A4A4A4",
+"*. c #DFDFDFDFDFDF",
+"=. c #E1E1E1E1E1E1",
+"-. c #E2E2E2E2E2E2",
+";. c gray91",
+":. c #E9E9E9E9E9E9",
+">. c #EAEAEAEAEAEA",
+",. c #EEEEEEEEEEEE",
+"<. c #EFEFEFEFEFEF",
+"1. c gray94",
+"2. c #F1F1F1F1F1F1",
+"3. c #F4F4F4F4F4F4",
+"4. c #F4F4F5F5F5F5",
+"5. c gray96",
+"6. c #F6F6F6F6F6F6",
+"7. c gray97",
+"8. c #F8F8F8F8F8F8",
+"9. c #F9F9F9F9F9F9",
+"0. c gray98",
+"q. c #FBFBFBFBFBFB",
+"w. c #FBFBFCFCFBFB",
+"e. c gray99",
+"r. c #FDFDFCFCFDFD",
+"t. c #FDFDFDFDFDFD",
+"y. c #FEFEFEFEFEFE",
+"u. c None",
+/* pixels */
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"2 2 2 2 < 2 2 2 < < ; ; = = % % ",
+"2 } } } ) ) ( R T U D C M n l $ ",
+"2 } D S S B N v c z u s t 0 j $ ",
+"a &.$.#.o.o.X. .] ` / W L H ^ + ",
+":.y.y.y.y.q.q.q.8.8.5.2.2.:.5.-.",
+";.y.y.y.y.8.8.8.8.8.5.2.<.:.5.-.",
+":.y.q.y.q.y.8.8.6.6.5.2.<.;.2.*.",
+"w $.o.o...| ^ ~ / E L H G F ! X ",
+"< R c u s i 0 9 6 5 4 3 > : 8 X ",
+"; U Z V M l k h g u y r e 8 8 X ",
+"= = = % % % % $ $ + o o X X . . ",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u."
+};
diff --git a/src/images/flags/AU.xpm b/src/images/flags/AU.xpm
new file mode 100644
index 0000000..23f8f70
--- /dev/null
+++ b/src/images/flags/AU.xpm
@@ -0,0 +1,190 @@
+/* XPM */
+static const char *AU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 168 2",
+" c black",
+". c #000000000303",
+"X c #000000000505",
+"o c #000000000D0D",
+"O c #000000000F0F",
+"+ c #000000001313",
+"@ c #000000001717",
+"# c #000000001919",
+"$ c #000000001B1B",
+"% c #000000001F1F",
+"& c #000000002525",
+"* c #000000002929",
+"= c #000000002D2D",
+"- c #000000002F2F",
+"; c #000000003535",
+": c #000000003737",
+"> c #000000003939",
+", c #000000003B3B",
+"< c #000000003F3F",
+"1 c #000000004141",
+"2 c #000000004949",
+"3 c #000000004D4D",
+"4 c #000000005151",
+"5 c #000000005353",
+"6 c #000000005959",
+"7 c #000000005B5B",
+"8 c #000000005F5F",
+"9 c #000000006363",
+"0 c #00000B0B7373",
+"q c #75753D3D6969",
+"w c #6B6B45457575",
+"e c #000023238787",
+"r c #000037379595",
+"t c #1B1B3B3B8787",
+"y c #20203F3F8B8B",
+"u c #252541418383",
+"i c #222240408A8A",
+"p c #282847478F8F",
+"a c #292946468F8F",
+"s c #30304D4D9393",
+"d c #30304D4D9494",
+"f c #31314D4D9494",
+"g c #31314E4E9494",
+"h c #323250509595",
+"j c #353551519696",
+"k c #353551519797",
+"l c #353552529797",
+"z c #363652529797",
+"x c #383854549999",
+"c c #3A3A56569999",
+"v c #3B3B56569A9A",
+"b c #3C3C57579898",
+"n c #3D3D59599B9B",
+"m c #3E3E5A5A9C9C",
+"M c #4B4B4D4D8D8D",
+"N c #404059599A9A",
+"B c #40405B5B9D9D",
+"V c #43435C5C9B9B",
+"C c #40405C5C9E9E",
+"Z c #43435D5D9D9D",
+"A c #44445E5E9D9D",
+"S c #45455F5F9E9E",
+"D c #47475E5E9E9E",
+"F c #40405D5DA0A0",
+"G c #44445F5FA0A0",
+"H c #484861619F9F",
+"J c #494963639F9F",
+"K c #48486262A2A2",
+"L c #49496262A2A2",
+"P c #4A4A6363A1A1",
+"I c #4A4A6363A2A2",
+"U c #4C4C6565A3A3",
+"Y c #4F4F6A6AA8A8",
+"T c #4C4C6C6CABAB",
+"R c #4C4C6C6CACAC",
+"E c #50506868A5A5",
+"W c #50506969A4A4",
+"Q c #53536A6AA6A6",
+"! c #57576A6AA6A6",
+"~ c #55556E6EA8A8",
+"^ c #57576F6FAAAA",
+"/ c #5F5F6E6EA7A7",
+"( c #52527171AEAE",
+") c #58587070ABAB",
+"_ c #5A5A7171A9A9",
+"` c #5A5A7272A9A9",
+"' c #5B5B7272AAAA",
+"] c #5D5D7474ACAC",
+"[ c #5D5D7474ADAD",
+"{ c #5A5A7A7AB6B6",
+"} c #66667B7BB1B1",
+"| c #69697E7EB3B3",
+" . c #69697F7FB3B3",
+".. c #6D6D8181B3B3",
+"X. c #6F6F8484B6B6",
+"o. c #70708686B8B8",
+"O. c #71718686B8B8",
+"+. c #72728585B8B8",
+"@. c #75758989BABA",
+"#. c #77778A8ABBBB",
+"$. c #77778E8EBDBD",
+"%. c #7F7F8989B7B7",
+"&. c #8D8D27274343",
+"*. c #8F8F35355555",
+"=. c #919125254141",
+"-. c #CDCD09090909",
+";. c #D6D666666A6A",
+":. c #E2E265656464",
+">. c #E4E46C6C6B6B",
+",. c #E0E06F6F7070",
+"<. c #E7E771716F6F",
+"1. c #E9E97A7A7979",
+"2. c #8A8A74749B9B",
+"3. c #8C8C78789E9E",
+"4. c #87877F7FA7A7",
+"5. c #B7B771718787",
+"6. c #C7C777778383",
+"7. c #E1E17F7F8080",
+"8. c #9A9A8989A9A9",
+"9. c #94949595BBBB",
+"0. c #B3B382829898",
+"q. c #A4A49090ACAC",
+"w. c #8D8D9B9BC1C1",
+"e. c #8F8F9E9EC2C2",
+"r. c #90909E9EC2C2",
+"t. c #9494A3A3C5C5",
+"y. c #9797A4A4C5C5",
+"u. c #9494A4A4C8C8",
+"i. c #9A9AA8A8CBCB",
+"p. c #9A9AA9A9CACA",
+"a. c #9D9DABABCCCC",
+"s. c #9F9FB9B9DBDB",
+"d. c #A1A1A2A2C2C2",
+"f. c #A5A5B2B2CFCF",
+"g. c #A4A4B0B0D0D0",
+"h. c #A6A6B3B3D0D0",
+"j. c #A9A9B5B5D4D4",
+"k. c #ACACB6B6D2D2",
+"l. c #AEAEB8B8D3D3",
+"z. c #B2B2BBBBD4D4",
+"x. c #B3B3BCBCD4D4",
+"c. c #B6B6BFBFD4D4",
+"v. c #BABAC2C2D9D9",
+"b. c #BABAC4C4DADA",
+"n. c #CACA87879494",
+"m. c #C8C88B8B9797",
+"M. c #DBDB8C8C9191",
+"N. c #DCDCA4A4AAAA",
+"B. c #DDDDACACB3B3",
+"V. c #DEDEB8B8BEBE",
+"C. c #E2E282828484",
+"Z. c #E6E68E8E8F8F",
+"A. c #E8E8B9B9BEBE",
+"S. c #F1F1A4A4A2A2",
+"D. c #F1F1A7A7A5A5",
+"F. c #C3C3CACADDDD",
+"G. c #DDDDC3C3CCCC",
+"H. c #C4C4CCCCE0E0",
+"J. c #C8C8D0D0E1E1",
+"K. c #C9C9D0D0E2E2",
+"L. c #DBDBE0E0EBEB",
+"P. c #EAEAC6C6C9C9",
+"I. c #E8E8CCCCD1D1",
+"U. c #EDEDD8D8DCDC",
+"Y. c #E5E5DDDDE6E6",
+"T. c #E0E0E2E2EAEA",
+"R. c #E7E7E9E9F0F0",
+"E. c None",
+/* pixels */
+"E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.",
+"E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.",
+"E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.",
+"6.4.r &.=.e q 5.0 9 8 7 J 4 < > ",
+"M P.Y.B.N.G.U.j. at .+. .H.J.h.] > ",
+"-.Z.1.>.:.<.,.;./ Y L } k.k ~ > ",
+"*.A.S.7.C.D.M.0.! a.L m k l...= ",
+"%.I.d.m.n.s.V.q.i.v.b.k w.x.z.& ",
+"w 9.{ 3.2.R +.8.D f.` g L r.J & ",
+"9 $.[ ( Y Y K F C x h s t.s D % ",
+"9 @.) h.H.U G B x k g p y i V $ ",
+"7 +.) L.R.i.m b k g p D y.t m @ ",
+"4 X. .t.F.` ` W W U D c.T.r.b + ",
+"3 2 < < : = * & % $ + O u ",
+"E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.",
+"E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E."
+};
diff --git a/src/images/flags/AW.xpm b/src/images/flags/AW.xpm
new file mode 100644
index 0000000..c74f6e1
--- /dev/null
+++ b/src/images/flags/AW.xpm
@@ -0,0 +1,193 @@
+/* XPM */
+static const char *AW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 171 2",
+" c black",
+". c #00001F1F8585",
+"X c #000023239191",
+"o c #000025259393",
+"O c #000029299595",
+"+ c #00002D2D9595",
+"@ c #00002D2D9797",
+"# c #000033338F8F",
+"$ c #000031319999",
+"% c #000037379D9D",
+"& c #000039399191",
+"* c #00003F3F9393",
+"= c #00003B3BA1A1",
+"- c #00003F3FA3A3",
+"; c #000045459797",
+": c #00004B4B9B9B",
+"> c #00004D4D9D9D",
+", c #00004545A7A7",
+"< c #00004B4BABAB",
+"1 c #00005151ADAD",
+"2 c #00005D5DA7A7",
+"3 c #00005555B1B1",
+"4 c #00005B5BB5B5",
+"5 c #00006161A9A9",
+"6 c #00006363ABAB",
+"7 c #00006767AFAF",
+"8 c #00006161B7B7",
+"9 c #00006D6DB1B1",
+"0 c #00006D6DB5B5",
+"q c #00006F6FBFBF",
+"w c #00007171B3B3",
+"e c #00007575B7B7",
+"r c #00007979B9B9",
+"t c #00007D7DBDBD",
+"y c #00007D7DBFBF",
+"u c #05058181BDBD",
+"i c #07078181C1C1",
+"p c #0B0B8383C1C1",
+"a c #0D0D8787C1C1",
+"s c #0F0F8787C3C3",
+"d c #0F0F8989C3C3",
+"f c #0F0F8B8BC5C5",
+"g c #11118989C5C5",
+"h c #15158B8BC5C5",
+"j c #19199191C9C9",
+"k c #1D1D9191C9C9",
+"l c #21219191C7C7",
+"z c #36369494C4C4",
+"x c #3A3A9696C6C6",
+"c c #3E3E9898C7C7",
+"v c #3F3F9999C8C8",
+"b c #43439B9BC9C9",
+"n c #44449B9BC9C9",
+"m c #45459B9BC9C9",
+"M c #47479E9ECBCB",
+"N c #48489E9ECBCB",
+"B c #49499E9ECBCB",
+"V c #4B4B9F9FCACA",
+"C c #4C4CA1A1CDCD",
+"Z c #4D4DA1A1CDCD",
+"A c #4E4EA1A1CCCC",
+"S c #4F4FA2A2CCCC",
+"D c #5050A2A2CCCC",
+"F c #5151A3A3CFCF",
+"G c #5151A4A4CFCF",
+"H c #5353A4A4CECE",
+"J c #5555A3A3CCCC",
+"K c #5454A5A5CECE",
+"L c #5555A6A6CECE",
+"P c #5B5BA7A7CFCF",
+"I c #5858A8A8CFCF",
+"U c #5454A6A6D1D1",
+"Y c #5656A7A7D1D1",
+"T c #5757A7A7D0D0",
+"R c #5959A8A8D0D0",
+"E c #5959A9A9D0D0",
+"W c #5959A9A9D3D3",
+"Q c #5B5BAAAAD3D3",
+"! c #5C5CAAAAD2D2",
+"~ c #5F5FA9A9D0D0",
+"^ c #5E5EABABD1D1",
+"/ c #5E5EABABD2D2",
+"( c #5E5EABABD4D4",
+") c #6262AEAED3D3",
+"_ c #6060ACACD4D4",
+"` c #6161ADADD4D4",
+"' c #6363AEAED4D4",
+"] c #6262AEAED6D6",
+"[ c #6363AFAFD6D6",
+"{ c #6464ADADD2D2",
+"} c #6464AFAFD6D6",
+"| c #6868AFAFD3D3",
+" . c #6666B0B0D5D5",
+".. c #6767B0B0D5D5",
+"X. c #6767B1B1D5D5",
+"o. c #6767B1B1D8D8",
+"O. c #6969B2B2D7D7",
+"+. c #6A6AB3B3D7D7",
+"@. c #6B6BB3B3D7D7",
+"#. c #6C6CB2B2D5D5",
+"$. c #6868B1B1D8D8",
+"%. c #6D6DB4B4D9D9",
+"&. c #6C6CB4B4DADA",
+"*. c #6E6EB5B5D8D8",
+"=. c #6E6EB6B6D8D8",
+"-. c #6F6FB6B6D8D8",
+";. c #7070B4B4D7D7",
+":. c #7070B6B6DBDB",
+">. c #7171B6B6DBDB",
+",. c #7272B7B7DADA",
+"<. c #7373B7B7DADA",
+"1. c #7575B7B7D8D8",
+"2. c #7676BABADBDB",
+"3. c #7474B9B9DCDC",
+"4. c #7575BABADCDC",
+"5. c #7676BABADCDC",
+"6. c #7979B9B9D9D9",
+"7. c #7C7CBBBBDBDB",
+"8. c #7E7EBBBBDADA",
+"9. c #7D7DBFBFDFDF",
+"0. c #7B7BBFBFE0E0",
+"q. c #E2E26D6D6D6D",
+"w. c #E3E371717171",
+"e. c #DDDDAFAF0000",
+"r. c #DFDFB3B30000",
+"t. c #F7F7D5D50000",
+"y. c #FBFBDBDB0000",
+"u. c #F2F2DBDB2727",
+"i. c #F2F2DCDC2C2C",
+"p. c #F3F3DEDE2F2F",
+"a. c #F4F4DFDF3434",
+"s. c #F5F5E1E13939",
+"d. c #F6F6E2E23E3E",
+"f. c #F2F2DDDD4040",
+"g. c #F2F2DFDF4242",
+"h. c #F2F2DFDF4646",
+"j. c #F3F3DFDF4646",
+"k. c #F7F7E3E34343",
+"l. c #F3F3E1E14949",
+"z. c #F4F4E2E24B4B",
+"x. c #F8F8E5E54848",
+"c. c #F9F9E6E64D4D",
+"v. c #F5F5E3E35050",
+"b. c #F6F6E3E35454",
+"n. c #F7F7E5E55858",
+"m. c #F7F7E6E65C5C",
+"M. c #FAFAE8E85252",
+"N. c #FBFBE9E95757",
+"B. c #FBFBEAEA5C5C",
+"V. c #F8F8E8E86161",
+"C. c #F9F9E9E96565",
+"Z. c #F9F9EAEA6969",
+"A. c #FAFAEBEB6E6E",
+"S. c #FBFBEDED7272",
+"D. c #FCFCEEEE7A7A",
+"F. c #8080BEBEDDDD",
+"G. c #8383BFBFDFDF",
+"H. c #8484C0C0DDDD",
+"J. c #8787C2C2DFDF",
+"K. c #9D9DC4C4DDDD",
+"L. c #9F9FC4C4DCDC",
+"P. c #8A8AC3C3E0E0",
+"I. c #8A8AC3C3E2E2",
+"U. c #8D8DC5C5E2E2",
+"Y. c #8E8EC6C6E2E2",
+"T. c #8F8FC7C7E2E2",
+"R. c #9191C8C8E3E3",
+"E. c #9191C8C8E4E4",
+"W. c #9999C8C8E1E1",
+"Q. c #E8E889898989",
+"!. c None",
+/* pixels */
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"l h j g d p u t r e w 9 9 5 2 5 ",
+"d L.Q.W.E.T.U.P.J.H.F.7.6.1.;.> ",
+"k Q.w.q.0.3.<.-. at . .' ^ R K #.: ",
+"f L.q.8.3.<.-.+. .' ^ T K D | ; ",
+"a R.9.3.<.-.+. .) ^ P K S V { * ",
+"i E.3.&.-.+.' ' ^ Y F S M m ^ & ",
+"y U.&.&.o.[ ( ^ Y F S M b c P # ",
+"y.D.B.N.M.c.z.k.d.s.a.p.i.u.j.r.",
+"0 G.o.' ( W U U S M b c x z J . ",
+"t.S.S.Z.C.V.m.n.b.v.l.l.j.g.g.e.",
+"q 4 4 3 1 < , - = % $ @ O o X O ",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!."
+};
diff --git a/src/images/flags/AX.xpm b/src/images/flags/AX.xpm
new file mode 100644
index 0000000..2f5f4f8
--- /dev/null
+++ b/src/images/flags/AX.xpm
@@ -0,0 +1,196 @@
+/* XPM */
+static const char *AX_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 174 2",
+" c black",
+". c #000000004747",
+"X c #000000004B4B",
+"o c #000000004D4D",
+"O c #000000004F4F",
+"+ c #000000005555",
+"@ c #000000005B5B",
+"# c #000000006161",
+"$ c #000000006565",
+"% c #000000006767",
+"& c #000000006969",
+"* c #000000007575",
+"= c #000000007B7B",
+"- c #000007078989",
+"; c #000009098787",
+": c #00000B0B8989",
+"> c #000011118F8F",
+", c #000017178F8F",
+"< c #000021219595",
+"1 c #00002B2B9B9B",
+"2 c #000033339F9F",
+"3 c #00003333A1A1",
+"4 c #00003535A1A1",
+"5 c #00003D3DA5A5",
+"6 c #00004343ABAB",
+"7 c #00004545AFAF",
+"8 c #01014B4BA5A5",
+"9 c #0B0B5353A9A9",
+"0 c #1A1A5959ABAB",
+"q c #1F1F6363BBBB",
+"w c #1D1D6161BDBD",
+"e c #1F1F6161BDBD",
+"r c #1F1F6363BDBD",
+"t c #21215D5DAEAE",
+"y c #25256060ABAB",
+"u c #2C2C6565AEAE",
+"i c #23236565B7B7",
+"p c #27276262B1B1",
+"a c #25256969BBBB",
+"s c #27276969BDBD",
+"d c #2D2D6767B4B4",
+"f c #32326A6AB1B1",
+"g c #37376F6FB0B0",
+"h c #35356D6DB7B7",
+"j c #39396F6FB5B5",
+"k c #3B3B6D6DBFBF",
+"l c #3B3B7272B3B3",
+"z c #3B3B7070B7B7",
+"x c #3F3F7575B4B4",
+"c c #44447575B6B6",
+"v c #41417575B9B9",
+"b c #46467979B7B7",
+"n c #45457A7AB8B8",
+"m c #47477A7ABCBC",
+"M c #48487A7ABDBD",
+"N c #4A4A7E7EBABA",
+"B c #4C4C7F7FBBBB",
+"V c #48487B7BC0C0",
+"C c #4C4C7E7EC1C1",
+"Z c #4F4F8181BDBD",
+"A c #53538484BFBF",
+"S c #4F4F8181C3C3",
+"D c #55558383C3C3",
+"F c #56568686C7C7",
+"G c #5B5B8A8AC2C2",
+"H c #5E5E8A8AC0C0",
+"J c #5F5F8A8AC3C3",
+"K c #5E5E8B8BCACA",
+"L c #5E5E8C8CC8C8",
+"P c #5F5F8F8FCBCB",
+"I c #62628F8FC5C5",
+"U c #65659393C8C8",
+"Y c #64649191CDCD",
+"T c #67679292CFCF",
+"R c #68689292C9C9",
+"E c #6C6C9898CBCB",
+"W c #6F6F9898C9C9",
+"Q c #6A6A9292D3D3",
+"! c #75759B9BC7C7",
+"~ c #72729C9CCDCD",
+"^ c #74749C9CCCCC",
+"/ c #74749D9DCFCF",
+"( c #78789F9FCDCD",
+") c #7878A0A0D0D0",
+"_ c #7979A1A1D3D3",
+"` c #7E7EA5A5D3D3",
+"' c #7F7FA5A5D3D3",
+"] c #D3D300000000",
+"[ c #E1E100000000",
+"{ c #FDFD13130909",
+"} c #FDFD1D1D0F0F",
+"| c #ECEC2C2C2525",
+" . c #EEEE34342C2C",
+".. c #EFEF3B3B3333",
+"X. c #CBCB59590000",
+"o. c #CFCF6B6B0000",
+"O. c #DDDD6F6F0000",
+"+. c #F1F143433C3C",
+"@. c #EDED4A4A4242",
+"#. c #F3F349494343",
+"$. c #F4F451514A4A",
+"%. c #F4F453534848",
+"&. c #F5F55A5A5050",
+"*. c #F6F658585252",
+"=. c #F7F75C5C5959",
+"-. c #F7F75D5D5959",
+";. c #F4F468685F5F",
+":. c #F9F960606060",
+">. c #FAFA6A6A6666",
+",. c #FAFA6C6C6868",
+"<. c #FBFB73736E6E",
+"1. c #FBFB77776F6F",
+"2. c #FCFC78787373",
+"3. c #FCFC7D7D7575",
+"4. c #CFCF8D8D0000",
+"5. c #FBFBAFAF1515",
+"6. c #F7F7B1B11111",
+"7. c #E8E8AFAF3131",
+"8. c #EAEAB2B23737",
+"9. c #ECECB6B63F3F",
+"0. c #F9F9BBBB2323",
+"q. c #EAEAB9B94040",
+"w. c #EDEDBABA4545",
+"e. c #EBEBBABA4D4D",
+"r. c #EDEDBCBC4848",
+"t. c #F0F0BDBD4C4C",
+"y. c #F2F2BCBC5151",
+"u. c #F6F6BABA6060",
+"i. c #EFEFC1C12D2D",
+"p. c #EFEFC0C04E4E",
+"a. c #EDEDC1C15A5A",
+"s. c #F0F0C3C35555",
+"d. c #F2F2C0C05454",
+"f. c #F3F3C6C65A5A",
+"g. c #F2F2C6C65C5C",
+"h. c #F4F4C2C25959",
+"j. c #EBEBCBCB6666",
+"k. c #EDEDD1D17979",
+"l. c #F2F2C3C36767",
+"z. c #F3F3C9C96363",
+"x. c #F6F6CFCF6A6A",
+"c. c #F9F9C4C46F6F",
+"v. c #F9F9CBCB6E6E",
+"b. c #FAFACECE7676",
+"n. c #F0F0D2D26B6B",
+"m. c #F8F8D0D07474",
+"M. c #FAFAD2D27B7B",
+"N. c #FBFBD3D37B7B",
+"B. c #FBFBD0D07C7C",
+"V. c #8383A9A9D5D5",
+"C. c #8686AAAAD5D5",
+"Z. c #8484A9A9D8D8",
+"A. c #8686ABABDADA",
+"S. c #8888AAAADADA",
+"D. c #8989ACACD8D8",
+"F. c #8989ACACDDDD",
+"G. c #8F8FB0B0D8D8",
+"H. c #9393B3B3D7D7",
+"J. c #9F9FBCBCDFDF",
+"K. c #9C9CBABAE2E2",
+"L. c #9E9EBCBCE2E2",
+"P. c #9E9EBCBCE3E3",
+"I. c #9E9EBDBDE2E2",
+"U. c #FCFC92928E8E",
+"Y. c #FDFD96968F8F",
+"T. c #F5F5DCDC8585",
+"R. c #F5F5DBDB8B8B",
+"E. c #FBFBD8D88181",
+"W. c #FBFBD9D98787",
+"Q. c #FCFCDBDB9494",
+"!. c #FCFCDADA9696",
+"~. c #FCFCE1E19D9D",
+"^. c #F7F7E2E2A2A2",
+"/. c None",
+/* pixels */
+"/./././././././././././././././.",
+"/./././././././././././././././.",
+"/./././././././././././././././.",
+"s i w w i.} 5.9 6 5 3 1 < , : ; ",
+"s P.P.K.^.Y.!.H.A.V.` ) ~ E U = ",
+"w P.F.A.R.3.N./ Q Y L F D V L * ",
+"i J.D.C.T.1.b.! U I H D N b H $ ",
+"0.~.W.E.N.,.c.x.z.g.s.p.r.q.a.o.",
+"{ U.2.1.>.:.=.*.$.#.+... .| @.] ",
+"6.!.M.m.v.=.u.f.y.t.w.q.8.7.e.X.",
+"8 G.^ W n.*.h.C M v z f u y c O ",
+"7 V.T P j.%.y.m k h d p t 0 j O ",
+"4 ` _ ~ k.;.l.J D Z N n c l g . ",
+"2 < > : 4.[ O.$ & # @ + O X . O ",
+"/./././././././././././././././.",
+"/./././././././././././././././."
+};
diff --git a/src/images/flags/AZ.xpm b/src/images/flags/AZ.xpm
new file mode 100644
index 0000000..a582914
--- /dev/null
+++ b/src/images/flags/AZ.xpm
@@ -0,0 +1,192 @@
+/* XPM */
+static const char *AZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 170 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002D2D0000",
+"O c #00002F2F0000",
+"+ c #000033330000",
+"@ c #000035350000",
+"# c #000039390000",
+"$ c #00003D3D0000",
+"% c #000041410000",
+"& c #000047470000",
+"* c #00004D4D0000",
+"= c #000051510000",
+"- c #000057570000",
+"; c #00005D5D0000",
+": c #000063630000",
+"> c #000067670000",
+", c #00006F6F0000",
+"< c #000075750000",
+"1 c #00007D7D0000",
+"2 c #00004D4D9D9D",
+"3 c #00005353A9A9",
+"4 c #00005D5DA7A7",
+"5 c #00006161A9A9",
+"6 c #00006363ABAB",
+"7 c #00006767AFAF",
+"8 c #00006D6DB1B1",
+"9 c #00007171B3B3",
+"0 c #00007575B7B7",
+"q c #00007979B9B9",
+"w c #00007D7DBDBD",
+"e c #0B0B9A9A3939",
+"r c #0F0F9C9C3C3C",
+"t c #13139F9F4040",
+"y c #1818A1A14545",
+"u c #1E1EA3A34949",
+"i c #2323A5A54D4D",
+"p c #2929A5A55050",
+"a c #2C2CA2A25353",
+"s c #2F2FA4A45555",
+"d c #2F2FA9A95656",
+"f c #2E2EABAB5555",
+"g c #3232A5A55858",
+"h c #3535A8A85B5B",
+"j c #3434AEAE5B5B",
+"k c #3939A9A95F5F",
+"l c #3D3DACAC6262",
+"z c #3A3AB1B16060",
+"x c #3F3FB3B36464",
+"c c #4242AEAE6565",
+"v c #4646B0B06969",
+"b c #4444B6B66969",
+"n c #4B4BB2B26D6D",
+"m c #5050B4B47171",
+"M c #5454B7B77575",
+"N c #5858B9B97979",
+"B c #5D5DBCBC7D7D",
+"V c #00008181BDBD",
+"C c #00008383C1C1",
+"Z c #00008585C3C3",
+"A c #00008787C3C3",
+"S c #00008989C3C3",
+"D c #00008F8FCDCD",
+"F c #00009191C7C7",
+"G c #2C2CAAAAD4D4",
+"H c #3131ADADD6D6",
+"J c #3737AFAFD8D8",
+"K c #3D3DB2B2DADA",
+"L c #6161BEBE8080",
+"P c #4242B4B4DBDB",
+"I c #4747B6B6DCDC",
+"U c #4E4EB4B4D7D7",
+"Y c #4949B5B5DADA",
+"T c #4C4CB7B7DCDC",
+"R c #5353B7B7D8D8",
+"E c #5151BABADFDF",
+"W c #5858B9B9D9D9",
+"Q c #5C5CBBBBDBDB",
+"! c #5454BDBDE0E0",
+"~ c #5959BFBFE2E2",
+"^ c #6161BEBEDDDD",
+"/ c #6666C3C38484",
+"( c #5C5CC0C0E3E3",
+") c #5F5FC2C2E3E3",
+"_ c #6565C0C0DDDD",
+"` c #6969C2C2DFDF",
+"' c #6D6DC3C3E0E0",
+"] c #7070C5C5E2E2",
+"[ c #7474C7C7E2E2",
+"{ c #7777C8C8E3E3",
+"} c #7979C9C9E4E4",
+"| c #7B7BCACAE4E4",
+" . c #7B7BCDCDE8E8",
+".. c #878700000000",
+"X. c #939300000000",
+"o. c #959500000000",
+"O. c #979700000000",
+"+. c #999900000000",
+"@. c #BBBB00000000",
+"#. c #C1C100000000",
+"$. c #C3C301010101",
+"%. c #C3C303030303",
+"&. c #C7C73C3C3C3C",
+"*. c #CBCB3E3E4141",
+"=. c #C9C940404040",
+"-. c #CACA44444444",
+";. c #CACA45454545",
+":. c #CDCD43434545",
+">. c #CFCF47474A4A",
+",. c #CCCC49494949",
+"<. c #CDCD49494848",
+"1. c #CFCF4D4D4D4D",
+"2. c #CECE4E4E4E4E",
+"3. c #CFCF4F4F4F4F",
+"4. c #CECE58585858",
+"5. c #D1D152525151",
+"6. c #D0D052525252",
+"7. c #D0D053535353",
+"8. c #D2D255555656",
+"9. c #D2D258585858",
+"0. c #D3D35B5B5B5B",
+"q. c #D2D25A5A5C5C",
+"w. c #D4D45D5D5D5D",
+"e. c #D5D55F5F5F5F",
+"r. c #D9D95D5D6060",
+"t. c #D2D260606060",
+"y. c #D4D462626161",
+"u. c #D6D661616161",
+"i. c #D7D763636363",
+"p. c #D5D567676767",
+"a. c #D7D766666666",
+"s. c #D7D768686868",
+"d. c #DBDB67676969",
+"f. c #D9D968686767",
+"g. c #D9D968686868",
+"h. c #D9D96A6A6A6A",
+"j. c #DADA6C6C6C6C",
+"k. c #DBDB6E6E6E6E",
+"l. c #DCDC6B6B6D6D",
+"z. c #DDDD6F6F7171",
+"x. c #D9D972727474",
+"c. c #DCDC71717171",
+"v. c #DDDD70707070",
+"b. c #DCDC72727272",
+"n. c #DDDD75757474",
+"m. c #DDDD75757575",
+"M. c #DEDE76767676",
+"N. c #DFDF78787777",
+"B. c #DBDB7D7D7C7C",
+"V. c #DEDE79797979",
+"C. c #DEDE79797A7A",
+"Z. c #DFDF7B7B7C7C",
+"A. c #E1E187878787",
+"S. c #E0E089898A8A",
+"D. c #E3E38E8E8F8F",
+"F. c #E4E48A8A8B8B",
+"G. c #E5E58F8F8F8F",
+"H. c #E5E593939393",
+"J. c #E5E59B9B9C9C",
+"K. c #E4E4AAAAAAAA",
+"L. c #E9E9B5B5B6B6",
+"P. c #EAEABABAB9B9",
+"I. c #EDEDBFBFC1C1",
+"U. c #EFEFC2C2C1C1",
+"Y. c #EFEFCDCDCDCD",
+"T. c #F0F0CECECECE",
+"R. c #F1F1D8D8D9D9",
+"E. c #F4F4DCDCDCDC",
+"W. c #F4F4E2E2E2E2",
+"Q. c None",
+/* pixels */
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"F S S S S Z V w q 0 9 8 8 5 4 5 ",
+"Z | | | { [ ' ` ' ^ ^ Q W R U 2 ",
+"D .( ( ( E E T I P K J H G U 3 ",
+"$.H.C.C.M.b.v.h.a.y.w.9.7.3.p.+.",
+"$.H.N.n.v.f.U.E.J.P.B.5.1.,.y.+.",
+"$.D.n.c.j.S.W.s.T.R.K.2.,.;.r.X.",
+"$.F.z.l.d.r.I.T.C.L.x.>.:.*.4.X.",
+"@.A.j.h.y.r.0.8.5.2.,.-.-.&.4...",
+"1 / b x z j f p i u y t r e d # ",
+", B B N M m n v c l k h g s a . ",
+"< > > ; - = * & % $ # + O O X + ",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q."
+};
diff --git a/src/images/flags/BA.xpm b/src/images/flags/BA.xpm
new file mode 100644
index 0000000..30f9b56
--- /dev/null
+++ b/src/images/flags/BA.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *BA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #555553535353",
+"X c #797978787878",
+"o c #000000008F8F",
+"O c #000000009191",
+"+ c #000000009393",
+"@ c #000000009797",
+"# c #000000009999",
+"$ c #000000009B9B",
+"% c #000000009D9D",
+"& c #000000009F9F",
+"* c #00000000A1A1",
+"= c #00000000A3A3",
+"- c #00000000A5A5",
+"; c #00000000A9A9",
+": c #00000000ADAD",
+"> c #00000000AFAF",
+", c #00000000B3B3",
+"< c #00000000B7B7",
+"1 c #00000000B9B9",
+"2 c #00000000BDBD",
+"3 c #00000000BFBF",
+"4 c #00000000C3C3",
+"5 c #00000000C5C5",
+"6 c #00000000C7C7",
+"7 c #00000000C9C9",
+"8 c #00000000CBCB",
+"9 c #0B0B2F2FCBCB",
+"0 c #10103333CCCC",
+"q c #14143838CECE",
+"w c #1A1A3C3CCFCF",
+"e c #20204242D2D2",
+"r c #23234444D3D3",
+"t c #26264747D3D3",
+"y c #25254747DBDB",
+"u c #29294949D5D5",
+"i c #2C2C4B4BD1D1",
+"p c #2F2F4D4DD2D2",
+"a c #2C2C4C4CD5D5",
+"s c #2E2E4E4ED6D6",
+"d c #2F2F4E4ED7D7",
+"f c #33335050D3D3",
+"g c #34345353D7D7",
+"h c #36365454D4D4",
+"j c #34345353D8D8",
+"k c #3A3A5757D9D9",
+"l c #3B3B5858D6D6",
+"z c #3D3D5A5AD7D7",
+"x c #3F3F5C5CD7D7",
+"c c #3A3A5858D9D9",
+"v c #3B3B5858DADA",
+"b c #3F3F5C5CDBDB",
+"n c #40405D5DDBDB",
+"m c #42425E5ED8D8",
+"M c #40405D5DDCDC",
+"N c #44446060D9D9",
+"B c #46466262DADA",
+"V c #44446161DCDC",
+"C c #45456161DDDD",
+"Z c #45456262DDDD",
+"A c #46466262DDDD",
+"S c #49496565DBDB",
+"D c #4B4B6666DBDB",
+"F c #49496666DEDE",
+"G c #4B4B6666DEDE",
+"H c #4E4E6969DCDC",
+"J c #50506A6ADDDD",
+"K c #53536D6DDDDD",
+"L c #54546E6EDDDD",
+"P c #58587272DFDF",
+"I c #5F5F7676DCDC",
+"U c #4F4F6A6AE0E0",
+"Y c #4F4F6B6BE0E0",
+"T c #50506B6BE0E0",
+"R c #53536F6FE1E1",
+"E c #54546F6FE1E1",
+"W c #58587272E2E2",
+"Q c #5D5D7676E1E1",
+"! c #5C5C7575E4E4",
+"~ c #5F5F7979E4E4",
+"^ c #68687E7EDFDF",
+"/ c #61617A7AE2E2",
+"( c #66667E7EE3E3",
+") c #79798989CFCF",
+"_ c #72728686DFDF",
+"` c #6A6A8282E5E5",
+"' c #6F6F8585E6E6",
+"] c #70708686E2E2",
+"[ c #72728888E7E7",
+"{ c #76768B8BE8E8",
+"} c #79798D8DE5E5",
+"| c #79798E8EE8E8",
+" . c #7B7B8F8FE8E8",
+".. c #7B7B9090E9E9",
+"X. c #80807E7E7E7E",
+"o. c #EBEBAFAF0000",
+"O. c #F3F3AFAF0000",
+"+. c #F5F5B3B30000",
+"@. c #F7F7B3B30000",
+"#. c #F7F7B9B90000",
+"$. c #F9F9B7B70000",
+"%. c #FBFBB9B90000",
+"&. c #FDFDBDBD0000",
+"*. c #F1F1C5C50E0E",
+"=. c #F2F2C7C71414",
+"-. c #F3F3C8C81919",
+";. c #F3F3C9C91919",
+":. c #F4F4CBCB1F1F",
+">. c #F4F4CCCC1F1F",
+",. c #F3F3CACA2525",
+"<. c #F5F5CCCC2525",
+"1. c #F5F5CDCD2525",
+"2. c #F6F6CFCF2B2B",
+"3. c #F1F1CBCB3333",
+"4. c #F6F6D0D02B2B",
+"5. c #F7F7D0D03030",
+"6. c #F7F7D1D13131",
+"7. c #F6F6D1D13E3E",
+"8. c #F8F8D2D23636",
+"9. c #F8F8D3D33737",
+"0. c #F9F9D4D43D3D",
+"q. c #F9F9D6D63C3C",
+"w. c #F7F7D4D44A4A",
+"e. c #FAFAD5D54242",
+"r. c #FBFBD9D94747",
+"t. c #FBFBD8D84D4D",
+"y. c #F8F8D7D75454",
+"u. c #F9F9DADA5757",
+"i. c #FAFADCDC5C5C",
+"p. c #FBFBDDDD6060",
+"a. c #FCFCDDDD6565",
+"s. c #FCFCDFDF6969",
+"d. c #FDFDE1E16D6D",
+"f. c #FAFAE0E07777",
+"g. c #FCFCE0E07171",
+"h. c #888886868686",
+"j. c #8A8A89898989",
+"k. c #8F8F8D8D8D8D",
+"l. c #969694949494",
+"z. c #9D9D9B9B9B9B",
+"x. c #A2A2A1A1A1A1",
+"c. c #B5B5B3B3B3B3",
+"v. c #81819494E8E8",
+"b. c #87879A9AEAEA",
+"n. c #8D8D9F9FECEC",
+"m. c #B8B8C3C3F3F3",
+"M. c #CDCDD5D5F7F7",
+"N. c #D0D0D5D5EEEE",
+"B. c #D4D4D8D8EFEF",
+"V. c #D8D8DCDCF1F1",
+"C. c #DBDBDFDFF4F4",
+"Z. c #DDDDE2E2F0F0",
+"A. c #DEDEE2E2F6F6",
+"S. c #E1E1E5E5F8F8",
+"D. c #E3E3E7E7F9F9",
+"F. c #E9E9EDEDFCFC",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"8 y M.. #.o.&.&.%.$. at .@.O., : : ",
+"8 ..m.F.c.f.g.d.s.a.p.i.u.K H ; ",
+"8 .~ n.D.x.u.t.r.e.0.8.6.a S - ",
+"8 } ! W b.S.z.w.e.0.8.6.2.t N = ",
+"8 { W E J v.A.l.7.8.6.2.<.e x % ",
+"8 [ Y U S Z } C.k.3.4.<.>.w l # ",
+"5 ' Y U A m c ' V.h.,.>.;.q h @ ",
+"4 ` S A M c j j ^ B.X.;.=.0 f + ",
+"3 ( Z b k j a u r I N.X *.9 p + ",
+"3 / ! W L J D N m z _ Z.j.p i o ",
+"< , , : : ; - = = # @ : ) ; o o ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/BB.xpm b/src/images/flags/BB.xpm
new file mode 100644
index 0000000..d490fdd
--- /dev/null
+++ b/src/images/flags/BB.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *BB_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000000001F1F",
+"X c #000000002121",
+"o c #000000002525",
+"O c #000000002B2B",
+"+ c #000000002F2F",
+"@ c #000000003131",
+"# c #000000003535",
+"$ c #000000003939",
+"% c #000000003B3B",
+"& c #000000004141",
+"* c #000000004747",
+"= c #000000004D4D",
+"- c #000000005353",
+"; c #000000005959",
+": c #000000005D5D",
+"> c #000000005F5F",
+", c #000000006363",
+"< c #000000006767",
+"1 c #000000006969",
+"2 c #000000006F6F",
+"3 c #000000007373",
+"4 c #000000007777",
+"5 c #000000007B7B",
+"6 c #000000007D7D",
+"7 c #000000007F7F",
+"8 c #000003037F7F",
+"9 c #727265652F2F",
+"0 c #747466662A2A",
+"q c #7C7C6E6E3535",
+"w c #7D7D6F6F3636",
+"e c #7F7F71713636",
+"r c #000003038181",
+"t c #0B0B39399595",
+"y c #0F0F3C3C9797",
+"u c #10103D3D9797",
+"i c #13133D3D9C9C",
+"p c #141441419999",
+"a c #141441419A9A",
+"s c #191942429F9F",
+"d c #191945459C9C",
+"f c #1A1A46469D9D",
+"g c #1F1F4A4A9F9F",
+"h c #1F1F4747A2A2",
+"j c #20204B4B9F9F",
+"k c #25254F4FA2A2",
+"l c #25254C4CA5A5",
+"z c #26265050A2A2",
+"x c #2B2B5454A5A5",
+"c c #2C2C5353A2A2",
+"v c #2C2C5454A6A6",
+"b c #2F2F5555A4A4",
+"n c #2F2F5656A4A4",
+"m c #2B2B5252A8A8",
+"M c #31315757ABAB",
+"N c #32325858A6A6",
+"B c #33335959A6A6",
+"V c #31315959A9A9",
+"C c #35355959A9A9",
+"Z c #36365C5CA8A8",
+"A c #37375C5CAEAE",
+"S c #3A3A5C5CB0B0",
+"D c #3B3B6060AAAA",
+"F c #3F3F6464ADAD",
+"G c #3F3F6363B0B0",
+"H c #44446868AFAF",
+"J c #40406161B3B3",
+"K c #45456666B6B6",
+"L c #44446969B1B1",
+"P c #45456868B2B2",
+"I c #49496C6CB1B1",
+"U c #49496D6DB4B4",
+"Y c #49496D6DB5B5",
+"T c #4B4B6A6AB8B8",
+"R c #4E4E7070B4B4",
+"E c #4F4F7171B7B7",
+"W c #4F4F7171B8B8",
+"Q c #50506F6FBBBB",
+"! c #53537575B7B7",
+"~ c #53537676B9B9",
+"^ c #54547171BABA",
+"/ c #54547373BDBD",
+"( c #54547575BABA",
+") c #59597676BFBF",
+"_ c #58587878B9B9",
+"` c #58587878BABA",
+"' c #58587979BCBC",
+"] c #5C5C7A7ABEBE",
+"[ c #5D5D7D7DBCBC",
+"{ c #5C5C7C7CBEBE",
+"} c #5F5F7F7FBFBF",
+"| c #61618080BEBE",
+" . c #66668484C0C0",
+".. c #6A6A8888C3C3",
+"X. c #6F6F8B8BC4C4",
+"o. c #72728E8EC6C6",
+"O. c #77778F8FCBCB",
+"+. c #76769191C8C8",
+"@. c #79799393C9C9",
+"#. c #79799494C9C9",
+"$. c #7B7B9595C9C9",
+"%. c #7B7B9595CACA",
+"&. c #8C8C7A7A2F2F",
+"*. c #828274743B3B",
+"=. c #818174743C3C",
+"-. c #868678783C3C",
+";. c #89897B7B4141",
+":. c #88887B7B4646",
+">. c #AEAE94943030",
+",. c #8C8C80804B4B",
+"<. c #B9B99F9F4040",
+"1. c #E7E793930000",
+"2. c #E5E59F9F0000",
+"3. c #E9E999990000",
+"4. c #E3E3A3A30000",
+"5. c #EBEBA9A90000",
+"6. c #EDEDB3B30000",
+"7. c #FBFBB9B90000",
+"8. c #FDFDBDBD0000",
+"9. c #DADABCBC4242",
+"0. c #DBDBBEBE4747",
+"q. c #F7F7C5C50000",
+"w. c #F9F9C3C30000",
+"e. c #FDFDCFCF0000",
+"r. c #F3F3D4D41919",
+"t. c #F4F4D0D01E1E",
+"y. c #F4F4D6D61F1F",
+"u. c #F5F5CCCC2323",
+"i. c #F6F6CECE2929",
+"p. c #F5F5D6D62424",
+"a. c #F6F6D1D12A2A",
+"s. c #F7F7D6D62E2E",
+"d. c #F5F5D8D82424",
+"f. c #F6F6D9D92B2B",
+"g. c #F5F5D6D63D3D",
+"h. c #F7F7DBDB3030",
+"j. c #F4F4DADA3939",
+"k. c #F8F8DBDB3434",
+"l. c #F8F8DCDC3434",
+"z. c #F8F8DEDE3636",
+"x. c #F9F9D8D83A3A",
+"c. c #F9F9DEDE3A3A",
+"v. c #F9F9DFDF3D3D",
+"b. c #F6F6D2D24242",
+"n. c #F7F7D3D34646",
+"m. c #F7F7DBDB4B4B",
+"M. c #FBFBDBDB4747",
+"N. c #FCFCDCDC4C4C",
+"B. c #FCFCDFDF6969",
+"V. c #FAFAE0E04040",
+"C. c #FAFAE0E04242",
+"Z. c #FBFBE1E14646",
+"A. c #FCFCE3E34B4B",
+"S. c #F8F8E1E15050",
+"D. c #FDFDE4E45151",
+"F. c #FDFDE5E55454",
+"G. c #FBFBE6E66060",
+"H. c #FCFCE2E26565",
+"J. c #FDFDE0E06D6D",
+"K. c #FDFDE6E67171",
+"L. c #FEFEEBEB7474",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"r r r r 8 e.e.8.7.w.q.2 : ; - = ",
+"r %.%. at .O.L.K.J.H.H.G.' ` ! R * ",
+"r %.} { ) F.D.N.M.M.v.A V v I & ",
+"8 %.{ ' / D.,.0.9.=.l.M x k H % ",
+"8 o.` ( Q A.:.;.-.w h.x k g H # ",
+"5 o.~ W U M.<.*.*.>.f.l g d D + ",
+"4 X.W U P M.x.w 9 i.d.h d p Z O ",
+"3 ..U P J c.k.&.0 p.y.s p u B o ",
+"2 .L L S l.s.i.u.t.r.i u t v X ",
+"1 } { ` ^ S.m.n.b.g.j.Z B v c . ",
+", < , : : 6.5.3.1.2.4.% @ X . . ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/BD.xpm b/src/images/flags/BD.xpm
new file mode 100644
index 0000000..4eabc02
--- /dev/null
+++ b/src/images/flags/BD.xpm
@@ -0,0 +1,149 @@
+/* XPM */
+static const char *BD_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 127 2",
+" c black",
+". c #000005050000",
+"X c #00000D0D0000",
+"o c #000013130000",
+"O c #000019190000",
+"+ c #000021210000",
+"@ c #000027270000",
+"# c #00002D2D0000",
+"$ c #00002F2F0000",
+"% c #000033330000",
+"& c #000035350000",
+"* c #000037370000",
+"= c #00003B3B0000",
+"- c #00003D3D0000",
+"; c #000041410000",
+": c #000043430000",
+"> c #0B0B67670B0B",
+", c #0F0F6A6A0E0E",
+"< c #10106A6A1010",
+"1 c #13136C6C1313",
+"2 c #14146E6E1414",
+"3 c #191970701919",
+"4 c #1A1A70701A1A",
+"5 c #1F1F74741F1F",
+"6 c #202075752020",
+"7 c #252578782525",
+"8 c #26267A7A2626",
+"9 c #2B2B7C7C2B2B",
+"0 c #2C2C7B7B2C2C",
+"q c #2C2C7C7C2C2C",
+"w c #2F2F7C7C2F2F",
+"e c #2F2F7D7D2F2F",
+"r c #32327F7F3232",
+"t c #33337F7F3232",
+"y c #6B6B50501919",
+"u c #7C7C63633131",
+"i c #7E7E65653434",
+"p c #313181813131",
+"a c #353582823535",
+"s c #363682823636",
+"d c #373784843737",
+"f c #393984843939",
+"g c #3B3B85853B3B",
+"h c #3A3A86863A3A",
+"j c #3D3D86863D3D",
+"k c #3F3F89893F3F",
+"l c #3F3F8A8A3F3F",
+"z c #42428A8A4242",
+"x c #44448C8C4444",
+"c c #44448E8E4444",
+"v c #45458E8E4545",
+"b c #46468D8D4646",
+"n c #49498F8F4949",
+"m c #494991914949",
+"M c #4B4B90904B4B",
+"N c #4E4E93934E4E",
+"B c #4F4F95954F4F",
+"V c #505093935050",
+"C c #535396965353",
+"Z c #535397975353",
+"A c #545496965555",
+"S c #545497975454",
+"D c #585898985757",
+"F c #585899995858",
+"G c #58589A9A5858",
+"H c #58589B9B5959",
+"J c #59599B9B5959",
+"K c #5C5C9B9B5C5C",
+"L c #5C5C9D9D5C5C",
+"P c #5D5D9D9D5D5D",
+"I c #5F5F9F9F5F5F",
+"U c #61619E9E6060",
+"Y c #61619F9F6262",
+"T c #6565A1A16565",
+"R c #6666A3A36666",
+"E c #6969A4A46969",
+"W c #6A6AA5A56A6A",
+"Q c #6D6DA7A76D6D",
+"! c #6F6FA8A86F6F",
+"~ c #7070A9A97171",
+"^ c #7272AAAA7373",
+"/ c #7474ABAB7474",
+"( c #7676ADAD7676",
+") c #7777ADAD7777",
+"_ c #7979AEAE7979",
+"` c #7B7BB0B07A7A",
+"' c #7B7BB0B07B7B",
+"] c #B9B936361F1F",
+"[ c #84846C6C3D3D",
+"{ c #85856E6E3F3F",
+"} c #BEBE41412B2B",
+"| c #94947F7F5454",
+" . c #CFCF2D2D1E1E",
+".. c #D5D53C3C2E2E",
+"X. c #F1F120201F1F",
+"o. c #EDED28282525",
+"O. c #F3F324242323",
+"+. c #F5F524242424",
+"@. c #F4F42A2A2929",
+"#. c #F6F62A2A2A2A",
+"$. c #F6F62B2B2B2B",
+"%. c #F7F72F2F2F2F",
+"&. c #F7F730303030",
+"*. c #F5F538383636",
+"=. c #F6F63C3C3A3A",
+"-. c #F8F834343434",
+";. c #F8F835353535",
+":. c #F8F836363636",
+">. c #F9F93B3B3A3A",
+",. c #F9F93B3B3B3B",
+"<. c #F9F93B3B3C3C",
+"1. c #F9F93C3C3C3C",
+"2. c #C8C859594545",
+"3. c #DBDB4F4F4242",
+"4. c #DFDF5C5C5151",
+"5. c #CCCC63635050",
+"6. c #F4F44D4D4B4B",
+"7. c #FAFA40404040",
+"8. c #FAFA41414141",
+"9. c #FAFA41414242",
+"0. c #FBFB46464646",
+"q. c #FBFB47474747",
+"w. c #F9F948484747",
+"e. c #FAFA4C4C4C4C",
+"r. c #FCFC4B4B4B4B",
+"t. c #FAFA51515151",
+"y. c None",
+/* pixels */
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+": : : : : = * % # @ + O o X . ",
+": ' ' _ ( ( ~ ! E T U L D C N ",
+": ' I L D | 4.r.q.3.[ s p q n ",
+": _ L H | t.r.w.8.1.*.u 9 8 x ",
+"= ( D S 5.r.q.8.<.*.%.} 8 6 k ",
+"= ~ Z B 6.0.1.>.:.&.#.o.5 4 g ",
+"* ! B M 2.8.1.:.&.#.+.] 4 2 s ",
+"% E M c { =.:.%.#.+.X.y 2 1 t ",
+"@ T c k g i ..#.O. .y 1 , > q ",
+"+ T L F A V M x z j g s t q w ",
+"O o X . ",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y."
+};
diff --git a/src/images/flags/BE.xpm b/src/images/flags/BE.xpm
new file mode 100644
index 0000000..445169d
--- /dev/null
+++ b/src/images/flags/BE.xpm
@@ -0,0 +1,156 @@
+/* XPM */
+static const char *BE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 134 2",
+" c black",
+". c #3A3A3A3A3A3A",
+"X c #3F3F3F3F3F3F",
+"o c #40403F3F3F3F",
+"O c #444444444444",
+"+ c gray27",
+"@ c #494949494949",
+"# c #49494A4A4949",
+"$ c #4B4B4A4A4B4B",
+"% c gray31",
+"& c #50504F4F5050",
+"* c #535353535353",
+"= c gray33",
+"- c #545454545555",
+"; c #585858585858",
+": c #585859595959",
+"> c gray35",
+", c gray36",
+"< c #5D5D5D5D5D5D",
+"1 c #5F5F5F5F5F5F",
+"2 c #616161616262",
+"3 c gray40",
+"4 c #6A6A6A6A6A6A",
+"5 c #6F6F6F6F6F6F",
+"6 c #727272727373",
+"7 c #767676767676",
+"8 c #777777777777",
+"9 c #797979797979",
+"0 c #7B7B7B7B7A7A",
+"q c #7B7B7B7B7B7B",
+"w c #A5A500000000",
+"e c #C1C100000000",
+"r c #C3C300000000",
+"t c #C7C700000000",
+"y c #C9C900000000",
+"u c #E3E300000000",
+"i c #E5E500000000",
+"p c #E7E700000000",
+"a c #E9E900000000",
+"s c #EBEB00000000",
+"d c #EDED00000000",
+"f c #EFEF00000000",
+"g c #F1F100000000",
+"h c #F3F300000000",
+"j c #F5F500000000",
+"k c #F1F10B0B0B0B",
+"l c #F1F10F0F0E0E",
+"z c #F2F210101010",
+"x c #F2F213131313",
+"c c #F2F214141414",
+"v c #F3F319191919",
+"b c #F3F31A1A1A1A",
+"n c #F4F41F1F1F1F",
+"m c #F4F420202020",
+"M c #F5F525252525",
+"N c #F5F526262626",
+"B c #F2F22C2C2C2C",
+"V c #F2F22F2F2F2F",
+"C c #F6F62B2B2B2B",
+"Z c #F6F62C2C2C2C",
+"A c #F2F232323232",
+"S c #F3F332323232",
+"D c #F3F335353535",
+"F c #F7F731313131",
+"G c #F4F436363636",
+"H c #F4F43B3B3B3B",
+"J c #F5F53F3F3F3F",
+"K c #F8F837373737",
+"L c #F6F644444444",
+"P c #F7F749494949",
+"I c #F7F74E4E4E4E",
+"U c #F8F853535353",
+"Y c #F9F957575757",
+"T c #FAFA5C5C5C5C",
+"R c #CFCFDBDB0000",
+"E c #D1D1DFDF0000",
+"W c #DFDFD1D10000",
+"Q c #DBDBDDDD0000",
+"! c #D5D5E1E10000",
+"~ c #E1E1E3E30000",
+"^ c #F1F1EFEF0000",
+"/ c #F7F7E9E90000",
+"( c #FBFBE7E70000",
+") c #FDFDE9E90000",
+"_ c #F4F4EDED1F1F",
+"` c #F9F9F7F70000",
+"' c #F3F3F2F21919",
+"] c #F4F4F4F41E1E",
+"[ c #F5F5EEEE2424",
+"{ c #F6F6EFEF2B2B",
+"} c #F4F4EDED3939",
+"| c #F5F5F5F52323",
+" . c #F5F5F5F52424",
+".. c #F6F6F6F62929",
+"X. c #F6F6F6F62A2A",
+"o. c #F7F7F7F72E2E",
+"O. c #F7F7F7F72F2F",
+"+. c #F1F1F1F13434",
+"@. c #F7F7F1F13030",
+"#. c #F7F7F7F73030",
+"$. c #F2F2F2F23A3A",
+"%. c #F5F5F5F53D3D",
+"&. c #F8F8F2F23636",
+"*. c #F9F9F3F33D3D",
+"=. c #F8F8F8F83434",
+"-. c #F8F8F8F83535",
+";. c #F8F8F8F83636",
+":. c #F9F9F9F93A3A",
+">. c #F9F9F9F93B3B",
+",. c #F9F9F9F93C3C",
+"<. c #F3F3F3F34040",
+"1. c #F6F6F6F64242",
+"2. c #F4F4F4F44646",
+"3. c #F7F7F7F74646",
+"4. c #F5F5F5F54B4B",
+"5. c #F7F7F7F74B4B",
+"6. c #FAFAFAFA4040",
+"7. c #FAFAFAFA4141",
+"8. c #FAFAFAFA4242",
+"9. c #FBFBFBFB4646",
+"0. c #FBFBFBFB4747",
+"q. c #FCFCFCFC4B4B",
+"w. c #FCFCFCFC4C4C",
+"e. c #F2F2F2F25050",
+"r. c #F6F6F6F65151",
+"t. c #F7F7F7F75454",
+"y. c #FDFDFDFD5151",
+"u. c #FBFBF6F66060",
+"i. c #FCFCFCFC6565",
+"p. c #FCFCFCFC6969",
+"a. c #FDFDFDFD6D6D",
+"s. c #F9F9F9F97474",
+"d. c #FDFDFDFD7171",
+"f. c None",
+/* pixels */
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+" ^ ( ( ( ` / j g g f f ",
+" q 0 q 7 s.d.a.p.i.t.T Y U I f ",
+" q < , , t.y.w.0.9.1.K F Z P p ",
+" q , , * t.0.9.8.*.&.F Z N L p ",
+" 7 - - % 4.9.6.*.;.O.C N m J p ",
+" 6 * % $ 2.6.,.;.#.{ M n v H p ",
+" 5 % $ + <.>.=.O.X.[ n v c G p ",
+" 4 $ O X $.=.o.X. ._ v c l S t ",
+" 3 O X . +.o...| ] ' x l k S r ",
+" 2 < , - e.4.3.1.%.} D S V V r ",
+" Q ! ! R ~ W t t r t w ",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f."
+};
diff --git a/src/images/flags/BF.xpm b/src/images/flags/BF.xpm
new file mode 100644
index 0000000..d20fb85
--- /dev/null
+++ b/src/images/flags/BF.xpm
@@ -0,0 +1,172 @@
+/* XPM */
+static const char *BF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 150 2",
+" c black",
+". c #000021210000",
+"X c #000023230000",
+"o c #000025250000",
+"O c #000029290000",
+"+ c #00002B2B0000",
+"@ c #00002D2D0000",
+"# c #000031310000",
+"$ c #000037370000",
+"% c #00003B3B0000",
+"& c #00003F3F0000",
+"* c #000045450000",
+"= c #00004B4B0000",
+"- c #000051510000",
+"; c #000055550000",
+": c #00005B5B0000",
+"> c #000061610000",
+", c #000067670000",
+"< c #00006B6B0000",
+"1 c #000071710000",
+"2 c #000075750000",
+"3 c #00007D7D0000",
+"4 c #0B0B95950B0B",
+"5 c #0F0F97970E0E",
+"6 c #101097971010",
+"7 c #131399991313",
+"8 c #141499991414",
+"9 c #14149B9B1414",
+"0 c #18189C9C1919",
+"q c #19199C9C1919",
+"w c #19199D9D1919",
+"e c #1E1E9F9F1E1E",
+"r c #1F1F9F9F1F1F",
+"t c #1F1FA2A21F1F",
+"y c #2323A1A12323",
+"u c #2626A3A32424",
+"i c #2424A4A42424",
+"p c #2A2AA3A32A2A",
+"a c #2929A4A42929",
+"s c #2A2AA7A72A2A",
+"d c #2C2CA2A22C2C",
+"f c #2F2FA4A42F2F",
+"g c #2E2EA6A62E2E",
+"h c #2F2FA6A62F2F",
+"j c #3232A5A53232",
+"k c #3333A6A63232",
+"l c #3434A9A93434",
+"z c #3535A8A83535",
+"x c #3535AAAA3434",
+"c c #3636A9A93636",
+"v c #3939A9A93939",
+"b c #3A3AACAC3A3A",
+"n c #3D3DACAC3D3D",
+"m c #3F3FAFAF3F3F",
+"M c #3B3BB4B43A3A",
+"N c #4040AFAF3F3F",
+"B c #4242AEAE4242",
+"V c #4040B2B24040",
+"C c #4444B1B14444",
+"Z c #4545B2B24545",
+"A c #4646B0B04646",
+"S c #4545B4B44545",
+"D c #4B4BB2B24B4B",
+"F c #4949B4B44949",
+"G c #4949B7B74949",
+"H c #4F4FB9B94F4F",
+"J c #5050B4B45050",
+"K c #5454B7B75555",
+"L c #5858B9B95858",
+"P c #5D5DBCBC5D5D",
+"I c #6161BEBE6262",
+"U c #6666C0C06666",
+"Y c #6A6AC3C36A6A",
+"T c #6F6FC6C66F6F",
+"R c #AFAF00000000",
+"E c #CBCB00000000",
+"W c #D8D82A2A1A1A",
+"Q c #D9D930301F1F",
+"! c #DBDB34342525",
+"~ c #DDDD3A3A2B2B",
+"^ c #E7E700000000",
+"/ c #E9E900000000",
+"( c #EBEB00000000",
+") c #EDED00000000",
+"_ c #EFEF00000000",
+"` c #F1F100000000",
+"' c #F3F300000000",
+"] c #F5F500000000",
+"[ c #F7F700000000",
+"{ c #F9F900000000",
+"} c #FBFB00000000",
+"| c #FDFD00000000",
+" . c red",
+".. c #F4F420202020",
+"X. c #F5F525252525",
+"o. c #F5F526262626",
+"O. c #F6F62B2B2B2B",
+"+. c #F6F62C2C2C2C",
+"@. c #F7F730303030",
+"#. c #F7F731313131",
+"$. c #F5F53F3F3F3F",
+"%. c #F8F837373636",
+"&. c #F8F837373737",
+"*. c #F8F83B3B3636",
+"=. c #F9F93C3C3C3C",
+"-. c #F9F93C3C3D3D",
+";. c #DDDD49493B3B",
+":. c #DEDE56564646",
+">. c #E0E05B5B4B4B",
+",. c #F6F644444444",
+"<. c #F7F749494949",
+"1. c #F7F74E4E4E4E",
+"2. c #FAFA42424242",
+"3. c #FBFB47474747",
+"4. c #FBFB49494646",
+"5. c #FCFC4B4B4B4B",
+"6. c #FCFC4C4C4C4C",
+"7. c #FDFD4F4F5050",
+"8. c #F8F853535353",
+"9. c #F9F957575757",
+"0. c #FDFD51515151",
+"q. c #FDFD54545454",
+"w. c #FAFA5C5C5C5C",
+"e. c #FEFE58585858",
+"r. c #FEFE59595959",
+"t. c #FEFE5C5C5C5C",
+"y. c #FEFE5F5F5F5F",
+"u. c #E1E160604F4F",
+"i. c #E2E264645353",
+"p. c #E8E87F7F7373",
+"a. c #FBFB60606060",
+"s. c #FCFC65656565",
+"d. c #FCFC69696969",
+"f. c #FDFD6D6D6D6D",
+"g. c #FDFD70707171",
+"h. c #FEFE74747474",
+"j. c #FEFE76767676",
+"k. c #FEFE77777777",
+"l. c #FEFE79797979",
+"z. c #FFFF7B7B7A7A",
+"x. c #FFFF7B7B7B7B",
+"c. c #F1F1B4B43C3C",
+"v. c #F2F2B6B64141",
+"b. c #D8D8DBDB3030",
+"n. c #D7D7E8E82F2F",
+"m. c #D8D8E9E93535",
+"M. c #EAEAF0F03636",
+"N. c #EAEAF0F03B3B",
+"B. c #DDDDDDDD4040",
+"V. c None",
+/* pixels */
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+" . . . .} . . .} } [ [ ' ' ) ) ",
+" .x.x.x.j.h.f.f.d.s.a.w.9.8.1.( ",
+" .x.t.t.t.q.q.5.3.2.-.%.#.+.<.( ",
+" .x.t.t.q.q.5.3.2.-.%.#.O.o.,.^ ",
+" .j.9.q.6.5.3.c.c.*. at .O.o...$.^ ",
+"E p.i.u.:.:.b.N.M.b.~ ! W W ;.R ",
+"3 T H G G S V m.n.s i t w 0 c @ ",
+"2 Y G C V b l f p u e 0 8 5 l + ",
+"1 U C m b l f s y e 0 7 5 4 f o ",
+"< I P L K J D A B n v c j f d . ",
+", > : ; - = * & % $ # @ + o . o ",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V."
+};
diff --git a/src/images/flags/BG.xpm b/src/images/flags/BG.xpm
new file mode 100644
index 0000000..3a54dd1
--- /dev/null
+++ b/src/images/flags/BG.xpm
@@ -0,0 +1,166 @@
+/* XPM */
+static const char *BG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 144 2",
+" c black",
+". c #00003B3B0000",
+"X c #00003D3D0000",
+"o c #00003F3F0000",
+"O c #000049490000",
+"+ c #454576761010",
+"@ c #49497A7A1414",
+"# c #4D4D7C7C1919",
+"$ c #52527F7F1F1F",
+"% c #000083830000",
+"& c #000085850000",
+"* c #14149E9E1414",
+"= c #1A1A9C9C1A1A",
+"- c #1F1F9F9F1F1F",
+"; c #1919A1A11919",
+": c #1F1FA4A41F1F",
+"> c #20209E9E2020",
+", c #2525A0A02525",
+"< c #2525A2A22525",
+"1 c #2424A5A52424",
+"2 c #2A2AA5A52B2B",
+"3 c #2B2BA4A42B2B",
+"4 c #2A2AA8A82A2A",
+"5 c #2F2FABAB2F2F",
+"6 c #3030A6A63030",
+"7 c #3030A8A83030",
+"8 c #3636A9A93636",
+"9 c #3636ABAB3636",
+"0 c #3535AEAE3535",
+"q c #3636ACAC3636",
+"w c #3B3BAAAA3B3B",
+"e c #3B3BADAD3B3B",
+"r c #3B3BACAC3C3C",
+"t c #3F3FABAB3F3F",
+"y c #3B3BB0B03A3A",
+"u c #565683832424",
+"i c #5B5B87872A2A",
+"p c #5F5F8A8A2F2F",
+"a c #61618A8A3232",
+"s c #63638E8E3434",
+"d c #686891913A3A",
+"f c #6C6C94943F3F",
+"g c #4141AFAF4141",
+"h c #4040B0B04040",
+"j c #4040B3B34040",
+"k c #4646B2B24646",
+"l c #4545B6B64545",
+"z c #4B4BB4B44B4B",
+"x c #4B4BB5B54B4B",
+"c c #4F4FB7B74F4F",
+"v c #4949B8B84949",
+"b c #4F4FBBBB4F4F",
+"n c #5050B6B65050",
+"m c #5353B9B95353",
+"M c #5454B8B85454",
+"N c #5858BABA5858",
+"B c #707098984545",
+"V c #74749B9B4949",
+"C c #6F6FC8C86F6F",
+"Z c #7272C6C67373",
+"A c #7676C7C77676",
+"S c #DDDD00000000",
+"D c #DFDF00000000",
+"F c #E1E100000000",
+"G c #E3E300000000",
+"H c #E5E500000000",
+"J c #E7E700000000",
+"K c #E9E900000000",
+"L c #EBEB00000000",
+"P c #EDED00000000",
+"I c #EFEF00000000",
+"U c #F1F100000000",
+"Y c #F3F300000000",
+"T c #F5F500000000",
+"R c #F7F700000000",
+"E c #F1F10B0B0B0B",
+"W c #F1F10F0F0E0E",
+"Q c #F9F900000000",
+"! c #F2F213131313",
+"~ c #F3F319191919",
+"^ c #F4F41E1E1E1E",
+"/ c #F5F523232323",
+"( c #F2F22C2C2C2C",
+") c #F2F22F2F2F2F",
+"_ c #F6F629292929",
+"` c #F7F72E2E2E2E",
+"' c #F2F232323232",
+"] c #F3F335353535",
+"[ c #F4F439393939",
+"{ c #F5F53D3D3D3D",
+"} c #F8F834343434",
+"| c #F9F93A3A3A3A",
+" . c #FAFA3F3F3F3F",
+".. c #F6F642424242",
+"X. c #F7F746464646",
+"o. c #F7F74B4B4B4B",
+"O. c #FAFA44444444",
+"+. c #F8F850505050",
+"@. c #F9F954545555",
+"#. c #F9F958585858",
+"$. c #FAFA5D5D5D5D",
+"%. c #FBFB61616262",
+"&. c #FCFC66666666",
+"*. c #8E8EAEAE6A6A",
+"=. c #B7B7D3D3B7B7",
+"-. c #DDDDDDDDDDDD",
+";. c #DFDFDFDFDFDF",
+":. c #D1D1E7E7D1D1",
+">. c #DBDBEBEBDBDB",
+",. c #DDDDECECDDDD",
+"<. c #DFDFEDEDDFDF",
+"1. c #E0E0EDEDDFDF",
+"2. c #E1E1E3E3E3E3",
+"3. c gray90",
+"4. c #E7E7E7E7E7E7",
+"5. c #E0E0EFEFE0E0",
+"6. c #E9E9E9E9E9E9",
+"7. c gray92",
+"8. c gray93",
+"9. c #EFEFEFEFEFEF",
+"0. c #E2E2F0F0E2E2",
+"q. c #E3E3F1F1E3E3",
+"w. c #E4E4F2F2E4E4",
+"e. c #E6E6F3F3E6E6",
+"r. c #E7E7F3F3E7E7",
+"t. c #E8E8F4F4E8E8",
+"y. c #E9E9F5F5E9E9",
+"u. c #EAEAF6F6EAEA",
+"i. c #EDEDF7F7EDED",
+"p. c #F1F1F1F1F1F1",
+"a. c #F3F3F3F3F3F3",
+"s. c gray96",
+"d. c #F6F6F6F6F6F6",
+"f. c gray97",
+"g. c #F8F8F8F8F8F8",
+"h. c #F9F9F9F9F9F9",
+"j. c gray98",
+"k. c #FBFBFBFBFBFB",
+"l. c gray99",
+"z. c #FDFDFDFDFDFD",
+"x. c #FDFDFDFDFEFE",
+"c. c #FEFEFEFEFEFE",
+"v. c gray100",
+"b. c None",
+/* pixels */
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"s.s.s.s.s.a.a.9.9.9.8.7.6.4.3.2.",
+"s.v.v.v.v.v.x.x.v.k.j.j.j.j.s.;.",
+"s.v.v.v.v.j.v.x.j.j.j.j.f.s.f.-.",
+":.i.u.u.e.e.e.e.5.5.5.1.,.>.1.=.",
+"% A N M c z g g r 8 6 3 , > t X ",
+"% Z m c x k h e 8 7 2 < - = w . ",
+"% C b v l h y 0 7 4 1 : ; * 0 X ",
+"O *.V B f d s p i u u # @ + a ",
+"Q &.X. .| } ` _ / ^ ~ ! W E ) D ",
+"Q %.$.#. at .+.o.X...{ [ ] ' ) ) S ",
+"T T U P P P P J J H H D D S S S ",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b."
+};
diff --git a/src/images/flags/BH.xpm b/src/images/flags/BH.xpm
new file mode 100644
index 0000000..6baf118
--- /dev/null
+++ b/src/images/flags/BH.xpm
@@ -0,0 +1,89 @@
+/* XPM */
+static const char * BH_xpm[] = {
+"16 16 70 1",
+" c None",
+". c #FED0D0",
+"+ c #FFA9A9",
+"@ c #FD0000",
+"# c #FD0303",
+"$ c #F30000",
+"% c #ED0000",
+"& c #FFFFFF",
+"* c #FBFBFB",
+"= c #FEE8E7",
+"- c #FE8686",
+"; c #FD6E6E",
+"> c #FD6D6D",
+", c #FB6665",
+"' c #FC6565",
+") c #FA5C5C",
+"! c #F95757",
+"~ c #F85353",
+"{ c #F74E4E",
+"] c #EB0000",
+"^ c #FD5757",
+"/ c #FD5151",
+"( c #FC4C4C",
+"_ c #FC4B4B",
+": c #FA4242",
+"< c #F83535",
+"[ c #F73131",
+"} c #F62C2C",
+"| c #F74949",
+"1 c #FDEBEB",
+"2 c #FB4747",
+"3 c #F93C3C",
+"4 c #F62B2B",
+"5 c #F52626",
+"6 c #F64444",
+"7 c #E50000",
+"8 c #FDD0D0",
+"9 c #FD5B5C",
+"0 c #FB4646",
+"a c #F93B3C",
+"b c #F42020",
+"c c #F53F3F",
+"d c #FCFCFC",
+"e c #FA4040",
+"f c #F72F2F",
+"g c #F41E1E",
+"h c #F31919",
+"i c #F43B3B",
+"j c #FBC8C7",
+"k c #F21414",
+"l c #F43636",
+"m c #FBFAFA",
+"n c #FAE2E2",
+"o c #F83434",
+"p c #F21010",
+"q c #DD0000",
+"r c #FAC4C4",
+"s c #F95151",
+"t c #F21313",
+"u c #F10F0E",
+"v c #F10B0B",
+"w c #F22F2F",
+"x c #F9F7F7",
+"y c #F9D8D8",
+"z c #F85858",
+"A c #F64242",
+"B c #F33232",
+"C c #F22C2C",
+"D c #EF8787",
+"E c #E30000",
+" ",
+" ",
+" ",
+"....+@@@@##$$$%%",
+".&&&*=-;>,')!~{]",
+".&&&.,^/(_:<[}|]",
+".&&&&1>_2:3[4567",
+".&&*89_0:a<45bc7",
+".&ddd1,ea<f5ghi7",
+".&ddj~ea<f4ghkl7",
+".d**mn!of45hkp[q",
+".d*mrsa}4bgtuvwq",
+".d**xyz|0AclBwCq",
+"....D%%]]77Eqqqq",
+" ",
+" "};
diff --git a/src/images/flags/BI.xpm b/src/images/flags/BI.xpm
new file mode 100644
index 0000000..d7f848c
--- /dev/null
+++ b/src/images/flags/BI.xpm
@@ -0,0 +1,181 @@
+/* XPM */
+static const char *BI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 159 2",
+" c black",
+". c #00004D4D0000",
+"X c #000053530000",
+"o c #000059590000",
+"O c #00005B5B0000",
+"+ c #00005D5D0000",
+"@ c #000063630000",
+"# c #000065650000",
+"$ c #00007D7D0000",
+"% c #7D7D00000000",
+"& c #00008D8D0000",
+"* c #000097970000",
+"= c #00009F9F0000",
+"- c #17178F8F0101",
+"; c #1B1B99990707",
+": c #0303A1A10303",
+"> c #25259B9B0F0F",
+", c #29299D9D1111",
+"< c #2B2BA7A72121",
+"1 c #2828A5A52727",
+"2 c #3939AEAE3838",
+"3 c #3A3AADAD3A3A",
+"4 c #3737B1B13434",
+"5 c #4141AFAF4141",
+"6 c #4444AFAF4444",
+"7 c #4949B6B64747",
+"8 c #4A4AB4B44A4A",
+"9 c #5050B9B95050",
+"0 c #5454BBBB5555",
+"q c #5757BEBE5656",
+"w c #5959BEBE5959",
+"e c #5959BFBF5959",
+"r c #5D5DBFBF5D5D",
+"t c #5E5EBFBF5E5E",
+"y c #6464BEBE6363",
+"u c #6060C0C05F5F",
+"i c #6666C4C46565",
+"p c #6969C2C26969",
+"a c #6B6BC1C16A6A",
+"s c #6C6CC6C66B6B",
+"d c #6C6CC4C46C6C",
+"f c #6D6DC5C56D6D",
+"g c #7171C5C57171",
+"h c #7070C6C67070",
+"j c #7373C8C87373",
+"k c #7676C9C97575",
+"l c #7D7DD0D07D7D",
+"z c #7D7DD0D07E7E",
+"x c #838300000000",
+"c c #8B8B00000000",
+"v c #8F8F00000000",
+"b c #919100000000",
+"n c #939300000000",
+"m c #999900000000",
+"M c #9D9D00000000",
+"N c #9F9F00000000",
+"B c #A3A300000000",
+"V c #ABAB00000000",
+"C c #C3C300000000",
+"Z c #CBCB00000000",
+"A c #CDCD00000000",
+"S c #CFCF00000000",
+"D c #D3D301010101",
+"F c #D5D500000000",
+"G c #D7D707070303",
+"H c #D5D509090909",
+"J c #D5D50F0F0F0F",
+"K c #D7D713131313",
+"L c #D9D917171717",
+"P c #D3D344444343",
+"I c #D5D54B4B4A4A",
+"U c #D9D955555555",
+"Y c #DEDE5B5B5B5B",
+"T c #DDDD5E5E5E5E",
+"R c #DDDD5F5F5F5F",
+"E c #DBDB63636363",
+"W c #DFDF67676666",
+"Q c #DCDC69696969",
+"! c #DDDD68686868",
+"~ c #DDDD6D6D6D6D",
+"^ c #E2E26A6A6A6A",
+"/ c #E2E26C6C6C6C",
+"( c #E2E277777777",
+") c #E4E471717171",
+"_ c #E5E574747474",
+"` c #E2E27A7A7A7A",
+"' c #8787CFCF8686",
+"] c #8181D1D18181",
+"[ c #8383D2D28484",
+"{ c #8888D2D28888",
+"} c #8C8CD4D48A8A",
+"| c #9797C1C19797",
+" . c #9090D5D59090",
+".. c #9595D8D89494",
+"X. c #9797D9D99797",
+"o. c #9A9ADADA9A9A",
+"O. c #9D9DDCDC9E9E",
+"+. c #B2B2E0E0B7B7",
+"@. c #D4D48C8C8282",
+"#. c #DADA9A9A9191",
+"$. c #C1C1A7A7ADAD",
+"%. c #E7E78A8A8A8A",
+"&. c #E8E885858585",
+"*. c #E9E984848484",
+"=. c #E8E889898989",
+"-. c #E8E88D8D8D8D",
+";. c #ECEC96969696",
+":. c #ECEC99999999",
+">. c #E7E7AAAAACAC",
+",. c #EDEDB3B3B4B4",
+"<. c #EDEDB9B9B9B9",
+"1. c #EFEFB5B5C7C7",
+"2. c #C1C1DFDFC1C1",
+"3. c #DDDDCFCFD7D7",
+"4. c #C3C3EBEBC7C7",
+"5. c #C9C9EAEACCCC",
+"6. c #C8C8EDEDCBCB",
+"7. c #CCCCEFEFD1D1",
+"8. c #D7D7F5F5DCDC",
+"9. c #EEEECFCFD0D0",
+"0. c #E3E3D1D1C7C7",
+"q. c #E6E6D5D5CDCD",
+"w. c #E7E7D8D8CFCF",
+"e. c #EFEFD0D0CFCF",
+"r. c #E7E7DEDED7D7",
+"t. c #F0F0C1C1C2C2",
+"y. c #F5F5C8C8C8C8",
+"u. c #FFFFCFCFDFDF",
+"i. c #FFFFD5D5D5D5",
+"p. c #F9F9DADADDDD",
+"a. c #F8F8DBDBDEDE",
+"s. c #E2E2E5E5DADA",
+"d. c #E8E8EAEADEDE",
+"f. c #EAEAF5F5F5F5",
+"g. c #ECECF7F7F2F2",
+"h. c #EDEDFCFCF4F4",
+"j. c #EBEBFAFAFAFA",
+"k. c #F7F7EAEAEFEF",
+"l. c #F2F2ECECF2F2",
+"z. c #F8F8EAEAF1F1",
+"x. c #FAFAEEEEF5F5",
+"c. c #F1F1F1F1F1F1",
+"v. c gray95",
+"b. c #F3F3F3F3F3F3",
+"n. c #F4F4F4F4F4F4",
+"m. c gray96",
+"M. c #F6F6F6F6F6F6",
+"N. c gray97",
+"B. c #FEFEF4F4FAFA",
+"V. c #F8F8F8F8F8F8",
+"C. c #F9F9F8F8F9F9",
+"Z. c #F9F9F9F9F9F9",
+"A. c gray98",
+"S. c #FBFBFBFBFBFB",
+"D. c gray99",
+"F. c #FDFDFDFDFDFD",
+"G. c #FEFEFEFEFEFE",
+"H. c gray100",
+"J. c None",
+/* pixels */
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"i.u.G F L K J H D S S Z C C 1.<.",
+"< H.H.y.*.:.;.=.=.-.%./ ,.Z.N.$ ",
+"- } 8.H.B._ _ p.p.^ Y k.N.7.r X ",
+", o.s O.H.H.Z.d.s.N.Z.N.' 2 g @ ",
+"> o.[ j i h.Z.q.0.N.g.7 8 w g O ",
+"; ..] z u 6.x.Z.Z.k.5.3 w 0 s o ",
+": ..z f q j.#.q.r. at .f.4 6 9 p @ ",
+": .t { S.Z.Z.N.N.N.v.v.p 1 y @ ",
+"& k 4.Z.Z.T T e.9.U P l.v.+.5 . ",
+"* Z.S.t.W ` ( Q E ~ Q I >.v.v.+ ",
+"2.3.V M B B M m n v v c % x $.| ",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J."
+};
diff --git a/src/images/flags/BJ.xpm b/src/images/flags/BJ.xpm
new file mode 100644
index 0000000..e7c6e2c
--- /dev/null
+++ b/src/images/flags/BJ.xpm
@@ -0,0 +1,163 @@
+/* XPM */
+static const char *BJ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 141 2",
+" c black",
+". c #000049490000",
+"X c #000053530000",
+"o c #000057570000",
+"O c #00005D5D0000",
+"+ c #000063630000",
+"@ c #000067670000",
+"# c #00006F6F0000",
+"$ c #000075750000",
+"% c #000077770000",
+"& c #00007B7B0000",
+"* c #00007F7F0000",
+"= c #000083830000",
+"- c #000085850000",
+"; c #000087870000",
+": c #000089890000",
+"> c #000091910000",
+", c #3A3AACAC3A3A",
+"< c #3C3CAAAA3A3A",
+"1 c #3E3EAEAE3E3E",
+"2 c #3F3FAFAF3F3F",
+"3 c #4040AFAF3F3F",
+"4 c #4343ADAD4040",
+"5 c #4444B1B14444",
+"6 c #4545B2B24545",
+"7 c #4848B0B04646",
+"8 c #4949B4B44949",
+"9 c #4949B5B54949",
+"0 c #4B4BB5B54B4B",
+"q c #4E4EB2B24B4B",
+"w c #4F4FB6B64F4F",
+"e c #4F4FB7B74F4F",
+"r c #5050B7B75050",
+"t c #5353B7B75151",
+"y c #5454B7B75555",
+"u c #5656B5B55555",
+"i c #5353B9B95353",
+"p c #5454B9B95454",
+"a c #5454BABA5454",
+"s c #5858BABA5656",
+"d c #5858B9B95858",
+"f c #5959BBBB5959",
+"g c #5858BCBC5858",
+"h c #5858BCBC5959",
+"j c #5959BCBC5959",
+"k c #5C5CBDBD5B5B",
+"l c #5C5CBDBD5C5C",
+"z c #5D5DBCBC5D5D",
+"x c #5C5CBEBE5C5C",
+"c c #5E5EBDBD5E5E",
+"v c #5F5FBFBF5F5F",
+"b c #6161BEBE6262",
+"n c #6666C0C06666",
+"m c #6A6AC3C36A6A",
+"M c #6F6FC4C46F6F",
+"N c #7272C6C67373",
+"B c #7676C8C87676",
+"V c #7777C8C87777",
+"C c #7979C8C87979",
+"Z c #7979C9C97979",
+"A c #7A7AC9C97A7A",
+"S c #7B7BCACA7A7A",
+"D c #7B7BCACA7B7B",
+"F c #DDDD00000000",
+"G c #DFDF00000000",
+"H c #E1E100000000",
+"J c #E3E300000000",
+"K c #E5E500000000",
+"L c #E7E700000000",
+"P c #E9E900000000",
+"I c #F1F10B0B0B0B",
+"U c #F1F10F0F0E0E",
+"Y c #F2F210101010",
+"T c #F2F213131313",
+"R c #F2F214141414",
+"E c #F3F319191919",
+"W c #F4F41E1E1E1E",
+"Q c #F4F41F1F1F1F",
+"! c #F3F326261A1A",
+"~ c #F4F42B2B1F1F",
+"^ c #F5F523232323",
+"/ c #F5F524242424",
+"( c #F2F22C2C2C2C",
+") c #F2F22F2F2F2F",
+"_ c #F6F629292929",
+"` c #F6F62A2A2A2A",
+"' c #F7F72F2F2F2F",
+"] c #F5F530302525",
+"[ c #F6F636362B2B",
+"{ c #F2F232323232",
+"} c #F3F332323232",
+"| c #F3F335353535",
+" . c #F4F436363636",
+".. c #F7F73B3B3030",
+"X. c #F4F439393939",
+"o. c #F5F53D3D3D3D",
+"O. c #F8F835353535",
+"+. c #F4F446463B3B",
+"@. c #F8F840403636",
+"#. c #F9F946463B3B",
+"$. c #F6F642424242",
+"%. c #F7F746464646",
+"&. c #E7E7E7E70000",
+"*. c #E9E9E9E90000",
+"=. c #EBEBEBEB0000",
+"-. c #EDEDEFEF0000",
+";. c #EFEFEFEF0000",
+":. c #F1F1F1F10000",
+">. c #F3F3F3F30000",
+",. c #F5F5F5F50000",
+"<. c #F7F7F7F70000",
+"1. c #F9F9F9F90000",
+"2. c #FBFBFBFB0000",
+"3. c #FDFDFDFD0000",
+"4. c #F4F4F4F42020",
+"5. c #F5F5F5F52525",
+"6. c #F5F5F5F52626",
+"7. c #F6F6F6F62B2B",
+"8. c #F6F6F6F62C2C",
+"9. c #F7F7F7F73030",
+"0. c #F7F7F7F73131",
+"q. c #F5F5F5F53F3F",
+"w. c #F8F8F8F83636",
+"e. c #F8F8F8F83737",
+"r. c #F9F9F9F93C3C",
+"t. c #F9F9F9F93D3D",
+"y. c #F6F6F6F64444",
+"u. c #F7F7F7F74949",
+"i. c #F7F7F7F74E4E",
+"p. c #FAFAFAFA4141",
+"a. c #FAFAFAFA4242",
+"s. c #FBFBFBFB4747",
+"d. c #FCFCFCFC4C4C",
+"f. c #F8F8F8F85353",
+"g. c #F9F9F9F95757",
+"h. c #FAFAFAFA5C5C",
+"j. c #FBFBFBFB6060",
+"k. c #FCFCFCFC6565",
+"l. c #FCFCFCFC6969",
+"z. c #FDFDFDFD6D6D",
+"x. c None",
+/* pixels */
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"> : : : - = = 3.2.1.<.,.,.:.-.-.",
+"- D D D B D D z.l.k.j.h.g.f.i.=.",
+": D v l p v k d.s.p.t.e.0.8.u.=.",
+"- D k k a f p s.p.t.e.0.7.6.y.&.",
+": B a a r a u p.t.e.8.7.6.4.q.&.",
+"- N i w 0 w q #.o...[ ] ~ ! +.L ",
+"* M e 9 6 8 7 O.' _ ^ W E R X.J ",
+"& m 9 6 4 5 4 ' _ ^ W E R Y } G ",
+"& b 5 1 , 1 < _ ^ W E R U I [ G ",
+"# b c d y f y %.$.o.X.| { ) ( F ",
+"$ @ + O o X . P L L J J G F F F ",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x."
+};
diff --git a/src/images/flags/BM.xpm b/src/images/flags/BM.xpm
new file mode 100644
index 0000000..be55a21
--- /dev/null
+++ b/src/images/flags/BM.xpm
@@ -0,0 +1,182 @@
+/* XPM */
+static const char *BM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 160 2",
+" c black",
+". c #343430302F2F",
+"X c #000000005959",
+"o c #000000006B6B",
+"O c #33331B1B6B6B",
+"+ c #7F7F15153D3D",
+"@ c #6B6B1D1D4D4D",
+"# c #7F7F25254D4D",
+"$ c #65656767A3A3",
+"% c #7676B5B55E5E",
+"& c #7979B8B86262",
+"* c #7C7CBDBD6666",
+"= c #7E7EBDBD6666",
+"- c #6B6BC3C3E4E4",
+"; c #6F6FC5C5E5E5",
+": c #818100000000",
+"> c #838300000000",
+", c #878700000000",
+"< c #898900000000",
+"1 c #8B8B00000000",
+"2 c #8F8F00000000",
+"3 c #919100000000",
+"4 c #939300000000",
+"5 c #979700000000",
+"6 c #999900000000",
+"7 c #9B9B00000000",
+"8 c #9D9D00000000",
+"9 c #9F9F00000000",
+"0 c #838317173D3D",
+"q c #A3A300000000",
+"w c #A7A700000000",
+"e c #ABAB00000000",
+"r c #AFAF00000000",
+"t c #B1B100000000",
+"y c #B3B300000000",
+"u c #B5B500000000",
+"i c #B7B700000000",
+"p c #B9B900000000",
+"a c #BBBB00000000",
+"s c #878746466A6A",
+"d c #929253537979",
+"f c #AFAF67677F7F",
+"g c #C2C20B0B0B0B",
+"h c #CACA0F0F0E0E",
+"j c #C5C510101010",
+"k c #C7C719191919",
+"l c #CBCB13131313",
+"z c #C9C91E1E1E1E",
+"x c #CBCB1F1F1F1F",
+"c c #CFCF19191919",
+"v c #D9D91B1B1515",
+"b c #CBCB23232323",
+"n c #CBCB24242424",
+"m c #CACA2C2C2C2C",
+"M c #CACA2F2F2F2F",
+"N c #CBCB2F2F2F2F",
+"B c #CDCD29292929",
+"V c #CDCD2A2A2A2A",
+"C c #CECE2A2A2A2A",
+"Z c #CFCF2C2C2C2C",
+"A c #CFCF2E2E2E2E",
+"S c #CFCF2F2F2F2F",
+"D c #CCCC32323232",
+"F c #CDCD32323232",
+"G c #CFCF30303030",
+"H c #CFCF31313131",
+"J c #CDCD35353535",
+"K c #CECE36363636",
+"L c #CFCF39393939",
+"P c #CFCF3B3B3B3B",
+"I c #D1D134343434",
+"U c #D1D135353535",
+"Y c #D1D136363636",
+"T c #D1D137373737",
+"R c #D3D336363636",
+"E c #D3D33A3A3A3A",
+"W c #D2D23B3B3D3D",
+"Q c #D0D03D3D3D3D",
+"! c #D2D23F3F3F3F",
+"~ c #D4D43B3B3A3A",
+"^ c #D4D43C3C3C3C",
+"/ c #D4D43C3C3D3D",
+"( c #D4D43F3F3F3F",
+") c #D5D53F3F3F3F",
+"_ c #D2D242424242",
+"` c #D3D344444444",
+"' c #D3D346464646",
+"] c #D5D541414242",
+"[ c #D5D542424242",
+"{ c #D6D640404040",
+"} c #D6D644444444",
+"| c #D6D645454545",
+" . c #D7D747474747",
+".. c #D5D549494949",
+"X. c #D5D54B4B4B4B",
+"o. c #D7D74E4E4E4E",
+"O. c #D8D849494949",
+"+. c #D8D84A4A4949",
+"@. c #DBDB4F4F4F4F",
+"#. c #D7D750505050",
+"$. c #D8D853535353",
+"%. c #D8D854545555",
+"&. c #D9D957575757",
+"*. c #DADA58585858",
+"=. c #DBDB5C5C5C5C",
+"-. c #DBDB5D5D5D5D",
+";. c #C5C55B5B6767",
+":. c #C6C65E5E6969",
+">. c #C7C762626E6E",
+",. c #C9C967677575",
+"<. c #DDDD60606060",
+"1. c #DDDD61616262",
+"2. c #DFDF65656565",
+"3. c #DEDE66666666",
+"4. c #DDDD69696A6A",
+"5. c #DEDE6E6E6E6E",
+"6. c #DFDF78787A7A",
+"7. c #E0E06A6A6A6A",
+"8. c #E1E16F6F6F6F",
+"9. c #E4E46B6B6969",
+"0. c #E4E472726F6F",
+"q. c #E5E574747272",
+"w. c #E8E87C7C7979",
+"e. c #858569699595",
+"r. c #9C9C78789B9B",
+"t. c #AFAF75758C8C",
+"y. c #C3C37C7C8E8E",
+"u. c #8080BFBF6A6A",
+"i. c #8888C3C37272",
+"p. c #99998B8B8B8B",
+"a. c #91918686B1B1",
+"s. c #B8B883839A9A",
+"d. c #BABA83839999",
+"f. c #8F8FA0A0CDCD",
+"g. c #A3A3A0A0C3C3",
+"h. c #D5D588889090",
+"j. c #D9D9A1A1AAAA",
+"k. c #D1D1AFAFBBBB",
+"l. c #DADAADADB6B6",
+"z. c #E2E282828484",
+"x. c #E3E389898B8B",
+"c. c #EBEB84848181",
+"v. c #E7E794949595",
+"b. c #E5E5B9B9BFBF",
+"n. c #F1F1A5A5A2A2",
+"m. c #F1F1AAAAA7A7",
+"M. c #DADAB7B7C1C1",
+"N. c #E7E7BDBDC3C3",
+"B. c #DFDFC1C1CBCB",
+"V. c #E8E8CFCFD6D6",
+"C. c #E2E2D5D5DFDF",
+"Z. c #EFEFD8D8D8D8",
+"A. c #F1F1DADAD9D9",
+"S. c #F2F2DCDCDBDB",
+"D. c #F3F3DFDFDEDE",
+"F. c #F2F2E0E0E0E0",
+"G. c #F3F3E7E7E7E7",
+"H. c #F4F4E5E5E5E5",
+"J. c #F4F4E8E8E8E8",
+"K. c None",
+/* pixels */
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+",.e.o + 0 X @ ;.u u u t r e w w ",
+"O N.C.l.j.M.V.g.4.2.<.=.&.$.o.8 ",
+"c v.c.q.9.w.w.5. .[ / T H Z ..7 ",
+"# b.n.z.x.m.h.t.[ ^ H.J.G.F.` 5 ",
+"$ B.a.s.s.f.k.r.W T D.; - A.! 4 ",
+"v y.d >.:.s f 0.T S S.. p.A.L 2 ",
+"p 8. at . . .[ E T S C i.& % = K 1 ",
+"p 7.+. ./ E T Z C b x u.* j H , ",
+"p 2. ./ E I Z m b z k l h g M , ",
+"t <.=.*.%.#...` _ ! L K D M m + ",
+"u t e w w 8 8 7 4 2 2 2 , , + 1 ",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K."
+};
diff --git a/src/images/flags/BN.xpm b/src/images/flags/BN.xpm
new file mode 100644
index 0000000..e6d15d5
--- /dev/null
+++ b/src/images/flags/BN.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *BN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #0B0B0B0B0B0B",
+"X c #0F0F0F0F0E0E",
+"o c #131313131313",
+"O c gray8",
+"+ c #181819191919",
+"@ c #191919191919",
+"# c gray12",
+"$ c #2C2C2C2C2C2C",
+"% c #2F2F2F2F2F2F",
+"& c #4A4A2F2F3030",
+"* c #404035353535",
+"= c #525229293636",
+"- c gray27",
+"; c #474745454545",
+": c #404040404949",
+"> c #49494A4A4949",
+", c #4B4B4A4A4B4B",
+"< c gray31",
+"1 c #535353535353",
+"2 c gray38",
+"3 c #727272727373",
+"4 c #767676767676",
+"5 c #D3D376765F5F",
+"6 c #DDDD76765E5E",
+"7 c #D5D57F7F6C6C",
+"8 c #DDDD7E7E6A6A",
+"9 c #B3B387870000",
+"0 c #B2B2A4A43737",
+"q c #D7D7A7A70000",
+"w c #D9D9A9A90000",
+"e c #D9D9ABAB0000",
+"r c #DDDDAFAF0000",
+"t c #D5D5B5B50000",
+"y c #D7D7B9B90000",
+"u c #D7D7BBBB0000",
+"i c #DBDBB3B30000",
+"p c #DBDBB5B50000",
+"a c #DFDFB3B30000",
+"s c #DFDFB5B50000",
+"d c #CDCDACAC3333",
+"f c #CECEBDBD3B3B",
+"g c #E1E1B7B70000",
+"h c #E1E1B9B90000",
+"j c #E3E3BBBB0000",
+"k c #E3E3BDBD0000",
+"l c #E5E5BFBF0000",
+"z c #D4D484847373",
+"x c #D7D787877777",
+"c c #DDDD83837070",
+"v c #DDDD82827272",
+"b c #DFDF89897777",
+"n c #C9C9AEAE4747",
+"m c #E1E188887878",
+"M c #E9E9C1C10000",
+"N c #E9E9C5C50000",
+"B c #EBEBC5C50000",
+"V c #EBEBC7C70000",
+"C c #EDEDC7C70000",
+"Z c #EDEDCBCB0000",
+"A c #EFEFC9C90000",
+"S c #EFEFCBCB0000",
+"D c #EFEFCDCD0000",
+"F c #F1F1CFCF0000",
+"G c #F1F1D1D10000",
+"H c #F1F1D3D30000",
+"J c #F3F3D1D10000",
+"K c #F3F3D3D30000",
+"L c #F3F3D7D70000",
+"P c #F5F5D3D30000",
+"I c #F5F5D5D50000",
+"U c #F5F5D9D90000",
+"Y c #E7E7CDCD3333",
+"T c #E8E8CECE3737",
+"R c #EEEED8D82F2F",
+"E c #EAEAD7D73F3F",
+"W c #EDEDD7D73B3B",
+"Q c #F0F0D9D93535",
+"! c #F1F1DCDC3535",
+"~ c #F2F2DDDD3A3A",
+"^ c #F2F2DEDE3B3B",
+"/ c #F5F5E6E63D3D",
+"( c #D8D8C2C24747",
+") c #D0D0C2C25757",
+"_ c #EFEFDBDB4B4B",
+"` c #EDEDD2D25050",
+"' c #EFEFDDDD5050",
+"] c #F4F4DFDF4040",
+"[ c #F4F4DEDE4545",
+"{ c #F1F1DEDE4E4E",
+"} c #F2F2DEDE4D4D",
+"| c #F0F0DDDD5050",
+" . c #F1F1E5E54141",
+".. c #F2F2E6E64646",
+"X. c #F6F6E6E64343",
+"o. c #F1F1E0E04848",
+"O. c #F4F4E0E04848",
+"+. c #F6F6E3E34848",
+"@. c #F6F6E3E34A4A",
+"#. c #F5F5E1E14D4D",
+"$. c #F8F8EDED4D4D",
+"%. c #F2F2E1E15151",
+"&. c #F3F3E2E25757",
+"*. c #F5F5E6E65353",
+"=. c #F6F6E5E55050",
+"-. c #F3F3E2E25858",
+";. c #F3F3E0E05E5E",
+":. c #F4F4E3E35B5B",
+">. c #F4F4E2E25C5C",
+",. c #F6F6E4E45F5F",
+"<. c #F7F7E8E85555",
+"1. c #F5F5E4E46060",
+"2. c #F7F7E5E56464",
+"3. c #F7F7E7E76868",
+"4. c #F7F7E7E76C6C",
+"5. c #F7F7E8E86868",
+"6. c #F7F7E9E96C6C",
+"7. c #F4F4E7E77878",
+"8. c #F8F8EAEA7070",
+"9. c #F9F9EBEB7070",
+"0. c #F9F9EAEA7474",
+"q. c #F9F9EDED7575",
+"w. c #F9F9E9E97878",
+"e. c #FAFAEAEA7A7A",
+"r. c #FAFAECEC7979",
+"t. c #FAFAECEC7D7D",
+"y. c #898987878787",
+"u. c #AAAAAAAAAAAA",
+"i. c #DCDC9A9A9191",
+"p. c #FCFCEEEE8E8E",
+"a. c #FCFCF2F2A3A3",
+"s. c #C2C2C8C8C8C8",
+"d. c #C3C3C9C9C9C9",
+"f. c #C7C7D3D3D3D3",
+"g. c #C9C9D1D1D1D1",
+"h. c #D5D5DBDBDFDF",
+"j. c #DADADFDFDFDF",
+"k. c #DFDFDFDFDFDF",
+"l. c #E4E4DEDEF8F8",
+"z. c #F5F5F2F2D7D7",
+"x. c gray89",
+"c. c gray90",
+"v. c #EDEDE4E4E2E2",
+"b. c #FCFCFBFBE8E8",
+"n. c gray95",
+"m. c #F3F3F3F3F3F3",
+"M. c #F2F2F7F7F7F7",
+"N. c #F4F4F4F4F4F4",
+"B. c #F4F4F5F5F5F5",
+"V. c gray96",
+"C. c #F6F6F6F6F6F6",
+"Z. c #F9F9F3F3F3F3",
+"A. c gray99",
+"S. c #FDFDFDFDFDFD",
+"D. c #FEFEFEFEFEFE",
+"F. c gray100",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"U P I I I F P F F S A C B M l k ",
+"F.F.a.p.t.e.e.w.9.4.3.2.,.:.&.g ",
+"F.F.F.F.F.b.t.| ` @.[ ] ^ ! %.a ",
+"y.F.F.F.F.F.A.h.i.#.O.^ Q R } r ",
+" 4 1 g.j.A.Z.b v l.M.C.z.| } q ",
+" 3 1 < , z x g.v.b v C.N.n.C.x.",
+"U 7.) > ; : 7 * & 5 s.f.N.n.N.x.",
+"H q.<.$.o.( n 8 6 = # + O ; u.k.",
+"F 8.#.+.X./ W T Y d + o X . % ",
+"D 6.5.1.>.-.*.%.} .. .E f 0 $ ",
+"Z V V l k g i g p e q i u y t 9 ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/BO.xpm b/src/images/flags/BO.xpm
new file mode 100644
index 0000000..6ee5916
--- /dev/null
+++ b/src/images/flags/BO.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *BO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000083830000",
+"X c #000087870000",
+"o c #00008B8B0000",
+"O c #00008F8F0000",
+"+ c #000091910000",
+"@ c #000093930000",
+"# c #000099990000",
+"$ c #00009D9D0000",
+"% c #00009F9F0000",
+"& c #0000A3A30000",
+"* c #0000A7A70000",
+"= c #0000ABAB0000",
+"- c #0000AFAF0000",
+"; c #0000B1B10000",
+": c #0000B3B30000",
+"> c #0000B7B70000",
+", c #1919C5C51A1A",
+"< c #1D1DC7C71D1D",
+"1 c #2222C8C82222",
+"2 c #2626CACA2626",
+"3 c #2B2BCCCC2B2B",
+"4 c #3131CECE3131",
+"5 c #3838CDCD3838",
+"6 c #3B3BCDCD3B3B",
+"7 c #3E3ECECE3E3E",
+"8 c #3636D0D03636",
+"9 c #3B3BD1D13B3B",
+"0 c #515195950000",
+"q c #4141D0D04141",
+"w c #4141D3D34141",
+"e c #4646D1D14545",
+"r c #4646D5D54646",
+"t c #4949D2D24949",
+"y c #4A4AD7D74A4A",
+"u c #4D4DD4D44D4D",
+"i c #4F4FD9D94F4F",
+"p c #5151D6D65151",
+"a c #5555D8D85555",
+"s c #5B5BD8D85B5B",
+"d c #5E5EDADA5F5F",
+"f c #6363DCDC6363",
+"g c #6767DDDD6767",
+"h c #6B6BDEDE6B6B",
+"j c #6F6FE0E06F6F",
+"k c #DBDB1F1F0000",
+"l c #E9E900000000",
+"z c #EBEB00000000",
+"x c #EDED00000000",
+"c c #EFEF00000000",
+"v c #F1F100000000",
+"b c #F3F300000000",
+"n c #F5F500000000",
+"m c #F7F700000000",
+"M c #F9F900000000",
+"N c #FBFB00000000",
+"B c #FDFD01010000",
+"V c #FDFD09090000",
+"C c #FDFD0B0B0000",
+"Z c #FDFD11110000",
+"A c #FFFF15150303",
+"S c #F5F56D6D0000",
+"D c #F6F660605454",
+"F c #F7F764645959",
+"G c #F8F869695E5E",
+"H c #F9F96D6D6363",
+"J c #F7F776766C6C",
+"K c #FAFA71716767",
+"L c #FBFB75756C6C",
+"P c #FCFC78786F6F",
+"I c #F7F77A7A7070",
+"U c #F8F87D7D7575",
+"Y c #FDFD7C7C7272",
+"T c #FDFD7F7F7676",
+"R c #9393C5C50000",
+"E c #ACACCDCD2828",
+"W c #AFAFCECE2C2C",
+"Q c #B0B0D0D03030",
+"! c #B3B3D2D23535",
+"~ c #B5B5D4D43A3A",
+"^ c #B8B8D6D63F3F",
+"/ c #B8B8D4D44646",
+"( c #BABAD7D74444",
+") c #BCBCD8D84949",
+"_ c #BFBFDADA4E4E",
+"` c #C5C59D9D0000",
+"' c #C9C9A1A10000",
+"] c #CBCBA3A30000",
+"[ c #EFEF96964848",
+"{ c #F0F099994D4D",
+"} c #F2F29C9C5252",
+"| c #F3F39F9F5656",
+" . c #F9F981817878",
+".. c #FAFA84847C7C",
+"X. c #FEFE83837A7A",
+"o. c #FEFE85857C7C",
+"O. c #FBFB88887F7F",
+"+. c #FEFE88887F7F",
+"@. c #F4F4A2A25B5B",
+"#. c #F1F1A4A46262",
+"$. c #F5F5A5A56060",
+"%. c #F5F5A8A86464",
+"&. c #F6F6AAAA6868",
+"*. c #F7F7ACAC6D6D",
+"=. c #F8F8AFAF7070",
+"-. c #F9F9B1B17373",
+";. c #F9F9B3B37777",
+":. c #E7E7C9C90000",
+">. c #E9E9CDCD0000",
+",. c #E9E9CFCF0000",
+"<. c #E4E4D1D13030",
+"1. c #E5E5D3D33434",
+"2. c #E5E5D3D33535",
+"3. c #E7E7D5D53939",
+"4. c #E8E8D7D73E3E",
+"5. c #E8E8D7D73F3F",
+"6. c #C1C1DCDC5353",
+"7. c #C3C3DDDD5858",
+"8. c #C5C5DFDF5D5D",
+"9. c #D0D0E5E57A7A",
+"0. c #E9E9D8D84343",
+"q. c #E9E9D9D94343",
+"w. c #E9E9D9D94444",
+"e. c #EBEBD9D94848",
+"r. c #EBEBD9D94949",
+"t. c #EBEBDADA4949",
+"y. c #E8E8D8D84E4E",
+"u. c #ECECDBDB4D4D",
+"i. c #ECECDCDC4E4E",
+"p. c #E9E9D8D85151",
+"a. c #E9E9DADA5555",
+"s. c #EDEDDDDD5252",
+"d. c #EDEDDDDD5353",
+"f. c #EEEEDEDE5757",
+"g. c #EFEFDEDE5757",
+"h. c #F0F0E0E05B5B",
+"j. c #F0F0E0E05C5C",
+"k. c #F1F1E1E15F5F",
+"l. c #F1F1E1E16161",
+"z. c #F1F1E3E36464",
+"x. c #F2F2E3E36565",
+"c. c #F2F2E4E46868",
+"v. c #F3F3E5E56C6C",
+"b. c #F4F4E8E87F7F",
+"n. c #FCFC8C8C8484",
+"m. c #FCFC8F8F8787",
+"M. c #FDFD91918A8A",
+"N. c #FDFD94948D8D",
+"B. c #FEFE97978F8F",
+"V. c #FEFE99999191",
+"C. c #FEFE9B9B9494",
+"Z. c #FFFF9C9C9595",
+"A. c #FFFF9D9D9595",
+"S. c #FBFBC1C18F8F",
+"D. c #F5F5E8E88484",
+"F. c #F6F6EAEA8787",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"A A A A Z V V B N N m m b b x x ",
+"A A.A.A.V.B.N.M.m.n.O... .U I z ",
+"A A.o.o.X.T Y Y L K H G F D J z ",
+"S S.;.-.=.*.&.%.$. at .| } { [ #.k ",
+",.F.v.c.x.l.j.f.d.i.t.w.5.3.a.] ",
+",.D.c.c.j.h.g.d.i.t.0.4.3.1.p.' ",
+":.b.c.j.j.g.d.u.w.0.0.3.1.<.y.` ",
+"R 9.8.7.6._ ) ( ( ~ ! Q W E / 0 ",
+"> h i y r w 9 5 3 3 2 1 < , 6 X ",
+": h h f d s a p u t e q 7 6 5 . ",
+"; ; = * & & $ # + + O o X X . . ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/BR.xpm b/src/images/flags/BR.xpm
new file mode 100644
index 0000000..21dd4eb
--- /dev/null
+++ b/src/images/flags/BR.xpm
@@ -0,0 +1,170 @@
+/* XPM */
+static const char *BR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 148 2",
+" c black",
+". c #000003030000",
+"X c #000007070000",
+"o c #00000B0B0000",
+"O c #00000D0D0000",
+"+ c #00000F0F0000",
+"@ c #000013130000",
+"# c #000019190000",
+"$ c #00001B1B0000",
+"% c #000021210000",
+"& c #000027270000",
+"* c #00002D2D0000",
+"= c #00002F2F0000",
+"- c #000035350000",
+"; c #00003B3B0000",
+": c #000041410000",
+"> c #000047470000",
+", c #00004B4B0000",
+"< c #00004D4D0000",
+"1 c #000051510000",
+"2 c #000053530000",
+"3 c #000057570000",
+"4 c #00005B5B0000",
+"5 c #00005D5D0000",
+"6 c #000061610000",
+"7 c #000063630000",
+"8 c #15157F7F1515",
+"9 c #2A2A5E5EF6F6",
+"0 c #2F2F6161F7F7",
+"q c #2F2F6B6BF7F7",
+"w c #36367070F8F8",
+"e c #3B3B7474F9F9",
+"r c #6D6D7373AAAA",
+"t c #42427171FAFA",
+"y c #47477575FBFB",
+"u c #40407878FAFA",
+"i c #44447878F8F8",
+"p c #60606767EEEE",
+"a c #65656969E2E2",
+"s c #6A6A6F6FEAEA",
+"d c #77777777E3E3",
+"f c #191982821919",
+"g c #1D1D85851D1D",
+"h c #1E1E85851E1E",
+"j c #373797971414",
+"k c #222287872222",
+"l c #2A2A8C8C2A2A",
+"z c #36368A8A3636",
+"x c #35358F8F3535",
+"c c #303090902F2F",
+"v c #343493933434",
+"b c #353593933535",
+"n c #363691913636",
+"m c #373792923737",
+"M c #3A3A93933B3B",
+"N c #3B3B94943B3B",
+"B c #3B3B96963B3B",
+"V c #3E3E96963E3E",
+"C c #3939A4A43434",
+"Z c #3F3F99994040",
+"A c #7676B7B73B3B",
+"S c #414198984141",
+"D c #42429B9B4242",
+"F c #454599994545",
+"G c #45459D9D4545",
+"H c #47479C9C4747",
+"J c #47479E9E4747",
+"K c #4C4C9E9E4C4C",
+"L c #4C4CA1A14C4C",
+"P c #4D4DA1A14D4D",
+"I c #5151A2A25151",
+"U c #5252A2A25252",
+"Y c #5151A4A45151",
+"T c #5656A4A45656",
+"R c #5757A4A45757",
+"E c #5B5BA7A75B5B",
+"W c #5B5BA8A85B5B",
+"Q c #5C5CAAAA5C5C",
+"! c #5F5FACAC5F5F",
+"~ c #6060A9A95F5F",
+"^ c #6363B2B24F4F",
+"/ c #6060B0B05858",
+"( c #6060AAAA6060",
+") c #6060ACAC6060",
+"_ c #6363AEAE6363",
+"` c #6464ADAD6464",
+"' c #6464ADAD6565",
+"] c #6767AFAF6767",
+"[ c #6868AFAF6969",
+"{ c #6666B0B06767",
+"} c #6B6BB1B16B6B",
+"| c #6D6DB3B36D6D",
+" . c #7171B4B47171",
+".. c #7575B8B87575",
+"X. c #7777B8B87777",
+"o. c #7A7ABABA7A7A",
+"O. c #7B7BBBBB7B7B",
+"+. c #7D7DBBBB7D7D",
+"@. c #7F7FBDBD7F7F",
+"#. c #5C5C8383E9E9",
+"$. c #7E7E9F9FD9D9",
+"%. c #73739A9AF9F9",
+"&. c #9E9ED2D23131",
+"*. c #A4A4D4D41919",
+"=. c #AFAFDCDC3F3F",
+"-. c #9595CACA7373",
+";. c #ADADDDDD4646",
+":. c #A8A8D9D95454",
+">. c #B0B0E1E14242",
+",. c #B3B3E2E26D6D",
+"<. c #B7B7E2E26969",
+"1. c #F4F4E9E91F1F",
+"2. c #F3F3F3F31919",
+"3. c #F3F3F3F31A1A",
+"4. c #F4F4F4F41E1E",
+"5. c #F4F4F4F41F1F",
+"6. c #F8F8EFEF3636",
+"7. c #F5F5F5F52525",
+"8. c #F6F6F6F62B2B",
+"9. c #F7F7F7F72E2E",
+"0. c #F9F9F0F03A3A",
+"q. c #F5F5EDED4444",
+"w. c #F6F6F2F24949",
+"e. c #FAFAFAFA4242",
+"r. c #FBFBFBFB4545",
+"t. c #FBFBFCFC4949",
+"y. c #FCFCFCFC4B4B",
+"u. c #FCFCFCFC4F4F",
+"i. c #FDFDF3F35151",
+"p. c #FBFBFBFB5555",
+"a. c #FAFAFDFD5454",
+"s. c #FDFDFCFC5050",
+"d. c #FDFDFDFD5151",
+"f. c #FDFDFDFD5353",
+"g. c #FCFCFCFC5A5A",
+"h. c #8F8F9494B3B3",
+"j. c #8080BEBE8080",
+"k. c #8080BEBE8181",
+"l. c #8181BEBE8181",
+"z. c #ADADACACA1A1",
+"x. c #ACACC6C6EBEB",
+"c. c #A8A8C0C0F3F3",
+"v. c #A9A9C0C0F6F6",
+"b. c #B9B9D5D5F7F7",
+"n. c #CDCDCACAA6A6",
+"m. c #D0D0E1E1FBFB",
+"M. c #DFDFE9E9F4F4",
+"N. c None",
+/* pixels */
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"7 7 7 7 7 5 4 4 1 , > : ; - = & ",
+"7 l. at .@.O.o.X.,.<.} { ' ~ E T % ",
+"7 l.{ { ~ Q d.g.a.e.H V B b I # ",
+"7 @._ ! :.i.d y t a 6.&.b c K @ ",
+"7 O.Q d.d.n.m.M.x.w r 8.7.l H o ",
+"5 -.f.y.y.#.u %.c.b.$.7.4.3.A ",
+"3 X.^ y.r.h.e i q v.z.4.3.j z + ",
+"1 .I L >.0.p 0 9 s 1.*.g f B ",
+"< | L H D C 9.w.q.4.k g f 8 b ",
+", [ ' ( W T I ;.>.F S S N b x ",
+": ; - = & % # @ + X ",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N."
+};
diff --git a/src/images/flags/BS.xpm b/src/images/flags/BS.xpm
new file mode 100644
index 0000000..e882b92
--- /dev/null
+++ b/src/images/flags/BS.xpm
@@ -0,0 +1,173 @@
+/* XPM */
+static const char *BS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 151 2",
+" c black",
+". c #00001B1B1B1B",
+"X c #00004B4B4B4B",
+"o c #4B4B48484646",
+"O c #494949494949",
+"+ c #49494A4A4949",
+"@ c #4B4B4A4A4B4B",
+"# c gray31",
+"$ c #454556565656",
+"% c #44445F5F5F5F",
+"& c #55554C4C4545",
+"* c #535353535353",
+"= c gray33",
+"- c #585858585858",
+"; c gray36",
+": c #58586C6C6C6C",
+"> c #5F5F7B7B7B7B",
+", c #626259595050",
+"< c gray40",
+"1 c #6A6A6A6A6A6A",
+"2 c #6F6F6F6F6F6F",
+"3 c #727272727373",
+"4 c #767676767676",
+"5 c #797979797979",
+"6 c #7B7B7B7B7A7A",
+"7 c #000081818181",
+"8 c #000083838383",
+"9 c #000087878787",
+"0 c #000089898989",
+"q c #00008B8B8B8B",
+"w c #00008F8F8F8F",
+"e c #000087879999",
+"r c #000091919191",
+"t c #000093939393",
+"y c #000099999999",
+"u c #00009D9D9D9D",
+"i c #00009F9F9F9F",
+"p c #00009B9BA9A9",
+"a c #0000A3A3A3A3",
+"s c #0000A7A7A7A7",
+"d c #0000A9A9A9A9",
+"f c #0000ABABABAB",
+"g c #0000AFAFAFAF",
+"h c #0000B1B1B1B1",
+"j c #0000B3B3B3B3",
+"k c #0000B5B5B5B5",
+"l c #0000B7B7B7B7",
+"z c #0000B9B9B9B9",
+"x c #0000BDBDBDBD",
+"c c #3F3FBFBFBFBF",
+"v c #0000C1C1C1C1",
+"b c #0000C3C3C3C3",
+"n c #0000C5C5C5C5",
+"m c #0000CBCBCBCB",
+"M c #0B0BC2C2CCCC",
+"N c #0F0FC4C4CDCD",
+"B c #1313C6C6CFCF",
+"V c #1818C7C7D1D1",
+"C c #1E1EC9C9D3D3",
+"Z c #2C2CCACACACA",
+"A c #2F2FCACACACA",
+"S c #2323CBCBD4D4",
+"D c #2929CDCDD6D6",
+"F c #2F2FCBCBD3D3",
+"G c #2C2CCECED6D6",
+"H c #2E2ECFCFD7D7",
+"J c #3232CCCCCCCC",
+"K c #3535CDCDCDCD",
+"L c #3939CFCFCFCF",
+"P c #3131D0D0D8D8",
+"I c #3434D1D1D9D9",
+"U c #3737D2D2DADA",
+"Y c #3D3DD0D0D0D0",
+"T c #3D3DD4D4DBDB",
+"R c #3A3ADCDCDFDF",
+"E c #616184848585",
+"W c #7B7B9E9E9E9E",
+"Q c #4242D2D2D2D2",
+"! c #4646D3D3D3D3",
+"~ c #4242D5D5DDDD",
+"^ c #4747D7D7DEDE",
+"/ c #4B4BD5D5D5D5",
+"( c #4E4ED7D7D7D7",
+") c #4949D5D5DBDB",
+"_ c #5C5CCFCFCFCF",
+"` c #5050D7D7D7D7",
+"' c #5353D8D8D8D8",
+"] c #5454D8D8D8D8",
+"[ c #5D5DD2D2D2D2",
+"{ c #5858D9D9D9D9",
+"} c #5858DFDFDFDF",
+"| c #5C5CDBDBDBDB",
+" . c #4C4CD8D8E0E0",
+".. c #5151DADAE1E1",
+"X. c #5454DBDBE2E2",
+"o. c #5959E4E4E7E7",
+"O. c #6161DDDDDDDD",
+"+. c #6565DDDDDDDD",
+"@. c #6969DFDFDFDF",
+"#. c #7B7BDFDFDFDF",
+"$. c #6D6DE0E0E0E0",
+"%. c #7070E2E2E2E2",
+"&. c #7474E2E2E2E2",
+"*. c #7777E3E3E3E3",
+"=. c #7979E8E8E8E8",
+"-. c #BABA9E9E3F3F",
+";. c #BABA9E9E4040",
+":. c #DFDF83830000",
+">. c #E3E38B8B0000",
+",. c #E5E58F8F0000",
+"<. c #E7E793930000",
+"1. c #C4C4AAAA4B4B",
+"2. c #C3C3AAAA5454",
+"3. c #DCDCBCBC4040",
+"4. c #F2F2C4C41010",
+"5. c #F2F2C6C61414",
+"6. c #F3F3C8C81919",
+"7. c #F3F3C8C81A1A",
+"8. c #F4F4C9C91F1F",
+"9. c #F4F4CACA1F1F",
+"0. c #F4F4CACA2020",
+"q. c #F5F5CBCB2424",
+"w. c #F5F5CBCB2525",
+"e. c #F5F5CCCC2525",
+"r. c #F5F5CDCD2626",
+"t. c #F6F6CDCD2A2A",
+"y. c #F6F6CDCD2B2B",
+"u. c #F6F6CECE2B2B",
+"i. c #F7F7CFCF2F2F",
+"p. c #F3F3CCCC3232",
+"a. c #F7F7CFCF3030",
+"s. c #F4F4CDCD3636",
+"d. c #F4F4CFCF3B3B",
+"f. c #F7F7D0D03131",
+"g. c #F5F5D2D23F3F",
+"h. c #F8F8D1D13434",
+"j. c #F8F8D1D13636",
+"k. c #F8F8D2D23535",
+"l. c #F8F8D2D23636",
+"z. c #F9F9D3D33A3A",
+"x. c #F9F9D3D33C3C",
+"c. c #F9F9D5D53A3A",
+"v. c #F9F9D8D83B3B",
+"b. c #F6F6D3D34444",
+"n. c #FAFAD5D54242",
+"m. c #FAFAD6D64141",
+"M. c #FBFBD7D74747",
+"N. c #FBFBD8D84646",
+"B. c #FCFCD8D84B4B",
+"V. c #FDFDDADA5151",
+"C. c None",
+/* pixels */
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"X n m b n b x x z l j j j d s d ",
+" W #.=.*.*.$.$. at .+.O.| { ` ( u ",
+" 6 > [ o.X.X. .^ ~ T U P G ) p ",
+" 6 ; : 2.V.B.M.n.x.j.f.u.r.b.<.",
+" 4 = = , 1.M.x.x.j.a.u.r.8.g.<.",
+" 3 * # @ o 3.v.j.a.u.w.8.7.d.,.",
+" 2 # @ & -.v.k.i.u.e.8.7.5.s.>.",
+" 1 o $ -.c.f.i.u.8.8.7.5.4.p.>.",
+" < % c R I H D S C V B N M F e ",
+" E [ } ] ` / ! Q Y L K J A A 7 ",
+". f l s a p u y t r r q 8 9 8 9 ",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C."
+};
diff --git a/src/images/flags/BT.xpm b/src/images/flags/BT.xpm
new file mode 100644
index 0000000..bf64cfe
--- /dev/null
+++ b/src/images/flags/BT.xpm
@@ -0,0 +1,175 @@
+/* XPM */
+static const char *BT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 153 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #E9E905050000",
+"& c #EDED0B0B0000",
+"* c #EDED0F0F0000",
+"= c #EFEF15150000",
+"- c #F1F100000000",
+"; c #F3F307070000",
+": c #CECE6D6D3E3E",
+"> c #EDED53530000",
+", c #F2F257571414",
+"< c #F1F167670B0B",
+"1 c #F1F16B6B0E0E",
+"2 c #F2F264641313",
+"3 c #F3F363631919",
+"4 c #F3F364641919",
+"5 c #F2F26B6B1010",
+"6 c #F2F26F6F1414",
+"7 c #F3F370701A1A",
+"8 c #F4F474741E1E",
+"9 c #F4F474741F1F",
+"0 c #F4F467672020",
+"q c #F4F463632C2C",
+"w c #F5F56D6D2323",
+"e c #F6F66D6D2A2A",
+"r c #F8F869693434",
+"t c #F5F573732626",
+"y c #F2F27B7B2C2C",
+"u c #F2F27C7C2F2F",
+"i c #F2F27D7D2F2F",
+"p c #F2F27F7F3232",
+"a c #F3F37F7F3232",
+"s c #BABA97977C7C",
+"d c #F3F39F9F0000",
+"f c #F3F380803535",
+"g c #F4F482823636",
+"h c #F4F482823939",
+"j c #F4F485853B3B",
+"k c #F5F587873D3D",
+"l c #F5F58A8A3F3F",
+"z c #EFEFBBBB0000",
+"x c #F3F3B1B10000",
+"c c #F3F3B3B30000",
+"v c #F1F1B7B70000",
+"b c #F5F5B1B10000",
+"n c #F7F7B7B70000",
+"m c #F5F5B9B90000",
+"M c #F7F7BBBB0000",
+"N c #F5F5BFBF0000",
+"B c #F9F9BDBD0000",
+"V c #F9F9BFBF0000",
+"C c #FBFBBDBD0000",
+"Z c #FBFBBFBF0000",
+"A c #D7D78B8B5757",
+"S c #DFDFBBBB5656",
+"D c #E6E688884444",
+"F c #F6F685854242",
+"G c #F7F786864949",
+"H c #F6F68D8D4444",
+"J c #F7F78E8E4E4E",
+"K c #F8F88A8A5050",
+"L c #F9F98F8F5555",
+"P c #F9F988885858",
+"I c #F1F191915151",
+"U c #F9F9ABAB5F5F",
+"Y c #F7F7C3C30000",
+"T c #F9F9C1C10000",
+"R c #F9F9C3C30000",
+"E c #ECECD7D75F5F",
+"W c #F2F2D2D24D4D",
+"Q c #FBFBD3D34646",
+"! c #FBFBD6D64747",
+"~ c #FBFBDEDE4545",
+"^ c #FBFBDADA4949",
+"/ c #FBFBDCDC4949",
+"( c #FCFCDBDB4B4B",
+") c #FCFCD9D94F4F",
+"_ c #FCFCDADA4F4F",
+"` c #FCFCDFDF4B4B",
+"' c #F7F7DDDD5757",
+"] c #F8F8D7D75353",
+"[ c #FDFDD9D95151",
+"{ c #FDFDDADA5050",
+"} c #FDFDDBDB5151",
+"| c #FDFDDBDB5353",
+" . c #FDFDDBDB5454",
+".. c #FAFADDDD5C5C",
+"X. c #FEFEDCDC5858",
+"o. c #FEFEDCDC5959",
+"O. c #FEFEDEDE5C5C",
+"+. c #FEFEDFDF5F5F",
+"@. c #E5E5CDCD6161",
+"#. c #FBFBDCDC6060",
+"$. c #FCFCDFDF6A6A",
+"%. c #FBFBE4E46262",
+"&. c #FCFCE2E26666",
+"*. c #FDFDE1E16F6F",
+"=. c #FDFDE2E26D6D",
+"-. c #FAFAE4E47272",
+";. c #FDFDE2E27171",
+":. c #FEFEE2E27373",
+">. c #FEFEE2E27474",
+",. c #FEFEE3E37676",
+"<. c #FEFEE4E47777",
+"1. c #FCFCE4E47979",
+"2. c #FEFEE5E57979",
+"3. c #FFFFE5E57A7A",
+"4. c #FFFFE5E57B7B",
+"5. c #ECECBABA9595",
+"6. c #F5F5A4A48787",
+"7. c #E6E6CACAB9B9",
+"8. c #E8E8DBDBA7A7",
+"9. c #F8F8E2E28B8B",
+"0. c #FCFCE8E88F8F",
+"q. c #F2F2E6E69B9B",
+"w. c #E8E8E4E4BBBB",
+"e. c #CFCFD7D7DDDD",
+"r. c #D4D4CECECCCC",
+"t. c #D6D6D0D0CFCF",
+"y. c #D6D6D7D7D9D9",
+"u. c #DDDDD8D8D8D8",
+"i. c #DFDFDFDFDFDF",
+"p. c #D6D6D7D7E5E5",
+"a. c #D4D4DBDBE6E6",
+"s. c #D6D6DDDDEEEE",
+"d. c #D8D8E2E2CECE",
+"f. c #D9D9E0E0E4E4",
+"g. c #DEDEE0E0E1E1",
+"h. c #DBDBE2E2EDED",
+"j. c #DDDDE5E5ECEC",
+"k. c #E0E0C0C0C0C0",
+"l. c #E3E3CFCFC1C1",
+"z. c #E0E0D7D7C9C9",
+"x. c #EAEAD2D2C3C3",
+"c. c #E8E8D8D8D0D0",
+"v. c #EBEBDDDDD5D5",
+"b. c #E7E7E4E4E2E2",
+"n. c #E7E7E4E4E4E4",
+"m. c #EFEFE8E8E5E5",
+"M. c #EAEAEAEAEAEA",
+"N. c #EAEAEAEAEBEB",
+"B. c #EDEDEBEBEEEE",
+"V. c #EAEAEDEDF3F3",
+"C. c #F0F0F2F2F6F6",
+"Z. c #FAFAFAFAF7F7",
+"A. c None",
+/* pixels */
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"R V V V V V M n V V n b c v v > ",
+"V 4.4.4.,.:.:.=.0.9.#...' ] J $ ",
+"R 4.+.O.o.| _ 4.Z.C.N.E S q G % ",
+"R 4.O.O. .| / ! N.V.m.B.: t H @ ",
+"R ,. . .| ^ W @.8.h.s e.l.0 l @ ",
+"V :.| _ _ Q s.a.f.j.b.b.8 7 j @ ",
+"M =._ ^ ~ w.a.v.c.y.x.D 4 6 g o ",
+"M $.^ q.d.t.c.7.e 6.i.r., 1 a X ",
+"c $.:.l.r.r a.A w 8 4 2 1 < p X ",
+"N %.U P L K 5.I F j h f p u y X ",
+"d ; - = = & $ $ $ @ o o o X . . ",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A."
+};
diff --git a/src/images/flags/BV.xpm b/src/images/flags/BV.xpm
new file mode 100644
index 0000000..ca6b0fa
--- /dev/null
+++ b/src/images/flags/BV.xpm
@@ -0,0 +1,149 @@
+/* XPM */
+static const char *BV_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 127 2",
+" c black",
+". c #00000000A5A5",
+"X c #00001D1DB7B7",
+"o c #03035353CFCF",
+"O c #09095959D1D1",
+"+ c #4B4B8383D5D5",
+"@ c #50508686D7D7",
+"# c #54548A8AD8D8",
+"$ c #59598D8DD9D9",
+"% c #5D5D9090DBDB",
+"& c #62629494DDDD",
+"* c #65659494DADA",
+"= c #65659696DEDE",
+"- c #66669797DEDE",
+"; c #6A6A9999E0E0",
+": c #6B6B9A9AE0E0",
+"> c #6F6F9C9CE1E1",
+", c #6F6F9D9DE1E1",
+"< c #73739F9FE3E3",
+"1 c #7777A3A3E4E4",
+"2 c #7A7AA4A4E2E2",
+"3 c #7A7AA5A5E5E5",
+"4 c #7B7BA6A6E5E5",
+"5 c #7E7EA8A8E7E7",
+"6 c #B1B100000000",
+"7 c #B5B500000000",
+"8 c #B9B900000000",
+"9 c #BBBB00000000",
+"0 c #BDBD00000000",
+"q c #BFBF00000000",
+"w c #C3C300000000",
+"e c #C5C500000000",
+"r c #C9C900000000",
+"t c #CBCB00000000",
+"y c #CFCF00000000",
+"u c #D1D100000000",
+"i c #D5D500000000",
+"p c #D7D700000000",
+"a c #D9D900000000",
+"s c #DBDB00000000",
+"d c #DDDD00000000",
+"f c #DADA0E0E0B0B",
+"g c #DCDC11110E0E",
+"h c #DCDC12121010",
+"j c #DDDD16161313",
+"k c #DDDD17171414",
+"l c #DFDF1B1B1919",
+"z c #DFDF1C1C1919",
+"x c #DEDE2E2E2C2C",
+"c c #E1E100000000",
+"v c #E0E021211E1E",
+"b c #E0E021211F1F",
+"n c #E1E126262323",
+"m c #E2E227272424",
+"M c #E2E229292626",
+"N c #E2E22B2B2929",
+"B c #E2E22C2C2A2A",
+"V c #E4E42E2E2B2B",
+"C c #E4E42E2E2C2C",
+"Z c #E0E031312F2F",
+"A c #E4E430302E2E",
+"S c #E4E431312F2F",
+"D c #E0E034343232",
+"F c #E0E035353232",
+"G c #E2E237373535",
+"H c #E5E534343131",
+"J c #E6E637373434",
+"K c #E7E739393636",
+"L c #E7E73A3A3737",
+"P c #E2E23B3B3939",
+"I c #E8E83E3E3C3C",
+"U c #E8E83F3F3D3D",
+"Y c #E4E440403D3D",
+"T c #E4E444444242",
+"R c #E6E646464444",
+"E c #E6E649494646",
+"W c #E7E74B4B4949",
+"Q c #E7E74C4C4B4B",
+"! c #E9E943434242",
+"~ c #E9E944444242",
+"^ c #EAEA46464444",
+"/ c #EAEA49494747",
+"( c #EBEB49494747",
+") c #EBEB4B4B4949",
+"_ c #EBEB4E4E4B4B",
+"` c #EBEB4E4E4C4C",
+"' c #E8E850504E4E",
+"] c #E9E955555353",
+"[ c #ECEC52525151",
+"{ c #EBEB5A5A5757",
+"} c #ECEC5E5E5C5C",
+"| c #ECEC5F5F5D5D",
+" . c #EFEF5D5D5C5C",
+".. c #F0F061615F5F",
+"X. c #EDED63636060",
+"o. c #EDED64646262",
+"O. c #EEEE67676565",
+"+. c #EEEE68686666",
+"@. c #EFEF6B6B6969",
+"#. c #EFEF6D6D6A6A",
+"$. c #EFEF6F6F6D6D",
+"%. c #F0F072727171",
+"&. c #F2F27A7A7979",
+"*. c #F2F27D7D7A7A",
+"=. c #F2F27D7D7B7B",
+"-. c #9292B6B6EAEA",
+";. c #9595B9B9EBEB",
+":. c gray89",
+">. c #E7E7E7E7E7E7",
+",. c gray93",
+"<. c #EFEFEFEFEFEF",
+"1. c gray95",
+"2. c #F3F3F3F3F3F3",
+"3. c #F4F4F4F4F4F4",
+"4. c gray96",
+"5. c #F6F6F6F6F6F6",
+"6. c gray97",
+"7. c #F8F8F8F8F8F8",
+"8. c #F9F9F9F9F9F9",
+"9. c gray98",
+"0. c #FBFBFBFBFBFB",
+"q. c #FBFBFCFCFBFB",
+"w. c gray99",
+"e. c #FDFDFDFDFDFD",
+"r. c #FEFEFEFEFEFE",
+"t. c gray100",
+"y. c None",
+/* pixels */
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"c c c t.O t.d s s s p p u u r r ",
+"c =.=.t.;.t.%.$. at .+.X.| { ] ' e ",
+"c =.| t.5 0.[ _ ( ~ Y J H C W w ",
+"c &. .t.2 t.) R ! I J H B M R q ",
+"t.t.t.0.1 t.0.0.0.0.0.4.4.4.4.>.",
+"o -.2 1 < : : = & $ $ # @ + * . ",
+"q.t.t.0.: 0.0.6.5.5.4.4.2.1.3.:.",
+"s #.( 0.: 0.J H N m v l k g F 7 ",
+"s O.~ 0.& 0.C N m v l j g f Z 6 ",
+"p X.| 0.2 0.W E T Y P G F Z x 6 ",
+"u u y <.X ,.w q q 9 9 7 7 6 6 6 ",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y."
+};
diff --git a/src/images/flags/BW.xpm b/src/images/flags/BW.xpm
new file mode 100644
index 0000000..293f56a
--- /dev/null
+++ b/src/images/flags/BW.xpm
@@ -0,0 +1,159 @@
+/* XPM */
+static const char *BW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 137 2",
+" c black",
+". c gray8",
+"X c #191919191919",
+"o c gray10",
+"O c gray12",
+"+ c #202020202020",
+"@ c gray14",
+"# c #252525252525",
+"$ c #2A2A2A2A2A2A",
+"% c #2A2A2B2B2B2B",
+"& c gray17",
+"* c #2F2F2F2F2F2F",
+"= c gray19",
+"- c #353535353535",
+"; c gray21",
+": c #3B3B3B3B3A3A",
+"> c gray23",
+", c #3B3B3B3B3C3C",
+"< c #3F3F3F3F3F3F",
+"1 c gray25",
+"2 c #414141414141",
+"3 c gray27",
+"4 c #464646464646",
+"5 c #49494A4A4949",
+"6 c #4B4B4A4A4B4B",
+"7 c #4B4B4B4B4B4B",
+"8 c gray31",
+"9 c #50504F4F5050",
+"0 c #535353535353",
+"q c gray33",
+"w c #585858585858",
+"e c #6F6F6F6F6F6F",
+"r c #727272727373",
+"t c #767676767676",
+"y c #00008383DDDD",
+"u c #00008585DDDD",
+"i c #00008787DFDF",
+"p c #00008989DDDD",
+"a c #00008989DFDF",
+"s c #00008B8BDDDD",
+"d c #00008D8DE1E1",
+"f c #00008F8FE3E3",
+"g c #00009191E5E5",
+"h c #00009595E7E7",
+"j c #00009B9BE9E9",
+"k c #00009D9DEBEB",
+"l c #00009F9FEBEB",
+"z c #0000A1A1EDED",
+"x c #0000A5A5EDED",
+"c c #0000A9A9EFEF",
+"v c #0000ADADF1F1",
+"b c #0000AFAFF3F3",
+"n c #0000B1B1F5F5",
+"m c #0000B3B3F7F7",
+"M c #0000B5B5F7F7",
+"N c #0000B7B7F5F5",
+"B c #0000B7B7F9F9",
+"V c #0000B9B9F9F9",
+"C c #0000BBBBFBFB",
+"Z c #0101BDBDFDFD",
+"A c #0707BFBFFDFD",
+"S c #0B0BC1C1FDFD",
+"D c #1111C3C3FDFD",
+"F c #1111C3C3FFFF",
+"G c #1313C3C3FFFF",
+"H c #1515C5C5FFFF",
+"J c #2525C9C9FFFF",
+"K c #3737C2C2F1F1",
+"L c #3B3BC4C4F1F1",
+"P c #3F3FC6C6F2F2",
+"I c #4444C7C7F3F3",
+"U c #4848C9C9F4F4",
+"Y c #4C4CCBCBF5F5",
+"T c #5151CDCDF6F6",
+"R c #5555CBCBF2F2",
+"E c #5757CBCBF2F2",
+"W c #5555CECEF6F6",
+"Q c #5555CFCFF7F7",
+"! c #5A5ACDCDF3F3",
+"~ c #5D5DCECEF3F3",
+"^ c #5959D0D0F7F7",
+"/ c #5A5AD1D1F8F8",
+"( c #5E5ED2D2F8F8",
+") c #5F5FD3D3F9F9",
+"_ c #6060CFCFF4F4",
+"` c #6363D1D1F5F5",
+"' c #6767D3D3F6F6",
+"] c #6363D4D4F9F9",
+"[ c #6363D4D4FAFA",
+"{ c #6767D5D5FAFA",
+"} c #6A6AD4D4F7F7",
+"| c #6C6CD5D5F7F7",
+" . c #6F6FD6D6F7F7",
+".. c #6868D6D6FAFA",
+"X. c #6B6BD7D7FBFB",
+"o. c #6F6FD8D8FCFC",
+"O. c #7272D7D7F7F7",
+"+. c #7373D8D8F8F8",
+"@. c #7373DADAFDFD",
+"#. c #7575D8D8F8F8",
+"$. c #7676D9D9F9F9",
+"%. c #7676DBDBFDFD",
+"&. c #7A7ADADAF9F9",
+"*. c #7A7ADCDCFEFE",
+"=. c #7E7EDCDCFAFA",
+"-. c #7C7CDEDEFEFE",
+";. c #7F7FDFDFFEFE",
+":. c #8181DDDDFBFB",
+">. c #8282DDDDFBFB",
+",. c #8484DEDEFCFC",
+"<. c #8888DFDFFCFC",
+"1. c #8A8AE1E1FDFD",
+"2. c #8E8EE2E2FEFE",
+"3. c #9090E2E2FEFE",
+"4. c #9393E4E4FEFE",
+"5. c #9494E5E5FEFE",
+"6. c #9595E4E4FFFF",
+"7. c #9696E5E5FFFF",
+"8. c #9797E5E5FFFF",
+"9. c #CDCDCDCDCDCD",
+"0. c #D5D5D5D5D5D5",
+"q. c gray93",
+"w. c #F1F1F1F1F1F1",
+"e. c gray95",
+"r. c #F3F3F3F3F3F3",
+"t. c #F4F4F4F4F4F4",
+"y. c gray96",
+"u. c #F6F6F6F6F6F6",
+"i. c gray97",
+"p. c #F8F8F8F8F8F8",
+"a. c #F9F9F9F9F9F9",
+"s. c gray98",
+"d. c #FBFBFBFBFBFB",
+"f. c gray99",
+"g. c #FDFDFDFDFDFD",
+"h. c #FEFEFEFEFEFE",
+"j. c None",
+/* pixels */
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"J H H H F S A Z C C M n v v c c ",
+"F 8.8.8.4.2.2.1.<.,.:.=.&.#.O.l ",
+"F 8.-.-.*.%. at .o.X.{ ] ) / Q | j ",
+"w.h.h.h.h.h.d.d.p.p.p.u.u.u.u.0.",
+" t w q 8 7 4 2 < ; = & @ + < ",
+" r 0 8 6 4 1 > ; = & @ O X , ",
+" e 8 7 4 < > - * & @ O X . ; ",
+"q.h.d.d.p.p.p.i.u.u.u.w.r.w.t.9.",
+"B :.{ [ ) ) Q T Y I I P L K R i ",
+"n >.=.&.#.+. .} ' ` ` ~ ! R R y ",
+"N b v c x z l l h g d d a a u a ",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j."
+};
diff --git a/src/images/flags/BY.xpm b/src/images/flags/BY.xpm
new file mode 100644
index 0000000..c27e859
--- /dev/null
+++ b/src/images/flags/BY.xpm
@@ -0,0 +1,170 @@
+/* XPM */
+static const char *BY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 148 2",
+" c black",
+". c #00002B2B0000",
+"X c #00002D2D0000",
+"o c #00002F2F0000",
+"O c #000033330000",
+"+ c #000037370000",
+"@ c #00003D3D0000",
+"# c #000041410000",
+"$ c #000047470000",
+"% c #00004D4D0000",
+"& c #000051510000",
+"* c #000057570000",
+"= c #00005D5D0000",
+"- c #0B0B9C9C0B0B",
+"; c #0F0F9E9E0E0E",
+": c #181898981010",
+"> c #1D1D9A9A1414",
+", c #1313A0A01313",
+"< c #1818A2A21919",
+"1 c #1E1EA5A51E1E",
+"2 c #21219D9D1919",
+"3 c #2727A0A01F1F",
+"4 c #2323A8A82323",
+"5 c #2C2CA3A32424",
+"6 c #2929AAAA2929",
+"7 c #2C2CA8A82C2C",
+"8 c #2F2FA9A92F2F",
+"9 c #2E2EADAD2E2E",
+"0 c #3131A5A52A2A",
+"q c #3737A7A72F2F",
+"w c #3232AAAA3232",
+"e c #3535ADAD3535",
+"r c #3A3AA7A73232",
+"t c #3C3CAAAA3434",
+"y c #3939AEAE3939",
+"u c #3434B0B03434",
+"i c #3A3AB3B33A3A",
+"p c #3D3DB0B03D3D",
+"a c #3F3FB5B53F3F",
+"s c #4141ADAD3A3A",
+"d c #4747B0B03F3F",
+"f c #4242B3B34242",
+"g c #4646B5B54646",
+"h c #4C4CB2B24545",
+"j c #4B4BB7B74B4B",
+"k c #5050B9B95050",
+"l c #5454BCBC5555",
+"z c #5858BEBE5858",
+"x c #E3E300000000",
+"c c #E5E500000000",
+"v c #E7E700000000",
+"b c #E9E900000000",
+"n c #EBEB00000000",
+"m c #EDED00000000",
+"M c #EFEF00000000",
+"N c #F1F100000000",
+"B c #F3F300000000",
+"V c #F5F500000000",
+"C c #F7F700000000",
+"Z c #F9F900000000",
+"A c #FBFB00000000",
+"S c #FDFD00000000",
+"D c red",
+"F c #F2F214141414",
+"G c #F3F319191919",
+"H c #F3F31A1A1A1A",
+"J c #F4F41F1F1F1F",
+"K c #F4F420202020",
+"L c #F5F524242424",
+"P c #F5F525252525",
+"I c #F5F526262626",
+"U c #F6F62A2A2A2A",
+"Y c #F6F62B2B2B2B",
+"T c #F6F62C2C2C2C",
+"R c #F7F72F2F2F2F",
+"E c #F7F730303030",
+"W c #F7F731313131",
+"Q c #F4F436363636",
+"! c #F4F43B3B3B3B",
+"~ c #F5F53F3F3F3F",
+"^ c #F8F835353535",
+"/ c #F8F836363636",
+"( c #F8F837373636",
+") c #F8F837373737",
+"_ c #FBFB35353B3B",
+"` c #F9F93B3B3A3A",
+"' c #F9F93B3B3B3B",
+"] c #F9F93B3B3C3C",
+"[ c #F9F93C3C3C3C",
+"{ c #F9F93C3C3D3D",
+"} c #EFEF5B5B5353",
+"| c #F6F644444444",
+" . c #F7F749494949",
+".. c #F7F74E4E4E4E",
+"X. c #FAFA40404040",
+"o. c #FAFA41414141",
+"O. c #FAFA41414242",
+"+. c #FAFA42424242",
+"@. c #FBFB45454545",
+"#. c #FBFB46464646",
+"$. c #FBFB47474747",
+"%. c #FBFB4A4A4949",
+"&. c #FCFC4A4A4B4B",
+"*. c #FCFC4B4B4B4B",
+"=. c #FCFC4C4C4C4C",
+"-. c #FCFC4F4F4F4F",
+";. c #FDFD4F4F5050",
+":. c #F8F853535353",
+">. c #F9F957575757",
+",. c #FDFD51515151",
+"<. c #FDFD54545454",
+"1. c #FDFD57575757",
+"2. c #FAFA5C5C5C5C",
+"3. c #FEFE59595959",
+"4. c #FEFE5C5C5C5C",
+"5. c #FFFF5F5F5F5F",
+"6. c #E9E970706666",
+"7. c #FBFB60606060",
+"8. c #FEFE61616161",
+"9. c #FCFC65656565",
+"0. c #FCFC69696969",
+"q. c #FDFD6D6D6D6D",
+"w. c #F8F877777575",
+"e. c #FDFD70707171",
+"r. c #FEFE74747474",
+"t. c #FEFE77777777",
+"y. c #FEFE79797979",
+"u. c #FFFF7E7E7E7E",
+"i. c #FDFDA3A3A3A3",
+"p. c #FEFEA5A5A5A5",
+"a. c #FFFFB3B3B3B3",
+"s. c #CBCBE3E3CBCB",
+"d. c #FFFFDFDFDFDF",
+"f. c #E7E7F3F3E7E7",
+"g. c #F5F5E7E7E9E9",
+"h. c #F9F9E9E9EBEB",
+"j. c #FCFCE9E9EAEA",
+"k. c #FDFDEBEBEBEB",
+"l. c #FEFEECECECEC",
+"z. c #FEFEEDEDEDED",
+"x. c #F7F7F4F4F2F2",
+"c. c #FAFAF3F3F2F2",
+"v. c #FFFFF1F1F1F1",
+"b. c #FEFEF4F4F4F4",
+"n. c #FEFEF5F5F5F5",
+"m. c #FFFFF5F5F5F5",
+"M. c #FFFFF9F9F9F9",
+"N. c None",
+/* pixels */
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"m.5.d.D A D D D A A C C B B m m ",
+"D M.u.y.t.r.q.q.0.9.2.5.>.:...n ",
+"v.a.k.5.3.<.<.-. at .O.~ ( W T .n ",
+"D m.8.3.<.<.&. at .O.~ ( W Y I | c ",
+"k.p.k.<.-.&. at .X.] ^ R Y I K ~ c ",
+"D m.<.-.&. at .X.` ^ W T I J G ! c ",
+"h.p.k.&. at .X.` ( R Y I K G F Q c ",
+"_ c.} h s s t q 0 5 3 > > : r o ",
+"h.w.f.a a u 9 6 4 3 < , ; - 8 O ",
+"C x.6.l l k j g f p y e w 8 7 . ",
+"g.n s.= * & % $ # @ @ + o o . o ",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N."
+};
diff --git a/src/images/flags/BZ.xpm b/src/images/flags/BZ.xpm
new file mode 100644
index 0000000..02f0d69
--- /dev/null
+++ b/src/images/flags/BZ.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *BZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #00000000A7A7",
+"X c #00000000B1B1",
+"o c #00000000C9C9",
+"O c #00000000CBCB",
+"+ c MediumBlue",
+"@ c #00000000CFCF",
+"# c #00000000D1D1",
+"$ c #00000000D7D7",
+"% c #00000101DBDB",
+"& c #00001F1FDDDD",
+"* c #00001717F1F1",
+"= c #00001F1FF1F1",
+"- c #00002525F1F1",
+"; c #00002B2BF3F3",
+": c #00002F2FF5F5",
+"> c #00003333F5F5",
+", c #13135151E7E7",
+"< c #17175353E5E5",
+"1 c #17175353E7E7",
+"2 c #1D1D5757E7E7",
+"3 c #1C1C5757E9E9",
+"4 c #3C3C5E5ED9D9",
+"5 c #23235B5BEAEA",
+"6 c #22225C5CE8E8",
+"7 c #28286060E9E9",
+"8 c #28286161EBEB",
+"9 c #2E2E6565EBEB",
+"0 c #2D2D6464EDED",
+"q c #37376A6AE4E4",
+"w c #33336969ECEC",
+"e c #36366A6AEAEA",
+"r c #34346969EEEE",
+"t c #39396D6DE9E9",
+"y c #39396D6DEFEF",
+"u c #3D3D6F6FE9E9",
+"i c #36367777E9E9",
+"p c #3E3E7171F0F0",
+"a c #40406060DADA",
+"s c #42426363DBDB",
+"d c #45456565DCDC",
+"f c #5B5B7979DFDF",
+"g c #41417373EBEB",
+"h c #44447676E9E9",
+"j c #46467676E8E8",
+"k c #46467676ECEC",
+"l c #4B4B7A7AEDED",
+"z c #41417B7BF4F4",
+"x c #46467F7FF5F5",
+"c c #50507E7EF0F0",
+"v c #61617575DEDE",
+"b c #65657979E0E0",
+"n c #6A6A7D7DE1E1",
+"m c #7676ACACBBBB",
+"M c #4A4A8787F2F2",
+"N c #4C4C8383F5F5",
+"B c #4C4C8383F6F6",
+"V c #4D4D8686F1F1",
+"C c #53538585F2F2",
+"Z c #51518686F6F6",
+"A c #51518787F6F6",
+"S c #56568A8AF7F7",
+"D c #57578A8AF8F8",
+"F c #5A5A8A8AF0F0",
+"G c #5B5B8D8DF8F8",
+"H c #5E5E9090F9F9",
+"J c #5E5E9191F9F9",
+"K c #5F5F9191F9F9",
+"L c #72728D8DD9D9",
+"P c #75759090D9D9",
+"I c #66668181E5E5",
+"U c #60608484ECEC",
+"Y c #65658888EDED",
+"T c #6E6E8080E1E1",
+"R c #69698C8CEDED",
+"E c #6D6D8F8FEEEE",
+"W c #61619292F6F6",
+"Q c #62629393F9F9",
+"! c #63639393F9F9",
+"~ c #61619797F9F9",
+"^ c #66669696FAFA",
+"/ c #6D6D9292F0F0",
+"( c #6C6C9999F8F8",
+") c #79798F8FE7E7",
+"_ c #70709C9CF8F8",
+"` c #75759F9FF9F9",
+"' c #7070A4A4C7C7",
+"] c #7D7DA2A2F6F6",
+"[ c #7878A2A2F9F9",
+"{ c #7B7BA4A4FAFA",
+"} c #7F7FA6A6FBFB",
+"| c #C3C300000000",
+" . c #C7C700000000",
+".. c #CBCB00000000",
+"X. c #CFCF00000000",
+"o. c #D1D100000000",
+"O. c #D3D300000000",
+"+. c #DDDD00000000",
+"@. c #E1E100000000",
+"#. c #E5E500000000",
+"$. c #E7E700000000",
+"%. c #E9E900000000",
+"&. c #EBEB00000000",
+"*. c #EDED00000000",
+"=. c #EFEF00000000",
+"-. c #F1F100000000",
+";. c #F5F500000000",
+":. c #F9F900000000",
+">. c #9393A0A0B3B3",
+",. c #B2B2A0A08E8E",
+"<. c #B4B4ADADABAB",
+"1. c #B3B3BDBDA6A6",
+"2. c #84849797ECEC",
+"3. c #84849B9BEEEE",
+"4. c #86869E9EEEEE",
+"5. c #8A8A9D9DE2E2",
+"6. c #8F8F9F9FE6E6",
+"7. c #88889E9EEFEF",
+"8. c #8383ABABDEDE",
+"9. c #8787B0B0D6D6",
+"0. c #8080A8A8FBFB",
+"q. c #A6A6B4B4C0C0",
+"w. c #8888C7C7AEAE",
+"e. c #8E8ED5D5BFBF",
+"r. c #BCBCC9C9AFAF",
+"t. c #BEBED5D5BEBE",
+"y. c #B1B1F4F4A9A9",
+"u. c #B1B1F4F4B2B2",
+"i. c #B9B9F5F5BDBD",
+"p. c #BABAF9F9B6B6",
+"a. c #9F9FCCCCC6C6",
+"s. c #9292D6D6C6C6",
+"d. c #9494DBDBC0C0",
+"f. c #9E9EDEDEC1C1",
+"g. c #A1A1D5D5D7D7",
+"h. c #A2A2E2E2C1C1",
+"j. c #AFAFEEEECCCC",
+"k. c #B7B7F1F1CFCF",
+"l. c #C9C9F5F5BEBE",
+"z. c #DDDDD5D5D3D3",
+"x. c #D4D4E9E9D2D2",
+"c. c #D2D2F5F5C8C8",
+"v. c #D5D5FCFCCDCD",
+"b. c #D8D8FAFACECE",
+"n. c #D9D9F5F5D3D3",
+"m. c #DEDEF3F3DADA",
+"M. c #DDDDE2E2E1E1",
+"N. c #E5E5FBFBDEDE",
+"B. c #E1E1E6E6E2E2",
+"V. c #E3E3E5E5E3E3",
+"C. c #E5E5ECECE4E4",
+"Z. c #E7E7FCFCE4E4",
+"A. c #EAEAF3F3ECEC",
+"S. c #F3F3EDEDE5E5",
+"D. c #F0F0F1F1F0F0",
+"F. c #F5F5F4F4F5F5",
+"G. c #F9F9F9F9F9F9",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+":.:.:.:.:.;.-.%.%.=.=.=.=.%.%.%.",
+"& 7.7.4.4.] 2.6.5.) / T n b v X ",
+"> 0.^ ! H ! g.k.j.s.V p y r C $ ",
+"> } Q H K i.Z.A.C.m.u.j r 9 l @ ",
+": { H G 8.v.S.r.1.z.l.' 9 5 k @ ",
+"; [ G D a.N.G.<.,.F.n.w.8 5 g @ ",
+"- [ S A 9.b.D.q.>.B.c.m 5 2 u o ",
+"= ( B N C p.x.B.M.t.y.q 2 < t o ",
+"* ( B B z M d.h.f.e.i 3 < , e o ",
+"% E R Y U F I P L f j d s a 4 . ",
+"=.%.#.#. at .+.o...| X.O.o.o.X.X.X.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/CA.xpm b/src/images/flags/CA.xpm
new file mode 100644
index 0000000..c60c383
--- /dev/null
+++ b/src/images/flags/CA.xpm
@@ -0,0 +1,169 @@
+/* XPM */
+static const char *CA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 147 2",
+" c black",
+". c #A1A100000000",
+"X c #A5A500000000",
+"o c #A7A700000000",
+"O c #ADAD00000000",
+"+ c #B1B100000000",
+"@ c #B5B500000000",
+"# c #BBBB00000000",
+"$ c #BFBF00000000",
+"% c #C3C300000000",
+"& c #C7C700000000",
+"* c #C9C900000000",
+"= c #CFCF00000000",
+"- c #D3D300000000",
+"; c #D5D500000000",
+": c #D9D900000000",
+"> c #DBDB00000000",
+", c #DFDF00000000",
+"< c #D4D415151414",
+"1 c #D6D61D1D1D1D",
+"2 c #D7D724242424",
+"3 c #D8D823232B2B",
+"4 c #DCDC2C2C2C2C",
+"5 c #DADA29293232",
+"6 c #D9D936363636",
+"7 c #DDDD30303838",
+"8 c #DEDE37373E3E",
+"9 c #E3E300000000",
+"0 c #E7E713131B1B",
+"q c #E9E91F1F2727",
+"w c #EDED27272F2F",
+"e c #E9E929292929",
+"r c #EDED2F2F3737",
+"t c #EFEF2D2D3737",
+"y c #E0E033333535",
+"u c #E2E23C3C3C3C",
+"i c #EFEF35353D3D",
+"p c #EFEF39393F3F",
+"a c #E0E03D3D4444",
+"s c #EFEF3B3B4343",
+"d c #F1F13F3F4545",
+"f c #DBDB44444444",
+"g c #DADA41414848",
+"h c #DCDC46464C4C",
+"j c #DDDD4A4A5050",
+"k c #DFDF4F4F5555",
+"l c #DBDB55555959",
+"z c #DEDE6A6A6B6B",
+"x c #E2E245454545",
+"c c #E7E743434343",
+"v c #E3E346464D4D",
+"b c #E5E54D4D5151",
+"n c #E6E64E4E5555",
+"m c #E6E64F4F5656",
+"M c #E2E255555B5B",
+"N c #E8E857575757",
+"B c #EAEA52525D5D",
+"V c #EAEA5D5D5E5E",
+"C c #EAEA5F5F5F5F",
+"Z c #ECEC59595959",
+"A c #F1F14B4B5353",
+"S c #E4E45B5B6060",
+"D c #ECEC5E5E6565",
+"F c #E5E561616464",
+"G c #E5E561616767",
+"H c #E2E26C6C6D6D",
+"J c #EDED63636666",
+"K c #ECEC66666666",
+"L c #E8E86A6A6A6A",
+"P c #EAEA6B6B6B6B",
+"I c #E8E868686D6D",
+"U c #E9E968686C6C",
+"Y c #E9E968686E6E",
+"T c #EEEE6D6D6E6E",
+"R c #EAEA6E6E7373",
+"E c #EEEE6E6E7474",
+"W c #EEEE6E6E7575",
+"Q c #ECEC71717676",
+"! c #EDED74747676",
+"~ c #EFEF75757A7A",
+"^ c #F0F073737373",
+"/ c #F1F17A7A7A7A",
+"( c #F1F17E7E7E7E",
+") c #E8E87B7B8181",
+"_ c #F1F17C7C8181",
+"` c gray75",
+"' c #EAEA83838484",
+"] c #EFEF80808484",
+"[ c #E9E98B8B8B8B",
+"{ c #F2F281818686",
+"} c #F0F084848A8A",
+"| c #F4F486868B8B",
+" . c #F2F28B8B8F8F",
+".. c #F5F58B8B9090",
+"X. c #F3F390909494",
+"o. c #F6F690909494",
+"O. c #F4F497979696",
+"+. c #F4F495959999",
+"@. c #F5F599999E9E",
+"#. c #F7F79E9EA2A2",
+"$. c #E8E8A8A8A7A7",
+"%. c #E9E9AFAFAFAF",
+"&. c #ECECBDBDBEBE",
+"*. c #F7F7A1A1A5A5",
+"=. c #F8F8A4A4A7A7",
+"-. c #F8F8A4A4A8A8",
+";. c gray77",
+":. c #C5C5C5C5C5C5",
+">. c #CBCBCBCBCBCB",
+",. c gray80",
+"<. c gray83",
+"1. c #E8E8C0C0C1C1",
+"2. c #EEEECECECDCD",
+"3. c #E8E8DDDDDBDB",
+"4. c #F5F5D0D0D3D3",
+"5. c #EBEBE3E3E3E3",
+"6. c #EDEDE1E1E2E2",
+"7. c #EDEDE6E6E6E6",
+"8. c #E9E9E9E9E9E9",
+"9. c gray92",
+"0. c #ECECECECECEC",
+"q. c gray93",
+"w. c #EEEEEEEEEEEE",
+"e. c #EFEFEFEFEFEF",
+"r. c #F1F1ECECEDED",
+"t. c #F0F0EEEEEEEE",
+"y. c #F7F7EBEBEDED",
+"u. c #F5F5EDEDEDED",
+"i. c #F6F6EDEDEDED",
+"p. c #F1F1F1F1F1F1",
+"a. c gray95",
+"s. c #F3F3F3F3F3F3",
+"d. c #F3F3F5F5F5F5",
+"f. c #F4F4F4F4F4F4",
+"g. c gray96",
+"h. c #F6F6F6F6F6F6",
+"j. c gray97",
+"k. c #F8F8F7F7F8F8",
+"l. c #F9F9F9F9F9F9",
+"z. c #F8F8FAFAFBFB",
+"x. c gray98",
+"c. c #FAFAFBFBFBFB",
+"v. c #FBFBFBFBFBFB",
+"b. c gray99",
+"n. c #FDFDFDFDFDFD",
+"m. c #FEFEFEFEFEFE",
+"M. c None",
+/* pixels */
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"A s d e f.f.f.s.f.s.s.q.- : - = ",
+"t -.=.O.m.m.m.u.y.v.z.k.U Q R * ",
+"p =.o.( m.v.z.' ) f.h.f.x n I % ",
+"i *.../ v.4.2.J V 1.&.s.u h G $ ",
+"t #.| ! v.U ! E I G f a.y a V # ",
+"w @.{ T x.[ Z D B c H e.4 a M @ ",
+"q +.( K z.u.H n b l 5.q.2 5 n + ",
+"0 ..~ C h.h.e.$.%.7.q.8.1 5 j O ",
+"9 ..E N h.s.a.3.5.q.q.8.< 3 h X ",
+", } ] P h.f.a.t.e.q.q.q.6 h g X ",
+": : - * <.,.>.>.;.;.;.` . X X X ",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M."
+};
diff --git a/src/images/flags/CC.xpm b/src/images/flags/CC.xpm
new file mode 100644
index 0000000..b200325
--- /dev/null
+++ b/src/images/flags/CC.xpm
@@ -0,0 +1,174 @@
+/* XPM */
+static const char *CC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 152 2",
+" c black",
+". c #000005050000",
+"X c #000009090000",
+"o c #00000B0B0000",
+"O c #00000F0F0000",
+"+ c #000011110000",
+"@ c #000017170000",
+"# c #000019190000",
+"$ c #00001D1D0000",
+"% c #000023230000",
+"& c #000025250000",
+"* c #00002B2B0000",
+"= c #000031310000",
+"- c #000037370000",
+"; c #00003D3D0000",
+": c #00003F3F0000",
+"> c #000043430000",
+", c #000045450000",
+"< c #000049490000",
+"1 c #00004B4B0000",
+"2 c #00004D4D0000",
+"3 c #00004F4F1919",
+"4 c #000051510000",
+"5 c #000053530000",
+"6 c #000055550000",
+"7 c #000057570000",
+"8 c #000059590000",
+"9 c #00005D5D0303",
+"0 c #00005D5D1717",
+"q c #0B0B7A7A3838",
+"w c #10107D7D3B3B",
+"e c #13137F7F3E3E",
+"r c #14147F7F3F3F",
+"t c #181882824343",
+"y c #191982824343",
+"u c #191982824444",
+"i c #1A1A84844444",
+"p c #1E1E85854747",
+"a c #1F1F86864848",
+"s c #1F1F87874848",
+"d c #242489894D4D",
+"f c #252589894D4D",
+"g c #25258B8B4E4E",
+"h c #26268B8B4E4E",
+"j c #2E2E8C8C4B4B",
+"k c #2A2A8A8A5252",
+"l c #2B2B8E8E5353",
+"z c #2C2C8A8A5151",
+"x c #2C2C8E8E5353",
+"c c #2F2F8D8D5555",
+"v c #31318F8F5757",
+"b c #33338F8F5858",
+"n c #38388E8E5050",
+"m c #343493935959",
+"M c #363691915B5B",
+"N c #373795955D5D",
+"B c #3C3C93935454",
+"V c #3E3E92925656",
+"C c #393994945D5D",
+"Z c #3A3A96965E5E",
+"A c #3D3D97976060",
+"S c #3B3B98986060",
+"D c #3C3C98986161",
+"F c #3D3D99996161",
+"G c #3F3F99996262",
+"H c #4E4E92923232",
+"J c #434396965A5A",
+"K c #464698985B5B",
+"L c #444498985E5E",
+"P c #4C4C9B9B5252",
+"I c #4C4C9D9D5E5E",
+"U c #5C5C9A9A4242",
+"Y c #424297976565",
+"T c #404099996363",
+"R c #42429B9B6666",
+"E c #44449C9C6767",
+"W c #45459D9D6767",
+"Q c #46469C9C6868",
+"! c #47479D9D6A6A",
+"~ c #4D4D9C9C6363",
+"^ c #4B4B9A9A6F6F",
+"/ c #49499E9E6A6A",
+"( c #49499F9F6C6C",
+") c #4B4B9E9E6C6C",
+"_ c #52529F9F6868",
+"` c #55559F9F6F6F",
+"' c #54549D9D7979",
+"] c #4F4FA0A06666",
+"[ c #4949A0A06C6C",
+"{ c #4E4EA1A16F6F",
+"} c #4F4FA2A27070",
+"| c #5050A0A06F6F",
+" . c #5757A1A16D6D",
+".. c #5757A2A26C6C",
+"X. c #5A5AA7A76F6F",
+"o. c #5454A4A47474",
+"O. c #5959A0A07373",
+"+. c #5959A5A57171",
+"@. c #5858A6A67777",
+"#. c #5D5DA9A97B7B",
+"$. c #65659E9E4D4D",
+"%. c #6060A2A25151",
+"&. c #6A6AA4A45353",
+"*. c #6F6FA6A65858",
+"=. c #7C7CADAD5F5F",
+"-. c #6464AEAE7070",
+";. c #6161ACAC7F7F",
+":. c #6C6CADAD7171",
+">. c #5F5FA2A28383",
+",. c #6565AEAE8282",
+"<. c #6666AEAE8383",
+"1. c #6969B0B08585",
+"2. c #6A6AB1B18787",
+"3. c #6D6DB3B38989",
+"4. c #6F6FB3B38A8A",
+"5. c #7070B5B58C8C",
+"6. c #7272B4B48F8F",
+"7. c #7474B3B38F8F",
+"8. c #7777B5B59191",
+"9. c #8C8CAAAA4747",
+"0. c #9393B0B05151",
+"q. c #8181B3B36D6D",
+"w. c #8181B5B57676",
+"e. c #8787B9B97676",
+"r. c #A8A8BABA4D4D",
+"t. c #ADADC4C47272",
+"y. c #B9B9C0C06B6B",
+"u. c #D1D1BEBE2727",
+"i. c #C2C2C0C03E3E",
+"p. c #CFCFC3C33C3C",
+"a. c #E6E6CCCC3E3E",
+"s. c #CACAC4C44848",
+"d. c #CFCFC9C95252",
+"f. c #D4D4C4C44141",
+"g. c #DADAC9C94141",
+"h. c #DADACACA4F4F",
+"j. c #E1E1CDCD4A4A",
+"k. c #E2E2CFCF5151",
+"l. c #ECECD2D24F4F",
+"z. c #E3E3D1D15454",
+"x. c #EAEAD4D45555",
+"c. c #FEFEDDDD5858",
+"v. c #E2E2D3D36565",
+"b. c #FDFDEDED5454",
+"n. c #FEFEEEEE5959",
+"m. c #FEFEF1F17D7D",
+"M. c #FFFFF6F67E7E",
+"N. c #ACACCCCC8A8A",
+"B. c #B3B3CDCD8D8D",
+"V. c #F3F3E2E28484",
+"C. c #FFFFE9E98282",
+"Z. c None",
+/* pixels */
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"9 9 9 9 8 7 5 2 < > ; - 7 * & $ ",
+"9 B.M.V.8.7.5.3.1.,.;.w.v.q.) @ ",
+"9 C.>.e.n.' +.` ! R F N %.x ) O ",
+"0 m.t.y.b.O.^ x.k.F 0.v l h =.X ",
+"3 N.c.b.-. .z.d.S r.g.9.h U h.* ",
+"7 6.:.X..._ l.I K P i.d a i *. ",
+"5 4.| [ ] ~ j.s.V k d a u u.M ",
+"< 2.[ W T L J a.p.d a t r w b ",
+", <.W F C m B n j p t e H q c ",
+"; ;.#. at .o.| ) ! Y F C &.f.$.z ",
+"- = * % $ @ + X . # ",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z."
+};
diff --git a/src/images/flags/CD.xpm b/src/images/flags/CD.xpm
new file mode 100644
index 0000000..f6fb10b
--- /dev/null
+++ b/src/images/flags/CD.xpm
@@ -0,0 +1,139 @@
+/* XPM */
+static const char *CD_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 117 2",
+" c black",
+". c #00008484B2B2",
+"X c #00008686B2B2",
+"o c #00008686B4B4",
+"O c #00008888B4B4",
+"+ c #00008989B6B6",
+"@ c #00008989B9B9",
+"# c #00008D8DBFBF",
+"$ c #00009292C1C1",
+"% c #00009494C4C4",
+"& c #00009898CBCB",
+"* c #0000B2B2E8E8",
+"= c #0000B4B4EDED",
+"- c #0000B9B9F4F4",
+"; c #0000BDBDF8F8",
+": c #0000BFBFFBFB",
+"> c #3D3DFFFFA0A0",
+", c #0000C1C1FDFD",
+"< c #0202C4C4FFFF",
+"1 c #0404C8C8FFFF",
+"2 c #0505CACAFFFF",
+"3 c #0505CBCBFFFF",
+"4 c #0505CFCFFFFF",
+"5 c #0707FFFFF6F6",
+"6 c #4848B1B1D1D1",
+"7 c #4949B2B2D3D3",
+"8 c #4949B3B3D4D4",
+"9 c #4A4AB4B4D6D6",
+"0 c #4A4AB5B5D6D6",
+"q c #4A4AB6B6D7D7",
+"w c #4B4BB7B7D9D9",
+"e c #4B4BB8B8DADA",
+"r c #6161BABAD4D4",
+"t c #6161BBBBD4D4",
+"y c #6262BBBBD5D5",
+"u c #6262BCBCD5D5",
+"i c #6262BDBDD7D7",
+"p c #6363BEBED9D9",
+"a c #6363BFBFDADA",
+"s c #4E4EC8C88484",
+"d c #5454CECEF4F4",
+"f c #5555D0D0F7F7",
+"g c #5555D1D1F8F8",
+"h c #5656D3D3FAFA",
+"j c #5757D4D4FBFB",
+"k c #5757D5D5FDFD",
+"l c #5858D7D7FFFF",
+"z c #6464C0C0DBDB",
+"x c #6565C2C2DDDD",
+"c c #6666C4C4E0E0",
+"v c #6C6CD4D4F3F3",
+"b c #6D6DD7D7F8F8",
+"n c #6E6ED9D9FAFA",
+"m c #6F6FDBDBFDFD",
+"M c #6F6FDCDCFEFE",
+"N c #7070DEDEFFFF",
+"B c #7070E0E0FFFF",
+"V c #7171E0E0FFFF",
+"C c #B2B200000000",
+"Z c #B8B800000000",
+"A c #C1C100000000",
+"S c #C4C400000000",
+"D c #C8C800000000",
+"F c #CACA00000000",
+"G c #F2F200000E0E",
+"H c #F4F400000E0E",
+"J c #F5F500000F0F",
+"K c #F6F600000F0F",
+"L c #F7F700000F0F",
+"P c #F8F800000F0F",
+"I c #F9F900000F0F",
+"U c #FCFC00000F0F",
+"Y c #FEFE00000F0F",
+"T c #FFFF00000F0F",
+"R c #FFFF00001010",
+"E c #FFFF00001111",
+"W c #FFFF37370D0D",
+"Q c #FFFF38380D0D",
+"! c #F5F525252828",
+"~ c #FEFE25252929",
+"^ c #FFFF25252A2A",
+"/ c #C8C862620000",
+"( c #FFFF53532626",
+") c #FFFF56562727",
+"_ c #FFFF63631919",
+"` c #FFFF64641919",
+"' c #FFFF65651919",
+"] c #FFFF78783131",
+"[ c #B8B8B6B60000",
+"{ c #C1C1DADA0707",
+"} c yellow",
+"| c #FFFFFFFF0A0A",
+" . c #FFFFFDFD1010",
+".. c #FFFFFFFF1010",
+"X. c #FFFFFFFF1111",
+"o. c #FFFFFFFF1212",
+"O. c #FFFFFFFF2323",
+"+. c #FFFFFBFB2A2A",
+"@. c #FFFFFFFF2B2B",
+"#. c #EFEFFFFF6F6F",
+"$. c #BCBCEEEE8484",
+"%. c #BDBDEFEF8585",
+"&. c #BFBFF1F18686",
+"*. c #B2B2EEEEACAC",
+"=. c #B4B4EFEFABAB",
+"-. c #B3B3F8F8A1A1",
+";. c #BBBBF6F6AAAA",
+":. c #B9B9FBFBB6B6",
+">. c #BCBCFCFCB7B7",
+",. c #C5C5EFEF9191",
+"<. c #C5C5F1F19090",
+"1. c #C6C6F3F39191",
+"2. c #CCCCF1F19B9B",
+"3. c #C3C3F6F6B2B2",
+"4. c #C9C9FDFDB7B7",
+"5. c #F6F6FFFF8181",
+"6. c None",
+/* pixels */
+"6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.",
+"6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.",
+"6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.",
+"4 4 > 4 4 2 2 2 , ; - = * { D A ",
+"4 >.O.:.B B N m b b v 2. at .( ! C ",
+"5 @.o.o.-.l j g d <.o.W J G ^ Z ",
+"4 5.o.#.k g g 1.o.W L J T T ] [ ",
+"2 4.l ;.g *.o.W I J T T _ o.,.# ",
+"< m g =.o.Q T I T T _ o.$.9 z + ",
+", 3.| Q T L T T ' o.&.q 9 9 i O ",
+"} ) I I T T ' o.&.e q 9 7 6 y . ",
+"D T E E ' o.&.e e e q 9 7 6 y . ",
+"D ^ ' | &.c c c x x z y y y y . ",
+"S / s & & & % $ $ + O O . . . . ",
+"6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.",
+"6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6."
+};
diff --git a/src/images/flags/CF.xpm b/src/images/flags/CF.xpm
new file mode 100644
index 0000000..549d020
--- /dev/null
+++ b/src/images/flags/CF.xpm
@@ -0,0 +1,182 @@
+/* XPM */
+static const char *CF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 160 2",
+" c black",
+". c #00001D1D0000",
+"X c #000023230000",
+"o c #00005A5A0000",
+"O c #00005E5E0000",
+"+ c #0C0C6D6D0C0C",
+"@ c #00000000CECE",
+"# c #00000C0CCECE",
+"$ c #00001010D3D3",
+"% c #00001616D7D7",
+"& c #00001C1CD9D9",
+"* c #00001F1FDCDC",
+"= c #00002525DEDE",
+"- c #09092F2FD8D8",
+"; c #00002424E3E3",
+": c #00002929E1E1",
+"> c #02023030E7E7",
+", c #05053C3CE7E7",
+"< c #0A0A3B3BE8E8",
+"1 c #0A0A3C3CE9E9",
+"2 c #0A0A3E3EE9E9",
+"3 c #0C0C3E3EE8E8",
+"4 c #0C0C3E3EE9E9",
+"5 c #101096961010",
+"6 c #141493931414",
+"7 c #141499991414",
+"8 c #191995951919",
+"9 c #191996961919",
+"0 c #1F1F98981F1F",
+"q c #3F3F8F8F0000",
+"w c #24249B9B2424",
+"e c #2A2A9E9E2A2A",
+"r c #3333A5A53232",
+"t c #3636A2A23636",
+"y c #3434AFAF3434",
+"u c #3A3AB2B23A3A",
+"i c #3B3BB2B23A3A",
+"p c #4040B4B43F3F",
+"a c #7474BCBC0000",
+"s c #4A4AA7A74A4A",
+"d c #4040B5B54040",
+"f c #4545B7B74545",
+"g c #4949B9B94949",
+"h c #4949BABA4949",
+"j c #4F4FBCBC4F4F",
+"k c #6A6AC7C76A6A",
+"l c #6F6FC8C86F6F",
+"z c #5D5D8282F1F1",
+"x c #62628686F2F2",
+"c c #66668989F4F4",
+"v c #6B6B8D8DF5F5",
+"b c #6F6F9090F6F6",
+"n c #74749393F2F2",
+"m c #77779E9EF2F2",
+"M c #7A7A9F9FF4F4",
+"N c #7B7B9999F8F8",
+"B c #7D7D9C9CF9F9",
+"V c #7F7FA3A3F5F5",
+"C c #7F7FA1A1F9F9",
+"Z c #D8D800000000",
+"A c #DADA00000000",
+"S c #F0F000000000",
+"D c #F3F300000000",
+"F c #F5F523232323",
+"G c #F6F629292929",
+"H c #F6F62A2A2A2A",
+"J c #F7F72F2F2F2F",
+"K c #F8F835353535",
+"L c #F8F836363636",
+"P c #F9F93B3B3B3B",
+"I c #F9F93B3B3C3C",
+"U c #F6F642424242",
+"Y c #F7F746464646",
+"T c #FAFA41414141",
+"R c #FAFA41414242",
+"E c #FBFB47474747",
+"W c #FCFC4C4C4C4C",
+"Q c #FCFC69696969",
+"! c #FDFD6D6D6D6D",
+"~ c #BBBBBBBB0202",
+"^ c #AAAAD5D50B0B",
+"/ c #ACACD6D60E0E",
+"( c #AEAED7D71313",
+") c #B0B0DADA1919",
+"_ c #B3B3DCDC1E1E",
+"` c #B6B6DADA2F2F",
+"' c #BABAE1E12E2E",
+"] c #BCBCE2E23434",
+"[ c #BFBFE2E23A3A",
+"{ c #C2C2C2C20000",
+"} c #C4C4C4C40000",
+"| c #CCCCCCCC0000",
+" . c #CDCDCDCD0000",
+".. c #CECECECE0000",
+"X. c #D1D1D1D10000",
+"o. c #D3D3D3D30000",
+"O. c #D4D4D4D40000",
+"+. c #D6D6D6D60000",
+"@. c #DDDDDDDD0000",
+"#. c #DFDFDFDF0000",
+"$. c #DFDFE2E20000",
+"%. c #C1C1E4E43F3F",
+"&. c #F2F2F2F22C2C",
+"*. c #F2F2F2F22F2F",
+"=. c #F2F2F2F23232",
+"-. c #F3F3F3F33535",
+";. c #F4F4F4F43939",
+":. c #F5F5F5F53D3D",
+">. c #C3C3E5E54444",
+",. c #CECEEAEA6666",
+"<. c #F7F7F7F74B4B",
+"1. c #F8F8F8F85050",
+"2. c #F9F9F9F95555",
+"3. c #F9F9F9F95858",
+"4. c #FAFAFAFA5D5D",
+"5. c #EDEDEDED7E7E",
+"6. c #FBFBFBFB6262",
+"7. c #FFFFFFFF7F7F",
+"8. c #B7B7B7B7B7B7",
+"9. c #8282A5A5F6F6",
+"0. c #8181A0A0F9F9",
+"q. c #8585A8A8F7F7",
+"w. c #8A8AA5A5F8F8",
+"e. c #9393ACACFAFA",
+"r. c #9494B3B3FAFA",
+"t. c #9797B5B5FAFA",
+"y. c #9C9CB3B3FBFB",
+"u. c #8787C8C88787",
+"i. c #8B8BCACA8B8B",
+"p. c #8E8ECBCB8E8E",
+"a. c #9898CFCF9898",
+"s. c #9090D1D19191",
+"d. c #9494D3D39494",
+"f. c #9D9DD8D89D9D",
+"g. c #A0A0DADAA1A1",
+"h. c #A3A3D8D8A3A3",
+"j. c #A6A6DADAA6A6",
+"k. c #A9A9DBDBA9A9",
+"l. c #B9B9E2E2B9B9",
+"z. c #EDEDEDED8F8F",
+"x. c #E4E4E4E49999",
+"c. c gray77",
+"v. c #E4E4E4E4E4E4",
+"b. c #E4E4E4E4E9E9",
+"n. c #F4F4F4F4F4F4",
+"m. c #F4F4F4F4F5F5",
+"M. c gray96",
+"N. c #F5F5F5F5F6F6",
+"B. c #F6F6F6F6F6F6",
+"V. c gray97",
+"C. c #F8F8F8F8F8F8",
+"Z. c #F9F9F9F9F9F9",
+"A. c #FBFBFBFBFBFB",
+"S. c #FBFBFBFBFEFE",
+"D. c gray99",
+"F. c #FCFCFCFCFDFD",
+"G. c #FDFDFCFCFDFD",
+"H. c #FDFDFDFDFDFD",
+"J. c #FEFEFEFEFEFE",
+"K. c None",
+/* pixels */
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"- 4 ~ 1 2 2 : D S ; : = * * % $ ",
+"4 x.7.z.t.r.e.! Q w.q.9.V M m # ",
+"< y.5.0.V B N W E b v c x z n @ ",
+"b.J.S.S.S.S.A.E T Z.C.V.N.N.N.c.",
+"v.J.J.J.S.J.A.T P C.V.N.N.N.N.8.",
+"s l.k.j.g.g.f.P L d.s.p.i.u.a.+ ",
+"O l j g f p i L J e w 0 9 6 t . ",
+"o k g f d i y J H w 0 9 7 5 r X ",
+"a ,.>.%.[ ] ' H F _ ) ( / ^ ` q ",
+"} 6.4.3.2.1.<.Y T :.;.-.=.*.*.| ",
+"{ } ..O.$.$. at .A Z +.X.X.....| | ",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K."
+};
diff --git a/src/images/flags/CG.xpm b/src/images/flags/CG.xpm
new file mode 100644
index 0000000..d1d9e8f
--- /dev/null
+++ b/src/images/flags/CG.xpm
@@ -0,0 +1,149 @@
+/* XPM */
+static const char *CG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 127 2",
+" c black",
+". c #0000B1B10000",
+"X c #0000B7B70000",
+"o c #0000B9B90000",
+"O c #0000BBBB0000",
+"+ c #0000BDBD0000",
+"@ c #0000BFBF0000",
+"# c #0000C1C10000",
+"$ c #0000C3C30000",
+"% c #0000C7C70000",
+"& c #4D4DD5D50000",
+"* c #4949D6D64949",
+"= c #4949D7D74949",
+"- c #4B4BD7D74B4B",
+"; c #4D4DD7D74B4B",
+": c #4D4DD8D84B4B",
+"> c #4F4FD9D94F4F",
+", c #5050D8D84C4C",
+"< c #5050D9D95050",
+"1 c #5151D9D95151",
+"2 c #5353DBDB5353",
+"3 c #5454DBDB5454",
+"4 c #5858DCDC5858",
+"5 c #5858DCDC5959",
+"6 c #5959DCDC5959",
+"7 c #5C5CDEDE5C5C",
+"8 c #5F5FDFDF5F5F",
+"9 c #6666DDDD6666",
+"0 c #6E6EDFDF6969",
+"q c #6D6DDFDF6D6D",
+"w c #6A6AE0E06A6A",
+"e c #6F6FE1E16F6F",
+"r c #7070E2E27171",
+"t c #7272E2E27373",
+"y c #7474E2E27474",
+"u c #7676E3E37676",
+"i c #7777E3E37777",
+"p c #7979E4E47979",
+"a c #7B7BE4E47A7A",
+"s c #7B7BE4E47B7B",
+"d c #DDDD00000000",
+"f c #DFDF00000000",
+"g c #E1E100000000",
+"h c #E3E300000000",
+"j c #E5E500000000",
+"k c #E7E700000000",
+"l c #E9E900000000",
+"z c #EBEB00000000",
+"x c #F1F10B0B0B0B",
+"c c #F1F10F0F0E0E",
+"v c #F2F210101010",
+"b c #F2F213131313",
+"n c #F2F214141414",
+"m c #F3F319191919",
+"M c #F3F31A1A1A1A",
+"N c #F4F41E1E1E1E",
+"B c #F4F41F1F1F1F",
+"V c #F4F420202020",
+"C c #F5F527272525",
+"Z c #F5F52B2B2323",
+"A c #F5F528282626",
+"S c #F5F52A2A2525",
+"D c #F5F52B2B2424",
+"F c #F2F22C2C2C2C",
+"G c #F2F22F2F2F2F",
+"H c #F2F232323232",
+"J c #F3F332323232",
+"K c #F3F335353535",
+"L c #F4F436363636",
+"P c #F4F439393939",
+"I c #F4F43B3B3B3B",
+"U c #F5F53D3D3D3D",
+"Y c #F5F53F3F3F3F",
+"T c #EDED49490000",
+"R c #F6F642424242",
+"E c #F6F644444444",
+"W c #F7F749494949",
+"Q c #F7F753534646",
+"! c #9E9EE8E84444",
+"~ c #A5A5EAEA4545",
+"^ c #ABABEBEB4545",
+"/ c #B1B1ECEC4646",
+"( c #B3B3EDED4646",
+") c #B4B4EDED4747",
+"_ c #BFBFF0F04747",
+"` c #ACACEBEB6262",
+"' c #EDEDBFBF0000",
+"] c #F6F6A0A02C2C",
+"[ c #F6F6A5A52B2B",
+"{ c #F6F6AAAA2B2B",
+"} c #F6F6AFAF2B2B",
+"| c #F6F6B3B32A2A",
+" . c #F6F6BDBD2929",
+".. c #F7F7AEAE4E4E",
+"X. c #EDEDC3C30000",
+"o. c #EFEFC5C50000",
+"O. c #F1F1C9C90101",
+"+. c #F3F3CBCB0909",
+"@. c #F5F5CDCD1111",
+"#. c #F7F7D1D11717",
+"$. c #F7F7F7F72E2E",
+"%. c #F7F7F7F72F2F",
+"&. c #F7F7F7F73030",
+"*. c #F7F7F7F73131",
+"=. c #F8F8F8F83434",
+"-. c #F8F8F8F83535",
+";. c #F8F8F8F83636",
+":. c #F8F8F8F83737",
+">. c #F9F9F9F93A3A",
+",. c #F9F9F9F93B3B",
+"<. c #F9F9F9F93C3C",
+"1. c #F9F9F9F93D3D",
+"2. c #FAFAFAFA3F3F",
+"3. c #CACAF2F26565",
+"4. c #F7F7CBCB4B4B",
+"5. c #FAFAFAFA4040",
+"6. c #FAFAFAFA4141",
+"7. c #FAFAFAFA4242",
+"8. c #F8F8F8F85050",
+"9. c #F8F8F8F85353",
+"0. c #F9F9F9F95555",
+"q. c #F9F9F9F95757",
+"w. c #F9F9F9F95858",
+"e. c #FAFAFAFA5C5C",
+"r. c #FAFAFAFA5D5D",
+"t. c #FBFBFBFB6060",
+"y. c None",
+/* pixels */
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"% $ $ $ $ $ + + o X #. at .+.O.o.T ",
+"$ s s s i u t q 0 3.t.r.q.9...z ",
+"$ s 7 7 4 3 < , _ 7.1.:.*.] W l ",
+"$ p 7 4 3 < ; ( 7.1.;.&.[ A E l ",
+"$ u 4 3 < ; ( 7.1.;.&.{ C V Y k ",
+"$ t 3 , : ( 7.:.;.%.| A N m I k ",
+"+ e < = ^ 7.:.;.%.| Z B m n L g ",
+"o w = ~ 7.:.=.$.| A B m n v H f ",
+"X 9 ! 7.:.;.$. .Z N m b c x G f ",
+". ` r.w.q.8.4.Q R Y P L H G F f ",
+"& +.O.o.X.' l l k k g g f f d d ",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y."
+};
diff --git a/src/images/flags/CH.xpm b/src/images/flags/CH.xpm
new file mode 100644
index 0000000..fc06045
--- /dev/null
+++ b/src/images/flags/CH.xpm
@@ -0,0 +1,88 @@
+/* XPM */
+static const char *CH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 66 1",
+" c black",
+". c #E3E300000000",
+"X c #E5E500000000",
+"o c #E7E700000000",
+"O c #E9E900000000",
+"+ c #EBEB00000000",
+"@ c #EDED00000000",
+"# c #EFEF00000000",
+"$ c #F1F100000000",
+"% c #F3F300000000",
+"& c #F5F500000000",
+"* c #F7F700000000",
+"= c #F9F900000000",
+"- c #FBFB00000000",
+"; c #FDFD00000000",
+": c red",
+"> c #F5F523232323",
+", c #F6F629292929",
+"< c #F6F62A2A2A2A",
+"1 c #F7F72F2F2F2F",
+"2 c #F5F53D3D3D3D",
+"3 c #FAFA3F3F3F3F",
+"4 c #F6F642424242",
+"5 c #F7F746464646",
+"6 c #F7F747474747",
+"7 c #FAFA41414242",
+"8 c #FAFA44444444",
+"9 c #FBFB45454545",
+"0 c #FBFB47474747",
+"q c #FBFB49494949",
+"w c #FCFC4C4C4C4C",
+"e c #F7F750505050",
+"r c #F8F857575858",
+"t c #F9F958585858",
+"y c #F9F958585959",
+"u c #F8F85B5B5B5B",
+"i c #F9F95B5B5B5B",
+"p c #FAFA5B5B5B5B",
+"a c #FAFA5D5D5D5D",
+"s c #FEFE59595959",
+"d c #FEFE5C5C5C5C",
+"f c #FEFE5F5F5F5F",
+"g c #FBFB60606060",
+"h c #FBFB61616262",
+"j c #FCFC65656565",
+"k c #FCFC66666666",
+"l c #FCFC69696969",
+"z c #FCFC6A6A6A6A",
+"x c #FDFD6D6D6D6D",
+"c c #FDFD72727272",
+"v c #FDFD75757575",
+"b c #FEFE79797979",
+"n c #FEFE7A7A7A7A",
+"m c #FFFF7B7B7A7A",
+"M c #FFFF7B7B7B7B",
+"N c gray97",
+"B c #F8F8F8F8F8F8",
+"V c #F9F9F9F9F9F9",
+"C c gray98",
+"Z c #FBFBFBFBFBFB",
+"A c #FBFBFCFCFBFB",
+"S c gray99",
+"D c #FDFDFCFCFDFD",
+"F c #FDFDFDFDFDFD",
+"G c #FEFEFEFEFEFE",
+"H c None",
+/* pixels */
+"HHHHHHHHHHHHHHHH",
+"HHHHHHHHHHHHHHHH",
+"HHHHHHHHHHHHHHHH",
+"HHH::::::::==*HH",
+"HHH:MMMMMvxzj*HH",
+"HHH:MfsGGGw0g%HH",
+"HHH:MfsGGV07i%HH",
+"HHH:vGGSGVVVi#HH",
+"HHH:MGGGVVVVu#HH",
+"HHH:xGVVGVNNeOHH",
+"HHH=zq8VVV1,6OHH",
+"HHH*j03VNN,>4oHH",
+"HHH*gaiuuw642oHH",
+"HHH*%%###OOoo.HH",
+"HHHHHHHHHHHHHHHH",
+"HHHHHHHHHHHHHHHH"
+};
diff --git a/src/images/flags/CI.xpm b/src/images/flags/CI.xpm
new file mode 100644
index 0000000..57c3ff7
--- /dev/null
+++ b/src/images/flags/CI.xpm
@@ -0,0 +1,144 @@
+/* XPM */
+static const char *CI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 122 2",
+" c black",
+". c #000081810000",
+"X c #000083830000",
+"o c #000087870000",
+"O c #000089890000",
+"+ c #00008B8B0000",
+"@ c #00008F8F0000",
+"# c #000093930000",
+"$ c #000097970000",
+"% c #00009B9B0000",
+"& c #00009D9D0000",
+"* c #0000A7A70000",
+"= c #0000A9A90000",
+"- c #0000ABAB0000",
+"; c #0000AFAF0000",
+": c #0000B1B10000",
+"> c #0B0BC2C20B0B",
+", c #0F0FC4C40E0E",
+"< c #1010C4C41010",
+"1 c #1313C5C51313",
+"2 c #1414C6C61414",
+"3 c #1919C7C71919",
+"4 c #1919C8C81919",
+"5 c #1A1AC8C81A1A",
+"6 c #1F1FC9C91F1F",
+"7 c #1F1FCACA1F1F",
+"8 c #2020CACA2020",
+"9 c #2525CBCB2525",
+"0 c #2525CCCC2525",
+"q c #2626CDCD2626",
+"w c #2B2BCDCD2B2B",
+"e c #2B2BCECE2B2B",
+"r c #2C2CCACA2C2C",
+"t c #2F2FCACA2F2F",
+"y c #2F2FCBCB2F2F",
+"u c #2C2CCECE2C2C",
+"i c #3131CFCF3131",
+"p c #3232CCCC3232",
+"a c #3333CCCC3232",
+"s c #3535CDCD3535",
+"d c #3636CDCD3636",
+"f c #3B3BCFCF3B3B",
+"g c #3131D0D03131",
+"h c #3737D1D13737",
+"j c #3F3FD2D23F3F",
+"k c #4444D3D34444",
+"l c #4949D5D54949",
+"z c #4E4ED7D74E4E",
+"x c #5353D8D85353",
+"c c #5858D9D95757",
+"v c #5C5CDADA5C5C",
+"b c #EDED53530000",
+"n c #EFEF5B5B0000",
+"m c #F1F163630000",
+"M c #F3F367670000",
+"N c #F7F76F6F0000",
+"B c #F5F575750000",
+"V c #F9F977770000",
+"C c #FBFB7B7B0000",
+"Z c #FDFD7F7F0000",
+"A c #FDFD83830000",
+"S c #FDFD87870000",
+"D c #FFFF85850000",
+"F c #FFFF87870000",
+"G c #FFFF89890000",
+"H c #FFFF91910000",
+"J c #F9F9AAAA3A3A",
+"K c #FAFAADAD3F3F",
+"L c #FAFAAEAE3F3F",
+"P c #FAFAB1B14444",
+"I c #FBFBB0B04545",
+"U c #FBFBB1B14545",
+"Y c #FBFBB4B44949",
+"T c #FCFCB3B34B4B",
+"R c #FCFCB6B64F4F",
+"E c #FCFCB7B74F4F",
+"W c #F9F9B5B55555",
+"Q c #FDFDB5B55050",
+"! c #FDFDB7B75454",
+"~ c #FDFDB9B95353",
+"^ c #FDFDB9B95454",
+"/ c #F9F9B9B95858",
+"( c #FAFABCBC5D5D",
+") c #FEFEBABA5959",
+"_ c #FEFEBBBB5959",
+"` c #FEFEBCBC5858",
+"' c #FEFEBDBD5C5C",
+"] c #FEFEBFBF5F5F",
+"[ c #FBFBBEBE6262",
+"{ c #FCFCC0C06666",
+"} c #FCFCC3C36A6A",
+"| c #FDFDC4C46F6F",
+" . c #FEFEC6C67373",
+".. c #FEFEC7C77777",
+"X. c #FEFEC8C87676",
+"o. c #FEFEC8C87979",
+"O. c #FFFFCACA7A7A",
+"+. c #FFFFCACA7B7B",
+"@. c gray82",
+"#. c LightGray",
+"$. c #D7D7D7D7D7D7",
+"%. c gray85",
+"&. c #DDDDDDDDDDDD",
+"*. c #E9E9E9E9E9E9",
+"=. c gray92",
+"-. c gray93",
+";. c #EFEFEFEFEFEF",
+":. c #EFEFEFEFF1F1",
+">. c #F3F3F3F3F3F3",
+",. c #F4F4F4F4F4F4",
+"<. c gray96",
+"1. c #F6F6F6F6F6F6",
+"2. c gray97",
+"3. c #F8F8F8F8F8F8",
+"4. c #F9F9F9F9F9F9",
+"5. c gray98",
+"6. c #FBFBFBFBFBFB",
+"7. c gray99",
+"8. c #FDFDFDFDFDFD",
+"9. c #FDFDFDFDFEFE",
+"0. c #FEFEFEFEFEFE",
+"q. c None",
+/* pixels */
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+"H G G F F :.;.=.=.=.=.: : = * = ",
+"F +.+.+...9.9.9.6.9.6.v c x z & ",
+"G +.' ' _ 9.9.9.5.5.5.h g u l % ",
+"F +._ _ ! 9.7.6.5.5.5.y e q k $ ",
+"F .._ ~ R 7.5.5.5.2.1.e q 8 j # ",
+"F .~ R T 5.5.5.2.2.1.9 7 3 j @ ",
+"Z | R Y I 5.5.2.2.1.1.7 3 1 d + ",
+"C } Y I K 5.5.1.1.1.>.3 2 < y o ",
+"V [ P K J 2.2.1.1.>.>.1 , > p o ",
+"N [ ( / W 5.1.2.1.1.>.d y p r . ",
+"B M m n b &.%.$.$. at .@.+ o o . + ",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q."
+};
diff --git a/src/images/flags/CK.xpm b/src/images/flags/CK.xpm
new file mode 100644
index 0000000..50b5f86
--- /dev/null
+++ b/src/images/flags/CK.xpm
@@ -0,0 +1,171 @@
+/* XPM */
+static const char *CK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 149 2",
+" c black",
+". c #000000000303",
+"X c #000000000909",
+"o c #000000000B0B",
+"O c #000000001111",
+"+ c #000000001919",
+"@ c #000000001F1F",
+"# c #000000002323",
+"$ c #000000002525",
+"% c #000000002B2B",
+"& c #000000003131",
+"* c #000000003737",
+"= c #000000003939",
+"- c #000000003F3F",
+"; c #000000004545",
+": c #000000004B4B",
+"> c #000019196B6B",
+", c #000029297777",
+"< c #20203A3A7676",
+"1 c #25253D3D7979",
+"2 c #292941417B7B",
+"3 c #2A2A42427C7C",
+"4 c #2D2D46467E7E",
+"5 c #2E2E46467F7F",
+"6 c #2F2F47477F7F",
+"7 c #3E3E51517F7F",
+"8 c #57571D1D5959",
+"9 c #59591F1F5D5D",
+"0 c #373737378181",
+"q c #323249498282",
+"w c #32324B4B8282",
+"e c #34344B4B8383",
+"r c #37374E4E8585",
+"t c #37374E4E8686",
+"y c #383850508686",
+"u c #393950508686",
+"i c #3A3A51518787",
+"p c #3C3C52528989",
+"a c #3C3C53538989",
+"s c #3D3D53538989",
+"d c #3D3D55558A8A",
+"f c #3E3E54548888",
+"g c #3E3E55558A8A",
+"h c #3F3F55558A8A",
+"j c #444456568383",
+"k c #404056568A8A",
+"l c #414157578A8A",
+"z c #414157578C8C",
+"x c #424257578C8C",
+"c c #424258588D8D",
+"v c #434359598D8D",
+"b c #444459598C8C",
+"n c #44445A5A8D8D",
+"m c #47475C5C8E8E",
+"M c #4A4A5C5C8888",
+"N c #48485D5D8F8F",
+"B c #46465C5C9090",
+"V c #47475C5C9090",
+"C c #48485E5E9191",
+"Z c #4A4A5F5F9292",
+"A c #4F4F61618B8B",
+"S c #4B4B60609090",
+"D c #4B4B60609393",
+"F c #4C4C60609292",
+"G c #4C4C61619393",
+"H c #4E4E62629393",
+"J c #4D4D61619494",
+"K c #4E4E63639494",
+"L c #4F4F63639595",
+"P c #505065659494",
+"I c #515165659696",
+"U c #515165659797",
+"Y c #515166669797",
+"T c #525266669595",
+"R c #535368689898",
+"E c #55556A6A9A9A",
+"W c #55556A6A9B9B",
+"Q c #57576A6A9999",
+"! c #56566A6A9A9A",
+"~ c #5A5A6D6D9A9A",
+"^ c #5A5A6E6E9C9C",
+"/ c #5B5B6E6E9C9C",
+"( c #5B5B6E6E9D9D",
+") c #5F5F71719E9E",
+"_ c #5F5F7272A0A0",
+"` c #6F6F57578F8F",
+"' c #6B6B61619797",
+"] c #606071719E9E",
+"[ c #63637575A0A0",
+"{ c #63637777A5A5",
+"} c #64647575A1A1",
+"| c #67677979A4A4",
+" . c #68687A7AA4A4",
+".. c #6B6B7D7DA6A6",
+"X. c #6B6B7D7DA7A7",
+"o. c #6C6C7E7EA7A7",
+"O. c #70707F7FA1A1",
+"+. c #6F6F8080A9A9",
+"@. c #70708181A9A9",
+"#. c #73738484ABAB",
+"$. c #75758585ACAC",
+"%. c #79798989AEAE",
+"&. c #7C7C8C8CB1B1",
+"*. c #89891D1D4343",
+"=. c #8D8D1D1D4141",
+"-. c #8B8B31315555",
+";. c #A5A553536D6D",
+":. c #BBBB67677B7B",
+">. c #D3D31B1B1919",
+",. c #D8D86F6F7373",
+"<. c #E3E36C6C6B6B",
+"1. c #E5E573737272",
+"2. c #E2E278787979",
+"3. c #EAEA7D7D7A7A",
+"4. c #828269699595",
+"5. c #84846D6D9999",
+"6. c #8F8F76769B9B",
+"7. c #94947D7DA3A3",
+"8. c #AFAF7B7B9595",
+"9. c #86868B8BB3B3",
+"0. c #90908E8EB7B7",
+"q. c #9393A0A0C7C7",
+"w. c #A4A4ACACCACA",
+"e. c #C7C786869696",
+"r. c #C5C589899999",
+"t. c #D9D990909797",
+"y. c #D8D8A4A4AEAE",
+"u. c #D4D4ABABB7B7",
+"i. c #DADAABABB4B4",
+"p. c #E0E085858787",
+"a. c #E1E186868989",
+"s. c #ECEC85858383",
+"d. c #E8E895959696",
+"f. c #E6E6B9B9BFBF",
+"g. c #F0F0AAAAA8A8",
+"h. c #F0F0ACACABAB",
+"j. c #D4D4BABAC8C8",
+"k. c #DFDFBFBFC8C8",
+"l. c #C3C3C3C3C3C3",
+"z. c #DDDDD3D3DEDE",
+"x. c #E6E6C3C3CACA",
+"c. c #E8E8CECED4D4",
+"v. c #F1F1F1F1F1F1",
+"b. c #F3F3F3F3F3F3",
+"n. c #F4F4F4F4F4F4",
+"m. c #F6F6F6F6F6F6",
+"M. c gray97",
+"N. c #F8F8F8F8F8F8",
+"B. c None",
+/* pixels */
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+":.` , *.=.> 8 ;.# - * & % $ @ + ",
+"0 x.z.i.y.j.c.w.o.#.+...| [ ) O ",
+">.d.s.1.<.3.2.,.A R L Z M.h ~ X ",
+"-.f.g.p.a.h.t.8.M H N.v h i M. ",
+"' k.0.r.e.q.u.7.j N v h i e L ",
+"9 9.{ 5.4.W X.6.7 N.h y w 6 D l.",
+": &._ ( ! Y J V b f y q 4 3 N ",
+"; %.( ! Y J V x h e M.4 2 1 b. ",
+"- $.W L Z V x p r q 4 2 v.< b ",
+"= @.o. .} ] ) ! T D Z m b h h ",
+"& % $ @ + O X ",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B."
+};
diff --git a/src/images/flags/CL.xpm b/src/images/flags/CL.xpm
new file mode 100644
index 0000000..f11772f
--- /dev/null
+++ b/src/images/flags/CL.xpm
@@ -0,0 +1,145 @@
+/* XPM */
+static const char *CL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 123 2",
+" c black",
+". c #00003F3FAFAF",
+"X c #00005353C1C1",
+"o c #00005959C3C3",
+"O c #00005B5BC3C3",
+"+ c #00005D5DC3C3",
+"@ c #00006767C7C7",
+"# c #00006161D3D3",
+"$ c #52529393D1D1",
+"% c #56569595D3D3",
+"& c #54549A9ADADA",
+"* c #5B5B9898D4D4",
+"= c #59599E9EDBDB",
+"- c #5C5CA1A1DADA",
+"; c #5050A1A1E2E2",
+": c #5454A6A6E5E5",
+"> c #5858A7A7E5E5",
+", c #6262A4A4DCDC",
+"< c #6666A7A7DEDE",
+"1 c #6A6AAAAADEDE",
+"2 c #7878ABABDCDC",
+"3 c #7777B1B1E2E2",
+"4 c #7676B9B9EBEB",
+"5 c #7B7BB5B5E4E4",
+"6 c #7A7AB6B6E5E5",
+"7 c #DDDD00000000",
+"8 c #DFDF00000000",
+"9 c #E1E100000000",
+"0 c #E3E300000000",
+"q c #E5E500000000",
+"w c #E7E700000000",
+"e c #E9E900000000",
+"r c #EBEB00000000",
+"t c #EDED00000000",
+"y c #EFEF00000000",
+"u c #F1F100000000",
+"i c #F3F300000000",
+"p c #F5F500000000",
+"a c #F7F700000000",
+"s c #F1F10B0B0B0B",
+"d c #F1F10F0F0E0E",
+"f c #F9F900000000",
+"g c #FBFB00000000",
+"h c #FDFD00000000",
+"j c #F2F210101010",
+"k c #F2F213131313",
+"l c #F2F214141414",
+"z c #F3F319191919",
+"x c #F4F41E1E1E1E",
+"c c #F4F41F1F1F1F",
+"v c #F5F523232323",
+"b c #F5F524242424",
+"n c #F2F22C2C2C2C",
+"m c #F2F22F2F2F2F",
+"M c #F6F629292929",
+"N c #F6F62A2A2A2A",
+"B c #F7F72E2E2E2E",
+"V c #F7F72F2F2F2F",
+"C c #F2F232323232",
+"Z c #F3F332323232",
+"A c #F3F335353535",
+"S c #F4F436363636",
+"D c #F4F439393939",
+"F c #F5F53D3D3D3D",
+"G c #F8F834343434",
+"H c #F8F835353535",
+"J c #F9F93A3A3A3A",
+"K c #F9F93B3B3A3A",
+"L c #FAFA3F3F3F3F",
+"P c #F6F642424242",
+"I c #F7F746464646",
+"U c #F7F74B4B4B4B",
+"Y c #FAFA40404040",
+"T c #FAFA44444444",
+"R c #FBFB45454545",
+"E c #FBFB49494949",
+"W c #FBFB4A4A4949",
+"Q c #FCFC4F4F4F4F",
+"! c #F8F850505050",
+"~ c #F9F954545555",
+"^ c #F9F958585858",
+"/ c #FAFA5D5D5D5D",
+"( c #FBFB61616262",
+") c #FCFC66666666",
+"_ c #FCFC6A6A6A6A",
+"` c #FDFD6F6F6F6F",
+"' c #8585BABAE5E5",
+"] c #8585BDBDE6E6",
+"[ c #9191C3C3E7E7",
+"{ c #D7D7E9E9F6F6",
+"} c #D8D8EAEAF7F7",
+"| c #DADAEAEAF7F7",
+" . c #DADAEBEBF7F7",
+".. c #DFDFEDEDF8F8",
+"X. c #E5E5D3D3D3D3",
+"o. c #E7E7E7E7E7E7",
+"O. c #E9E9E9E9E9E9",
+"+. c gray92",
+"@. c #EDEDEFEFEFEF",
+"#. c #EFEFEFEFEFEF",
+"$. c #F3F3EBEBEBEB",
+"%. c #F4F4ECECECEC",
+"&. c #F4F4EDEDEDED",
+"*. c #F5F5EDEDEDED",
+"=. c #F6F6EFEFEFEF",
+"-. c #F1F1F1F1F1F1",
+";. c #F3F3F3F3F3F3",
+":. c #F7F7F0F0F0F0",
+">. c #F4F4F4F4F4F4",
+",. c gray96",
+"<. c #F6F6F6F6F6F6",
+"1. c gray97",
+"2. c #F8F8F1F1F1F1",
+"3. c #F9F9F2F2F2F2",
+"4. c #FAFAF2F2F2F2",
+"5. c #F8F8F8F8F8F8",
+"6. c #F9F9F9F9F9F9",
+"7. c gray98",
+"8. c #FBFBFBFBFBFB",
+"9. c gray99",
+"0. c #FDFDFDFDFDFD",
+"q. c #FDFDFDFDFEFE",
+"w. c None",
+/* pixels */
+"w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.",
+"w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.",
+"w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.",
+"@ O O O X O 0.0.8.7.1.,.;.-. at .@.",
+"O 5 } 5 3 ' 0.0.0.8.7.7.7.7.,.+.",
+"O ..} } = 1 0.0.7.7.7.7.1.,.1.O.",
+"O ' { [ & < 0.8.7.7.7.,.,.,.1.o.",
+"# 4 > : ; , 9.7.7.1.1.,.,.,.,.o.",
+". 2 * $ $ - 4.:.:.:.:.*.*.$.*.X.",
+"h ` Q E R Y K S V N b x z l S 9 ",
+"h _ E R L K G B N v x z k k Z 8 ",
+"g ) R L K G B N v x z k d s m 8 ",
+"g ( / ^ ~ ! U I P F D A Z m n 8 ",
+"i i i t t t r r w w 9 9 8 8 7 7 ",
+"w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.",
+"w.w.w.w.w.w.w.w.w.w.w.w.w.w.w.w."
+};
diff --git a/src/images/flags/CM.xpm b/src/images/flags/CM.xpm
new file mode 100644
index 0000000..e18b4d0
--- /dev/null
+++ b/src/images/flags/CM.xpm
@@ -0,0 +1,178 @@
+/* XPM */
+static const char *CM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 156 2",
+" c black",
+". c #00005F5F0000",
+"X c #000063630000",
+"o c #000067670000",
+"O c #00006F6F0000",
+"+ c #000075750000",
+"@ c #000077770000",
+"# c #00007B7B0000",
+"$ c #00007F7F0000",
+"% c #000083830000",
+"& c #000085850000",
+"* c #000087870000",
+"= c #000089890000",
+"- c #00008D8D0000",
+"; c #000091910000",
+": c #3A3AB0B03A3A",
+"> c #3F3FB0B03F3F",
+", c #4040B3B33F3F",
+"< c #4444B1B14444",
+"1 c #4545B2B24545",
+"2 c #4545B6B64545",
+"3 c #4949B4B44949",
+"4 c #4949B5B54949",
+"5 c #4F4FB7B74F4F",
+"6 c #4B4BB8B84B4B",
+"7 c #4F4FB8B84F4F",
+"8 c #5050BBBB5050",
+"9 c #5353B9B95353",
+"0 c #5454BABA5454",
+"q c #5454BABA5555",
+"w c #5454BDBD5454",
+"e c #5858BABA5858",
+"r c #5858BCBC5858",
+"t c #5858BCBC5959",
+"y c #5959BFBF5959",
+"u c #5C5CBDBD5C5C",
+"i c #5D5DBCBC5D5D",
+"p c #5C5CBEBE5C5C",
+"a c #5F5FBFBF5F5F",
+"s c #6161BEBE6262",
+"d c #6666C0C06666",
+"f c #6A6AC3C36A6A",
+"g c #6F6FC4C46F6F",
+"h c #7272C6C67373",
+"j c #7676C8C87676",
+"k c #7777CBCB7777",
+"l c #7979C8C87979",
+"z c #7979C9C97979",
+"x c #7B7BCACA7A7A",
+"c c #7B7BCACA7B7B",
+"v c #C9C900000000",
+"b c #E1E100000000",
+"n c #E3E300000000",
+"m c #E5E500000000",
+"M c #E7E700000000",
+"N c #E9E900000000",
+"B c #EBEB00000000",
+"V c #F7F700000000",
+"C c #F9F900000000",
+"Z c #FBFB00000000",
+"A c #FDFD00000000",
+"S c #F4F41E1E1E1E",
+"D c #F3F32B2B1919",
+"F c #F4F430301F1F",
+"G c #E6E63F3F3434",
+"H c #F5F523232323",
+"J c #F5F524242424",
+"K c #F6F629292929",
+"L c #F6F62A2A2A2A",
+"P c #F7F72E2E2E2E",
+"I c #F7F72F2F2F2F",
+"U c #F5F535352424",
+"Y c #F6F63A3A2B2B",
+"T c #F5F53D3D3D3D",
+"R c #F8F834343434",
+"E c #F8F83C3C3636",
+"W c #F9F93B3B3A3A",
+"Q c #F9F93C3C3C3C",
+"! c #E7E745453A3A",
+"~ c #F7F740403030",
+"^ c #F4F449493939",
+"/ c #F8F847473636",
+"( c #F9F94C4C3D3D",
+") c #E8E84A4A4040",
+"_ c #EAEA4F4F4646",
+"` c #EBEB55554B4B",
+"' c #E8E859595050",
+"] c #ECEC5A5A5151",
+"[ c #EDED5E5E5454",
+"{ c #F6F642424242",
+"} c #F7F746464646",
+"| c #F7F74B4B4B4B",
+" . c #FAFA41414242",
+".. c #FAFA42424242",
+"X. c #FBFB47474747",
+"o. c #FBFB4C4C4646",
+"O. c #FCFC4B4B4B4B",
+"+. c #FCFC4C4C4C4C",
+"@. c #FDFD51515151",
+"#. c #FCFC65656565",
+"$. c #FBFB6E6E6060",
+"%. c #FCFC69696969",
+"&. c #FDFD6D6D6D6D",
+"*. c #F1F17B7B7474",
+"=. c #FDFD70707171",
+"-. c #F7F7B6B63030",
+";. c #FAFABCBC4040",
+":. c #DDDDDDDD0000",
+">. c #DFDFDFDF0000",
+",. c #F7F7C3C32F2F",
+"<. c #F8F8C4C43535",
+"1. c #F9F9C5C53C3C",
+"2. c #F8F8DEDE3636",
+"3. c #F9F9DDDD3B3B",
+"4. c #E1E1E1E10000",
+"5. c #E3E3E3E30000",
+"6. c #E5E5E5E50000",
+"7. c #E7E7E7E70000",
+"8. c #E9E9E9E90000",
+"9. c #EBEBEBEB0000",
+"0. c #EDEDEFEF0000",
+"q. c #EFEFEFEF0000",
+"w. c #F1F1F1F10000",
+"e. c #F3F3F3F30000",
+"r. c #F5F5F5F50000",
+"t. c #F1F1F1F10B0B",
+"y. c #F1F1F1F10E0E",
+"u. c #F2F2F2F21010",
+"i. c #F2F2F2F21313",
+"p. c #F2F2F2F21414",
+"a. c #F3F3F3F31919",
+"s. c #F3F3F3F31A1A",
+"d. c #F4F4F4F41F1F",
+"f. c #F4F4F4F42020",
+"g. c #F5F5F5F52525",
+"h. c #F5F5F5F52626",
+"j. c #F2F2F2F22C2C",
+"k. c #F2F2F2F22F2F",
+"l. c #F6F6F6F62B2B",
+"z. c #F6F6F6F62C2C",
+"x. c #F2F2F2F23232",
+"c. c #F3F3F3F33232",
+"v. c #F3F3F3F33535",
+"b. c #F7F7F7F73131",
+"n. c #F4F4F4F43636",
+"m. c #F4F4F5F53B3B",
+"M. c #F5F5F5F53F3F",
+"N. c #F8F8F8F83737",
+"B. c #FAFAC7C74141",
+"V. c #F6F6F6F64444",
+"C. c #F7F7F7F74949",
+"Z. c #F7F7F7F74E4E",
+"A. c #F8F8F8F85353",
+"S. c #F9F9F9F95757",
+"D. c #FAFAFAFA5C5C",
+"F. c None",
+/* pixels */
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"; = = = - b A A A C V r.r.w.0.0.",
+"& c c k j *.=.&.%.#.$.D.S.A.Z.9.",
+"= c a u y [ @.+.X...( N.b.z.C.9.",
+"& c u u w ] O.X...Q / b.l.h.V.6.",
+"= j q q 8 ` o.B.1.E ~ l.h.f.M.6.",
+"% h 9 7 4 ` ;.3.2.-.Y h.d.s.m.7.",
+"$ g 7 3 2 ! Q <.,.L U f.s.p.n.6.",
+"# f 3 < < ! R P L J D s.p.u.c.>.",
+"# s < : : ! P K H S D p.y.t.k.>.",
+"O s i e q ' | } { T ^ v.x.k.k.:.",
+"+ o X . . v B B M M b 4.>.:.:.:.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F."
+};
diff --git a/src/images/flags/CN.xpm b/src/images/flags/CN.xpm
new file mode 100644
index 0000000..a618d71
--- /dev/null
+++ b/src/images/flags/CN.xpm
@@ -0,0 +1,158 @@
+/* XPM */
+static const char *CN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 136 2",
+" c black",
+". c #9D9D00000000",
+"X c #9F9F00000000",
+"o c #A1A100000000",
+"O c #A3A300000000",
+"+ c #A5A500000000",
+"@ c #A7A700000000",
+"# c #A9A900000000",
+"$ c #ABAB00000000",
+"% c #AFAF00000000",
+"& c #B3B300000000",
+"* c #B7B700000000",
+"= c #B9B900000000",
+"- c #BDBD00000000",
+"; c #C1C100000000",
+": c #C3C300000000",
+"> c #C7C700000000",
+", c #CBCB00000000",
+"< c #CDCD00000000",
+"1 c #CFCF00000000",
+"2 c #D1D100000000",
+"3 c #D3D300000000",
+"4 c #D5D500000000",
+"5 c #D7D700000000",
+"6 c #D0D00B0B0B0B",
+"7 c #D1D10F0F0E0E",
+"8 c #D1D110101010",
+"9 c #D3D313131313",
+"0 c #D3D314141414",
+"q c #D4D419191919",
+"w c #D5D519191919",
+"e c #D5D51A1A1A1A",
+"r c #D5D51E1E1E1E",
+"t c #D6D61F1F1F1F",
+"y c #D7D71F1F1F1F",
+"u c #D7D720202020",
+"i c #D7D723232323",
+"p c #D6D62C2C2C2C",
+"a c #D6D62F2F2F2F",
+"s c #D7D72F2F2F2F",
+"d c #D8D824242424",
+"f c #D9D925252525",
+"g c #D9D926262626",
+"h c #D9D929292929",
+"j c #D9D92A2A2A2A",
+"k c #D9D92B2B2B2B",
+"l c #DADA2B2B2B2B",
+"z c #DBDB2C2C2C2C",
+"x c #DBDB2E2E2E2E",
+"c c #DBDB2F2F2F2F",
+"v c #D8D832323232",
+"b c #DBDB30303030",
+"n c #D8D835353535",
+"m c #D8D836363636",
+"M c #DCDC31313131",
+"N c #DCDC34343434",
+"B c #DDDD34343434",
+"V c #DDDD35353535",
+"C c #DDDD36363636",
+"Z c #DEDE37373636",
+"A c #DEDE37373737",
+"S c #DADA39393939",
+"D c #DADA3B3B3B3B",
+"F c #DBDB3D3D3D3D",
+"G c #DEDE3A3A3A3A",
+"H c #DEDE3B3B3A3A",
+"J c #DEDE3B3B3B3B",
+"K c #DEDE3B3B3C3C",
+"L c #DCDC3F3F3F3F",
+"P c #DEDE3C3C3C3C",
+"I c #DFDF3C3C3D3D",
+"U c #E0E03F3F3F3F",
+"Y c #E5E545450000",
+"T c #DCDC42424242",
+"R c #DFDF40404040",
+"E c #DDDD44444444",
+"W c #DDDD46464646",
+"Q c #DFDF49494949",
+"! c #DFDF4B4B4B4B",
+"~ c #E0E041414242",
+"^ c #E1E142424141",
+"/ c #E0E042424242",
+"( c #E1E144444444",
+") c #E1E145454545",
+"_ c #E1E147474747",
+"` c #E3E349494949",
+"' c #E3E34A4A4949",
+"] c #E1E14E4E4E4E",
+"[ c #E3E34F4F4F4F",
+"{ c #E4E44F4F4F4F",
+"} c #E4E452524B4B",
+"| c #E1E150505050",
+" . c #E2E253535353",
+".. c #E2E254545555",
+"X. c #E3E357575757",
+"o. c #E5E553535353",
+"O. c #E4E454545454",
+"+. c #E6E657575454",
+"@. c #E3E358585858",
+"#. c #E6E658585858",
+"$. c #E7E75C5C5959",
+"%. c #E4E45C5C5C5C",
+"&. c #E4E45D5D5D5D",
+"*. c #EAEA7F7F4747",
+"=. c #E6E660606060",
+"-. c #E6E661616262",
+";. c #E7E765656565",
+":. c #E8E866666666",
+">. c #E8E869696969",
+",. c #E8E86A6A6A6A",
+"<. c #E8E86F6F6D6D",
+"1. c #E9E96F6F6F6F",
+"2. c #EAEA72727373",
+"3. c #ECEC79797676",
+"4. c #EDED7F7F7B7B",
+"5. c #EDED89895050",
+"6. c #ECEC90904646",
+"7. c #EDED92924646",
+"8. c #EDED96964C4C",
+"9. c #EFEF98985959",
+"0. c #F0F09B9B5454",
+"q. c #EDED84847979",
+"w. c #EEEE89897979",
+"e. c #F1F1A8A85151",
+"r. c #F2F2A5A57777",
+"t. c #F5F5BFBF7171",
+"y. c #F5F5CBCB4B4B",
+"u. c #F5F5CCCC4B4B",
+"i. c #F6F6CFCF5151",
+"p. c #F9F9DADA7474",
+"a. c #FAFADCDC7B7B",
+"s. c #FAFADDDD7A7A",
+"d. c #FAFAE2E25C5C",
+"f. c #FBFBE6E65C5C",
+"g. c #FDFDF3F35F5F",
+"h. c None",
+/* pixels */
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"4 4 3 4 4 Y 1 1 1 , > > ; ; - - ",
+"4 4.a.q.r.p.t.<.,.:.=.%.+. .] * ",
+"4 s.g.d.$.0.i.8._ R K A M x Q & ",
+"3 w.f.9.+.e.y.*.R I A M k g E % ",
+"3 3.#.+.5.y.6.R K A b l g u L $ ",
+"3 2.o.{ } 7.I G A b l g r q D $ ",
+"1 <.{ ` _ R P A x l g r q 0 m O ",
+"1 ,.' _ I G A x l d t q 0 8 v o ",
+", ;.( U G m x l u r q 0 7 6 a o ",
+"> -.&.#...| Q E T F D m v a a X ",
+"> ; ; - = * & % $ $ $ o o X X o ",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h."
+};
diff --git a/src/images/flags/CO.xpm b/src/images/flags/CO.xpm
new file mode 100644
index 0000000..f6a560f
--- /dev/null
+++ b/src/images/flags/CO.xpm
@@ -0,0 +1,181 @@
+/* XPM */
+static const char *CO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 159 2",
+" c black",
+". c #000000009D9D",
+"X c #000000009F9F",
+"o c #00000101C7C7",
+"O c #00000909C7C7",
+"+ c #00001111C7C7",
+"@ c #10104A4ACFCF",
+"# c #14144E4ED0D0",
+"$ c #18185151CECE",
+"% c #1D1D5656CFCF",
+"& c #19195252D2D2",
+"* c #1D1D5555D0D0",
+"= c #1F1F5656D4D4",
+"- c #22225959D2D2",
+"; c #23235A5AD2D2",
+": c #24245A5AD6D6",
+"> c #28285E5ED3D3",
+", c #28285C5CD4D4",
+"< c #2A2A5E5ED7D7",
+"1 c #2E2E6161D6D6",
+"2 c #2E2E6262D5D5",
+"3 c #2F2F6262D8D8",
+"4 c #33336464D5D5",
+"5 c #33336666D7D7",
+"6 c #33336565D8D8",
+"7 c #34346767DADA",
+"8 c #39396A6AD5D5",
+"9 c #3E3E6E6ED6D6",
+"0 c #38386969D9D9",
+"q c #39396B6BD9D9",
+"w c #3A3A6B6BDCDC",
+"e c #3E3E6E6EDADA",
+"r c #3E3E6F6FDADA",
+"t c #40406F6FDDDD",
+"y c #42427272DCDC",
+"u c #43437373DCDC",
+"i c #45457373DFDF",
+"p c #48487676DDDD",
+"a c #48487777DDDD",
+"s c #4C4C7A7ADFDF",
+"d c #4D4D7B7BDEDE",
+"f c #49497878E0E0",
+"g c #52527E7EE0E0",
+"h c #52527F7FE0E0",
+"j c #56568282E1E1",
+"k c #6A6A9090E7E7",
+"l c #71719595E7E7",
+"z c #75759999E7E7",
+"x c #ADAD00000000",
+"c c #B9B900000000",
+"v c #BBBB00000000",
+"b c #BDBD00000000",
+"n c #BFBF00000000",
+"m c #C1C100000000",
+"M c #C3C300000000",
+"N c #C5C500000000",
+"B c #C9C900000000",
+"V c #CBCB00000000",
+"C c #CFCF00000000",
+"Z c #D1D100000000",
+"A c #D3D300000000",
+"S c #D7D700000000",
+"D c #D9D900000000",
+"F c #DDDD00000000",
+"G c #D8D80E0E1313",
+"H c #DADA11111717",
+"J c #DBDB16161C1C",
+"K c #DDDD1B1B2020",
+"L c #DEDE21212525",
+"P c #DEDE31313636",
+"I c #E0E026262A2A",
+"U c #E2E22E2E2E2E",
+"Y c #E2E22B2B3030",
+"T c #E3E331313131",
+"R c #E2E230303535",
+"E c #E4E434343535",
+"W c #E6E637373737",
+"Q c #E4E436363B3B",
+"! c #E6E63B3B3B3B",
+"~ c #E5E53B3B4040",
+"^ c #CFCF7F7F0000",
+"/ c #E7E740404040",
+"( c #E7E741414545",
+") c #E8E844444444",
+"_ c #E8E846464B4B",
+"` c #E9E949494949",
+"' c #EBEB4C4C4C4C",
+"] c #ECEC51515151",
+"[ c #EDED55555555",
+"{ c #EEEE5B5B5B5B",
+"} c #EFEF5F5F5F5F",
+"| c #EDED68686C6C",
+" . c #F0F064646464",
+".. c #CFCF81810000",
+"X. c #D3D387870000",
+"o. c #D5D58B8B0000",
+"O. c #D9D993930000",
+"+. c #DBDB93930000",
+"@. c #DDDD97970000",
+"#. c #DFDF9B9B0000",
+"$. c #E1E19F9F0000",
+"%. c #E3E3A3A30000",
+"&. c #E5E5A7A70000",
+"*. c #E7E7ABAB0000",
+"=. c #E9E9ADAD0000",
+"-. c #E9E9AFAF0000",
+";. c #EBEBB1B10000",
+":. c #EDEDB1B10000",
+">. c #EDEDB3B30000",
+",. c #EDEDB5B50000",
+"<. c #EFEFB7B70000",
+"1. c #F4F4CCCC2020",
+"2. c #F5F5CDCD2626",
+"3. c #F5F5CECE2525",
+"4. c #F6F6CECE2B2B",
+"5. c #F6F6CECE2C2C",
+"6. c #F6F6D0D02B2B",
+"7. c #F7F7D0D03131",
+"8. c #F7F7D2D23030",
+"9. c #F5F5D3D33F3F",
+"0. c #F8F8D2D23636",
+"q. c #F8F8D2D23737",
+"w. c #F8F8D4D43636",
+"e. c #F9F9D3D33C3C",
+"r. c #F9F9D4D43D3D",
+"t. c #F9F9D5D53C3C",
+"y. c #F6F6D3D34444",
+"u. c #F7F7D5D54949",
+"i. c #F7F7D7D74E4E",
+"p. c #FAFAD5D54242",
+"a. c #FAFAD7D74141",
+"s. c #FBFBD7D74747",
+"d. c #FBFBD9D94646",
+"f. c #FCFCD8D84B4B",
+"g. c #FCFCDBDB4B4B",
+"h. c #FCFCD8D84C4C",
+"j. c #F8F8D8D85353",
+"k. c #F9F9D9D95757",
+"l. c #FDFDDADA5151",
+"z. c #FDFDDBDB5454",
+"x. c #FDFDDCDC5050",
+"c. c #FDFDDDDD5454",
+"v. c #FAFADBDB5C5C",
+"b. c #FEFEDCDC5959",
+"n. c #FEFEDEDE5858",
+"m. c #FEFEDEDE5C5C",
+"M. c #FEFEDFDF5F5F",
+"N. c #FBFBDDDD6060",
+"B. c #FCFCDDDD6565",
+"V. c #FCFCDFDF6969",
+"C. c #FDFDE0E06D6D",
+"Z. c #FDFDE2E27171",
+"A. c #FEFEE2E27474",
+"S. c #FEFEE3E37777",
+"D. c #FEFEE4E47676",
+"F. c #FEFEE4E47979",
+"G. c #FFFFE4E47A7A",
+"H. c #FFFFE4E47B7B",
+"J. c None",
+/* pixels */
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+",.,.,.,.>.>.=.=.*.&.%.$.$. at .O.O.",
+",.H.H.H.A.A.A.V.C.B.N.v.k.j.i.o.",
+",.H.M.m.m.z.l.g.d.p.r.q.7.5.u.X.",
+",.H.m.m.l.l.g.s.p.e.q.7.4.2.y.^ ",
+">.D.c.c.g.g.s.p.r.w.6.4.2.1.y.^ ",
+"+ z j g d a u r q 5 2 , ; % 9 X ",
+"O k g f a y r q 5 2 , : * $ 8 . ",
+"o k f f r w 7 3 < : = & @ @ 5 . ",
+"D | _ ( ~ Q R Y L L K J H G P x ",
+"F .} { [ ] ' ` ) / ! W W T U c ",
+"F D D A Z C V V N M M b b b c c ",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J."
+};
diff --git a/src/images/flags/CR.xpm b/src/images/flags/CR.xpm
new file mode 100644
index 0000000..42e75dd
--- /dev/null
+++ b/src/images/flags/CR.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *CR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000000002323",
+"X c #000000002525",
+"o c #000000002929",
+"O c #000000002B2B",
+"+ c #000000003131",
+"@ c #000000003737",
+"# c #000000003B3B",
+"$ c #000000003F3F",
+"% c #000000004545",
+"& c #000000004B4B",
+"* c #000000005151",
+"= c #000000005555",
+"- c #000000005757",
+"; c #000000005B5B",
+": c #000000005D5D",
+"> c #000000006161",
+", c #000000006363",
+"< c #000000006767",
+"1 c #000000006D6D",
+"2 c #000000007171",
+"3 c #000000007373",
+"4 c #000000007575",
+"5 c #000000007979",
+"6 c #000000007D7D",
+"7 c #000001017F7F",
+"8 c #000007078383",
+"9 c #000009098585",
+"0 c #00000F0F8585",
+"q c #000019198D8D",
+"w c #5B5B7979B5B5",
+"e c #5C5C7A7AB6B6",
+"r c #60607D7DB8B8",
+"t c #62627F7FB9B9",
+"y c #65658282BBBB",
+"u c #69698484BDBD",
+"i c #6C6C8888BEBE",
+"p c #6F6F8A8AC1C1",
+"a c #6F6F8A8AC2C2",
+"s c #73738E8EC3C3",
+"d c #74748E8EC3C3",
+"f c #77779191C5C5",
+"g c #77779090C6C6",
+"h c #7B7B9494C7C7",
+"j c #7A7A9494C8C8",
+"k c #7F7F9797C9C9",
+"l c #7F7F9797CACA",
+"z c #B7B700000000",
+"x c #B9B900000000",
+"c c #BBBB00000000",
+"v c #DDDD00000000",
+"b c #DFDF00000000",
+"n c #DCDC14141414",
+"m c #DDDD19191919",
+"M c #DEDE1A1A1A1A",
+"N c #DFDF1F1F1F1F",
+"B c #E1E100000000",
+"V c #E0E01F1F1F1F",
+"C c #E0E020202020",
+"Z c #E0E024242424",
+"A c #E1E125252525",
+"S c #E2E22A2A2A2A",
+"D c #E3E32B2B2B2B",
+"F c #E3E32F2F2F2F",
+"G c #E0E036363636",
+"H c #E4E430303030",
+"J c #E5E535353535",
+"K c #E6E636363636",
+"L c #E2E23B3B3B3B",
+"P c #E3E33F3F3F3F",
+"I c #E6E63B3B3A3A",
+"U c #E7E73B3B3B3B",
+"Y c #E7E73B3B3C3C",
+"T c #D3D341413F3F",
+"R c #DFDF69696767",
+"E c #E7E740404040",
+"W c #E8E840404040",
+"Q c #E9E941414141",
+"! c #E8E845454545",
+"~ c #E9E946464646",
+"^ c #E9E94A4A4949",
+"/ c #EAEA4A4A4B4B",
+"( c #EAEA4B4B4B4B",
+") c #EBEB4F4F4F4F",
+"_ c #EBEB4F4F5050",
+"` c #EDED53535353",
+"' c #EDED54545454",
+"] c #EEEE58585858",
+"[ c #EFEF6F6F6F6F",
+"{ c #F1F172727373",
+"} c #F1F176767676",
+"| c #82829A9ACBCB",
+" . c #82829A9ACCCC",
+".. c #85859D9DCDCD",
+"X. c #85859E9ECDCD",
+"o. c #8989A0A0CECE",
+"O. c #8B8BA2A2D0D0",
+"+. c #8F8FA4A4D2D2",
+"@. c #9191A7A7D3D3",
+"#. c #9393A8A8D4D4",
+"$. c #9494A9A9D4D4",
+"%. c #9595A9A9D4D4",
+"&. c #F1F187878585",
+"*. c #EBEBA0A09F9F",
+"=. c #ECECA2A2A2A2",
+"-. c #EEEEA4A4A3A3",
+";. c #EEEEA7A7A6A6",
+":. c #EFEFAAAAA9A9",
+">. c #EDEDAEAEADAD",
+",. c #F0F0ACACABAB",
+"<. c #F1F1AFAFAEAE",
+"1. c #F9F9A1A1A1A1",
+"2. c #F3F3B2B2B1B1",
+"3. c #F2F2B4B4B3B3",
+"4. c #F3F3B6B6B5B5",
+"5. c #F4F4B4B4B3B3",
+"6. c #F5F5B7B7B6B6",
+"7. c #F3F3BEBEBEBE",
+"8. c #F4F4B9B9B8B8",
+"9. c #F6F6B9B9B8B8",
+"0. c #F4F4BCBCBBBB",
+"q. c #F7F7BCBCBBBB",
+"w. c #F5F5BDBDBDBD",
+"e. c #F6F6BFBFBFBF",
+"r. c #DDDDDFDFDFDF",
+"t. c #F7F7C2C2C1C1",
+"y. c #F8F8C4C4C3C3",
+"u. c #F9F9C6C6C5C5",
+"i. c #FAFAC8C8C7C7",
+"p. c #F9F9C8C8C8C8",
+"a. c #FAFAC9C9C9C9",
+"s. c #FBFBCBCBCACA",
+"d. c #FCFCD4D4D4D4",
+"f. c #E5E5E9E9E9E9",
+"g. c #F0F0F1F1F1F1",
+"h. c #F1F1F1F1F1F1",
+"j. c #F1F1F2F2F2F2",
+"k. c #F2F2F3F3F3F3",
+"l. c #F3F3F4F4F4F4",
+"z. c #F4F4F5F5F5F5",
+"x. c #F4F4F6F6F6F6",
+"c. c #F5F5F6F6F6F6",
+"v. c #F5F5F7F7F7F7",
+"b. c gray97",
+"n. c #F5F5F8F8F8F8",
+"m. c #F6F6F9F9F9F9",
+"M. c #F7F7F9F9F9F9",
+"N. c #F7F7FAFAFAFA",
+"B. c #F8F8F8F8F8F8",
+"V. c #F9F9F9F9F9F9",
+"C. c #F8F8FBFBFBFB",
+"Z. c #F9F9FAFAFAFA",
+"A. c gray98",
+"S. c #F9F9FCFCFCFC",
+"D. c #F9F9FFFFFFFF",
+"F. c #FAFAFDFDFDFD",
+"G. c #FBFBFCFCFCFC",
+"H. c #FBFBFDFDFDFD",
+"J. c #FBFBFEFEFEFE",
+"K. c #FCFCFEFEFEFE",
+"L. c #FCFCFFFFFFFF",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"0 9 9 9 8 7 6 5 4 2 1 < < : = = ",
+"q %. at .@. at .@.o.X.X. .l j f d s = ",
+"D.L.L.L.L.G.G.D.D.N.n.n.B.c.c.f.",
+"1.d.s.s.u.u.y.t.w.w.w.8.3.3.7.R ",
+"B } ] ' _ / ~ Q Y K H D A C P c ",
+"B { ` ) / ~ Q L K H D A N m L c ",
+"b [ ) / ~ P I K F S Z N m n G c ",
+"&.s.q.9.6.5.2.<.,.:.;.=.=.*.>.T ",
+"n.A.V.V.V.V.b.c.c.k.k.k.g.g.k.r.",
+"2 X.| | h f d p i u y t e e e O ",
+"< , ; = * & % $ # @ + O O X . X ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/CS.xpm b/src/images/flags/CS.xpm
new file mode 100644
index 0000000..ebbf3b0
--- /dev/null
+++ b/src/images/flags/CS.xpm
@@ -0,0 +1,162 @@
+/* XPM */
+static const char *CS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 140 2",
+" c black",
+". c #000000004343",
+"X c #000000004D4D",
+"o c #000000005D5D",
+"O c #000000006161",
+"+ c #000000006363",
+"@ c #000000006767",
+"# c #000000006D6D",
+"$ c #000000007171",
+"% c #000000007575",
+"& c #000000007979",
+"* c #000000007B7B",
+"= c #000000007D7D",
+"- c #000000008181",
+"; c #000000008383",
+": c #000000008585",
+"> c #000000008787",
+", c #000000008989",
+"< c #000000009191",
+"1 c #2C2C2C2CA1A1",
+"2 c #31313131A4A4",
+"3 c #37373737A7A7",
+"4 c #35353535AFAF",
+"5 c #3D3D3C3CAAAA",
+"6 c #42424242ADAD",
+"7 c #49494949AEAE",
+"8 c #47474747B0B0",
+"9 c #4C4C4C4CB2B2",
+"0 c #4E4E4E4EB4B4",
+"q c #51515151B4B4",
+"w c #53535353B7B7",
+"e c #54545454B7B7",
+"r c #58585757B9B9",
+"t c #59595959B8B8",
+"y c #5C5C5C5CBABA",
+"u c #5C5C5C5CBBBB",
+"i c #5F5F5F5FBBBB",
+"p c #61616060BEBE",
+"a c #6A6A6A6ABEBE",
+"s c #65656565C0C0",
+"d c #69696969C2C2",
+"f c #6D6D6D6DC3C3",
+"g c #6E6E6E6EC0C0",
+"h c #72727272C2C2",
+"j c #70707070C5C5",
+"k c #74747474C7C7",
+"l c #76767676C4C4",
+"z c #77777777C8C8",
+"x c #7A7A7A7AC6C6",
+"c c #7F7F7F7FC6C6",
+"v c #79797979C9C9",
+"b c #7B7B7B7BC8C8",
+"n c #7B7B7B7BCACA",
+"m c #7D7D7D7DC9C9",
+"M c #DDDD00000000",
+"N c #DFDF00000000",
+"B c #E1E100000000",
+"V c #E3E300000000",
+"C c #E5E500000000",
+"Z c #E7E700000000",
+"A c #E9E900000000",
+"S c #EBEB00000000",
+"D c #EDED00000000",
+"F c #EFEF00000000",
+"G c #F1F100000000",
+"H c #F3F300000000",
+"J c #F5F500000000",
+"K c #F7F700000000",
+"L c #F1F10B0B0B0B",
+"P c #F1F10F0F0E0E",
+"I c #F9F900000000",
+"U c #F2F213131313",
+"Y c #F3F319191919",
+"T c #F4F41E1E1E1E",
+"R c #F5F523232323",
+"E c #F2F22C2C2C2C",
+"W c #F2F22F2F2F2F",
+"Q c #F6F629292929",
+"! c #F7F72E2E2E2E",
+"~ c #FBFB29292929",
+"^ c #F2F232323232",
+"/ c #F3F335353535",
+"( c #F4F439393939",
+") c #F5F53D3D3D3D",
+"_ c #F8F834343434",
+"` c #F9F93A3A3A3A",
+"' c #FAFA3F3F3F3F",
+"] c #F6F642424242",
+"[ c #F7F746464646",
+"{ c #F7F74B4B4B4B",
+"} c #FAFA44444444",
+"| c #F8F850505050",
+" . c #F9F954545555",
+".. c #F9F958585858",
+"X. c #FAFA5D5D5D5D",
+"o. c #F2F263636363",
+"O. c #F2F266666666",
+"+. c #F3F36A6A6A6A",
+"@. c #F4F46E6E6E6E",
+"#. c #FBFB61616262",
+"$. c #FCFC66666666",
+"%. c #F3F377777777",
+"&. c #F5F571717171",
+"*. c #F6F675757575",
+"=. c #F7F778787979",
+"-. c #F8F87C7C7C7C",
+";. c #81818181CACA",
+":. c #85858585CCCC",
+">. c #88888888CECE",
+",. c #8B8B8B8BCFCF",
+"<. c #8E8E8F8FD1D1",
+"1. c #90909090D2D2",
+"2. c #A4A4A4A4DADA",
+"3. c #F9F980808080",
+"4. c #FAFA84848484",
+"5. c #FBFB88888888",
+"6. c #FBFB8B8B8B8B",
+"7. c #FCFCA0A0A0A0",
+"8. c #E3E3C7C7C7C7",
+"9. c #E5E5C9C9C9C9",
+"0. c #E7E7CDCDCDCD",
+"q. c #FDFDE7E7E7E7",
+"w. c #FDFDE9E9E9E9",
+"e. c gray95",
+"r. c #F3F3F3F3F3F3",
+"t. c #F4F4F4F4F4F4",
+"y. c #F4F4F5F5F5F5",
+"u. c gray96",
+"i. c #F6F6F6F6F6F6",
+"p. c gray97",
+"a. c #F8F8F8F8F8F8",
+"s. c #F9F9F9F9F9F9",
+"d. c gray98",
+"f. c #FBFBFBFBFBFB",
+"g. c #FBFBFCFCFBFB",
+"h. c gray99",
+"j. c #FDFDFCFCFDFD",
+"k. c #FDFDFDFDFDFD",
+"l. c #FEFEFEFEFEFE",
+"z. c None",
+/* pixels */
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"< , , , , - - = & % $ # @ O o O ",
+": n n n k k j f d p p i r w 0 X ",
+"- n i y y e q 9 7 6 5 3 2 1 7 . ",
+"4 2.1.<.>.>.:.;.m x l h f a c = ",
+"w.l.l.l.l.f.d.d.d.d.p.i.t.u.u.0.",
+"w.l.l.l.f.d.d.d.u.d.u.u.u.r.u.9.",
+"q.l.f.f.d.d.d.a.u.u.u.u.r.r.r.8.",
+"~ 7.6.5.4.3.-.=.*.&. at .+.O.o.%.N ",
+"K $.} ' ` _ ! Q R T Y U P L W N ",
+"K #.X... .| { [ ] ) ( / ^ W W N ",
+"K G G D D D S S Z Z B B N N M M ",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z."
+};
diff --git a/src/images/flags/CU.xpm b/src/images/flags/CU.xpm
new file mode 100644
index 0000000..74c084b
--- /dev/null
+++ b/src/images/flags/CU.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *CU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000000005F5F",
+"X c #000000006B6B",
+"o c #000000006D6D",
+"O c #000000006F6F",
+"+ c #000000007373",
+"@ c #000000007575",
+"# c #000000007979",
+"$ c #000000007B7B",
+"% c #000000007F7F",
+"& c #000000008181",
+"* c #000000008383",
+"= c #000001018585",
+"- c #000000008787",
+"; c #000000008B8B",
+": c #000001018F8F",
+"> c #000007078B8B",
+", c #000009098B8B",
+"< c #000009099393",
+"1 c #00000F0F9797",
+"2 c #000011118F8F",
+"3 c #000017179393",
+"4 c #000015159999",
+"5 c #00001D1D9797",
+"6 c #000023239B9B",
+"7 c #000029299D9D",
+"8 c #00002F2FA1A1",
+"9 c #00003535A3A3",
+"0 c #00003939A5A5",
+"q c #00003D3DA9A9",
+"w c #00003F3FA9A9",
+"e c #00004141A7A7",
+"r c #00004747B3B3",
+"t c #1A1A5858B0B0",
+"y c #1F1F5C5CB2B2",
+"u c #25256060B4B4",
+"i c #2A2A6565B6B6",
+"p c #30306969B9B9",
+"a c #36366E6EBCBC",
+"s c #3B3B7070BABA",
+"d c #37377575C0C0",
+"f c #3B3B7474C1C1",
+"g c #3B3B7878C2C2",
+"h c #3F3F7C7CC4C4",
+"j c #42427D7DC3C3",
+"k c #42427E7EC4C4",
+"l c #45457E7EC3C3",
+"z c #44448080C6C6",
+"x c #47478181C6C6",
+"c c #48488080C4C4",
+"v c #4B4B8383C5C5",
+"b c #4E4E8585C7C7",
+"n c #49498383C8C8",
+"m c #4B4B8585C8C8",
+"M c #4E4E8686CACA",
+"N c #50508888CACA",
+"B c #52528888C9C9",
+"V c #53538989C8C8",
+"C c #52528A8ACCCC",
+"Z c #56568B8BCBCB",
+"A c #54548C8CCCCC",
+"S c #59598E8ECECE",
+"D c #5A5A8C8CCCCC",
+"F c #5B5B8F8FCDCD",
+"G c #5C5C8F8FCCCC",
+"H c #5F5F9191CECE",
+"J c #5E5E9292D0D0",
+"K c #61619494CFCF",
+"L c #63639494D0D0",
+"P c #64649494D0D0",
+"I c #65659797D1D1",
+"U c #67679898D2D2",
+"Y c #6A6A9999D3D3",
+"T c #6B6B9A9AD3D3",
+"R c #6F6F9D9DD4D4",
+"E c #71719D9DD3D3",
+"W c #72729F9FD6D6",
+"Q c #7676A3A3D8D8",
+"! c #7A7AA5A5D9D9",
+"~ c #7E7EA8A8DBDB",
+"^ c #9F9F4E4E6F6F",
+"/ c #A8A852527171",
+"( c #ADAD5D5D7A7A",
+") c #CBCB00000000",
+"_ c #DBDB00000000",
+"` c #EBEB00000000",
+"' c #EDED00000000",
+"] c #EFEF00000000",
+"[ c #F1F100000000",
+"{ c #F3F300000000",
+"} c #F7F700000000",
+"| c red",
+" . c #EBEB45454545",
+".. c #EBEB46464646",
+"X. c #EDED45454545",
+"o. c #EFEF4F4F5050",
+"O. c #F4F44A4A4B4B",
+"+. c #F6F649494949",
+"@. c #F4F44D4D4C4C",
+"#. c #F1F15A5A5959",
+"$. c #F6F658585858",
+"%. c #F9F95C5C5C5C",
+"&. c #ECEC63636565",
+"*. c #F0F061616161",
+"=. c #F7F76A6A6A6A",
+"-. c #FBFB66666666",
+";. c #F2F27D7D7E7E",
+":. c #F9F979797979",
+">. c #FEFE7B7B7A7A",
+",. c #8080AAAADCDC",
+"<. c #8484ACACDDDD",
+"1. c #8686AEAEDEDE",
+"2. c #8787B0B0DFDF",
+"3. c #9797A5A5CDCD",
+"4. c #F8F884848484",
+"5. c #F8F887878787",
+"6. c #F5F5ADADACAC",
+"7. c #FAFAA5A5A3A3",
+"8. c #FDFDB8B8B6B6",
+"9. c #F9F9B8B8B9B9",
+"0. c #FBFBBDBDBDBD",
+"q. c #FAFABEBEBEBE",
+"w. c #D5D5D7D7DBDB",
+"e. c #DFDFDFDFDFDF",
+"r. c #FEFEC3C3C1C1",
+"t. c #FCFCCCCCCCCC",
+"y. c #E1E1E5E5E7E7",
+"u. c #E7E7E7E7E7E7",
+"i. c #ECECEDEDEFEF",
+"p. c #EDEDEEEEF0F0",
+"a. c #EEEEEEEEF0F0",
+"s. c #EEEEEFEFF1F1",
+"d. c #F0F0F1F1F2F2",
+"f. c #F1F1F2F2F3F3",
+"g. c gray95",
+"h. c #F3F3F3F3F3F3",
+"j. c #F1F1F3F3F5F5",
+"k. c #F2F2F3F3F5F5",
+"l. c #F2F2F4F4F6F6",
+"z. c #F3F3F4F4F6F6",
+"x. c #F4F4F4F4F4F4",
+"c. c gray96",
+"v. c #F4F4F5F5F7F7",
+"b. c #F6F6F6F6F6F6",
+"n. c gray97",
+"m. c #F4F4F5F5F8F8",
+"M. c #F5F5F5F5F8F8",
+"N. c #F5F5F7F7F9F9",
+"B. c #F6F6F6F6F9F9",
+"V. c #F6F6F7F7FAFA",
+"C. c #F7F7F8F8FBFB",
+"Z. c #F8F8F8F8F8F8",
+"A. c #F9F9F9F9F9F9",
+"S. c #F8F8F9F9FBFB",
+"D. c gray98",
+"F. c #FBFBFBFBFBFB",
+"G. c #F9F9FBFBFCFC",
+"H. c #F9F9FBFBFDFD",
+"J. c #FCFCF9F9F9F9",
+"K. c gray99",
+"L. c #FDFDFDFDFDFD",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"_ e r w w 0 9 8 7 6 5 3 3 , = > ",
+"| ;.3.1.1.<.,.~ ! Q W R Y P K ; ",
+"{ >.&.r.G.D.V.D.G.z.z.b.k.k.l.y.",
+"{ :.%.#.8.L.L.K.G.D.D.b.b.b.b.u.",
+"{ 5.q.$.o.( K H D C M m x k G & ",
+"{ t.J.9.O...^ f a p i u y t s X ",
+"` 4.q. at .X./ D C M n x k f d V @ ",
+"` =.O.X.7.D.B.n.b.b.h.d.h.h.h.e.",
+"` -...6.z.b.b.l.k.d.a.a.i.i.i.w.",
+"} &.E T U L H D Z B b v c l k . ",
+") 4 1 < : ; = = % # @ + o o X o ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/CV.xpm b/src/images/flags/CV.xpm
new file mode 100644
index 0000000..27d2029
--- /dev/null
+++ b/src/images/flags/CV.xpm
@@ -0,0 +1,163 @@
+/* XPM */
+static const char *CV_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 141 2",
+" c black",
+". c #00000000DDDD",
+"X c #00000000DFDF",
+"o c #00000000E1E1",
+"O c #00000000E3E3",
+"+ c #00000505E5E5",
+"@ c #00000909E7E7",
+"# c #00000F0FE7E7",
+"$ c #00001111E9E9",
+"% c #00001515E9E9",
+"& c #00001717EBEB",
+"* c #00001D1DEBEB",
+"= c #00001D1DEDED",
+"- c #00002525EDED",
+"; c #00002525EFEF",
+": c #00002B2BEFEF",
+"> c #00003131F1F1",
+", c #00003939F3F3",
+"< c #00003F3FF5F5",
+"1 c #00004545F7F7",
+"2 c #00004949F9F9",
+"3 c #00004B4BF9F9",
+"4 c #00004F4FFBFB",
+"5 c #00005353FDFD",
+"6 c #00005959FDFD",
+"7 c #00005B5BFDFD",
+"8 c #00005D5DFDFD",
+"9 c #00005F5FFDFD",
+"0 c #00006161FFFF",
+"q c #20207D7DF1F1",
+"w c #24248080F1F1",
+"e c #29298383F2F2",
+"r c #2D2D8686F3F3",
+"t c #34348A8AF4F4",
+"y c #39398D8DF5F5",
+"u c #3A3A8E8EF5F5",
+"i c #3E3E8E8EF2F2",
+"p c #3E3E9191F6F6",
+"a c #3F3F9191F6F6",
+"s c #7E7EAFAFB5B5",
+"d c #40409090F2F2",
+"f c #41419090F2F2",
+"g c #41419292F7F7",
+"h c #43439494F7F7",
+"j c #44449191F3F3",
+"k c #47479494F3F3",
+"l c #44449494F7F7",
+"z c #45459494F7F7",
+"x c #4B4B9797F4F4",
+"c c #49499797F8F8",
+"v c #4E4E9999F5F5",
+"b c #4A4A9898F8F8",
+"n c #4E4E9B9BF9F9",
+"m c #4F4F9B9BF9F9",
+"M c #50509A9AF5F5",
+"N c #55559D9DF6F6",
+"B c #53539E9EFAFA",
+"V c #55559F9FFAFA",
+"C c #5757A0A0FBFB",
+"Z c #5A5AA0A0F7F7",
+"A c #5F5FA3A3F7F7",
+"S c #5D5DA3A3FCFC",
+"D c #6666A4A4D5D5",
+"F c #6E6EA9A9D7D7",
+"G c #7878B0B0DCDC",
+"H c #7F7FB5B5DEDE",
+"J c #6363A6A6F8F8",
+"K c #6161A6A6FDFD",
+"L c #6767A9A9F9F9",
+"P c #6565A9A9FDFD",
+"I c #6767ABABFEFE",
+"U c #6868A9A9F9F9",
+"Y c #6B6BABABFAFA",
+"T c #6969ABABFEFE",
+"R c #6B6BADADFEFE",
+"E c #6C6CACACFAFA",
+"W c #6F6FAEAEFBFB",
+"Q c #6E6EAFAFFEFE",
+"! c #7070AEAEFBFB",
+"~ c #7373B0B0FCFC",
+"^ c #7575B1B1FCFC",
+"/ c #7777B2B2FCFC",
+"( c #7A7AB4B4FDFD",
+") c #7E7EB7B7FEFE",
+"_ c #CFCF00000000",
+"` c #EDED00000000",
+"' c #E9E928282828",
+"] c #EAEA2D2D2D2D",
+"[ c #EBEB32323131",
+"{ c #EBEB46464646",
+"} c #F0F045454545",
+"| c #F1F14B4B4B4B",
+" . c #F2F250505050",
+".. c #F3F354545454",
+"X. c #EFEF7E7E4444",
+"o. c #F7F77B7B7B7B",
+"O. c #F1F185854E4E",
+"+. c #F8F899996A6A",
+"@. c #F6F6E6E65D5D",
+"#. c #F0F0EAEA5D5D",
+"$. c #F4F4EFEF6E6E",
+"%. c #F5F5EFEF7070",
+"&. c #FBFBEEEE7676",
+"*. c #F7F7F0F07777",
+"=. c #F8F8F2F27F7F",
+"-. c #FCFCF4F47878",
+";. c #8E8EBABABFBF",
+":. c #8F8FBABAC3C3",
+">. c #9393BEBEC3C3",
+",. c #9292BEBEC6C6",
+"<. c #9696BEBEC3C3",
+"1. c #8181B9B9FEFE",
+"2. c #8383B9B9FEFE",
+"3. c #8484BABAFEFE",
+"4. c #8585BBBBFEFE",
+"5. c #8585BCBCFEFE",
+"6. c #8888BDBDFFFF",
+"7. c #9898C1C1C6C6",
+"8. c #9C9CC2C2C7C7",
+"9. c #9C9CC3C3CACA",
+"0. c #9E9EC5C5CACA",
+"q. c #9E9EC5C5CDCD",
+"w. c #A1A1C7C7CBCB",
+"e. c #DFDFDFDFDFDF",
+"r. c gray90",
+"t. c #FCFCFBFBE0E0",
+"y. c gray95",
+"u. c #F3F3F3F3F3F3",
+"i. c #F4F4F4F4F4F4",
+"p. c #F4F4F5F5F5F5",
+"a. c gray96",
+"s. c #F6F6F6F6F6F6",
+"d. c gray97",
+"f. c #F8F8F8F8F8F8",
+"g. c #F9F9F9F9F9F9",
+"h. c gray98",
+"j. c #FBFBFBFBFBFB",
+"k. c gray99",
+"l. c #FDFDFDFDFDFD",
+"z. c #FEFEFEFEFEFE",
+"x. c None",
+/* pixels */
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"0 0 0 0 0 6 6 5 4 2 1 < , > : ; ",
+"0 6.6.5.4.2.) ( / ~ W Y L J A * ",
+"0 6.Q R I P K S V B m c z a Z % ",
+"0 4.R I q.0.-.7.,.m c h a u N # ",
+"8 2.I w.=.H V G %.;.h a u t M @ ",
+"l.l.l.t.j.j.g.g.g.d.d.s.u.u.s.r.",
+"` o.+.&... .| } O. at .X.[ ] ' { _ ",
+"j.l.j.j.j.g.f.f.s.s.s.u.u.u.u.e.",
+"2 / V >.$.F g D #.s r w q q f X ",
+"1 ! W L 0.8.&.,.:.v x k j f i . ",
+"< , > : ; = & $ @ + o o X . . . ",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x."
+};
diff --git a/src/images/flags/CX.xpm b/src/images/flags/CX.xpm
new file mode 100644
index 0000000..4eea892
--- /dev/null
+++ b/src/images/flags/CX.xpm
@@ -0,0 +1,191 @@
+/* XPM */
+static const char *CX_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 169 2",
+" c black",
+". c #000001010000",
+"X c #000000004141",
+"o c #000017175F5F",
+"O c #000000006969",
+"+ c #000000006D6D",
+"@ c #000000007777",
+"# c #000000007B7B",
+"$ c #000065650000",
+"% c #000069690000",
+"& c #00006B6B0000",
+"* c #00006F6F0000",
+"= c #000073730000",
+"- c #000077770000",
+"; c #0F0F7D7D4A4A",
+": c #000000008181",
+"> c #000000008585",
+", c #000000008989",
+"< c #000000008D8D",
+"1 c #000000008F8F",
+"2 c #000000009393",
+"3 c #000000009797",
+"4 c #000000009B9B",
+"5 c #00000000A1A1",
+"6 c #00000000A5A5",
+"7 c #00000000A7A7",
+"8 c #00000000ABAB",
+"9 c #00000000AFAF",
+"0 c #00000000B1B1",
+"q c #00000000B3B3",
+"w c #00000000B5B5",
+"e c #13131D1DB1B1",
+"r c #18181919BCBC",
+"t c #1E1E1E1EBEBE",
+"y c #24242424C1C1",
+"u c #23232323C8C8",
+"i c #2E2E2E2EC6C6",
+"p c #29292929CACA",
+"a c #32323232C3C3",
+"s c #35353535C3C3",
+"d c #34343434C7C7",
+"f c #35353535C9C9",
+"g c #39393939C5C5",
+"h c #3D3D3D3DC7C7",
+"j c #3A3A3A3AC9C9",
+"k c #3A3A3A3ACACA",
+"l c #1F1F4A4A9393",
+"z c #2F2F5D5D9292",
+"x c #42424242C8C8",
+"c c #42424242CCCC",
+"v c #46464646CACA",
+"b c #49494949CECE",
+"n c #49494949CFCF",
+"m c #4B4B4B4BCCCC",
+"M c #4B4B4D4DCECE",
+"N c #40404040D1D1",
+"B c #46464646D8D8",
+"V c #50504F4FD1D1",
+"C c #50505050CECE",
+"Z c #54545454CFCF",
+"A c #50505050D1D1",
+"S c #51515151D0D0",
+"D c #53535353D2D2",
+"F c #55555555D4D4",
+"G c #59595959D2D2",
+"H c #58585959D4D4",
+"J c #5C5C5C5CD5D5",
+"K c #5F5F5F5FD7D7",
+"L c #54546767C0C0",
+"P c #61616161D4D4",
+"I c #63636363D7D7",
+"U c #66666666D7D7",
+"Y c #6A6A6A6AD8D8",
+"T c #76767676DBDB",
+"R c #76767777DADA",
+"E c #79797979DDDD",
+"W c #7B7B7B7BDDDD",
+"Q c #000081810000",
+"! c #000085850000",
+"~ c #00008B8B0000",
+"^ c #00008F8F0000",
+"/ c #000093930000",
+"( c #000097970000",
+") c #00009B9B0000",
+"_ c #00009D9D0000",
+"` c #0000A1A10000",
+"' c #0000A3A30000",
+"] c #0000A5A50000",
+"[ c #0000A7A70000",
+"{ c #0000ABAB0000",
+"} c #0000ADAD0000",
+"| c #0000AFAF0000",
+" . c #0B0BB7B70B0B",
+".. c #1010B9B91010",
+"X. c #1414BBBB1414",
+"o. c #1919ACAC2A2A",
+"O. c #2C2CB6B63636",
+"+. c #2424C1C12424",
+"@. c #2525C1C12525",
+"#. c #2A2AC3C32B2B",
+"$. c #2B2BC3C32B2B",
+"%. c #2F2FC1C12F2F",
+"&. c #3333C3C33232",
+"*. c #3030C5C53030",
+"=. c #3131C6C63131",
+"-. c #3636C4C43636",
+";. c #3737C8C83636",
+":. c #3737C8C83737",
+">. c #3B3BC6C63B3B",
+",. c #3E3ECACA3636",
+"<. c #3C3CCACA3C3C",
+"1. c #3D3DCACA3D3D",
+"2. c #5151B7B76B6B",
+"3. c #7D7DD3D30000",
+"4. c #7E7EE1E13B3B",
+"5. c #4242CBCB4242",
+"6. c #4242CCCC4242",
+"7. c #4747CECE4747",
+"8. c #4949CCCC4949",
+"9. c #4E4ECDCD4E4E",
+"0. c #4B4BD0D04B4B",
+"q. c #4C4CD0D04C4C",
+"w. c #5151D1D15151",
+"e. c #5454D3D35454",
+"r. c #5858D2D25757",
+"t. c #5959D0D05D5D",
+"y. c #5C5CD3D35C5C",
+"u. c #6161D4D46060",
+"i. c #6565D6D66565",
+"p. c #6969D8D86969",
+"a. c #6D6DD9D96D6D",
+"s. c #7070DADA7171",
+"d. c #7474DBDB7474",
+"f. c #7777DDDD7777",
+"g. c #7979DDDD7979",
+"h. c #5C5C9191A1A1",
+"j. c #7B7B8585D3D3",
+"k. c #7B7BC3C39797",
+"l. c #878787877D7D",
+"z. c #8B8BDBDB1919",
+"x. c #8B8BDBDB1A1A",
+"c. c #8E8EDDDD1F1F",
+"v. c #9595E0E02C2C",
+"b. c #9E9EE1E13F3F",
+"n. c #9F9FE5E53C3C",
+"m. c #A3A3E6E64141",
+"M. c #A9A9E7E75353",
+"N. c #C0C0EAEA2020",
+"B. c #C2C2ECEC2626",
+"V. c #C3C3EDED2B2B",
+"C. c #CBCBEAEA2E2E",
+"Z. c #C5C5EEEE3030",
+"A. c #C5C5EEEE3131",
+"S. c #C7C7EFEF3636",
+"D. c #D6D6F3F32F2F",
+"F. c #EAEAF8F83535",
+"G. c #D3D3DEDE4E4E",
+"H. c #CACAEDED4444",
+"J. c #D3D3EEEE4C4C",
+"K. c #ECECF9F94242",
+"L. c #828282828787",
+"P. c #84848484DFDF",
+"I. c #A9A9A9A9E5E5",
+"U. c #B0B0B0B0E8E8",
+"Y. c #DFDFDFDFF3F3",
+"T. c #E1E1E1E1F7F7",
+"R. c #E2E2E2E2F5F5",
+"E. c #E8E8E8E8F7F7",
+"W. c None",
+/* pixels */
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"o ' | | | | | [ ] ' _ ) ( / ^ ~ ",
+"9 j.k.g.g.d.s.a.p.i.u.y.r.M.9.! ",
+"w W K h.t.e.w.0.7.6.1.-.=.v.8.Q ",
+"w W J J L 2.0.7.6.1.-.A.V.B.H.3.",
+"q T Y.I V n J.m.n.S.=.$. at .N.b.- ",
+"q P.D F Y.B K.4.,.A.#. at .c.z.<.- ",
+"9 E.D G D N G.F.D.C.+.c.z.X.-.* ",
+"8 Y n U.I.j f L.l.y l o.X...&.% ",
+"6 U n c j d i p u t r e ; .%.% ",
+"5 P T Y.D C m v x h g s a z O.$ ",
+"6 4 3 2 < < , > : # @ + O O X ",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W."
+};
diff --git a/src/images/flags/CY.xpm b/src/images/flags/CY.xpm
new file mode 100644
index 0000000..2170cdc
--- /dev/null
+++ b/src/images/flags/CY.xpm
@@ -0,0 +1,101 @@
+/* XPM */
+static const char *CY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 79 1",
+" c black",
+". c #7A7AC1C18282",
+"X c #F9F9D3D33F3F",
+"o c #F9F9CDCD4242",
+"O c #FAFACDCD4141",
+"+ c #FAFAD3D34040",
+"@ c #F8F8D5D54747",
+"# c #FBFBD4D45656",
+"$ c #F8F8D9D95A5A",
+"% c #FBFBDDDD6464",
+"& c #FCFCDADA6A6A",
+"* c #F7F7D6D67878",
+"= c #F8F8D9D97B7B",
+"- c #8787C9C99191",
+"; c #8D8DCCCC9696",
+": c #9A9AD0D09F9F",
+"> c #9E9ED5D5A5A5",
+", c #A6A6D7D7AEAE",
+"< c #A5A5D8D8ADAD",
+"1 c #BBBBDFDFB1B1",
+"2 c #FBFBDFDF8C8C",
+"3 c #F7F7E3E39797",
+"4 c #F7F7E5E59494",
+"5 c #EAEAE6E6A7A7",
+"6 c gray81",
+"7 c gray82",
+"8 c LightGray",
+"9 c #D5D5D5D5D5D5",
+"0 c #D7D7D7D7D7D7",
+"q c gray85",
+"w c gray86",
+"e c #DDDDDDDDDDDD",
+"r c #DFDFDFDFDFDF",
+"t c #CECEE4E4C0C0",
+"y c #DFDFEDEDDFDF",
+"u c #FDFDF1F1C5C5",
+"i c #F8F8F1F1D5D5",
+"p c #F9F9F2F2D6D6",
+"a c #FDFDF3F3D3D3",
+"s c #E1E1E1E1E1E1",
+"d c #E1E1E3E3E1E1",
+"f c gray89",
+"g c gray90",
+"h c #E7E7E7E7E7E7",
+"j c #E1E1ECECE1E1",
+"k c #E9E9E9E9E9E9",
+"l c gray92",
+"z c gray93",
+"x c #EFEFEFEFEFEF",
+"c c #EFEFEFEFF1F1",
+"v c #FCFCF7F7E4E4",
+"b c #FAFAF8F8EFEF",
+"n c #F1F1F1F1F1F1",
+"m c gray95",
+"M c #F2F2F2F2F3F3",
+"N c #F3F3F3F3F3F3",
+"B c #F6F6F5F5F0F0",
+"V c #F6F6F6F6F3F3",
+"C c #F4F4F4F4F4F4",
+"Z c #F4F4F5F5F5F5",
+"A c gray96",
+"S c #F6F6F6F6F6F6",
+"D c gray97",
+"F c #F7F7F9F9F7F7",
+"G c #F8F8F8F8F7F7",
+"H c #FCFCFAFAF2F2",
+"J c #F8F8F8F8F8F8",
+"K c #F9F9F9F9F9F9",
+"L c #F8F8FAFAF9F9",
+"P c gray98",
+"I c #FBFBFBFBFBFB",
+"U c #FBFBFCFCFBFB",
+"Y c gray99",
+"T c #FDFDFDFDFCFC",
+"R c #FDFDFDFDFDFD",
+"E c #FDFDFDFDFEFE",
+"W c #FEFEFEFEFEFE",
+"Q c gray100",
+"! c None",
+/* pixels */
+"!!!!!!!!!!!!!!!!",
+"!!!!!!!!!!!!!!!!",
+"!!!!!!!!!!!!!!!!",
+"nnnnncczzzkhgfsr",
+"AQQQIQIQIIIIIIAr",
+"AQQQQIIIIIDIAADe",
+"AQQQIav2bp**VAAe",
+"AQQIu&#XX at 3BAAA0",
+"nQQIH%XX$3DANNA0",
+"xQIII15pt,ANNNN7",
+"nUIID>-,.;NNNnN8",
+"zQFIIDy:yNNMnnM6",
+"zIIIIDDDAAANMnN6",
+"lkgffeewq0087666",
+"!!!!!!!!!!!!!!!!",
+"!!!!!!!!!!!!!!!!"
+};
diff --git a/src/images/flags/CZ.xpm b/src/images/flags/CZ.xpm
new file mode 100644
index 0000000..44da191
--- /dev/null
+++ b/src/images/flags/CZ.xpm
@@ -0,0 +1,148 @@
+/* XPM */
+static const char *CZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 126 2",
+" c black",
+". c #5D5D00001111",
+"X c #00003939AFAF",
+"o c #00004141B3B3",
+"O c #00004747B5B5",
+"+ c #00004D4DB9B9",
+"@ c #03035151BBBB",
+"# c #07075555BFBF",
+"$ c #00005F5FCDCD",
+"% c #0D0D5959C1C1",
+"& c #11115D5DC1C1",
+"* c #11115D5DC3C3",
+"= c #13135F5FC3C3",
+"- c #63639D9DDEDE",
+"; c #71719D9DD8D8",
+": c #7575A0A0D9D9",
+"> c #7676A0A0DADA",
+", c #7A7AA3A3DBDB",
+"< c #7D7DA6A6DCDC",
+"1 c #7E7EA6A6DDDD",
+"2 c #6D6DA4A4E1E1",
+"3 c #7373A9A9E4E4",
+"4 c #7979ADADE6E6",
+"5 c #C3C300000000",
+"6 c #C5C500000000",
+"7 c #C7C700000000",
+"8 c #C9C900000000",
+"9 c #CDCD00000000",
+"0 c #CFCF00000000",
+"q c #D1D100000000",
+"w c #D5D500000000",
+"e c #D7D700000000",
+"r c #D7D707070707",
+"t c #D9D900000000",
+"y c #DBDB00000000",
+"u c #E3E30B0B0B0B",
+"i c #E3E30F0F0E0E",
+"p c #E4E410101010",
+"a c #E5E513131313",
+"s c #E4E414141414",
+"d c #E5E514141414",
+"f c #E5E519191919",
+"g c #E6E619191919",
+"h c #E7E71F1F1F1F",
+"j c #E8E81E1E1E1E",
+"k c #E8E81F1F1F1F",
+"l c #E6E62C2C2C2C",
+"z c #E7E72F2F2F2F",
+"x c #E9E923232323",
+"c c #E8E824242424",
+"v c #E9E924242424",
+"b c #E9E92A2A2A2A",
+"n c #EAEA29292929",
+"m c #EAEA2A2A2A2A",
+"M c #EBEB2E2E2E2E",
+"N c #ECEC2F2F2F2F",
+"B c #E8E832323232",
+"V c #E8E835353535",
+"C c #E8E836363636",
+"Z c #EDED34343434",
+"A c #EDED35353535",
+"S c #E9E939393939",
+"D c #EAEA3D3D3D3D",
+"F c #EEEE3A3A3A3A",
+"G c #EEEE3B3B3A3A",
+"H c #EBEB42424242",
+"J c #EDED46464646",
+"K c #EDED4B4B4B4B",
+"L c #EEEE50505050",
+"P c #F0F054545555",
+"I c #F0F058585858",
+"U c #AFAF6B6B8989",
+"Y c #AFAF6C6C8989",
+"T c #B0B06D6D8A8A",
+"R c #BBBB83839C9C",
+"E c #8181A9A9DDDD",
+"W c #8383AAAADEDE",
+"Q c #8787ACACDEDE",
+"! c #8B8BAFAFDFDF",
+"~ c #8B8BAFAFE1E1",
+"^ c #8F8FB2B2E1E1",
+"/ c #9292B4B4E2E2",
+"( c #9595B6B6E2E2",
+") c #9797B8B8E4E4",
+"_ c #9191BCBCEAEA",
+"` c #9999B9B9E5E5",
+"' c #9C9CBBBBE6E6",
+"] c #BBBBD0D0EBEB",
+"[ c #BFBFD3D3EDED",
+"{ c #D2D287879696",
+"} c #EEEE89898989",
+"| c #EFEF8C8C8C8C",
+" . c #EFEF99999999",
+".. c #F0F08F8F8F8F",
+"X. c #F0F092929292",
+"o. c #F1F195959595",
+"O. c #F3F399999999",
+"+. c #F4F49C9C9C9C",
+"@. c #D7D7D7D7D7D7",
+"#. c gray86",
+"$. c #DDDDDDDDDDDD",
+"%. c #DFDFDFDFDFDF",
+"&. c #C2C2D5D5EFEF",
+"*. c #CECEDDDDF2F2",
+"=. c #E1E1E3E3E3E3",
+"-. c gray90",
+";. c #E7E7E7E7E7E7",
+":. c #E9E9E9E9E9E9",
+">. c gray92",
+",. c gray93",
+"<. c #EFEFEFEFEFEF",
+"1. c #F1F1F1F1F1F1",
+"2. c #F3F3F3F3F3F3",
+"3. c #F4F4F4F4F4F4",
+"4. c gray96",
+"5. c #F6F6F6F6F6F6",
+"6. c gray97",
+"7. c #F8F8F8F8F8F8",
+"8. c #F9F9F9F9F9F9",
+"9. c gray98",
+"0. c #FBFBFBFBFBFB",
+"q. c gray99",
+"w. c #FDFDFDFDFDFD",
+"e. c #FDFDFDFDFEFE",
+"r. c #FEFEFEFEFEFE",
+"t. c None",
+/* pixels */
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+"$ ~ 4.4.4.2.2.1.<.<.,.>.:.;.-.=.",
+"& _ *.e.e.e.e.e.0.e.0.8.8.8.6.%.",
+"& ' 4 &.e.e.e.0.0.8.8.8.6.4.6.$.",
+"= ` W 3 &.e.0.0.0.8.8.6.4.4.4.$.",
+"% ) W 1 2 ] 0.0.8.7.6.4.4.4.4. at .",
+"# ( 1 , ; - { +.O.o.X...| } .r ",
+"+ / , , ; T G Z N b v h g s C 6 ",
+"+ / ; ; T G Z N b v j g d p B 6 ",
+"O ! ; T G Z N b x j g a i u z 6 ",
+"o Q R P P L K J H D S C B z l 5 ",
+"X . y y e e e 0 9 9 8 8 6 6 5 6 ",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t."
+};
diff --git a/src/images/flags/DE.xpm b/src/images/flags/DE.xpm
new file mode 100644
index 0000000..0fe5bcf
--- /dev/null
+++ b/src/images/flags/DE.xpm
@@ -0,0 +1,183 @@
+/* XPM */
+static const char *DE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 161 2",
+" c black",
+". c #3F3F3F3F2F2F",
+"X c #3F3F3F3F3131",
+"o c #3E3E3D3D3D3D",
+"O c #656536363535",
+"+ c #6C6C3C3C3C3C",
+"@ c #404041413636",
+"# c #464646463A3A",
+"$ c #474747473A3A",
+"% c #4C4C47473838",
+"& c #494949493C3C",
+"* c #4C4C49493A3A",
+"= c #4C4C4A4A3C3C",
+"- c #666649493C3C",
+"; c gray27",
+": c #4C4C4C4C4343",
+"> c gray30",
+", c gray33",
+"< c #5B5B5B5B5B5B",
+"1 c #717145454444",
+"2 c #78784C4C4B4B",
+"3 c #7E7E53535353",
+"4 c #626262626262",
+"5 c #696968686969",
+"6 c #6F6F6F6F6F6F",
+"7 c gray46",
+"8 c gray48",
+"9 c #7E7E7E7E7E7E",
+"0 c #9D9D3F3F2F2F",
+"q c #A5A53F3F2F2F",
+"w c #A8A83F3F2F2F",
+"e c #A9A93F3F2F2F",
+"r c #BCBC3F3F2F2F",
+"t c #BDBD3F3F2F2F",
+"y c #939373732F2F",
+"u c #9D9D79792F2F",
+"i c #9E9E7C7C2F2F",
+"p c #BEBE44443535",
+"a c #A1A176762F2F",
+"s c #A1A179792F2F",
+"d c #A0A07F7F2F2F",
+"f c #A3A37E7E2F2F",
+"g c #AAAA7F7F2F2F",
+"h c #ACAC7F7F2F2F",
+"j c #B7B779792F2F",
+"k c #83835B5B5B5B",
+"l c #898961616161",
+"z c #8E8E68686868",
+"x c #93936F6F6F6F",
+"c c #979774747474",
+"v c #9B9B7A7A7A7A",
+"b c #9F9F7E7E7E7E",
+"n c #EAEA1E1E1E1E",
+"m c #EBEB24242424",
+"M c #ECEC24242525",
+"N c #EEEE2C2C2B2B",
+"B c #EEEE2C2C2C2C",
+"V c #EEEE2D2D2D2D",
+"C c #EFEF32323232",
+"Z c #EFEF33333333",
+"A c #F0F033333535",
+"S c #F1F13B3B3B3B",
+"D c #F1F13C3C3C3C",
+"F c #F2F242424242",
+"G c #F3F343434343",
+"H c #F3F344444444",
+"J c #F4F449494949",
+"K c #F4F44A4A4A4A",
+"L c #F4F44B4B4B4B",
+"P c #F6F651515151",
+"I c #F6F652525252",
+"U c #F6F652525353",
+"Y c #F7F759595959",
+"T c #F8F85A5A5A5A",
+"R c #F9F95F5F5F5F",
+"E c #F9F960606060",
+"W c #F9F961616161",
+"Q c #FAFA66666666",
+"! c #FAFA68686868",
+"~ c #FBFB6D6D6D6D",
+"^ c #FBFB6D6D6E6E",
+"/ c #FBFB6E6E6E6E",
+"( c #F1F17C7C6B6B",
+") c #F2F27F7F7070",
+"_ c #FCFC73737373",
+"` c #FDFD79797979",
+"' c #9B9B84842F2F",
+"] c #A3A385852F2F",
+"[ c #A9A982822F2F",
+"{ c #ABAB85852F2F",
+"} c #A9A98D8D2F2F",
+"| c #AEAE8E8E2F2F",
+" . c #B4B485852F2F",
+".. c #B3B388882F2F",
+"X. c #B6B68B8B2F2F",
+"o. c #B6B6A1A12F2F",
+"O. c #B6B6A7A72F2F",
+"+. c #8D8D8D8D7F7F",
+"@. c #A5A589897A7A",
+"#. c #E8E882821D1D",
+"$. c #EAEA87872424",
+"%. c #EBEB8B8B2A2A",
+"&. c #EEEE90903232",
+"*. c #EFEF94943939",
+"=. c #F1F199994141",
+"-. c #F2F29D9D4747",
+";. c #F3F384847676",
+":. c #F4F4A2A24F4F",
+">. c #F5F5A5A55656",
+",. c #F7F7AAAA5D5D",
+"<. c #F9F9AFAF6464",
+"1. c #F0F0B6B66C6C",
+"2. c #FAFAB2B26B6B",
+"3. c #E6E6CDCD1D1D",
+"4. c #E8E8CFCF2222",
+"5. c #E9E9D1D12929",
+"6. c #EBEBD4D42F2F",
+"7. c #EDEDD7D73737",
+"8. c #EFEFD9D93D3D",
+"9. c #F1F1DBDB4545",
+"0. c #F2F2DDDD4B4B",
+"q. c #EFEFDADA6969",
+"w. c #EFEFDBDB6B6B",
+"e. c #F0F0DCDC6F6F",
+"r. c #F1F1DDDD7373",
+"t. c #F2F2DEDE7676",
+"y. c #F4F4E0E05353",
+"u. c #F5F5E2E25A5A",
+"i. c #EFEFE0E06D6D",
+"p. c #F7F7E4E46161",
+"a. c #F9F9E6E66868",
+"s. c #F3F3E0E07A7A",
+"d. c #F4F4E2E27F7F",
+"f. c #828283838383",
+"g. c #919191918484",
+"h. c #969696968989",
+"j. c #9A9A9A9A8E8E",
+"k. c #9E9E9D9D9292",
+"l. c #A2A2A2A29797",
+"z. c #A6A6A6A69B9B",
+"x. c #AAAAAAAA9F9F",
+"c. c #ADADADADA3A3",
+"v. c #B0B0B0B0A7A7",
+"b. c #B3B3B3B3A9A9",
+"n. c #B6B6B6B6ADAD",
+"m. c #B8B8B8B8AFAF",
+"M. c #BABABABAB1B1",
+"N. c #CACAB8B8AFAF",
+"B. c #FCFCAFAFA5A5",
+"V. c #FCFCB2B2A9A9",
+"C. c #FDFDB5B5ACAC",
+"Z. c #FCFCD5D5A4A4",
+"A. c #F5F5E4E48282",
+"S. c #F5F5E5E58787",
+"D. c #F7F7E7E78B8B",
+"F. c #F8F8E9E99191",
+"G. c #F9F9EBEB9494",
+"H. c #F9F9EBEB9A9A",
+"J. c #FAFAEDED9D9D",
+"K. c #FBFBF1F1A2A2",
+"L. c None",
+/* pixels */
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+": * % = $ @ X . . . . . . . . . ",
+"$ M.M.m.n.b.v.c.x.z.l.k.j.h.g.. ",
+"& M.f.9 8 7 6 5 4 < , > ; o +.. ",
+"- N.b v c x z l k 3 2 1 + O @.. ",
+"p C.` _ / ! W T U L H D A V ;.e ",
+"t V._ ^ Q R Y U L G D C N m ;.e ",
+"t B.^ ! R Y P L G S C N m n ( q ",
+"j Z.2.<.,.>.:.-.*.*.&.%.$.#.1.0 ",
+"O.K.a.u.u.y.0.9.9.7.6.5.4.3.w.' ",
+"o.J.H.G.F.D.S.A.d.s.s.r.w.w.w.u ",
+"| X. .X.h [ } { [ ] f i f a a y ",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L."
+};
diff --git a/src/images/flags/DJ.xpm b/src/images/flags/DJ.xpm
new file mode 100644
index 0000000..40b8321
--- /dev/null
+++ b/src/images/flags/DJ.xpm
@@ -0,0 +1,177 @@
+/* XPM */
+static const char *DJ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 155 2",
+" c black",
+". c #00003939E7E7",
+"X c #000049498181",
+"o c #00004545E7E7",
+"O c #00004B4BE9E9",
+"+ c #00004D4DEBEB",
+"@ c #13135D5DEFEF",
+"# c #19196161EFEF",
+"$ c #19196363F1F1",
+"% c #21216767F3F3",
+"& c #27276D6DF5F5",
+"* c #2D2D7171F7F7",
+"= c #35357575F9F9",
+"- c #39397979FBFB",
+"; c #3F3F7D7DFDFD",
+": c #000081810000",
+"> c #000083830000",
+", c #000087870000",
+"< c #000089890000",
+"1 c #00008B8B0000",
+"2 c #00008F8F0000",
+"3 c #000091910000",
+"4 c #000093930000",
+"5 c #000099990000",
+"6 c #00009D9D0000",
+"7 c #00009F9F0000",
+"8 c #0000A3A30000",
+"9 c #0000A5A50000",
+"0 c #0000A7A70000",
+"q c #0000B5B50000",
+"w c #0B0BC2C20B0B",
+"e c #0F0FC4C40E0E",
+"r c #1010C4C41010",
+"t c #1313C6C61313",
+"y c #1414C6C61414",
+"u c #1414CACA1414",
+"i c #1818C7C71919",
+"p c #1919C8C81919",
+"a c #1919CBCB1919",
+"s c #1E1EC9C91E1E",
+"d c #1F1FC9C91F1F",
+"f c #1F1FCDCD1F1F",
+"g c #2323CBCB2323",
+"h c #2424CBCB2424",
+"j c #2424CFCF2424",
+"k c #2929CDCD2929",
+"l c #2A2ACDCD2A2A",
+"z c #2C2CCACA2C2C",
+"x c #2F2FCACA2F2F",
+"c c #2F2FCBCB2F2F",
+"v c #2E2ECFCF2E2E",
+"b c #2F2FCECE2F2F",
+"n c #2A2AD1D12A2A",
+"m c #2F2FD2D22F2F",
+"M c #3232CCCC3232",
+"N c #3333CCCC3232",
+"B c #3535CDCD3535",
+"V c #3434CECE3434",
+"C c #3434CFCF3434",
+"Z c #3939CFCF3939",
+"A c #3636D1D13636",
+"S c #3D3DD0D03D3D",
+"D c #4242D2D24242",
+"F c #4646D3D34646",
+"G c #4848D6D64444",
+"H c #4B4BD5D54B4B",
+"J c #4B4BD6D64B4B",
+"K c #5050D7D75050",
+"L c #5454D8D85555",
+"P c #5858D8D85858",
+"I c #7474DEDE7474",
+"U c #43438181FDFD",
+"Y c #43438181FFFF",
+"T c #45458383FDFD",
+"R c #4B4B8787FDFD",
+"E c #4B4B8787FFFF",
+"W c #5B5B9393FFFF",
+"Q c #5D5DA6A6C0C0",
+"! c #7B7B9C9CF4F4",
+"~ c #7F7F9F9FF5F5",
+"^ c #6161A9A9C2C2",
+"/ c #6565ACACC4C4",
+"( c #6969AEAEC6C6",
+") c #6D6DB1B1C9C9",
+"_ c #7171B3B3CBCB",
+"` c #7474B3B3C9C9",
+"' c #7A7AA2A2F5F5",
+"] c #7C7CA5A5F6F6",
+"[ c #7E7EA6A6F6F6",
+"{ c #FDFD6E6E6E6E",
+"} c #8282A2A2F6F6",
+"| c #8686A5A5F7F7",
+" . c #8080A8A8F7F7",
+".. c #8181A9A9F7F7",
+"X. c #8484ABABF8F8",
+"o. c #8D8DA9A9F5F5",
+"O. c #8C8CAFAFF6F6",
+"+. c #8A8AA8A8F8F8",
+"@. c #8B8BAAAAF9F9",
+"#. c #8888AEAEF9F9",
+"$. c #8F8FB2B2F7F7",
+"%. c #8B8BB0B0FAFA",
+"&. c #8B8BB1B1FAFA",
+"*. c #8C8CB2B2FBFB",
+"=. c #8F8FB3B3FBFB",
+"-. c #8C8CB2B2FCFC",
+";. c #9393B4B4F7F7",
+":. c #9292B6B6FCFC",
+">. c #9393B7B7FDFD",
+",. c #9595B3B3FAFA",
+"<. c #9696B7B7F8F8",
+"1. c #9595B7B7FDFD",
+"2. c #9999B9B9F9F9",
+"3. c #9B9BBBBBFAFA",
+"4. c #9E9EBEBEFBFB",
+"5. c #A0A0BFBFFEFE",
+"6. c #8D8DDFDF8D8D",
+"7. c #9595E7E79696",
+"8. c #ABABEAEAABAB",
+"9. c #B7B7ECECB7B7",
+"0. c #A1A1C0C0FCFC",
+"q. c #A4A4C2C2FCFC",
+"w. c #A7A7C3C3FDFD",
+"e. c #A9A9C5C5FEFE",
+"r. c #ABABC7C7FEFE",
+"t. c #AFAFC9C9FDFD",
+"y. c #BFBFE3E3D6D6",
+"u. c #FCFCA9A9A9A9",
+"i. c #FCFCB2B2B2B2",
+"p. c #FEFEB7B7B7B7",
+"a. c #C3C3D7D7FFFF",
+"s. c #C9C9DADAFBFB",
+"d. c #C8C8DADAFFFF",
+"f. c #DDDDF4F4DDDD",
+"g. c #D6D6E4E4FEFE",
+"h. c #FEFECACACACA",
+"j. c #E9E9F7F7E9E9",
+"k. c #EAEAF1F1FDFD",
+"l. c gray97",
+"z. c #F3F3F7F7FFFF",
+"x. c #FBFBF1F1F1F1",
+"c. c #FDFDF3F3F3F3",
+"v. c #F9F9F9F9F9F9",
+"b. c #F9F9FAFAF9F9",
+"n. c gray98",
+"m. c #FBFBFBFBFBFB",
+"M. c #FAFAFAFAFCFC",
+"N. c gray99",
+"B. c #FDFDFCFCFCFC",
+"V. c #FDFDFCFCFDFD",
+"C. c #FDFDFDFDFDFD",
+"Z. c #FEFEFDFDFDFD",
+"A. c #FEFEFEFEFEFE",
+"S. c gray100",
+"D. c None",
+/* pixels */
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"a.W Y E E T Y ; - = * & % $ @ # ",
+"S.z.a.r.r.r.r.w.w.5.4.3.2.<.;.+ ",
+"S.S.S.g.5.:.1.:.=.&.#.X...[ $.O ",
+"S.S.S.S.k.t.*.*.&.X.X.[ [ ' O.o ",
+"S.S.i.c.S.v.s.,. at .@.| } ~ ! o.. ",
+"N.h.{ u.m.l.k.f._ ) ( / ^ Q ` X ",
+"S.N.i.x.m.l.8.G m n j f a u A 4 ",
+"m.m.m.m.f.I N b l h s i y r N < ",
+"l.N.m.9.J N v l g s i t e w c , ",
+"l.j.7.P L K H F D S Z B N c z : ",
+"6.q 0 0 8 8 6 5 4 2 2 1 , , : < ",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D."
+};
diff --git a/src/images/flags/DK.xpm b/src/images/flags/DK.xpm
new file mode 100644
index 0000000..fa76907
--- /dev/null
+++ b/src/images/flags/DK.xpm
@@ -0,0 +1,146 @@
+/* XPM */
+static const char *DK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 124 2",
+" c black",
+". c #C5C500000000",
+"X c #C7C700000000",
+"o c #C9C900000000",
+"O c #CBCB00000000",
+"+ c #CDCD00000000",
+"@ c #CFCF00000000",
+"# c #D1D100000000",
+"$ c #D5D500000000",
+"% c #D7D700000000",
+"& c #DBDB00000000",
+"* c #DFDF00000000",
+"= c #E1E100000000",
+"- c #E3E300000000",
+"; c #E5E500000000",
+": c #E7E700000000",
+"> c #E4E40B0B0B0B",
+", c #E4E40F0F0E0E",
+"< c #E9E900000000",
+"1 c #EBEB00000000",
+"2 c #EDED00000000",
+"3 c #EFEF00000000",
+"4 c #E4E410101010",
+"5 c #E6E613131313",
+"6 c #E5E514141414",
+"7 c #E6E619191919",
+"8 c #E7E719191919",
+"9 c #E8E81E1E1E1E",
+"0 c #E8E81F1F1F1F",
+"q c #F1F100000000",
+"w c #E6E62C2C2C2C",
+"e c #E9E920202020",
+"r c #EAEA23232323",
+"t c #E9E924242424",
+"y c #E9E926262626",
+"u c #EAEA25252525",
+"i c #EAEA2A2A2A2A",
+"p c #EAEA2B2B2B2B",
+"a c #EBEB2B2B2B2B",
+"s c #E8E82F2F2F2F",
+"d c #EBEB2C2C2C2C",
+"f c #E8E832323232",
+"g c #E8E835353535",
+"h c #ECEC30303030",
+"j c #ECEC31313131",
+"k c #EDED31313131",
+"l c #EDED37373636",
+"z c #EEEE36363636",
+"x c #EEEE37373737",
+"c c #ECEC37373838",
+"v c #EAEA39393939",
+"b c #EBEB3D3D3D3D",
+"n c #EBEB3F3F3F3F",
+"m c #EFEF3A3A3A3A",
+"M c #EFEF3B3B3C3C",
+"N c #EEEE3C3C3C3C",
+"B c #EFEF3C3C3D3D",
+"V c #EFEF3F3F3F3F",
+"C c #ECEC42424242",
+"Z c #EFEF41414242",
+"A c #ECEC44444444",
+"S c #EDED49494949",
+"D c #EEEE4E4E4E4E",
+"F c #F0F041414141",
+"G c #F0F042424242",
+"H c #F0F044444444",
+"J c #F0F045454545",
+"K c #F1F147474747",
+"L c #F1F149494949",
+"P c #F1F14E4E4E4E",
+"I c #F3F34F4F5050",
+"U c #F0F053535353",
+"Y c #F3F353535454",
+"T c #F0F054545555",
+"R c #F1F157575757",
+"E c #F3F354545454",
+"W c #F1F158585858",
+"Q c #F2F25C5C5C5C",
+"! c #F2F25D5D5D5D",
+"~ c #F4F458585858",
+"^ c #F4F459595959",
+"/ c #F5F55C5C5C5C",
+"( c #F5F55F5F5F5F",
+") c #F2F260606060",
+"_ c #F2F261616262",
+"` c #F3F365656565",
+"' c #F3F366666666",
+"] c #F4F469696969",
+"[ c #F4F46A6A6A6A",
+"{ c #F6F674747373",
+"} c #F7F776767676",
+"| c #F7F777777777",
+" . c #F7F779797979",
+".. c #F7F77B7B7A7A",
+"X. c #F7F77B7B7B7B",
+"o. c #E9E9CFCFCFCF",
+"O. c gray89",
+"+. c gray90",
+"@. c gray93",
+"#. c #F7F7E9E9E9E9",
+"$. c #F7F7ECECECEC",
+"%. c #FBFBE7E7E7E7",
+"&. c #F8F8EAEAEAEA",
+"*. c gray95",
+"=. c #F3F3F3F3F3F3",
+"-. c #F4F4F4F4F4F4",
+";. c #F4F4F5F5F5F5",
+":. c gray96",
+">. c #F6F6F6F6F6F6",
+",. c gray97",
+"<. c #FBFBF0F0F0F0",
+"1. c #FAFAF2F2F2F2",
+"2. c #FCFCF1F1F1F1",
+"3. c #FDFDF4F4F4F4",
+"4. c #F8F8F8F8F8F8",
+"5. c #F9F9F9F9F9F9",
+"6. c #FAFAF9F9F9F9",
+"7. c gray98",
+"8. c #FBFBFBFBFBFB",
+"9. c #FBFBFCFCFBFB",
+"0. c gray99",
+"q. c #FDFDFDFDFDFD",
+"w. c #FEFEFEFEFEFE",
+"e. c None",
+/* pixels */
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"q 3 3 3 3 q.%.3 < : : = = * & & ",
+"3 X.X.X.} q.3.{ ] ' ( Q R Y D $ ",
+"3 X./ / / q.2.E A Z N l k d S $ ",
+"3 X./ / Y q.$.P H N l k p y A @ ",
+"< } ~ Y P 8.3.F M l k p y 0 n @ ",
+"q.q.q.q.8.8.6.6.6.,.>.>.=.=.>.+.",
+"q.q.q.q.8.6.6.6.,.>.>.-.*.*.=.O.",
+"< [ L A Z 6.#.c p u 0 8 6 5 f X ",
+"< ' A N m ,.#.k 0 e 8 5 , > w X ",
+": _ ! W R ,.$.D C n v g f w w X ",
+": * * & $ @.o.$ @ @ @ X X X X X ",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e."
+};
diff --git a/src/images/flags/DM.xpm b/src/images/flags/DM.xpm
new file mode 100644
index 0000000..b1d3f33
--- /dev/null
+++ b/src/images/flags/DM.xpm
@@ -0,0 +1,170 @@
+/* XPM */
+static const char *DM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 148 2",
+" c black",
+". c #000029290000",
+"X c #00002D2D0000",
+"o c #00002F2F0000",
+"O c #000031310000",
+"+ c #000033330000",
+"@ c #000039390000",
+"# c #282827272020",
+"$ c #2E2E2D2D2626",
+"% c #000045450000",
+"& c #00004B4B0000",
+"* c #00004D4D0000",
+"= c #000051510000",
+"- c #000057570000",
+"; c #00005D5D0000",
+": c #000063630000",
+"> c #000067670000",
+", c #00006D6D0000",
+"< c #000071710000",
+"1 c #000077770000",
+"2 c #00007B7B0000",
+"3 c #474746464040",
+"4 c #4E4E4D4D4646",
+"5 c #565655554F4F",
+"6 c #5A5A5A5A5454",
+"7 c #5F5F5E5E5858",
+"8 c #737373736D6D",
+"9 c #7C7C7B7B7676",
+"0 c #000081810000",
+"q c #000083830000",
+"w c #000087870000",
+"e c #000089890000",
+"r c #18189A9A1919",
+"t c #1C1C9C9C1C1C",
+"y c #1D1D9C9C1D1D",
+"u c #21219F9F2121",
+"i c #3232A8A83232",
+"p c #3737AAAA3737",
+"a c #3838A7A73838",
+"s c #3838AAAA3838",
+"d c #3A3AA8A83A3A",
+"f c #3B3BA9A93B3B",
+"g c #3D3DA9A93D3D",
+"h c #3E3EAAAA3E3E",
+"j c #3D3DAEAE3D3D",
+"k c #3C3CD5D55353",
+"l c #7272B4B42727",
+"z c #7474B3B32727",
+"x c #7676B8B83C3C",
+"c c #4040ACAC4040",
+"v c #4040AEAE4040",
+"b c #4545AEAE4444",
+"n c #4242B0B04242",
+"m c #4545B1B14545",
+"M c #4A4AB3B34A4A",
+"N c #4B4BB4B44A4A",
+"B c #4F4FB3B34F4F",
+"V c #4E4EB6B64E4E",
+"C c #4F4FB6B64F4F",
+"Z c #5353B6B65353",
+"A c #5555B6B65555",
+"S c #5454B9B95454",
+"D c #5858B9B95858",
+"F c #5A5AB9B95A5A",
+"G c #5C5CBBBB5C5C",
+"H c #5E5EBBBB5E5E",
+"J c #5E5EBEBE5E5E",
+"K c #6060BDBD5B5B",
+"L c #6161BDBD6060",
+"P c #6262BEBE6262",
+"I c #6262BFBF6262",
+"U c #6565BFBF6565",
+"Y c #6666BFBF6666",
+"T c #5757C0C02A2A",
+"R c #5151CFCF3939",
+"E c #7F7FCDCD5050",
+"W c #6565C1C16666",
+"Q c #6666C1C16666",
+"! c #6868C3C36969",
+"~ c #6A6AC1C16A6A",
+"^ c #6A6AC2C26A6A",
+"/ c #6F6FC3C36F6F",
+"( c #7373C6C67373",
+") c #7979C8C87A7A",
+"_ c #7B7BCACA7B7B",
+"` c #7F7FCBCB7F7F",
+"' c #3636A3A3E4E4",
+"] c #58589E9EDDDD",
+"[ c #4242A8A8E9E9",
+"{ c #9F9F6D6D2222",
+"} c #A9A97B7B3737",
+"| c #ABAB7E7E3939",
+" . c #DDDD62621F1F",
+".. c #E0E056563232",
+"X. c #E0E056563434",
+"o. c #EFEF66662B2B",
+"O. c #EAEA6B6B3030",
+"+. c #E4E471713535",
+"@. c #E7E773733737",
+"#. c #F1F16D6D2A2A",
+"$. c #F3F36F6F3131",
+"%. c #F3F371713636",
+"&. c #F3F377773535",
+"*. c #E8E86E6E5555",
+"=. c #E8E870705353",
+"-. c #F1F16B6B4242",
+";. c #F1F16C6C4444",
+":. c #F4F473734040",
+">. c #9191B4B42F2F",
+",. c #9999BABA3D3D",
+"<. c #AFAF83834242",
+"1. c #B0B085854545",
+"2. c #BABA92925858",
+"3. c #9797CBCB4646",
+"4. c #E7E7BBBB0000",
+"5. c #E9E9BFBF0000",
+"6. c #EAEA82824C4C",
+"7. c #F9F989895353",
+"8. c #F8F888885454",
+"9. c #F6F683836262",
+"0. c #F7F784846262",
+"q. c #FDFDDBDB0000",
+"w. c #FDFDE1E10000",
+"e. c #F7F7E1E13434",
+"r. c #F4F4E1E13B3B",
+"t. c #E0E0FAFA4C4C",
+"y. c #F5F5E2E24141",
+"u. c #F5F5E4E45757",
+"i. c #F7F7E6E65E5E",
+"p. c #FDFDECEC6666",
+"a. c #FDFDEDED6A6A",
+"s. c #FEFEEEEE6D6D",
+"d. c #FDFDEFEF7F7F",
+"f. c #8080CDCD8080",
+"g. c #8383CDCD8383",
+"h. c #FEFEF2F28787",
+"j. c gray89",
+"k. c gray90",
+"l. c gray95",
+"z. c #F3F3F3F3F3F3",
+"x. c #F4F4F4F4F4F4",
+"c. c gray96",
+"v. c #F9F9F9F9F9F9",
+"b. c #FBFBFBFBFBFB",
+"n. c #FBFBFCFCFBFB",
+"m. c gray99",
+"M. c #FDFDFDFDFDFD",
+"N. c None",
+/* pixels */
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"e e e e e 0 0 q. v.< , > : ; - ",
+"e g.g.f.` _ _ d.8 m.~ U L G D = ",
+"e g.! W I J 2.8.*.9.1.n j s Z & ",
+"w g.W I J 2.6.E [ K @.| p i B % ",
+"w.h.a.a.p.7.3.t.k ' x %.y.r.u.4.",
+" 9 7 6 5 *.:.] R O.o.X.$ # 3 ",
+"m.m.m.m.b.9.,.&.e.T z ;.z.z.z.j.",
+"2 ( S V N <. at .>.#.l .{ u y h O ",
+"2 / V N m v } $...-.{ u y r s X ",
+"< ~ U L L F A i.4 z.b v h s a . ",
+", > : ; - = * 5. k.@ O X X . . ",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N."
+};
diff --git a/src/images/flags/DO.xpm b/src/images/flags/DO.xpm
new file mode 100644
index 0000000..1ba42ac
--- /dev/null
+++ b/src/images/flags/DO.xpm
@@ -0,0 +1,161 @@
+/* XPM */
+static const char * DO_xpm[] = {
+"16 16 142 2",
+" c None",
+". c #0329A3",
+"+ c #0025A1",
+"@ c #001F9F",
+"# c #001D9D",
+"$ c #EDF3FD",
+"% c #FBEFED",
+"& c #D90000",
+"* c #D70000",
+"= c #D50000",
+"- c #D10000",
+"; c #CF0000",
+"> c #CB0000",
+", c #C90000",
+"' c #95A5D8",
+") c #94A5D8",
+"! c #93A4D8",
+"~ c #91A1D7",
+"{ c #8F9FD6",
+"] c #8B9DD4",
+"^ c #F7F9FD",
+"/ c #FCF7F7",
+"( c #EE6565",
+"_ c #ED6060",
+": c #EC5C5C",
+"< c #EB5757",
+"[ c #E95353",
+"} c #E84E4E",
+"| c #C50000",
+"1 c #94A4D8",
+"2 c #7E92D0",
+"3 c #7B8FCF",
+"4 c #798DCE",
+"5 c #758ACC",
+"6 c #7287CB",
+"7 c #F4F8FC",
+"8 c #FBF5F4",
+"9 c #E94242",
+"0 c #E83C3D",
+"a c #E73737",
+"b c #E53131",
+"c c #E42C2C",
+"d c #E74949",
+"e c #C30000",
+"f c #0027A3",
+"g c #93A3D8",
+"h c #788DCE",
+"i c #7187CB",
+"j c #6D83C9",
+"k c #F2F7FB",
+"l c #FAF4F2",
+"m c #E83C3C",
+"n c #E73736",
+"o c #E42B2B",
+"p c #E22626",
+"q c #E64444",
+"r c #BF0000",
+"s c #0023A1",
+"t c #8FA1D7",
+"u c #7186CA",
+"v c #697FC7",
+"w c #F6F8FA",
+"x c #F9F6F5",
+"y c #E73636",
+"z c #E53030",
+"A c #E32B2B",
+"B c #E22525",
+"C c #E12020",
+"D c #E43F3F",
+"E c #BB0000",
+"F c #FDFDFD",
+"G c #FEFEFE",
+"H c #FCFCFC",
+"I c #FBFBFB",
+"J c #FAFAFA",
+"K c #F9F9F9",
+"L c #F8F8F8",
+"M c #F7F7F7",
+"N c #F6F6F6",
+"O c #F5F5F5",
+"P c #F4F4F4",
+"Q c #F3F3F3",
+"R c #F4F5F5",
+"S c #E5E5E5",
+"T c #DD0000",
+"U c #F06F6F",
+"V c #EC4F4F",
+"W c #EB4A49",
+"X c #EA4545",
+"Y c #E84040",
+"Z c #E73B3A",
+"` c #F8F4F3",
+" . c #F5F6F7",
+".. c #516BBB",
+"+. c #4D67B9",
+"@. c #4863B6",
+"#. c #445FB4",
+"$. c #3F5BB2",
+"%. c #5B72BD",
+"&. c #00005D",
+"*. c #DB0000",
+"=. c #EF6A6A",
+"-. c #EB4949",
+";. c #E83F3F",
+">. c #E73A3A",
+",. c #E63434",
+"'. c #F7EDEB",
+"). c #EFF3F6",
+"!. c #435FB4",
+"~. c #3B57AF",
+"{. c #586FBB",
+"]. c #000059",
+"^. c #EE6666",
+"/. c #EA4444",
+"(. c #E42E2E",
+"_. c #F6ECEA",
+":. c #EDF2F5",
+"<. c #4762B6",
+"[. c #435EB4",
+"}. c #3E5AB2",
+"|. c #3A57AF",
+"1. c #3654AE",
+"2. c #556DB9",
+"3. c #000055",
+"4. c #ED6162",
+"5. c #EC5D5D",
+"6. c #EB5858",
+"7. c #EA5455",
+"8. c #E85050",
+"9. c #E74B4B",
+"0. c #F7EEED",
+"a. c #6078C0",
+"b. c #5D75BE",
+"c. c #5A72BC",
+"d. c #566FBB",
+"e. c #546DB9",
+"f. c #516AB8",
+"g. c #000053",
+"h. c #E9D5D1",
+"i. c #D9DFE7",
+"j. c #000063",
+"k. c #00005F",
+" ",
+" ",
+". . . . + @ # $ % & * = - ; > , ",
+". ' ) ! ~ { ] ^ / ( _ : < [ } | ",
+". 1 2 3 4 5 6 7 8 9 0 a b c d e ",
+"f g 3 h 5 i j k l m n b o p q r ",
+"s t h 5 u j v w x y z A B C D E ",
+"F G F H H I J K L M N O P Q R S ",
+"T U V W X Y Z ` ...+. at .#.$.%.&.",
+"*.=.-.X ;.>.,.'.).+. at .!.$.~.{.].",
+"& ^./.;.>.,.(._.:.<.[.}.|.1.2.3.",
+"* 4.5.6.7.8.9.0.).a.b.c.d.e.f.g.",
+"= - ; > , | e h.i.j.k.&.].3.g.g.",
+" ",
+" ",
+" "};
diff --git a/src/images/flags/DZ.xpm b/src/images/flags/DZ.xpm
new file mode 100644
index 0000000..173e43b
--- /dev/null
+++ b/src/images/flags/DZ.xpm
@@ -0,0 +1,160 @@
+/* XPM */
+static const char *DZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 138 2",
+" c black",
+". c #000005050000",
+"X c #00000B0B0000",
+"o c #000011110000",
+"O c #00001B1B0000",
+"+ c #000023230000",
+"@ c #00002D2D0000",
+"# c #000035350000",
+"$ c #000047470909",
+"% c #00004B4B1111",
+"& c #00004F4F1717",
+"* c #000057572121",
+"= c #00005F5F2B2B",
+"- c #010165653333",
+"; c #030365653535",
+": c #030367673737",
+"> c #09096B6B3939",
+", c #0B0B6D6D3D3D",
+"< c #0D0D6F6F3D3D",
+"1 c #11116F6F3F3F",
+"2 c #111171714141",
+"3 c #212179794D4D",
+"4 c #727270705656",
+"5 c #3E3E85856060",
+"6 c #45458E8E6969",
+"7 c #4C4C91916E6E",
+"8 c #535395957474",
+"9 c #545491917070",
+"0 c #555595957474",
+"q c #545497977575",
+"w c #54549C9C7A7A",
+"e c #5A5A9A9A7A7A",
+"r c #5B5B9A9A7B7B",
+"t c #5B5B9E9E7D7D",
+"y c #66669A9A7C7C",
+"u c #757585856969",
+"i c #4E4EA2A28080",
+"p c #61619E9E8080",
+"a c #61619F9F8080",
+"s c #62629E9E8080",
+"d c #6262A1A18282",
+"f c #6767A3A38585",
+"g c #6868A3A38585",
+"h c #6868A4A48686",
+"j c #6A6AA4A48686",
+"k c #6969A7A78888",
+"l c #6E6EA6A68A8A",
+"z c #6E6EA7A78A8A",
+"x c #6F6FA7A78B8B",
+"c c #6F6FA8A88C8C",
+"v c #6F6FA9A98C8C",
+"b c #7474AAAA8F8F",
+"n c #7373ABAB9090",
+"m c #7474ABAB9090",
+"M c #7575ABAB9090",
+"N c #7979AEAE9494",
+"B c #7A7AAEAE9494",
+"V c #7D7DB1B19797",
+"C c #7F7FB2B29999",
+"Z c #B9B96D6D6060",
+"A c #DBDB51514444",
+"S c #DDDD55554A4A",
+"D c #D6D65A5A5050",
+"F c #DFDF55555050",
+"G c #CECE6E6E6161",
+"H c #D1D17B7B6F6F",
+"J c #DDDD77776D6D",
+"K c #E0E058584D4D",
+"L c #E1E15E5E5252",
+"P c #E5E570706666",
+"I c #E6E671716666",
+"U c #E7E771716666",
+"Y c #E3E374746C6C",
+"T c #E6E67B7B7474",
+"R c #8D8D95958080",
+"E c #8C8C9B9B8282",
+"W c #8585B5B59D9D",
+"Q c #8787B5B59E9E",
+"! c #8585B9B9A1A1",
+"~ c #8A8AB8B8A1A1",
+"^ c #8B8BB9B9A2A2",
+"/ c #8E8EBBBBA4A4",
+"( c #8F8FBCBCA5A5",
+") c #9292BEBEA8A8",
+"_ c #9494BFBFA9A9",
+"` c #9494BFBFAAAA",
+"' c #9595BFBFAAAA",
+"] c #BEBEC7C7C3C3",
+"[ c #E7E78C8C8484",
+"{ c #E7E790908A8A",
+"} c #EDEDB9B9B8B8",
+"| c gray79",
+" . c #CBCBCBCBCBCB",
+".. c #CECECECECECE",
+"X. c #D0D0D0D0D0D0",
+"o. c #D2D2D2D2D2D2",
+"O. c gray84",
+"+. c #D8D8D8D8D8D8",
+"@. c gray85",
+"#. c gray86",
+"$. c #DDDDDDDDDDDD",
+"%. c #E8E8CFCFCCCC",
+"&. c #EAEAD9D9D7D7",
+"*. c #F5F5CBCBCBCB",
+"=. c #F1F1D3D3D3D3",
+"-. c #F3F3D7D7D7D7",
+";. c #E1E1E1E1E1E1",
+":. c #E0E0E3E3E1E1",
+">. c gray89",
+",. c gray90",
+"<. c #E6E6E6E6E6E6",
+"1. c gray92",
+"2. c #ECECECECECEC",
+"3. c gray93",
+"4. c #EEEEEEEEEEEE",
+"5. c #EFEFEFEFEFEF",
+"6. c #EBEBF4F4F2F2",
+"7. c #F1F1ECECECEC",
+"8. c #F3F3ECECECEC",
+"9. c #F2F2EEEEEEEE",
+"0. c #F4F4E8E8E8E8",
+"q. c #F4F4EAEAEAEA",
+"w. c gray94",
+"e. c #F1F1F1F1F1F1",
+"r. c gray95",
+"t. c #F3F3F3F3F3F3",
+"y. c #F5F5F0F0F0F0",
+"u. c #F4F4F4F4F4F4",
+"i. c gray96",
+"p. c #F6F6F6F6F6F6",
+"a. c gray97",
+"s. c #F5F5FCFCFAFA",
+"d. c #F8F8F8F8F8F8",
+"f. c #F9F9F9F9F9F9",
+"g. c gray98",
+"h. c #FCFCFBFBFBFB",
+"j. c gray99",
+"k. c None",
+/* pixels */
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"3 2 2 2 , ; = ; :.<.<.<.>.;.$.#.",
+"< ' ` ) ( ^ Q ! s.j.g.g.g.a.a. at .",
+"2 ' V N M v j R =.8.e.4.4.4.p. at .",
+"1 ) N n v E J U { -.9.4.4.1.p.O.",
+"> / b z k H U y &.[ 9.4.4.1.p.o.",
+"- ^ l g d U Z i L K A e.e.4.e.o.",
+"= Q f s t G F 9 %.T 9.p.e.4.e...",
+"* V t r q u D S Y *.0.t.e.e.e. .",
+"& N r q 7 6 5 4 } 0.t.e.e.4.e. .",
+"$ b l g s r 0 w 6.e.p.e.e.e.5. .",
+"% # @ + O o . X ] o..... . .| .",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k."
+};
diff --git a/src/images/flags/EC.xpm b/src/images/flags/EC.xpm
new file mode 100644
index 0000000..fb6d17c
--- /dev/null
+++ b/src/images/flags/EC.xpm
@@ -0,0 +1,178 @@
+/* XPM */
+static const char *EC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 156 2",
+" c black",
+". c #000000004545",
+"X c #000000006565",
+"o c #000000006767",
+"O c #00002525A1A1",
+"+ c #00002D2DA3A3",
+"@ c #111153538989",
+"# c #24246363B5B5",
+"$ c #29296767B7B7",
+"% c #2D2D6A6AB9B9",
+"& c #2E2E6B6BBABA",
+"* c #31316E6EBCBC",
+"= c #32326F6FBCBC",
+"- c #37377272BDBD",
+"; c #37377272BEBE",
+": c #3C3C7676BFBF",
+"> c #44447A7ABFBF",
+", c #41417979C1C1",
+"< c #41417A7AC2C2",
+"1 c #47477D7DC1C1",
+"2 c #46467D7DC4C4",
+"3 c #54548080A4A4",
+"4 c #59598383A6A6",
+"5 c #5D5D8787A8A8",
+"6 c #60608B8BABAB",
+"7 c #65658E8EAEAE",
+"8 c #69699191B0B0",
+"9 c #6C6C9393B0B0",
+"0 c #6E6E9595B3B3",
+"q c #72729898B6B6",
+"w c #76769B9BB8B8",
+"e c #7A7A9E9EBABA",
+"r c #7D7DA0A0BDBD",
+"t c #4B4B8181C6C6",
+"y c #4C4C8181C6C6",
+"u c #50508484C8C8",
+"i c #51518585C8C8",
+"p c #55558888CACA",
+"a c #55558989CACA",
+"s c #5A5A8C8CCCCC",
+"d c #5F5F8F8FCECE",
+"f c #7878A1A1D6D6",
+"g c #7C7CA4A4D8D8",
+"h c #A5A500000000",
+"j c #C1C100000000",
+"k c #C3C300000000",
+"l c #C5C500000000",
+"z c #C7C700000000",
+"x c #CBCB00000000",
+"c c #CDCD00000000",
+"v c #CFCF00000000",
+"b c #D1D100000000",
+"n c #D3D300000000",
+"m c #D5D500000000",
+"M c #D7D700000000",
+"N c #D9D900000000",
+"B c #DBDB00000000",
+"V c #DDDD00000000",
+"C c #D3D31D1D1D1D",
+"Z c #D4D421212020",
+"A c #D5D525252525",
+"S c #D6D62A2A2A2A",
+"D c #D8D82F2F2F2F",
+"F c #DADA33333333",
+"G c #D8D83F3F3F3F",
+"H c #DCDC38383838",
+"J c #DDDD3E3E3E3E",
+"K c #E1E100000000",
+"L c #EFEF00000000",
+"P c #ECEC33332C2C",
+"I c #EDED35352F2F",
+"U c #EDED38383232",
+"Y c #EEEE3C3C3535",
+"T c #EFEF40403939",
+"R c #F0F043433D3D",
+"E c #DFDF43434343",
+"W c #E0E048484848",
+"Q c #E2E24D4D4D4D",
+"! c #E3E352525252",
+"~ c #F1F147474242",
+"^ c #F2F24C4C4646",
+"/ c #F2F250504B4B",
+"( c #F3F355555050",
+") c #F5F55A5A5555",
+"_ c #F6F65F5F5858",
+"` c #F7F763635D5D",
+"' c #E9E972727272",
+"] c #F7F767676262",
+"[ c #DFDFB1B10000",
+"{ c #E3E3B3B30000",
+"} c #E5E5B9B90000",
+"| c #E7E7BBBB0000",
+" . c #E9E9BFBF0000",
+".. c #EBEBC1C10000",
+"X. c #EDEDC5C50000",
+"o. c #EFEFC7C70000",
+"O. c #EFEFC9C90000",
+"+. c #F1F1CBCB0000",
+"@. c #F3F3CFCF0101",
+"#. c #F5F5D1D10707",
+"$. c #F7F7D1D10D0D",
+"%. c #FDFDDFDF0B0B",
+"&. c #F7F7D3D31111",
+"*. c #F9F9D5D51717",
+"=. c #F9F9D7D71515",
+"-. c #F9F9D5D51919",
+";. c #F9F9D7D71919",
+":. c #F9F9D9D92727",
+">. c #F4F4DEDE4949",
+",. c #F5F5DFDF4E4E",
+"<. c #F2F2DADA5454",
+"1. c #F3F3DBDB5959",
+"2. c #F4F4DDDD5D5D",
+"3. c #F4F4DEDE6262",
+"4. c #F5F5DFDF6262",
+"5. c #F5F5DFDF6666",
+"6. c #F6F6DFDF6767",
+"7. c #F3F3DEDE6C6C",
+"8. c #F6F6E1E15252",
+"9. c #F7F7E3E35757",
+"0. c #F8F8E4E45C5C",
+"q. c #F5F5E2E26262",
+"w. c #F6F6E1E16B6B",
+"e. c #F7F7E2E26F6F",
+"r. c #F9F9E6E66060",
+"t. c #FAFAE7E76565",
+"y. c #FBFBE8E86969",
+"u. c #FCFCE9E96D6D",
+"i. c #F4F4E0E07070",
+"p. c #F5F5E1E17575",
+"a. c #F6F6E2E27979",
+"s. c #F7F7E4E47B7B",
+"d. c #F7F7E5E57F7F",
+"f. c #F8F8E4E47373",
+"g. c #F9F9E5E57777",
+"h. c #FAFAE6E67B7B",
+"j. c #FAFAE7E77D7D",
+"k. c #FDFDEAEA7171",
+"l. c #FDFDEBEB7575",
+"z. c #FEFEECEC7878",
+"x. c #8181A3A3BEBE",
+"c. c #9797B4B4CACA",
+"v. c #F8F8E6E68383",
+"b. c #F8F8E7E78787",
+"n. c #FBFBE8E88080",
+"m. c #FCFCE9E98383",
+"M. c #F9F9E8E88A8A",
+"N. c #FAFAE9E98D8D",
+"B. c #FBFBEAEA9090",
+"V. c #FBFBEBEB9292",
+"C. c #FCFCECEC9595",
+"Z. c #FCFCEDED9696",
+"A. c #FCFCEDED9898",
+"S. c #FCFCEDED9999",
+"D. c #FEFEF0F08F8F",
+"F. c None",
+/* pixels */
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+":.;.;.;.=.&.$.#. at .+.+.o.X... . .",
+"=.S.S.Z.Z.V.V.N.b.b.v.d.s.a.p.} ",
+";.S.m.j.j.h.g.f.f.w.6.3.2.1.i.{ ",
+";.Z.m.h.h.g.f.e.6.6.3.2.1.<.7.[ ",
+"%.N.z.z.k.u.y.t.r.0.9.8.,.>.q.| ",
+"@ c.c.r e w q 0 8 7 5 5 4 3 0 . ",
+"+ f a s a i y 2 < : - * & $ 1 o ",
+"O f s a i t 2 , : - * % $ # > o ",
+"x ' ! Q E E J H F F S A Z C G h ",
+"L ] ` _ ) ( / ^ ~ R T Y U I P b ",
+"K V V M M M M x x x l x l j j j ",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F."
+};
diff --git a/src/images/flags/EE.xpm b/src/images/flags/EE.xpm
new file mode 100644
index 0000000..259f418
--- /dev/null
+++ b/src/images/flags/EE.xpm
@@ -0,0 +1,137 @@
+/* XPM */
+static const char *EE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 115 2",
+" c black",
+". c gray8",
+"X c #191919191919",
+"o c gray10",
+"O c gray12",
+"+ c #202020202020",
+"@ c gray14",
+"# c #252525252525",
+"$ c #2A2A2A2A2A2A",
+"% c #2A2A2B2B2B2B",
+"& c gray17",
+"* c #2F2F2F2F2F2F",
+"= c gray19",
+"- c #353535353535",
+"; c gray21",
+": c #3B3B3B3B3A3A",
+"> c gray23",
+", c #3B3B3B3B3C3C",
+"< c #3F3F3F3F3F3F",
+"1 c gray25",
+"2 c #414141414141",
+"3 c gray27",
+"4 c #464646464646",
+"5 c #49494A4A4949",
+"6 c #4B4B4A4A4B4B",
+"7 c #4B4B4B4B4B4B",
+"8 c gray31",
+"9 c #50504F4F5050",
+"0 c #535353535353",
+"q c gray33",
+"w c #585858585858",
+"e c #6F6F6F6F6F6F",
+"r c #727272727373",
+"t c #767676767676",
+"y c #000000009393",
+"u c #000000009797",
+"i c #000000009B9B",
+"p c #000000009F9F",
+"a c #00000505A3A3",
+"s c #00000D0DA5A5",
+"d c #00001313A9A9",
+"f c #00001919ADAD",
+"g c #00002121B1B1",
+"h c #00002727B3B3",
+"j c #00002D2DB5B5",
+"k c #00003333B9B9",
+"l c #00003737BBBB",
+"z c #00003B3BBDBD",
+"x c #00004141BFBF",
+"c c #00004343BFBF",
+"v c #26267A7ACCCC",
+"b c #2B2B7C7CCECE",
+"n c #2C2C7C7CCECE",
+"m c #31318080D0D0",
+"M c #31318181D0D0",
+"N c #37378484D1D1",
+"B c #37378484D2D2",
+"V c #3C3C8888D3D3",
+"C c #3D3D8888D4D4",
+"Z c #42428B8BD5D5",
+"A c #44448C8CD3D3",
+"S c #47478F8FD7D7",
+"D c #49498F8FD5D5",
+"F c #4E4E9393D7D7",
+"G c #4B4B9292D8D8",
+"H c #4C4C9292D8D8",
+"J c #51519595DADA",
+"K c #53539696D8D8",
+"L c #54549898DBDB",
+"P c #58589898D9D9",
+"I c #58589B9BDCDC",
+"U c #59599B9BDDDD",
+"Y c #5C5C9B9BDBDB",
+"T c #5C5C9D9DDEDE",
+"R c #5F5F9F9FDFDF",
+"E c #61619E9EDDDD",
+"W c #6565A1A1DDDD",
+"Q c #6969A4A4DFDF",
+"! c #6D6DA7A7E0E0",
+"~ c #7070A9A9E2E2",
+"^ c #7474ABABE2E2",
+"/ c #7777ADADE3E3",
+"( c #7979AEAEE4E4",
+") c #7B7BB0B0E4E4",
+"_ c gray75",
+"` c #C1C1C1C1C1C1",
+"' c #C3C3C3C3C3C3",
+"] c #C5C5C5C5C5C5",
+"[ c gray79",
+"{ c #CBCBCBCBCBCB",
+"} c gray81",
+"| c gray82",
+" . c LightGray",
+".. c #D7D7D7D7D7D7",
+"X. c #D9D9D7D7D9D9",
+"o. c gray85",
+"O. c gray86",
+"+. c #DFDFDFDFDFDF",
+"@. c #E1E1E1E1E1E1",
+"#. c gray89",
+"$. c gray90",
+"%. c #F1F1F1F1F1F1",
+"&. c gray95",
+"*. c #F2F2F2F2F3F3",
+"=. c #F3F3F3F3F3F3",
+"-. c #F4F4F4F4F4F4",
+";. c gray96",
+":. c #F6F6F6F6F6F6",
+">. c gray97",
+",. c #F8F8F8F8F8F8",
+"<. c #F9F9F9F9F9F9",
+"1. c gray98",
+"2. c #FBFBFBFBFBFB",
+"3. c gray99",
+"4. c None",
+/* pixels */
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"c c c c x z l k j h g f d s a p ",
+"c ) ) ( ( ^ ~ ! Q W E Y P J F i ",
+"c ) T T I L J H S Z C N M n D u ",
+"c ( T I L J H S Z V N M n v A y ",
+" t w q 9 7 4 2 > ; = & # + 1 ",
+" r 0 8 6 4 < > ; = & # O X > ",
+" e 8 6 4 1 > ; * & @ O X . ; ",
+"$.3.2.2.<.<.<.:.:.:.=.=.*.*.=.' ",
+"#.3.<.<.<.<.:.:.:.=.*.*.%.*.*.` ",
+"@.2.<.<.<.<.:.:.:.:.:.=.*.=.*._ ",
+"+.O.o.o... . .} [ [ ] ] ` ` _ _ ",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4."
+};
diff --git a/src/images/flags/EG.xpm b/src/images/flags/EG.xpm
new file mode 100644
index 0000000..1f70785
--- /dev/null
+++ b/src/images/flags/EG.xpm
@@ -0,0 +1,149 @@
+/* XPM */
+static const char *EG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 127 2",
+" c black",
+". c #0B0B0B0B0B0B",
+"X c #0F0F0F0F0E0E",
+"o c #131313131313",
+"O c #181819191919",
+"+ c #1E1E1E1E1E1E",
+"@ c #232323232323",
+"# c gray16",
+"$ c #2C2C2C2C2C2C",
+"% c gray18",
+"& c #2F2F2F2F2F2F",
+"* c #323232323232",
+"= c #343434343434",
+"- c #353535353535",
+"; c #393939393939",
+": c #3A3A3A3A3A3A",
+"> c gray24",
+", c #3F3F3F3F3F3F",
+"< c gray26",
+"1 c #444444444444",
+"2 c #464646464646",
+"3 c #4B4B4B4B4B4B",
+"4 c #505050505050",
+"5 c #545454545555",
+"6 c #585858585858",
+"7 c #5D5D5D5D5D5D",
+"8 c #616161616262",
+"9 c gray39",
+"0 c gray40",
+"q c #6A6A6A6A6A6A",
+"w c #6C6C6C6C6D6D",
+"e c #707070707171",
+"r c gray48",
+"t c #7B7B7B7B7C7C",
+"y c #CFCF00000000",
+"u c #D3D300000000",
+"i c #D5D500000000",
+"p c #D7D700000000",
+"a c #D9D900000000",
+"s c #DBDB00000000",
+"d c #DFDF00000000",
+"f c #E1E100000000",
+"g c #E3E300000000",
+"h c #E5E500000000",
+"j c #E7E700000000",
+"k c #E9E900000000",
+"l c #EBEB00000000",
+"z c #EDED00000000",
+"x c #E9E92C2C2C2C",
+"c c #E9E931313131",
+"v c #EBEB37373737",
+"b c #ECEC3C3C3D3D",
+"n c #F1F135353535",
+"m c #EDED42424242",
+"M c #EFEF47474747",
+"N c #EBEB49494949",
+"B c #EDED4E4E4E4E",
+"V c #EDED53535353",
+"C c #EEEE57575757",
+"Z c #F0F04C4C4C4C",
+"A c #F1F151515151",
+"S c #F2F254545454",
+"D c #F2F259595959",
+"F c #F0F05C5C5C5C",
+"G c #F3F35C5C5C5C",
+"H c #F3F35F5F5F5F",
+"J c #ECEC69696969",
+"K c #EDED6D6D6D6D",
+"L c #EEEE71717171",
+"P c #EFEF75757575",
+"I c #EDED7E7E7E7E",
+"U c #F1F160606060",
+"Y c #F2F265656565",
+"T c #F2F269696969",
+"R c #F3F36D6D6D6D",
+"E c #F4F470707171",
+"W c #F5F574747474",
+"Q c #F6F677777777",
+"! c #F1F17A7A7B7B",
+"~ c #F6F679797979",
+"^ c #F6F67B7B7A7A",
+"/ c #F7F77B7B7B7B",
+"( c #EFEF7E7E8080",
+") c #F2F2BBBB7676",
+"_ c #DEDECBCB6262",
+"` c #DFDFCCCC6666",
+"' c #EFEFDDDD7272",
+"] c #F0F0DDDD7474",
+"[ c #F1F1DEDE7777",
+"{ c #F2F2E0E07B7B",
+"} c #F3F3E2E27F7F",
+"| c #808080808080",
+" . c #848484848484",
+".. c #888888888888",
+"X. c #8B8B8B8B8B8B",
+"o. c #A0A0A0A0A0A0",
+"O. c #F4F485858585",
+"+. c #F4F488888888",
+"@. c #F5F58B8B8B8B",
+"#. c #F6F68E8E8E8E",
+"$. c #F6F690909090",
+"%. c #F8F8A4A4A4A4",
+"&. c #E8E8D8D88383",
+"*. c #E9E9DADA8888",
+"=. c #EEEEDEDE8989",
+"-. c #F4F4E3E38383",
+";. c #F2F2E5E59797",
+":. c gray89",
+">. c gray90",
+",. c #E7E7E7E7E7E7",
+"<. c gray95",
+"1. c #F3F3F3F3F3F3",
+"2. c #F4F4F4F4F4F4",
+"3. c #F4F4F5F5F5F5",
+"4. c gray96",
+"5. c #F6F6F6F6F6F6",
+"6. c gray97",
+"7. c #F7F7F8F8F3F3",
+"8. c #FAFAFAFAF9F9",
+"9. c gray98",
+"0. c #FBFBFBFBFBFB",
+"q. c #FBFBFCFCFBFB",
+"w. c gray99",
+"e. c #FDFDFCFCFDFD",
+"r. c #FDFDFDFDFDFD",
+"t. c #FEFEFEFEFEFE",
+"y. c None",
+/* pixels */
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"z l l l l l j j j f f d a a a p ",
+"l / / / Q Q E R T Y U F C V B p ",
+"l / H G D A A Z M m b v c x N y ",
+"n %.$.#. at .+.+.! ) ! P L K J I p ",
+"r.r.r.r.r.r.6.;.{ 7.6.3.3.3.3.,.",
+"r.r.r.w.w.w.-.=.] [ 3.3.3.<.3.>.",
+"r.r.w.w.8.8.-.*.&.' 3.3.3.<.3.:.",
+"& o.X... .| t ` _ e w q 0 9 r ",
+" 0 1 , : - $ # @ + O o X . & ",
+" 8 7 6 5 4 3 2 < > : - * & $ ",
+" ",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y."
+};
diff --git a/src/images/flags/EH.xpm b/src/images/flags/EH.xpm
new file mode 100644
index 0000000..90a6d46
--- /dev/null
+++ b/src/images/flags/EH.xpm
@@ -0,0 +1,168 @@
+/* XPM */
+static const char *EH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 146 2",
+" c black",
+". c #000025250000",
+"X c #000027270000",
+"o c #00002B2B0000",
+"O c #00002D2D0000",
+"+ c #00002F2F0000",
+"@ c #000035350000",
+"# c #00003B3B0000",
+"$ c #00003F3F0000",
+"% c #3B3B37373737",
+"& c gray24",
+"* c #000045450000",
+"= c #00004B4B0000",
+"- c #000051510000",
+"; c #000055550000",
+": c #00005B5B0000",
+"> c #000061610000",
+", c #00006B6B0000",
+"< c #00006D6D0000",
+"1 c #00006F6F0000",
+"2 c gray26",
+"3 c gray28",
+"4 c #4B4B4B4B4D4D",
+"5 c #515150505151",
+"6 c #555555555555",
+"7 c gray35",
+"8 c #5A5A58585858",
+"9 c gray36",
+"0 c #5D5D5D5D5D5D",
+"q c #616160606161",
+"w c gray38",
+"e c #646464646464",
+"r c #656565656565",
+"t c #6A6A6A6A6A6A",
+"y c #6D6D6D6D6D6D",
+"u c #717171717070",
+"i c gray46",
+"p c #777777777777",
+"a c gray48",
+"s c gray49",
+"d c #7F7F7F7F7E7E",
+"f c gray50",
+"g c #121296960E0E",
+"h c #13139A9A1313",
+"j c #18189B9B1919",
+"k c #1E1E9C9C1E1E",
+"l c #23239F9F2323",
+"z c #2929A2A22929",
+"x c #2E2EA6A62E2E",
+"c c #3131A3A32F2F",
+"v c #3232A6A63232",
+"b c #3434A9A93434",
+"n c #3535A8A83535",
+"m c #3939A9A93939",
+"M c #3A3AABAB3A3A",
+"N c #3D3DACAC3D3D",
+"B c #3F3FADAD3F3F",
+"V c #4242AEAE4242",
+"C c #4444B0B04444",
+"Z c #4646B0B04646",
+"A c #4B4BB2B24B4B",
+"S c #5050B4B45050",
+"D c #5454B7B75555",
+"F c #5858B9B95858",
+"G c #5D5DBCBC5D5D",
+"H c #6161BEBE6262",
+"J c #6666BFBF6666",
+"K c #B1B100000000",
+"L c #B9B900000000",
+"P c #DDDD00000000",
+"I c #DFDF00000000",
+"U c #DFDF0B0B0B0B",
+"Y c #D8D82C2C2C2C",
+"T c #D8D82D2D2D2D",
+"R c #E3E300000000",
+"E c #E5E500000000",
+"W c #E7E700000000",
+"Q c #E9E900000000",
+"! c #EBEB00000000",
+"~ c #E2E214141414",
+"^ c #E4E41F1F1F1F",
+"/ c #F2F210101010",
+"( c #F2F214141414",
+") c #F3F319191919",
+"_ c #F3F31A1A1A1A",
+"` c #F4F41F1F1F1F",
+"' c #E2E22C2C2C2C",
+"] c #F4F420202020",
+"[ c #F5F525252525",
+"{ c #F5F526262626",
+"} c #F2F22F2F2F2F",
+"| c #F3F332323232",
+" . c #F4F436363636",
+".. c #F4F43B3B3B3B",
+"X. c #F5F53F3F3F3F",
+"o. c #DEDE4F4F4F4F",
+"O. c #F6F644444444",
+"+. c #F7F749494949",
+"@. c #FAFA62626262",
+"#. c #F7F779797A7A",
+"$. c #F8F878787878",
+"%. c #F9F981818181",
+"&. c #F8F884848686",
+"*. c #FAFA91919191",
+"=. c #DFDFDFDFDFDF",
+"-. c #DFDFE8E8DBDB",
+";. c #DDDDEFEFDDDD",
+":. c #F9F9C4C4C4C4",
+">. c #FBFBC8C8C8C8",
+",. c #FBFBD0D0D0D0",
+"<. c #F9F9D7D7D7D7",
+"1. c #E4E4E1E1E1E1",
+"2. c #E5E5E6E6E6E6",
+"3. c #E6E6E6E6E6E6",
+"4. c #E0E0EDEDE1E1",
+"5. c #E2E2EDEDE2E2",
+"6. c #E2E2EFEFE2E2",
+"7. c #E4E4EFEFE4E4",
+"8. c gray91",
+"9. c #E9E9E9E9E9E9",
+"0. c #EAEAEAEAEAEA",
+"q. c gray92",
+"w. c #ECECECECECEC",
+"e. c gray93",
+"r. c #E6E6F1F1E6E6",
+"t. c #E7E7F1F1E7E7",
+"y. c #E8E8F2F2E8E8",
+"u. c #EAEAF3F3EAEA",
+"i. c #EBEBF4F4EBEB",
+"p. c #EFEFF7F7EFEF",
+"a. c #F5F5E7E7E9E9",
+"s. c #F1F1F1F1F1F1",
+"d. c #F7F7F3F3F3F3",
+"f. c #F6F6F6F6F6F6",
+"g. c gray97",
+"h. c #F1F1F9F9F1F1",
+"j. c #F3F3F9F9F3F3",
+"k. c #F8F8F8F8F8F8",
+"l. c gray98",
+"z. c #FBFBFBFBFBFB",
+"x. c #FBFBFCFCFBFB",
+"c. c gray99",
+"v. c #FDFDFCFCFDFD",
+"b. c #FDFDFDFDFDFD",
+"n. c #FEFEFEFEFEFE",
+"m. c None",
+/* pixels */
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+" K ",
+" f f f a i i u y t r q 0 7 o.! ",
+" f e q 0 7 6 5 4 3 2 & % Y +.! ",
+"=.s.e.e.e.0.0.0.0.3.3.1.Y { O.E ",
+"j.n.n.n.n.l.>.*.%.g.d.Y { ` X.E ",
+"j.n.n.z.n.,. at .<.$.g.Y [ ` ) ..E ",
+"p.n.z.n.l.z.:.&.#.g.a.^ ) ( .R ",
+";.p.i.y.y.7.7.7.5.5.5.-.~ / | P ",
+"1 J C V M n v z l k j h g U } P ",
+"1 H G F D S A V V N m n v c ' P ",
+", : : ; - = * * # @ O o X X O L ",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m."
+};
diff --git a/src/images/flags/ER.xpm b/src/images/flags/ER.xpm
new file mode 100644
index 0000000..ad80157
--- /dev/null
+++ b/src/images/flags/ER.xpm
@@ -0,0 +1,189 @@
+/* XPM */
+static const char *ER_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 167 2",
+" c black",
+". c #00003F3F0000",
+"X c #000049490000",
+"o c #00004D4D0000",
+"O c #000051510000",
+"+ c #00005F5F0000",
+"@ c #000063630000",
+"# c #000069690000",
+"$ c #00006D6D0000",
+"% c #0B0B6B6B0000",
+"& c #000071710000",
+"* c #000077770000",
+"= c #00007B7B0000",
+"- c #00007F7F0000",
+"; c #5F5F35350000",
+": c #555500004141",
+"> c #6E6E70702121",
+", c #010100009D9D",
+"< c #00000000B9B9",
+"1 c #00000000BBBB",
+"2 c #00000000BDBD",
+"3 c #00000000BFBF",
+"4 c #00000000C1C1",
+"5 c #00000000C3C3",
+"6 c #00000000C5C5",
+"7 c #00000000C9C9",
+"8 c MediumBlue",
+"9 c #00000000D5D5",
+"0 c #00000505DDDD",
+"q c #00000D0DD5D5",
+"w c #39396464DFDF",
+"e c #34346D6DECEC",
+"r c #3C3C6868E1E1",
+"t c #3C3C6B6BE7E7",
+"y c #3D3D6E6EE7E7",
+"u c #3B3B7373EEEE",
+"i c #58586464CCCC",
+"p c #46467373E8E8",
+"a c #54547979E2E2",
+"s c #56567A7AE3E3",
+"d c #57577B7BE3E3",
+"f c #59597D7DE4E4",
+"g c #59597E7EE7E7",
+"h c #5C5C7F7FE6E6",
+"j c #61616B6BCECE",
+"k c #6F6F7676D3D3",
+"l c #000085850000",
+"z c #000089890000",
+"x c #00008B8B0000",
+"c c #000091910000",
+"v c #2626AAAA2626",
+"b c #2B2BA9A92B2B",
+"n c #2C2CA9A92C2C",
+"m c #3131ACAC3131",
+"M c #3737B0B03737",
+"N c #3D3DB4B43D3D",
+"B c #49499B9B3232",
+"V c #5555A0A03F3F",
+"C c #4242B4B44242",
+"Z c #4444B3B34444",
+"A c #4949B4B44949",
+"S c #4E4EB7B74E4E",
+"D c #5454AFAF4848",
+"F c #5353B9B95353",
+"G c #5858BCBC5757",
+"H c #5C5CBEBE5C5C",
+"J c #6161C0C06060",
+"K c #6565C2C26565",
+"L c #6969C5C56969",
+"P c #6D6DC8C86D6D",
+"I c #7070C5C57171",
+"U c #7E7E8A8ADDDD",
+"Y c #60608282E6E6",
+"T c #62628585E8E8",
+"R c #65658888EAEA",
+"E c #68688C8CEDED",
+"W c #6D6D8E8EECEC",
+"Q c #B1B100000000",
+"! c #B1B137375C5C",
+"~ c #B9B93E3E6161",
+"^ c #81817E7E3838",
+"/ c #AAAA4F4F2828",
+"( c #B8B861613E3E",
+") c #C3C309090000",
+"_ c #DFDF00000000",
+"` c #DBDB27272E2E",
+"' c #DFDF2F2F3737",
+"] c #DCDC35352E2E",
+"[ c #E1E100000000",
+"{ c #E5E500000000",
+"} c #E7E700000000",
+"| c #EFEF00000000",
+" . c #F1F11A1A1A1A",
+".. c #F4F41F1F1F1F",
+"X. c #E7E72D2D2D2D",
+"o. c #EBEB25252525",
+"O. c #ECEC24242424",
+"+. c #E9E92F2F2F2F",
+"@. c #EEEE2A2A2A2A",
+"#. c #EFEF2F2F2F2F",
+"$. c #E7E733333333",
+"%. c #E6E63F3F3C3C",
+"&. c #E8E836363939",
+"*. c #ECEC3B3B3F3F",
+"=. c #F1F130303434",
+"-. c #F3F336363939",
+";. c #C5C53C3C5E5E",
+":. c #ECEC5D5D3737",
+">. c #EFEF77773D3D",
+",. c #F4F476763434",
+"<. c #F7F775753A3A",
+"1. c #F5F575753F3F",
+"2. c #D3D34A4A4A4A",
+"3. c #CACA68685252",
+"4. c #D3D364647E7E",
+"5. c #E4E448484444",
+"6. c #ECEC46464848",
+"7. c #EFEF4D4D4545",
+"8. c #EFEF5F5F4444",
+"9. c #EFEF59594D4D",
+"0. c #F5F547474A4A",
+"q. c #EDED5F5F6363",
+"w. c #EFEF78785757",
+"e. c #F1F16B6B5656",
+"r. c #FBFB73735B5B",
+"t. c #FAFA7F7F5E5E",
+"y. c #F5F561616262",
+"u. c #F4F467676262",
+"i. c #F1F166666969",
+"p. c #F2F27E7E7E7E",
+"a. c #F5F57B7B7C7C",
+"s. c #FBFB7B7B7E7E",
+"d. c #80804A4A9595",
+"f. c #878752529797",
+"g. c #969656569494",
+"h. c #ACAC7272A9A9",
+"j. c #979787874E4E",
+"k. c #8A8AB6B67575",
+"l. c #B1B1A0A07878",
+"z. c #F4F4B9B93A3A",
+"x. c #D8D889897A7A",
+"c. c #F2F29D9D4242",
+"v. c #F5F590905959",
+"b. c #F5F59C9C5050",
+"n. c #F3F38F8F6D6D",
+"m. c #F6F690907A7A",
+"M. c #F4F4AFAF4646",
+"N. c #F6F6A1A15555",
+"B. c #F7F7BDBD4B4B",
+"V. c #FAFAB5B54D4D",
+"C. c #F6F6D6D63B3B",
+"Z. c #F6F6C1C14242",
+"A. c #F6F6C0C04646",
+"S. c #F7F7C6C64C4C",
+"D. c #F6F6C9C94040",
+"F. c #F7F7CDCD4747",
+"G. c #F8F8CBCB4A4A",
+"H. c #F8F8C2C25151",
+"J. c #F9F9C1C15656",
+"K. c #F8F8C8C85151",
+"L. c #FAFACCCC5151",
+"P. c #FAFACBCB5E5E",
+"I. c #F9F9D0D05959",
+"U. c #FAFAD8D86F6F",
+"Y. c #FBFBD7D77676",
+"T. c #FBFBDDDD7373",
+"R. c None",
+/* pixels */
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+") ; % z c z l - - * & $ # @ + + ",
+"| s.p.x.l.k.I P L K J H G F S O ",
+"} a.u.t.r.w.3.j.D C N M m n A o ",
+"} m.P.I.J.L.V.0.5.( ^ B b v Z X ",
+"} Y.v.N.K.9.F.8.*.-.=.] / > V . ",
+"} T.e.H.S.6.Z.>.&.$.X.o... .2. ",
+"} U.b.B.A.c.C.:.+. at .O.` ! d.k 7 ",
+"_ n.G.M.D.z.,.#.' ~ f.i y e g 4 ",
+"_ i.7.1.<.%.;.g.j p u t r w d 2 ",
+"} y.q.4.h.U W E R T Y h g d a < ",
+"Q : , q 0 9 8 7 6 6 4 2 2 < < < ",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R."
+};
diff --git a/src/images/flags/ES.xpm b/src/images/flags/ES.xpm
new file mode 100644
index 0000000..6865b0f
--- /dev/null
+++ b/src/images/flags/ES.xpm
@@ -0,0 +1,160 @@
+/* XPM */
+static const char *ES_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 138 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c red",
+"3 c #F2F213131313",
+"4 c #F3F319191919",
+"5 c #F4F41E1E1E1E",
+"6 c #F5F523232323",
+"7 c #F2F22C2C2C2C",
+"8 c #F2F22F2F2F2F",
+"9 c #F6F629292929",
+"0 c #F6F62C2C2C2C",
+"q c #F7F72E2E2E2E",
+"w c #F2F232323232",
+"e c #F3F335353535",
+"r c #F7F731313131",
+"t c #F4F439393939",
+"y c #F5F53D3D3D3D",
+"u c #F8F834343434",
+"i c #F8F837373737",
+"p c #F9F93A3A3A3A",
+"a c #F9F93C3C3D3D",
+"s c #FAFA3F3F3F3F",
+"d c #ECEC53535151",
+"f c #F6F642424242",
+"g c #F7F746464646",
+"h c #F7F749494949",
+"j c #F7F74B4B4B4B",
+"k c #F7F74E4E4E4E",
+"l c #FAFA42424242",
+"z c #FAFA44444444",
+"x c #FBFB47474747",
+"c c #FCFC4C4C4C4C",
+"v c #F8F850505050",
+"b c #F8F853535353",
+"n c #F9F954545555",
+"m c #F9F957575757",
+"M c #FDFD51515151",
+"N c #FDFD54545454",
+"B c #F9F958585858",
+"V c #FAFA5C5C5C5C",
+"C c #FAFA5D5D5D5D",
+"Z c #FEFE59595959",
+"A c #FEFE5C5C5C5C",
+"S c #FEFE5F5F5F5F",
+"D c #EDED67675353",
+"F c #EBEB69695757",
+"G c #F1F17E7E5757",
+"H c #FBFB60606060",
+"J c #FBFB61616262",
+"K c #FCFC65656565",
+"L c #FCFC66666666",
+"P c #FCFC69696969",
+"I c #FDFD6D6D6D6D",
+"U c #FDFD70707171",
+"Y c #FEFE74747474",
+"T c #FEFE77777777",
+"R c #FEFE79797979",
+"E c #FFFF7B7B7A7A",
+"W c #FFFF7B7B7B7B",
+"Q c #E0E08C8C5151",
+"! c #E4E4A7A74A4A",
+"~ c #DFDFDFDF0000",
+"^ c #E3E3E3E30000",
+"/ c #E5E5E5E50000",
+"( c #E7E7E7E70000",
+") c #FBFBFBFB0000",
+"_ c #FDFDFDFD0000",
+"` c #FFFFFDFD0000",
+"' c #F2F2F2F21010",
+"] c #F2F2F2F21414",
+"[ c #F3F3F3F31919",
+"{ c #F3F3F3F31A1A",
+"} c #F4F4F4F41F1F",
+"| c #E8E8EEEE3D3D",
+" . c #F4F4F4F42020",
+".. c #F5F5F5F52424",
+"X. c #F5F5F5F52525",
+"o. c #F5F5F4F42626",
+"O. c #F6F6F6F62A2A",
+"+. c #F6F6F6F62B2B",
+"@. c #F7F7F7F72F2F",
+"#. c #F3F3F3F33232",
+"$. c #F7F7F7F73030",
+"%. c #F7F7F7F73131",
+"&. c #F4F4F4F43636",
+"*. c #F4F4F5F53B3B",
+"=. c #F5F5F5F53F3F",
+"-. c #F8F8F8F83636",
+";. c #F9F9F9F93C3C",
+":. c #EBEBC9C94B4B",
+">. c #EBEBDEDE5353",
+",. c #ECECE1E14242",
+"<. c #F0F0E0E04848",
+"1. c #F4F4EEEE5757",
+"2. c #F3F3F4F44141",
+"3. c #F6F6F5F54444",
+"4. c #F8F8F4F44B4B",
+"5. c #FAFAFAFA4242",
+"6. c #FBFBFBFB4747",
+"7. c #FBFBFBFB4949",
+"8. c #FCFCFCFC4F4F",
+"9. c #F2F2F3F35555",
+"0. c #FDFDFDFD5353",
+"q. c #FEFEFEFE5858",
+"w. c #FEFEFEFE5959",
+"e. c #FEFEFEFE5C5C",
+"r. c #FCFCFCFC6A6A",
+"t. c #FDFDFDFD6F6F",
+"y. c #FEFEFEFE7373",
+"u. c #FEFEFEFE7676",
+"i. c #FEFEFEFE7979",
+"p. c #B6B6BBBB9D9D",
+"a. c #F2F2BDBDB0B0",
+"s. c #C0C0CECEA8A8",
+"d. c #F5F5C3C3B1B1",
+"f. c #EDEDE0E08D8D",
+"g. c #ECECD3D3D4D4",
+"h. c #F9F9F1F1D6D6",
+"j. c #F5F5EAEAE2E2",
+"k. c None",
+/* pixels */
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"2 2 2 2 < 2 2 2 < < ; ; = = % % ",
+"2 W W W T Y U I P K H C m b k $ ",
+"2 W A A Z N M c x l y i r 0 h $ ",
+"` i.e.q.1.>.4.6.5.;.-.$.+.o.3.( ",
+"` u.q.9.G F f.2.;.-.$.+.o. .=.( ",
+"` y.0.d.D g.a.,.-.$.O.o.} [ *.( ",
+"` t.8.h.Q d j.<. at .O...} [ ] &.^ ",
+") r.6.s.:.! p.| O.o.} [ ] ] #.~ ",
+"< K x y y u 0 9 6 5 4 3 > : 8 X ",
+"; H C B n v k g f y i e w 8 7 X ",
+"; = = % % = $ $ O O o o X X . . ",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k."
+};
diff --git a/src/images/flags/ET.xpm b/src/images/flags/ET.xpm
new file mode 100644
index 0000000..1b41c09
--- /dev/null
+++ b/src/images/flags/ET.xpm
@@ -0,0 +1,181 @@
+/* XPM */
+static const char *ET_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 159 2",
+" c black",
+". c #000013130000",
+"X c #000015150000",
+"o c #000019190000",
+"O c #00001B1B0000",
+"+ c #000021210000",
+"@ c #000027270000",
+"# c #00002D2D0000",
+"$ c #000035350000",
+"% c #000039390000",
+"& c #00003D3D0000",
+"* c #000043430505",
+"= c #000045450B0B",
+"- c #00004B4B0F0F",
+"; c #000043431515",
+": c #00004D4D1313",
+"> c #000059592121",
+", c #000065650000",
+"< c #2C2C76765757",
+"1 c #31317B7B5C5C",
+"2 c #37377F7F6161",
+"3 c #3D3D83836161",
+"4 c #48488E8E4949",
+"5 c #4C4C91914D4D",
+"6 c #515194945252",
+"7 c #525295955A5A",
+"8 c #42428B8B6666",
+"9 c #49498A8A6F6F",
+"0 c #4E4E93937070",
+"q c #515195957272",
+"w c #535396967575",
+"e c #545494947676",
+"r c #595996967C7C",
+"t c #585898987878",
+"y c #5C5C98987E7E",
+"u c #5C5C9B9B7C7C",
+"i c #61619D9D6262",
+"p c #61619E9E7F7F",
+"a c #6969A4A47070",
+"s c #7070A9A97070",
+"d c #7272ABAB7474",
+"f c #7676ADAD7777",
+"g c #4D4D96968A8A",
+"h c #525299998C8C",
+"j c #5F5F9A9A8181",
+"k c #6565A1A18282",
+"l c #6969A3A38383",
+"z c #6D6DA5A58686",
+"x c #7070A9A98C8C",
+"c c #7474ABAB8F8F",
+"v c #7777ADAD9191",
+"b c #7B7BABAB9696",
+"n c #7979AEAE9494",
+"m c #7B7BB0B09595",
+"M c #6B6BA3A3D1D1",
+"N c #6A6AB3B3DBDB",
+"B c #6B6BB3B3DEDE",
+"V c #7777ABABD7D7",
+"C c #7373B8B8CACA",
+"Z c #7E7EBCBCCBCB",
+"A c #6363B0B0E2E2",
+"S c #6464B0B0E2E2",
+"D c #6868B2B2E3E3",
+"F c #6E6EB6B6E4E4",
+"G c #7171B9B9E6E6",
+"H c #7777BABAE2E2",
+"J c #7777BBBBE6E6",
+"K c #7C7CBEBEE7E7",
+"L c #7A7ABDBDE8E8",
+"P c #DDDD00000000",
+"I c #DFDF00000000",
+"U c #E1E100000000",
+"Y c #E3E300000000",
+"T c #E5E500000000",
+"R c #E7E700000000",
+"E c #E9E900000000",
+"W c #EBEB00000000",
+"Q c #EDED00000000",
+"! c #EFEF00000000",
+"~ c #F1F100000000",
+"^ c #F3F300000000",
+"/ c #F5F500000000",
+"( c #F7F700000000",
+") c #F1F10B0B0B0B",
+"_ c #F1F10F0F0E0E",
+"` c #F9F900000000",
+"' c #FBFB00000000",
+"] c #F2F213131313",
+"[ c #F3F319191919",
+"{ c #F1F11E1E2323",
+"} c #F2F238381010",
+"| c #F2F23C3C1414",
+" . c #F2F22C2C2C2C",
+".. c #F2F22F2F2F2F",
+"X. c #F5F52E2E3131",
+"o. c #F2F232323232",
+"O. c #F3F335353535",
+"+. c #F4F439393939",
+"@. c #F5F53D3D3D3D",
+"#. c #F8F834343434",
+"$. c #F9F93A3A3A3A",
+"%. c #FAFA3F3F3F3F",
+"&. c #F3F341411919",
+"*. c #EFEF42422525",
+"=. c #F3F355553232",
+"-. c #F4F45A5A3F3F",
+";. c #FAFA61613F3F",
+":. c #C9C942425959",
+">. c #CCCC46465C5C",
+",. c #F6F642424242",
+"<. c #F7F746464646",
+"1. c #F7F74B4B4B4B",
+"2. c #FAFA44444444",
+"3. c #F8F850505050",
+"4. c #F9F954545555",
+"5. c #F9F958585858",
+"6. c #FAFA5D5D5D5D",
+"7. c #FBFB65654545",
+"8. c #FBFB69694949",
+"9. c #FBFB61616262",
+"0. c #FCFC66666666",
+"q. c #FCFC84846A6A",
+"w. c #E3E3E3E30000",
+"e. c #E5E5E5E50000",
+"r. c #E7E7E7E70000",
+"t. c #FDFDFDFD0000",
+"y. c #F2F2F2F21414",
+"u. c #F3F3F3F31919",
+"i. c #F3F3F3F31A1A",
+"p. c #F4F4F4F41F1F",
+"a. c #F4F4F4F42020",
+"s. c #F5F5F5F52525",
+"d. c #F6F6F6F62B2B",
+"f. c #F4F4F4F43636",
+"g. c #F4F4F5F53B3B",
+"h. c #F5F5F5F53F3F",
+"j. c #FBFBFBFB4545",
+"k. c #FBFBFCFC4949",
+"l. c #FCFCFCFC4B4B",
+"z. c #FCFCFCFC4F4F",
+"x. c #FDFDFCFC5050",
+"c. c #FDFDFDFD5353",
+"v. c #FDFDFDFD5454",
+"b. c #FEFEFEFE5858",
+"n. c #FDFDFDFD6F6F",
+"m. c #FEFEFEFE7373",
+"M. c #FEFEFEFE7676",
+"N. c #8F8FBBBB8F8F",
+"B. c #9898CACAADAD",
+"V. c #9696C9C9B0B0",
+"C. c #9A9ACBCBB2B2",
+"Z. c #9A9ACBCBB3B3",
+"A. c #B0B0D5D58888",
+"S. c #B0B0D5D58989",
+"D. c #BABADBDB9292",
+"F. c #8686C4C4D2D2",
+"G. c #8585C2C2DADA",
+"H. c #9090C8C8D4D4",
+"J. c None",
+/* pixels */
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"> : : : - = * & % $ # @ + O . O ",
+"- m m n v c x z l k p y t w 0 ",
+"; b j y r e q h g 8 3 2 1 < 9 ",
+", N.f d s a H L J B 7 6 5 4 i X ",
+"t.M.b.v.x.H.K D.C.F Z d.s.a.h.r.",
+"t.m.x.z.l.G.D.Z.V.A.N s.p.u.g.r.",
+"t.n.z.l.j.F.G B.A.S C p.u.y.f.w.",
+"' q.5.7.;.-.V S A M *.&.| } =.P ",
+"' 0.2.=.$.#.X.>.:.{ [ ] _ ) ..P ",
+"' 9.6.5.4.3.1.<.,. at .+.O.o.....P ",
+"^ ^ ^ Q Q Q W W R R U U U P P P ",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J."
+};
diff --git a/src/images/flags/FAM.xpm b/src/images/flags/FAM.xpm
new file mode 100644
index 0000000..e2e0939
--- /dev/null
+++ b/src/images/flags/FAM.xpm
@@ -0,0 +1,183 @@
+/* XPM */
+static const char *FAM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 161 2",
+" c black",
+". c #5353C9C90000",
+"X c #6363D1D10000",
+"o c #6767D3D30000",
+"O c #6969D3D30000",
+"+ c #6969D5D50000",
+"@ c #6969D7D70000",
+"# c #6D6DD7D70000",
+"$ c #7171D9D90000",
+"% c #7575DBDB0000",
+"& c #7F7FE1E10000",
+"* c #0000A7A7EFEF",
+"= c #0000ABABE9E9",
+"- c #0000A9A9F1F1",
+"; c #0000ADADF3F3",
+": c #0000B1B1F5F5",
+"> c #0000B3B3F7F7",
+", c #0000B5B5F9F9",
+"< c #0000B9B9FBFB",
+"1 c #0000BBBBFDFD",
+"2 c #0000BFBFFDFD",
+"3 c #0000C5C5F3F3",
+"4 c #0000C1C1FDFD",
+"5 c #0000C3C3FFFF",
+"6 c #3B3BD8D8F9F9",
+"7 c #4646D7D7FAFA",
+"8 c #4141DADAFAFA",
+"9 c #4747DCDCFBFB",
+"0 c #4C4CD8D8FAFA",
+"q c #4C4CD9D9FBFB",
+"w c #4C4CDDDDFCFC",
+"e c #5151D9D9FBFB",
+"r c #5151DADAFBFB",
+"t c #5252DFDFFDFD",
+"y c #5656DBDBFCFC",
+"u c #5555DDDDF9F9",
+"i c #5656DCDCFCFC",
+"p c #5B5BDCDCFDFD",
+"a c #5B5BDDDDFDFD",
+"s c #5F5FDCDCF9F9",
+"d c #5F5FDDDDFEFE",
+"f c #5E5EDEDEFEFE",
+"g c #5656E0E0FDFD",
+"h c #5B5BE2E2FEFE",
+"j c #6363DFDFFEFE",
+"k c #6464DDDDFAFA",
+"l c #6868DEDEFBFB",
+"z c #6D6DDFDFFCFC",
+"x c #6363E0E0FEFE",
+"c c #6666E0E0FEFE",
+"v c #7171E1E1FCFC",
+"b c #7575E2E2FDFD",
+"n c #7878E2E2FEFE",
+"m c #7B7BE4E4FEFE",
+"M c #7F7FE5E5FEFE",
+"N c #7F7FE6E6FEFE",
+"B c #7979E8E8FEFE",
+"V c #E3E300000000",
+"C c #E5E500000000",
+"Z c #E7E700000000",
+"A c #E9E900000000",
+"S c #EBEB00000000",
+"D c #EDED00000000",
+"F c #F7F700001111",
+"G c #F9F900001717",
+"H c #FBFB00001F1F",
+"J c #FDFD00002525",
+"K c #FDFD00002929",
+"L c #FDFD00002F2F",
+"P c #F3F322226767",
+"I c #F4F427276B6B",
+"U c #F4F428286B6B",
+"Y c #F5F52C2C6E6E",
+"T c #F5F52D2D6F6F",
+"R c #F7F72E2E6F6F",
+"E c #F6F631317272",
+"W c #F6F632327373",
+"Q c #F6F633337373",
+"! c #F7F737377777",
+"~ c #F7F738387777",
+"^ c #F7F739397878",
+"/ c #F8F834347373",
+"( c #F9F93B3B7777",
+") c #F8F83C3C7A7A",
+"_ c #F8F83D3D7B7B",
+"` c #F8F83E3E7B7B",
+"' c #F8F83F3F7C7C",
+"] c #F4F441417C7C",
+"[ c #F5F545457F7F",
+"{ c #F9F942427E7E",
+"} c #F9F943437F7F",
+"| c #FAFA40407C7C",
+" . c #F6F649498282",
+".. c #F7F74B4B8282",
+"X. c #F7F74E4E8585",
+"o. c #F9F944448080",
+"O. c #FBFB46468080",
+"+. c #FAFA48488383",
+"@. c #FAFA49498383",
+"#. c #FAFA49498484",
+"$. c #FBFB4D4D8787",
+"%. c #FBFB4E4E8787",
+"&. c #FCFC4B4B8484",
+"*. c #FBFB4F4F8888",
+"=. c #F8F856568C8C",
+"-. c #FDFD51518888",
+";. c #FCFC53538A8A",
+":. c #FCFC53538B8B",
+">. c #FDFD58588E8E",
+",. c #FDFD5C5C9191",
+"<. c #FBFB67679898",
+"1. c #FCFC6B6B9B9B",
+"2. c #FCFC6F6F9E9E",
+"3. c #FDFD7474A0A0",
+"4. c #FDFD7777A3A3",
+"5. c #FEFE7A7AA5A5",
+"6. c #8F8FE5E50000",
+"7. c #9595EBEB0000",
+"8. c #9999EFEF0000",
+"9. c #9D9DEFEF0000",
+"0. c #A1A1EDED0000",
+"q. c #A1A1F1F10000",
+"w. c #A3A3F3F30000",
+"e. c #BFBFF1F14B4B",
+"r. c #C1C1F1F14E4E",
+"t. c #C1C1F2F24F4F",
+"y. c #C2C2F2F25151",
+"u. c #C3C3F2F25252",
+"i. c #C3C3F2F25353",
+"p. c #C5C5F3F35656",
+"a. c #C6C6F3F35656",
+"s. c #C6C6F3F35757",
+"d. c #C7C7F4F45A5A",
+"f. c #C8C8F4F45A5A",
+"g. c #C8C8F4F45C5C",
+"h. c #C9C9F5F55E5E",
+"j. c #CACAF5F55F5F",
+"k. c #C8C8F2F26363",
+"l. c #C8C8F2F26565",
+"z. c #CACAF5F56060",
+"x. c #CBCBF6F66363",
+"c. c #CCCCF6F66464",
+"v. c #CCCCF6F66565",
+"b. c #C9C9F2F26868",
+"n. c #C9C9F3F36868",
+"m. c #CACAF3F36A6A",
+"M. c #CBCBF4F46B6B",
+"N. c #CDCDF7F76868",
+"B. c #CECEF7F76969",
+"V. c #CDCDF5F56F6F",
+"C. c #CFCFF8F86E6E",
+"Z. c #CFCFF5F57373",
+"A. c #D1D1F6F67676",
+"S. c #D3D3F7F77A7A",
+"D. c #D4D4F7F77E7E",
+"F. c #8080E6E6FFFF",
+"G. c #8181E6E6FFFF",
+"H. c #D6D6F8F88181",
+"J. c #D8D8F9F98585",
+"K. c #D8D8FAFA8989",
+"L. c None",
+/* pixels */
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"5 5 5 5 3 L K J H G F w.0.q.9.8.",
+"5 G.M M B 5.4.3.2.1.<.K.J.H.D.7.",
+"5 G.c j h ,.;.;.-.#.} C.B.v.S.6.",
+"5 M j d g >.&.*.#.o.| B.v.z.A.& ",
+"5 m d p g ;.} @.[ ` ^ v.g.g.Z.% ",
+"2 m p i w %.| | _ ! Q g.g.p.V.$ ",
+"1 b y r 9 #.^ _ ! Q Y d.p.p.M.# ",
+"1 v r q 8 | / ( Q Y U p.u.t.n.@ ",
+"> z q 7 6 _ Y Q Y I P y.t.e.l.o ",
+"> l k s u =. at .X. .[ [ m.l.l.l.@ ",
+"; ; - - = D A A C C V @ O O X . ",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L."
+};
diff --git a/src/images/flags/FI.xpm b/src/images/flags/FI.xpm
new file mode 100644
index 0000000..596da14
--- /dev/null
+++ b/src/images/flags/FI.xpm
@@ -0,0 +1,150 @@
+/* XPM */
+static const char *FI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 128 2",
+" c black",
+". c #000000008585",
+"X c #000000008787",
+"o c #000000008F8F",
+"O c #000000009999",
+"+ c #000000009B9B",
+"@ c #000000009F9F",
+"# c #00002929B9B9",
+"$ c #00002929BBBB",
+"% c #00002B2BBDBD",
+"& c #00002F2FBDBD",
+"* c #00003535BDBD",
+"= c #00003333C1C1",
+"- c #30306363C9C9",
+"; c #32326565CBCB",
+": c #35356767CACA",
+"> c #37376A6ACCCC",
+", c #3A3A6B6BCCCC",
+"< c #3A3A6C6CCDCD",
+"1 c #3D3D6D6DCECE",
+"2 c #3F3F6F6FCECE",
+"3 c #40406F6FCFCF",
+"4 c #41417272D0D0",
+"5 c #44447373D0D0",
+"6 c #44447373D1D1",
+"7 c #45457474D1D1",
+"8 c #47477676D2D2",
+"9 c #49497777D2D2",
+"0 c #4A4A7878D3D3",
+"q c #4D4D7A7AD3D3",
+"w c #4E4E7A7AD0D0",
+"e c #4C4C7A7AD4D4",
+"r c #4F4F7B7BD5D5",
+"t c #4F4F7C7CD5D5",
+"y c #50507C7CD2D2",
+"u c #51517D7DD5D5",
+"i c #53537F7FD6D6",
+"p c #54548080D7D7",
+"a c #55558080D7D7",
+"s c #55558181D7D7",
+"d c #56568080D4D4",
+"f c #59598383D7D7",
+"g c #59598484D9D9",
+"h c #5A5A8585D9D9",
+"j c #5E5E8686D8D8",
+"k c #5E5E8888DADA",
+"l c #5F5F8888DBDB",
+"z c #60608989DADA",
+"x c #62628A8AD8D8",
+"c c #62628B8BDCDC",
+"v c #63638B8BDCDC",
+"b c #63638C8CDCDC",
+"n c #66668D8DDADA",
+"m c #64648C8CDCDC",
+"M c #65658E8EDDDD",
+"N c #66668E8EDEDE",
+"B c #67678F8FDEDE",
+"V c #69699090DDDD",
+"C c #6B6B9191DEDE",
+"Z c #6C6C9393DFDF",
+"A c #8080A1A1E3E3",
+"S c #8080A2A2E2E2",
+"D c #8181A3A3E3E3",
+"F c #8383A4A4E3E3",
+"G c #8585A5A5E5E5",
+"H c #8787A7A7E5E5",
+"J c #A7A7B1B1C1C1",
+"K c #B5B5BDBDCDCD",
+"L c #B7B7BFBFCDCD",
+"P c #B7B7BFBFD7D7",
+"I c #B9B9C1C1CFCF",
+"U c #B9B9C1C1D3D3",
+"Y c #BBBBC3C3D1D1",
+"T c #BFBFC3C3D3D3",
+"R c #BFBFC7C7D5D5",
+"E c #C1C1C9C9D7D7",
+"W c #C3C3C9C9D7D7",
+"Q c #C1C1CBCBD9D9",
+"! c #C7C7CFCFDBDB",
+"~ c #CDCDD3D3DDDD",
+"^ c #D1D1D7D7E3E3",
+"/ c #D3D3D9D9E5E5",
+"( c #D7D7DBDBE7E7",
+") c #D5D5DBDBEDED",
+"_ c #D9D9DDDDE9E9",
+"` c #DBDBDFDFEBEB",
+"' c #DBDBDFDFEFEF",
+"] c #DBDBE1E1EDED",
+"[ c #DDDDE1E1EBEB",
+"{ c #DDDDE3E3EDED",
+"} c #DFDFE3E3EDED",
+"| c #E3E3E9E9F3F3",
+" . c #E5E5EBEBF3F3",
+".. c #E7E7EBEBF3F3",
+"X. c #E5E5EBEBF5F5",
+"o. c #F1F1F1F1F1F1",
+"O. c #F1F1F1F1F2F2",
+"+. c gray95",
+"@. c #F2F2F2F2F3F3",
+"#. c #F3F3F3F3F3F3",
+"$. c #F3F3F3F3F4F4",
+"%. c #F4F4F4F4F4F4",
+"&. c #F4F4F4F4F5F5",
+"*. c #F4F4F5F5F5F5",
+"=. c gray96",
+"-. c #F4F4F5F5F6F6",
+";. c #F5F5F5F5F6F6",
+":. c #F5F5F6F6F7F7",
+">. c #F6F6F6F6F6F6",
+",. c gray97",
+"<. c #F6F6F7F7F8F8",
+"1. c #F7F7F8F8F9F9",
+"2. c #F6F6F8F8FAFA",
+"3. c #F7F7F9F9FAFA",
+"4. c #F8F8F8F8F8F8",
+"5. c #F9F9F9F9F9F9",
+"6. c #F8F8F9F9FAFA",
+"7. c #F9F9FAFAFAFA",
+"8. c gray98",
+"9. c #FBFBFBFBFBFB",
+"0. c #F9F9FBFBFCFC",
+"q. c #FBFBFCFCFDFD",
+"w. c gray99",
+"e. c #FDFDFDFDFDFD",
+"r. c #FCFCFDFDFEFE",
+"t. c #FEFEFEFEFEFE",
+"y. c gray100",
+"u. c None",
+/* pixels */
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+" . . .X.& $ * ` } { ` _ ( / ^ Q ",
+" .y.y.q.H S Z y.w.w.7.7.7.7.>.~ ",
+" .y.y.y.C N c y.9.7.7.7.,.>.,.! ",
+" .y.q.q.N b l 7.7.,.,.>.>.%.>.Q ",
+"= H C C v j h h i r 9 5 3 , i o ",
+"$ D N b j g s u e 8 4 2 > ; q X ",
+"$ S b j h s u q 8 5 2 , : - w X ",
+"' q.7.<.i t 9 ,.>.%.%.+.+.+. at .U ",
+"{ q.7.q.t 0 7 >.>.%. at .+.o.+.@.L ",
+"[ 9.7.7.n c j ,.>.>.>. at .+.+.+.L ",
+"_ ( / ^ @ O O P W E Y Y L L K J ",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u."
+};
diff --git a/src/images/flags/FJ.xpm b/src/images/flags/FJ.xpm
new file mode 100644
index 0000000..0ca057d
--- /dev/null
+++ b/src/images/flags/FJ.xpm
@@ -0,0 +1,188 @@
+/* XPM */
+static const char *FJ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 166 2",
+" c black",
+". c #000000005959",
+"X c #000000006B6B",
+"o c #31311D1D6F6F",
+"O c #7F7F13133B3B",
+"+ c #676719194B4B",
+"@ c #00002727DDDD",
+"# c #00002929DDDD",
+"$ c #00002929DFDF",
+"% c #00002D2DDFDF",
+"& c #00002F2FDFDF",
+"* c #00002F2FE1E1",
+"= c #00003131E3E3",
+"- c #00003535E3E3",
+"; c #00003737E5E5",
+": c #00003B3BE5E5",
+"> c #00003D3DE7E7",
+", c #00004141E7E7",
+"< c #00004343E9E9",
+"1 c #00004747E9E9",
+"2 c #00004949EBEB",
+"3 c #00004D4DEBEB",
+"4 c #00004D4DEDED",
+"5 c #00005555EDED",
+"6 c #00005555EFEF",
+"7 c #00005959EFEF",
+"8 c #00005F5FF1F1",
+"9 c #00005B5BFBFB",
+"0 c #00006363F1F1",
+"q c #00006565F3F3",
+"w c #00006969F5F5",
+"e c #00006F6FF7F7",
+"r c #00007171F7F7",
+"t c #00007575F9F9",
+"y c #00007777F9F9",
+"u c #00007B7BFBFB",
+"i c #696955558F8F",
+"p c #7D7D7F7FB7B7",
+"a c #51517878C5C5",
+"s c #00008181FDFD",
+"d c #5E5E8585CECE",
+"f c #54549E9EF8F8",
+"g c #4242A0A0F3F3",
+"h c #4646A1A1F4F4",
+"j c #4D4DA1A1F5F5",
+"k c #4C4CA4A4F5F5",
+"l c #4D4DA7A7F6F6",
+"z c #5050A5A5F2F2",
+"x c #5353A7A7F2F2",
+"c c #5252A4A4F6F6",
+"v c #5454A7A7F2F2",
+"b c #5656A6A6F7F7",
+"n c #5757A7A7F7F7",
+"m c #5252A9A9F6F6",
+"M c #5252AAAAF7F7",
+"N c #5555A8A8F3F3",
+"B c #5757A8A8F7F7",
+"V c #5757ACACF7F7",
+"C c #5959A1A1F9F9",
+"Z c #5E5EA4A4FAFA",
+"A c #5959AAAAF3F3",
+"S c #5C5CADADF4F4",
+"D c #5B5BA9A9F8F8",
+"F c #5B5BAAAAF8F8",
+"G c #5A5AADADF8F8",
+"H c #5C5CAAAAF8F8",
+"J c #5C5CAFAFF8F8",
+"K c #5B5BB1B1F9F9",
+"L c #78789D9DD9D9",
+"P c #6363A7A7FBFB",
+"I c #6060AEAEF5F5",
+"U c #6060ACACF9F9",
+"Y c #6060ADADF9F9",
+"T c #6464AFAFFAFA",
+"R c #6565AFAFFAFA",
+"E c #6464B0B0F6F6",
+"W c #6060B1B1F9F9",
+"Q c #6363B4B4FAFA",
+"! c #6565B0B0FAFA",
+"~ c #6868B3B3F7F7",
+"^ c #6A6AB4B4F7F7",
+"/ c #6B6BB5B5F7F7",
+"( c #6E6EB7B7F7F7",
+") c #6969B1B1FAFA",
+"_ c #6969B2B2FBFB",
+"` c #6D6DB4B4FBFB",
+"' c #6D6DB5B5FBFB",
+"] c #6F6FB8B8F8F8",
+"[ c #7171B7B7FCFC",
+"{ c #7272B9B9F8F8",
+"} c #7373B9B9F9F9",
+"| c #7676BCBCF9F9",
+" . c #7777BCBCF9F9",
+".. c #7A7ABEBEFAFA",
+"X. c #7E7EC0C0FBFB",
+"o. c #7F7FC0C0FBFB",
+"O. c #898919193D3D",
+"+. c #838323234949",
+"@. c #B7B769697F7F",
+"#. c #B8B860607070",
+"$. c #BCBC6D6D7A7A",
+"%. c #CFCF19191919",
+"&. c #CFCF3A3A3737",
+"*. c #D2D23B3B3939",
+"=. c #D1D13F3F3C3C",
+"-. c #CFCF53535454",
+";. c #D5D548484545",
+":. c #D5D548484646",
+">. c #D3D35C5C5D5D",
+",. c #CCCC60606666",
+"<. c #CECE65656A6A",
+"1. c #C5C56D6D7B7B",
+"2. c #CDCD6A6A7070",
+"3. c #CFCF6F6F7474",
+"4. c #D8D874747979",
+"5. c #E3E36B6B6969",
+"6. c #E5E574747272",
+"7. c #E0E078787A7A",
+"8. c #E9E97C7C7A7A",
+"9. c #818167679595",
+"0. c #9A9A7A7A9C9C",
+"q. c #ACAC7B7B9595",
+"w. c #C0C07C7C8D8D",
+"e. c #C3C37C7C8C8C",
+"r. c #E5E5B0B05050",
+"t. c #E6E6B0B05353",
+"y. c #E7E7B4B45959",
+"u. c #E8E8B5B55959",
+"i. c #9A9A8383A8A8",
+"p. c #93939393C0C0",
+"a. c #92929595C3C3",
+"s. c #97979A9AC2C2",
+"d. c #9F9FA4A4CBCB",
+"f. c #9999A7A7D3D3",
+"g. c #8787BEBEF1F1",
+"h. c #8080B8B8FCFC",
+"j. c #A6A6AFAFD5D5",
+"k. c #8484C0C0FCFC",
+"l. c #8C8CC2C2F2F2",
+"z. c #8888C3C3FCFC",
+"x. c #8B8BC4C4FDFD",
+"c. c #D7D788888E8E",
+"v. c #D9D9A1A1AAAA",
+"b. c #D9D9A7A7AFAF",
+"n. c #DADAABABB4B4",
+"m. c #E2E281818282",
+"M. c #E3E386868787",
+"N. c #EBEB85858383",
+"B. c #E7E794949595",
+"V. c #E4E4B7B7BEBE",
+"C. c #F1F1A6A6A4A4",
+"Z. c #F1F1A9A9A7A7",
+"A. c #DADAB9B9C4C4",
+"S. c #E5E5BFBFC6C6",
+"D. c #E6E6BFBFC6C6",
+"F. c #C7C7DFDFF4F4",
+"G. c #C9C9DFDFF3F3",
+"H. c #CDCDE2E2F5F5",
+"J. c #CCCCE3E3F6F6",
+"K. c #E9E9CFCFD4D4",
+"L. c #E2E2D6D6E0E0",
+"P. c #E7E7EDEDF2F2",
+"I. c #EAEAEEEEF3F3",
+"U. c #EAEAEFEFF3F3",
+"Y. c #EDEDF1F1F5F5",
+"T. c None",
+/* pixels */
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"1.9.X O O.. + e.9 t r w q 0 7 6 ",
+"o D.D.Z.Z.A.D.j...z.X...g.} { 2 ",
+"%.B.e.e.5.e.e.e.P Q J J U D _ 1 ",
+"+.V.C.y.e.Z.e.q.P G <.>.u.-.3., ",
+"i D.i.q.e.b.n.q.C D ,.u.t.r.2.> ",
+"p f.d p.p.a L j.f M H.U.:.U.H.; ",
+"s x.[ ` _ ! Y H n l #.;.*.=.$.= ",
+"u k.` _ ! Y D n c l F.I.=.I.G.* ",
+"y z._ T Y D b c j h g l.&.g.v $ ",
+"e o... .} ] / ~ E I S A v x x @ ",
+"w q 8 8 5 4 2 < > : - * * @ @ @ ",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T."
+};
diff --git a/src/images/flags/FK.xpm b/src/images/flags/FK.xpm
new file mode 100644
index 0000000..27728ab
--- /dev/null
+++ b/src/images/flags/FK.xpm
@@ -0,0 +1,192 @@
+/* XPM */
+static const char *FK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 170 2",
+" c black",
+". c #000000000303",
+"X c #000000000707",
+"o c #000000000909",
+"O c #000000000F0F",
+"+ c #000000001313",
+"@ c #000000001717",
+"# c #000000001919",
+"$ c #000000001D1D",
+"% c #000000001F1F",
+"& c #000000002121",
+"* c #000000002525",
+"= c #000000002B2B",
+"- c #000000002D2D",
+"; c #000000002F2F",
+": c #000000003333",
+"> c #000000003939",
+", c #000000003F3F",
+"< c #000000004545",
+"1 c #000000004949",
+"2 c #000000004B4B",
+"3 c #000000004F4F",
+"4 c #000000005353",
+"5 c #000000005757",
+"6 c #000000005959",
+"7 c #000000005B5B",
+"8 c #000000005D5D",
+"9 c #000000006161",
+"0 c #000000006565",
+"q c #000000006969",
+"w c #000003037D7D",
+"e c #797931316565",
+"r c #727269696767",
+"t c #74746C6C6E6E",
+"y c #7D7D72726D6D",
+"u c #00001D1D9393",
+"i c #21213B3B8F8F",
+"p c #23233B3B9191",
+"a c #2A2A3C3C9191",
+"s c #3B3B33338383",
+"d c #292942429494",
+"f c #2A2A42429494",
+"g c #2C2C43439393",
+"h c #2E2E47479797",
+"j c #2F2F46469696",
+"k c #2F2F47479797",
+"l c #2F2F49499898",
+"z c #313144449797",
+"x c #363647479696",
+"c c #32324A4A9595",
+"v c #36364B4B9191",
+"b c #36364B4B9A9A",
+"n c #353549499C9C",
+"m c #34344C4C9A9A",
+"M c #34344C4C9B9B",
+"N c #3C3C4C4C9696",
+"B c #3B3B4C4C9898",
+"V c #3B3B4D4D9C9C",
+"C c #3C3C4F4F9D9D",
+"Z c #3C3C50509494",
+"A c #3A3A51519D9D",
+"S c #3A3A51519E9E",
+"D c #3D3D53539A9A",
+"F c #3D3D54549D9D",
+"G c #3F3F5353A0A0",
+"H c #3F3F5555A1A1",
+"J c #3A3A7878B8B8",
+"K c #3D3D7A7AB9B9",
+"L c #404052529C9C",
+"P c #424257579F9F",
+"I c #444456569E9E",
+"U c #40405656A0A0",
+"Y c #40405656A1A1",
+"T c #42425757A2A2",
+"R c #44445A5AA4A4",
+"E c #45455A5AA4A4",
+"W c #45455A5AA6A6",
+"Q c #46465959A7A7",
+"! c #46465C5CA2A2",
+"~ c #49495959A0A0",
+"^ c #49495D5DA2A2",
+"/ c #49495F5FA7A7",
+"( c #49495F5FA8A8",
+") c #52525E5EA1A1",
+"_ c #4B4B6060A5A5",
+"` c #4E4E6363A8A8",
+"' c #4F4F6363A9A9",
+"] c #46467575A9A9",
+"[ c #50506363A8A8",
+"{ c #54546767A9A9",
+"} c #54546868AAAA",
+"| c #5A5A6B6BABAB",
+" . c #58586C6CADAD",
+".. c #5C5C6E6EAEAE",
+"X. c #53536A6AB2B2",
+"o. c #5D5D7070B0B0",
+"O. c #7A7A79798585",
+"+. c #61617373B0B0",
+"@. c #61617474B3B3",
+"#. c #65657777B3B3",
+"$. c #66667878B4B4",
+"%. c #6B6B7A7AB6B6",
+"&. c #68687C7CB6B6",
+"*. c #6A6A7C7CB7B7",
+"=. c #6F6F7F7FB9B9",
+"-. c #73737777AFAF",
+";. c #4F4F8080B0B0",
+":. c #53538484B3B3",
+">. c #7A7AA8A8B6B6",
+",. c #45458787D1D1",
+"<. c #45458F8FDCDC",
+"1. c #4C4C9090D8D8",
+"2. c #58589393D7D7",
+"3. c #5E5E9595D1D1",
+"4. c #58589797DBDB",
+"5. c #4D4D9595E0E0",
+"6. c #54549999E2E2",
+"7. c #55559A9AE3E3",
+"8. c #9D9D1F1F4545",
+"9. c #818129295B5B",
+"0. c #A3A31F1F4343",
+"q. c #A5A52D2D5151",
+"w. c #828278787373",
+"e. c #808078787575",
+"r. c #80807A7A7878",
+"t. c #FDFD13131515",
+"y. c #CDCD63637575",
+"u. c #DFDF71717B7B",
+"i. c #FEFE68686767",
+"p. c #F0F06C6C7070",
+"a. c #FEFE72727070",
+"s. c #F9F976767878",
+"d. c #FDFD78787575",
+"f. c #FBFB7B7B7D7D",
+"g. c #8D8D6B6B9898",
+"h. c #929271719C9C",
+"j. c #87877979A7A7",
+"k. c #BCBC7C7C9696",
+"l. c #FEFE80807D7D",
+"z. c #92928E8E9191",
+"x. c #969691919090",
+"c. c #989891919191",
+"v. c #9F9F9E9E9D9D",
+"b. c #90908B8BB7B7",
+"n. c #8585ABABB1B1",
+"m. c #A3A38181A4A4",
+"M. c #A4A48383A6A6",
+"N. c #A4A49696B9B9",
+"B. c #9B9BAEAED5D5",
+"V. c #9F9FADADD3D3",
+"C. c #B4B4CACAD5D5",
+"Z. c #BCBCD7D7E8E8",
+"A. c #D4D487879797",
+"S. c #D7D789899898",
+"D. c #EBEB87878D8D",
+"F. c #FAFA85858686",
+"G. c #FCFC93939494",
+"H. c #FEFE9F9F9C9C",
+"J. c #FDFDA1A19E9E",
+"K. c #E7E7A1A1A9A9",
+"L. c #E9E9AEAEB6B6",
+"P. c #E8E8B2B2B7B7",
+"I. c #F2F2B8B8BEBE",
+"U. c #E2E2B9B9C2C2",
+"Y. c #F0F0BFBFC4C4",
+"T. c #C0C0D9D9E8E8",
+"R. c #EEEEC6C6CBCB",
+"E. c #EFEFD3D3D8D8",
+"W. c #E6E6D8D8E2E2",
+"Q. c None",
+/* pixels */
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"u.j.u 0.8.w 9.y.q 7 5 3 1 < , < ",
+"s Y.W.L.K.U.E.V.%.#.+...| { ` ; ",
+"t.G.l.a.i.d.s.p.) T 2.4.1.,.^ = ",
+"q.I.H.f.F.J.D.k.~ C 7.T.Z.<.I * ",
+"-.R.N.S.A.B.P.M.G b 5.>.n.J L % ",
+"e b.X.h.g.W &.m.N z 7.C.v.K C $ ",
+"0 =.` / W T V M l a 3.x.y ] x + ",
+"9 &./ W H A m k f c.z.:.;.t O.O ",
+"8 $.R H A b k f p i e.w.y r k o ",
+"4 @.o. .} [ _ ! T F D Z v c g ",
+"7 1 < , > : ; * & % + + O o o + ",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q."
+};
diff --git a/src/images/flags/FM.xpm b/src/images/flags/FM.xpm
new file mode 100644
index 0000000..7a4f788
--- /dev/null
+++ b/src/images/flags/FM.xpm
@@ -0,0 +1,163 @@
+/* XPM */
+static const char *FM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 141 2",
+" c black",
+". c #00001F1F7D7D",
+"X c #000021218181",
+"o c #000025258181",
+"O c #000027278383",
+"+ c #000029298585",
+"@ c #00002B2B8585",
+"# c #00002D2D8989",
+"$ c #00002F2F8989",
+"% c #000033338B8B",
+"& c #000035358D8D",
+"* c #000039398F8F",
+"= c #00003B3B9393",
+"- c #00003D3D9393",
+"; c #000041419797",
+": c #000047479B9B",
+"> c #00004D4D9F9F",
+", c #03035353A3A3",
+"< c #0B0B5959A5A5",
+"1 c #11115D5DA9A9",
+"2 c #19196363ADAD",
+"3 c #1F1F6969B1B1",
+"4 c #25256D6DB3B3",
+"5 c #27276F6FB5B5",
+"6 c #2B2B7373B5B5",
+"7 c #2D2D7373B5B5",
+"8 c #31317575B9B9",
+"9 c #33337777B9B9",
+"0 c #35357979BBBB",
+"q c #39397B7BBDBD",
+"w c #3B3B7D7DBDBD",
+"e c #3D3D7D7DBFBF",
+"r c #3F3F7F7FBFBF",
+"t c #41417F7FBFBF",
+"y c #41418181BFBF",
+"u c #67679595C2C2",
+"i c #6A6A9797C4C4",
+"p c #6C6C9999C6C6",
+"a c #6E6E9999C6C6",
+"s c #6E6E9A9AC6C6",
+"d c #6F6F9B9BC7C7",
+"f c #6F6F9B9BC8C8",
+"g c #70709C9CC7C7",
+"h c #70709C9CC8C8",
+"j c #72729D9DC9C9",
+"k c #75759F9FCACA",
+"l c #7777A1A1CBCB",
+"z c #7B7BA2A2CACA",
+"x c #7878A1A1CCCC",
+"c c #7A7AA2A2CCCC",
+"v c #7A7AA4A4CDCD",
+"b c #7C7CA4A4CACA",
+"n c #7D7DA4A4CBCB",
+"m c #7C7CA5A5CECE",
+"M c #7F7FA5A5CCCC",
+"N c #7F7FA6A6CCCC",
+"B c #7E7EA6A6CECE",
+"V c #7E7EA7A7CFCF",
+"C c #8282A8A8CDCD",
+"Z c #8484A9A9CFCF",
+"A c #8585AAAACFCF",
+"S c #8585ABABCFCF",
+"D c #8080A8A8D0D0",
+"F c #8181A9A9D0D0",
+"G c #8181AAAAD1D1",
+"H c #8282A9A9D0D0",
+"J c #8282A9A9D1D1",
+"K c #8383A9A9D1D1",
+"L c #8383ABABD2D2",
+"P c #8484ABABD2D2",
+"I c #8585ACACD2D2",
+"U c #8686ACACD3D3",
+"Y c #8686ADADD2D2",
+"T c #8787ADADD3D3",
+"R c #8989ADADD2D2",
+"E c #8888ADADD4D4",
+"W c #8888AEAED4D4",
+"Q c #8989AFAFD5D5",
+"! c #8A8AAEAED4D4",
+"~ c #8A8AAFAFD4D4",
+"^ c #8C8CAFAFD3D3",
+"/ c #8F8FB1B1D4D4",
+"( c #8E8EB1B1D6D6",
+") c #8F8FB2B2D5D5",
+"_ c #8E8EB2B2D6D6",
+"` c #9191B4B4D7D7",
+"' c #9393B4B4D7D7",
+"] c #9595B6B6D7D7",
+"[ c #9090B5B5D8D8",
+"{ c #9191B4B4D8D8",
+"} c #9191B5B5D8D8",
+"| c #9292B6B6D9D9",
+" . c #9292B7B7D9D9",
+".. c #9595B7B7DADA",
+"X. c #9696B7B7D8D8",
+"o. c #9797B9B9DBDB",
+"O. c #9797BABADBDB",
+"+. c #9898B8B8D8D8",
+"@. c #9999B9B9D9D9",
+"#. c #9999B9B9DADA",
+"$. c #9898BABADBDB",
+"%. c #9B9BBBBBDBDB",
+"&. c #9A9ABCBCDCDC",
+"*. c #9B9BBCBCDDDD",
+"=. c #9C9CBCBCDBDB",
+"-. c #9D9DBDBDDEDE",
+";. c #9D9DBEBEDEDE",
+":. c #9E9EBEBEDDDD",
+">. c #9F9FBEBEDDDD",
+",. c #9F9FBFBFDFDF",
+"<. c #A0A0BFBFDDDD",
+"1. c #A3A3C0C0DEDE",
+"2. c #A5A5C0C0DBDB",
+"3. c #A5A5C2C2DFDF",
+"4. c #A6A6C1C1DCDC",
+"5. c #A8A8C2C2DBDB",
+"6. c #ADADC6C6DDDD",
+"7. c #AEAEC7C7DFDF",
+"8. c #A5A5C3C3E0E0",
+"9. c #A8A8C4C4E0E0",
+"0. c #A8A8C4C4E1E1",
+"q. c #AAAAC6C6E2E2",
+"w. c #ABABC7C7E2E2",
+"e. c #ADADC8C8E3E3",
+"r. c #AEAEC8C8E4E4",
+"t. c #AEAEC9C9E4E4",
+"y. c #B1B1C9C9E0E0",
+"u. c #B0B0CACAE4E4",
+"i. c #B5B5CCCCE4E4",
+"p. c #B9B9CFCFE4E4",
+"a. c #B8B8CECEE6E6",
+"s. c #B9B9D0D0E6E6",
+"d. c #BABAD0D0E6E6",
+"f. c #BDBDD3D3E7E7",
+"g. c #BFBFD2D2E5E5",
+"h. c #BFBFD4D4E9E9",
+"j. c gray96",
+"k. c #F6F6F6F6F6F6",
+"l. c #FBFBFBFBFBFB",
+"z. c gray99",
+"x. c None",
+/* pixels */
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"y y y y e w 0 8 6 4 3 2 1 < , > ",
+"y u.u.r.e.w.9.s.a.-.<.O.$.o.` : ",
+"y u.,.-.&.$.| z.l.! ! P Z B / ; ",
+"t r.-.&.O. .| 3.3.T J V B z ^ = ",
+"e e.&.o.h.f.` Q T T y.7.l k R & ",
+"w 9.o.| l.l.i.T Z d.k.j.j d S $ ",
+"8 9..._ s.a.R Z B B 6.4.j s Z @ ",
+"7 9.| _ Q T J $.] l d d s i n O ",
+"5 1._ R T J v j.j.d d s i u B . ",
+"3 -.-.$.$.] / 3.<.S Z Z B n z . ",
+"2 1 < , > : - - & % $ @ . o . . ",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x."
+};
diff --git a/src/images/flags/FO.xpm b/src/images/flags/FO.xpm
new file mode 100644
index 0000000..645271d
--- /dev/null
+++ b/src/images/flags/FO.xpm
@@ -0,0 +1,128 @@
+/* XPM */
+static const char *FO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 106 2",
+" c black",
+". c #00000000B1B1",
+"X c #00000000B5B5",
+"o c #00000000BDBD",
+"O c #00000000C3C3",
+"+ c #00000303D7D7",
+"@ c #00000707D9D9",
+"# c #00000F0FDBDB",
+"$ c #00001111DBDB",
+"% c #14144C4CDADA",
+"& c #19195050DBDB",
+"* c #1F1F5555DDDD",
+"= c #20205555DDDD",
+"- c #24245959DEDE",
+"; c #25255959DEDE",
+": c #2A2A5E5EE0E0",
+"> c #2B2B5E5EE0E0",
+", c #36366565DEDE",
+"< c #2E2E6060E2E2",
+"1 c #2F2F6262E2E2",
+"2 c #30306363E2E2",
+"3 c #34346565E3E3",
+"4 c #35356666E3E3",
+"5 c #36366767E3E3",
+"6 c #3A3A6969E4E4",
+"7 c #3B3B6B6BE5E5",
+"8 c #3F3F6D6DE1E1",
+"9 c #40406E6EE5E5",
+"0 c #41417070E6E6",
+"q c #45457272E7E7",
+"w c #46467474E8E8",
+"e c #4B4B7676E5E5",
+"r c #49497777E8E8",
+"t c #4B4B7777E9E9",
+"y c #4F4F7A7AE9E9",
+"u c #54547D7DE7E7",
+"i c #50507B7BE9E9",
+"p c #51517B7BE9E9",
+"a c #54547E7EEAEA",
+"s c #54547F7FEAEA",
+"d c #58588282ECEC",
+"f c #59598282ECEC",
+"g c #6F6F9393EDED",
+"h c #70709494EEEE",
+"j c #76769898EFEF",
+"k c #77779999F0F0",
+"l c #B3B300000000",
+"z c #BFBF00000000",
+"x c #D9D900000000",
+"c c #DBDB00000000",
+"v c #DBDB31311A1A",
+"b c #DDDD36361F1F",
+"n c #DEDE3B3B2525",
+"m c #E0E040402B2B",
+"M c #E2E245453030",
+"N c #E3E349493434",
+"B c #E3E34A4A3636",
+"V c #E0E04F4F3B3B",
+"C c #E5E54E4E3A3A",
+"Z c #E5E54F4F3B3B",
+"A c #E6E654544040",
+"S c #E7E759594646",
+"D c #E8E85D5D4B4B",
+"F c #E9E95E5E4B4B",
+"G c #E9E962624F4F",
+"H c #E6E661615050",
+"J c #E9E963635151",
+"K c #EAEA65655353",
+"L c #EBEB67675454",
+"P c #EEEE81817373",
+"I c #EFEF82827474",
+"U c #CDCDCDCDCDCD",
+"Y c #D1D1CFCFCFCF",
+"T c gray82",
+"R c LightGray",
+"E c #D5D5D5D5D5D5",
+"W c #D7D7D7D7D7D7",
+"Q c gray85",
+"! c gray86",
+"~ c #DDDDDDDDDDDD",
+"^ c #E1E1E1E1E1E1",
+"/ c gray89",
+"( c gray90",
+") c #E7E7E7E7E7E7",
+"_ c #E9E9E9E9E9E9",
+"` c gray92",
+"' c gray93",
+"] c #EFEFEFEFEFEF",
+"[ c #F1F1F1F1F1F1",
+"{ c gray95",
+"} c #F2F2F2F2F3F3",
+"| c #F3F3F3F3F3F3",
+" . c #F4F4F4F4F4F4",
+".. c gray96",
+"X. c #F6F6F6F6F6F6",
+"o. c gray97",
+"O. c #F8F8F8F8F8F8",
+"+. c #F9F9F9F9F9F9",
+"@. c gray98",
+"#. c #FBFBFBFBFBFB",
+"$. c #F9F9FEFEFEFE",
+"%. c gray99",
+"&. c #FDFDFDFDFDFD",
+"*. c #FEFEFEFEFEFE",
+"=. c gray100",
+"-. c None",
+/* pixels */
+"-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.",
+"-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.",
+"-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.",
+"| | | | $ c @ ] ' ' ` _ ) ( / ^ ",
+"| =.=.=.j L h =.#.#.#. at .@. at .X.~ ",
+"| =.=.=.f L y =.#. at .@.O.o.X.X.! ",
+"| =.=.$.d K w $. at .@. at .X.X.X.X.! ",
+"# j d a d K w 7 7 5 3 ; - * 8 X ",
+"c L K G D S A Z B m m n b v V l ",
+"$ g y r q A 7 3 1 < - * & % , . ",
+"X.$. at .@.9 Z 5 X.o.X.| | ] | | T ",
+"] $. at .@.7 N < X.X.| | | | | | U ",
+"` @. at .@.u H e X.X.X.X.| | | | U ",
+"` ) ( / O z o ! E E T T U U U U ",
+"-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.",
+"-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-."
+};
diff --git a/src/images/flags/FR.xpm b/src/images/flags/FR.xpm
new file mode 100644
index 0000000..9af48e5
--- /dev/null
+++ b/src/images/flags/FR.xpm
@@ -0,0 +1,153 @@
+/* XPM */
+static const char *FR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 131 2",
+" c black",
+". c #17174747A5A5",
+"X c #23234F4FABAB",
+"o c #2D2D5757AFAF",
+"O c #35355F5FB5B5",
+"+ c #3F3F6767B9B9",
+"@ c #49497171BDBD",
+"# c #53537777C3C3",
+"$ c #5B5B7F7FC7C7",
+"% c #63638585CBCB",
+"& c #69698989CDCD",
+"* c #6F6F8F8FD1D1",
+"= c #71719191D1D1",
+"- c #73739393D3D3",
+"; c #73739595D3D3",
+": c #C5C500000000",
+"> c #C7C700000000",
+", c #CBCB00000000",
+"< c #CDCD00000000",
+"1 c #D3D300000000",
+"2 c #D5D500000000",
+"3 c #DBDB00000000",
+"4 c #DDDD00000000",
+"5 c #E1E100000000",
+"6 c #E5E500000000",
+"7 c #E7E700000000",
+"8 c #EBEB00000000",
+"9 c #EFEF07070000",
+"0 c #F1F113130000",
+"q c #E6E64D4D3E3E",
+"w c #E8E852524343",
+"e c #E9E956564848",
+"r c #EAEA57574848",
+"t c #EAEA57574A4A",
+"y c #EBEB5D5D4F4F",
+"u c #ECEC5E5E5050",
+"i c #E8E863635555",
+"p c #EEEE63635555",
+"a c #EEEE64645656",
+"s c #EEEE64645757",
+"d c #E9E966665959",
+"f c #E9E966665A5A",
+"g c #EAEA69695D5D",
+"h c #EAEA6A6A5D5D",
+"j c #EFEF69695C5C",
+"k c #F0F06A6A5C5C",
+"l c #F0F06C6C5D5D",
+"z c #ECEC6D6D6161",
+"x c #ECEC6E6E6262",
+"c c #EDED74746868",
+"v c #EFEF78786C6C",
+"b c #F1F170706363",
+"n c #F1F170706464",
+"m c #F2F271716464",
+"M c #F3F377776A6A",
+"N c #F3F377776B6B",
+"B c #F1F17E7E7272",
+"V c #F5F57D7D7272",
+"C c #F2F284847878",
+"Z c #F4F488887E7E",
+"A c #9F9F9F9F9F9F",
+"S c #A7A7A7A7A7A7",
+"D c gray68",
+"F c #B3B3B0B0B0B0",
+"G c gray72",
+"H c gray",
+"J c #9797ACACD8D8",
+"K c #9C9CB0B0DADA",
+"L c #A0A0B4B4DDDD",
+"P c #A0A0B5B5DDDD",
+"I c #A1A1B5B5DDDD",
+"U c #A3A3B5B5DCDC",
+"Y c #A5A5B8B8DFDF",
+"T c #A5A5B9B9DFDF",
+"R c #A7A7B9B9DDDD",
+"E c #A6A6B9B9E0E0",
+"W c #A9A9BCBCE1E1",
+"Q c #A9A9BDBDE1E1",
+"! c #AAAABDBDE0E0",
+"~ c #AAAABDBDE1E1",
+"^ c #AEAEBFBFE3E3",
+"/ c #AFAFBFBFE2E2",
+"( c #AEAEBFBFE4E4",
+") c #AEAEC0C0E4E4",
+"_ c #B1B1C2C2E5E5",
+"` c #B1B1C3C3E5E5",
+"' c #B2B2C3C3E5E5",
+"] c #B3B3C3C3E4E4",
+"[ c #B4B4C5C5E7E7",
+"{ c #B7B7C7C7E6E6",
+"} c #B7B7C8C8E8E8",
+"| c #BABAC9C9E8E8",
+" . c #BEBECCCCE9E9",
+".. c #F5F58D8D8383",
+"X. c #F7F793938989",
+"o. c #F8F897978E8E",
+"O. c #CECECECECECE",
+"+. c gray81",
+"@. c #D2D2D2D2D2D2",
+"#. c #D5D5D5D5D5D5",
+"$. c gainsboro",
+"%. c #DFDFDFDFDFDF",
+"&. c #C0C0CECEEAEA",
+"*. c #C1C1CFCFEBEB",
+"=. c #C3C3D0D0ECEC",
+"-. c #C3C3D1D1ECEC",
+";. c #C4C4D2D2EDED",
+":. c #C4C4D3D3EDED",
+">. c #E2E2E2E2E2E2",
+",. c #E4E4E4E4E4E4",
+"<. c gray90",
+"1. c #E6E6E6E6E6E6",
+"2. c #E7E7E7E7E7E7",
+"3. c gray91",
+"4. c #E9E9E9E9E9E9",
+"5. c #E9E9E9E9EAEA",
+"6. c #EAEAEAEAEAEA",
+"7. c gray92",
+"8. c #ECECEBEBEBEB",
+"9. c #ECECECECECEC",
+"0. c gray93",
+"q. c #EEEEEEEEEEEE",
+"w. c #EFEFEFEFEFEF",
+"e. c gray94",
+"r. c #F1F1F1F1F1F1",
+"t. c #F3F3F3F3F3F3",
+"y. c #F4F4F4F4F4F4",
+"u. c #F6F6F6F6F6F6",
+"i. c gray97",
+"p. c #F8F8F8F8F8F8",
+"a. c None",
+/* pixels */
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"; ; ; ; - $.$.#. at .O.@.0 9 8 6 6 ",
+"; :.:.*.*.p.i.i.i.i.t.o.X...Z 5 ",
+"; :.} [ ' q.7.6.6.6.<.V N m C 4 ",
+"- *.[ ' ) w.7.q.6.6.<.M m l B 4 ",
+"* &.' ( ~ q.q.8.6.<.<.b j s v 2 ",
+"& .) Q Y t.q.q.q.6.6.j s u c 2 ",
+"% } Q E U q.q.q.6.6.<.p y e x < ",
+"$ { E U K q.q.6.2.<.<.y e w h , ",
+"# ' K K J 7.6.<.<.<.>.e w q f > ",
+"@ / ~ Y U q.q.6.6.<.<.x h f i > ",
+"+ O o X . H G F D S A < , > : > ",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a."
+};
diff --git a/src/images/flags/GA.xpm b/src/images/flags/GA.xpm
new file mode 100644
index 0000000..b1e0ae9
--- /dev/null
+++ b/src/images/flags/GA.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *GA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #000000006D6D",
+"X c #000000007D7D",
+"o c #000000007F7F",
+"O c #000041410000",
+"+ c #000047470000",
+"@ c #000049490000",
+"# c #000051510000",
+"$ c #000055550000",
+"% c #000059590000",
+"& c #00005F5F0000",
+"* c #000065650000",
+"= c #00006B6B0000",
+"- c #00006F6F0000",
+"; c #000073730000",
+": c #000077770000",
+"> c #00007B7B0000",
+", c #00007D7D0000",
+"< c #000000008383",
+"1 c #000000008787",
+"2 c #000000008B8B",
+"3 c #000000008D8D",
+"4 c #000000009191",
+"5 c #000000009595",
+"6 c #000000009999",
+"7 c #000000009D9D",
+"8 c #00000101A1A1",
+"9 c #00000707A3A3",
+"0 c #00000D0DA7A7",
+"q c #00001313A9A9",
+"w c #00001D1DAFAF",
+"e c #00002323B3B3",
+"r c #00002929B7B7",
+"t c #00003F3FA7A7",
+"y c #36366666C4C4",
+"u c #3A3A6969C6C6",
+"i c #3E3E6B6BC7C7",
+"p c #49497373B8B8",
+"a c #4D4D7676BABA",
+"s c #51517979BBBB",
+"d c #55557D7DBDBD",
+"f c #43436F6FC9C9",
+"g c #47477373CBCB",
+"h c #4C4C7676CDCD",
+"j c #53537B7BCACA",
+"k c #51517A7ACFCF",
+"l c #55557C7CCACA",
+"z c #55557C7CCCCC",
+"x c #58587F7FCCCC",
+"c c #54547E7ED1D1",
+"v c #000081810000",
+"b c #000083830000",
+"n c #000089890000",
+"m c #2C2CA5A52C2C",
+"M c #3232A8A82626",
+"N c #3737AAAA2B2B",
+"B c #3131A8A83131",
+"V c #3737AAAA3737",
+"C c #3D3DADAD3131",
+"Z c #3D3DADAD3D3D",
+"A c #4242B0B03636",
+"S c #4747B2B23C3C",
+"D c #4242B0B04242",
+"F c #4747B3B34747",
+"G c #4F4FB3B34444",
+"H c #4C4CB4B44242",
+"J c #4949B1B14949",
+"K c #4C4CB5B54C4C",
+"L c #4E4EB4B44E4E",
+"P c #5151B7B74747",
+"I c #5656B9B94B4B",
+"U c #5151B7B75151",
+"Y c #5353B7B75353",
+"T c #5454B9B95454",
+"R c #5858B9B95757",
+"E c #5B5BBCBC5151",
+"W c #5E5EBEBE5454",
+"Q c #5959BBBB5959",
+"! c #5C5CBBBB5C5C",
+"~ c #5C5CBDBD5C5C",
+"^ c #5F5FBEBE5F5F",
+"/ c #6262BFBF5959",
+"( c #6161BEBE6060",
+") c #6565C1C15C5C",
+"_ c #6565C0C06565",
+"` c #6969C2C26969",
+"' c #6D6DC3C36D6D",
+"] c #7070C5C57171",
+"[ c #7474C7C77474",
+"{ c #7777C8C87777",
+"} c #7979C9C97979",
+"| c #7B7BC9C97A7A",
+" . c #7B7BCACA7B7B",
+".. c #5A5A8080C0C0",
+"X. c #5E5E8383C2C2",
+"o. c #5B5B8282CDCD",
+"O. c #5F5F8484CFCF",
+"+. c #59598282D3D3",
+"@. c #5E5E8585D4D4",
+"#. c #62628686C4C4",
+"$. c #64648787C2C2",
+"%. c #66668A8AC6C6",
+"&. c #6A6A8E8EC8C8",
+"*. c #62628686D0D0",
+"=. c #62628989D6D6",
+"-. c #65658A8AD2D2",
+";. c #67678D8DD8D8",
+":. c #69698D8DD3D3",
+">. c #6F6F9191CACA",
+",. c #6D6D9090D5D5",
+"<. c #73739494CDCD",
+"1. c #77779898CECE",
+"2. c #71719393D7D7",
+"3. c #75759696D8D8",
+"4. c #79799999DADA",
+"5. c #7D7D9D9DDBDB",
+"6. c #8080CDCD7979",
+"7. c #E3E3E3E30000",
+"8. c #E5E5E5E50000",
+"9. c #E7E7E7E70000",
+"0. c #FDFDFDFD0000",
+"q. c #F2F2F2F21414",
+"w. c #F3F3F3F31919",
+"e. c #F3F3F3F31A1A",
+"r. c #F4F4F4F41F1F",
+"t. c #F4F4F4F42020",
+"y. c #F5F5F5F52424",
+"u. c #F5F5F5F52525",
+"i. c #F6F6F6F62A2A",
+"p. c #F6F6F6F62B2B",
+"a. c #F7F7F7F72F2F",
+"s. c #F7F7F7F73030",
+"d. c #F4F4F4F43636",
+"f. c #F4F4F5F53B3B",
+"g. c #F5F5F5F53F3F",
+"h. c #F8F8F8F83535",
+"j. c #F8F8F8F83636",
+"k. c #F9F9F9F93A3A",
+"l. c #F9F9F9F93B3B",
+"z. c #F9F9F9F93C3C",
+"x. c #FAFAFAFA4040",
+"c. c #FAFAFAFA4141",
+"v. c #FBFBFBFB4545",
+"b. c #FBFBFBFB4646",
+"n. c #FBFBFCFC4949",
+"m. c #FCFCFCFC4B4B",
+"M. c #FCFCFCFC4F4F",
+"N. c #FDFDFCFC5050",
+"B. c #FDFDFDFD5353",
+"V. c #FDFDFDFD5454",
+"C. c #FEFEFEFE5858",
+"Z. c #FDFDFDFD6F6F",
+"A. c #FEFEFEFE7373",
+"S. c #FEFEFEFE7676",
+"D. c #80809F9FDDDD",
+"F. c #8383A2A2DFDF",
+"G. c #9090ABABD8D8",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"b b b b b , > : ; - = * & % $ # ",
+"b . . .[ [ ] ' ' ( ( ! R U L @ ",
+"b .( ~ Q T U L J D Z V B m J O ",
+"n 6./ / W E I P H S A C N M P + ",
+"0.S.C.V.N.m.b.c.l.j.s.p.u.r.g.8.",
+"0.A.V.m.m.b.x.k.j.s.p.u.r.w.f.8.",
+"0.Z.N.n.b.x.k.j.a.p.u.r.w.q.d.7.",
+"t G.1.<.>.&.%.#.X...d s a p $.. ",
+"r F.;.=. at .+.c k h g f i u y l 1 ",
+"e 5.5.4.3.2.,.:.-.*.*.x x l j X ",
+"w q 0 9 8 7 6 5 4 2 2 2 1 < X X ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/GB.xpm b/src/images/flags/GB.xpm
new file mode 100644
index 0000000..e4c1089
--- /dev/null
+++ b/src/images/flags/GB.xpm
@@ -0,0 +1,162 @@
+/* XPM */
+static const char *GB_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 140 2",
+" c black",
+". c #000011116767",
+"X c #000013136B6B",
+"o c #000013136D6D",
+"O c #000015157070",
+"+ c #000017177373",
+"@ c #141431317E7E",
+"# c #454535356E6E",
+"$ c #18181B1B9A9A",
+"% c #080825259090",
+"& c #0C0C28289393",
+"* c #11112D2D9191",
+"= c #11112C2C9C9C",
+"- c #191934349898",
+"; c #3A3A3F3FA4A4",
+": c #37375656AEAE",
+"> c #3D3D5C5CB0B0",
+", c #3F3F5E5EB2B2",
+"< c #41414949A7A7",
+"1 c #55555E5EABAB",
+"2 c #43436969A2A2",
+"3 c #48486666B8B8",
+"4 c #49496B6BB6B6",
+"5 c #54546060AFAF",
+"6 c #57576666B6B6",
+"7 c #5A5A6666B8B8",
+"8 c #6B6B7272A4A4",
+"9 c #5C5C7474C6C6",
+"0 c #5A5A8181B9B9",
+"q c #61618181C0C0",
+"w c #62628484C1C1",
+"e c #64648383C3C3",
+"r c #64648383C6C6",
+"t c #6E6E8080C3C3",
+"y c #71718080C1C1",
+"u c #72728282C4C4",
+"i c #74748E8ED2D2",
+"p c #7B7B9797C6C6",
+"a c #7A7A9E9EC0C0",
+"s c #7B7B9D9DC5C5",
+"d c #7E7E9191D5D5",
+"f c #848417173434",
+"g c #85851B1B3838",
+"h c #85851F1F3A3A",
+"j c #949444446363",
+"k c #9C9C51516F6F",
+"l c #ACAC61617D7D",
+"z c #ACAC60607E7E",
+"x c #F5F52B2B2B2B",
+"c c #F5F52E2E2E2E",
+"v c #FAFA29292B2B",
+"b c #FCFC2B2B2D2D",
+"n c #FBFB2F2F3131",
+"m c #F7F734343434",
+"M c #FEFE32323434",
+"N c #FCFC36363838",
+"B c #F9F939393939",
+"V c #FAFA3F3F3F3F",
+"C c #FFFF3D3D3D3D",
+"Z c #E5E542424141",
+"A c #FEFE45454545",
+"S c #FFFF4C4C4C4C",
+"D c #FFFF4E4E4E4E",
+"F c #FBFB52524343",
+"G c #F9F953534646",
+"H c #FDFD54544848",
+"J c #FFFF54545454",
+"K c #FFFF55555555",
+"L c #FFFF57575858",
+"P c #FFFF59595959",
+"I c #FFFF5C5C5C5C",
+"U c #FFFF5F5F5F5F",
+"Y c #EBEB60604D4D",
+"T c #E8E860605C5C",
+"R c #F9F963635F5F",
+"E c #FFFF60606161",
+"W c #FFFF64646464",
+"Q c #FFFF65656969",
+"! c #FFFF6D6D6969",
+"~ c #ADAD63638181",
+"^ c #F3F381817E7E",
+"/ c #F7F787877878",
+"( c #FCFC82827F7F",
+") c #FEFE8A8A7C7C",
+"_ c #92929999BEBE",
+"` c #BFBF9999B5B5",
+"' c #82829595CECE",
+"] c #8C8C9C9CCFCF",
+"[ c #86869696D5D5",
+"{ c #8D8D9D9DD0D0",
+"} c #8D8DBCBCD7D7",
+"| c #9292A1A1D3D3",
+" . c #9E9EAAAAD2D2",
+".. c #9F9FAFAFDCDC",
+"X. c #9090B2B2D0D0",
+"o. c #9393B3B3D3D3",
+"O. c #A4A4A8A8CACA",
+"+. c #A3A3AFAFD5D5",
+"@. c #A2A2B0B0DBDB",
+"#. c #A1A1B0B0DDDD",
+"$. c #B7B7C3C3DADA",
+"%. c #BCBCC9C9EEEE",
+"&. c #B8B8D5D5ECEC",
+"*. c #F0F08A8A8A8A",
+"=. c #F7F78B8B8B8B",
+"-. c #FFFF8E8E8585",
+";. c #FFFF93938888",
+":. c #FFFF94948C8C",
+">. c #F4F49A9A9D9D",
+",. c #F4F4A2A2ACAC",
+"<. c #FFFFA5A5A7A7",
+"1. c #FFFFB1B1AAAA",
+"2. c #E1E1BEBEDFDF",
+"3. c #FFFFC1C1BDBD",
+"4. c #C5C5C0C0DBDB",
+"5. c #C9C9C8C8E3E3",
+"6. c #C9C9D5D5E8E8",
+"7. c #CBCBD4D4E9E9",
+"8. c #CCCCD6D6E9E9",
+"9. c #CFCFD6D6E8E8",
+"0. c #D4D4D5D5EFEF",
+"q. c #D0D0DCDCEDED",
+"w. c #D9D9DDDDEDED",
+"e. c #DBDBE1E1F4F4",
+"r. c #FFFFE8E8E8E8",
+"t. c #FFFFEDEDECEC",
+"y. c #F9F9FFFFFFFF",
+"u. c #FBFBFCFCFCFC",
+"i. c #FDFDFCFCF8F8",
+"p. c #FEFEFDFDF9F9",
+"a. c #FCFCFDFDFCFC",
+"s. c #FDFDFDFDFDFD",
+"d. c #FEFEFDFDFDFD",
+"f. c #FEFEFEFEFDFD",
+"g. c #FFFFFFFFFDFD",
+"h. c #FEFEFEFEFFFF",
+"j. c #FFFFFEFEFEFE",
+"k. c #FFFFFFFFFEFE",
+"l. c gray100",
+"z. c None",
+/* pixels */
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"_ &.p r e q w.~ l w.4 3 > 0 k s ",
+"O.1.h.e. at ...h.:.-.h.| { 5.) p.X.",
+"w %.<.3.h.[ h.Q E h.i ,.=.h. .- ",
+"w #.d 2.( h.h.I L h.! r.q.< u * ",
+"w.h.h.h.h.h.h.K D h.h.h.h.h.h.8.",
+"l ;.E R L J D D A V B m c c G g ",
+"w.h.h.h.h.h.h.C N h.u.y.u.u.u.6.",
+"> { 7 0.t.R h.M M h.p.B ` $ 5 o ",
+": +.h.^ *.9 h.b v h.: u.>.T ' . ",
+"o.h./ 4.y t h.H F h.6 1 $.i.Y 8 ",
+"a j 2 = & % 8.g f 7.O O o @ } # ",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z."
+};
diff --git a/src/images/flags/GD.xpm b/src/images/flags/GD.xpm
new file mode 100644
index 0000000..a9efe6a
--- /dev/null
+++ b/src/images/flags/GD.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *GD_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #10109C9C1010",
+"X c #171799991414",
+"o c #19199B9B1919",
+"O c #1F1F9C9C1F1F",
+"+ c #1F1F9F9F1F1F",
+"@ c #1414A0A01414",
+"# c #1A1AA3A31A1A",
+"$ c #3636B0B00B0B",
+"% c #2020A6A62020",
+"& c #2525A1A12525",
+"* c #2525A2A22525",
+"= c #2626A6A62626",
+"- c #2B2BA3A32B2B",
+"; c #2A2AA4A42B2B",
+": c #3131A6A62B2B",
+"> c #3838A5A52424",
+", c #41419C9C2F2F",
+"< c #47479B9B3232",
+"1 c #4B4B9E9E3636",
+"2 c #4F4FA1A13B3B",
+"3 c #4949ACAC3030",
+"4 c #5353A4A43F3F",
+"5 c #5A5ABFBF2C2C",
+"6 c #60608C8C2C2C",
+"7 c #7070AEAE1919",
+"8 c #4545B1B14545",
+"9 c #4545B2B24545",
+"0 c #4646B2B24646",
+"q c #4B4BB4B44B4B",
+"w c #4949B9B94949",
+"e c #5858A6A64444",
+"r c #5A5AACAC4949",
+"t c #5050B2B24040",
+"y c #5F5FB9B94B4B",
+"u c #5050B5B55050",
+"i c #5454BABA5454",
+"p c #5B5BBCBC5959",
+"a c #6767B2B24949",
+"s c #7D7DA0A04E4E",
+"d c #7676B9B96666",
+"f c #7B7BB9B96A6A",
+"g c #7F7FBDBD6F6F",
+"h c #5C5CC0C05C5C",
+"j c #6464C8C84444",
+"k c #D7D700000000",
+"l c #DDDD00000000",
+"z c #DFDF00000000",
+"x c #E3E300000000",
+"c c #E5E500000000",
+"v c #E7E700000000",
+"b c #E9E900000000",
+"n c #EBEB00000000",
+"m c #EDED00000000",
+"M c #EFEF00000000",
+"N c #F1F100000000",
+"B c #F3F300000000",
+"V c #F5F500000000",
+"C c #F7F700000000",
+"Z c #F9F900000000",
+"A c #FBFB00000000",
+"S c #FDFD00000000",
+"D c red",
+"F c #E3E323230000",
+"G c #E1E13B3B0000",
+"H c #E7E73D3D0000",
+"J c #EDED3F3F0000",
+"K c #C3C370703636",
+"L c #E9E941410000",
+"P c #EDED5F5F0000",
+"I c #F7F75D5D0000",
+"U c #F5F55E5E3737",
+"Y c #F5F56F6F0000",
+"T c #FBFB73730000",
+"R c #FDFD73730000",
+"E c #FDFD77770000",
+"W c #F6F664643C3C",
+"Q c #CACA7B7B4646",
+"! c #F8F86B6B4343",
+"~ c #F8F870704848",
+"^ c #8787BDBD3F3F",
+"/ c #8989BABA3131",
+"( c #9B9BBDBD2A2A",
+") c #8B8BBBBB4F4F",
+"_ c #8A8AACAC6262",
+"` c #8484BFBF7373",
+"' c #8686BFBF7676",
+"] c #9F9FBABA7B7B",
+"[ c #B3B3C4C40E0E",
+"{ c #A0A0C4C43A3A",
+"} c #A9A9C3C33636",
+"| c #8080D3D35F5F",
+" . c #9C9CC8C85454",
+".. c #8888C2C27979",
+"X. c #8989C4C47A7A",
+"o. c #AFAFCACA4646",
+"O. c #FDFD89890000",
+"+. c #DFDF89895555",
+"@. c #D7D7C5C51F1F",
+"#. c #C3C3D4D43F3F",
+"$. c #C9C9D2D23131",
+"%. c #DDDDCECE3A3A",
+"&. c #F2F2D1D11313",
+"*. c #F3F3D4D41919",
+"=. c #F4F4D4D41E1E",
+"-. c #E5E5CECE3636",
+";. c #F5F5CECE2424",
+":. c #F0F0CCCC2F2F",
+">. c #F4F4C7C73636",
+",. c #F2F2CDCD3232",
+"<. c #F5F5C9C93B3B",
+"1. c #F4F4CFCF3939",
+"2. c #F5F5D4D42323",
+"3. c #F6F6D4D42A2A",
+"4. c #F6F6D7D72929",
+"5. c #F7F7D6D62F2F",
+"6. c #F7F7D9D92E2E",
+"7. c #F3F3D0D03535",
+"8. c #F5F5D1D13D3D",
+"9. c #F8F8D3D33434",
+"0. c #F9F9D6D63C3C",
+"q. c #F8F8DCDC3434",
+"w. c #F8F8DCDC3737",
+"e. c #F9F9DCDC3A3A",
+"r. c #F9F9DFDF3D3D",
+"t. c #D5D5DFDF5C5C",
+"y. c #D8D8DDDD5858",
+"u. c #E9E9D7D75151",
+"i. c #F7F7C8C85353",
+"p. c #F7F7CDCD5D5D",
+"a. c #F6F6D3D34242",
+"s. c #F7F7D5D54646",
+"d. c #F7F7D6D64B4B",
+"f. c #FAFADBDB4242",
+"g. c #FBFBDCDC4747",
+"h. c #FCFCDBDB4B4B",
+"j. c #F3F3DDDD5353",
+"k. c #F8F8D8D85050",
+"l. c #F9F9DBDB5555",
+"z. c #F9F9DADA5757",
+"x. c #F9F9DADA5858",
+"c. c #FAFADDDD5C5C",
+"v. c #FBFBDDDD6060",
+"b. c #FCFCDDDD6565",
+"n. c #FAFAE0E04242",
+"m. c #FBFBE0E04747",
+"M. c #FCFCE1E14C4C",
+"N. c #FDFDE3E35151",
+"B. c #FDFDE5E55454",
+"V. c #FEFEE5E55959",
+"C. c #FCFCE0E06969",
+"Z. c #FDFDE2E26D6D",
+"A. c #FDFDE2E27171",
+"S. c #FEFEE2E27474",
+"D. c #FEFEE5E57777",
+"F. c #FEFEE4E47979",
+"G. c #FEFEE4E47B7B",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"D D D D O.T D E T A I Y B B m m ",
+"D ] G.G.G.G.A.Z.C.b.v.c.x.i.s b ",
+"D X.j t.V.V.B.M.m.n.r.w.$.5 r v ",
+"D ..h p .u.h.g.f.0.-./ : = e v ",
+"A ' y.i i y o.~ ! } 3 ; * % 4 v ",
+"D ` j.+.q 0 Q <.>.K ; * + # 2 v ",
+"D g ) a 0 t { W U ( > O o @ 1 x ",
+"A f w 9 ^ %.9.5.3.;. at .7 X . < z ",
+"V d j #.e.w.6.4.2.=.*.&.[ $ , z ",
+"V _ p.z.l.k.d.s.a.8.1.7.,.:.6 k ",
+"V B B m P J b L H v F G z z l l ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/GE.xpm b/src/images/flags/GE.xpm
new file mode 100644
index 0000000..2653b15
--- /dev/null
+++ b/src/images/flags/GE.xpm
@@ -0,0 +1,150 @@
+/* XPM */
+static const char *GE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 128 2",
+" c black",
+". c #CDCD00000000",
+"X c #D3D303030000",
+"o c #D5D500000000",
+"O c #D7D700000000",
+"+ c #D9D91D1D1717",
+"@ c #EDED00000000",
+"# c #EDED03030000",
+"$ c #E8E82E2E2828",
+"% c #E9E933332D2D",
+"& c #EBEB38383232",
+"* c #ECEC3D3D3636",
+"= c #EDED45453F3F",
+"- c #D3D351514646",
+"; c #DFDF67675E5E",
+": c #EBEB4C4C4646",
+"> c #ECEC4D4D4848",
+", c #EDED52524D4D",
+"< c #EDED54544F4F",
+"1 c #EEEE56565050",
+"2 c #EEEE59595454",
+"3 c #EFEF5A5A5454",
+"4 c #EFEF5B5B5656",
+"5 c #F1F153534E4E",
+"6 c #F2F255555151",
+"7 c #F1F15B5B5555",
+"8 c #F2F25A5A5656",
+"9 c #F0F05D5D5858",
+"0 c #F3F35F5F5A5A",
+"q c #F1F160605B5B",
+"w c #F4F463635E5E",
+"e c #EDED65656060",
+"r c #EEEE6B6B6767",
+"t c #E2E275756D6D",
+"y c #E4E47D7D7474",
+"u c #F2F265656060",
+"i c #F2F266666161",
+"p c #F3F36B6B6666",
+"a c #F5F56D6D6767",
+"s c #F3F36D6D6868",
+"d c #F4F471716D6D",
+"f c #F7F77F7F7B7B",
+"g c #EAEA80807A7A",
+"h c #EBEB80807D7D",
+"j c gray75",
+"k c #E6E689898383",
+"l c #EFEF83838080",
+"z c #EEEE87878282",
+"x c #E9E98A8A8282",
+"c c #EEEE88888484",
+"v c #EFEF89898686",
+"b c #EFEF8E8E8D8D",
+"n c #E7E793938B8B",
+"m c #EDED91918F8F",
+"M c #F6F687878383",
+"N c #F7F78B8B8888",
+"B c #F3F391918D8D",
+"V c #F3F392928E8E",
+"C c #F1F195959292",
+"Z c #F1F198989494",
+"A c #F1F199999494",
+"S c #F2F298989595",
+"D c #F4F49A9A9797",
+"F c #F1F19E9E9B9B",
+"G c #F5F59D9D9A9A",
+"H c #F6F69E9E9B9B",
+"J c #F0F0A5A5A0A0",
+"K c #F0F0A7A7A2A2",
+"L c #F7F7A3A3A0A0",
+"P c #F7F7A4A4A1A1",
+"I c #F7F7A7A7A4A4",
+"U c #F6F6A9A9A7A7",
+"Y c #F3F3ADADA8A8",
+"T c #F8F8AAAAA7A7",
+"R c #F9F9AEAEACAC",
+"E c #F9F9B0B0ADAD",
+"W c #F3F3B8B8B5B5",
+"Q c #F3F3BBBBB7B7",
+"! c #F1F1BFBFBBBB",
+"~ c #F9F9B3B3B1B1",
+"^ c #F8F8BEBEBABA",
+"/ c #FAFABDBDBABA",
+"( c #FBFBBEBEBCBC",
+") c #F9F9C1C1BEBE",
+"_ c #C1C1C1C1C1C1",
+"` c #C3C3C3C3C3C3",
+"' c #C5C5C5C5C5C5",
+"] c gray79",
+"[ c #CDCDCDCDCDCD",
+"{ c #CFCFCFCFD1D1",
+"} c gray82",
+"| c LightGray",
+" . c #D7D7D7D7D7D7",
+".. c #D9D9D7D7D9D9",
+"X. c gray85",
+"o. c gray86",
+"O. c #DFDFDFDFDFDF",
+"+. c #EFEFC9C9C8C8",
+"@. c #F9F9CECECACA",
+"#. c #F2F2D8D8D8D8",
+"$. c #F7F7DEDEDDDD",
+"%. c #F8F8DDDDDCDC",
+"&. c #FAFADFDFDEDE",
+"*. c #E1E1E1E1E1E1",
+"=. c gray89",
+"-. c gray90",
+";. c #E7E7E7E7E7E7",
+":. c #E9E9E9E9E9E9",
+">. c gray92",
+",. c #FAFAEAEAEAEA",
+"<. c #FDFDEDEDECEC",
+"1. c #FEFEEEEEEDED",
+"2. c gray95",
+"3. c #F3F3F3F3F3F3",
+"4. c #F4F4F4F4F4F4",
+"5. c gray96",
+"6. c #F6F6F6F6F6F6",
+"7. c gray97",
+"8. c #F8F8F8F8F8F8",
+"9. c #F9F9F9F9F9F9",
+"0. c gray98",
+"q. c #FBFBFBFBFBFB",
+"w. c gray99",
+"e. c #FDFDFDFDFDFD",
+"r. c #FDFDFDFDFEFE",
+"t. c #FEFEFEFEFEFE",
+"y. c gray100",
+"u. c None",
+/* pixels */
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+">.>.>.>.>.>.;.# @ =.=.O.X.X.X. .",
+">.y.1.( <.y.y.N M q.0.,.T $.8.| ",
+">.y.) k ^ y.y.d p 0.0.W ; J 7.{ ",
+">.y.y. at .q.y.0.s i 0.0.6.! 6.6.[ ",
+"a / R R T I G w 0 B Z C Z b F + ",
+"@ f q 0 8 6 < 0 2 : * & % $ : . ",
+"8 ~ L I G D B 2 1 f v c c h m X ",
+";.q.y.W q.0.0.1 , 3.3.3.n 2.3.` ",
+"=.q.Y t J 7.7.< : 3.3.k - y 2._ ",
+"=.q.&.Z %.6.6.r e 6.6.#.h +.2._ ",
+"O.X.X.X. . .} o o ' ' ' ` _ j j ",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u."
+};
diff --git a/src/images/flags/GF.xpm b/src/images/flags/GF.xpm
new file mode 100644
index 0000000..ce48440
--- /dev/null
+++ b/src/images/flags/GF.xpm
@@ -0,0 +1,153 @@
+/* XPM */
+static const char *GF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 131 2",
+" c black",
+". c #17174747A5A5",
+"X c #23234F4FABAB",
+"o c #2D2D5757AFAF",
+"O c #35355F5FB5B5",
+"+ c #3F3F6767B9B9",
+"@ c #49497171BDBD",
+"# c #53537777C3C3",
+"$ c #5B5B7F7FC7C7",
+"% c #63638585CBCB",
+"& c #69698989CDCD",
+"* c #6F6F8F8FD1D1",
+"= c #71719191D1D1",
+"- c #73739393D3D3",
+"; c #73739595D3D3",
+": c #C5C500000000",
+"> c #C7C700000000",
+", c #CBCB00000000",
+"< c #CDCD00000000",
+"1 c #D3D300000000",
+"2 c #D5D500000000",
+"3 c #DBDB00000000",
+"4 c #DDDD00000000",
+"5 c #E1E100000000",
+"6 c #E5E500000000",
+"7 c #E7E700000000",
+"8 c #EBEB00000000",
+"9 c #EFEF07070000",
+"0 c #F1F113130000",
+"q c #E6E64D4D3E3E",
+"w c #E8E852524343",
+"e c #E9E956564848",
+"r c #EAEA57574848",
+"t c #EAEA57574A4A",
+"y c #EBEB5D5D4F4F",
+"u c #ECEC5E5E5050",
+"i c #E8E863635555",
+"p c #EEEE63635555",
+"a c #EEEE64645656",
+"s c #EEEE64645757",
+"d c #E9E966665959",
+"f c #E9E966665A5A",
+"g c #EAEA69695D5D",
+"h c #EAEA6A6A5D5D",
+"j c #EFEF69695C5C",
+"k c #F0F06A6A5C5C",
+"l c #F0F06C6C5D5D",
+"z c #ECEC6D6D6161",
+"x c #ECEC6E6E6262",
+"c c #EDED74746868",
+"v c #EFEF78786C6C",
+"b c #F1F170706363",
+"n c #F1F170706464",
+"m c #F2F271716464",
+"M c #F3F377776A6A",
+"N c #F3F377776B6B",
+"B c #F1F17E7E7272",
+"V c #F5F57D7D7272",
+"C c #F2F284847878",
+"Z c #F4F488887E7E",
+"A c #9F9F9F9F9F9F",
+"S c #A7A7A7A7A7A7",
+"D c gray68",
+"F c #B3B3B0B0B0B0",
+"G c gray72",
+"H c gray",
+"J c #9797ACACD8D8",
+"K c #9C9CB0B0DADA",
+"L c #A0A0B4B4DDDD",
+"P c #A0A0B5B5DDDD",
+"I c #A1A1B5B5DDDD",
+"U c #A3A3B5B5DCDC",
+"Y c #A5A5B8B8DFDF",
+"T c #A5A5B9B9DFDF",
+"R c #A7A7B9B9DDDD",
+"E c #A6A6B9B9E0E0",
+"W c #A9A9BCBCE1E1",
+"Q c #A9A9BDBDE1E1",
+"! c #AAAABDBDE0E0",
+"~ c #AAAABDBDE1E1",
+"^ c #AEAEBFBFE3E3",
+"/ c #AFAFBFBFE2E2",
+"( c #AEAEBFBFE4E4",
+") c #AEAEC0C0E4E4",
+"_ c #B1B1C2C2E5E5",
+"` c #B1B1C3C3E5E5",
+"' c #B2B2C3C3E5E5",
+"] c #B3B3C3C3E4E4",
+"[ c #B4B4C5C5E7E7",
+"{ c #B7B7C7C7E6E6",
+"} c #B7B7C8C8E8E8",
+"| c #BABAC9C9E8E8",
+" . c #BEBECCCCE9E9",
+".. c #F5F58D8D8383",
+"X. c #F7F793938989",
+"o. c #F8F897978E8E",
+"O. c #CECECECECECE",
+"+. c gray81",
+"@. c #D2D2D2D2D2D2",
+"#. c #D5D5D5D5D5D5",
+"$. c gainsboro",
+"%. c #DFDFDFDFDFDF",
+"&. c #C0C0CECEEAEA",
+"*. c #C1C1CFCFEBEB",
+"=. c #C3C3D0D0ECEC",
+"-. c #C3C3D1D1ECEC",
+";. c #C4C4D2D2EDED",
+":. c #C4C4D3D3EDED",
+">. c #E2E2E2E2E2E2",
+",. c #E4E4E4E4E4E4",
+"<. c gray90",
+"1. c #E6E6E6E6E6E6",
+"2. c #E7E7E7E7E7E7",
+"3. c gray91",
+"4. c #E9E9E9E9E9E9",
+"5. c #E9E9E9E9EAEA",
+"6. c #EAEAEAEAEAEA",
+"7. c gray92",
+"8. c #ECECEBEBEBEB",
+"9. c #ECECECECECEC",
+"0. c gray93",
+"q. c #EEEEEEEEEEEE",
+"w. c #EFEFEFEFEFEF",
+"e. c gray94",
+"r. c #F1F1F1F1F1F1",
+"t. c #F3F3F3F3F3F3",
+"y. c #F4F4F4F4F4F4",
+"u. c #F6F6F6F6F6F6",
+"i. c gray97",
+"p. c #F8F8F8F8F8F8",
+"a. c None",
+/* pixels */
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"; ; ; ; - $.$.#. at .O.@.0 9 8 6 6 ",
+"; :.:.*.*.p.i.i.i.i.t.o.X...Z 5 ",
+"; :.} [ ' q.7.6.6.6.<.V N m C 4 ",
+"- *.[ ' ) w.7.q.6.6.<.M m l B 4 ",
+"* &.' ( ~ q.q.8.6.<.<.b j s v 2 ",
+"& .) Q Y t.q.q.q.6.6.j s u c 2 ",
+"% } Q E U q.q.q.6.6.<.p y e x < ",
+"$ { E U K q.q.6.2.<.<.y e w h , ",
+"# ' K K J 7.6.<.<.<.>.e w q f > ",
+"@ / ~ Y U q.q.6.6.<.<.x h f i > ",
+"+ O o X . H G F D S A < , > : > ",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a."
+};
diff --git a/src/images/flags/GH.xpm b/src/images/flags/GH.xpm
new file mode 100644
index 0000000..35939ce
--- /dev/null
+++ b/src/images/flags/GH.xpm
@@ -0,0 +1,171 @@
+/* XPM */
+static const char *GH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 149 2",
+" c black",
+". c #00001F1F0000",
+"X c #000021210000",
+"o c #000025250000",
+"O c #000027270000",
+"+ c #000029290000",
+"@ c #00002D2D0000",
+"# c #000033330000",
+"$ c #000039390000",
+"% c #00003D3D0000",
+"& c #000041410000",
+"* c #000047470000",
+"= c #00004D4D0000",
+"- c #000053530000",
+"; c #000059590000",
+": c #00005D5D0000",
+"> c #000063630000",
+", c #000069690000",
+"< c #00006F6F0000",
+"1 c #000073730000",
+"2 c #434343433636",
+"3 c #4A4A4B4B3B3B",
+"4 c #60605E5E2F2F",
+"5 c #686866663535",
+"6 c #0B0B95950B0B",
+"7 c #0F0F97970E0E",
+"8 c #101097971010",
+"9 c #131399991313",
+"0 c #141499991414",
+"q c #18189C9C1919",
+"w c #19199C9C1919",
+"e c #1E1E9F9F1E1E",
+"r c #1F1F9F9F1F1F",
+"t c #2323A1A12323",
+"y c #2424A2A22424",
+"u c #2929A4A42929",
+"i c #2A2AA4A42A2A",
+"p c #2C2CA2A22C2C",
+"a c #2F2FA4A42F2F",
+"s c #2E2EA6A62E2E",
+"d c #2F2FA7A72F2F",
+"f c #3232A5A53232",
+"g c #3333A6A63232",
+"h c #3434A9A93434",
+"j c #3535A8A83535",
+"k c #3434AAAA3434",
+"l c #3939A9A93939",
+"z c #3A3AACAC3A3A",
+"x c #3D3DACAC3D3D",
+"c c #3F3FAFAF3F3F",
+"v c #4040AFAF3F3F",
+"b c #4242AEAE4242",
+"n c #4444B1B14444",
+"m c #4545B2B24545",
+"M c #4646B0B04646",
+"N c #4B4BB2B24B4B",
+"B c #4949B4B44949",
+"V c #5050B4B45050",
+"C c #5454B7B75555",
+"Z c #5858B9B95858",
+"A c #5D5DBCBC5D5D",
+"S c #6161BEBE6262",
+"D c #6666C0C06666",
+"F c #6A6AC3C36A6A",
+"G c #E7E700000000",
+"H c #E9E900000000",
+"J c #EBEB00000000",
+"K c #EDED00000000",
+"L c #EFEF00000000",
+"P c #F1F100000000",
+"I c #F3F300000000",
+"U c #F5F500000000",
+"Y c #F7F700000000",
+"T c #F9F900000000",
+"R c #FBFB00000000",
+"E c #FDFD00000000",
+"W c red",
+"Q c #F5F526262626",
+"! c #F6F62B2B2B2B",
+"~ c #F6F62C2C2C2C",
+"^ c #F7F731313131",
+"/ c #F8F837373636",
+"( c #F8F837373737",
+") c #F9F93C3C3C3C",
+"_ c #F9F93C3C3D3D",
+"` c #F6F644444444",
+"' c #F7F749494949",
+"] c #F7F74E4E4E4E",
+"[ c #FAFA41414242",
+"{ c #FAFA42424242",
+"} c #FBFB47474747",
+"| c #FCFC4B4B4B4B",
+" . c #FCFC4C4C4C4C",
+".. c #F8F853535353",
+"X. c #F9F957575757",
+"o. c #FDFD51515151",
+"O. c #FDFD54545454",
+"+. c #FAFA5C5C5C5C",
+"@. c #FEFE59595959",
+"#. c #FEFE5C5C5C5C",
+"$. c #FEFE5F5F5F5F",
+"%. c #FBFB60606060",
+"&. c #FCFC65656565",
+"*. c #FCFC69696969",
+"=. c #FDFD6D6D6D6D",
+"-. c #FDFD70707171",
+";. c #FEFE74747474",
+":. c #FEFE77777777",
+">. c #FEFE79797979",
+",. c #FFFF7B7B7A7A",
+"<. c #FFFF7B7B7B7B",
+"1. c #939394943030",
+"2. c #929295953C3C",
+"3. c #98989A9A4141",
+"4. c #A1A1A1A14040",
+"5. c #E3E3E3E30000",
+"6. c #E5E5E5E50000",
+"7. c #E7E7E7E70000",
+"8. c #FDFDFDFD0000",
+"9. c #F2F2F2F21414",
+"0. c #F3F3F3F31919",
+"q. c #F3F3F3F31A1A",
+"w. c #F4F4F4F41F1F",
+"e. c #ECECEFEF3636",
+"r. c #F2F2EFEF2A2A",
+"t. c #F4F4F4F42020",
+"y. c #F5F5F5F52424",
+"u. c #F5F5F5F52525",
+"i. c #F6F6F6F62B2B",
+"p. c #F7F7F7F73030",
+"a. c #F4F4F4F43636",
+"s. c #F4F4F5F53B3B",
+"d. c #F5F5F5F53F3F",
+"f. c #F9F9F4F43A3A",
+"g. c #F0F0F3F34646",
+"h. c #FAFAFAFA4040",
+"j. c #FBFBFBFB4545",
+"k. c #FBFBFBFB4646",
+"l. c #FBFBFCFC4949",
+"z. c #FCFCFCFC4B4B",
+"x. c #FCFCFCFC4F4F",
+"c. c #FDFDFCFC5050",
+"v. c #FDFDFDFD5353",
+"b. c #FDFDFDFD5454",
+"n. c #FEFEFEFE5858",
+"m. c #FDFDFDFD6F6F",
+"M. c #FEFEFEFE7373",
+"N. c #FEFEFEFE7676",
+"B. c None",
+/* pixels */
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"W W W W R W W W R R Y Y I I K K ",
+"W <.<.:.:.;.-.=.*.&.%.+.X...] J ",
+"W <.$.#.#.O.o. .} { _ / ^ ~ ' J ",
+"W <.#.#.o.o.| } { _ / ^ ! Q ` G ",
+"8.N.b.b.c.z.g.3.2.e.p.i.u.t.d.7.",
+"8.N.v.z.z.l.4.3 2 1.i.u.w.0.d.7.",
+"8.m.z.l.l.d.f.5 4 r.u.w.0.9.a.5.",
+"1 F B m v z k d i y e q 0 7 f o ",
+"1 D n v z k a i t e q 9 7 6 a X ",
+", S A Z C V N M b x l j f a p . ",
+"> : ; - = * & % $ # @ + o X . . ",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B."
+};
diff --git a/src/images/flags/GI.xpm b/src/images/flags/GI.xpm
new file mode 100644
index 0000000..3032d96
--- /dev/null
+++ b/src/images/flags/GI.xpm
@@ -0,0 +1,137 @@
+/* XPM */
+static const char *GI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 115 2",
+" c black",
+". c #B9B93D3D3535",
+"X c #ADAD69696565",
+"o c #D5D500000000",
+"O c #DDDD00000000",
+"+ c #DFDF00000000",
+"@ c #DEDE3D3D3131",
+"# c #E1E100000000",
+"$ c #E3E300000000",
+"% c #E5E500000000",
+"& c #E7E700000000",
+"* c #E9E900000000",
+"= c #EDED00000000",
+"- c #EFEF00000000",
+"; c #F1F100000000",
+": c #F3F300000000",
+"> c #F5F500000000",
+", c #F7F700000000",
+"< c #F9F915150505",
+"1 c #F2F238382C2C",
+"2 c #F2F23B3B2F2F",
+"3 c #F2F23F3F3232",
+"4 c #E1E148483C3C",
+"5 c #F0F043433737",
+"6 c #F3F341413535",
+"7 c #F4F446463939",
+"8 c #F2F248483B3B",
+"9 c #F5F54A4A3D3D",
+"0 c #E8E855554A4A",
+"q c #ECEC5E5E5454",
+"w c #F1F14E4E4343",
+"e c #F2F24D4D4141",
+"r c #F1F152524545",
+"t c #F4F450504242",
+"y c #F1F154544848",
+"u c #F3F35A5A4141",
+"i c #F2F258584C4C",
+"p c #F4F458584D4D",
+"a c #F0F05B5B5151",
+"s c #F3F35C5C5151",
+"d c #F5F55E5E5353",
+"f c #F8F85B5B5050",
+"g c #F9F95F5F5555",
+"h c #F7F760605555",
+"j c #F9F963635858",
+"k c #FAFA68685D5D",
+"l c #F2F26A6A6060",
+"z c #F8F86B6B6161",
+"x c #FBFB6B6B6262",
+"c c #F8F86D6D6363",
+"v c #F7F777776E6E",
+"b c #F9F974746A6A",
+"n c #FAFA78786E6E",
+"m c #FAFA7C7C7272",
+"M c #E1E1A1A13F3F",
+"N c #E8E8A7A73C3C",
+"B c #FBFB84847C7C",
+"V c #EEEEABAB5858",
+"C c #EBEBB0B05555",
+"Z c #FCFC94948D8D",
+"A c #C9C9C7C7C7C7",
+"S c #CBCBCBCBCBCB",
+"D c #CDCDCDCDCDCD",
+"F c gray81",
+"G c gray82",
+"H c #D5D5D5D5D5D5",
+"J c #D7D7D7D7D7D7",
+"K c gray85",
+"L c gray86",
+"P c #DFDFDFDFDFDF",
+"I c #E3E3CACAC8C8",
+"U c #EDEDCCCCCACA",
+"Y c #EBEBD3D3D0D0",
+"T c #EDEDD4D4D3D3",
+"R c #F1F1DEDEDDDD",
+"E c #F7F7E0E0DEDE",
+"W c #E1E1E1E1E1E1",
+"Q c gray89",
+"! c gray90",
+"~ c #E7E7E7E7E7E7",
+"^ c #E9E9E7E7E7E7",
+"/ c #EFEFE2E2E1E1",
+"( c #EEEEE5E5E4E4",
+") c #E9E9E9E9E9E9",
+"_ c gray92",
+"` c gray93",
+"' c #EFEFEFEFEFEF",
+"] c #F7F7E5E5E4E4",
+"[ c #F9F9E3E3E2E2",
+"{ c #F2F2F1F1F1F1",
+"} c gray95",
+"| c #F3F3F2F2F2F2",
+" . c #F3F3F3F3F3F3",
+".. c #F7F7F2F2F1F1",
+"X. c #F6F6F3F3F3F3",
+"o. c #F4F4F4F4F4F4",
+"O. c #F4F4F5F5F5F5",
+"+. c gray96",
+"@. c #F6F6F6F6F6F6",
+"#. c gray97",
+"$. c #FAFAF3F3F3F3",
+"%. c #F8F8F8F8F8F8",
+"&. c #F9F9F9F9F9F9",
+"*. c gray98",
+"=. c #FBFBFAFAFAFA",
+"-. c #FBFBFBFBFBFB",
+";. c #FBFBFCFCFBFB",
+":. c gray99",
+">. c #FDFDFCFCFCFC",
+",. c #FDFDFCFCFDFD",
+"<. c #FDFDFDFDFDFD",
+"1. c #FDFDFDFDFEFE",
+"2. c #FEFEFEFEFEFE",
+"3. c gray100",
+"4. c None",
+/* pixels */
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"' ' ' ' ' ' _ ^ ) ~ ~ W W W K K ",
+"' 3.3.*.3.3.>.3.*.3.*.*.*.*. at .J ",
+"' 3.3.3.3.*.$.B ] *.*. at .@. at .@.J ",
+"' 3.3.3.3.[ z q d R *. at .@. at .@.F ",
+"' 3.3.*.*.T q X 0 Y @. at . . at .@.F ",
+") 3.-.3.3.v e 8 5 w @. at . . . .F ",
+") 3.-.-.*.U 4 . @ I @. . . . .S ",
+"^ 3.*.*.*.../ M R ] . .' ' .A ",
+"< Z m n b z h N u p s i 0 r k O ",
+"> z k j h f V C t 9 7 6 6 2 1 O ",
+"> : : : - - * o % % % # # O O O ",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4."
+};
diff --git a/src/images/flags/GL.xpm b/src/images/flags/GL.xpm
new file mode 100644
index 0000000..7ec2ff3
--- /dev/null
+++ b/src/images/flags/GL.xpm
@@ -0,0 +1,148 @@
+/* XPM */
+static const char *GL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 126 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #E5E511111111",
+"= c #F1F100000000",
+"- c #F3F300000000",
+"; c #F5F500000000",
+": c #F7F700000000",
+"> c #F1F10B0B0B0B",
+", c #F1F10F0F0E0E",
+"< c #F9F900000000",
+"1 c #FBFB00000000",
+"2 c #FDFD00000000",
+"3 c #F2F210101010",
+"4 c #F2F213131313",
+"5 c #F2F214141414",
+"6 c #F3F319191919",
+"7 c #F4F41E1E1E1E",
+"8 c #F4F41F1F1F1F",
+"9 c #F5F524242424",
+"0 c #F2F22C2C2C2C",
+"q c #F2F22F2F2F2F",
+"w c #F2F232323232",
+"e c #F3F332323232",
+"r c #F3F335353535",
+"t c #F4F436363636",
+"y c #F4F439393939",
+"u c #F5F53D3D3D3D",
+"i c #F9F93B3B3C3C",
+"p c #F6F642424242",
+"a c #FAFA41414141",
+"s c #FAFA44444444",
+"d c #FAFA46464747",
+"f c #FBFB46464646",
+"g c #FBFB47474747",
+"h c #FBFB4B4B4B4B",
+"j c #FCFC4B4B4B4B",
+"k c #FDFD4F4F5050",
+"l c #F7F752525252",
+"z c #F5F558585858",
+"x c #FAFA51515151",
+"c c #F9F954545555",
+"v c #FDFD51515151",
+"b c #FDFD54545454",
+"n c #FDFD55555555",
+"m c #F9F958585858",
+"M c #FAFA5D5D5D5D",
+"N c #FDFD5E5E5E5E",
+"B c #F5F56E6E6E6E",
+"V c #FBFB61616262",
+"C c #FDFD65656565",
+"Z c #FCFC66666666",
+"A c #FCFC67676767",
+"S c #F8F86A6A6A6A",
+"D c #FCFC6A6A6A6A",
+"F c #FCFC6D6D6D6D",
+"G c #FDFD6F6F6F6F",
+"H c #F7F770707070",
+"J c #F8F875757575",
+"K c #F3F387878787",
+"L c #F4F48B8B8B8B",
+"P c #F5F58E8E8E8E",
+"I c #F6F691919191",
+"U c #F7F794949494",
+"Y c #F4F498989898",
+"T c #F8F897979797",
+"R c #FEFE92929292",
+"E c #FEFE93939393",
+"W c #F9F99A9A9A9A",
+"Q c #FAFA9D9D9D9D",
+"! c #FBFBA0A0A1A1",
+"~ c #FCFCA3A3A3A3",
+"^ c #FCFCA5A5A5A5",
+"/ c #FDFDA9A9A9A9",
+"( c #F6F6B6B6B6B6",
+") c #F9F9BEBEBEBE",
+"_ c #FEFEB9B9B9B9",
+"` c #D5D5D5D5D5D5",
+"' c #D7D7D7D7D7D7",
+"] c gray85",
+"[ c #DDDDDDDDDDDD",
+"{ c #DFDFDFDFDFDF",
+"} c #FBFBC0C0C0C0",
+"| c #FBFBC2C2C2C2",
+" . c #F9F9CFCFCFCF",
+".. c #F6F6DCDCDCDC",
+"X. c #E1E1E1E1E1E1",
+"o. c gray89",
+"O. c gray90",
+"+. c #E7E7E7E7E7E7",
+"@. c #E9E9E9E9E9E9",
+"#. c gray92",
+"$. c gray93",
+"%. c #EFEFEFEFEFEF",
+"&. c #EFEFEFEFF1F1",
+"*. c #FEFEE3E3E3E3",
+"=. c #FDFDE5E5E5E5",
+"-. c #FEFEEDEDEDED",
+";. c #F1F1F1F1F1F1",
+":. c #F6F6F2F2F2F2",
+">. c #F4F4F4F4F4F4",
+",. c gray96",
+"<. c #F7F7F4F4F4F4",
+"1. c #F6F6F6F6F6F6",
+"2. c gray97",
+"3. c #F8F8F1F1F1F1",
+"4. c #FEFEF2F2F2F2",
+"5. c #FDFDF7F7F7F7",
+"6. c #F8F8F8F8F8F8",
+"7. c #F9F9F9F9F9F9",
+"8. c gray98",
+"9. c #FBFBFBFBFBFB",
+"0. c #FBFBFCFCFBFB",
+"q. c gray99",
+"w. c #FEFEFDFDFDFD",
+"e. c #FEFEFEFEFEFE",
+"r. c gray100",
+"t. c None",
+/* pixels */
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+";.;.;.;.;.;.$.$.$.$. at .+.O.o.X.{ ",
+";.r.r.r.r.-.=.5.9.r.9.7.7.7.1.[ ",
+";.r.r.4.R M n A } 7.7.7.2.2.2.] ",
+";.r.r.R x x j g d .7.1.2.1.1.' ",
+";.r.*.x k j g a i J 1.1.1.;.1.` ",
+"A _ / ^ ! ! Q W T U I P P K U * ",
+"2 F F q.r.7.7.7.1.( 9 8 6 4 t o ",
+"2 D j ) 7.7.2.1.;.m 8 6 4 4 e X ",
+"< A s x ) :.1...B 8 6 4 , > e X ",
+"< V M m c S H l p u y r e q 0 . ",
+"; - - % % % $ $ @ @ o o X X . . ",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.",
+"t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t."
+};
diff --git a/src/images/flags/GM.xpm b/src/images/flags/GM.xpm
new file mode 100644
index 0000000..c663ad3
--- /dev/null
+++ b/src/images/flags/GM.xpm
@@ -0,0 +1,189 @@
+/* XPM */
+static const char *GM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 167 2",
+" c black",
+". c #000021210000",
+"X c #000023230000",
+"o c #000027270000",
+"O c #00002B2B0000",
+"+ c #00002F2F0000",
+"@ c #000035350000",
+"# c #000039390000",
+"$ c #00003D3D0000",
+"% c #000043430000",
+"& c #000049490000",
+"* c #00004F4F0000",
+"= c #000055550000",
+"- c #000059590000",
+"; c #00005F5F0000",
+": c #000067670000",
+"> c #00006B6B0000",
+", c #00006F6F0000",
+"< c #00000303E3E3",
+"1 c #00000000E5E5",
+"2 c #00001515E7E7",
+"3 c #00004141FDFD",
+"4 c #09095B5BFDFD",
+"5 c #17176767FDFD",
+"6 c #3C3C7171F3F3",
+"7 c #41417575F4F4",
+"8 c #45457979F5F5",
+"9 c #4A4A7D7DF6F6",
+"0 c #0B0B92920B0B",
+"q c #0F0F94940E0E",
+"w c #131396961313",
+"e c #181899991919",
+"r c #1E1E9C9C1E1E",
+"t c #23239F9F2323",
+"y c #2929A2A22929",
+"u c #2C2CA2A22C2C",
+"i c #2F2FA2A22F2F",
+"p c #2E2EA5A52E2E",
+"a c #2F2FA4A42F2F",
+"s c #3232A5A53232",
+"d c #3434A8A83434",
+"f c #3535A8A83535",
+"g c #3939A9A93939",
+"h c #3A3AABAB3A3A",
+"j c #3D3DACAC3D3D",
+"k c #3F3FAEAE3F3F",
+"l c #4242AEAE4242",
+"z c #4444B1B14444",
+"x c #4646B0B04646",
+"c c #4B4BB2B24B4B",
+"v c #5050B4B45050",
+"b c #5454B7B75555",
+"n c #5858B9B95858",
+"m c #5D5DBCBC5D5D",
+"M c #6161BEBE6262",
+"N c #6666BFBF6666",
+"B c #4E4E8383F2F2",
+"V c #4F4F8080F7F7",
+"C c #52528686F3F3",
+"Z c #54548484F8F8",
+"A c #56568A8AF4F4",
+"S c #58588686F5F5",
+"D c #58588D8DF4F4",
+"F c #5B5B8D8DF5F5",
+"G c #5F5F8F8FF6F6",
+"H c #59598888F9F9",
+"J c #5E5E8B8BFAFA",
+"K c #5C5C9090F5F5",
+"L c #62628F8FFBFB",
+"P c #61619393F6F6",
+"I c #63639393F7F7",
+"U c #65659696F7F7",
+"Y c #67679494F4F4",
+"T c #66669292FCFC",
+"R c #67679696F8F8",
+"E c #6B6B9595FCFC",
+"W c #6F6F9D9DF5F5",
+"Q c #6A6A9A9AF8F8",
+"! c #6C6C9999F9F9",
+"~ c #6F6F9898FDFD",
+"^ c #6D6D9D9DF9F9",
+"/ c #70709D9DFAFA",
+"( c #74749F9FFBFB",
+") c #7171A0A0FAFA",
+"_ c #7575A3A3FBFB",
+"` c #7878A2A2FBFB",
+"' c #7979A6A6FCFC",
+"] c #7C7CA5A5FCFC",
+"[ c #7D7DA8A8FDFD",
+"{ c #999900000000",
+"} c #9D9D00000000",
+"| c #A7A700000000",
+" . c #ABAB00000000",
+".. c #AFAF00000000",
+"X. c #B1B100000000",
+"o. c #B3B300000000",
+"O. c #B7B700000000",
+"+. c #B9B900000000",
+"@. c #BDBD00000000",
+"#. c #C1C100000000",
+"$. c #C3C300000000",
+"%. c #C7C700000000",
+"&. c #CECE2C2C2C2C",
+"*. c #D0D031313131",
+"=. c #D1D137373737",
+"-. c #D3D33C3C3D3D",
+";. c #D5D542424242",
+":. c #D6D647474747",
+">. c #D4D449494949",
+",. c #D7D74E4E4E4E",
+"<. c #D8D84C4C4C4C",
+"1. c #D9D951515151",
+"2. c #D8D853535353",
+"3. c #D9D957575757",
+"4. c #DBDB54545454",
+"5. c #DBDB5C5C5C5C",
+"6. c #DDDD59595959",
+"7. c #DDDD5C5C5C5C",
+"8. c #DEDE5F5F5F5F",
+"9. c #DDDD60606060",
+"0. c #DDDD65656565",
+"q. c #DFDF69696969",
+"w. c #E0E06D6D6D6D",
+"e. c #E2E270707171",
+"r. c #E2E274747474",
+"t. c #E3E377777777",
+"y. c #E4E479797979",
+"u. c #E4E47B7B7A7A",
+"i. c #E4E47B7B7B7B",
+"p. c #8080ABABFDFD",
+"a. c #8383ADADFEFE",
+"s. c #8888AAAAFEFE",
+"d. c #9494B6B6FDFD",
+"f. c #9999BCBCFEFE",
+"g. c #BBBBC1C1BBBB",
+"h. c #CDCDC7C7C7C7",
+"j. c #DFDFE5E5DFDF",
+"k. c #EBEBE7E7E7E7",
+"l. c #EDEDF0F0EDED",
+"z. c #EEEEF0F0EEEE",
+"x. c #EEEEF1F1EEEE",
+"c. c #EFEFF2F2EFEF",
+"v. c #F0F0F2F2F0F0",
+"b. c #F1F1F4F4F1F1",
+"n. c #F2F2F5F5F2F2",
+"m. c #F3F3F6F6F3F3",
+"M. c #F4F4F2F2F1F1",
+"N. c #F5F5F3F3F2F2",
+"B. c #F6F6F3F3F2F2",
+"V. c #F7F7F4F4F3F3",
+"C. c #F4F4F7F7F4F4",
+"Z. c #F5F5F8F8F5F5",
+"A. c #F6F6F9F9F6F6",
+"S. c #F7F7FAFAF7F7",
+"D. c #F8F8F4F4F3F3",
+"F. c #F9F9F5F5F5F5",
+"G. c #FAFAF6F6F6F6",
+"H. c #FAFAF7F7F7F7",
+"J. c #FBFBF8F8F7F7",
+"K. c #F8F8FAFAF8F8",
+"L. c #FAFAFCFCFAFA",
+"P. c #FCFCF9F9F8F8",
+"I. c #FCFCFAFAF9F9",
+"U. c #FDFDFAFAF9F9",
+"Y. c #FEFEFBFBFAFA",
+"T. c #FEFEFCFCFCFC",
+"R. c None",
+/* pixels */
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"%.$.$.$.$.$. at .@.+.O.o.o... .| | ",
+"$.i.i.i.r.r.e.q.q.0.8.8.3.4.,.} ",
+"$.i.8.7.7.4.1.<.:.;.-.=.*.&.>.{ ",
+"k.T.Y.Y.Y.J.J.G.G.G.B.B.m.M.m.h.",
+"5 f.a.p.] ' _ ) ^ Q U P G D W 2 ",
+"3 s.~ E T T J H Z 9 9 8 7 6 S 1 ",
+"4 d.' ' / / Q R P P G A C B Y < ",
+"j.L.K.S.C.C.C.m.m.v.v.z.x.x.x.g.",
+", N z k j f i y t r e w q 0 i o ",
+"> M m n b v c x l j h f s i i . ",
+": ; - = * & % $ # @ + O o . . . ",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R."
+};
diff --git a/src/images/flags/GN.xpm b/src/images/flags/GN.xpm
new file mode 100644
index 0000000..db23f9b
--- /dev/null
+++ b/src/images/flags/GN.xpm
@@ -0,0 +1,168 @@
+/* XPM */
+static const char *GN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 146 2",
+" c black",
+". c #000021210000",
+"X c #000023230000",
+"o c #000027270000",
+"O c #000029290000",
+"+ c #00002B2B0000",
+"@ c #00002D2D0000",
+"# c #000031310000",
+"$ c #000037370000",
+"% c #00003D3D0000",
+"& c #000043430000",
+"* c #000049490000",
+"= c #000051510000",
+"- c #000055550000",
+"; c #000059590000",
+": c #00005F5F0000",
+"> c #000065650000",
+", c #0B0B95950B0B",
+"< c #0F0F97970E0E",
+"1 c #101097971010",
+"2 c #131399991313",
+"3 c #141499991414",
+"4 c #14149A9A1414",
+"5 c #19199C9C1919",
+"6 c #1A1A9C9C1A1A",
+"7 c #1F1F9F9F1F1F",
+"8 c #20209F9F2020",
+"9 c #2525A2A22525",
+"0 c #2626A2A22626",
+"q c #2B2BA5A52B2B",
+"w c #2C2CA2A22C2C",
+"e c #2C2CA6A62C2C",
+"r c #2F2FA4A42F2F",
+"t c #3232A5A53232",
+"y c #3333A6A63232",
+"u c #3131A8A83131",
+"i c #3131A9A93131",
+"p c #3535A8A83535",
+"a c #3636A8A83636",
+"s c #3737ABAB3737",
+"d c #3B3BAAAA3B3B",
+"f c #3F3FADAD3F3F",
+"g c #4444AFAF4444",
+"h c #4949B2B24949",
+"j c #4E4EB4B44E4E",
+"k c #5353B7B75353",
+"l c #5858B9B95757",
+"z c #5C5CBBBB5C5C",
+"x c #EDED00000000",
+"c c #EFEF00000000",
+"v c #F1F100000000",
+"b c #F3F300000000",
+"n c #F5F500000000",
+"m c #F7F700000000",
+"M c #F9F900000000",
+"N c #FBFB00000000",
+"B c #FDFD00000000",
+"V c red",
+"C c #F9F93A3A3A3A",
+"Z c #FAFA3F3F3F3F",
+"A c #FAFA44444444",
+"S c #FBFB45454545",
+"D c #FBFB49494949",
+"F c #FBFB4A4A4949",
+"G c #FCFC4A4A4B4B",
+"H c #FCFC4F4F4F4F",
+"J c #FDFD4F4F5050",
+"K c #F9F954545555",
+"L c #FDFD53535353",
+"P c #FDFD54545454",
+"I c #F9F958585858",
+"U c #FAFA5D5D5D5D",
+"Y c #FEFE58585858",
+"T c #FEFE59595959",
+"R c #FEFE5C5C5C5C",
+"E c #FEFE5F5F5F5F",
+"W c #FBFB61616262",
+"Q c #FCFC66666666",
+"! c #FCFC6A6A6A6A",
+"~ c #FDFD6F6F6F6F",
+"^ c #FEFE72727373",
+"/ c #FEFE76767676",
+"( c #FEFE77777777",
+") c #FEFE79797979",
+"_ c #FFFF7B7B7A7A",
+"` c #FFFF7B7B7B7B",
+"' c #CBCBDBDB0000",
+"] c #EDEDD5D50000",
+"[ c #E5E5E5E50000",
+"{ c #E7E7E7E70000",
+"} c #E5E5EFEF0000",
+"| c #E9E9E9E90000",
+" . c #EBEBEBEB0000",
+".. c #E7E7EEEE1919",
+"X. c #E8E8EFEF1F1F",
+"o. c #FDFDEBEB0000",
+"O. c #F9F9F9F90000",
+"+. c #FBFBFBFB0000",
+"@. c #FDFDFDFD0000",
+"#. c #F4F4F4F41E1E",
+"$. c #EAEAF0F02424",
+"%. c #EBEBF1F12B2B",
+"&. c #ECECF2F23030",
+"*. c #EEEEF4F43636",
+"=. c #EAEAF0F03939",
+"-. c #EFEFF5F53D3D",
+";. c #F8F8ECEC3434",
+":. c #F9F9EDED3A3A",
+">. c #F5F5F5F52323",
+",. c #F5F5F5F52424",
+"<. c #F6F6F6F62929",
+"1. c #F6F6F6F62A2A",
+"2. c #F7F7F7F72E2E",
+"3. c #F7F7F7F72F2F",
+"4. c #F7F7F7F73030",
+"5. c #F5F5F5F53D3D",
+"6. c #F8F8F8F83434",
+"7. c #F8F8F8F83535",
+"8. c #F8F8F8F83636",
+"9. c #F9F9F9F93A3A",
+"0. c #F9F9F9F93B3B",
+"q. c #F9F9F9F93C3C",
+"w. c #FAFAEEEE4040",
+"e. c #F8F8EEEE5050",
+"r. c #F6F6F6F64242",
+"t. c #F7F7F7F74646",
+"y. c #F7F7F7F74B4B",
+"u. c #FBFBF0F04646",
+"i. c #FCFCF1F14B4B",
+"p. c #FAFAFAFA4040",
+"a. c #FAFAFAFA4141",
+"s. c #FAFAFAFA4242",
+"d. c #FBFBFBFB4646",
+"f. c #FBFBFBFB4747",
+"g. c #FCFCFCFC4B4B",
+"h. c #FCFCFCFC4C4C",
+"j. c #FDFDF2F25151",
+"k. c #FDFDF2F25454",
+"l. c #FDFDFDFD5151",
+"z. c #F2F2F7F76060",
+"x. c #FCFCFCFC6565",
+"c. c #FCFCFCFC6969",
+"v. c #FDFDFDFD6D6D",
+"b. c #FEFEF5F57474",
+"n. c #FDFDFDFD7171",
+"m. c None",
+/* pixels */
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"V V V V V o.+.+.+.O.} > : ; - = ",
+"V ` ` ` / b.n.v.c.x.z.z l k j * ",
+"V ` E R R k.l.h.f.a.-.s i e h & ",
+"V ` R R L j.f.d.a.q.*.i q 0 g % ",
+"V / P P H i.d.a.q.8.&.q 0 8 f $ ",
+"V ^ L H G i.a.0.8.4.%.0 7 5 d # ",
+"V ~ H D S :.0.8.4.1.$.7 5 3 a @ ",
+"M ! D S Z :.4.4.1.>.X.5 4 1 y O ",
+"M Q S Z C ;.2.1.>.#...3 < , r X ",
+"n W U I K e.f.y.r.5.=.a y r e . ",
+"n b b x x ] | | [ [ ' @ X X . . ",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m."
+};
diff --git a/src/images/flags/GP.xpm b/src/images/flags/GP.xpm
new file mode 100644
index 0000000..303f856
--- /dev/null
+++ b/src/images/flags/GP.xpm
@@ -0,0 +1,172 @@
+/* XPM */
+static const char *GP_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 150 2",
+" c black",
+". c #0000C1C10000",
+"X c #0000C3C30000",
+"o c #0000C5C50000",
+"O c #0000C7C70000",
+"+ c #0000CBCB0000",
+"@ c #0000CDCD0000",
+"# c #0000CFCF0000",
+"$ c #0000D3D30000",
+"% c #0000D5D50000",
+"& c #0000D7D70000",
+"* c #0000D9D90000",
+"= c #0000DBDB0000",
+"- c #0000DDDD0000",
+"; c #0000DFDF0000",
+": c #0000E1E10000",
+"> c #0000E3E30000",
+", c #0000E5E50000",
+"< c #0000E7E70000",
+"1 c #0000E9E90000",
+"2 c #0303EBEB0000",
+"3 c #0909EBEB0000",
+"4 c #0D0DEDED0000",
+"5 c #0000F1F10000",
+"6 c #1D1DEDED0000",
+"7 c #1717F9F90303",
+"8 c #5757EDED4747",
+"9 c #5959EDED4B4B",
+"0 c #5C5CEFEF4D4D",
+"q c #6060F0F05050",
+"w c #6262F0F05454",
+"e c #6565F1F15757",
+"r c #6969F2F25B5B",
+"t c #6D6DF3F35F5F",
+"y c #7171F4F46363",
+"u c #7575F5F56767",
+"i c #7575F6F66A6A",
+"p c #7878F6F66B6B",
+"a c #7979F7F76E6E",
+"s c #7C7CF7F76F6F",
+"d c #7D7DF7F77272",
+"f c #7F7FF7F77474",
+"g c #DBDB00000000",
+"h c #DFDF00000000",
+"j c #E1E100000000",
+"k c #E3E300000000",
+"l c #E5E500000000",
+"z c #FBFB00000000",
+"x c #F9F90B0B0000",
+"c c #FBFB09090000",
+"v c #FFFF0F0F0000",
+"b c #FBFB15150000",
+"n c #F0F041411F1F",
+"m c #F1F146462424",
+"M c #F2F243432828",
+"N c #F3F347472C2C",
+"B c #F1F149492929",
+"V c #F1F14A4A2A2A",
+"C c #F2F24E4E2E2E",
+"Z c #F2F24E4E2F2F",
+"A c #F2F24F4F2F2F",
+"S c #F4F44A4A3131",
+"D c #F5F54F4F3636",
+"F c #F4F452523333",
+"G c #F4F453533434",
+"H c #F4F453533535",
+"J c #F4F454543535",
+"K c #F5F557573838",
+"L c #F5F557573A3A",
+"P c #F6F654543939",
+"I c #F6F654543B3B",
+"U c #F5F558583B3B",
+"Y c #F7F759593E3E",
+"T c #F6F65B5B3E3E",
+"R c #F2F25C5C4040",
+"E c #F7F758584040",
+"W c #F6F65C5C4040",
+"Q c #F8F85D5D4343",
+"! c #F8F85D5D4545",
+"~ c #F2F260604343",
+"^ c #F7F760604343",
+"/ c #F7F761614545",
+"( c #F3F364644848",
+") c #F4F468684C4C",
+"_ c #F9F961614949",
+"` c #F9F961614A4A",
+"' c #F8F864644848",
+"] c #F8F865654A4A",
+"[ c #FAFA66664E4E",
+"{ c #FAFA66664F4F",
+"} c #F9F969694D4D",
+"| c #F9F969694F4F",
+" . c #F9F96A6A4F4F",
+".. c #F5F56C6C5050",
+"X. c #FBFB69695353",
+"o. c #FAFA6A6A5151",
+"O. c #FBFB6A6A5353",
+"+. c #FAFA6E6E5353",
+"@. c #FAFA6E6E5454",
+"#. c #FCFC6E6E5757",
+"$. c #FBFB6A6A5858",
+"%. c #FAFA6D6D5858",
+"&. c #FAFA72725858",
+"*. c #FBFB75755C5C",
+"=. c #FDFD72725B5B",
+"-. c #FDFD76766060",
+";. c #FEFE75756464",
+":. c #8181F7F77676",
+">. c #8484F8F87878",
+",. c #8484F8F87A7A",
+"<. c #8888F9F97D7D",
+"1. c #FEFE83836868",
+"2. c #FBFB88886262",
+"3. c #FCFC86867777",
+"4. c #FBFBB5B55F5F",
+"5. c #FCFCCACA7F7F",
+"6. c #FCFCD6D66868",
+"7. c #FCFCE3E36969",
+"8. c #FEFEE9E97070",
+"9. c #FDFDFAFA6F6F",
+"0. c #8B8BFAFA8080",
+"q. c #8F8FFBFB8484",
+"w. c #9191FCFC8888",
+"e. c #9494FCFC8A8A",
+"r. c #9696FCFC8D8D",
+"t. c #9898FCFC8F8F",
+"y. c #9999FCFC9090",
+"u. c #C9C9B1B19797",
+"i. c #DDDDBFBFA9A9",
+"p. c #FEFE93938282",
+"a. c #FDFDB5B58484",
+"s. c #FEFEEDED8888",
+"d. c #EBEBD9D9C5C5",
+"f. c #F5F5DFDFCFCF",
+"g. c #F1F1F1F1F1F1",
+"h. c gray95",
+"j. c #F3F3F3F3F3F3",
+"k. c #F4F4F4F4F4F4",
+"l. c gray96",
+"z. c #F6F6F6F6F6F6",
+"x. c gray97",
+"c. c #F8F8F8F8F8F8",
+"v. c #F9F9F9F9F9F9",
+"b. c gray98",
+"n. c #FBFBFBFBFBFB",
+"m. c gray99",
+"M. c #FDFDFDFDFDFD",
+"N. c #FEFEFEFEFEFE",
+"B. c gray100",
+"V. c None",
+/* pixels */
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"6 4 4 4 3 2 < < < < > ; ; * * & ",
+"7 y.t.t.r.e.q.q.0.<.,.:.d a i < ",
+"f.B.B.B.B.B.B.B.B.v.v.v.x.x.x.i.",
+"v p.1.;.*.=.#.O.[ ! W W P J ) l ",
+"b a.8.2.*.%.#.) ] / R P F F ) l ",
+"b s.9.6.%. at .o.[ / R P J C V ( j ",
+"b a.7.4.+. .! W T U F C V m ~ h ",
+"z 3.$.O.[ ! W W I D N N N n R g ",
+"d.b.b.b.b.v.x.x.x.k.x.g.g.g.g.u.",
+"5 ,.f s p u y t r e w q 0 9 8 $ ",
+"> ; * * & & $ @ @ @ X + X . . . ",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V."
+};
diff --git a/src/images/flags/GQ.xpm b/src/images/flags/GQ.xpm
new file mode 100644
index 0000000..2281843
--- /dev/null
+++ b/src/images/flags/GQ.xpm
@@ -0,0 +1,181 @@
+/* XPM */
+static const char *GQ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 159 2",
+" c black",
+". c #000043430000",
+"X c #00004D4D0000",
+"o c #00005D5D0000",
+"O c #000061610000",
+"+ c #000063630000",
+"@ c #000067670000",
+"# c #00006D6D0000",
+"$ c #000071710000",
+"% c #000075750000",
+"& c #000079790000",
+"* c #00007D7D0000",
+"= c #00005F5FDDDD",
+"- c #00007171F5F5",
+"; c #00007B7BFBFB",
+": c #00007D7DF9F9",
+"> c #03037F7FFDFD",
+", c #000081810000",
+"< c #000083830000",
+"1 c #000087870000",
+"2 c #000089890000",
+"3 c #2C2CA1A12C2C",
+"4 c #3131A4A43131",
+"5 c #3737A7A73737",
+"6 c #3D3DAAAA3D3D",
+"7 c #4242ADAD4242",
+"8 c #4949AEAE4949",
+"9 c #4747B0B04747",
+"0 c #4C4CB3B34C4C",
+"q c #4E4EB4B44E4E",
+"w c #5151B4B45151",
+"e c #5353B7B75353",
+"r c #5454B7B75454",
+"t c #5858B9B95757",
+"y c #5959B8B85959",
+"u c #5C5CBABA5C5C",
+"i c #5C5CBBBB5C5C",
+"p c #5F5FBDBD5F5F",
+"a c #6161BEBE6060",
+"s c #6565C0C06565",
+"d c #6969C2C26969",
+"f c #6D6DC3C36D6D",
+"g c #7070C5C57171",
+"h c #7474C7C77474",
+"j c #7777C8C87777",
+"k c #7979C9C97979",
+"l c #7B7BCACA7B7B",
+"z c #13138989DFDF",
+"x c #07078383FDFD",
+"c c #0D0D8787FDFD",
+"v c #11118787FFFF",
+"b c #15158989FBFB",
+"n c #15158989FFFF",
+"m c #7C7CBBBBFCFC",
+"M c #999900000000",
+"N c #9B9B00000000",
+"B c #9D9D00000000",
+"V c #A1A100000000",
+"C c #A3A300000000",
+"Z c #A5A500000000",
+"A c #A9A900000000",
+"S c #ABAB00000000",
+"D c #AFAF00000000",
+"F c #B3B300000000",
+"G c #B7B700000000",
+"H c #B9B900000000",
+"J c #BDBD00000000",
+"K c #CDCD00000000",
+"L c #CCCC1D1D1D1D",
+"P c #CECE20201F1F",
+"I c #CFCF24242424",
+"U c #D1D129292929",
+"Y c #D3D32E2E2E2E",
+"T c #D7D735353535",
+"R c #D3D33E3E3E3E",
+"E c #D7D739393939",
+"W c #D7D73D3D3D3D",
+"Q c #D4D443434343",
+"! c #D5D546464646",
+"~ c #D6D64A4A4A4A",
+"^ c #D7D74C4C4C4C",
+"/ c #D9D942424242",
+"( c #DBDB48484848",
+") c #DEDE4C4C4B4B",
+"_ c #D8D850505050",
+"` c #D9D954545454",
+"' c #DBDB57575757",
+"] c #DDDD5C5C5C5C",
+"[ c #DDDD60606060",
+"{ c #DFDF63636464",
+"} c #E0E059595959",
+"| c #E1E168686969",
+" . c #E2E26C6C6C6C",
+".. c #E4E46F6F6F6F",
+"X. c #8A8ABFBF8585",
+"o. c #B9B9BFBFB9B9",
+"O. c #9E9EA5A5D0D0",
+"+. c #8080BEBEFDFD",
+"@. c #8383BFBFFEFE",
+"#. c #9191BEBEF3F3",
+"$. c #9090C3C38B8B",
+"%. c #BDBDC4C4BEBE",
+"&. c #8F8FCACAE9E9",
+"*. c #8888C1C1FCFC",
+"=. c #8888C3C3FDFD",
+"-. c #8F8FC5C5FCFC",
+";. c #9191C8C8FEFE",
+":. c #9A9ACDCDF7F7",
+">. c #9898C9C9FAFA",
+",. c #9999CBCBFEFE",
+"<. c #9B9BCDCDFEFE",
+"1. c #BFBFC1C1C2C2",
+"2. c #A1A1D0D0FDFD",
+"3. c #F8F8EFEFB6B6",
+"4. c #F9F9F0F0B8B8",
+"5. c #C5C5C8C8C9C9",
+"6. c #DDDDD7D7D5D5",
+"7. c #D8D8DCDCDDDD",
+"8. c gray87",
+"9. c #DFDFE5E5DFDF",
+"0. c #DEDEE2E2E2E2",
+"q. c #E1E1E0E0E0E0",
+"w. c gray89",
+"e. c gray90",
+"r. c #E7E7E7E7E7E7",
+"t. c #E9E9F7F7FBFB",
+"y. c #F1F1EDEDEDED",
+"u. c #F1F1EEEEEEEE",
+"i. c #F2F2EEEEEEEE",
+"p. c #F2F2EFEFEFEF",
+"a. c #F3F3F0F0F0F0",
+"s. c gray95",
+"d. c #F3F3F3F3F3F3",
+"f. c #F1F1F4F4F1F1",
+"g. c #F2F2F5F5F2F2",
+"h. c #F3F3F6F6F3F3",
+"j. c #F4F4F1F1F1F1",
+"k. c #F4F4F7F7F3F3",
+"l. c #F4F4F4F4F4F4",
+"z. c #F4F4F5F5F5F5",
+"x. c gray96",
+"c. c #F6F6F6F6F6F6",
+"v. c gray97",
+"b. c #F1F1F6F6FDFD",
+"n. c #F5F5F8F8F5F5",
+"m. c #F7F7FAFAF7F7",
+"M. c #F8F8F4F4F4F4",
+"N. c #F9F9F5F5F5F5",
+"B. c #F9F9F6F6F6F6",
+"V. c #FAFAF7F7F7F7",
+"C. c #F8F8F8F8F8F8",
+"Z. c #F8F8FBFBF8F8",
+"A. c #F9F9FBFBF9F9",
+"S. c gray98",
+"D. c #FBFBFBFBFBFB",
+"F. c #F9F9FCFCF9F9",
+"G. c gray99",
+"H. c #FDFDFCFCFDFD",
+"J. c None",
+/* pixels */
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"z 2 2 2 2 , , * & % $ # @ O o O ",
+"b &.l l h h g f d s a u t r q X ",
+"n :.p u y r w 0 9 7 6 5 4 3 8 . ",
+"v <.2.F.A.A.m.4.3.m.h.g.g.g.g.9.",
+"c ,. at .b.H.H.A.$.X.v.m.x.x.x.x.r.",
+"x ;. at .@.D.D.A.%.o.x.M.x.x.d.x.e.",
+"> *.m t.D.A.0.5.5.7.M.h.d.s.x.w.",
+"; -.,.V.V.M.M.q.7.p.p.i.u.u.u.6.",
+": #.} ) ( / W E T Y U I L L R M ",
+"- O... .| { [ ] ' ` _ ^ ~ ! ! M ",
+"= K J J G F D S S Z V V B B M B ",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J."
+};
diff --git a/src/images/flags/GR.xpm b/src/images/flags/GR.xpm
new file mode 100644
index 0000000..969c355
--- /dev/null
+++ b/src/images/flags/GR.xpm
@@ -0,0 +1,175 @@
+/* XPM */
+static const char *GR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 153 2",
+" c black",
+". c #000000008787",
+"X c #000000008B8B",
+"o c #000000008F8F",
+"O c #000000009191",
+"+ c #000000009393",
+"@ c #000000009797",
+"# c #000000009B9B",
+"$ c #000000009F9F",
+"% c #00000000A3A3",
+"& c #00000000A7A7",
+"* c #00000000ABAB",
+"= c #00000101ABAB",
+"- c #00000707ADAD",
+"; c #00000F0FAFAF",
+": c #00001818A1A1",
+"> c #00001717B3B3",
+", c #00001D1DB7B7",
+"< c #07072121A9A9",
+"1 c #00002323B9B9",
+"2 c #00002929BDBD",
+"3 c #00002F2FBFBF",
+"4 c #0A0A3434A1A1",
+"5 c #00003535C1C1",
+"6 c #03033535C3C3",
+"7 c #07073B3BC3C3",
+"8 c #09093B3BC4C4",
+"9 c #09093D3DC3C3",
+"0 c #0D0D3F3FC5C5",
+"q c #2B2B5656C8C8",
+"w c #2D2D5757C9C9",
+"e c #2F2F5858CACA",
+"r c #31315A5ACBCB",
+"t c #33335C5CCCCC",
+"y c #35355E5ECDCD",
+"u c #37375F5FCCCC",
+"i c #37376060CDCD",
+"p c #39396161CECE",
+"a c #3C3C6363CFCF",
+"s c #3D3D6565D0D0",
+"d c #3F3F6767D1D1",
+"f c #4C4C7171D4D4",
+"g c #4D4D7171D4D4",
+"h c #4D4D7272D5D5",
+"j c #4F4F7373D5D5",
+"k c #58587676C8C8",
+"l c #7A7A9292D9D9",
+"z c #7C7C9595DADA",
+"x c #81818282C8C8",
+"c c #81818484CDCD",
+"v c #80809898DCDC",
+"b c #84849C9CDDDD",
+"n c #89899F9FD8D8",
+"m c #88889F9FDEDE",
+"M c #8C8CA1A1D9D9",
+"N c #8F8FA3A3DADA",
+"B c #8C8CA2A2DDDD",
+"V c #9292A5A5DCDC",
+"C c #9595A8A8DEDE",
+"Z c #9797AAAADFDF",
+"A c #9B9BACACDDDD",
+"S c #8B8BA2A2E0E0",
+"D c #8F8FA5A5E1E1",
+"F c #9292A7A7E3E3",
+"G c #9797AAAAE0E0",
+"H c #9A9AADADE1E1",
+"J c #9D9DAFAFE2E2",
+"K c #AAAAB0B0C7C7",
+"L c #A0A0B2B2E3E3",
+"P c #A3A3B5B5E5E5",
+"I c #A6A6B7B7E6E6",
+"U c #A9A9BABAE7E7",
+"Y c #B3B3C0C0E4E4",
+"T c #B5B5C1C1E5E5",
+"R c #B5B5C2C2E7E7",
+"E c #B6B6C3C3E6E6",
+"W c #B7B7C4C4E8E8",
+"Q c #B8B8C4C4E6E6",
+"! c #BABAC5C5E7E7",
+"~ c #B9B9C5C5E9E9",
+"^ c #BBBBC7C7E8E8",
+"/ c #BBBBC7C7E9E9",
+"( c #B9B9C6C6EDED",
+") c #BDBDC8C8E7E7",
+"_ c #BDBDC8C8E9E9",
+"` c #BCBCC8C8EAEA",
+"' c #BEBECACAE9E9",
+"] c #BEBECACAEBEB",
+"[ c #BFBFCACAEAEA",
+"{ c #C8C8CACAD6D6",
+"} c #D0D0D0D0D4D4",
+"| c #D5D5D5D5D5D5",
+" . c #D2D2D6D6DDDD",
+".. c #C0C0CBCBECEC",
+"X. c #C0C0CCCCEAEA",
+"o. c #C2C2CDCDEBEB",
+"O. c #C2C2CCCCECEC",
+"+. c #C4C4CECEECEC",
+"@. c #C5C5D0D0EDED",
+"#. c #CFCFD7D7EFEF",
+"$. c #D9D9DFDFF1F1",
+"%. c #E2E2E2E2E2E2",
+"&. c #E0E0E3E3EDED",
+"*. c #E2E2E4E4EDED",
+"=. c #E2E2E5E5EFEF",
+"-. c #E8E8E8E8ECEC",
+";. c #E3E3E6E6F0F0",
+":. c #E4E4E7E7F0F0",
+">. c #E5E5E8E8F1F1",
+",. c #E6E6E9E9F2F2",
+"<. c #E8E8EAEAF3F3",
+"1. c #E8E8ECECF4F4",
+"2. c #E9E9EDEDF5F5",
+"3. c #EBEBEDEDF6F6",
+"4. c #ECECEEEEF2F2",
+"5. c #EDEDEFEFF4F4",
+"6. c #EDEDEEEEF7F7",
+"7. c #EDEDF0F0F7F7",
+"8. c #EEEEF0F0F4F4",
+"9. c #EFEFF0F0F5F5",
+"0. c #EEEEF1F1F8F8",
+"q. c #F0F0F0F0F1F1",
+"w. c #F0F0F0F0F2F2",
+"e. c #F1F1F2F2F3F3",
+"r. c #F2F2F2F2F3F3",
+"t. c #F0F0F2F2F6F6",
+"y. c #F1F1F3F3F7F7",
+"u. c #F3F3F3F3F4F4",
+"i. c #F2F2F4F4F7F7",
+"p. c #F4F4F4F4F5F5",
+"a. c #F4F4F5F5F7F7",
+"s. c #F5F5F5F5F7F7",
+"d. c #F2F2F3F3F8F8",
+"f. c #F3F3F4F4F9F9",
+"g. c #F3F3F5F5FAFA",
+"h. c #F5F5F6F6F8F8",
+"j. c #F6F6F6F6F8F8",
+"k. c #F6F6F7F7F9F9",
+"l. c #F7F7F7F7F9F9",
+"z. c #F7F7F7F7FAFA",
+"x. c #F7F7F8F8FBFB",
+"c. c #F7F7F9F9FCFC",
+"v. c #F8F8F8F8F9F9",
+"b. c #F9F9F9F9FAFA",
+"n. c #FAFAFAFAFBFB",
+"m. c #FBFBFBFBFBFB",
+"M. c #F8F8F9F9FCFC",
+"N. c #F9F9FAFAFCFC",
+"B. c gray99",
+"V. c #FDFDFDFDFDFD",
+"C. c #FEFEFEFEFEFE",
+"Z. c gray100",
+"A. c None",
+/* pixels */
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"0 0 | | 9 8 5 5 2 1 , > ; - * * ",
+"0 j Z.m.f j m.m.z.z.z.z.s.s.g. .",
+"%.Z.Z.Z.Z.m......./ / ! W R X.l ",
+"%.Z.Z.Z.Z.Z.F B S m b v v l n : ",
+"7 j Z.m.a a g.g.d.d.9.9.4.-.q.{ ",
+"5 g Z.B.a a p p y t r e w w y : ",
+"-.B.l.m.m.l.l.s.s.p.e.e.w.w.p.| ",
+"H #. at .@.o.o.[ _ / ! Q T T T _ x ",
+"k ( U I P J J H Z C V V M n A 4 ",
+"$.7.7.6.6.2.2.,.,.:.:.=.=.*.&.K ",
+"> ; - * & % $ # # + O o X X . . ",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A."
+};
diff --git a/src/images/flags/GS.xpm b/src/images/flags/GS.xpm
new file mode 100644
index 0000000..a302573
--- /dev/null
+++ b/src/images/flags/GS.xpm
@@ -0,0 +1,172 @@
+/* XPM */
+static const char *GS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 150 2",
+" c black",
+". c #000000000505",
+"X c #000000000707",
+"o c #000000000D0D",
+"O c #000000001515",
+"+ c #000000001B1B",
+"@ c #000000002323",
+"# c #000000002727",
+"$ c #000000002929",
+"% c #000000002B2B",
+"& c #000000002F2F",
+"* c #000000003131",
+"= c #000000003737",
+"- c #000000003939",
+"; c #000000004343",
+": c #000000005959",
+"> c #000000005D5D",
+", c #0B0B0B0B6464",
+"< c #000000007D7D",
+"1 c #151515156F6F",
+"2 c #181819196D6D",
+"3 c #1A1A1A1A7373",
+"4 c #1E1E1E1E7474",
+"5 c #232323237777",
+"6 c #242424247474",
+"7 c #292929297B7B",
+"8 c #2A2A2A2A7979",
+"9 c #2A2A2A2A7B7B",
+"0 c #2C2C2C2C7A7A",
+"q c #2C2C2C2C7B7B",
+"w c #2F2F2F2F7C7C",
+"e c #2F2F2F2F7D7D",
+"r c #2E2E2E2E7F7F",
+"t c #2F2F2F2F7F7F",
+"y c #323232327F7F",
+"u c #363636367F7F",
+"i c #3A3A37377F7F",
+"p c #5F5F0D0D3F3F",
+"a c #6F6F03032D2D",
+"s c #464646467C7C",
+"d c #313131318282",
+"f c #333333338282",
+"g c #353535358181",
+"h c #343434348383",
+"j c #3B3B3B3B8383",
+"k c #393939398484",
+"l c #383839398686",
+"z c #3A3A3A3A8686",
+"x c #3C3C3C3C8585",
+"c c #3D3D3C3C8686",
+"v c #3D3D3D3D8686",
+"b c #3F3F3F3F8787",
+"n c #3F3F3F3F8A8A",
+"m c #40403F3F8A8A",
+"M c #404040408A8A",
+"N c #424242428A8A",
+"B c #424242428C8C",
+"V c #444444448E8E",
+"C c #454545458E8E",
+"Z c #454545458F8F",
+"A c #464646468D8D",
+"S c #484844448B8B",
+"D c #494949498F8F",
+"F c #494949499191",
+"G c #49494A4A9292",
+"H c #4B4B4B4B9090",
+"J c #4E4E4E4E9393",
+"K c #4F4F4F4F9494",
+"L c #505049498D8D",
+"P c #505050509393",
+"I c #535353539696",
+"U c #545454549696",
+"Y c #535353539B9B",
+"T c #585857579898",
+"R c #585858589999",
+"E c #5C5C5C5C9B9B",
+"W c #5D5D5D5D9D9D",
+"Q c #4F4F6767AFAF",
+"! c #616160609E9E",
+"~ c #616161619F9F",
+"^ c #68686A6A9999",
+"/ c #757572729F9F",
+"( c #65656565A1A1",
+") c #66666666A3A3",
+"_ c #6A6A6A6AA5A5",
+"` c #6B6B6B6BA4A4",
+"' c #6F6F6F6FA8A8",
+"] c #70707070A2A2",
+"[ c #77777777A8A8",
+"{ c #7E7E7E7EABAB",
+"} c #7A7A7F7FB4B4",
+"| c #59598E8E5E5E",
+" . c #65658787C7C7",
+".. c #7777A3A3DBDB",
+"X. c #7A7AB6B6F0F0",
+"o. c #979711112D2D",
+"O. c #A5A521213737",
+"+. c #97972F2F4F4F",
+"@. c #FFFF1B1B0000",
+"#. c #E7E759595959",
+"$. c #EAEA65655F5F",
+"%. c #FCFC69695050",
+"&. c #E3E362626161",
+"*. c #E5E57A7A7979",
+"=. c #E4E47D7D7E7E",
+"-. c #F0F06A6A6262",
+";. c #F1F16F6F6767",
+":. c #F9F979797171",
+">. c #8A8A60608888",
+",. c #8B8B64648D8D",
+"<. c #A4A47B7B9B9B",
+"1. c #AAAA7E7E9898",
+"2. c #959596969A9A",
+"3. c #86868686B4B4",
+"4. c #8B8B8585B3B3",
+"5. c #9B9BB8B8B8B8",
+"6. c #B5B5B5B58383",
+"7. c #D8D880808585",
+"8. c #D8D884848C8C",
+"9. c #D3D38C8C9696",
+"0. c #C8C89191A0A0",
+"q. c #DADAA3A3ACAC",
+"w. c #DADAB3B3BDBD",
+"e. c #E7E78D8D8C8C",
+"r. c #FDFD99998181",
+"t. c #FEFEBCBCACAC",
+"y. c #CACAC3C39F9F",
+"u. c #D3D3CECEA2A2",
+"i. c #FDFDC9C9B8B8",
+"p. c #C1C1C1C1D4D4",
+"a. c #C5C5C5C5D7D7",
+"s. c #C8C8C8C8D9D9",
+"d. c #CACACACADADA",
+"f. c #DEDEDFDFE6E6",
+"g. c #E8E8CACAD0D0",
+"h. c #EBEBCECED3D3",
+"j. c #FFFFCACAC4C4",
+"k. c #FBFBDADAC6C6",
+"l. c #FEFEDFDFD1D1",
+"z. c #E3E3E2E2E3E3",
+"x. c #E1E1E1E1E8E8",
+"c. c #E4E4E4E4ECEC",
+"v. c #E8E8E8E8ECEC",
+"b. c #E9E9E9E9EEEE",
+"n. c #EBEBECECEBEB",
+"m. c #EEEEEEEEEEEE",
+"M. c #F3F3F3F3F4F4",
+"N. c #FDFDFDFDF7F7",
+"B. c #F9F9FFFFFFFF",
+"V. c None",
+/* pixels */
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+":.4.: o.O.> a r.; & $ @ + O o X ",
+"< j.B.w.q.h.N...` ( ! E T I J ",
+"@.=.;.$.#.-.&.%.L N v l f 0 D ",
+"p g.t.*.e.i.7.1.S v 3.b.M.s.{ ",
+" .l.} 9.8.X.k.<.v u c.n.^ x.s. ",
+"+./ Y ,.>.s Q 0.i f M.5.| 2.b. ",
+"- ' K F Z N x g t 8 f.u.6.y.a. ",
+"= ` F Z n l h t 9 6 [ z.n.p.] ",
+"* ) Z m l g t 9 5 4 2 3 1 , e ",
+"$ ~ W R U P D S N v l g f e 0 ",
+"$ + O o X ",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V."
+};
diff --git a/src/images/flags/GT.xpm b/src/images/flags/GT.xpm
new file mode 100644
index 0000000..0862a13
--- /dev/null
+++ b/src/images/flags/GT.xpm
@@ -0,0 +1,161 @@
+/* XPM */
+static const char *GT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 139 2",
+" c black",
+". c #00000000DDDD",
+"X c #00000000DFDF",
+"o c #00000000E1E1",
+"O c #00000000E3E3",
+"+ c #00000000E5E5",
+"@ c #00000303E7E7",
+"# c #00000909E7E7",
+"$ c #00001111E9E9",
+"% c #00001515EBEB",
+"& c #00001919EDED",
+"* c #00002323EFEF",
+"= c #00002525EFEF",
+"- c #00002D2DEFEF",
+"; c #00002D2DF1F1",
+": c #00003131F3F3",
+"> c #00003333F3F3",
+", c #00003535F5F5",
+"< c #00003D3DF7F7",
+"1 c #00004545F5F5",
+"2 c #00004747F9F9",
+"3 c #00004D4DFBFB",
+"4 c #00005151FDFD",
+"5 c #00005353FDFD",
+"6 c #00005555FDFD",
+"7 c #00005959FDFD",
+"8 c #00005B5BFFFF",
+"9 c #00005D5DFFFF",
+"0 c #00005F5FFFFF",
+"q c #03036767FFFF",
+"w c #1F1F7373F1F1",
+"e c #23237575F1F1",
+"r c #23237676F2F2",
+"t c #24247676F2F2",
+"y c #28287979F2F2",
+"u c #29297A7AF2F2",
+"i c #29297A7AF3F3",
+"p c #2D2D7C7CF3F3",
+"a c #2E2E7D7DF3F3",
+"s c #2E2E7E7EF4F4",
+"d c #32328080F4F4",
+"f c #34348181F4F4",
+"g c #34348282F5F5",
+"h c #38388383F5F5",
+"j c #39398585F5F5",
+"k c #39398686F6F6",
+"l c #3D3D8686F2F2",
+"z c #3D3D8787F6F6",
+"x c #3E3E8888F6F6",
+"c c #3F3F8989F7F7",
+"v c #40408787F2F2",
+"b c #42428989F3F3",
+"n c #42428A8AF3F3",
+"m c #43438B8BF7F7",
+"M c #44448A8AF3F3",
+"N c #47478D8DF4F4",
+"B c #45458D8DF8F8",
+"V c #45458D8DF9F9",
+"C c #4B4B8F8FF5F5",
+"Z c #4B4B9090FAFA",
+"A c #4F4F9393FAFA",
+"S c #50509393F5F5",
+"D c #55559696F6F6",
+"F c #50509494FBFB",
+"G c #54549797FBFB",
+"H c #55559797FAFA",
+"J c #55559797FCFC",
+"K c #59599999F7F7",
+"L c #5E5E9C9CF7F7",
+"P c #59599B9BFBFB",
+"I c #5A5A9B9BFBFB",
+"U c #5A5A9B9BFDFD",
+"Y c #5E5E9C9CF9F9",
+"T c #5E5E9E9EFCFC",
+"R c #5E5E9E9EFDFD",
+"E c #5F5F9E9EFCFC",
+"W c #62629E9EF8F8",
+"Q c #6363A0A0FDFD",
+"! c #6363A1A1FDFD",
+"~ c #6262A1A1FEFE",
+"^ c #6666A1A1F9F9",
+"/ c #6666A2A2F9F9",
+"( c #6666A3A3FEFE",
+") c #6767A3A3FEFE",
+"_ c #6868A3A3FAFA",
+"` c #6B6BA5A5FAFA",
+"' c #6A6AA5A5FEFE",
+"] c #6A6AA6A6FEFE",
+"[ c #6F6FA8A8FBFB",
+"{ c #6E6EA8A8FEFE",
+"} c #7474AAAAFCFC",
+"| c #7878AEAEFCFC",
+" . c #7C7CAFAFFDFD",
+".. c #7F7FB1B1FEFE",
+"X. c #7F7FB2B2FEFE",
+"o. c #8282B3B3FEFE",
+"O. c #8484B5B5FEFE",
+"+. c #8585B5B5FEFE",
+"@. c #8787B7B7FFFF",
+"#. c #BBBBC1C1CBCB",
+"$. c gray81",
+"%. c #CBCBCFCFD7D7",
+"&. c gray82",
+"*. c LightGray",
+"=. c #D7D7D7D7D7D7",
+"-. c #D9D9DDDDE5E5",
+";. c #E7E7E7E7E7E7",
+":. c #E3E3E7E7EDED",
+">. c #E9E9E9E9E9E9",
+",. c gray92",
+"<. c #EAEAEEEEF3F3",
+"1. c #EBEBEEEEF4F4",
+"2. c #ECECEFEFF5F5",
+"3. c #EDEDEFEFF4F4",
+"4. c #EEEEF1F1F6F6",
+"5. c #EFEFF2F2F7F7",
+"6. c #F4F4F4F4F4F4",
+"7. c gray96",
+"8. c #F6F6F6F6F6F6",
+"9. c gray97",
+"0. c #F0F0F4F4F8F8",
+"q. c #F1F1F5F5F9F9",
+"w. c #F2F2F4F4F8F8",
+"e. c #F3F3F5F5F8F8",
+"r. c #F3F3F5F5F9F9",
+"t. c #F4F4F6F6FAFA",
+"y. c #F5F5F7F7FBFB",
+"u. c #F6F6F8F8FCFC",
+"i. c #F7F7F9F9FDFD",
+"p. c #F8F8F8F8F8F8",
+"a. c #F9F9F9F9F9F9",
+"s. c gray98",
+"d. c #FBFBFBFBFBFB",
+"f. c #F8F8FAFAFDFD",
+"g. c #FAFAFBFBFEFE",
+"h. c gray99",
+"j. c #FDFDFDFDFDFD",
+"k. c #FDFDFDFDFEFE",
+"l. c None",
+/* pixels */
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"q q 9 9 5 :.,.,.,.;.-., : ; = - ",
+"8 @. at .@. .g.h.h.h.h.y._ ^ W L % ",
+"9 @.{ { ! g.h.h.d.d.0.V m x K $ ",
+"9 @.' ! T i.h.d.a.a.0.c z j D # ",
+"8 o.! ! U y.g.a.a.a.5.j h f S @ ",
+"5 o.! T J t.a.a.a.9.4.g g p C @ ",
+"5 .T I F t.a.p.9.9.1.a p y N o ",
+"3 | I H Z t.p.9.9.6.<.y p t b X ",
+"2 } H F V 0.9.9.9.6.<.e w w v X ",
+"< [ _ ^ Y 0.p.9.9.9.4.b b v l X ",
+"1 : ; = & %.=.*.$.$.#.o X X . . ",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l."
+};
diff --git a/src/images/flags/GU.xpm b/src/images/flags/GU.xpm
new file mode 100644
index 0000000..6ce0217
--- /dev/null
+++ b/src/images/flags/GU.xpm
@@ -0,0 +1,159 @@
+/* XPM */
+static const char *GU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 137 2",
+" c black",
+". c #35355858F1F1",
+"X c #38385C5CF1F1",
+"o c #39395C5CF2F2",
+"O c #3C3C5E5EF2F2",
+"+ c #3D3D6060F2F2",
+"@ c #7F7F7575A9A9",
+"# c #49496464EDED",
+"$ c #41416262F3F3",
+"% c #42426262F3F3",
+"& c #42426464F3F3",
+"* c #46466666F4F4",
+"= c #46466767F4F4",
+"- c #47476767F4F4",
+"; c #47476868F4F4",
+": c #4C4C6B6BF3F3",
+"> c #4C4C6B6BF5F5",
+", c #4C4C6D6DF5F5",
+"< c #50506F6FF2F2",
+"1 c #51516F6FF3F3",
+"2 c #51516F6FF6F6",
+"3 c #52527070F2F2",
+"4 c #53537070F2F2",
+"5 c #51517070F6F6",
+"6 c #51517171F6F6",
+"7 c #55557373F3F3",
+"8 c #56567373F3F3",
+"9 c #55557272F5F5",
+"0 c #55557373F6F6",
+"q c #56567474F7F7",
+"w c #56567575F7F7",
+"e c #58587575F3F3",
+"r c #59597676F4F4",
+"t c #59597676F8F8",
+"y c #5B5B7878F4F4",
+"u c #5C5C7A7AF5F5",
+"i c #5B5B7878F8F8",
+"p c #5C5C7A7AF9F9",
+"a c #5D5D7A7AF9F9",
+"s c #65656464E9E9",
+"d c #60607B7BF5F5",
+"f c #61617D7DF5F5",
+"g c #63637F7FF5F5",
+"h c #60607C7CF9F9",
+"j c #61617E7EFAFA",
+"k c #62627F7FF9F9",
+"l c #62627E7EFAFA",
+"z c #66667F7FF8F8",
+"x c #65658181F6F6",
+"c c #66668282FAFA",
+"v c #66668282FBFB",
+"b c #67678383FAFA",
+"n c #68688383F6F6",
+"m c #69698484F7F7",
+"M c #6B6B8585F7F7",
+"N c #6A6A8686FBFB",
+"B c #6B6B8686FCFC",
+"V c #6C6C8787FCFC",
+"C c #6E6E8888F7F7",
+"Z c #6E6E8989F8F8",
+"A c #6E6E8989FCFC",
+"S c #6F6F8A8AFCFC",
+"D c #71718B8BFBFB",
+"F c #72728B8BF8F8",
+"G c #70708A8AFDFD",
+"H c #70708B8BFDFD",
+"J c #72728C8CF9F9",
+"K c #73738C8CFDFD",
+"L c #73738D8DFDFD",
+"P c #73738E8EFDFD",
+"I c #75758F8FF9F9",
+"U c #76768F8FF9F9",
+"Y c #74748E8EFDFD",
+"T c #76769090FEFE",
+"R c #77779090FEFE",
+"E c #7A7A9191FAFA",
+"W c #7A7A9393FAFA",
+"Q c #7A7A9393FEFE",
+"! c #7E7E9494FBFB",
+"~ c #7E7E9696FBFB",
+"^ c #7D7D9595FEFE",
+"/ c #A0A04A4A7B7B",
+"( c #D9D900000000",
+") c #DBDB00000000",
+"_ c #DFDF00000000",
+"` c #E1E100000000",
+"' c #E3E300000000",
+"] c #E5E500000000",
+"[ c #E7E700000000",
+"{ c #EBEB00000000",
+"} c #EDED00000000",
+"| c #EFEF00000000",
+" . c #F1F100000000",
+".. c #F3F300000000",
+"X. c #F5F500000000",
+"o. c #F7F700000000",
+"O. c #F9F900000000",
+"+. c #FBFB00000000",
+"@. c #FBFB01010000",
+"#. c #FBFB03030000",
+"$. c #FDFD07070000",
+"%. c #FDFD09090000",
+"&. c #C8C855555F5F",
+"*. c #D5D558585F5F",
+"=. c #CECE56566565",
+"-. c #DDDD66664343",
+";. c #D9D961616C6C",
+":. c #E5E564646060",
+">. c #E3E366666868",
+",. c #E5E56E6E6D6D",
+"<. c #E2E26D6D7171",
+"1. c #C7C760608585",
+"2. c #C7C77B7B9F9F",
+"3. c #C2C27979A0A0",
+"4. c #ACAC81817F7F",
+"5. c #DADABCBC4242",
+"6. c #8D8D8383A9A9",
+"7. c #9F9FB8B88989",
+"8. c #A0A0BABA8F8F",
+"9. c #81819898FCFC",
+"0. c #82829999FCFC",
+"q. c #84849A9AFCFC",
+"w. c #85859C9CFCFC",
+"e. c #88889E9EFDFD",
+"r. c #8A8A9E9EFDFD",
+"t. c #8A8AA0A0FEFE",
+"y. c #8C8CA1A1FEFE",
+"u. c #8D8DA2A2FEFE",
+"i. c #8F8FA4A4FEFE",
+"p. c #9292A5A5FEFE",
+"a. c #9292A6A6FEFE",
+"s. c #9494A8A8FFFF",
+"d. c #B4B4C1C1A6A6",
+"f. c #DCDCCFCFD5D5",
+"g. c #D3D3D2D2D8D8",
+"h. c #DDDDD1D1D6D6",
+"j. c None",
+/* pixels */
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"%.%.%.%.#.#.#.#.o.o.o. . . .} } ",
+"%.s.s.p.p.y.t.w.q.0.^ E U D C } ",
+"%.s.^ Q T L L 3.2.z h t w 6 m [ ",
+"%.p.Q T L S 4.7.g.1.i w 5 , x [ ",
+"#.i.T L L B <.7.d.>.0 2 > ; f ` ",
+"#.y.L A B v ,.h.f.:.1 > * & u ` ",
+"#.w.A B v x ;.s 6.*.: * % + r ` ",
+"o.q.b v a p =.@ 5./ * % + o 7 ) ",
+"o.0.v v p i 0 &.-.# % O o . 4 ) ",
+"o.^ W E J C m n x u y r 7 4 , ) ",
+" . . .} } { { [ [ ` _ _ ) ) ) ) ",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j."
+};
diff --git a/src/images/flags/GW.xpm b/src/images/flags/GW.xpm
new file mode 100644
index 0000000..6aa76df
--- /dev/null
+++ b/src/images/flags/GW.xpm
@@ -0,0 +1,175 @@
+/* XPM */
+static const char *GW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 153 2",
+" c black",
+". c #000023230000",
+"X c #000025250000",
+"o c #000027270000",
+"O c #00002D2D0000",
+"+ c #00002F2F0000",
+"@ c #000031310000",
+"# c #000033330000",
+"$ c #000035350000",
+"% c #000039390000",
+"& c #00003B3B0000",
+"* c #00003D3D0000",
+"= c #000041410000",
+"- c #000047470000",
+"; c #5B5B53535353",
+": c #65654F4F4F4F",
+"> c #66664F4F4F4F",
+", c #6F6F58585858",
+"< c #0B0B95950B0B",
+"1 c #0F0F97970E0E",
+"2 c #11118F8F0000",
+"3 c #101097971010",
+"4 c #131399991313",
+"5 c #141499991414",
+"6 c #14149A9A1414",
+"7 c #18189D9D1919",
+"8 c #19199C9C1919",
+"9 c #19199D9D1919",
+"0 c #1F1F9F9F1F1F",
+"q c #1E1EA0A01E1E",
+"w c #1F1FA0A01F1F",
+"e c #2323A2A22323",
+"r c #2424A2A22424",
+"t c #2424A3A32424",
+"y c #2929A4A42929",
+"u c #2A2AA5A52A2A",
+"i c #2C2CA3A32C2C",
+"p c #2F2FA4A42F2F",
+"a c #2F2FA7A72F2F",
+"s c #2E2EA8A82E2E",
+"d c #2F2FA8A82F2F",
+"f c #3232A5A53232",
+"g c #3333A6A63232",
+"h c #3535A8A83535",
+"j c #3434ABAB3434",
+"k c #3535AAAA3535",
+"l c #3636A8A83636",
+"z c #3939A9A93939",
+"x c #3B3BAEAE3A3A",
+"c c #3D3DACAC3D3D",
+"v c #4141A3A33434",
+"b c #4747A6A63A3A",
+"n c #4242AEAE4242",
+"m c #4B4BA8A84040",
+"M c #4646B0B04646",
+"N c #4B4BB3B34B4B",
+"B c #5B5BAEAE5050",
+"V c #8D8D72727373",
+"C c #EDED00000000",
+"Z c #EFEF00000000",
+"A c #F1F100000000",
+"S c #F3F300000000",
+"D c #F5F500000000",
+"F c #F7F700000000",
+"G c #F9F900000000",
+"H c #FBFB00000000",
+"J c #FDFD00000000",
+"K c red",
+"L c #F9F93A3A3A3A",
+"P c #FAFA3F3F3F3F",
+"I c #D4D44A4A4949",
+"U c #DCDC54545454",
+"Y c #FAFA44444444",
+"T c #FBFB45454545",
+"R c #FBFB49494949",
+"E c #FBFB4A4A4B4B",
+"W c #FCFC4F4F5050",
+"Q c #F9F954545555",
+"! c #FDFD54545454",
+"~ c #F9F958585858",
+"^ c #FAFA5D5D5D5D",
+"/ c #FEFE59595959",
+"( c #FDFD5C5C5C5C",
+") c #FEFE5C5C5C5C",
+"_ c #FEFE5F5F5F5F",
+"` c #F6F66F6F6F6F",
+"' c #FBFB61616262",
+"] c #FCFC66666666",
+"[ c #FCFC6A6A6A6A",
+"{ c #F5F576767676",
+"} c #FEFE77777777",
+"| c #FEFE79797979",
+" . c #FFFF7B7B7A7A",
+".. c #FFFF7B7B7B7B",
+"X. c #8787C8C81A1A",
+"o. c #8B8BCACA1F1F",
+"O. c #8E8ECBCB2525",
+"+. c #9090CDCD2B2B",
+"@. c #9494CFCF3030",
+"#. c #9898CFCF3B3B",
+"$. c #9797D1D13636",
+"%. c #9A9AD3D33B3B",
+"&. c #9D9DD8D84040",
+"*. c #A7A7D0D04646",
+"=. c #D7D7A1A10000",
+"-. c #DBDBA5A50000",
+";. c #DDDDA9A90000",
+":. c #DFDFADAD0000",
+">. c #E1E1B1B10000",
+",. c #E5E5B5B50000",
+"<. c #E7E7B7B70000",
+"1. c #E9E9BBBB0000",
+"2. c #EBEBBFBF0000",
+"3. c #EDEDC1C10000",
+"4. c #EFEFC5C50000",
+"5. c #F1F1C7C70000",
+"6. c #F3F3C9C90000",
+"7. c #F3F3CBCB0000",
+"8. c #F4F4F4F42020",
+"9. c #F5F5F5F52525",
+"0. c #F5F5F5F52626",
+"q. c #F6F6F6F62B2B",
+"w. c #F6F6F6F62C2C",
+"e. c #F7F7F7F73030",
+"r. c #F7F7F7F73131",
+"t. c #F5F5F5F53F3F",
+"y. c #F8F8F8F83636",
+"u. c #F8F8F8F83737",
+"i. c #F9F9F9F93C3C",
+"p. c #F9F9F9F93D3D",
+"a. c #F6F6F6F64444",
+"s. c #F7F7F7F74949",
+"d. c #F7F7F7F74E4E",
+"f. c #FCFCF1F14B4B",
+"g. c #FAFAFAFA4141",
+"h. c #FAFAFAFA4242",
+"j. c #FBFBFBFB4646",
+"k. c #FBFBFBFB4747",
+"l. c #FCFCFCFC4B4B",
+"z. c #FCFCFCFC4C4C",
+"x. c #FDFDF1F15151",
+"c. c #FDFDF2F25454",
+"v. c #F8F8F8F85353",
+"b. c #F9F9F9F95757",
+"n. c #FDFDFDFD5151",
+"m. c #FAFAFAFA5C5C",
+"M. c #FBFBFBFB6060",
+"N. c #FCFCFCFC6565",
+"B. c #FCFCFCFC6969",
+"V. c #FDFDFDFD6D6D",
+"C. c #FEFEF5F57474",
+"Z. c #FDFDFDFD7171",
+"A. c None",
+/* pixels */
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"K K K K K 6.6.6.4.4.3.3.1.,.,.>.",
+"K ......} C.Z.V.B.N.m.m.b.v.d.:.",
+"K ..( ( / x.n.z.j.j.p.y.r.w.s.;.",
+"K ..( ( ! x.z.k.h.p.y.r.q.0.a.-.",
+"K { , U E f.k.h.p.y.r.q.0.8.t.=.",
+"K V ; > E *.%.%.$. at .+.O.o.X.#.2 ",
+"K ` > I R m x j d u r q 9 5 l O ",
+"G [ R T P b j p u t q 9 5 3 g @ ",
+"G ] T P L v a u t q 9 4 1 < p X ",
+"D ' ^ ~ Q B N M n c z l g p p X ",
+"D S S C C & - - = * & @ O O X $ ",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A."
+};
diff --git a/src/images/flags/GY.xpm b/src/images/flags/GY.xpm
new file mode 100644
index 0000000..1d91d1f
--- /dev/null
+++ b/src/images/flags/GY.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char * GY_xpm[] = {
+"16 16 165 2",
+" c None",
+". c #39391D",
+"+ c #39A747",
+"@ c #15AB1B",
+"# c #008900",
+"$ c #007F00",
+"% c #007D00",
+"& c #007900",
+"* c #007500",
+"= c #007100",
+"- c #006D00",
+"; c #006700",
+"> c #006300",
+", c #005D00",
+"' c #005700",
+") c #D30000",
+"! c #C19192",
+"~ c #CDD5B3",
+"{ c #EDF9DD",
+"] c #DAF1D8",
+"^ c #8ACF91",
+"/ c #70C475",
+"( c #6DC06D",
+"_ c #69C069",
+": c #65BF65",
+"< c #61BE60",
+"[ c #5CBB5C",
+"} c #58B957",
+"| c #53B753",
+"1 c #4EB44E",
+"2 c #004B00",
+"3 c #FF0000",
+"4 c #FC7B7A",
+"5 c #C1605F",
+"6 c #B0A163",
+"7 c #F1F67D",
+"8 c #FCFDCD",
+"9 c #E6F3D4",
+"0 c #CAE8CA",
+"a c #5DBB68",
+"b c #42AE46",
+"c c #3DA93D",
+"d c #37AA37",
+"e c #31A831",
+"f c #2CA62C",
+"g c #49B249",
+"h c #004500",
+"i c #FE7979",
+"j c #FE5C5C",
+"k c #DB5959",
+"l c #A27554",
+"m c #CAD051",
+"n c #FCFC56",
+"o c #FBFB75",
+"p c #F5F8C9",
+"q c #DCEDCA",
+"r c #82C881",
+"s c #47B152",
+"t c #2BA32F",
+"u c #269E26",
+"v c #44AE44",
+"w c #004100",
+"x c #FD0000",
+"y c #FE7676",
+"z c #FE5858",
+"A c #FD5454",
+"B c #F44F50",
+"C c #B24F4B",
+"D c #777046",
+"E c #E9EA41",
+"F c #F9F93C",
+"G c #F8F845",
+"H c #F7F7AF",
+"I c #F0F3C0",
+"J c #D3E7C1",
+"K c #71C069",
+"L c #55B455",
+"M c #004300",
+"N c #FE7273",
+"O c #FD5353",
+"P c #FC4F4F",
+"Q c #FC4A4B",
+"R c #FB4646",
+"S c #744040",
+"T c #83833B",
+"U c #F4F636",
+"V c #F7F730",
+"W c #F6F62B",
+"X c #F5F525",
+"Y c #F4F43C",
+"Z c #F3F3D9",
+"` c #E8EFE4",
+" . c #007700",
+".. c #FD6F6F",
+"+. c #FB4A49",
+"@. c #F64545",
+"#. c #794040",
+"$. c #9E8B3A",
+"%. c #E2E335",
+"&. c #F7F72F",
+"*. c #F6F635",
+"=. c #F5F5A5",
+"-. c #EFF2B8",
+";. c #D5E7BC",
+">. c #73BF68",
+",. c #53B352",
+"'. c #003B00",
+"). c #FB0000",
+"!. c #FC6A6A",
+"~. c #FB4949",
+"{. c #D94545",
+"]. c #6B4E3F",
+"^. c #BAC03A",
+"/. c #F8F83C",
+"(. c #F7F75D",
+"_. c #F2F5BE",
+":. c #D8EAC1",
+"<. c #7AC377",
+"[. c #39A845",
+"}. c #14981C",
+"|. c #109210",
+"1. c #33A432",
+"2. c #002F00",
+"3. c #F90000",
+"4. c #FB6666",
+"5. c #BA4444",
+"6. c #6D6241",
+"7. c #E6EC5D",
+"8. c #F8F8BE",
+"9. c #E2EEC8",
+"0. c #C1E1BE",
+"a. c #44AE50",
+"b. c #1E9D25",
+"c. c #189619",
+"d. c #139613",
+"e. c #0F960E",
+"f. c #0B950B",
+"g. c #2FA42F",
+"h. c #002D00",
+"i. c #CD0000",
+"j. c #B57779",
+"k. c #8D907D",
+"l. c #E8F4D2",
+"m. c #D1EACC",
+"n. c #71C178",
+"o. c #4CB255",
+"p. c #46AC46",
+"q. c #42AC42",
+"r. c #3DAB3D",
+"s. c #39A939",
+"t. c #35A835",
+"u. c #32A532",
+"v. c #2CA22C",
+"w. c #002700",
+"x. c #150900",
+"y. c #000100",
+"z. c #009300",
+"A. c #006100",
+"B. c #004D00",
+"C. c #004700",
+"D. c #003D00",
+"E. c #003900",
+"F. c #003300",
+"G. c #002900",
+"H. c #003500",
+" ",
+" ",
+". + @ # $ % % & * = - ; > , ' ' ",
+") ! ~ { ] ^ / ( _ : < [ } | 1 2 ",
+"3 4 5 6 7 8 9 0 a b c d e f g h ",
+"3 i j k l m n o p q r s t u v w ",
+"x y z A B C D E F G H I J K L M ",
+"x N O P Q R S T U V W X Y Z ` .",
+"x ..P +. at .#.$.%.&.*.=.-.;.>.,.'.",
+").!.~.{.].^./.(._.:.<.[.}.|.1.2.",
+"3.4.5.6.7.8.9.0.a.b.c.d.e.f.g.h.",
+"i.j.k.l.m.n.o.p.q.r.s.t.u.g.v.w.",
+"x.y.z.A.B.2 2 C.w D.E.F.2.h.G.H.",
+" ",
+" ",
+" "};
diff --git a/src/images/flags/HK.xpm b/src/images/flags/HK.xpm
new file mode 100644
index 0000000..b4b4b6f
--- /dev/null
+++ b/src/images/flags/HK.xpm
@@ -0,0 +1,159 @@
+/* XPM */
+static const char *HK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 137 2",
+" c black",
+". c #BBBB00000000",
+"X c #BDBD00000000",
+"o c #BFBF00000000",
+"O c #C1C100000000",
+"+ c #C3C300000000",
+"@ c #C7C700000000",
+"# c #C9C900000000",
+"$ c #CBCB00000000",
+"% c #CDCD00000000",
+"& c #CFCF00000000",
+"* c #D1D100000000",
+"= c #D5D500000000",
+"- c #D7D700000000",
+"; c #D9D900000000",
+": c #DBDB00000000",
+"> c #DFDF00000000",
+", c #DFDF0B0B0B0B",
+"< c #E1E100000000",
+"1 c #E3E300000000",
+"2 c #E5E500000000",
+"3 c #E7E700000000",
+"4 c #E1E10F0F0E0E",
+"5 c #E9E900000000",
+"6 c #EBEB00000000",
+"7 c #EDED00000000",
+"8 c #E1E110101010",
+"9 c #E1E113131313",
+"0 c #E2E214141414",
+"q c #E3E319191919",
+"w c #E2E21B1B1B1B",
+"e c #E4E41A1A1A1A",
+"r c #E4E41F1F1F1F",
+"t c #E5E520202020",
+"y c #E5E524242424",
+"u c #E6E625252525",
+"i c #E6E626262626",
+"p c #E2E22C2C2C2C",
+"a c #E3E32F2F2F2F",
+"s c #E7E72B2B2B2B",
+"d c #E8E82C2C2C2C",
+"f c #E9E92C2C2C2C",
+"g c #EAEA2E2E2E2E",
+"h c #E4E432323232",
+"j c #E6E635353535",
+"k c #E6E636363636",
+"l c #E6E639393939",
+"z c #E7E73B3B3B3B",
+"x c #E7E73D3D3D3D",
+"c c #E8E831313131",
+"v c #E9E931313131",
+"b c #EBEB31313131",
+"n c #EAEA37373737",
+"m c #EBEB38383838",
+"M c #EBEB3A3A3A3A",
+"N c #E8E83F3F3F3F",
+"B c #EBEB3C3C3D3D",
+"V c #ECEC38383838",
+"C c #EEEE38383838",
+"Z c #ECEC3E3E3D3D",
+"A c #ECEC3F3F3F3F",
+"S c #E8E842424242",
+"D c #E9E944444444",
+"F c #E9E946464646",
+"G c #ECEC40404040",
+"H c #EDED42424242",
+"J c #EEEE44444444",
+"K c #EEEE45454545",
+"L c #EAEA49494949",
+"P c #EBEB4B4B4B4B",
+"I c #EFEF49494949",
+"U c #EFEF4A4A4949",
+"Y c #EFEF4A4A4C4C",
+"T c #ECEC4E4E4E4E",
+"R c #ECEC50505050",
+"E c #EDED53535353",
+"W c #EDED54545555",
+"Q c #EEEE57575757",
+"! c #EEEE58585858",
+"~ c #EFEF5C5C5C5C",
+"^ c #EFEF5D5D5D5D",
+"/ c #F0F04F4F4F4F",
+"( c #F2F24F4F4F4F",
+") c #F0F051515151",
+"_ c #F0F053535353",
+"` c #F3F350505050",
+"' c #F3F353535353",
+"] c #F1F154545454",
+"[ c #F1F156565656",
+"{ c #F2F254545454",
+"} c #F2F255555555",
+"| c #F3F356565656",
+" . c #F5F555555555",
+".. c #F1F158585858",
+"X. c #F1F159595959",
+"o. c #F2F25C5C5C5C",
+"O. c #F3F35F5F5F5F",
+"+. c #F0F060606060",
+"@. c #F0F061616262",
+"#. c #F1F165656565",
+"$. c #F2F266666666",
+"%. c #F2F26A6A6A6A",
+"&. c #F2F26D6D6D6D",
+"*. c #F2F26F6F6F6F",
+"=. c #F3F370707171",
+"-. c #F3F372727373",
+";. c #F3F374747474",
+":. c #F4F476767676",
+">. c #F4F477777777",
+",. c #F5F579797979",
+"<. c #F5F57B7B7A7A",
+"1. c #F5F57B7B7B7B",
+"2. c #F6F67E7E7E7E",
+"3. c #F6F68F8F8F8F",
+"4. c #FCFC8B8B8C8C",
+"5. c #FBFB96969696",
+"6. c #F9F99E9E9F9F",
+"7. c #F8F8A7A7A8A8",
+"8. c #F9F9AAAAAAAA",
+"9. c #FBFBAAAAAAAA",
+"0. c #FAFABDBDBDBD",
+"q. c #F7F7C3C3C3C3",
+"w. c #F7F7CACACBCB",
+"e. c #F7F7CECECECE",
+"r. c #F7F7CECECFCF",
+"t. c #FBFBC0C0C0C0",
+"y. c #F9F9C5C5C6C6",
+"u. c #FAFACDCDCECE",
+"i. c #F6F6D8D8D8D8",
+"p. c #F8F8D0D0D1D1",
+"a. c #FCFCD1D1D1D1",
+"s. c #F8F8D8D8D8D8",
+"d. c #F5F5E1E1E1E1",
+"f. c #F8F8E7E7E7E7",
+"g. c #FAFAECECECEC",
+"h. c #FBFBEEEEEEEE",
+"j. c None",
+/* pixels */
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"7 6 6 6 6 7 1 1 1 1 > : : - - - ",
+"6 1.1.1.:.:.=.&.%.#.+.~ Q E T & ",
+"6 1.O.~ ..' ' 4.5.H B n v d L & ",
+"6 ,.~ ..] ] ] h.0. .Z v s i D $ ",
+"6 :...] ] a.t.a.y.f.r.m i t x $ ",
+"6 -.' ( / 7.g.6.7.q.2.g r e M @ ",
+"1 =.T I J H 7.p.r.i.s r q 0 k + ",
+"1 %.I K Z ( i.w.3.d.V w 9 9 h + ",
+"1 $.K G m V ' v i ' w 9 4 , a X ",
+"1 @.~ ! Q T L F S x l k h a p . ",
+"1 : : - - * & & $ @ + + + X X + ",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j."
+};
diff --git a/src/images/flags/HM.xpm b/src/images/flags/HM.xpm
new file mode 100644
index 0000000..5fc845d
--- /dev/null
+++ b/src/images/flags/HM.xpm
@@ -0,0 +1,186 @@
+/* XPM */
+static const char * HM_xpm[] = {
+"16 16 167 2",
+" c None",
+". c #C77783",
+"+ c #877FA7",
+"@ c #003795",
+"# c #8D2743",
+"$ c #912541",
+"% c #002387",
+"& c #753D69",
+"* c #B77187",
+"= c #000B73",
+"- c #000063",
+"; c #00005F",
+"> c #00005B",
+", c #49639F",
+"' c #000051",
+") c #00003F",
+"! c #000039",
+"~ c #4B4D8D",
+"{ c #EAC6C9",
+"] c #E5DDE6",
+"^ c #DDACB3",
+"/ c #DCA4AA",
+"( c #DDC3CC",
+"_ c #EDD8DC",
+": c #A9B5D4",
+"< c #7589BA",
+"[ c #7285B8",
+"} c #697FB3",
+"| c #C4CCE0",
+"1 c #C8D0E1",
+"2 c #A6B3D0",
+"3 c #5D74AC",
+"4 c #00003B",
+"5 c #CD0909",
+"6 c #E68E8F",
+"7 c #E97A79",
+"8 c #E46C6B",
+"9 c #E26564",
+"0 c #E7716F",
+"a c #E06F70",
+"b c #D6666A",
+"c c #5F6EA7",
+"d c #4F6AA8",
+"e c #4962A2",
+"f c #667BB1",
+"g c #ACB6D2",
+"h c #355197",
+"i c #556EA8",
+"j c #000037",
+"k c #8F3555",
+"l c #E8B9BE",
+"m c #F1A4A2",
+"n c #E17F80",
+"o c #E28284",
+"p c #F1A7A5",
+"q c #DB8C91",
+"r c #B38298",
+"s c #576AA6",
+"t c #9DABCC",
+"u c #3E5A9C",
+"v c #AEB8D3",
+"w c #6D81B3",
+"x c #00002D",
+"y c #7F89B7",
+"z c #E8CCD1",
+"A c #A1A2C2",
+"B c #C88B97",
+"C c #CA8794",
+"D c #9FB9DB",
+"E c #DEB8BE",
+"F c #A490AC",
+"G c #9AA8CB",
+"H c #BAC2D9",
+"I c #BAC4DA",
+"J c #355297",
+"K c #8D9BC1",
+"L c #B3BCD4",
+"M c #B2BBD4",
+"N c #000025",
+"O c #6B4575",
+"P c #9495BB",
+"Q c #5A7AB6",
+"R c #8C789E",
+"S c #8A749B",
+"T c #4C6CAC",
+"U c #7086B8",
+"V c #9A89A9",
+"W c #475E9E",
+"X c #A5B2CF",
+"Y c #5A72A9",
+"Z c #304D94",
+"` c #4A63A1",
+" . c #8F9EC2",
+".. c #48619F",
+"+. c #778EBD",
+"@. c #5D74AD",
+"#. c #5271AE",
+"$. c #4C6CAB",
+"%. c #5068A5",
+"&. c #4862A2",
+"*. c #405DA0",
+"=. c #405C9E",
+"-. c #385499",
+";. c #325095",
+">. c #304D93",
+",. c #94A3C5",
+"'. c #314E94",
+"). c #455F9E",
+"!. c #00001F",
+"~. c #778ABB",
+"{. c #5870AB",
+"]. c #A4B0D0",
+"^. c #C9D0E2",
+"/. c #4A63A2",
+"(. c #445FA0",
+"_. c #405B9D",
+":. c #3B569A",
+"<. c #365297",
+"[. c #314D94",
+"}. c #29468F",
+"|. c #203F8B",
+"1. c #22408A",
+"2. c #435C9B",
+"3. c #00001B",
+"4. c #000059",
+"5. c #7186B8",
+"6. c #576FAA",
+"7. c #DBE0EB",
+"8. c #E7E9F0",
+"9. c #9AA9CA",
+"0. c #3D599B",
+"a. c #3A5699",
+"b. c #355196",
+"c. c #28478F",
+"d. c #445E9D",
+"e. c #97A4C5",
+"f. c #1B3B87",
+"g. c #40599A",
+"h. c #000017",
+"i. c #000053",
+"j. c #6F84B6",
+"k. c #697EB3",
+"l. c #94A4C8",
+"m. c #C3CADD",
+"n. c #5B72AA",
+"o. c #5A71A9",
+"p. c #536AA6",
+"q. c #5069A4",
+"r. c #4C65A3",
+"s. c #435D9D",
+"t. c #B6BFD4",
+"u. c #E0E2EA",
+"v. c #909EC2",
+"w. c #3C5798",
+"x. c #00000F",
+"y. c #00004D",
+"z. c #000049",
+"A. c #000041",
+"B. c #000035",
+"C. c #00002F",
+"D. c #000029",
+"E. c #000019",
+"F. c #000013",
+"G. c #00000D",
+"H. c #254183",
+"I. c #000005",
+"J. c #000003",
+" ",
+" ",
+". + @ # $ % & * = - ; > , ' ) ! ",
+"~ { ] ^ / ( _ : < [ } | 1 2 3 4 ",
+"5 6 7 8 9 0 a b c d e f g h i j ",
+"k l m n o p q r s t e u h v w x ",
+"y z A B C D E F G H I J K L M N ",
+"O P Q R S T U V W X Y Z ` ...N ",
+"- +. at .#.$.%.&.*.=.-.;.>.,.'.).!.",
+"; ~.{.].^./.(._.:.<.[.}.|.1.2.3.",
+"4.5.6.7.8.9.0.a.b.Z c.d.e.f.g.h.",
+"i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.",
+"y.z.A.4 B.C.D.N !.E.F.G.H.I.J.J.",
+" ",
+" ",
+" "};
diff --git a/src/images/flags/HN.xpm b/src/images/flags/HN.xpm
new file mode 100644
index 0000000..40e11b0
--- /dev/null
+++ b/src/images/flags/HN.xpm
@@ -0,0 +1,176 @@
+/* XPM */
+static const char *HN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 154 2",
+" c black",
+". c #000000004B4B",
+"X c #000000004D4D",
+"o c #000000005151",
+"O c #000000005353",
+"+ c #000000005555",
+"@ c #000000005757",
+"# c #000000005959",
+"$ c #000000005F5F",
+"% c #000000006363",
+"& c #000000006767",
+"* c #000000006D6D",
+"= c #000000006F6F",
+"- c #000000007171",
+"; c #000000007575",
+": c #000000007B7B",
+"> c #000000007F7F",
+", c #000000008383",
+"< c #000000008787",
+"1 c #000000008989",
+"2 c #000000008B8B",
+"3 c #000000008D8D",
+"4 c #000000008F8F",
+"5 c #000000009393",
+"6 c #000000009797",
+"7 c #000003039999",
+"8 c #000007079B9B",
+"9 c #000007079D9D",
+"0 c #00000D0D9F9F",
+"q c #00001111A1A1",
+"w c #00001F1FA5A5",
+"e c #0B0B3232B1B1",
+"r c #0F0F3636B2B2",
+"t c #13133939B4B4",
+"y c #18183E3EB8B8",
+"u c #1E1E4242B9B9",
+"i c #3B3B51519B9B",
+"p c #23234747BBBB",
+"a c #29294B4BBCBC",
+"s c #2C2C4E4EBFBF",
+"d c #2F2F5050BCBC",
+"f c #2E2E5050BFBF",
+"g c #36365555BEBE",
+"h c #37375757BFBF",
+"j c #31315454C1C1",
+"k c #34345656C2C2",
+"l c #37375858C4C4",
+"z c #3B3B5B5BC0C0",
+"x c #3A3A5A5AC3C3",
+"c c #3F3F5E5EC2C2",
+"v c #3D3D5E5EC6C6",
+"b c #3F3F5E5EC6C6",
+"n c #45455B5BA5A5",
+"m c #42426161C3C3",
+"M c #46466464C4C4",
+"N c #42426262C8C8",
+"B c #44446363C8C8",
+"V c #47476666CACA",
+"C c #4A4A6767C6C6",
+"Z c #49496767C8C8",
+"A c #4F4F6B6BC8C8",
+"S c #4C4C6A6ACCCC",
+"D c #53536F6FCACA",
+"F c #51516E6ECDCD",
+"G c #55557272CFCF",
+"H c #57577373CCCC",
+"J c #58587373CCCC",
+"K c #5B5B7676CDCD",
+"L c #5C5C7777CDCD",
+"P c #59597575D1D1",
+"I c #5C5C7878D1D1",
+"U c #5F5F7B7BD3D3",
+"Y c #60607A7ACFCF",
+"T c #60607B7BCFCF",
+"R c #64647E7ED1D1",
+"E c #65657F7FD1D1",
+"W c #66667F7FD3D3",
+"Q c #68688181D3D3",
+"! c #69698383D3D3",
+"~ c #6C6C8484D5D5",
+"^ c #70708888D6D6",
+"/ c #74748B8BD7D7",
+"( c #77778F8FD8D8",
+") c #7A7A9191DADA",
+"_ c #7B7B9292DADA",
+"` c #7D7D9494DADA",
+"' c #7F7F9595DCDC",
+"] c #83839393C9C9",
+"[ c #87879797CDCD",
+"{ c #81819595D6D6",
+"} c #81819797DCDC",
+"| c #84849898D9D9",
+" . c #87879B9BD9D9",
+".. c #9797A8A8DFDF",
+"X. c #A9A9B5B5DDDD",
+"o. c #ABABB7B7DEDE",
+"O. c #A2A2B0B0E1E1",
+"+. c #A6A6B5B5E2E2",
+"@. c #ADADB9B9E0E0",
+"#. c #AEAEBABAE0E0",
+"$. c #AEAEBBBBE2E2",
+"%. c #B2B2BDBDE2E2",
+"&. c #B0B0BDBDE4E4",
+"*. c #B2B2BFBFE5E5",
+"=. c #B4B4BFBFE1E1",
+"-. c #B5B5BFBFE7E7",
+";. c #B4B4C0C0E3E3",
+":. c #B6B6C2C2E5E5",
+">. c #B9B9C4C4E6E6",
+",. c #B9B9C4C4E7E7",
+"<. c #B8B8C4C4E8E8",
+"1. c #BBBBC6C6E9E9",
+"2. c #BDBDC8C8E9E9",
+"3. c #BEBEC8C8EAEA",
+"4. c #BFBFCACAEBEB",
+"5. c #C1C1C1C1C1C1",
+"6. c #C5C5C5C5C5C5",
+"7. c gray78",
+"8. c #C0C0CACAEAEA",
+"9. c #C1C1CACAECEC",
+"0. c #C2C2CCCCECEC",
+"q. c #C2C2CDCDEDED",
+"w. c #C5C5CFCFEEEE",
+"e. c #C6C6D0D0EFEF",
+"r. c #CDCDD6D6F0F0",
+"t. c #D0D0D8D8F2F2",
+"y. c gray90",
+"u. c #E7E7E7E7E7E7",
+"i. c #E3E3E5E5F1F1",
+"p. c #E8E8EBEBF6F6",
+"a. c #EBEBECECF1F1",
+"s. c #EAEAEDEDF3F3",
+"d. c gray95",
+"f. c #F3F3F3F3F3F3",
+"g. c #F3F3F3F3F4F4",
+"h. c #F4F4F4F4F4F4",
+"j. c #F4F4F5F5F5F5",
+"k. c gray96",
+"l. c #F6F6F6F6F6F6",
+"z. c gray97",
+"x. c #F3F3F4F4F9F9",
+"c. c #F3F3F4F4FBFB",
+"v. c #F8F8F8F8F8F8",
+"b. c #F8F8F9F9F9F9",
+"n. c #F9F9F9F9F9F9",
+"m. c #F9F9F9F9FAFA",
+"M. c gray98",
+"N. c #FAFAFAFAFBFB",
+"B. c #FBFBFBFBFBFB",
+"V. c #FBFBFCFCFBFB",
+"C. c gray99",
+"Z. c #FDFDFDFDFDFD",
+"A. c #FEFEFEFEFEFE",
+"S. c None",
+/* pixels */
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"w q q q 0 8 7 6 5 4 2 < , > : : ",
+"0 } ' ' ` _ _ / / ~ Q E Y K H = ",
+"9 _ R P P G S S V N v l j s Z & ",
+"[ t.e.w.q.4.4.3.<.<.-.*.$.$.>.n ",
+"u.A.A.A.c...B.B.v.v. .s.k.k.k.7.",
+"u.A.A.A.C.p.v.+.O.z.i.k.f.f.k.7.",
+"u.A.B.B.c.| v.v.z.z.{ a.f.d.d.5.",
+"] r.q.8.2.>.>.:.*.%.$.o.X.X.=.i ",
+"2 E B v x k d a p u y t r e d . ",
+"2 ! E Y L K D A C M m b z h g . ",
+": , > : ; - = & % $ # O O O X O ",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S."
+};
diff --git a/src/images/flags/HR.xpm b/src/images/flags/HR.xpm
new file mode 100644
index 0000000..47ace6c
--- /dev/null
+++ b/src/images/flags/HR.xpm
@@ -0,0 +1,153 @@
+/* XPM */
+static const char *HR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 131 2",
+" c black",
+". c #000000008F8F",
+"X c #000000009191",
+"o c #000000009393",
+"O c #000003039595",
+"+ c #000009099797",
+"@ c #00000D0D9B9B",
+"# c #000013139F9F",
+"$ c #00001919A3A3",
+"% c #00001F1FA5A5",
+"& c #00002727A9A9",
+"* c #00002D2DADAD",
+"= c #00003333AFAF",
+"- c #00003939B3B3",
+"; c #00004141B7B7",
+": c #00004545B9B9",
+"> c #00004B4BBDBD",
+", c #00005151BFBF",
+"< c #00005757C3C3",
+"1 c #42427474A9A9",
+"2 c #36368282CBCB",
+"3 c #3A3A8585CCCC",
+"4 c #3B3B8585CCCC",
+"5 c #3E3E8686CDCD",
+"6 c #3F3F8888CDCD",
+"7 c #51518080B1B1",
+"8 c #43438A8ACFCF",
+"9 c #47478D8DD1D1",
+"0 c #48488D8DD1D1",
+"q c #4C4C9090D3D3",
+"w c #51519292D1D1",
+"e c #51519393D5D5",
+"r c #54549494D2D2",
+"t c #55559494D2D2",
+"y c #56569595D3D3",
+"u c #54549696D6D6",
+"i c #58589696D3D3",
+"p c #59599A9AD7D7",
+"a c #5A5A9898D4D4",
+"s c #5D5D9999D5D5",
+"d c #5E5E9D9DD9D9",
+"f c #60609C9CD7D7",
+"g c #65659E9ED8D8",
+"h c #6262A0A0DBDB",
+"j c #6363A0A0DBDB",
+"k c #6767A3A3DCDC",
+"l c #6767A3A3DDDD",
+"z c #6868A1A1DADA",
+"x c #6A6AA4A4DEDE",
+"c c #6C6CA4A4DBDB",
+"v c #6C6CA6A6DEDE",
+"b c #6F6FA7A7DDDD",
+"n c #7474A9A9DDDD",
+"m c #7777ACACDFDF",
+"M c #7272A9A9E0E0",
+"N c #7B7BAFAFE1E1",
+"B c #7F7FB2B2E2E2",
+"V c #6666C4C4DCDC",
+"C c #6E6EC8C8DFDF",
+"Z c #E7E700000000",
+"A c #E9E900000000",
+"S c #EBEB00000000",
+"D c #EDED00000000",
+"F c #EFEF00000000",
+"G c #F1F100000000",
+"H c #F3F300000000",
+"J c #F5F500000000",
+"K c #F7F700000000",
+"L c #F9F900000000",
+"P c #FBFB00000000",
+"I c #FDFD00000000",
+"U c red",
+"Y c #F5F526262626",
+"T c #F6F62A2A2A2A",
+"R c #F6F62B2B2B2B",
+"E c #F6F62C2C2C2C",
+"W c #F7F72F2F2F2F",
+"Q c #F7F731313131",
+"! c #F4F437373636",
+"~ c #F8F835353535",
+"^ c #F8F836363636",
+"/ c #F8F837373737",
+"( c #F9F93C3C3D3D",
+") c #F6F644444444",
+"_ c #F7F749494949",
+"` c #FAFA40404040",
+"' c #FAFA41414141",
+"] c #FAFA41414242",
+"[ c #FCFC4B4B4B4B",
+"{ c #F7F757575757",
+"} c #F8F851515151",
+"| c #FDFD54545454",
+" . c #F8F85C5C5C5C",
+".. c #FEFE59595959",
+"X. c #FEFE5C5C5C5C",
+"o. c #FEFE5F5F5F5F",
+"O. c #F9F960606060",
+"+. c #FAFA65656565",
+"@. c #FBFB69696969",
+"#. c #FBFB6E6E6E6E",
+"$. c #FAFA73737474",
+"%. c #FBFB76767676",
+"&. c #FDFD79797A7A",
+"*. c #FEFE79797979",
+"=. c #FEFE7B7B7B7B",
+"-. c #FFFF7B7B7A7A",
+";. c #FFFF7B7B7B7B",
+":. c #8383B4B4E3E3",
+">. c #8787B6B6E5E5",
+",. c #F7F7C8C8C8C8",
+"<. c #F9F9CCCCCCCC",
+"1. c #FBFBD0D0D0D0",
+"2. c gray89",
+"3. c gray90",
+"4. c #E7E7E7E7E7E7",
+"5. c #EFEFEFEFEFEF",
+"6. c #F0F0F1F1F1F1",
+"7. c gray95",
+"8. c #F3F3F3F3F3F3",
+"9. c #F4F4F4F4F4F4",
+"0. c #F4F4F5F5F5F5",
+"q. c gray96",
+"w. c #F6F6F6F6F6F6",
+"e. c gray97",
+"r. c #FBFBFBFBFBFB",
+"t. c #FBFBFCFCFBFB",
+"y. c gray99",
+"u. c #FDFDFCFCFDFD",
+"i. c #FDFDFDFDFDFD",
+"p. c #FEFEFEFEFEFE",
+"a. c None",
+/* pixels */
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"U U U U P U U U P P K K H H D D ",
+"U ;.;.;.;.;.;.%.$.#. at .+.O. .{ S ",
+"U ;.X.X.| | M C x V ( / Q E _ S ",
+"U ;.X.X.| } [ 1.' <.! Q T Y ) Z ",
+"i.i.i.i.i.e.1.' <./ 8.0.0.0.0.4.",
+"i.i.i.i.i.w.' <./ ,.8.8.8.8.0.4.",
+"i.i.t.i.r.0.<./ ,.T 5.8.8.8.8.2.",
+"< >.x l g d 7 E T 1 0 8 6 3 y o ",
+", :.l h d p u e 0 0 8 8 3 2 y o ",
+"> B B m n b c z g f s a y y w . ",
+": ; - = * & % $ # @ + O o . . . ",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a."
+};
diff --git a/src/images/flags/HT.xpm b/src/images/flags/HT.xpm
new file mode 100644
index 0000000..cb8e49e
--- /dev/null
+++ b/src/images/flags/HT.xpm
@@ -0,0 +1,133 @@
+/* XPM */
+static const char * HT_xpm[] = {
+"16 16 114 2",
+" c None",
+". c #0527C7",
+"+ c #0327C7",
+"@ c #001FC5",
+"# c #0019C3",
+"$ c #0013C1",
+"% c #0007BB",
+"& c #0001B9",
+"* c #0000B5",
+"= c #0000B1",
+"- c #0000AF",
+"; c #0000AB",
+"> c #95A4E8",
+", c #94A3E8",
+"' c #93A1E7",
+") c #919FE7",
+"! c #8F9EE6",
+"~ c #8C9BE5",
+"{ c #8A99E3",
+"] c #8696E2",
+"^ c #8393E1",
+"/ c #7B8CDE",
+"( c #7889DD",
+"_ c #7687DF",
+": c #6F82DA",
+"< c #0000A3",
+"[ c #7E8FE2",
+"} c #7B8DE2",
+"| c #798AE0",
+"1 c #7286DF",
+"2 c #6F83DE",
+"3 c #6B7DDB",
+"4 c #667ADA",
+"5 c #677AD7",
+"6 c #5D71D6",
+"7 c #586DD5",
+"8 c #5469D3",
+"9 c #6B7ED8",
+"0 c #00009F",
+"a c #7689E0",
+"b c #6075D5",
+"c c #586DD4",
+"d c #4F65D1",
+"e c #000099",
+"f c #6276D8",
+"g c #5E74D8",
+"h c #546CD4",
+"i c #5068D3",
+"j c #4B63D1",
+"k c #465FCF",
+"l c #0B15AF",
+"m c #969ADC",
+"n c #7B81D3",
+"o c #787DD1",
+"p c #7379CF",
+"q c #6F76CD",
+"r c #6A70C8",
+"s c #676DC9",
+"t c #6369C7",
+"u c #565CC0",
+"v c #5258BE",
+"w c #000079",
+"x c #FD0000",
+"y c #FD7B6F",
+"z c #FB5A49",
+"A c #FB5445",
+"B c #FA5040",
+"C c #F94B3A",
+"D c #F84535",
+"E c #F63B2A",
+"F c #F53724",
+"G c #F32D19",
+"H c #F22814",
+"I c #F44636",
+"J c #E70000",
+"K c #E90000",
+"L c #F5796A",
+"M c #F25A49",
+"N c #F15645",
+"O c #F15544",
+"P c #F04C3A",
+"Q c #EE4734",
+"R c #ED412F",
+"S c #EC3C29",
+"T c #EB3723",
+"U c #E9321E",
+"V c #E82E19",
+"W c #E72A14",
+"X c #E52510",
+"Y c #E94432",
+"Z c #CB0000",
+"` c #F47566",
+" . c #EE4634",
+".. c #EC3C2A",
+"+. c #E82D19",
+"@. c #E5240E",
+"#. c #E5200B",
+"$. c #E8412F",
+"%. c #C50000",
+"&. c #F37062",
+"*. c #F26C5D",
+"=. c #F16455",
+"-. c #EF6050",
+";. c #EF5B4B",
+">. c #ED5242",
+",. c #EC4E3D",
+"'. c #EB4B39",
+"). c #E94735",
+"!. c #E8402F",
+"~. c #E73E2C",
+"{. c #E10000",
+"]. c #D90000",
+"^. c #D70000",
+"/. c #CF0000",
+" ",
+" ",
+" ",
+". + . . @ @ # $ $ % & * = - ; ; ",
+"+ > , ' ) ! ~ { ] ^ / / ( _ : < ",
+"+ , [ } | _ 1 2 3 4 5 6 7 8 9 0 ",
+"+ ' } a _ 1 2 3 4 b 6 c 8 d 5 e ",
+"@ ! a a 2 3 4 f g 7 h i j k g e ",
+"l m ^ n o p q r s t t u v v r w ",
+"x y z z A B C D D E F F G H I J ",
+"K L M N O P Q R S T U V W X Y Z ",
+"J ` N P P .R ..T U +.X @.#.$.%.",
+"J &.*.=.=.-.;.N >.,.'.).Y !.~.%.",
+"{.{.{.].].^.^./././.Z Z Z %.%.%.",
+" ",
+" "};
diff --git a/src/images/flags/HU.xpm b/src/images/flags/HU.xpm
new file mode 100644
index 0000000..75ab3c7
--- /dev/null
+++ b/src/images/flags/HU.xpm
@@ -0,0 +1,142 @@
+/* XPM */
+static const char *HU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 120 2",
+" c black",
+". c #000001010000",
+"X c #000007070000",
+"o c #00000D0D0000",
+"O c #000013130000",
+"+ c #00001B1B0000",
+"@ c #000021210000",
+"# c #000027270000",
+"$ c #00002F2F0000",
+"% c #000035350000",
+"& c #00003B3B0000",
+"* c #000041410000",
+"= c #000047470000",
+"- c #00004F4F0000",
+"; c #0B0B7B7B0B0B",
+": c #0F0F7E7E0E0E",
+"> c #10107E7E1010",
+", c #131381811313",
+"< c #141481811414",
+"1 c #181884841919",
+"2 c #191984841919",
+"3 c #1E1E87871E1E",
+"4 c #1F1F87871F1F",
+"5 c #23238A8A2323",
+"6 c #24248B8B2424",
+"7 c #29298D8D2929",
+"8 c #2A2A8E8E2A2A",
+"9 c #2C2C8C8C2C2C",
+"0 c #2F2F8F8F2F2F",
+"q c #2E2E90902E2E",
+"w c #2F2F91912F2F",
+"e c #32328F8F3232",
+"r c #333390903232",
+"t c #353593933535",
+"y c #343494943434",
+"u c #393995953939",
+"i c #3A3A97973A3A",
+"p c #3D3D98983D3D",
+"a c #3F3F9A9A3F3F",
+"s c #40409B9B3F3F",
+"d c #424299994242",
+"f c #44449E9E4444",
+"g c #45459E9E4545",
+"h c #46469D9D4646",
+"j c #4B4B9F9F4B4B",
+"k c #4949A1A14949",
+"l c #5050A2A25050",
+"z c #5454A4A45555",
+"x c #5858A8A85858",
+"c c #5D5DAAAA5D5D",
+"v c #6161ADAD6262",
+"b c #6666AFAF6666",
+"n c #6A6AB3B36A6A",
+"m c #A3A300000000",
+"M c #A9A900000000",
+"N c #ABAB00000000",
+"B c #AFAF00000000",
+"V c #B3B300000000",
+"C c #B7B700000000",
+"Z c #B9B900000000",
+"A c #BDBD00000000",
+"S c #BFBF00000000",
+"D c #C3C300000000",
+"F c #C7C700000000",
+"G c #C9C900000000",
+"H c #CDCD00000000",
+"J c #D5D526262626",
+"K c #D7D72B2B2B2B",
+"L c #D7D72C2C2C2C",
+"P c #D9D931313131",
+"I c #DADA37373636",
+"U c #DADA37373737",
+"Y c #DCDC3C3C3C3C",
+"T c #DCDC3C3C3D3D",
+"R c #DBDB44444444",
+"E c #DEDE41414242",
+"W c #DEDE42424242",
+"Q c #DFDF47474747",
+"! c #DCDC49494949",
+"~ c #DDDD4E4E4E4E",
+"^ c #DFDF53535353",
+"/ c #E0E04B4B4B4B",
+"( c #E1E14C4C4C4C",
+") c #E1E151515151",
+"_ c #E1E157575757",
+"` c #E3E354545454",
+"' c #E2E25C5C5C5C",
+"] c #E4E459595959",
+"[ c #E4E45C5C5C5C",
+"{ c #E5E55F5F5F5F",
+"} c #E3E360606060",
+"| c #E4E465656565",
+" . c #E6E669696969",
+".. c #E6E66D6D6D6D",
+"X. c #E8E870707171",
+"o. c #E8E874747474",
+"O. c #E8E877777777",
+"+. c #E9E979797979",
+"@. c #EAEA7B7B7A7A",
+"#. c #EAEA7B7B7B7B",
+"$. c gray89",
+"%. c gray90",
+"&. c #E7E7E7E7E7E7",
+"*. c gray95",
+"=. c #F3F3F3F3F3F3",
+"-. c #F4F4F4F4F4F4",
+";. c #F4F4F5F5F5F5",
+":. c gray96",
+">. c #F6F6F6F6F6F6",
+",. c gray97",
+"<. c #F8F8F8F8F8F8",
+"1. c #F9F9F9F9F9F9",
+"2. c gray98",
+"3. c #FBFBFBFBFBFB",
+"4. c #FBFBFCFCFBFB",
+"5. c gray99",
+"6. c #FDFDFCFCFDFD",
+"7. c #FDFDFDFDFDFD",
+"8. c #FEFEFEFEFEFE",
+"9. c None",
+/* pixels */
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"H H H H H G G G D D S S Z C V B ",
+"H #.#.O.O.o.o... .| } ' _ ^ ~ N ",
+"H #.{ [ [ ` ) / Q W T I P L ! N ",
+"H #.[ [ ` ( / Q W T I P K J R m ",
+"7.7.7.7.5.5.7.2.2.2.,.;.;.;.;.&.",
+"7.7.7.7.2.2.2.2.,.;.,.;.=.=.;.&.",
+"7.7.4.4.2.2.2.2.,.,.;.;.=.=.=.$.",
+"- n j g s i y q 8 5 4 2 < > e ",
+"= b g p i y q 8 5 3 2 < > ; 0 ",
+"* v c x z l j h d p u t e 0 9 ",
+"& % % # @ + O o X ",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9."
+};
diff --git a/src/images/flags/ID.xpm b/src/images/flags/ID.xpm
new file mode 100644
index 0000000..af91ef5
--- /dev/null
+++ b/src/images/flags/ID.xpm
@@ -0,0 +1,134 @@
+/* XPM */
+static const char *ID_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 112 2",
+" c black",
+". c #B5B500000000",
+"X c #BBBB00000000",
+"o c #BFBF00000000",
+"O c #C1C100000000",
+"+ c #C7C700000000",
+"@ c #C9C900000000",
+"# c #CBCB00000000",
+"$ c #CFCF00000000",
+"% c #CBCB1F1F1313",
+"& c #D1D100000000",
+"* c #D3D300000000",
+"= c #D5D500000000",
+"- c #D9D900000000",
+"; c #DBDB00000000",
+": c #DDDD00000000",
+"> c #DFDF00000000",
+", c #DFDF03030000",
+"< c #DFDF11110303",
+"1 c #DBDB33332727",
+"2 c #DDDD37372C2C",
+"3 c #DFDF3D3D3232",
+"4 c #DFDF44443939",
+"5 c #E0E042423737",
+"6 c #E2E247473C3C",
+"7 c #E0E048483E3E",
+"8 c #E1E148483E3E",
+"9 c #E3E34B4B4141",
+"0 c #E2E24E4E4343",
+"q c #E2E24E4E4444",
+"w c #E0E050504646",
+"e c #E5E550504646",
+"r c #E3E352524848",
+"t c #E3E353534949",
+"y c #E5E557574E4E",
+"u c #E6E655554C4C",
+"i c #E2E25E5E5555",
+"p c #E7E75A5A5050",
+"a c #E6E65C5C5252",
+"s c #E6E65C5C5353",
+"d c #E9E95E5E5555",
+"f c #E4E462625959",
+"g c #E6E666665E5E",
+"h c #E8E860605656",
+"j c #E8E861615757",
+"k c #E9E963635A5A",
+"l c #E9E964645B5B",
+"z c #E9E964645C5C",
+"x c #EAEA67675D5D",
+"c c #E7E76A6A6262",
+"v c #E9E968686060",
+"b c #EAEA68686060",
+"n c #E8E86F6F6666",
+"m c #EAEA6C6C6464",
+"M c #EBEB6C6C6464",
+"N c #EBEB6D6D6565",
+"B c #E9E973736B6B",
+"V c #EAEA77776F6F",
+"C c #ECEC70706868",
+"Z c #EDED73736B6B",
+"A c #EDED76766E6E",
+"S c #ECEC7A7A7373",
+"D c #EDED7F7F7676",
+"F c #EDED81817A7A",
+"G c #EEEE81817A7A",
+"H c #EEEE84847E7E",
+"J c #E6E68E8E8888",
+"K c #EFEF87878080",
+"L c #E8E891918B8B",
+"P c #E9E994948E8E",
+"I c #EAEA97979191",
+"U c #ECEC9A9A9595",
+"Y c #E9E99E9E9999",
+"T c #EDED9E9E9898",
+"R c #F0F08A8A8383",
+"E c #F0F08B8B8585",
+"W c #F0F08C8C8585",
+"Q c #F1F18E8E8787",
+"! c #EEEEA0A09B9B",
+"~ c #EFEFA4A49E9E",
+"^ c #F0F0A7A7A1A1",
+"/ c #F1F1A9A9A4A4",
+"( c #F2F2ABABA7A7",
+") c #F3F3AEAEAAAA",
+"_ c #F6F6BDBDB9B9",
+"` c #DDDDDDDDDDDD",
+"' c #DFDFDFDFDFDF",
+"] c #E1E1E1E1E1E1",
+"[ c gray89",
+"{ c gray90",
+"} c #E7E7E7E7E7E7",
+"| c #E9E9E9E9E9E9",
+" . c gray92",
+".. c gray93",
+"X. c #EDEDEFEFEDED",
+"o. c #EFEFEFEFEFEF",
+"O. c #F1F1F1F1F1F1",
+"+. c gray95",
+"@. c #F2F2F2F2F3F3",
+"#. c #F3F3F3F3F3F3",
+"$. c #F4F4F4F4F4F4",
+"%. c gray96",
+"&. c #F6F6F6F6F6F6",
+"*. c gray97",
+"=. c #F8F8F8F8F8F8",
+"-. c #F9F9F9F9F9F9",
+";. c gray98",
+":. c #FBFBFBFBFBFB",
+">. c #FBFBFCFCFBFB",
+",. c gray99",
+"<. c #FDFDFDFDFDFD",
+"1. c None",
+/* pixels */
+"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.",
+"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.",
+"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.",
+"< , , , , , ; ; ; * * * * @ @ + ",
+", Q Q E E H H D D S V B n c v o ",
+", Q A Z C N v x f s u t q 7 f o ",
+", E Z C M b l h s y t q 4 4 i X ",
+"; D x z d p u e 9 6 4 3 2 1 w . ",
+"N _ ) ( / ^ ~ ! T U P P L J Y % ",
+">.>.>.>.;.;.=.=.=.*.&.&.+.+.&.[ ",
+">.>.>.>.;.=.=.*.&.&.+.+.+.+.+.' ",
+",.>.;.;.;.=.*.&.&.&.+.+.+.+.+.' ",
+"*.,.=.=.=.=.*.*.&.&.&.+.+.+.+.` ",
+"*.#.+.O.o.o. .| { { ] ] ' ' ` ` ",
+"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.",
+"1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1."
+};
diff --git a/src/images/flags/IE.xpm b/src/images/flags/IE.xpm
new file mode 100644
index 0000000..d05df0b
--- /dev/null
+++ b/src/images/flags/IE.xpm
@@ -0,0 +1,158 @@
+/* XPM */
+static const char *IE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 136 2",
+" c black",
+". c #000053530000",
+"X c #00005B5B0000",
+"o c #000063630000",
+"O c #000067670000",
+"+ c #00006F6F0000",
+"@ c #000075750000",
+"# c #000077770000",
+"$ c #00007B7B0000",
+"% c #00007F7F0000",
+"& c #000083830000",
+"* c #000085850000",
+"= c #000087870000",
+"- c #000089890000",
+"; c #000091910000",
+": c #3A3AAAAA3A3A",
+"> c #3F3FAEAE3F3F",
+", c #4040ADAD3F3F",
+"< c #4444B1B14444",
+"1 c #4545B0B04545",
+"2 c #4545B1B14545",
+"3 c #4B4BB3B34B4B",
+"4 c #4949B4B44949",
+"5 c #4F4FB6B64F4F",
+"6 c #4F4FB7B74F4F",
+"7 c #5050B5B55050",
+"8 c #5454B5B55555",
+"9 c #5454B7B75454",
+"0 c #5353B9B95353",
+"q c #5454B9B95454",
+"w c #5858B9B95858",
+"e c #5858BBBB5959",
+"r c #5959BABA5959",
+"t c #5858BCBC5858",
+"y c #5C5CBDBD5C5C",
+"u c #5D5DBCBC5D5D",
+"i c #5F5FBFBF5F5F",
+"p c #6161BEBE6262",
+"a c #6666C0C06666",
+"s c #6A6AC3C36A6A",
+"d c #6F6FC4C46F6F",
+"f c #7272C6C67373",
+"g c #7777C7C77777",
+"h c #7676C8C87676",
+"j c #7979C8C87979",
+"k c #7B7BCACA7A7A",
+"l c #7B7BCACA7B7B",
+"z c #DDDD00000000",
+"x c #DFDF00000000",
+"c c #E1E100000000",
+"v c #E3E300000000",
+"b c #E5E500000000",
+"n c #E7E700000000",
+"m c #E9E900000000",
+"M c #EBEB00000000",
+"N c #EFEF13130000",
+"B c #EDED1B1B0000",
+"V c #F1F119190000",
+"C c #F3F31F1F0000",
+"Z c #F5F521210000",
+"A c #F1F167670B0B",
+"S c #F1F169690E0E",
+"D c #F2F269691313",
+"F c #F2F26A6A1010",
+"G c #F2F26D6D1414",
+"H c #F2F26E6E1414",
+"J c #F3F36D6D1919",
+"K c #F3F36F6F1919",
+"L c #F3F370701A1A",
+"P c #F4F472721F1F",
+"I c #F4F474741F1F",
+"U c #F4F475752020",
+"Y c #F5F575752525",
+"T c #F5F577772525",
+"R c #F5F57A7A2626",
+"E c #F2F27B7B2C2C",
+"W c #F2F27C7C2F2F",
+"Q c #F2F27D7D2F2F",
+"! c #F6F679792B2B",
+"~ c #F6F67B7B2B2B",
+"^ c #F6F67C7C2C2C",
+"/ c #F2F27F7F3232",
+"( c #F3F37F7F3232",
+") c #F3F37F7F3535",
+"_ c #F7F77E7E3131",
+"` c #F7F781813131",
+"' c #F4F482823636",
+"] c #F4F485853B3B",
+"[ c #F5F589893F3F",
+"{ c #F8F882823737",
+"} c #F6F68C8C4444",
+"| c #F7F78F8F4949",
+" . c #F7F793934E4E",
+".. c #F8F896965353",
+"X. c #F9F998985757",
+"o. c #FAFA99995C5C",
+"O. c #B7B7C7C7B7B7",
+"+. c #C5C5B5B5A9A9",
+"@. c gray79",
+"#. c #CBCBCBCBCBCB",
+"$. c gray81",
+"%. c gray82",
+"&. c #E1E1DFDFDBDB",
+"*. c gray89",
+"=. c gray90",
+"-. c #E5E5E7E7E5E5",
+";. c #E7E7E7E7E7E7",
+":. c #E9E9F2F2E9E9",
+">. c #EAEAF3F3EAEA",
+",. c #EBEBF3F3EBEB",
+"<. c #ECECF4F4ECEC",
+"1. c #EDEDF5F5EDED",
+"2. c #EEEEF6F6EEEE",
+"3. c #EFEFF7F7EFEF",
+"4. c #F3F3EAEAE2E2",
+"5. c #F4F4EBEBE4E4",
+"6. c #F5F5ECECE5E5",
+"7. c #F4F4ECECE6E6",
+"8. c #F6F6EEEEE7E7",
+"9. c #F7F7EFEFE8E8",
+"0. c #F8F8F0F0EAEA",
+"q. c #F9F9F1F1EBEB",
+"w. c #F4F4F4F4F4F4",
+"e. c gray96",
+"r. c #F6F6F6F6F6F6",
+"t. c gray97",
+"y. c #F0F0F8F8F0F0",
+"u. c #F8F8F8F8F8F8",
+"i. c #F9F9F9F9F9F9",
+"p. c #FBFBFAFAF8F8",
+"a. c gray98",
+"s. c #FBFBFBFBFBFB",
+"d. c gray99",
+"f. c #FDFDFDFDFDFD",
+"g. c #FDFDFDFDFEFE",
+"h. c None",
+/* pixels */
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"; - - = & ;.;.;.;.*.&.Z C V N B ",
+"= l l l g s.d.d.d.d.p.o.X... .M ",
+"- l i y e y.d.d.p.d.q.{ ` ^ | M ",
+"= l r r 0 3.d.d.a.i.9._ ~ R } b ",
+"= g r 0 5 2.d.i.i.u.9.~ T U [ b ",
+"& f 0 5 3 2.i.i.u.u.9.Y P K ] b ",
+"% d 5 4 1 2.i.i.r.r.5.P K G ' v ",
+"$ s 3 < > :.i.e.r.e.5.J G S ( x ",
+"$ p < > : :.u.e.e.w.5.D S A / x ",
+"+ p u e 8 <.r.u.e.e.7.) / W E z ",
+"@ O o X . O.%.$.#. at .+.v v x z z ",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h."
+};
diff --git a/src/images/flags/IL.xpm b/src/images/flags/IL.xpm
new file mode 100644
index 0000000..6c058c0
--- /dev/null
+++ b/src/images/flags/IL.xpm
@@ -0,0 +1,116 @@
+/* XPM */
+static const char *IL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 94 2",
+" c black",
+". c #00000000BBBB",
+"X c #00000000CFCF",
+"o c #00002525DFDF",
+"O c #07074747E9E9",
+"+ c #58588484F2F2",
+"@ c #5A5A8585F2F2",
+"# c #5D5D8282F6F6",
+"$ c #5D5D8787F3F3",
+"% c #62628585F7F7",
+"& c #60608A8AF3F3",
+"* c #63638C8CF4F4",
+"= c #66668F8FF5F5",
+"- c #67678A8AF8F8",
+"; c #6B6B8B8BF9F9",
+": c #6A6A9191F6F6",
+"> c #6E6E9494F7F7",
+", c #76768E8EF7F7",
+"< c #70708F8FFAFA",
+"1 c #71719797F7F7",
+"2 c #74749494FBFB",
+"3 c #75759999F7F7",
+"4 c #75759A9AF8F8",
+"5 c #79799D9DF8F8",
+"6 c #79799E9EF9F9",
+"7 c #7C7C9F9FF9F9",
+"8 c #7D7DA0A0F9F9",
+"9 c #7F7FA3A3FAFA",
+"0 c #BBBBBBBBBBBB",
+"q c gray74",
+"w c gray75",
+"e c #80809393F6F6",
+"r c #81819494F7F7",
+"t c #86869F9FF5F5",
+"y c #83839999FAFA",
+"u c #88889F9FFAFA",
+"i c #9B9B9B9BF9F9",
+"p c #9F9F9F9FF8F8",
+"a c #8080A4A4FAFA",
+"s c #8383A5A5FBFB",
+"d c #8484A6A6FBFB",
+"f c #8787A8A8FCFC",
+"g c #8D8DA6A6F7F7",
+"h c #8A8AA0A0FBFB",
+"j c #8A8AAAAAFCFC",
+"k c #8D8DADADFDFD",
+"l c #9090AFAFFEFE",
+"z c #9595ABABFAFA",
+"x c #9292B1B1FEFE",
+"c c #9595B3B3FEFE",
+"v c #9696B4B4FEFE",
+"b c #9999B5B5FFFF",
+"n c #9C9CB1B1FCFC",
+"m c #C1C1C1C1C1C1",
+"M c #C3C3C3C3C3C3",
+"N c #C5C5C5C5C5C5",
+"B c gray78",
+"V c #CBCBCBCBCBCB",
+"C c #CDCDCDCDCDCD",
+"Z c gray81",
+"A c LightGray",
+"S c #D5D5D5D5D5D5",
+"D c #D7D7D7D7D7D7",
+"F c gray86",
+"G c #DFDFDFDFDFDF",
+"H c #E1E1E1E1E1E1",
+"J c gray89",
+"K c gray90",
+"L c #E7E7E7E7E7E7",
+"P c #E9E9E9E9E9E9",
+"I c #E9E9E9E9F6F6",
+"U c #E9E9E9E9F8F8",
+"Y c #ECECECECFBFB",
+"T c #EFEFEFEFF9F9",
+"R c #F1F1F1F1F1F1",
+"E c gray95",
+"W c #F3F3F3F3F3F3",
+"Q c #F2F2F2F2F4F4",
+"! c #F4F4F4F4F4F4",
+"~ c #F4F4F5F5F5F5",
+"^ c gray96",
+"/ c #F6F6F6F6F6F6",
+"( c gray97",
+") c #F8F8F8F8F8F8",
+"_ c #F9F9F9F9F9F9",
+"` c gray98",
+"' c #FBFBFBFBFBFB",
+"] c #FBFBFCFCFBFB",
+"[ c gray99",
+"{ c #FDFDFCFCFDFD",
+"} c #FDFDFDFDFDFD",
+"| c #FEFEFEFEFEFE",
+" . c gray100",
+".. c None",
+/* pixels */
+"................................",
+"................................",
+"................................",
+"P P P P P L L K J H G F F D S A ",
+"O b c c c l l k j d s 8 7 5 3 X ",
+"P . . . .} } } ' ' ' ' ( / ( C ",
+"P . . .} } ' u t ' ( / / / / V ",
+"L . .' } n 2 y i - g / W / / B ",
+"L . .' .Y < Q U % I ^ ! W ! N ",
+"J .' ' ' z ; p , # t W W W W m ",
+"H [ ' ' ' ) ' , , ^ W W W R W w ",
+"H [ ) ' ' ) / / ( ^ W W R R W w ",
+"o d a 7 5 4 1 > > * * & $ $ + . ",
+"F F D S A Z C C B N M m w 0 0 0 ",
+"................................",
+"................................"
+};
diff --git a/src/images/flags/IN.xpm b/src/images/flags/IN.xpm
new file mode 100644
index 0000000..9894b85
--- /dev/null
+++ b/src/images/flags/IN.xpm
@@ -0,0 +1,178 @@
+/* XPM */
+static const char *IN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 156 2",
+" c black",
+". c #00001F1F0000",
+"X c #000021210000",
+"o c #000025250000",
+"O c #000027270000",
+"+ c #000029290000",
+"@ c #00002D2D0000",
+"# c #000033330000",
+"$ c #000039390000",
+"% c #00003D3D0000",
+"& c #000041410000",
+"* c #000047470000",
+"= c #00004D4D0000",
+"- c #000053530000",
+"; c #000059590000",
+": c #00005D5D0000",
+"> c #000063630000",
+", c #000069690000",
+"< c #00006F6F0000",
+"1 c #000073730000",
+"2 c #383895953939",
+"3 c #3C3C97973C3C",
+"4 c #3D3D97973D3D",
+"5 c #404099994040",
+"6 c #414199994141",
+"7 c #45459C9C4545",
+"8 c #49499F9F4949",
+"9 c #4D4DA1A14D4D",
+"0 c #4E4EA2A24E4E",
+"q c #5353A2A25353",
+"w c #5252A4A45252",
+"e c #5555A4A45555",
+"r c #5656A4A45656",
+"t c #5656A6A65656",
+"y c #5757A7A75757",
+"u c #5858A5A55858",
+"i c #5959A6A65959",
+"p c #5B5BA8A85B5B",
+"a c #5B5BA9A95B5B",
+"s c #5B5BAAAA5B5B",
+"d c #5F5FA9A95F5F",
+"f c #6060ACAC6060",
+"g c #6262ACAC6262",
+"h c #6464AFAF6464",
+"j c #6565AEAE6565",
+"k c #6565AFAF6464",
+"l c #6969B0B06969",
+"z c #6969B1B16969",
+"x c #6969B2B26969",
+"c c #6D6DB2B26D6D",
+"v c #6D6DB4B46D6D",
+"b c #7171B4B47171",
+"n c #7575B7B77575",
+"m c #7979B9B97979",
+"M c #7D7DBCBC7D7D",
+"N c #7F7F9292C7C7",
+"B c #E9E997970000",
+"V c #EBEB9B9B0000",
+"C c #EDED9F9F0000",
+"Z c #EFEFA3A30000",
+"A c #E7E7B1B10000",
+"S c #F1F1A5A50000",
+"D c #F3F3A9A90000",
+"F c #F5F5ADAD0000",
+"G c #F7F7B1B10000",
+"H c #F9F9B3B30000",
+"J c #FBFBB5B50000",
+"K c #FDFDB9B90000",
+"L c #FDFDBBBB0000",
+"P c #FDFDBDBD0000",
+"I c #FDFDBFBF0000",
+"U c #FFFFBFBF0000",
+"Y c #F6F6CECE2C2C",
+"T c #F7F7D0D03131",
+"R c #F8F8D2D23737",
+"E c #FDFDD5D53535",
+"W c #F9F9D4D43D3D",
+"Q c #F7F7D5D54949",
+"! c #F7F7D7D74E4E",
+"~ c #FAFAD5D54242",
+"^ c #FBFBD7D74747",
+"/ c #FCFCD8D84C4C",
+"( c #F8F8D8D85353",
+") c #F9F9D9D95757",
+"_ c #FDFDDADA5151",
+"` c #FDFDDBDB5454",
+"' c #FAFADBDB5C5C",
+"] c #FEFEDCDC5959",
+"[ c #FEFEDEDE5C5C",
+"{ c #FEFEDFDF5F5F",
+"} c #F4F4DADA6969",
+"| c #F6F6DBDB6D6D",
+" . c #FBFBDDDD6060",
+".. c #FCFCDDDD6565",
+"X. c #FCFCDFDF6969",
+"o. c #F7F7DDDD7171",
+"O. c #F5F5DEDE7E7E",
+"+. c #F8F8DEDE7575",
+"@. c #FDFDE0E06D6D",
+"#. c #FDFDE2E27171",
+"$. c #FEFEE2E27474",
+"%. c #FEFEE3E37777",
+"&. c #FEFEE4E47979",
+"*. c #FFFFE4E47A7A",
+"=. c #FFFFE4E47B7B",
+"-. c #83838C8CBDBD",
+";. c #8080BEBE8080",
+":. c #A1A1AAAAB5B5",
+">. c #A4A4ACACB8B8",
+",. c #84849595CACA",
+"<. c #8A8A9E9ECECE",
+"1. c #9A9AA5A5CFCF",
+"2. c #9696A8A8D3D3",
+"3. c #9797A9A9D5D5",
+"4. c #A1A1B3B3DADA",
+"5. c #8484C0C08484",
+"6. c #8888C3C38888",
+"7. c #BBBBC2C2DEDE",
+"8. c #BDBDC0C0D9D9",
+"9. c #D3D3CACA9090",
+"0. c #D8D8D0D09A9A",
+"q. c #FCFCE5E58888",
+"w. c #FCFCE6E68B8B",
+"e. c #FDFDE7E78E8E",
+"r. c #FEFEE8E89090",
+"t. c #FEFEEDEDA4A4",
+"y. c #C4C4CBCBE4E4",
+"u. c #C9C9CDCDE2E2",
+"i. c gray89",
+"p. c #E3E3E3E3E5E5",
+"a. c #E3E3E5E5E7E7",
+"s. c gray95",
+"d. c #F2F2F2F2F3F3",
+"f. c #F3F3F3F3F3F3",
+"g. c #F2F2F3F3F4F4",
+"h. c #F3F3F3F3F4F4",
+"j. c #F4F4F4F4F4F4",
+"k. c #F4F4F4F4F5F5",
+"l. c gray96",
+"z. c #F5F5F6F6F6F6",
+"x. c #F6F6F6F6F6F6",
+"c. c gray97",
+"v. c gray98",
+"b. c #FBFBFBFBFBFB",
+"n. c #FBFBFBFBFCFC",
+"m. c #FBFBFCFCFBFB",
+"M. c #FBFBFCFCFCFC",
+"N. c #FBFBFCFCFDFD",
+"B. c #FBFBFDFDFDFD",
+"V. c gray99",
+"C. c #FCFCFCFCFDFD",
+"Z. c #FDFDFDFDFDFD",
+"A. c #FCFCFDFDFEFE",
+"S. c #FDFDFDFDFEFE",
+"D. c #FDFDFEFEFEFE",
+"F. c None",
+/* pixels */
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"U U U U U U K K J H G F D S Z C ",
+"U =.=.=.%.%.#.X.X... .' ) ( ! V ",
+"U =.[ [ ` ` ` / ^ ~ W R T Y Q B ",
+"E t.r.e.e.q.0.:.:.9.+.+.| } O.A ",
+"B.D.D.B.n.B.4.1.u.3.z.z.k.g.k.a.",
+"D.D.D.B.D.v.3.8.-.<.c.k.k.f.g.i.",
+"D.D.m.v.v.v.y.,.N 7.k.k.f.f.k.i.",
+"1 6.v x k f p y w 9 8 7 6 4 i O ",
+"< ;.l k f p r w 9 8 7 6 4 2 r X ",
+", ;.M m n b c l j g d p r e q . ",
+"> : ; - = * & % $ # @ + O X . . ",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F."
+};
diff --git a/src/images/flags/IO.xpm b/src/images/flags/IO.xpm
new file mode 100644
index 0000000..e918c51
--- /dev/null
+++ b/src/images/flags/IO.xpm
@@ -0,0 +1,193 @@
+/* XPM */
+static const char *IO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 171 2",
+" c black",
+". c #000000003737",
+"X c #000000003939",
+"o c #000000003D3D",
+"O c #000029290F0F",
+"+ c #000000004141",
+"@ c #000000004343",
+"# c #000000004949",
+"$ c #000000004B4B",
+"% c #000000004F4F",
+"& c #000000005353",
+"* c #000000005757",
+"= c #000000005959",
+"- c #000000005B5B",
+"; c #000000006161",
+": c #000000006767",
+"> c #000000006B6B",
+", c #000000006D6D",
+"< c #000000007171",
+"1 c #000000007373",
+"2 c #000000007575",
+"3 c #000000007F7F",
+"4 c #000000008181",
+"5 c #000000008383",
+"6 c #000000008989",
+"7 c #000009099191",
+"8 c #3F3F27278B8B",
+"9 c #5B5B47479999",
+"0 c #40404949A7A7",
+"q c #45454D4DAAAA",
+"w c #49495151ACAC",
+"e c #4A4A5252ACAC",
+"r c #4E4E5656AFAF",
+"t c #4F4F5757AFAF",
+"y c #52525959AEAE",
+"u c #53535A5AB1B1",
+"i c #53535B5BB2B2",
+"p c #56565F5FB1B1",
+"a c #58585F5FB4B4",
+"s c #59596060B2B2",
+"d c #58586060B4B4",
+"f c #59596161B5B5",
+"g c #5D5D6565B3B3",
+"h c #5C5C6464B7B7",
+"j c #5D5D6464B7B7",
+"k c #5E5E6565B7B7",
+"l c #5F5F6767B7B7",
+"z c #63636D6DB1B1",
+"x c #60606868B8B8",
+"c c #62626969B9B9",
+"v c #63636A6ABABA",
+"b c #65656D6DBBBB",
+"n c #67676F6FBBBB",
+"m c #66666D6DBCBC",
+"M c #67676E6EBCBC",
+"N c #6A6A7171BDBD",
+"B c #6E6E7575BFBF",
+"V c #6C6C9B9B4B4B",
+"C c #6F6F9C9C5C5C",
+"Z c #71719A9A6060",
+"A c #7676A3A35656",
+"S c #7575A5A55151",
+"D c #7575A1A15858",
+"F c #7575A1A15F5F",
+"G c #7979A8A85555",
+"H c #7E7EA9A95F5F",
+"J c #7A7AA5A56363",
+"K c #838337377171",
+"L c #A1A129295555",
+"P c #A7A72B2B5353",
+"I c #A9A94D4D7373",
+"U c #AAAA66664646",
+"Y c #ABAB6D6D4C4C",
+"T c #B0B073735656",
+"R c #C7C744444646",
+"E c #CECE45454242",
+"W c #CECE5A5A4E4E",
+"Q c #F5F55F5F5F5F",
+"! c #8F8F7575ABAB",
+"~ c #83837E7EBBBB",
+"^ c #B5B57F7F9F9F",
+"/ c #D7D77D7D8D8D",
+"( c #8181AAAA6565",
+") c #8585ACAC7070",
+"_ c #9999BBBB7F7F",
+"` c #B2B2A5A56464",
+"' c #EEEECCCC3939",
+"] c #DDDDC9C94545",
+"[ c #DDDDCDCD7A7A",
+"{ c #EFEFCFCF4343",
+"} c #EBEBD5D54E4E",
+"| c #8F8F9393BBBB",
+" . c #8F8F9B9BB4B4",
+".. c #92928787BEBE",
+"X. c #93939797BFBF",
+"o. c #9494B3B38383",
+"O. c #9B9BB5B59797",
+"+. c #A3A38282B1B1",
+"@. c #81818888C8C8",
+"#. c #8D8D8A8AC2C2",
+"$. c #89898E8ECCCC",
+"%. c #99998F8FC3C3",
+"&. c #99999D9DC5C5",
+"*. c #9D9DA2A2CDCD",
+"=. c #9D9DA2A2D0D0",
+"-. c #9D9DA2A2D3D3",
+";. c #9E9EA2A2D0D0",
+":. c #A1A1A3A3CBCB",
+">. c #A9A9ABABCFCF",
+",. c #A3A3A8A8D4D4",
+"<. c #A7A7ABABD6D6",
+"1. c #A7A7ACACD4D4",
+"2. c #A9A9AEAED3D3",
+"3. c #AAAAAEAED7D7",
+"4. c #A6A6B1B1C3C3",
+"5. c #AFAFB3B3D9D9",
+"6. c #B8B8ABABCECE",
+"7. c #B3B3B6B6D8D8",
+"8. c #B1B1B6B6DDDD",
+"9. c #B4B4B8B8D8D8",
+"0. c #B7B7BBBBDADA",
+"q. c #B4B4B8B8DDDD",
+"w. c #BBBBBFBFDFDF",
+"e. c #AAAAC5C59C9C",
+"r. c #B9B9C1C1D0D0",
+"t. c #BBBBC0C0DFDF",
+"y. c #BDBDC0C0DDDD",
+"u. c #BCBCC0C0E0E0",
+"i. c #BCBCC0C0E1E1",
+"p. c #C1C1A0A0BEBE",
+"a. c #DEDEA7A7B6B6",
+"s. c #DADAA7A7B8B8",
+"d. c #FBFB98989696",
+"f. c #FBFB9F9F9C9C",
+"g. c #F4F49F9FA1A1",
+"h. c #E9E9B6B6BEBE",
+"j. c #F5F5A1A1A0A0",
+"k. c #FCFCA4A4A1A1",
+"l. c #FEFEAAAAA7A7",
+"z. c #F8F8B4B4B4B4",
+"x. c #F9F9BFBFBFBF",
+"c. c #C1C1C5C5DADA",
+"v. c #C2C2C4C4E1E1",
+"b. c #C3C3C6C6E0E0",
+"n. c #C2C2C6C6E2E2",
+"m. c #C3C3C6C6E2E2",
+"M. c #C4C4C5C5E2E2",
+"N. c #C7C7C9C9E4E4",
+"B. c #D3D3D4D4EAEA",
+"V. c #D4D4D5D5EBEB",
+"C. c #D7D7D7D7E9E9",
+"Z. c #D6D6D8D8ECEC",
+"A. c #DBDBD3D3E5E5",
+"S. c #DADADBDBEAEA",
+"D. c #DCDCDDDDEEEE",
+"F. c #DEDEDFDFEDED",
+"G. c #DEDEE0E0EEEE",
+"H. c #E2E2C3C3CCCC",
+"J. c #E0E0CECEDCDC",
+"K. c #EDEDD4D4DBDB",
+"L. c #F1F1CCCCD1D1",
+"P. c #F2F2D6D6DCDC",
+"I. c #F5F5D9D9DDDD",
+"U. c #FDFDD3D3D0D0",
+"Y. c #EEEEDBDBE2E2",
+"T. c #F5F5DEDEE2E2",
+"R. c #E0E0E0E0F1F1",
+"E. c #F5F5EBEBEDED",
+"W. c #FEFEE3E3E1E1",
+"Q. c #F7F7F2F2F7F7",
+"!. c None",
+/* pixels */
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"/ ! 7 L P 4 K 8 4 4 1 , O > : ; ",
+"9 T.Q.P.h.Y.E.-.i.V.r._ e.O.c.>.",
+"Q z.l.f.d.k.j.+.M v l J F Z ) * ",
+"I I.W.x.g.U.L...3.N.H G S D o.:.",
+"%.K.6.s.a.8.H.~ l f p C Y V z $ ",
+"^ A.R.J.p.v.G.#.,.v.A 4.U .( &.",
+"6 $.B N m v l s i r w W { R s + ",
+"n S.8.w.D.<.w.V.-.w.*.[ E } 0.X.",
+"3 @.m x h a i r w q 0 ` ' ] y X ",
+"g B.w.b.G.5.b.S.1.b.2.7.T *.9.X.",
+"2 1 > : ; - - & % $ + + o X . . ",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!."
+};
diff --git a/src/images/flags/IQ.xpm b/src/images/flags/IQ.xpm
new file mode 100644
index 0000000..9850943
--- /dev/null
+++ b/src/images/flags/IQ.xpm
@@ -0,0 +1,164 @@
+/* XPM */
+static const char *IQ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 142 2",
+" c black",
+". c #0B0B0B0B0B0B",
+"X c #0F0F0F0F0E0E",
+"o c #131313131313",
+"O c #181819191919",
+"+ c #1E1E1E1E1E1E",
+"@ c #232323232323",
+"# c gray16",
+"$ c #2C2C2C2C2C2C",
+"% c gray18",
+"& c #2F2F2F2F2F2F",
+"* c #323232323232",
+"= c #343434343434",
+"- c #353535353535",
+"; c #393939393939",
+": c #3A3A3A3A3A3A",
+"> c gray24",
+", c #3F3F3F3F3F3F",
+"< c gray26",
+"1 c #444444444444",
+"2 c #464646464646",
+"3 c #4B4B4B4B4B4B",
+"4 c #505050505050",
+"5 c #545454545555",
+"6 c #585858585858",
+"7 c #5D5D5D5D5D5D",
+"8 c #616161616262",
+"9 c gray39",
+"0 c gray40",
+"q c #6B6B6A6A6B6B",
+"w c #6C6C68686C6C",
+"e c #70706E6E7070",
+"r c #737372727373",
+"t c #787876767878",
+"y c gray48",
+"u c #7D7D7A7A7D7D",
+"i c #7F7F7D7D7F7F",
+"p c #6B6BBFBF6D6D",
+"a c #E7E700000000",
+"s c #E9E900000000",
+"d c #EBEB00000000",
+"f c #EDED00000000",
+"g c #EFEF00000000",
+"h c #F1F100000000",
+"j c #F3F300000000",
+"k c #F5F500000000",
+"l c #F7F700000000",
+"z c #F9F900000000",
+"x c #FBFB00000000",
+"c c #FDFD00000000",
+"v c red",
+"b c #F6F62C2C2C2C",
+"n c #F7F731313131",
+"m c #F8F837373737",
+"M c #FFFF35353535",
+"N c #F9F93C3C3D3D",
+"B c #F7F749494949",
+"V c #F7F74E4E4E4E",
+"C c #FAFA42424242",
+"Z c #FBFB47474747",
+"A c #FCFC4C4C4C4C",
+"S c #F8F853535353",
+"D c #F9F957575757",
+"F c #FDFD51515151",
+"G c #FDFD54545454",
+"H c #FAFA5C5C5C5C",
+"J c #FEFE59595959",
+"K c #FEFE5C5C5C5C",
+"L c #FEFE5F5F5F5F",
+"P c #F5F56A6A6A6A",
+"I c #FBFB60606060",
+"U c #FCFC65656565",
+"Y c #FCFC69696969",
+"T c #FDFD6D6D6D6D",
+"R c #F6F670707171",
+"E c #F7F772727373",
+"W c #F6F67F7F7F7F",
+"Q c #F8F877777777",
+"! c #FDFD70707171",
+"~ c #FEFE74747474",
+"^ c #FEFE77777777",
+"/ c #F9F97A7A7A7A",
+"( c #FAFA7E7E7F7F",
+") c #FEFE79797979",
+"_ c #FFFF7B7B7A7A",
+"` c #FFFF7B7B7B7B",
+"' c #848482828484",
+"] c #888885858888",
+"[ c #8C8C8B8B8C8C",
+"{ c #8D8D8A8A8D8D",
+"} c #A0A0A0A0A0A0",
+"| c #8989CDCD8B8B",
+" . c #8D8DCFCF8E8E",
+".. c #8F8FCDCD9292",
+"X. c #8B8BD0D08D8D",
+"o. c #9595CFCF9696",
+"O. c #9B9BD1D19D9D",
+"+. c #9C9CD3D39E9E",
+"@. c #A8A8DADAA9A9",
+"#. c #ADADDDDDAEAE",
+"$. c #B3B3E0E0B4B4",
+"%. c #B4B4E1E1B7B7",
+"&. c #BCBCE2E2BDBD",
+"*. c #BDBDE3E3BDBD",
+"=. c #BDBDE0E0C0C0",
+"-. c #BEBEE4E4C4C4",
+";. c #FBFB82828484",
+":. c #FCFC85858585",
+">. c #FDFD88888989",
+",. c #FDFD8B8B8B8B",
+"<. c #FEFE8F8F9191",
+"1. c #FEFE90909191",
+"2. c #FEFEA4A4A4A4",
+"3. c #C1C1E5E5C4C4",
+"4. c #C3C3E6E6C5C5",
+"5. c #CACAE7E7CDCD",
+"6. c #D4D4ECECD6D6",
+"7. c gray89",
+"8. c gray90",
+"9. c #E7E7E7E7E7E7",
+"0. c #E4E4F3F3E4E4",
+"q. c #E7E7F6F6E7E7",
+"w. c #E9E9F4F4E9E9",
+"e. c #EAEAF5F5EAEA",
+"r. c #EFEFF4F4EFEF",
+"t. c #EDEDF7F7F2F2",
+"y. c #EEEEF6F6F1F1",
+"u. c gray95",
+"i. c #F2F2F4F4F4F4",
+"p. c #F4F4F4F4F4F4",
+"a. c #F4F4F5F5F5F5",
+"s. c gray96",
+"d. c #F1F1F9F9F0F0",
+"f. c #F5F5F8F8F8F8",
+"g. c #F6F6FBFBFAFA",
+"h. c #F8F8FCFCFCFC",
+"j. c #F9F9FEFEFCFC",
+"k. c gray99",
+"l. c #FCFCFCFCFDFD",
+"z. c #FDFDFDFDFDFD",
+"x. c #FEFEFEFEFEFE",
+"c. c None",
+/* pixels */
+"c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.",
+"c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.",
+"c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.",
+"v v v v x v v v x x l l j j f f ",
+"v ` ` ` ^ ~ ! T Y U I H D S V d ",
+"v ` K K J G F A Z C N m n b B d ",
+"M 2.1.1.,.>.;.;.( / Q E R P W a ",
+"z.z.j.%.z.j.g.3.3.f.t.t.+.i.a.9.",
+"z.z.$. . at .-.6.| .5.=.o.p O.i.7.",
+"z.z.z.#.q.0.d.*.*.e.w.y.o.u.a.7.",
+"& } [ { ] ' i u t r e q w 9 y ",
+" 0 < < ; * & # @ + O o X . & ",
+" 9 7 6 5 4 3 2 < > ; - * & & ",
+" ",
+"c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.",
+"c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.c."
+};
diff --git a/src/images/flags/IR.xpm b/src/images/flags/IR.xpm
new file mode 100644
index 0000000..b59a137
--- /dev/null
+++ b/src/images/flags/IR.xpm
@@ -0,0 +1,171 @@
+/* XPM */
+static const char *IR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 149 2",
+" c black",
+". c #00004B4B0000",
+"X c #00004D4D0000",
+"o c #00005D5D0000",
+"O c #000061610000",
+"+ c #000063630000",
+"@ c #000067670000",
+"# c #00006D6D0000",
+"$ c #000071710000",
+"% c #000075750000",
+"& c #000079790000",
+"* c #00007D7D0000",
+"= c #000081810000",
+"- c #000083830000",
+"; c #000085850000",
+": c #000087870000",
+"> c #000089890000",
+", c #000091910000",
+"< c #2E2EA6A62D2D",
+"1 c #3333A9A93333",
+"2 c #3F3FA3A33F3F",
+"3 c #3939ACAC3939",
+"4 c #3E3EAFAF3E3E",
+"5 c #4444B1B14444",
+"6 c #4B4BB3B34B4B",
+"7 c #4848B4B44949",
+"8 c #4E4EB3B34E4E",
+"9 c #4E4EB7B74E4E",
+"0 c #5353B6B65353",
+"q c #5252B8B85151",
+"w c #5656BABA5656",
+"e c #5858B9B95757",
+"r c #5A5ABCBC5A5A",
+"t c #5C5CBABA5C5C",
+"y c #5E5EBEBE5E5E",
+"u c #6161BDBD6060",
+"i c #6060BFBF6161",
+"p c #6565BFBF6565",
+"a c #6969C1C16969",
+"s c #6D6DC3C36D6D",
+"d c #7070C4C47171",
+"f c #7474C6C67474",
+"g c #7777C8C87777",
+"h c #7979C8C87979",
+"j c #7B7BCACA7B7B",
+"k c #7C7CCACA7C7C",
+"l c #DDDD00000000",
+"z c #DFDF00000000",
+"x c #E1E100000000",
+"c c #E3E300000000",
+"v c #E5E500000000",
+"b c #E7E700000000",
+"n c #E9E900000000",
+"m c #EBEB00000000",
+"M c #EDED00000000",
+"N c #EFEF00000000",
+"B c #F1F100000000",
+"V c #F3F300000000",
+"C c #F5F500000000",
+"Z c #F7F700000000",
+"A c #F1F10F0F0F0F",
+"S c #F9F900000000",
+"D c #F1F112121212",
+"F c #F2F217171717",
+"G c #F3F31C1C1C1C",
+"H c #F4F422222222",
+"J c #F5F527272727",
+"K c #F2F22C2C2C2C",
+"L c #F2F22F2F2F2F",
+"P c #F6F62C2C2C2C",
+"I c #F2F232323232",
+"U c #F3F335353535",
+"Y c #F7F731313131",
+"T c #F4F439393939",
+"R c #F5F53D3D3D3D",
+"E c #F8F837373737",
+"W c #F9F93C3C3C3C",
+"Q c #F6F642424242",
+"! c #F7F746464646",
+"~ c #F7F74B4B4B4B",
+"^ c #FAFA41414141",
+"/ c #FAFA47474747",
+"( c #F8F850505050",
+") c #F9F954545555",
+"_ c #F9F958585858",
+"` c #FAFA5D5D5D5D",
+"' c #FBFB61616262",
+"] c #FCFC69696969",
+"[ c #A3A3D5D5A3A3",
+"{ c #AAAAD9D9AAAA",
+"} c #AFAFDEDEB1B1",
+"| c #B3B3DFDFB4B4",
+" . c #B7B7E3E3B7B7",
+".. c #B8B8E1E1B8B8",
+"X. c #BDBDE4E4BDBD",
+"o. c #DFDF83838181",
+"O. c #F7F782828282",
+"+. c #F8F887878787",
+"@. c #FBFB85858585",
+"#. c #F7F791919191",
+"$. c #FAFA9B9B9B9B",
+"%. c #F2F2A5A5A5A5",
+"&. c #F3F3AFAFAFAF",
+"*. c #F4F4A8A8A8A8",
+"=. c #F6F6ABABABAB",
+"-. c #F9F9A2A2A2A2",
+";. c #F8F8B5B5B5B5",
+":. c #F9F9B4B4B6B6",
+">. c #FAFAB6B6B7B7",
+",. c #F8F8BABABABA",
+"<. c #FAFAB9B9B9B9",
+"1. c #FBFBBCBCBCBC",
+"2. c #C8C8E4E4C8C8",
+"3. c #CCCCE7E7CCCC",
+"4. c #CDCDE6E6CDCD",
+"5. c #C9C9E9E9C9C9",
+"6. c #CFCFE9E9CFCF",
+"7. c #D4D4ECECD5D5",
+"8. c #D7D7EEEED7D7",
+"9. c #D9D9EFEFD9D9",
+"0. c #F2F2C2C2C2C2",
+"q. c #F3F3C7C7C7C7",
+"w. c #F5F5CCCCCCCC",
+"e. c #F7F7CCCCCDCD",
+"r. c #F9F9D2D2D2D2",
+"t. c #FBFBD5D5D5D5",
+"y. c gray89",
+"u. c gray90",
+"i. c #E7E7E7E7E7E7",
+"p. c #FCFCE5E5E5E5",
+"a. c #F8F8EFEFF1F1",
+"s. c gray95",
+"d. c #F3F3F3F3F3F3",
+"f. c #F6F6F2F2F2F2",
+"g. c #F4F4F4F4F4F4",
+"h. c #F4F4F5F5F5F5",
+"j. c gray96",
+"k. c #F6F6F6F6F6F6",
+"l. c gray97",
+"z. c #FBFBF3F3F5F5",
+"x. c #F9F9F7F7F7F7",
+"c. c gray98",
+"v. c #FBFBFBFBFBFB",
+"b. c #FBFBFCFCFBFB",
+"n. c gray99",
+"m. c #FDFDFCFCFDFD",
+"M. c #FDFDFDFDFDFD",
+"N. c #FEFEFEFEFEFE",
+"B. c None",
+/* pixels */
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+", > > > ; ; = * & % $ # @ O o O ",
+"; j g g g f s s a p u t e 0 9 . ",
+"> k a y r w 0 9 7 5 4 3 1 < 6 X ",
+" .5.9.X.8. .7.| 6.} 4.{ 2.[ 4.2 ",
+"M.M.M.M.M.M.z.>.>.a.l.j.j.j.j.i.",
+"M.M.M.v.v.c.$.-.,.#.j.j.j.d.j.u.",
+"M.M.M.v.v.c.x. at .O.f.j.d.d.s.j.y.",
+"@.p.1.t.,.r.>.e.=.w.*.q.%.0.&.o.",
+"S ] / ^ W E Y L J H G F D A I l ",
+"S ' ` _ ) ( ~ ! Q R T U I L L l ",
+"C C B N N N n n v v c c l l l l ",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B."
+};
diff --git a/src/images/flags/IS.xpm b/src/images/flags/IS.xpm
new file mode 100644
index 0000000..b8337ab
--- /dev/null
+++ b/src/images/flags/IS.xpm
@@ -0,0 +1,153 @@
+/* XPM */
+static const char *IS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 131 2",
+" c black",
+". c #000000004343",
+"X c #000000004545",
+"o c #000000004949",
+"O c #000000004B4B",
+"+ c #000000004F4F",
+"@ c #000000005555",
+"# c #000000005757",
+"$ c #000000005B5B",
+"% c #000000005D5D",
+"& c #000000006161",
+"* c #000000006565",
+"= c #000000006B6B",
+"- c #000000007171",
+"; c #000000007575",
+": c #000000007B7B",
+"> c #000003037F7F",
+", c #000009098383",
+"< c #00000B0B8383",
+"1 c #000011118787",
+"2 c #000011118989",
+"3 c #000017178B8B",
+"4 c #000019198D8D",
+"5 c #00001D1D8F8F",
+"6 c #00002D2D9797",
+"7 c #00002F2F9999",
+"8 c #23235858A5A5",
+"9 c #27275C5CA7A7",
+"0 c #28285C5CA8A8",
+"q c #2B2B5E5EAAAA",
+"w c #2C2C6060AAAA",
+"e c #2F2F6262ADAD",
+"r c #30306262ADAD",
+"t c #34346666AEAE",
+"y c #35356666AFAF",
+"u c #39396A6AB0B0",
+"i c #3A3A6A6AB1B1",
+"p c #3D3D6D6DB2B2",
+"a c #3F3F6E6EB3B3",
+"s c #40406F6FB1B1",
+"d c #43437070B3B3",
+"f c #40407070B5B5",
+"g c #42427171B5B5",
+"h c #46467373B3B3",
+"j c #47477373B3B3",
+"k c #44447272B6B6",
+"l c #46467474B7B7",
+"z c #46467575B7B7",
+"x c #4A4A7575B5B5",
+"c c #4B4B7878BABA",
+"v c #4D4D7878B8B8",
+"b c #50507B7BB9B9",
+"n c #50507C7CBCBC",
+"m c #51517C7CBCBC",
+"M c #53537E7EBDBD",
+"N c #55557F7FBBBB",
+"B c #55557F7FBFBF",
+"V c #55558080BFBF",
+"C c #58588181BDBD",
+"Z c #59598282BDBD",
+"A c #58588282BFBF",
+"S c #5C5C8484BEBE",
+"D c #59598383C0C0",
+"F c #5A5A8383C1C1",
+"G c #5D5D8686C2C2",
+"H c #5F5F8787C2C2",
+"J c #60608888C1C1",
+"K c #65658B8BC3C3",
+"L c #6A6A8F8FC5C5",
+"P c #6A6A9090C8C8",
+"I c #6D6D9191C8C8",
+"U c #6D6D9393C9C9",
+"Y c #6E6E9393C8C8",
+"T c #71719494C9C9",
+"R c #70709595CBCB",
+"E c #72729696C9C9",
+"W c #75759898CBCB",
+"Q c #76769999CBCB",
+"! c #79799A9ACCCC",
+"~ c #7A7A9C9CCDCD",
+"^ c #7C7C9E9ECDCD",
+"/ c #B3B300000000",
+"( c #C1C100000000",
+") c #DBDB00000000",
+"_ c #DCDC24242222",
+"` c #DEDE28282828",
+"' c #DFDF2D2D2C2C",
+"] c #E1E133333232",
+"[ c #E3E338383737",
+"{ c #E3E33C3C3B3B",
+"} c #E4E43E3E3C3C",
+"| c #E1E143434242",
+" . c #E5E542424141",
+".. c #E6E643434242",
+"X. c #E7E748484646",
+"o. c #E7E748484747",
+"O. c #E7E74D4D4C4C",
+"+. c #E7E756565555",
+"@. c #E9E952525151",
+"#. c #E9E953535151",
+"$. c #EAEA57575656",
+"%. c #EAEA58585656",
+"&. c #EBEB5B5B5A5A",
+"*. c #EBEB5C5C5B5B",
+"=. c #EFEF78787777",
+"-. c #EFEF7A7A7979",
+";. c #8787A5A5D3D3",
+":. c #8787A6A6D3D3",
+">. c #8989A8A8D3D3",
+",. c #8989A8A8D4D4",
+"<. c gray89",
+"1. c #E7E7E7E7E7E7",
+"2. c gray92",
+"3. c #EDEDEFEFEDED",
+"4. c gray95",
+"5. c #F3F3F3F3F3F3",
+"6. c #F4F4F4F4F4F4",
+"7. c gray96",
+"8. c #F6F6F6F6F6F6",
+"9. c gray97",
+"0. c #F8F8F8F8F8F8",
+"q. c #F9F9F9F9F9F9",
+"w. c gray98",
+"e. c #FBFBFBFBFBFB",
+"r. c #FBFBFCFCFBFB",
+"t. c gray99",
+"y. c #FDFDFCFCFDFD",
+"u. c #FDFDFDFDFDFD",
+"i. c #FDFDFDFDFEFE",
+"p. c #FEFEFEFEFEFE",
+"a. c None",
+/* pixels */
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"7 7 7 7 u.) u.5 3 1 , > : ; - = ",
+"7 ,.,.:.u.-.u.^ ! W T U L K J * ",
+"7 >.R U u.*.u.H D B m c z g S & ",
+"6 :.U P u.%.u.D B m c z a p C $ ",
+"u.u.u.u.u.#.u.w.w.0.9.9.7.7.7.1.",
+") =.&.$. at .O.o. .{ [ ] ' ` _ | / ",
+"u.u.u.e.w.o.w.0.0.7.7.7.5.4.7.<.",
+"4 ! H C w. .w.g a u y r q q h o ",
+"1 Q V M w.{ w.s u t e q 9 8 s X ",
+", E U L w.$.7.C N b v x h s s X ",
+", : ; - 3.( 2.$ @ @ @ o o X . . ",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a."
+};
diff --git a/src/images/flags/IT.xpm b/src/images/flags/IT.xpm
new file mode 100644
index 0000000..95c6bf3
--- /dev/null
+++ b/src/images/flags/IT.xpm
@@ -0,0 +1,136 @@
+/* XPM */
+static const char *IT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 114 2",
+" c black",
+". c #000053530000",
+"X c #00005B5B0000",
+"o c #000063630000",
+"O c #000067670000",
+"+ c #00006F6F0000",
+"@ c #000075750000",
+"# c #000077770000",
+"$ c #00007B7B0000",
+"% c #00007F7F0000",
+"& c #000083830000",
+"* c #000085850000",
+"= c #000087870000",
+"- c #000089890000",
+"; c #000091910000",
+": c #3A3AAAAA3A3A",
+"> c #3F3FAEAE3F3F",
+", c #4040ADAD3F3F",
+"< c #4444B1B14444",
+"1 c #4545B0B04545",
+"2 c #4545B1B14545",
+"3 c #4B4BB3B34B4B",
+"4 c #4949B4B44949",
+"5 c #4F4FB6B64F4F",
+"6 c #4F4FB7B74F4F",
+"7 c #5050B5B55050",
+"8 c #5454B5B55555",
+"9 c #5454B7B75454",
+"0 c #5353B9B95353",
+"q c #5454B9B95454",
+"w c #5858B9B95858",
+"e c #5858BBBB5959",
+"r c #5959BABA5959",
+"t c #5858BCBC5858",
+"y c #5C5CBDBD5C5C",
+"u c #5D5DBCBC5D5D",
+"i c #5F5FBFBF5F5F",
+"p c #6161BEBE6262",
+"a c #6666C0C06666",
+"s c #6A6AC3C36A6A",
+"d c #6F6FC4C46F6F",
+"f c #7272C6C67373",
+"g c #7777C7C77777",
+"h c #7676C8C87676",
+"j c #7979C8C87979",
+"k c #7B7BCACA7A7A",
+"l c #7B7BCACA7B7B",
+"z c #DDDD00000000",
+"x c #DFDF00000000",
+"c c #E1E100000000",
+"v c #E3E300000000",
+"b c #E5E500000000",
+"n c #E7E700000000",
+"m c #E9E900000000",
+"M c #EBEB00000000",
+"N c #EDED00000000",
+"B c #EFEF00000000",
+"V c #F1F100000000",
+"C c #F3F300000000",
+"Z c #F5F500000000",
+"A c #F1F10B0B0B0B",
+"S c #F1F10F0F0E0E",
+"D c #F2F210101010",
+"F c #F2F213131313",
+"G c #F2F214141414",
+"H c #F3F319191919",
+"J c #F3F31A1A1A1A",
+"K c #F4F41F1F1F1F",
+"L c #F4F420202020",
+"P c #F5F525252525",
+"I c #F5F526262626",
+"U c #F2F22C2C2C2C",
+"Y c #F2F22F2F2F2F",
+"T c #F6F62B2B2B2B",
+"R c #F6F62C2C2C2C",
+"E c #F2F232323232",
+"W c #F3F332323232",
+"Q c #F3F335353535",
+"! c #F7F731313131",
+"~ c #F4F436363636",
+"^ c #F4F43B3B3B3B",
+"/ c #F5F53F3F3F3F",
+"( c #F8F837373737",
+") c #F6F644444444",
+"_ c #F7F749494949",
+"` c #F7F74E4E4E4E",
+"' c #F8F853535353",
+"] c #F9F957575757",
+"[ c #FAFA5C5C5C5C",
+"{ c #C1C1C1C1C1C1",
+"} c #C3C3C3C3C3C3",
+"| c gray78",
+" . c gray79",
+".. c #CDCDCDCDCDCD",
+"X. c gray86",
+"o. c #DDDDDDDDDDDD",
+"O. c #DFDFDFDFDFDF",
+"+. c #E1E1E1E1E1E1",
+"@. c gray89",
+"#. c gray90",
+"$. c #F3F3F3F3F3F3",
+"%. c #F4F4F4F4F4F4",
+"&. c gray96",
+"*. c #F6F6F6F6F6F6",
+"=. c gray97",
+"-. c #F8F8F8F8F8F8",
+";. c #F9F9F9F9F9F9",
+":. c gray98",
+">. c #FBFBFBFBFBFB",
+",. c gray99",
+"<. c #FDFDFDFDFDFD",
+"1. c #FDFDFDFDFEFE",
+"2. c #FEFEFEFEFEFE",
+"3. c None",
+/* pixels */
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"; - - = & #. at .+.O.o.X.Z C C N N ",
+"= l l l g <.<.<.,.<.>.[ ] ' ` M ",
+"- l i y e <.<.,.>.;.;.( ! R _ M ",
+"= l r r 0 <.,.,.;.;.;.! T I ) b ",
+"= g r 0 5 ,.,.;.;.;.=.T I L / b ",
+"= f q 5 3 <.;.;.-.=.*.P K H / b ",
+"% d 6 2 1 ;.;.;.=.*.*.K G G ~ v ",
+"$ s 3 < > ;.;.*.*.*.$.H F F W x ",
+"# p < > : ;.=.*.*.$.$.F S A Y x ",
+"+ p p w 8 ;.*.=.*.*.%.Q W Y U x ",
+"# O o X . .. .| { { { v x x z z ",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.",
+"3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3."
+};
diff --git a/src/images/flags/JM.xpm b/src/images/flags/JM.xpm
new file mode 100644
index 0000000..7751c16
--- /dev/null
+++ b/src/images/flags/JM.xpm
@@ -0,0 +1,178 @@
+/* XPM */
+static const char *JM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 156 2",
+" c black",
+". c #131300000000",
+"X c #121212121010",
+"o c gray8",
+"O c #191919191919",
+"+ c gray10",
+"@ c gray12",
+"# c #00002D2D0000",
+"$ c #000031310000",
+"% c #000039390000",
+"& c #00003D3D0000",
+"* c #29290F0F0000",
+"= c #202020202020",
+"- c #252525252525",
+"; c #2D2D2B2B2626",
+": c #393935352B2B",
+"> c #333332323232",
+", c gray21",
+"< c gray23",
+"1 c #3F3F3F3F3F3F",
+"2 c #000041410000",
+"3 c #000047470000",
+"4 c #00004D4D0000",
+"5 c #000051510000",
+"6 c #000055550000",
+"7 c #000059590000",
+"8 c #000063630000",
+"9 c #00006B6B0000",
+"0 c #000071710000",
+"q c #000075750000",
+"w c #000079790000",
+"e c #00007D7D0000",
+"r c #0D0D7D7D0000",
+"t c #55553B3B0000",
+"y c #494940401F1F",
+"u c #4C4C46462F2F",
+"i c #5A5A51512B2B",
+"p c #7A7A65651414",
+"a c #444444444444",
+"s c #49494A4A4949",
+"d c #4B4B4B4B4949",
+"f c #4B4B4A4A4B4B",
+"g c gray31",
+"h c #50504E4E4646",
+"j c #535353535353",
+"k c gray33",
+"l c #585858585858",
+"z c #60605F5F5C5C",
+"x c #666660604545",
+"c c #696963634949",
+"v c #76766E6E5050",
+"b c #6A6A6A6A6A6A",
+"n c #6F6F6F6F6F6F",
+"m c #7B7B77776666",
+"M c #727272727373",
+"N c #767676767676",
+"B c #797979797979",
+"V c #000081810000",
+"C c #000083830000",
+"Z c #000085850000",
+"A c #1E1E9C9C1E1E",
+"S c #37379B9B0000",
+"D c #2323A1A12323",
+"F c #2929A3A32929",
+"G c #2E2EA5A52E2E",
+"H c #3636A6A62A2A",
+"J c #3C3CA8A82F2F",
+"K c #3939A7A73939",
+"L c #3D3DACAC3D3D",
+"P c #5D5DA9A91919",
+"I c #4A4AAAAA3535",
+"U c #7373B6B63434",
+"Y c #7070B8B83D3D",
+"T c #4242AEAE4242",
+"R c #4646B0B04646",
+"E c #4747B3B34747",
+"W c #4848B1B14242",
+"Q c #4E4EB4B44747",
+"! c #4B4BB2B24B4B",
+"~ c #4C4CB5B54C4C",
+"^ c #5050B3B35050",
+"/ c #5151B6B65151",
+"( c #6767B9B95555",
+") c #6A6ABDBD5C5C",
+"_ c #6161BBBB6060",
+"` c #6565C0C06565",
+"' c #6969C2C26969",
+"] c #6D6DC3C36D6D",
+"[ c #7070C5C57171",
+"{ c #7474C5C57474",
+"} c #91917C7C2B2B",
+"| c #9B9BBABA2424",
+" . c #AFAF8F8F0B0B",
+".. c #B7B785850000",
+"X. c #ABABBEBE3232",
+"o. c #BEBEA1A12424",
+"O. c #959585854545",
+"+. c #92928D8D7A7A",
+"@. c #A9A999995959",
+"#. c #A6A6C1C13434",
+"$. c #A0A0C2C23C3C",
+"%. c #8585C3C35454",
+"&. c #8282C9C97777",
+"*. c #AAAAC9C94B4B",
+"=. c #B7B7CCCC5757",
+"-. c #DDDD93930000",
+";. c #D1D1A7A70000",
+":. c #DBDBAFAF0000",
+">. c #C5C5A7A72C2C",
+",. c #CCCCAEAE3030",
+"<. c #D7D7B6B63030",
+"1. c #EDEDB1B10000",
+"2. c #F5F5BDBD0000",
+"3. c #E1E1BEBE2C2C",
+"4. c #C5C5ACAC4444",
+"5. c #C8C8AEAE4040",
+"6. c #D3D3B9B94B4B",
+"7. c #DADABCBC4040",
+"8. c #D6D6BFBF5F5F",
+"9. c #D7D7C5C51313",
+"0. c #D2D2C8C82F2F",
+"q. c #D5D5CBCB3535",
+"w. c #D0D0CBCB3C3C",
+"e. c #DBDBCFCF3737",
+"r. c #E5E5C3C30000",
+"t. c #ECECC3C31919",
+"y. c #F1F1CFCF0E0E",
+"u. c #FFFFCFCF0000",
+"i. c #F4F4D3D31F1F",
+"p. c #E4E4D2D23A3A",
+"a. c #F6F6CFCF3131",
+"s. c #F2F2CFCF3F3F",
+"d. c #F2F2D4D42F2F",
+"f. c #F6F6D0D02A2A",
+"g. c #F7F7DCDC3131",
+"h. c #F8F8D5D53636",
+"j. c #F9F9D5D53A3A",
+"k. c #F8F8D9D93636",
+"l. c #F9F9DBDB3B3B",
+"z. c #F9F9DCDC3A3A",
+"x. c #FAFADFDF3F3F",
+"c. c #C0C0CFCF5858",
+"v. c #D3D3CECE4141",
+"b. c #C8C8D9D97979",
+"n. c #EEEECFCF4E4E",
+"m. c #E6E6DBDB5959",
+"M. c #FBFBDADA4646",
+"N. c #FBFBDADA5454",
+"B. c #F8F8DFDF5353",
+"V. c #EEEED3D36262",
+"C. c #F7F7DFDF7B7B",
+"Z. c #FDFDE1E15151",
+"A. c #FAFAE3E35D5D",
+"S. c #FEFEE6E65C5C",
+"D. c #FFFFEAEA7B7B",
+"F. c None",
+/* pixels */
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"u.r.S Z Z V V e w q 0 9 8 w ;.1.",
+"t C.D.b.&.{ [ ] ' ` _ ) =.Z.n.. ",
+" +.8.S.m.%./ ~ E T Y e.g.>.c ",
+" B z @.N.Z.*.Q W $.k.a.} ; a ",
+" N l k v 6.M.v.w.h.,.i - = 1 ",
+" M j g f h 7.z.k.<., - = O < ",
+" n g s x 5.j.q.q.f.o.t O o , ",
+" b f O.s.z.X.K H | i.t.p o , ",
+" m 4.x.p.U G F D A P 9.y. .u ",
+"* V.A.=.( ^ ! E T L K I X.d.3. ",
+"2.:.r 7 6 5 4 3 2 & % $ # 4 ..-.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F."
+};
diff --git a/src/images/flags/JO.xpm b/src/images/flags/JO.xpm
new file mode 100644
index 0000000..4bffa1a
--- /dev/null
+++ b/src/images/flags/JO.xpm
@@ -0,0 +1,143 @@
+/* XPM */
+static const char *JO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 121 2",
+" c black",
+". c #000029290000",
+"X c #00002D2D0000",
+"o c #00002F2F0000",
+"O c #000033330000",
+"+ c #000039390000",
+"@ c #00003D3D0000",
+"# c #2C2C2C2C2C2C",
+"$ c #313131313131",
+"% c #373737373737",
+"& c #3D3D3C3C3D3D",
+"* c #000041410000",
+"= c #000047470000",
+"- c #00004D4D0000",
+"; c #000051510000",
+": c #000057570000",
+"> c #00005D5D0000",
+", c #000063630000",
+"< c gray26",
+"1 c gray28",
+"2 c #494949494949",
+"3 c #4C4C4C4C4C4C",
+"4 c #4E4E4E4E4E4E",
+"5 c #515151515151",
+"6 c #535353535353",
+"7 c gray33",
+"8 c #585857575757",
+"9 c gray36",
+"0 c #636359595959",
+"q c #616160606060",
+"w c #656565656565",
+"e c DimGray",
+"r c #6D6D6D6D6D6D",
+"t c #707070707171",
+"y c #747474747474",
+"u c #777777777777",
+"i c #797979797979",
+"p c #18189A9A1919",
+"a c #1C1C9C9C1C1C",
+"s c #21219F9F2121",
+"d c #2525A1A12626",
+"f c #2A2AA3A32A2A",
+"g c #3030A6A63030",
+"h c #3535A9A93535",
+"j c #3838A7A73838",
+"k c #3A3AA8A83A3A",
+"l c #3B3BA9A93B3B",
+"z c #3A3AACAC3A3A",
+"x c #3D3DA9A93D3D",
+"c c #4040ACAC4040",
+"v c #4040AEAE4040",
+"b c #4545AEAE4444",
+"n c #4848AFAF4848",
+"m c #4545B1B14545",
+"M c #4C4CB2B24C4C",
+"N c #5050B4B45050",
+"B c #5555B6B65555",
+"V c #5A5AB9B95A5A",
+"C c #5E5EBBBB5E5E",
+"Z c #6262BEBE6262",
+"A c #898900000000",
+"S c #9B9B00000000",
+"D c #B5B569693F3F",
+"F c #BCBC5C5C5C5C",
+"G c #A4A47B7B7B7B",
+"H c #F7F700000000",
+"J c #F9F900000000",
+"K c #FBFB00000000",
+"L c #FDFD00000000",
+"P c red",
+"I c #DCDC51513F3F",
+"U c #DDDD54545454",
+"Y c #FAFA40404040",
+"T c #FAFA44444444",
+"R c #FBFB45454545",
+"E c #FBFB46464646",
+"W c #FAFA44444949",
+"Q c #FBFB49494949",
+"! c #FBFB4E4E4E4E",
+"~ c #FCFC4A4A4B4B",
+"^ c #FDFD4F4F5050",
+"/ c #FCFC55555555",
+"( c #FDFD57575757",
+") c #FEFE59595959",
+"_ c #FEFE5C5C5C5C",
+"` c #FEFE5F5F5F5F",
+"' c #E8E86C6C6262",
+"] c #EBEB7B7B7B7B",
+"[ c #FCFC66666666",
+"{ c #FCFC6A6A6A6A",
+"} c #FDFD6F6F6F6F",
+"| c #FEFE76767676",
+" . c #FEFE79797979",
+".. c #FFFF7B7B7A7A",
+"X. c #94949B9B5D5D",
+"o. c #F9F988888989",
+"O. c #FCFC8D8D8D8D",
+"+. c #FEFE8E8E8E8E",
+"@. c #F9F98E8E9191",
+"#. c #FCFC90909090",
+"$. c #FBFB9E9E9E9E",
+"%. c #FEFE9A9A9A9A",
+"&. c #FDFD9C9C9F9F",
+"*. c gray81",
+"=. c gray82",
+"-. c #D5D5D5D5D5D5",
+";. c #D7D7D7D7D7D7",
+":. c gray95",
+">. c #F3F3F3F3F3F3",
+",. c #F4F4F4F4F4F4",
+"<. c #F4F4F5F5F5F5",
+"1. c gray96",
+"2. c #F6F6F6F6F6F6",
+"3. c gray97",
+"4. c #F8F8F8F8F8F8",
+"5. c #F9F9F9F9F9F9",
+"6. c gray98",
+"7. c #FBFBFBFBFBFB",
+"8. c gray99",
+"9. c #FDFDFDFDFDFD",
+"0. c None",
+/* pixels */
+"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.",
+"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.",
+"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.",
+"S ",
+"P ] G i u y t r e w q 9 8 6 4 ",
+"P .._ F 0 7 4 3 1 < & % $ # 3 ",
+"P .._ _ U &.7.7.7.7.1.3.1.1.1.;.",
+"P | O.( ^ ( $.7.7.1.7.1.1.>.>.;.",
+"P %.9.#.~ T Y o.3.1.1.1.1.>.1.=.",
+"P | O.! T W @.7.3.3.1.1.>.>.>.=.",
+"J { Q T I @.7.1.1.1.1.>.>.>.>.*.",
+"J [ T D m c z h g f d s a p l X ",
+"H ' X.Z C V B N M n b c j l j . ",
+"A ; , > : ; - = * @ + O X X . . ",
+"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.",
+"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0."
+};
diff --git a/src/images/flags/JP.xpm b/src/images/flags/JP.xpm
new file mode 100644
index 0000000..62ac6d6
--- /dev/null
+++ b/src/images/flags/JP.xpm
@@ -0,0 +1,104 @@
+/* XPM */
+static const char *JP_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 82 1",
+" c black",
+". c #F5F524242424",
+"X c #F5F52A2A2A2A",
+"o c #F6F62A2A2A2A",
+"O c #F6F62B2B2B2B",
+"+ c #F7F72F2F2F2F",
+"@ c #F7F730303030",
+"# c #F7F737373737",
+"$ c #F8F834343434",
+"% c #F8F835353535",
+"& c #F8F836363636",
+"* c #F9F93B3B3A3A",
+"= c #F9F93B3B3B3B",
+"- c #F9F93B3B3C3C",
+"; c #F9F93C3C3C3C",
+": c #FAFA40404040",
+"> c #FAFA41414141",
+", c #FAFA41414242",
+"< c #FBFB46464646",
+"1 c #FBFB47474747",
+"2 c #FAFA48484848",
+"3 c #FCFC4B4B4B4B",
+"4 c #F5F555555555",
+"5 c #F6F65B5B5B5B",
+"6 c #FCFC55555555",
+"7 c #F4F47D7D7D7D",
+"8 c #FBFB79797979",
+"9 c #FCFC7E7E7F7F",
+"0 c #F4F493939393",
+"q c #F8F894949393",
+"w c #F9F997979797",
+"e c #F7F7A1A1A1A1",
+"r c #FAFAAFAFAFAF",
+"t c #FDFDAAAAAAAA",
+"y c #F5F5BBBBBBBB",
+"u c #FDFDBBBBBBBB",
+"i c gray81",
+"p c gray82",
+"a c LightGray",
+"s c #D5D5D5D5D5D5",
+"d c #D7D7D7D7D7D7",
+"f c gray85",
+"g c gray86",
+"h c #DDDDDDDDDDDD",
+"j c #DFDFDFDFDFDF",
+"k c #F4F4D5D5D5D5",
+"l c #F6F6DADADADA",
+"z c #FCFCD2D2D2D2",
+"x c #E1E1E3E3E1E1",
+"c c #E1E1E3E3E3E3",
+"v c gray90",
+"b c #E7E7E7E7E7E7",
+"n c #E9E9E9E9E9E9",
+"m c gray92",
+"M c gray93",
+"N c #EFEFEFEFEFEF",
+"B c #F3F3EFEFEFEF",
+"V c #FBFBE7E7E7E7",
+"C c #FDFDEAEAEAEA",
+"Z c #F1F1F1F1F1F1",
+"A c gray95",
+"S c #F2F2F2F2F3F3",
+"D c #F3F3F3F3F3F3",
+"F c #F4F4F4F4F4F4",
+"G c #F4F4F5F5F5F5",
+"H c gray96",
+"J c #F6F6F4F4F4F4",
+"K c #F7F7F5F5F5F5",
+"L c #F6F6F6F6F6F6",
+"P c gray97",
+"I c #F8F8F7F7F7F7",
+"U c #F8F8F8F8F8F8",
+"Y c #F9F9F9F9F9F9",
+"T c gray98",
+"R c #FBFBFBFBFBFB",
+"E c #FBFBFCFCFBFB",
+"W c gray99",
+"Q c #FDFDFDFDFDFD",
+"! c #FDFDFDFDFEFE",
+"~ c #FEFEFEFEFEFE",
+"^ c gray100",
+"/ c None",
+/* pixels */
+"////////////////",
+"////////////////",
+"////////////////",
+"HHHHHDDNNNNnnvvc",
+"H^^^R^^^RRRRRHHc",
+"H^^^^Ru98rRHHRHh",
+"H^^^^t21>-qRHHLg",
+"H^^RV61>-&&lHHHd",
+"D^RRz1;*&@XyHDHa",
+"N^RRV2;&+XXkDDHa",
+"DRRRRq$+X.7DDDDa",
+"NRRRRRe540BDNDDi",
+"NRRIIIILHHHDDDDi",
+"nnvvcchgddaaiiii",
+"////////////////",
+"////////////////"
+};
diff --git a/src/images/flags/KE.xpm b/src/images/flags/KE.xpm
new file mode 100644
index 0000000..077c7d3
--- /dev/null
+++ b/src/images/flags/KE.xpm
@@ -0,0 +1,176 @@
+/* XPM */
+static const char *KE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 154 2",
+" c black",
+". c #000029290000",
+"X c #00002D2D0000",
+"o c #00002F2F0000",
+"O c #000031310000",
+"+ c #000033330000",
+"@ c #000035350000",
+"# c #000039390000",
+"$ c #00003D3D0000",
+"% c #2C2C2C2C2C2C",
+"& c #313131313131",
+"* c #373737373737",
+"= c #000041410000",
+"- c #000047470000",
+"; c #00004D4D0000",
+": c #000051510000",
+"> c #000057570000",
+", c #00005D5D0000",
+"< c #000063630000",
+"1 c #000067670000",
+"2 c #00006F6F0000",
+"3 c #000071710000",
+"4 c #000079790000",
+"5 c #4C4C32323333",
+"6 c #4D4D3F3F3E3E",
+"7 c #58582F2F3131",
+"8 c #62623C3C3C3C",
+"9 c #414146464646",
+"0 c #494949494949",
+"q c #4E4E4E4E4E4E",
+"w c #5D5D43434343",
+"e c #535353535353",
+"r c #57575C5C5C5C",
+"t c #585857575757",
+"y c gray35",
+"u c gray36",
+"i c #5F5F5F5F5F5F",
+"p c #70704D4D4D4D",
+"a c #646463636363",
+"s c #656566666666",
+"d c DimGray",
+"f c #6D6D6D6D6D6D",
+"g c #727272727272",
+"h c gray46",
+"j c #777777777777",
+"k c #797979797979",
+"l c #7B7B7B7B7A7A",
+"z c #7B7B7B7B7B7B",
+"x c #0B0B9A9A0E0E",
+"c c #0F0F9C9C1111",
+"v c #13139F9F1616",
+"b c #1919A1A12020",
+"n c #2C2CA4A43434",
+"m c #3636A6A63636",
+"M c #3636A9A93737",
+"N c #3434AFAF3A3A",
+"B c #3838A8A83838",
+"V c #3B3BA9A93C3C",
+"C c #3A3AB1B13B3B",
+"Z c #3B3BADAD4343",
+"A c #3F3FB3B34141",
+"S c #6F6F82823939",
+"D c #6E6E88883E3E",
+"F c #4040ABAB4040",
+"G c #4141ACAC4040",
+"H c #4444AEAE4444",
+"J c #4444B6B64646",
+"K c #4848B1B14848",
+"L c #4D4DB3B34D4D",
+"P c #5151B5B55151",
+"I c #5656B7B75656",
+"U c #5B5BB9B95B5B",
+"Y c #5F5FBBBB5F5F",
+"T c #6464BEBE6464",
+"R c #6868BFBF6868",
+"E c #6C6CC3C36D6D",
+"W c #BBBB00000000",
+"Q c #808057575858",
+"! c #83835E5E5E5E",
+"~ c #C1C100000000",
+"^ c #DFDF00000000",
+"/ c #E5E500000000",
+"( c #E9E900000000",
+") c #E0E017171F1F",
+"_ c #E0E01B1B2121",
+"` c #E1E11A1A2222",
+"' c #E1E11F1F2727",
+"] c #E2E220202626",
+"[ c #E3E324242A2A",
+"{ c #E3E325252C2C",
+"} c #E4E427272D2D",
+"| c #E5E527272D2D",
+" . c #E4E42C2C3232",
+".. c #E5E52D2D3333",
+"X. c #E7E735353A3A",
+"o. c #E4E438383F3F",
+"O. c #E3E33B3B4141",
+"+. c #E0E03F3F4343",
+"@. c #DCDC42424646",
+"#. c #DEDE43434848",
+"$. c #DCDC48484B4B",
+"%. c #DFDF4E4E5151",
+"&. c #E7E743434848",
+"*. c #E4E44B4B4E4E",
+"=. c #EFEF47474D4D",
+"-. c #EEEE48484C4C",
+";. c #ECEC4A4A5050",
+":. c #EEEE4B4B5151",
+">. c #EDED50505555",
+",. c #EFEF51515555",
+"<. c #EEEE54545959",
+"1. c #F1F155555858",
+"2. c #F1F155555A5A",
+"3. c #F1F159595C5C",
+"4. c #F2F25D5D6161",
+"5. c #E2E268686969",
+"6. c #E0E06C6C6C6C",
+"7. c #E7E77B7B7B7B",
+"8. c #E7E77F7F7F7F",
+"9. c #F3F361616565",
+"0. c #F1F173737777",
+"q. c #F3F375757878",
+"w. c #F6F67D7D7F7F",
+"e. c #B1B19D9D9D9D",
+"r. c #ABABAFAF8F8F",
+"t. c #D5D5D7D7BFBF",
+"y. c #C6C6C8C8C8C8",
+"u. c #CCCCCDCDCDCD",
+"i. c #D5D5C9C9C9C9",
+"p. c #DBDBD3D3C8C8",
+"a. c #E0E0D9D9CECE",
+"s. c #E5E5D5D5D5D5",
+"d. c #E9E9DBDBDBDB",
+"f. c #E7E7E8E8E2E2",
+"g. c #EBEBE7E7E7E7",
+"h. c #E9E9EAEAE3E3",
+"j. c #EAEAEBEBE4E4",
+"k. c #EBEBEBEBE6E6",
+"l. c #EBEBECECE6E6",
+"z. c #ECECE9E9E9E9",
+"x. c #EDEDEAEAEAEA",
+"c. c #EDEDEBEBEAEA",
+"v. c #EFEFEBEBEBEB",
+"b. c #F0F0F1F1ECEC",
+"n. c #F2F2F2F2EEEE",
+"m. c #F3F3F3F3EFEF",
+"M. c #F3F3F1F1F1F1",
+"N. c #F4F4F2F2F2F2",
+"B. c #F5F5F3F3F3F3",
+"V. c #F4F4F4F4F0F0",
+"C. c #F7F7F7F7F3F3",
+"Z. c #F6F6F4F4F4F4",
+"A. c #F7F7F6F6F6F6",
+"S. c None",
+/* pixels */
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+" ",
+" z z z h h g f d s a u t e q ",
+" z i u u r u.! Q y.9 * & % 0 ",
+"i.A.A.A.M.M.d.8.7.s.v.z.z.k.c.e.",
+"( w.4.4.<.1.p %.*.8 X...} [ &.~ ",
+"/ 0.<.>.;.-.w $.#.5 ..[ ' ` O.W ",
+"/ q.1.,.;.=.6 @.+.7 } ' ` ) o.W ",
+"p.V.V.V.m.m.a.6.5.p.k.k.h.f.l.r.",
+"4 E J C C N Z D S n b v c x M O ",
+"3 E T U U I P L K H G G V B m . ",
+"3 1 < , > : ; - = $ # O o o . @ ",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S."
+};
diff --git a/src/images/flags/KG.xpm b/src/images/flags/KG.xpm
new file mode 100644
index 0000000..35b6175
--- /dev/null
+++ b/src/images/flags/KG.xpm
@@ -0,0 +1,155 @@
+/* XPM */
+static const char *KG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 133 2",
+" c black",
+". c #C7C700000000",
+"X c #C9C900000000",
+"o c #CBCB00000000",
+"O c #CDCD00000000",
+"+ c #D1D100000000",
+"@ c #D3D300000000",
+"# c #D5D500000000",
+"$ c #D7D700000000",
+"% c #D9D900000000",
+"& c #DBDB00000000",
+"* c #DDDD00000000",
+"= c #E1E100000000",
+"- c #E3E300000000",
+"; c #E5E500000000",
+": c #E7E700000000",
+"> c #E5E50B0B0B0B",
+", c #E5E50F0F0E0E",
+"< c #E9E900000000",
+"1 c #EBEB00000000",
+"2 c #EDED00000000",
+"3 c #EFEF00000000",
+"4 c #E5E510101010",
+"5 c #E7E713131313",
+"6 c #E7E714141414",
+"7 c #E8E819191919",
+"8 c #E8E81A1A1A1A",
+"9 c #E9E91F1F1F1F",
+"0 c #F1F100000000",
+"q c #E9E920201F1F",
+"w c #EAEA28281F1F",
+"e c #EAEA2C2C1E1E",
+"r c #E7E72C2C2C2C",
+"t c #E9E920202020",
+"y c #EBEB25252525",
+"u c #EBEB26262525",
+"i c #EBEB26262626",
+"p c #E8E82F2F2F2F",
+"a c #ECEC2B2B2B2B",
+"s c #ECEC2C2C2C2C",
+"d c #EDED38382E2E",
+"f c #E9E932323232",
+"g c #E9E935353535",
+"h c #E9E936363636",
+"j c #EDED31313131",
+"k c #EEEE34343434",
+"l c #EFEF37373737",
+"z c #EBEB39393939",
+"x c #EBEB3B3B3B3B",
+"c c #EFEF3A3A3A3A",
+"v c #ECEC3D3D3D3D",
+"b c #ECEC3F3F3F3F",
+"n c #F0F03C3C3D3D",
+"m c #F0F03F3F3F3F",
+"M c #F1F13F3F3F3F",
+"N c #EFEF40403636",
+"B c #EEEE5F5F2323",
+"V c #F0F041413A3A",
+"C c #EFEF67672929",
+"Z c #EFEF69692424",
+"A c #F2F269693030",
+"S c #EDED42424242",
+"D c #EDED44444444",
+"F c #EEEE46464646",
+"G c #EEEE49494949",
+"H c #EFEF4B4B4B4B",
+"J c #EFEF4E4E4E4E",
+"K c #EFEF50505050",
+"L c #F1F144444444",
+"P c #F1F145454545",
+"I c #F2F248484242",
+"U c #F2F249494949",
+"Y c #F2F24A4A4949",
+"T c #F2F24A4A4B4B",
+"R c #F3F34F4F4F4F",
+"E c #F0F053535353",
+"W c #F3F350505050",
+"Q c #F1F154545555",
+"! c #F2F257575757",
+"~ c #F4F453535353",
+"^ c #F4F455555151",
+"/ c #F4F454545454",
+"( c #F4F459595151",
+") c #F2F258585858",
+"_ c #F2F25C5C5C5C",
+"` c #F2F25D5D5D5D",
+"' c #F5F558585858",
+"] c #F5F559595959",
+"[ c #F6F65C5C5C5C",
+"{ c #F6F65F5F5F5F",
+"} c #F4F473734040",
+"| c #F5F577774747",
+" . c #F5F576764C4C",
+".. c #F6F67D7D4B4B",
+"X. c #F3F360606060",
+"o. c #F3F361616262",
+"O. c #F4F465656565",
+"+. c #F4F466666666",
+"@. c #F5F569696969",
+"#. c #F5F56A6A6A6A",
+"$. c #F6F66D6D6D6D",
+"%. c #F6F66F6F6F6F",
+"&. c #F6F670707171",
+"*. c #F7F772727373",
+"=. c #F7F774747474",
+"-. c #F7F776767676",
+";. c #F7F777777777",
+":. c #F7F779797979",
+">. c #F8F87B7B7A7A",
+",. c #F8F87B7B7B7B",
+"<. c #F1F185852B2B",
+"1. c #F3F382823636",
+"2. c #F5F588883B3B",
+"3. c #F3F394942F2F",
+"4. c #F2F299992424",
+"5. c #F4F497973535",
+"6. c #F5F59E9E3434",
+"7. c #F6F69B9B3C3C",
+"8. c #F6F6A0A03C3C",
+"9. c #F4F4B7B72A2A",
+"0. c #F7F792924646",
+"q. c #F6F6A0A04141",
+"w. c #F8F8A5A54B4B",
+"e. c #F5F5C4C42A2A",
+"r. c #F6F6C7C72F2F",
+"t. c #F5F5C3C33030",
+"y. c #F7F7C2C23636",
+"u. c #F8F8C0C03A3A",
+"i. c #F8F8CBCB4040",
+"p. c #F9F9C8C84646",
+"a. c #FAFAD4D44242",
+"s. c #FAFAD7D74747",
+"d. c None",
+/* pixels */
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"0 0 0 0 3 3 3 1 1 1 : : = = * * ",
+"0 ,.,.:.:.-.&.$. at .O.X._ ! W K % ",
+"0 ,.[ [ ' / ( .| I n l j s G # ",
+"3 :.[ ' / ^ w.s.a.8.n j r i D @ ",
+"3 -.' / W ..p.q.7.y.A r i t V @ ",
+"3 *.~ R T 0.i.2.1.r.<.y 9 8 x O ",
+"3 %.R U P } u.5.3.9.Z 9 7 5 h O ",
+"1 #.H L L n 6.r.e.4.w 7 6 4 f O ",
+"1 +.L V c k d C B e 7 5 4 > r . ",
+": o.` ) ! J H D S v z h f p r . ",
+": = = * % % % # @ @ O o o . . o ",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d."
+};
diff --git a/src/images/flags/KH.xpm b/src/images/flags/KH.xpm
new file mode 100644
index 0000000..0af2cb2
--- /dev/null
+++ b/src/images/flags/KH.xpm
@@ -0,0 +1,183 @@
+/* XPM */
+static const char *KH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 161 2",
+" c black",
+". c #000000006969",
+"X c #000000007B7B",
+"o c #000000007D7D",
+"O c #000000007F7F",
+"+ c #000000008181",
+"@ c #000000008585",
+"# c #000000008989",
+"$ c #000000008B8B",
+"% c #000000008F8F",
+"& c #000000009393",
+"* c #000000009797",
+"= c #000000009999",
+"- c #000000009B9B",
+"; c #000000009F9F",
+": c #00000000A1A1",
+"> c #00000000A3A3",
+", c #00000000A7A7",
+"< c #00000000A9A9",
+"1 c #00000000ADAD",
+"2 c #00000000AFAF",
+"3 c #00000000B1B1",
+"4 c #00000000B3B3",
+"5 c #00000000B7B7",
+"6 c #00000707B3B3",
+"7 c #00000000B9B9",
+"8 c #00000000BBBB",
+"9 c #00000303BDBD",
+"0 c #00000707BDBD",
+"q c #00000707BFBF",
+"w c #00000D0DBFBF",
+"e c #22223838B4B4",
+"r c #26263B3BB7B7",
+"t c #2B2B4444BCBC",
+"y c #2F2F4747BDBD",
+"u c #34344B4BBFBF",
+"i c #39394F4FC1C1",
+"p c #34345252C8C8",
+"a c #36365555C9C9",
+"s c #3F3F5454C3C3",
+"d c #39395757CACA",
+"f c #3D3D5B5BCBCB",
+"g c #42425555BFBF",
+"h c #44445959C6C6",
+"j c #45455858C6C6",
+"k c #41415E5ECDCD",
+"l c #49495E5EC8C8",
+"z c #4A4A5D5DC8C8",
+"x c #44446161CECE",
+"c c #48486565CFCF",
+"v c #4E4E6363CBCB",
+"b c #4F4F6262CACA",
+"n c #4D4D6868D1D1",
+"m c #52526363C9C9",
+"M c #53536666CBCB",
+"N c #57576868CBCB",
+"B c #57576B6BCDCD",
+"V c #5A5A6B6BCBCB",
+"C c #5D5D6E6ECFCF",
+"Z c #51516C6CD3D3",
+"A c #55556F6FD5D5",
+"S c #56567070D4D4",
+"D c #5A5A7474D7D7",
+"F c #5B5B7575D6D6",
+"G c #5F5F7777D8D8",
+"H c #5F5F7878D8D8",
+"J c #61617272D1D1",
+"K c #65657676D2D2",
+"L c #63637B7BDADA",
+"P c #64647C7CDADA",
+"I c #67677F7FDBDB",
+"U c #69697979D3D3",
+"Y c #6B6B7C7CD5D5",
+"T c #6E6E7E7ED6D6",
+"R c #68687F7FDCDC",
+"E c #6A6A8383DDDD",
+"W c #6F6F8686DDDD",
+"Q c #76768484D5D5",
+"! c #73738A8ADFDF",
+"~ c #76768C8CE0E0",
+"^ c #79798F8FE2E2",
+"/ c #7C7C9191E2E2",
+"( c #7F7F9393E3E3",
+") c #8B8B00000000",
+"_ c #8F8F00000000",
+"` c #979700000000",
+"' c #BDBD00000000",
+"] c #BFBF00000000",
+"[ c #C3C300000000",
+"{ c #C6C610101010",
+"} c #C8C814141414",
+"| c #C9C918181616",
+" . c #C8C819191919",
+".. c #C8C81A1A1A1A",
+"X. c #C9C91F1F1F1F",
+"o. c #CCCC20202020",
+"O. c #CDCD25252525",
+"+. c #CDCD26262626",
+"@. c #CECE2B2B2B2B",
+"#. c #CFCF2E2E2D2D",
+"$. c #CDCD32323232",
+"%. c #CFCF31313131",
+"&. c #CECE32323232",
+"*. c #CFCF36363636",
+"=. c #CFCF3B3B3B3B",
+"-. c #D0D038383737",
+";. c #D2D238383939",
+":. c #D2D23C3C3C3C",
+">. c #D3D33F3F3F3F",
+",. c #D3D344444444",
+"<. c #D7D749494747",
+"1. c #D7D74B4B4B4B",
+"2. c #D8D847474646",
+"3. c #D9D949494949",
+"4. c #D8D84A4A4949",
+"5. c #D9D94F4F4F4F",
+"6. c #DBDB4F4F4F4F",
+"7. c #DBDB51515050",
+"8. c #DADA51515252",
+"9. c #DADA52525252",
+"0. c #DBDB53535353",
+"q. c #DBDB54545454",
+"w. c #DDDD54545454",
+"e. c #DCDC58585757",
+"r. c #DCDC59595959",
+"t. c #DDDD58585858",
+"y. c #DDDD5B5B5A5A",
+"u. c #DEDE5C5C5C5C",
+"i. c #DBDB60606161",
+"p. c #DDDD63636363",
+"a. c #DEDE6F6F6E6E",
+"s. c #E1E16A6A6A6A",
+"d. c #E2E26F6F6F6F",
+"f. c #E2E272727373",
+"g. c #E4E476767676",
+"h. c #E4E479797979",
+"j. c #88889494DDDD",
+"k. c #80809595E3E3",
+"l. c #E5E581818080",
+"z. c #E5E59B9B9B9B",
+"x. c #E8E8A3A3A3A3",
+"c. c #EEEEDCDCDBDB",
+"v. c #F5F5DEDEDDDD",
+"b. c #F4F4DEDEDEDE",
+"n. c #F2F2E2E2E2E2",
+"m. c #F3F3E4E4E4E4",
+"M. c #F4F4E6E6E6E6",
+"N. c #F5F5E6E6E6E6",
+"B. c #F6F6E5E5E5E5",
+"V. c #F6F6E8E8E7E7",
+"C. c #F4F4EBEBEBEB",
+"Z. c #F7F7E8E8E8E8",
+"A. c #F7F7EDEDECEC",
+"S. c #F7F7F2F2F2F2",
+"D. c #F4F4F4F4F4F4",
+"F. c #F5F5F4F4F4F4",
+"G. c #F6F6F6F6F6F6",
+"H. c gray97",
+"J. c #F9F9F6F6F6F6",
+"K. c #F8F8F8F8F8F8",
+"L. c None",
+/* pixels */
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"w 0 0 0 8 8 5 5 5 3 1 < < > ; ; ",
+"0 k.( ( / / ~ ~ W E I L H F A = ",
+"6 j.T Y U K J C B M b z h s V @ ",
+"[ h.u.t.q.9.1.p.i.:.;.%. at .+.,.` ",
+"[ g.t.w.9.l.t.b.b.<.a.#.+.o.>.` ",
+"[ f.9.5.7.V.x.M.M.z.n.%.X. .=._ ",
+"' d.5.3.e.K.V.K.S.n.D.*. .} *._ ",
+"' s.3.2.B.J.A.H.H.C.H.c.| { %.) ",
+"; Q N M v z h s i u y t r e g . ",
+"3 E L G F S Z n c x k f d a p o ",
+"1 > > ; = * * % $ $ @ O O o o o ",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L."
+};
diff --git a/src/images/flags/KI.xpm b/src/images/flags/KI.xpm
new file mode 100644
index 0000000..61894de
--- /dev/null
+++ b/src/images/flags/KI.xpm
@@ -0,0 +1,187 @@
+/* XPM */
+static const char *KI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 165 2",
+" c black",
+". c #000000004F4F",
+"X c #000000005151",
+"o c #000000005B5B",
+"O c #000000005F5F",
+"+ c #000000006D6D",
+"@ c #000000007373",
+"# c #000007077777",
+"$ c #000000007F7F",
+"% c #01011F1F7373",
+"& c #090923237777",
+"* c #33332F2F6969",
+"= c #000023239191",
+"- c #131333338F8F",
+"; c #33334B4B9595",
+": c #35354D4D9595",
+"> c #474757578585",
+", c #45455B5B9F9F",
+"< c #53535F5F8D8D",
+"1 c #535361618B8B",
+"2 c #5B5B69699393",
+"3 c #53536969A9A9",
+"4 c #636371719999",
+"5 c #7F7F7B7BA5A5",
+"6 c #4E4E6F6FC9C9",
+"7 c #53537171C6C6",
+"8 c #52527171C9C9",
+"9 c #5B5B7878CACA",
+"0 c #5F5F7B7BCCCC",
+"q c #5F5F7C7CD0D0",
+"w c #63637C7CCACA",
+"e c #61617D7DCFCF",
+"r c #62627D7DCCCC",
+"t c #6A6A8484CDCD",
+"y c #63638080D1D1",
+"u c #6B6B8484D1D1",
+"i c #6E6E8888D1D1",
+"p c #70708989D1D1",
+"a c #70708989D3D3",
+"s c #70708B8BD6D6",
+"d c #7A7A9191D5D5",
+"f c #7E7E9494D7D7",
+"g c #7B7B9393D9D9",
+"h c #7D7D9797DBDB",
+"j c #B9B900000000",
+"k c #BBBB00000000",
+"l c #BFBF00000000",
+"z c #ADAD49494545",
+"x c #C1C100000000",
+"c c #C3C300000000",
+"v c #C7C700000000",
+"b c #CBCB00000000",
+"n c #CDCD00000000",
+"m c #CFCF00000000",
+"M c #D7D700000000",
+"N c #DBDB00000000",
+"B c #DDDD00000000",
+"V c #DFDF00000000",
+"C c #DDDD34342020",
+"Z c #DEDE39392525",
+"A c #DFDF3C3C2626",
+"S c #E3E300000000",
+"D c #E5E53E3E2B2B",
+"F c #E1E141412D2D",
+"G c #E1E141412E2E",
+"H c #E1E142422F2F",
+"J c #E3E343433131",
+"K c #E3E348483434",
+"L c #E3E348483535",
+"P c #E4E44C4C3A3A",
+"I c #E4E44D4D3B3B",
+"U c #E4E452523F3F",
+"Y c #E2E253534141",
+"T c #E2E257574545",
+"R c #E6E652524040",
+"E c #E7E755554545",
+"W c #E4E45B5B4A4A",
+"Q c #E8E85B5B4747",
+"! c #E9E95C5C4C4C",
+"~ c #E6E660604F4F",
+"^ c #E8E860604E4E",
+"/ c #EEEE60604F4F",
+"( c #E7E765655454",
+") c #E5E56F6F5151",
+"_ c #EAEA63635252",
+"` c #EAEA63635353",
+"' c #EBEB63635353",
+"] c #EAEA65655454",
+"[ c #EBEB67675757",
+"{ c #ECEC67675858",
+"} c #E9E96F6F5555",
+"| c #E8E86A6A5B5B",
+" . c #EAEA6E6E5F5F",
+".. c #ECEC6B6B5B5B",
+"X. c #EDED6E6E5E5E",
+"o. c #EDED6F6F5E5E",
+"O. c #EBEB71716363",
+"+. c #EDED70706060",
+"@. c #E8E87C7C6969",
+"#. c #EFEF83837575",
+"$. c #ECEC85857474",
+"%. c #F0F085857979",
+"&. c #F0F086867A7A",
+"*. c #F2F287877A7A",
+"=. c #F1F188887B7B",
+"-. c #F1F189897B7B",
+";. c #F1F189897C7C",
+":. c #F4F48A8A7B7B",
+">. c #E7E7BBBB4848",
+",. c #E9E9C2C25757",
+"<. c #EAEAC1C15656",
+"1. c #EBEBC3C35B5B",
+"2. c #E8E8DCDC5252",
+"3. c #EAEADEDE5757",
+"4. c #F1F1DDDD7A7A",
+"5. c #F2F2DDDD7E7E",
+"6. c #F2F2E3E35050",
+"7. c #F5F5E6E65555",
+"8. c #8D8D9999BBBB",
+"9. c #87879D9DDBDB",
+"0. c #8E8E9D9DD8D8",
+"q. c #8B8BA0A0DDDD",
+"w. c #9393A6A6DFDF",
+"e. c #9B9BACACDDDD",
+"r. c #9C9CACACDADA",
+"t. c #8B8BA4A4E1E1",
+"y. c #9191A5A5E0E0",
+"u. c #A9A9B7B7DFDF",
+"i. c #AAAAB9B9DFDF",
+"p. c #AFAFBCBCE2E2",
+"a. c #B2B2C0C0E6E6",
+"s. c #B3B3C1C1E7E7",
+"d. c #B7B7C3C3E6E6",
+"f. c #B9B9C5C5E8E8",
+"g. c #D7D78D8D8B8B",
+"h. c #EFEFDCDCBEBE",
+"j. c #F9F9C3C3BBBB",
+"k. c #C1C1CACAE4E4",
+"l. c #C3C3CDCDE6E6",
+"z. c #C6C6CDCDE6E6",
+"x. c #C0C0CCCCEBEB",
+"c. c #C8C8D0D0E9E9",
+"v. c #CBCBD3D3E8E8",
+"b. c #CBCBD3D3EAEA",
+"n. c #CDCDD5D5EBEB",
+"m. c #CECED7D7EDED",
+"M. c #D0D0D7D7EBEB",
+"N. c #D0D0D8D8EFEF",
+"B. c #D4D4DBDBEFEF",
+"V. c #D6D6DDDDF1F1",
+"C. c #D8D8DDDDF0F0",
+"Z. c #DEDEE3E3F3F3",
+"A. c #E4E4CECED2D2",
+"S. c #E2E2D4D4DADA",
+"D. c #EEEEDBDBDDDD",
+"F. c #F2F2CDCDC9C9",
+"G. c #F4F4CECECBCB",
+"H. c #FBFBCFCFC8C8",
+"J. c #F1F1D4D4CFCF",
+"K. c #F8F8D7D7D3D3",
+"L. c #E4E4E4E4DEDE",
+"P. c #F6F6EEEEDDDD",
+"I. c #E7E7E7E7E1E1",
+"U. c #F0F0E5E5E9E9",
+"Y. c None",
+/* pixels */
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"B N N B N N M M M m m m b v c c ",
+"B ;.;.;.*.#.$.5.4. at .O. ...( ~ l ",
+"S -.+.X...] ] } ) E R I L G W l ",
+"B *.X...[ ` ! 1.<.U P K H A T j ",
+"S *.[ ] ` ! ,.3.2.>.J H Z C Y j ",
+"g.:.H.j./ K.P.7.6.h.G.D F.J.Q z ",
+"5 U.t.V.D.0.h I.L.q w A.w 6 S.* ",
+"8.y.V.a.s N.m.y e b.e.8 l.k.i < ",
+"= Z.g V.a.p u n.b.0 9 l.r.7 b.& ",
+"3 w.x.9.9.f.d.f d M.p.p i.u.t . ",
+"# , = : ; @ + 4 2 O o < % . > - ",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y."
+};
diff --git a/src/images/flags/KM.xpm b/src/images/flags/KM.xpm
new file mode 100644
index 0000000..7601c33
--- /dev/null
+++ b/src/images/flags/KM.xpm
@@ -0,0 +1,174 @@
+/* XPM */
+static const char *KM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 152 2",
+" c black",
+". c #000053530000",
+"X c #000059590000",
+"o c #000055551717",
+"O c #000067670000",
+"+ c #00006F6F0000",
+"@ c #00000000DDDD",
+"# c #00000000DFDF",
+"$ c #00000000E1E1",
+"% c #00000000E3E3",
+"& c #00000000E5E5",
+"* c #00000101E7E7",
+"= c #00000707E9E9",
+"- c #00000F0FEBEB",
+"; c #00001313EDED",
+": c #00001B1BEDED",
+"> c #00003939C3C3",
+", c #00002121EFEF",
+"< c #00002F2FF1F1",
+"1 c #6D6D6D6DA7A7",
+"2 c #595996963F3F",
+"3 c #4F4FA7A70000",
+"4 c #4040A0A04040",
+"5 c #4141A1A14040",
+"6 c #4646A3A34646",
+"7 c #4F4FA7A75151",
+"8 c #5050A9A95050",
+"9 c #5353A9A95353",
+"0 c #5C5CB0B05D5D",
+"q c #7D7D9B9B7474",
+"w c #6060B1B15F5F",
+"e c #6363AFAF7171",
+"r c #6868B5B56666",
+"t c #6C6CB6B66B6B",
+"y c #7474B9B97373",
+"u c #7B7BBCBC7A7A",
+"i c #6E6EA7A7BDBD",
+"p c #4D4D8A8AF2F2",
+"a c #4F4F8C8CF2F2",
+"s c #52528F8FF3F3",
+"d c #55559090F3F3",
+"f c #59599393F4F4",
+"g c #5C5C9595F5F5",
+"h c #60609898F6F6",
+"j c #64649B9BF7F7",
+"k c #68689E9EF7F7",
+"l c #6B6B9F9FF8F8",
+"z c #7373A2A2F9F9",
+"x c #7979A3A3F9F9",
+"c c #B3B300000000",
+"v c #B5B500000000",
+"b c #B3B36E6E3A3A",
+"n c #DADA2E2E1414",
+"m c #DBDB35351010",
+"M c #DBDB31311919",
+"N c #DDDD36361F1F",
+"B c #DCDC39391414",
+"V c #DEDE3D3D1919",
+"C c #DEDE3B3B2424",
+"Z c #E1E13F3F2A2A",
+"A c #DFDF41411F1F",
+"S c #DEDE4B4B3636",
+"D c #D3D356563535",
+"F c #E1E146462424",
+"G c #E4E445452F2F",
+"H c #E2E24B4B2A2A",
+"J c #E8E84E4E2F2F",
+"K c #E0E052523232",
+"L c #EDED51513434",
+"P c #828281813A3A",
+"I c #8080A5A56262",
+"U c #9D9DCFCF5C5C",
+"Y c #8E8EC8C87B7B",
+"T c #E7E7D6D60000",
+"R c #EAEAD3D30000",
+"E c #EBEBD4D40000",
+"W c #ECECD5D50000",
+"Q c #EDEDD6D60000",
+"! c #EEEED7D70000",
+"~ c #EFEFD8D80000",
+"^ c #F0F0D9D90000",
+"/ c #F1F1DADA0000",
+"( c #F2F2DBDB0000",
+") c #D4D4EAEA7B7B",
+"_ c #F7F7F7F74E4E",
+"` c #F8F8F8F85353",
+"' c #F9F9F9F95757",
+"] c #FAFAFAFA5C5C",
+"[ c #F6F6F6F66060",
+"{ c #F7F7F7F76464",
+"} c #FBFBFBFB6060",
+"| c #FCFCFCFC6565",
+" . c #F8F8F8F86969",
+".. c #F9F9F9F96D6D",
+"X. c #FCFCFCFC6969",
+"o. c #FDFDFDFD6D6D",
+"O. c #F7F7F7F77575",
+"+. c #F3F3F9F97979",
+"@. c #FAFAFAFA7171",
+"#. c #FBFBFBFB7575",
+"$. c #FDFDFDFD7171",
+"%. c #FEFEFEFE7474",
+"&. c #FEFEFEFE7777",
+"*. c #FCFCFCFC7979",
+"=. c #FEFEFEFE7979",
+"-. c #FDFDFDFD7D7D",
+";. c #88888282BEBE",
+":. c #88888484BEBE",
+">. c #97978787B5B5",
+",. c #89898585C0C0",
+"<. c #89898686C1C1",
+"1. c #8A8A8787C2C2",
+"2. c #8B8B8989C4C4",
+"3. c #8B8B8A8AC5C5",
+"4. c #8B8B8B8BC7C7",
+"5. c #8D8D8C8CC7C7",
+"6. c #8E8E8D8DC9C9",
+"7. c #9B9BCDCD9E9E",
+"8. c #B9B9DDDDB9B9",
+"9. c #DBDBA5A59797",
+"0. c #FDFDFDFD8686",
+"q. c #CACAE4E4CACA",
+"w. c #CECEE7E7CECE",
+"e. c #CFCFE7E7CFCF",
+"r. c #D3D3E8E8D3D3",
+"t. c #DCDCEDEDDCDC",
+"y. c #EFEFD3D3CCCC",
+"u. c #F1F1D5D5CECE",
+"i. c #F1F1D7D7D0D0",
+"p. c #F1F1D8D8D3D3",
+"a. c #F2F2D9D9D2D2",
+"s. c #F3F3D9D9D3D3",
+"d. c #F4F4DBDBD4D4",
+"f. c #E7E7E7E7E7E7",
+"g. c #E8E8F3F3E8E8",
+"h. c #EAEAF3F3EAEA",
+"j. c #E8E8F4F4E8E8",
+"k. c #EBEBF4F4EBEB",
+"l. c #EEEEF7F7EEEE",
+"z. c #ECECF8F8F2F2",
+"x. c #F4F4F4F4F4F4",
+"c. c #F5F5F5F5F4F4",
+"v. c gray96",
+"b. c #F6F6F6F6F5F5",
+"n. c #F6F6F6F6F6F6",
+"m. c gray97",
+"M. c #F8F8F8F8F8F8",
+"N. c #F9F9F9F9F9F9",
+"B. c gray98",
+"V. c #FBFBFBFBFBFB",
+"C. c gray99",
+"Z. c None",
+/* pixels */
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"3 T ( ( ( ( ( ( ( ( ! ( ! W W W ",
+"O Y ) &.&.%.%.o.o.| } ] ' ` _ W ",
+"+ u t U +.0.-.*. at .@.....{ [ O.R ",
+"X u k.t.y w.C.V.V.V.n.n.b.b.b.f.",
+"X k.l.0 w.7 7.z.V.b.n.b.x.b.b.f.",
+"X k.8.9 k.6 4 I s.p.i.i.u.y.i.9.",
+"X k.k.8 q.4 P D G Z C C M n S c ",
+"X r g.e.2 b L J H F A B B m K v ",
+"X r r q >.5.5.2.2.1.1.1.;.;.4.1 ",
+". e i x z l k j h g f d s a p @ ",
+"o > < , : ; - = * * $ $ $ @ @ @ ",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z."
+};
diff --git a/src/images/flags/KN.xpm b/src/images/flags/KN.xpm
new file mode 100644
index 0000000..91f9f7a
--- /dev/null
+++ b/src/images/flags/KN.xpm
@@ -0,0 +1,168 @@
+/* XPM */
+static const char *KN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 146 2",
+" c black",
+". c #353535353535",
+"X c gray21",
+"o c #3B3B3B3B3A3A",
+"O c gray23",
+"+ c #3B3B3B3B3C3C",
+"@ c #00006F6F0000",
+"# c #000073730000",
+"$ c #000079790000",
+"% c #00007D7D0000",
+"& c #00007F7F0000",
+"* c #4D4D2F2F0000",
+"= c #44443F3F2C2C",
+"- c #4D4D49492F2F",
+"; c #494943433030",
+": c #4A4A45453030",
+"> c #4E4E48483434",
+", c #51514C4C3636",
+"< c #55554E4E3C3C",
+"1 c #565650502F2F",
+"2 c #404040404848",
+"3 c #4E4E4E4E4E4E",
+"4 c #565650504040",
+"5 c #5A5A54544040",
+"6 c #595954544444",
+"7 c #535353535353",
+"8 c #545452525151",
+"9 c #61615A5A4040",
+"0 c #64645F5F4141",
+"q c #656561614949",
+"w c #656563635D5D",
+"e c #6A6A66665757",
+"r c #6D6D69695858",
+"t c #74746F6F4242",
+"y c #71716B6B5555",
+"u c #696967676262",
+"i c #000081810000",
+"p c #000083830000",
+"a c #000085850000",
+"s c #000087870000",
+"d c #000089890000",
+"f c #000091910000",
+"g c #01019B9B0000",
+"h c #4C4CB4B44C4C",
+"j c #5353BBBB4B4B",
+"k c #5353BBBB4F4F",
+"l c #5050B5B55050",
+"z c #5151B5B55151",
+"x c #5151B7B75151",
+"c c #5353B6B65353",
+"v c #5454B9B95454",
+"b c #5454BABA5454",
+"n c #5858BCBC5858",
+"m c #5858BCBC5959",
+"M c #5959BCBC5959",
+"N c #5C5CBDBD5C5C",
+"B c #5C5CBEBE5C5C",
+"V c #5F5FBFBF5F5F",
+"C c #6969BFBF6969",
+"Z c #6D6DC8C84F4F",
+"A c #7676CCCC4747",
+"S c #7373CACA4B4B",
+"D c #6D6DC3C36D6D",
+"F c #6F6FC2C26F6F",
+"G c #7171C7C76565",
+"H c #7070C5C57171",
+"J c #7272C6C67373",
+"K c #7474C7C77474",
+"L c #7676C8C87676",
+"P c #7777C8C87777",
+"I c #7979C8C87979",
+"U c #7979C9C97979",
+"Y c #7B7BCACA7A7A",
+"T c #7B7BCACA7B7B",
+"R c #DDDD00000000",
+"E c #DFDF00000000",
+"W c #E1E100000000",
+"Q c #E3E300000000",
+"! c #E5E500000000",
+"~ c #E7E700000000",
+"^ c #E9E900000000",
+"/ c #EBEB00000000",
+"( c #EDED00000000",
+") c #F1F10B0B0B0B",
+"_ c #F1F10F0F0E0E",
+"` c #F2F210101010",
+"' c #F2F213131313",
+"] c #F2F214141414",
+"[ c #F3F319191919",
+"{ c #F3F31A1A1A1A",
+"} c #F4F41E1E1E1E",
+"| c #F4F41F1F1F1F",
+" . c #EDED3B3B0000",
+".. c #F4F429291F1F",
+"X. c #F5F523232323",
+"o. c #F2F22C2C2C2C",
+"O. c #F2F22F2F2F2F",
+"+. c #F5F536362424",
+"@. c #F2F232323232",
+"#. c #F3F332323232",
+"$. c #F3F335353535",
+"%. c #F4F436363636",
+"&. c #F4F439393939",
+"*. c #F4F43B3B3B3B",
+"=. c #F5F53D3D3D3D",
+"-. c #F5F53F3F3F3F",
+";. c #C7C76D6D0000",
+":. c #F4F451512020",
+">. c #F6F642424242",
+",. c #F7F746464646",
+"<. c #9F9FA7A70000",
+"1. c #9D9DBFBF0000",
+"2. c #BABAB1B12B2B",
+"3. c #868681815C5C",
+"4. c #868682826666",
+"5. c #8C8C88887979",
+"6. c #8C8C88887B7B",
+"7. c #BABADBDB4747",
+"8. c #BABADDDD4B4B",
+"9. c #CFCFBEBE2626",
+"0. c #D3D3BABA2E2E",
+"q. c #F5F58B8B2424",
+"w. c #F6F693932929",
+"e. c #F4F4B9B92525",
+"r. c #F4F4BEBE2A2A",
+"t. c #F7F78E8E4B4B",
+"y. c #E6E6C3C32525",
+"u. c #E3E3C5C52A2A",
+"i. c #C6C6C4C44646",
+"p. c #C7C7C8C84949",
+"a. c #CACAD3D34242",
+"s. c #C9C9D7D74646",
+"d. c #C9C9DADA4949",
+"f. c #C3C3E2E26A6A",
+"g. c #C8C8E0E06060",
+"h. c #F6F6C1C14444",
+"j. c #F2F2CACA5050",
+"k. c #878787878D8D",
+"l. c #8B8B8A8A8A8A",
+"z. c #9D9D9A9A8E8E",
+"x. c #A0A09C9C8A8A",
+"c. c #DADADADADADA",
+"v. c #DFDFDFDFE0E0",
+"b. c #E9E9E8E8E8E8",
+"n. c #EAEAEAEAECEC",
+"m. c None",
+/* pixels */
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"f d d d a p p & $ # # g <. ",
+"a T T T K J F D C G g.3.e 7 3 ",
+"d T V N N b c h A a.0 c.2 = q ;.",
+"a T N N v c j 7.t < k.n.6.9.h.~ ",
+"d L b b h S s.0 + X ; 6.y.:.-.~ ",
+"p J v k 8.i.< O X : 2.e...[ &.~ ",
+"& F Z d.x.4 + X > u.q...[ ' %.Q ",
+"& f.p.z.n.l.> 1 r.+.} [ ' ' @.E ",
+"1.4.6 8 c., 0.w.X.} [ ' _ ) O.E ",
+" u w r y j.t.,.>.=.&.$. at .O.o.E ",
+" * .( / / ~ ~ Q Q E E R R ",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m."
+};
diff --git a/src/images/flags/KP.xpm b/src/images/flags/KP.xpm
new file mode 100644
index 0000000..762132f
--- /dev/null
+++ b/src/images/flags/KP.xpm
@@ -0,0 +1,182 @@
+/* XPM */
+static const char *KP_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 160 2",
+" c black",
+". c #00000B0BDDDD",
+"X c #00000F0FDDDD",
+"o c #00001111DFDF",
+"O c #00001919DDDD",
+"+ c #00001717E1E1",
+"@ c #00001D1DE3E3",
+"# c #00002121E5E5",
+"$ c #00002525E7E7",
+"% c #00002B2BE9E9",
+"& c #00003131EBEB",
+"* c #00003737EDED",
+"= c #00003F3FEDED",
+"- c #00004343EFEF",
+"; c #00004949EFEF",
+": c #00004949F1F1",
+"> c #00004F4FF3F3",
+", c #00005555F5F5",
+"< c #00005B5BF7F7",
+"1 c #03035F5FF5F5",
+"2 c #05055F5FF9F9",
+"3 c #0B0B6363FBFB",
+"4 c #11116767FDFD",
+"5 c #17176D6DFDFD",
+"6 c #1B1B6F6FFDFD",
+"7 c #21217373FDFD",
+"8 c #25257575FFFF",
+"9 c #31317D7DFFFF",
+"0 c #7F7FA3A3DDDD",
+"q c #C7C700000000",
+"w c #CDCD00000000",
+"e c #CFCF00000000",
+"r c #D1D100000000",
+"t c #D5D500000000",
+"y c #D7D700000000",
+"u c #E9E900000000",
+"i c #EDED00000000",
+"p c #EFEF00000000",
+"a c #E7E710101010",
+"s c #E7E714141414",
+"d c #E9E914141414",
+"f c #E8E819191919",
+"g c #E8E81A1A1A1A",
+"h c #EAEA19191919",
+"j c #E9E91F1F1F1F",
+"k c #EBEB1F1F1F1F",
+"l c #F1F100000000",
+"z c #F1F100000101",
+"x c #E6E623232323",
+"c c #E6E627272727",
+"v c #E9E920202020",
+"b c #EBEB24242424",
+"n c #EBEB25252525",
+"m c #ECEC24242424",
+"M c #EDED26262626",
+"N c #E8E82B2B2B2B",
+"B c #ECEC2A2A2A2A",
+"V c #ECEC2B2B2B2B",
+"C c #EEEE2A2A2A2A",
+"Z c #EEEE2B2B2B2B",
+"A c #EDED2F2F2F2F",
+"S c #E9E930303030",
+"D c #EBEB32323232",
+"F c #E9E936363636",
+"G c #EAEA34343434",
+"H c #EDED30303030",
+"J c #EFEF31313131",
+"K c #EFEF34343434",
+"L c #EFEF36363636",
+"P c #EBEB3B3B3B3B",
+"I c #ECEC39393939",
+"U c #ECEC3F3F3F3F",
+"Y c #EDED3E3E3E3E",
+"T c #F0F037373636",
+"R c #F0F03B3B3C3C",
+"E c #F1F13C3C3C3C",
+"W c #E9E943434343",
+"Q c #EDED41414242",
+"! c #EEEE44444444",
+"~ c #ECEC4A4A4C4C",
+"^ c #EEEE4D4D4D4D",
+"/ c #EDED50505151",
+"( c #EFEF54545656",
+") c #F2F241414242",
+"_ c #F3F347474747",
+"` c #F0F048484848",
+"' c #F0F04E4E4E4E",
+"] c #F2F24D4D4D4D",
+"[ c #F0F051515252",
+"{ c #F0F059595B5B",
+"} c #F2F258585858",
+"| c #F1F15E5E5F5F",
+" . c #EEEE64646565",
+".. c #F2F261616161",
+"X. c #F2F261616363",
+"o. c #F2F265656565",
+"O. c #F3F366666767",
+"+. c #F4F469696969",
+"@. c #F7F76A6A6A6A",
+"#. c #F6F66F6F6F6F",
+"$. c #F4F46E6E7171",
+"%. c #F4F472727272",
+"&. c #F4F472727373",
+"*. c #F7F772727373",
+"=. c #F5F576767676",
+"-. c #F6F674747575",
+";. c #F7F776767676",
+":. c #F6F677777979",
+">. c #F8F879797979",
+",. c #F9F979797979",
+"<. c #9D9DBBBBEBEB",
+"1. c #B3B3CDCDF7F7",
+"2. c #F6F685858484",
+"3. c #F5F58A8A8A8A",
+"4. c #F7F78C8C8C8C",
+"5. c #F8F88F8F8F8F",
+"6. c #F7F799999999",
+"7. c #F9F9A3A3A3A3",
+"8. c #C1C1D9D9FFFF",
+"9. c #CBCBD9D9F2F2",
+"0. c #CBCBDADAF2F2",
+"q. c #CDCDDBDBF3F3",
+"w. c #CECEDCDCF3F3",
+"e. c #D0D0DDDDF4F4",
+"r. c #D1D1DEDEF5F5",
+"t. c #D3D3E0E0F6F6",
+"y. c #D4D4E1E1F7F7",
+"u. c #D6D6E2E2F7F7",
+"i. c #D7D7E3E3F7F7",
+"p. c #D8D8E4E4F8F8",
+"a. c #D8D8E5E5F8F8",
+"s. c #D9D9E6E6F9F9",
+"d. c #DADAE6E6F9F9",
+"f. c #DADAE7E7F9F9",
+"g. c #DCDCE8E8FAFA",
+"h. c #DDDDE8E8FBFB",
+"j. c #DEDEE9E9FCFC",
+"k. c #DFDFEBEBFCFC",
+"l. c #F8F8C2C2C2C2",
+"z. c #FAFAC5C5C5C5",
+"x. c #FBFBC8C8C7C7",
+"c. c #FBFBC8C8C8C8",
+"v. c #FBFBC9C9C9C9",
+"b. c #FAFACACACACA",
+"n. c #F9F9D3D3D3D3",
+"m. c #FBFBD2D2D2D2",
+"M. c #FBFBDDDDDCDC",
+"N. c #FAFADEDEDEDE",
+"B. c #E1E1ECECFDFD",
+"V. c #E2E2EDEDFEFE",
+"C. c #E4E4EEEEFEFE",
+"Z. c #E5E5EEEEFEFE",
+"A. c #E5E5EFEFFFFF",
+"S. c #F9F9E1E1E1E1",
+"D. c #F9F9E3E3E2E2",
+"F. c #FDFDE1E1E1E1",
+"G. c #F9F9E8E8E8E8",
+"H. c #F9F9EAEAEAEA",
+"J. c #FCFCE8E8E8E8",
+"K. c None",
+/* pixels */
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"9 8 8 8 7 6 5 4 3 2 < , > : - ; ",
+"8.A.A.A.V.V.V.V.k.j.g.g.d.d.u.<.",
+"z 5.:.;.$.&.O.O.X.| { ( / ~ .t ",
+"z ,.,.x.J.F.5._ ) E L J Z M ! t ",
+"p ;.x.7.z.6.N.] Y L A Z M v U r ",
+"p *.M.m.%.n.G.X.T A Z n k f P w ",
+"p #.z.2.l.3.S._ A Z b k f s F w ",
+"p +.+.b.S.G.O.T Z m k h s a D w ",
+"u =.{ [ ^ ^ Q U F G S N c x W q ",
+"1.g.g.a.d.d.t.t.t.e.e.w.q.0.0.0 ",
+"3 > : - = * & % $ # @ + o X . O ",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K."
+};
diff --git a/src/images/flags/KR.xpm b/src/images/flags/KR.xpm
new file mode 100644
index 0000000..da5d67b
--- /dev/null
+++ b/src/images/flags/KR.xpm
@@ -0,0 +1,146 @@
+/* XPM */
+static const char *KR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 124 2",
+" c black",
+". c #565656565656",
+"X c #585858585858",
+"o c gray39",
+"O c #676766666666",
+"+ c DimGray",
+"@ c gray42",
+"# c #777777777777",
+"$ c #7C7C7B7B7C7C",
+"% c #7E7E7E7E7E7E",
+"& c gray50",
+"* c #2A2A6666D6D6",
+"= c #3A3A6D6DD5D5",
+"- c #3A3A7676DDDD",
+"; c #3C3C7272D9D9",
+": c #65656E6EBEBE",
+"> c #4B4B6767C5C5",
+", c #55556969C2C2",
+"< c #58586F6FC7C7",
+"1 c #6D6D9292DCDC",
+"2 c #7A7AA1A1E6E6",
+"3 c #E7E736363D3D",
+"4 c #EEEE3D3D4343",
+"5 c #E3E343434F4F",
+"6 c #E8E842424949",
+"7 c #FAFA41414141",
+"8 c #FAFA44444242",
+"9 c #FBFB46464646",
+"0 c #FBFB4A4A4A4A",
+"q c #F9F978787575",
+"w c #C6C679799393",
+"e c gray53",
+"r c gray55",
+"t c gray62",
+"y c #ABABAAAAA7A7",
+"u c #AAAAA9A9A8A8",
+"i c #ADADAFAFAFAF",
+"p c #AEAEAEAEAEAE",
+"a c #ADADB0B0B0B0",
+"s c #B1B1B1B1B1B1",
+"d c #BABAB9B9BABA",
+"f c #BBBBBBBBBBBB",
+"g c #B5B59D9DC3C3",
+"h c #A3A3ACACD9D9",
+"j c #AAAAC4C4F0F0",
+"k c #FCFC8A8A8A8A",
+"l c #F7F796969595",
+"z c #F3F3B1B1B5B5",
+"x c gray76",
+"c c #C5C5C5C5C5C5",
+"v c #C6C6C6C6C6C6",
+"b c #C8C8C8C8C8C8",
+"n c #CBCBCBCBCBCB",
+"m c #CBCBD1D1CFCF",
+"M c #CBCBD1D1D1D1",
+"N c #CBCBD3D3D1D1",
+"B c #CFCFD3D3D1D1",
+"V c #CFCFD5D5D3D3",
+"C c #CFCFD7D7D5D5",
+"Z c #D0D0D0D0CDCD",
+"A c #D3D3D3D3D1D1",
+"S c #D1D1D7D7D5D5",
+"D c #D5D5D5D5D5D5",
+"F c #D7D7D7D7D7D7",
+"G c #D1D1D9D9D7D7",
+"H c #D3D3D9D9D9D9",
+"J c #D5D5DBDBD9D9",
+"K c #D7D7DBDBDBDB",
+"L c #D7D7DFDFDDDD",
+"P c gray85",
+"I c #D8D8DADADBDB",
+"U c #DADAD9D9DADA",
+"Y c #DADADADADADA",
+"T c #DBDBDADADADA",
+"R c #DADADCDCDCDC",
+"E c #DFDFDFDFDFDF",
+"W c #C5C5D2D2ECEC",
+"Q c #C9C9D5D5EDED",
+"! c #D9D9E1E1DFDF",
+"~ c #DDDDE3E3E1E1",
+"^ c #DFDFE5E5E3E3",
+"/ c #FBFBD6D6D6D6",
+"( c #FCFCDADADADA",
+") c #E1E1E7E7E5E5",
+"_ c #E7E7E7E7E7E7",
+"` c #E3E3E9E9E9E9",
+"' c #E5E5EBEBEBEB",
+"] c #E7E7EDEDEDED",
+"[ c gray91",
+"{ c #E9E9E9E9E9E9",
+"} c #E9E9E9E9EAEA",
+"| c #EAEAEAEAEAEA",
+" . c #E9E9EEEEEEEE",
+".. c #E9E9EFEFEFEF",
+"X. c #EDEDECECE8E8",
+"o. c #E8E8EEEEF4F4",
+"O. c #EBEBF1F1EFEF",
+"+. c #EBEBF1F1F1F1",
+"@. c #EDEDF1F1F1F1",
+"#. c #EDEDF3F3F3F3",
+"$. c #EFEFF5F5F3F3",
+"%. c gray95",
+"&. c #F2F2F2F2F3F3",
+"*. c #F3F3F3F3F3F3",
+"=. c #F1F1F7F7F5F5",
+"-. c #F2F2F5F5F5F5",
+";. c #F5F5F4F4F3F3",
+":. c #F4F4F4F4F4F4",
+">. c #F4F4F5F5F5F5",
+",. c gray96",
+"<. c #F6F6F6F6F6F6",
+"1. c gray97",
+"2. c #F2F2F4F4F9F9",
+"3. c #F8F8F0F0F0F0",
+"4. c #FDFDF6F6F5F5",
+"5. c #F8F8F8F8F8F8",
+"6. c gray98",
+"7. c #FBFBFBFBFBFB",
+"8. c gray99",
+"9. c #FDFDFDFDFDFD",
+"0. c #FDFDFDFDFEFE",
+"q. c #FEFEFEFEFEFE",
+"w. c gray100",
+"e. c None",
+/* pixels */
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"=.=.=.=.=.=.=. at .@.O...] ' ` ) ^ ",
+"=.w.w.F v :.w.8.5.w.*.d b 5.5.~ ",
+"=.w.{ r $ R w.( / 7.P O # P 1.! ",
+"=.w.P e i 4.k 0 8 q 3.a o x :.! ",
+"=.w.w._ =.z 9 4 4 3 l ..P :.:.J ",
+"@.w.w.7.w.g 6 5 : > w :.:.:.:.G ",
+"@.w.7.{ *.j , < - * h X.P *.:.S ",
+"@.8.F % u 2.2 ; = 1 o.u X f :.V ",
+"+.8.E % @ A <.Q W &.Z . @ b %.N ",
+"+.8.5.v i { 1.:.<.:.' t s %.%.N ",
+"] ` ` ^ ^ ~ ~ L I J S C B V N n ",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e."
+};
diff --git a/src/images/flags/KW.xpm b/src/images/flags/KW.xpm
new file mode 100644
index 0000000..99098c1
--- /dev/null
+++ b/src/images/flags/KW.xpm
@@ -0,0 +1,163 @@
+/* XPM */
+static const char *KW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 141 2",
+" c black",
+". c #000041410000",
+"X c #000049490000",
+"o c #000051510000",
+"O c #000055550000",
+"+ c #000059590000",
+"@ c #00005F5F0000",
+"# c #000065650000",
+"$ c #00006B6B0000",
+"% c #00006F6F0000",
+"& c #000073730000",
+"* c #000075750000",
+"= c #000079790000",
+"- c #00007D7D0000",
+"; c #484849494545",
+": c #4D4D49494444",
+"> c #494949494949",
+", c #49494A4A4949",
+"< c gray31",
+"1 c #535353535353",
+"2 c gray33",
+"3 c #585858585858",
+"4 c #58585F5F5959",
+"5 c gray36",
+"6 c #5F5F69695F5F",
+"7 c #646467676262",
+"8 c gray40",
+"9 c #6A6A6A6A6A6A",
+"0 c #6F6F6F6F6F6F",
+"q c #727272727373",
+"w c #767676767676",
+"e c #797979797979",
+"r c #7B7B7B7B7A7A",
+"t c #000081810000",
+"y c #000089890000",
+"u c #000091910000",
+"i c #2C2CA5A52C2C",
+"p c #3131A8A83131",
+"a c #3737AAAA3737",
+"s c #3D3DADAD3D3D",
+"d c #4F4FA9A94F4F",
+"f c #4242B0B04242",
+"g c #4747B3B34747",
+"h c #4949B1B14949",
+"j c #4C4CB5B54C4C",
+"k c #4E4EB4B44E4E",
+"l c #5C5CA9A95C5C",
+"z c #5151B7B75151",
+"x c #5353B7B75353",
+"c c #5454B9B95454",
+"v c #5858B9B95757",
+"b c #5959BCBC5959",
+"n c #5C5CBBBB5C5C",
+"m c #7B7B87877B7B",
+"M c #6161BEBE6060",
+"N c #6565C0C06565",
+"B c #6969C2C26969",
+"V c #6D6DC3C36D6D",
+"C c #7070C5C57171",
+"Z c #7474C7C77474",
+"A c #7777C8C87777",
+"S c #7B7BC3C37B7B",
+"D c #7979CDCD7979",
+"F c #C7C700000000",
+"G c #C9C900000000",
+"H c #CDCD00000000",
+"J c #CFCF00000000",
+"K c #D1D100000000",
+"L c #D5D500000000",
+"P c #D7D700000000",
+"I c #DBDB00000000",
+"U c #DDDD00000000",
+"Y c #DFDF00000000",
+"T c #C5C53F3F3F3F",
+"R c #E5E50B0B0B0B",
+"E c #E5E50F0F0E0E",
+"W c #E7E713131313",
+"Q c #E8E819191919",
+"! c #E9E91E1E1E1E",
+"~ c #F1F100000000",
+"^ c #EBEB23232323",
+"/ c #E8E82C2C2C2C",
+"( c #E8E82F2F2F2F",
+") c #E9E92F2F2F2F",
+"_ c #ECEC29292929",
+"` c #EDED2E2E2E2E",
+"' c #E9E932323232",
+"] c #EAEA35353535",
+"[ c #EEEE34343434",
+"{ c #ECEC39393939",
+"} c #EDED3D3D3D3D",
+"| c #F8F83A3A3A3A",
+" . c #D7D745454545",
+".. c #EDED42424242",
+"X. c #EEEE46464646",
+"o. c #EFEF4B4B4B4B",
+"O. c #E1E15D5D5D5D",
+"+. c #F0F050505050",
+"@. c #F1F154545555",
+"#. c #F9F958585858",
+"$. c #AEAECECEAEAE",
+"%. c #A8A8D6D6A8A8",
+"&. c #AAAAD8D8AAAA",
+"*. c #ADADDADAADAD",
+"=. c #B0B0DBDBAFAF",
+"-. c #B3B3DBDBB3B3",
+";. c #B2B2DDDDB2B2",
+":. c #B4B4DEDEB4B4",
+">. c #B7B7DFDFB7B7",
+",. c #B9B9E1E1B9B9",
+"<. c #BCBCE3E3BCBC",
+"1. c #D9D9A4A4A4A4",
+"2. c #EEEEA2A2A2A2",
+"3. c #EFEFA4A4A4A4",
+"4. c #EFEFA6A6A6A6",
+"5. c #F1F1A9A9A9A9",
+"6. c #F2F2ABABABAB",
+"7. c #F0F0AEAEAEAE",
+"8. c #F3F3AEAEAEAE",
+"9. c #F4F4B0B0B1B1",
+"0. c #F5F5B3B3B3B3",
+"q. c #F8F8B6B6B6B6",
+"w. c #DDDDDFDFDFDF",
+"e. c gray88",
+"r. c #E2E2E0E0E2E2",
+"t. c gray89",
+"y. c gray90",
+"u. c #E7E7E7E7E7E7",
+"i. c gray95",
+"p. c #F3F3F3F3F3F3",
+"a. c #F4F4F4F4F4F4",
+"s. c #F4F4F5F5F5F5",
+"d. c gray96",
+"f. c #F6F6F6F6F6F6",
+"g. c gray97",
+"h. c #F8F8F8F8F8F8",
+"j. c #F9F9F9F9F9F9",
+"k. c gray98",
+"l. c #FBFBFBFBFBFB",
+"z. c gray99",
+"x. c None",
+/* pixels */
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+" y u y t - = * & % $ # @ + O o ",
+" m M %.B V C V V M M n v z k X ",
+" r 6 l b x z j g f s a p i h . ",
+" r 5 6 $.<.,.>.:.;.=.*.%.%.-.d ",
+" w 2 2 e.z.l.k.k.k.g.f.f.f.f.u.",
+" q 1 < w.k.k.k.g.f.f.f.p.p.f.t.",
+" 0 < > w.k.k.h.g.f.f.a.i.i.f.t.",
+" 9 > ; 1.q.0.9.8.6.5.4.3.2.7. .",
+" 8 : T | [ ` _ ^ ! Q W E R ( F ",
+" 7 O.#. at .+.o.X...} { ] ' ( ( F ",
+" I ~ U U I L I L K K K H F F F ",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x."
+};
diff --git a/src/images/flags/KY.xpm b/src/images/flags/KY.xpm
new file mode 100644
index 0000000..d2ff731
--- /dev/null
+++ b/src/images/flags/KY.xpm
@@ -0,0 +1,175 @@
+/* XPM */
+static const char *KY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 153 2",
+" c black",
+". c #000000000303",
+"X c #000000000B0B",
+"o c #000000001111",
+"O c #000000001919",
+"+ c #000000001F1F",
+"@ c #000000002525",
+"# c #000000002727",
+"$ c #000000002D2D",
+"% c #000000002F2F",
+"& c #000000003131",
+"* c #000000003333",
+"= c #000000003939",
+"- c #000000003B3B",
+"; c #000000003F3F",
+": c #000000004949",
+"> c #000009096363",
+", c #00001D1D7575",
+"< c #272733337373",
+"1 c #303043437F7F",
+"2 c #3B3B4E4E7F7F",
+"3 c #575739396565",
+"4 c #77772D2D4F4F",
+"5 c #7F7F2F2F4F4F",
+"6 c #71713D3D6161",
+"7 c #75753D3D6161",
+"8 c #5D5D66666F6F",
+"9 c #606070704949",
+"0 c #636374744D4D",
+"q c #646473735050",
+"w c #6F6F7E7E5D5D",
+"e c #6A6A72727777",
+"r c #23233D3D8282",
+"t c #2A2A41418787",
+"y c #292944448585",
+"u c #2C2C43438585",
+"i c #2D2D44448686",
+"p c #2F2F40408888",
+"a c #2E2E48488989",
+"s c #2F2F49498989",
+"d c #2E2E4B4B8E8E",
+"f c #303042428888",
+"g c #36364E4E8787",
+"h c #353548488B8B",
+"j c #34344D4D8D8D",
+"k c #34344E4E8D8D",
+"l c #37374E4E8C8C",
+"z c #3B3B4E4E8686",
+"x c #39394B4B8F8F",
+"c c #3A3A4E4E8B8B",
+"v c #3B3B4D4D8D8D",
+"b c #3B3B4F4F8D8D",
+"n c #36364C4C9090",
+"m c #3B3B52528989",
+"M c #3D3D54548F8F",
+"N c #3A3A52529090",
+"B c #3C3C52529191",
+"V c #3F3F55559292",
+"C c #3F3F57579393",
+"Z c #3F3F55559494",
+"A c #414154548383",
+"S c #474759598787",
+"D c #4C4C5E5E8B8B",
+"F c #404057579393",
+"G c #404058589393",
+"H c #424259599393",
+"J c #424258589595",
+"K c #44445A5A9595",
+"L c #464659599797",
+"P c #44445C5C9797",
+"I c #45455C5C9797",
+"U c #46465E5E9696",
+"Y c #41415C5C9999",
+"T c #45455B5B9898",
+"R c #48485C5C9595",
+"E c #49495F5F9898",
+"W c #494960609A9A",
+"Q c #494960609B9B",
+"! c #4B4B60609999",
+"~ c #4E4E64649B9B",
+"^ c #4F4F64649D9D",
+"/ c #525261619696",
+"( c #505065659C9C",
+") c #545469699E9E",
+"_ c #53536868A3A3",
+"` c #54546969A0A0",
+"' c #58586D6DA2A2",
+"] c #5D5D7272A4A4",
+"[ c #67676F6F9B9B",
+"{ c #7E7E70709797",
+"} c #7F7F74749B9B",
+"| c #61617575A7A7",
+" . c #61617474A9A9",
+".. c #65657777A8A8",
+"X. c #64647A7AA9A9",
+"o. c #66667A7AAAAA",
+"O. c #6D6D7B7BA0A0",
+"+. c #6D6D7A7AA2A2",
+"@. c #6B6B7C7CACAC",
+"#. c #6A6A7E7EADAD",
+"$. c #6F6F7F7FAEAE",
+"%. c #737381815959",
+"&. c #777784845E5E",
+"*. c #7C7C9292BABA",
+"=. c #7F7F9595BCBC",
+"-. c #B5B571717F7F",
+";. c #CBCB32322E2E",
+":. c #C3C333333939",
+">. c #D1D142423D3D",
+",. c #C0C065656B6B",
+"<. c #C2C269696F6F",
+"1. c #E0E077777B7B",
+"2. c #8D8D7F7FA1A1",
+"3. c #ACAC9C9C6E6E",
+"4. c #B0B099997878",
+"5. c #B2B29D9D7F7F",
+"6. c #B7B7A1A16E6E",
+"7. c #CECE96966D6D",
+"8. c #C0C0A0A06565",
+"9. c #CCCCA3A37373",
+"0. c #CACAACAC7272",
+"q. c #8B8B8E8EB2B2",
+"w. c #9C9C9797B4B4",
+"e. c #9797AAAACBCB",
+"r. c #BFBFCACADADA",
+"t. c #C3C38E8E9E9E",
+"y. c #DEDE86868B8B",
+"u. c #C0C09090A1A1",
+"i. c #D3D39797A0A0",
+"p. c #D7D7BFBF9595",
+"a. c #CBCBACACB5B5",
+"s. c #D8D8A9A9B3B3",
+"d. c #D0D0B4B4BCBC",
+"f. c #D9D9B5B5BEBE",
+"g. c #DADAB5B5BEBE",
+"h. c #E4E480808484",
+"j. c #E8E88A8A8C8C",
+"k. c #E0E08E8E9393",
+"l. c #E0E093939898",
+"z. c #EAEA92929393",
+"x. c #E6E69F9FA4A4",
+"c. c #F1F1B3B3B4B4",
+"v. c #F1F1B6B6B6B6",
+"b. c #DADABFBFCACA",
+"n. c #C1C1CBCBDBDB",
+"m. c #C3C3CDCDDDDD",
+"M. c #C5C5CFCFDEDE",
+"N. c #DFDFC2C2CACA",
+"B. c #E2E2C1C1C8C8",
+"V. c #E4E4C9C9D1D1",
+"C. c #E4E4D3D3DCDC",
+"Z. c #E2E2D9D9E2E2",
+"A. c None",
+/* pixels */
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"-.2., 4 5 > 6 @ ; = & % @ + O o ",
+"< N.Z.g.s.b.C.O. at .o.| O.p.` ^ X ",
+":.x.z.h.1.j.y.D / J T &.%.d E ",
+"7 B.c.k.l.v.i.S U M >.7.9.;.K ",
+"[ V.w.u.t.e.g.A M n s.,.-.a.Z ",
+"3 q._ } { T X.2 v f w q.*.q N ",
+": *.^ W T C m h h i M.M.r.r.l ",
+"= o.W T C N k a r 4.0.0 9 6.t. ",
+"= o.T Z N l a y r i e 6.3.8 m ",
+"& | ] ' ) ( ! W H V v m 2 i i ",
+"% @ @ O o X ",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A."
+};
diff --git a/src/images/flags/KZ.xpm b/src/images/flags/KZ.xpm
new file mode 100644
index 0000000..183dc9f
--- /dev/null
+++ b/src/images/flags/KZ.xpm
@@ -0,0 +1,185 @@
+/* XPM */
+static const char *KZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 163 2",
+" c black",
+". c #00007F7FDDDD",
+"X c #00008181DDDD",
+"o c #00008383DFDF",
+"O c #00008585DFDF",
+"+ c #00008787DDDD",
+"@ c #00008787DFDF",
+"# c #00008585E1E1",
+"$ c #00008787E3E3",
+"% c #00008989E3E3",
+"& c #00008B8BE5E5",
+"* c #00008F8FE7E7",
+"= c #00009595E7E7",
+"- c #00009393E9E9",
+"; c #00009797E9E9",
+": c #00009797EBEB",
+"> c #00009D9DEBEB",
+", c #00009D9DEDED",
+"< c #0000A1A1EFEF",
+"1 c #0000A3A3EDED",
+"2 c #0000A7A7EFEF",
+"3 c #0000ABABF1F1",
+"4 c #0000AFAFF3F3",
+"5 c #0000ADADF5F5",
+"6 c #0000B1B1F7F7",
+"7 c #0000B3B3F9F9",
+"8 c #0000B5B5F9F9",
+"9 c #0000B5B5FBFB",
+"0 c #0000B9B9FDFD",
+"q c #0000BBBBFDFD",
+"w c #0000BDBDFDFD",
+"e c #0000BFBFFDFD",
+"r c #0303BFBFFFFF",
+"t c #0909C3C3FFFF",
+"y c #0F0FC3C3FDFD",
+"u c #1313C3C3FFFF",
+"i c #3838C2C2F1F1",
+"p c #3B3BC6C6F2F2",
+"a c #3C3CC4C4F1F1",
+"s c #3D3DC4C4F2F2",
+"d c #7878C7C7B2B2",
+"f c #4141C6C6F2F2",
+"g c #4545C8C8F3F3",
+"h c #4646C8C8F3F3",
+"j c #4A4ACACAF4F4",
+"k c #4B4BCACAF4F4",
+"l c #4F4FCCCCF5F5",
+"z c #5E5ECECEE7E7",
+"x c #5353CACAF2F2",
+"c c #5050CDCDF5F5",
+"v c #5555CACAF2F2",
+"b c #5656CBCBF2F2",
+"n c #5454CECEF6F6",
+"m c #5555CECEF6F6",
+"M c #5555CFCFF7F7",
+"N c #5858CCCCF3F3",
+"B c #5959CCCCF3F3",
+"V c #5B5BCDCDF3F3",
+"C c #5C5CCDCDF4F4",
+"Z c #5E5ECFCFF4F4",
+"A c #5353D0D0F7F7",
+"S c #5959D0D0F7F7",
+"D c #5B5BD1D1F8F8",
+"F c #5C5CD2D2F8F8",
+"G c #5F5FD3D3F9F9",
+"H c #7272CBCBC9C9",
+"J c #7C7CD1D1D0D0",
+"K c #7E7ED3D3D4D4",
+"L c #6161CDCDE1E1",
+"P c #6060CFCFF5F5",
+"I c #6F6FD0D0E5E5",
+"U c #6464D2D2F5F5",
+"Y c #6262D5D5F9F9",
+"T c #6464D4D4FAFA",
+"R c #6464D6D6FAFA",
+"E c #6868D3D3F6F6",
+"W c #6868D3D3F7F7",
+"Q c #6868D4D4F1F1",
+"! c #6C6CD5D5F7F7",
+"~ c #6969D6D6FBFB",
+"^ c #6B6BD8D8FBFB",
+"/ c #6D6DDADAFCFC",
+"( c #6F6FDADAFCFC",
+") c #7171D2D2E7E7",
+"_ c #7575D6D6ECEC",
+"` c #7F7FD6D6E0E0",
+"' c #7C7CD7D7E4E4",
+"] c #7070D7D7F7F7",
+"[ c #7171D7D7F8F8",
+"{ c #7171D8D8F7F7",
+"} c #7575D8D8F3F3",
+"| c #7373DADAFBFB",
+" . c #7272DADAFCFC",
+".. c #7373DBDBFDFD",
+"X. c #7575D8D8F8F8",
+"o. c #7575D8D8F9F9",
+"O. c #7474DADAF8F8",
+"+. c #7575DBDBFDFD",
+"@. c #7676DBDBFDFD",
+"#. c #7575DCDCFEFE",
+"$. c #7979D9D9F9F9",
+"%. c #7979DADAF9F9",
+"&. c #7979DCDCFEFE",
+"*. c #7A7ADCDCFEFE",
+"=. c #7A7ADFDFFEFE",
+"-. c #7C7CDBDBFAFA",
+";. c #7F7FDDDDFBFB",
+":. c #7C7CDEDEFEFE",
+">. c #8787A9A90303",
+",. c #A2A2C8C87F7F",
+"<. c #B5B5CACA6D6D",
+"1. c #B2B2CACA7171",
+"2. c #DFDFBFBF0000",
+"3. c #DFDFCACA3838",
+"4. c #F8F8D1D13636",
+"5. c #F8F8D3D33636",
+"6. c #F9F9D5D53C3C",
+"7. c #D3D3CECE5656",
+"8. c #D2D2D1D15F5F",
+"9. c #C5C5D0D06D6D",
+"0. c #D0D0D4D46E6E",
+"q. c #E7E7CFCF4646",
+"w. c #EAEAD3D35252",
+"e. c #ECECD6D65353",
+"r. c #FAFAD5D54343",
+"t. c #EBEBDDDD7575",
+"y. c #EDEDDEDE7A7A",
+"u. c #8B8BCBCBACAC",
+"i. c #8282CDCDBBBB",
+"p. c #9797CFCFA9A9",
+"a. c #9F9FD2D2A7A7",
+"s. c #A2A2CCCC8D8D",
+"d. c #AAAACCCC8181",
+"f. c #A8A8CDCD8B8B",
+"g. c #AFAFD1D19191",
+"h. c #BCBCD3D38888",
+"j. c #BEBED7D79494",
+"k. c #A3A3D5D5AEAE",
+"l. c #ABABD5D5A5A5",
+"z. c #8D8DD5D5C9C9",
+"x. c #8E8ED8D8D5D5",
+"c. c #8383D8D8E1E1",
+"v. c #8787DDDDF7F7",
+"b. c #8E8EDFDFF4F4",
+"n. c #8A8AE0E0FCFC",
+"m. c #8C8CE2E2FEFE",
+"M. c #8F8FE2E2FEFE",
+"N. c #9191E3E3FEFE",
+"B. c #9494E4E4FEFE",
+"V. c #C2C2D7D78F8F",
+"C. c #C6C6D8D88A8A",
+"Z. c #CACADBDB9191",
+"A. c #CCCCDBDB9696",
+"S. c #CECEDEDE9797",
+"D. c #D3D3E0E09F9F",
+"F. c #D4D4E1E1A2A2",
+"G. c #D8D8E4E4A9A9",
+"H. c #D8D8E4E4AAAA",
+"J. c #D8D8E4E4ABAB",
+"K. c #EFEFE2E28484",
+"L. c #F0F0E3E38787",
+"P. c #F2F2E4E48D8D",
+"I. c None",
+/* pixels */
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"r 2.t u t t 0 0 9 7 6 5 4 3 2 < ",
+"r P.H.B.N.M.m.n.b.v.:.-.$.O.] > ",
+"r H.=.:. at .#. .x.V.l.Q G S m ! ; ",
+"r H.S. at .#.O.o.V.r.w.a.c m c E = ",
+"r K.#.#.O.} ' e.6.5.8.z l k U * ",
+"r K.Z.( c.c.k.h.5.q.f.u.h h P % ",
+"0 F.( ^ _ z.0.J p.i.H 1.h s C $ ",
+"9 D.C.~ Y K g.9.7.s.3.d.f s B O ",
+"9 y.Y T G D M L d.1.d p s i b o ",
+"6 t.A.$.O.] ! W ) ) Z B B b x . ",
+"5 >.3 2 < , ; - * % % $ O + . o ",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I."
+};
diff --git a/src/images/flags/LA.xpm b/src/images/flags/LA.xpm
new file mode 100644
index 0000000..5327a46
--- /dev/null
+++ b/src/images/flags/LA.xpm
@@ -0,0 +1,174 @@
+/* XPM */
+static const char *LA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 152 2",
+" c black",
+". c #232300000000",
+"X c #4D4D00003F3F",
+"o c #6D6D03034F4F",
+"O c #7D7D32326F6F",
+"+ c #000000008181",
+"@ c #000000008383",
+"# c #000000008787",
+"$ c #000000008B8B",
+"% c #000000009191",
+"& c #00001111B5B5",
+"* c #00001717B9B9",
+"= c #00001B1BBBBB",
+"- c #00002121BDBD",
+"; c #00002525BFBF",
+": c #2A2A5555C3C3",
+"> c #2D2D5959C5C5",
+", c #2F2F5959C5C5",
+"< c #33335D5DC7C7",
+"1 c #35355D5DC6C6",
+"2 c #31315C5CC8C8",
+"3 c #33335D5DC8C8",
+"4 c #35355F5FC8C8",
+"5 c #39395F5FC8C8",
+"6 c #39396262CACA",
+"7 c #3A3A6161C8C8",
+"8 c #3E3E6666CCCC",
+"9 c #3F3F6868CDCD",
+"0 c #40406666C9C9",
+"q c #45456A6ACBCB",
+"w c #49496F6FCBCB",
+"e c #48486C6CCCCC",
+"r c #4A4A6E6ECECE",
+"t c #4B4B6E6ECECE",
+"y c #4C4C7070CDCD",
+"u c #4B4B7272D1D1",
+"i c #50507575CECE",
+"p c #50507474D0D0",
+"a c #54547878D1D1",
+"s c #56567979D5D5",
+"d c #5B5B7A7AD0D0",
+"f c #58587B7BD5D5",
+"g c #5A5A7D7DD6D6",
+"h c #5C5C7E7ED3D3",
+"j c #5C5C7D7DD5D5",
+"k c #5D5D7D7DD5D5",
+"l c #5E5E8080D7D7",
+"z c #5F5F8181D7D7",
+"x c #63638282D7D7",
+"c c #67678484D3D3",
+"v c #65658585D7D7",
+"b c #62628484D8D8",
+"n c #63638585D9D9",
+"m c #64648484D8D8",
+"M c #65658484D8D8",
+"N c #69698787D9D9",
+"B c #6D6D8888D6D6",
+"V c #68688888DBDB",
+"C c #6A6A8888DADA",
+"Z c #6B6B8B8BDCDC",
+"A c #6D6D8B8BDADA",
+"S c #71718D8DDBDB",
+"D c #74749090DADA",
+"F c #76769191DBDB",
+"G c #7B7B9898DFDF",
+"H c #7F7F9B9BE0E0",
+"J c #808036367171",
+"K c #838339397575",
+"L c #84843E3E7B7B",
+"P c #86863D3D7878",
+"I c #878743437D7D",
+"U c #95954D4D7E7E",
+"Y c #D9D900000000",
+"T c #DBDB00000000",
+"R c #DFDF00000000",
+"E c #E1E100000000",
+"W c #E3E300000000",
+"Q c #E5E500000000",
+"! c #E7E700000000",
+"~ c #EBEB00000000",
+"^ c #EDED00000000",
+"/ c #EFEF00000000",
+"( c #F1F100000000",
+") c #F3F300000000",
+"_ c #F5F500000000",
+"` c #F7F700000000",
+"' c #F9F900000000",
+"] c #FBFB00000000",
+"[ c #FDFD00000000",
+"{ c #F0F02C2C2C2C",
+"} c #F0F02F2F2F2F",
+"| c #F2F232323232",
+" . c #F2F235353535",
+".. c #F2F239393939",
+"X. c #F3F33D3D3D3D",
+"o. c #F4F442424242",
+"O. c #F5F546464646",
+"+. c #F7F74B4B4B4B",
+"@. c #F7F74E4E4E4E",
+"#. c #F7F750505050",
+"$. c #F7F753535353",
+"%. c #F8F854545555",
+"&. c #F8F857575757",
+"*. c #F9F958585858",
+"=. c #F9F95C5C5C5C",
+"-. c #FAFA5D5D5D5D",
+";. c #FAFA60606060",
+":. c #FAFA61616262",
+">. c #FBFB65656565",
+",. c #FCFC69696969",
+"<. c #FCFC6D6D6D6D",
+"1. c #FCFC70707171",
+"2. c #FCFC74747474",
+"3. c #FDFD77777777",
+"4. c #FDFD79797979",
+"5. c #FEFE7B7B7B7B",
+"6. c #8B8B48488080",
+"7. c #8F8F4D4D8484",
+"8. c #909050508484",
+"9. c #959555558989",
+"0. c #999952528282",
+"q. c #9C9C56568686",
+"w. c #99995A5A8D8D",
+"e. c #9F9F5A5A8A8A",
+"r. c #9F9F5D5D8C8C",
+"t. c #9C9C5E5E9090",
+"y. c #9F9F63639393",
+"u. c #A0A060609090",
+"i. c #A3A364649393",
+"p. c #A4A465659090",
+"a. c #A7A769699696",
+"s. c #ADAD70709999",
+"d. c #AFAF73739C9C",
+"f. c #B1B176769E9E",
+"g. c #B2B27979A0A0",
+"h. c #B1B17F7FA8A8",
+"j. c #82829E9EE2E2",
+"k. c #85859F9FE2E2",
+"l. c #8A8AA2A2E2E2",
+"z. c #C0C09090B1B1",
+"x. c #C9C9D3D3EDED",
+"c. c #CECED6D6EFEF",
+"v. c #CFCFD7D7F0F0",
+"b. c #E3E3E8E8F2F2",
+"n. c #E6E6E9E9F4F4",
+"m. c #ECECEFEFF6F6",
+"M. c #EDEDF0F0F7F7",
+"N. c gray97",
+"B. c #F8F8F8F8F8F8",
+"V. c #F9F9F9F9F9F9",
+"C. c gray98",
+"Z. c None",
+/* pixels */
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"[ [ [ [ [ ' ' ' ' ` ` ( ( ( ^ ^ ",
+"[ 5.5.5.3.2.2.<.,.>.;.=.&.$. at .^ ",
+"o z.g.f.d.s.a.i.u.r.e.q.0.U p.. ",
+"; l.S A N x F c.c.B r r q 0 d % ",
+"- k.Z V x m M.C.C.n.p 9 8 6 a $ ",
+"= j.V m h S C.C.C.N.c 1 6 1 i # ",
+"= H m l f j m.C.N.b.r 4 1 , t @ ",
+"& G l j s y v x.x.h , 3 , : w @ ",
+"X h.i.t.w.9.7.6.I L P K O O 8. ",
+"` ;.=.*.&. at .+.O.o.X... . .} { T ",
+"( ( ( ( ^ ~ Q Q Q E E T T T T T ",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z."
+};
diff --git a/src/images/flags/LB.xpm b/src/images/flags/LB.xpm
new file mode 100644
index 0000000..9cd3b89
--- /dev/null
+++ b/src/images/flags/LB.xpm
@@ -0,0 +1,161 @@
+/* XPM */
+static const char *LB_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 139 2",
+" c black",
+". c #3B3B92923B3B",
+"X c #3E3E93933E3E",
+"o c #3E3E94943E3E",
+"O c #434396964343",
+"+ c #434396964444",
+"@ c #444497974545",
+"# c #454599994545",
+"$ c #494999994949",
+"% c #49499B9B4A4A",
+"& c #52529D9D5353",
+"* c #5757A2A25757",
+"= c #5757A3A35757",
+"- c #5A5AA4A45A5A",
+"; c #6262A8A86262",
+": c #7D7DB3B37B7B",
+"> c #ADAD00000000",
+", c #B1B100000000",
+"< c #B5B500000000",
+"1 c #B7B700000000",
+"2 c #BBBB00000000",
+"3 c #BDBD00000000",
+"4 c #BFBF00000000",
+"5 c #C1C100000000",
+"6 c #C3C300000000",
+"7 c #C5C500000000",
+"8 c #C9C900000000",
+"9 c #CBCB00000000",
+"0 c #CFCF00000000",
+"q c #D1D100000000",
+"w c #D3D300000000",
+"e c #D5D500000000",
+"r c #D7D700000000",
+"t c #D9D900000000",
+"y c #DBDB00000000",
+"u c #DDDD00000000",
+"i c #DFDF00000000",
+"p c #E1E12A2A1414",
+"a c #E2E22D2D1818",
+"s c #E3E331311D1D",
+"d c #E4E436362121",
+"f c #E5E53A3A2525",
+"g c #E4E43E3E2929",
+"h c #E4E43E3E2C2C",
+"j c #E5E540402F2F",
+"k c #E6E644443232",
+"l c #E7E747473535",
+"z c #E5E549493636",
+"x c #E8E844443030",
+"c c #E9E945453333",
+"v c #E9E948483535",
+"b c #E8E84B4B3939",
+"n c #EAEA4B4B3838",
+"m c #E8E84E4E3D3D",
+"M c #EBEB4E4E3C3C",
+"N c #EBEB4F4F3E3E",
+"B c #EAEA52524242",
+"V c #EBEB57574646",
+"C c #ECEC53534141",
+"Z c #EDED54544343",
+"A c #EEEE58584646",
+"S c #EBEB5F5F4F4F",
+"D c #ECEC5B5B4B4B",
+"F c #EEEE5A5A4848",
+"G c #EDED5F5F4E4E",
+"H c #EFEF5C5C4C4C",
+"J c #EFEF5E5E4D4D",
+"K c #EDED60605050",
+"L c #EDED63635353",
+"P c #EEEE64645555",
+"I c #EEEE67675757",
+"U c #EFEF68685858",
+"Y c #F0F062625151",
+"T c #F1F166665656",
+"R c #F2F26A6A5A5A",
+"E c #F0F06B6B5C5C",
+"W c #F0F06C6C5D5D",
+"Q c #F3F36D6D5E5E",
+"! c #F1F16F6F6060",
+"~ c #F1F170706262",
+"^ c #F2F273736565",
+"/ c #F4F471716161",
+"( c #F4F473736565",
+") c #F2F277776969",
+"_ c #F2F27A7A6C6C",
+"` c #F3F37A7A6D6D",
+"' c #F4F47E7E7171",
+"] c #F5F581817474",
+"[ c #F6F684847777",
+"{ c #F6F686867979",
+"} c #F7F788887B7B",
+"| c #F7F78C8C7F7F",
+" . c #8585BABA8484",
+".. c #BBBBBBBBBBBB",
+"X. c gray75",
+"o. c #9696C6C69797",
+"O. c #A3A3CACAA4A4",
+"+. c #A0A0CDCDA2A2",
+"@. c #C1C1C1C1C1C1",
+"#. c #C5C5C3C3C3C3",
+"$. c #CBCBDFDFCBCB",
+"%. c #DFDFDFDFDFDF",
+"&. c #CECEE4E4CFCF",
+"*. c #D8D8E8E8DADA",
+"=. c #D8D8E9E9DADA",
+"-. c #DEDEEAEADEDE",
+";. c #E1E1E1E1E1E1",
+":. c gray89",
+">. c #E5E5E3E3E3E3",
+",. c gray90",
+"<. c #E7E7F0F0E6E6",
+"1. c #EEEEF2F2EFEF",
+"2. c gray95",
+"3. c #F3F3F3F3F3F3",
+"4. c #F3F3F6F6F3F3",
+"5. c #F1F1F4F4F4F4",
+"6. c #F3F3F7F7F6F6",
+"7. c #F4F4F4F4F4F4",
+"8. c #F4F4F5F5F5F5",
+"9. c #F5F5F4F4F4F4",
+"0. c gray96",
+"q. c #F6F6F5F5F4F4",
+"w. c #F6F6F5F5F5F5",
+"e. c #F6F6F6F6F6F6",
+"r. c #F7F7F6F6F6F6",
+"t. c #F8F8F8F8F8F8",
+"y. c gray98",
+"u. c #FAFAFBFBFBFB",
+"i. c #FBFBFBFBFBFB",
+"p. c #FBFBFCFCFBFB",
+"a. c #FDFDFBFBFBFB",
+"s. c #FDFDFBFBFCFC",
+"d. c gray99",
+"f. c #FDFDFCFCFDFD",
+"g. c #FDFDFDFDFDFD",
+"h. c #FEFEFCFCFCFC",
+"j. c #FEFEFDFDFDFD",
+"k. c #FEFEFEFEFEFE",
+"l. c None",
+/* pixels */
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"i i i i t i i t t e w w w 8 8 7 ",
+"i } } { [ ] ' ` ) ( ! E I K K 5 ",
+"i | ( Q Q R T K J A Z N n k K 5 ",
+">.k.k.a.k.a.<. .: -.t.r.8.8.8.#.",
+",.k.k.k.k.a.+.* % o.8.r.8.8.8. at .",
+";.k.k.k.k.&.- # @ % $.8.8.3.8.X.",
+";.k.i.i.t.; = @ o O & 5.2.2.8...",
+"%.a.a.i.a.4.*.o . O.*.1.2.2.3...",
+"e ) H A C m v k g f d s a p z > ",
+"w ~ U U I K D V B m n v k h h > ",
+"w 0 8 8 7 5 5 3 2 < < , , > > > ",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l."
+};
diff --git a/src/images/flags/LC.xpm b/src/images/flags/LC.xpm
new file mode 100644
index 0000000..8c13909
--- /dev/null
+++ b/src/images/flags/LC.xpm
@@ -0,0 +1,176 @@
+/* XPM */
+static const char *LC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 154 2",
+" c black",
+". c gray21",
+"X c gray23",
+"o c #3F3F3B3B3C3C",
+"O c #4A4A41414141",
+"+ c #2A2A5D5DDDDD",
+"@ c #2A2A5E5EDDDD",
+"# c #2A2A5F5FDCDC",
+"$ c #2A2A5F5FDDDD",
+"% c #2A2A5E5EDEDE",
+"& c #2A2A5F5FDEDE",
+"* c #2A2A5F5FE0E0",
+"= c #2A2A5F5FE1E1",
+"- c #2A2A5F5FE2E2",
+"; c #2A2A6060DBDB",
+": c #2A2A6161E2E2",
+"> c #2A2A6262E2E2",
+", c #2A2A6262E3E3",
+"< c #2A2A6262E4E4",
+"1 c #2A2A6262EDED",
+"2 c #2A2A6363F2F2",
+"3 c #2C2C6464F2F2",
+"4 c #31316868F3F3",
+"5 c #33336969F5F5",
+"6 c #34346868F1F1",
+"7 c #35356A6AF4F4",
+"8 c #38386B6BF5F5",
+"9 c #38386B6BF7F7",
+"0 c #3F3F6F6FF7F7",
+"q c #3B3B6F6FF9F9",
+"w c #555554548B8B",
+"e c #6C6C6B6B9F9F",
+"r c #43437474F7F7",
+"t c #46467474F5F5",
+"y c #41417272FAFA",
+"u c #48487676F8F8",
+"i c #4B4B7A7AF9F9",
+"p c #4D4D7C7CF9F9",
+"a c #4F4F7C7CF9F9",
+"s c #4F4F7D7DFAFA",
+"d c #56567F7FECEC",
+"f c #51517E7EFAFA",
+"g c #45458080EEEE",
+"h c #53538484EEEE",
+"j c #59598282EDED",
+"k c #59598383ECEC",
+"l c #5E5E8787EDED",
+"z c #5F5F8888EFEF",
+"x c #52528080F9F9",
+"c c #54548181FAFA",
+"v c #55558181FAFA",
+"b c #5F5F8A8AF9F9",
+"n c #60608989EEEE",
+"m c #63638E8EEFEF",
+"M c #65658F8FEFEF",
+"N c #61618B8BF2F2",
+"B c #66668D8DF0F0",
+"V c #6B6B9494EDED",
+"C c #6C6C9292ECEC",
+"Z c #6E6E9393ECEC",
+"A c #6E6E9595ECEC",
+"S c #69699999EEEE",
+"D c #61619797F4F4",
+"F c #68689191F0F0",
+"G c #6B6B9494F0F0",
+"H c #6F6F9393F1F1",
+"J c #6D6D9595F1F1",
+"K c #6E6E9595F0F0",
+"L c #6F6F9696F0F0",
+"P c #6C6C9E9EF4F4",
+"I c #70709797EDED",
+"U c #73739999EEEE",
+"Y c #77779D9DEFEF",
+"T c #71719999F1F1",
+"R c #71719E9EF3F3",
+"E c #74749D9DF1F1",
+"W c #75759C9CF5F5",
+"Q c #7A7A9C9CF4F4",
+"! c #6868AAAAF2F2",
+"~ c #7B7BA2A2EFEF",
+"^ c #7878A9A9EFEF",
+"/ c #7676A7A7F7F7",
+"( c #7979A1A1F3F3",
+") c #7C7CA2A2F4F4",
+"_ c #7E7EA4A4F0F0",
+"` c #7D7DBABAF6F6",
+"' c #8F8F6B6B2424",
+"] c #949474743737",
+"[ c #88887F7F7D7D",
+"{ c #CACA9F9F3535",
+"} c #D0D0A2A22F2F",
+"| c #F4F4C7C71E1E",
+" . c #F7F7CCCC2E2E",
+".. c #F5F5D1D12323",
+"X. c #F6F6D4D42929",
+"o. c #F5F5D2D23D3D",
+"O. c #F4F4D9D93939",
+"+. c #F6F6EDED2A2A",
+"@. c #F7F7EDED2F2F",
+"#. c #F6F6D1D14242",
+"$. c #F7F7D3D34646",
+"%. c #F7F7D8D84B4B",
+"&. c #F8F8E2E25050",
+"*. c #94948C8C8A8A",
+"=. c #8080A7A7F3F3",
+"-. c #8080A5A5F4F4",
+";. c #8181A5A5F7F7",
+":. c #8181A6A6F5F5",
+">. c #8181A9A9F1F1",
+",. c #8282A9A9F4F4",
+"<. c #8383AAAAF4F4",
+"1. c #8181AFAFF3F3",
+"2. c #8686AEAEF1F1",
+"3. c #8888AEAEF5F5",
+"4. c #8989AEAEF5F5",
+"5. c #8989AEAEF6F6",
+"6. c #8A8AAFAFF6F6",
+"7. c #8787B9B9F3F3",
+"8. c #8888B0B0F3F3",
+"9. c #8989B0B0F2F2",
+"0. c #8B8BB0B0F6F6",
+"q. c #8C8CB2B2F2F2",
+"w. c #8C8CB0B0F6F6",
+"e. c #8D8DB1B1F7F7",
+"r. c #8E8EB1B1F7F7",
+"t. c #8F8FB5B5F3F3",
+"y. c #9191B5B5F3F3",
+"u. c #9090B5B5F7F7",
+"i. c #9191B4B4F7F7",
+"p. c #9393B9B9F4F4",
+"a. c #9292B9B9F7F7",
+"s. c #9797BBBBF5F5",
+"d. c #ADADBEBEE1E1",
+"f. c #9A9AC0C0F6F6",
+"g. c #9D9DC2C2F7F7",
+"h. c #9F9FC3C3F7F7",
+"j. c #8B8BE6E6F3F3",
+"k. c #9797EDEDF7F7",
+"l. c #9D9DEDEDF8F8",
+"z. c #9F9FEDEDF9F9",
+"x. c #A0A0C3C3F7F7",
+"c. c #A2A2C6C6F8F8",
+"v. c #A3A3C7C7F8F8",
+"b. c #A5A5C7C7F9F9",
+"n. c #B2B2C3C3EDED",
+"m. c #B0B0C5C5EFEF",
+"M. c #B4B4CBCBF4F4",
+"N. c #BBBBE1E1F8F8",
+"B. c #BBBBE2E2F9F9",
+"V. c #CBCBDCDCE9E9",
+"C. c #D1D1DCDCE8E8",
+"Z. c #C0C0F2F2F6F6",
+"A. c #C5C5F5F5F9F9",
+"S. c None",
+/* pixels */
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"b f c c f a s y q r 0 8 7 4 2 6 ",
+"s b.b.c.c.c.i.B.N.5.a.t.q.9.2.< ",
+"c b.a.u.e.6./ V.C.P ( E T L >., ",
+"c b.t.e.e.;.z.*.[ k.H T L G _ , ",
+"x c.e.6.5.W A.O o Z.z L F M ~ = ",
+"s g.5.5.:.` M.X . m.! B m n Y = ",
+"i g.5.<.Q l.e { } w j.z n l U = ",
+"u s.>.:.R 7.] @.+.' ^ h l j I @ ",
+"t s.=.) D n. .X...| d.g j d A @ ",
+"9 a.y.9.1.&.%.$.#.o.O.S V A C @ ",
+"t 5 4 3 1 , < , = , @ @ @ $ @ # ",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S."
+};
diff --git a/src/images/flags/LI.xpm b/src/images/flags/LI.xpm
new file mode 100644
index 0000000..33c3be7
--- /dev/null
+++ b/src/images/flags/LI.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *LI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000000000B0B",
+"X c #000000006F6F",
+"o c #000000007171",
+"O c #000000007575",
+"+ c #000000007979",
+"@ c #000000007F7F",
+"# c #29290B0B6161",
+"$ c #000000008383",
+"% c #000000008787",
+"& c #000000008B8B",
+"* c #000000009191",
+"= c #000000009595",
+"- c #000000009999",
+"; c #000003039B9B",
+": c #000009099D9D",
+"> c #00000F0FA1A1",
+", c #00001515A5A5",
+"< c #00001919A7A7",
+"1 c #00001B1BA7A7",
+"2 c #00001D1DA7A7",
+"3 c #00001919A9A9",
+"4 c #00001D1DA9A9",
+"5 c #27275A5ABBBB",
+"6 c #2C2C5E5EBDBD",
+"7 c #30305E5EBBBB",
+"8 c #35356262BDBD",
+"9 c #36366262BDBD",
+"0 c #3A3A6666BFBF",
+"q c #32326363C0C0",
+"w c #37376666C2C2",
+"e c #3B3B6767C0C0",
+"r c #3F3F6B6BC2C2",
+"t c #3D3D6A6AC4C4",
+"y c #61614A4A8686",
+"u c #65654E4E8989",
+"i c #696952528C8C",
+"p c #6C6C57579090",
+"a c #70705B5B9393",
+"s c #757560609696",
+"d c #777764649797",
+"f c #797965659999",
+"g c #7D7D69699B9B",
+"h c #40406B6BC2C2",
+"j c #41416F6FC6C6",
+"k c #45456F6FC4C4",
+"l c #46467171C4C4",
+"z c #46467373C8C8",
+"x c #4A4A7272C6C6",
+"c c #4A4A7373C7C7",
+"v c #4D4D7474C4C4",
+"b c #4C4C7777CBCB",
+"n c #4F4F7676C9C9",
+"m c #51517878C6C6",
+"M c #51517B7BCBCB",
+"N c #54547B7BCBCB",
+"B c #57577C7CC8C8",
+"V c #58587E7EC6C6",
+"C c #5B5B7F7FCACA",
+"Z c #5C5C8181C8C8",
+"A c #5D5D8484CFCF",
+"S c #60608383CCCC",
+"D c #64648787CECE",
+"F c #68688A8AD0D0",
+"G c #6C6C8E8ED2D2",
+"H c #70709090D3D3",
+"J c #74749494D4D4",
+"K c #7A7A9B9BDADA",
+"L c #7F7F9D9DD9D9",
+"P c #B9B900000000",
+"I c #BBBB00000000",
+"U c #BDBD00000000",
+"Y c #BFBF00000000",
+"T c #C1C100000000",
+"R c #C3C300000000",
+"E c #C5C500000000",
+"W c #C9C900000000",
+"Q c #CBCB00000000",
+"! c #CFCF00000000",
+"~ c #D1D100000000",
+"^ c #D5D500000000",
+"/ c #D7D700000000",
+"( c #DBDB00000000",
+") c #DDDD00000000",
+"_ c #DFDF00000000",
+"` c #DEDE26260B0B",
+"' c #E9E900000000",
+"] c #E0E029290E0E",
+"[ c #E0E02A2A1010",
+"{ c #E1E12D2D1313",
+"} c #E1E12E2E1414",
+"| c #EAEA2E2E1414",
+" . c #E2E232321919",
+".. c #E2E233331919",
+"X. c #E3E337371E1E",
+"o. c #E3E337371F1F",
+"O. c #ECEC32321919",
+"+. c #EDED37371F1F",
+"@. c #E4E43C3C2323",
+"#. c #E4E43D3D2424",
+"$. c #EEEE3C3C2424",
+"%. c #E2E243432C2C",
+"&. c #E2E246462F2F",
+"*. c #E6E641412929",
+"=. c #E6E642422A2A",
+"-. c #E7E746462E2E",
+";. c #E7E747472F2F",
+":. c #EFEF41412A2A",
+">. c #E3E349493232",
+",. c #E5E54B4B3535",
+"<. c #E6E64F4F3939",
+"1. c #E9E94B4B3434",
+"2. c #E9E94C4C3434",
+"3. c #EDED4C4C3636",
+"4. c #E6E653533D3D",
+"5. c #EAEA50503A3A",
+"6. c #EBEB55553F3F",
+"7. c #ECEC56563F3F",
+"8. c #F0F046462F2F",
+"9. c #F1F14B4B3535",
+"0. c #F2F250503A3A",
+"q. c #E8E857574242",
+"w. c #E8E85B5B4646",
+"e. c #EDED5A5A4444",
+"r. c #EDED5A5A4545",
+"t. c #EEEE5F5F4949",
+"y. c #F3F355554040",
+"u. c #F4F45A5A4545",
+"i. c #F5F55F5F4949",
+"p. c #EAEA60604B4B",
+"a. c #EBEB63635050",
+"s. c #EDED68685555",
+"d. c #EDED6C6C5858",
+"f. c #EEEE70705D5D",
+"g. c #F6F662624F4F",
+"h. c #F0F074746262",
+"j. c #F1F178786666",
+"k. c #F2F27C7C6A6A",
+"l. c #F6F67F7F6F6F",
+"z. c #80806D6D9F9F",
+"x. c #83837171A4A4",
+"c. c #86867575A7A7",
+"v. c #8A8A7979A8A8",
+"b. c #F5F5DBDB5D5D",
+"n. c #FBFBDFDF5F5F",
+"m. c #E0E0CFCF6E6E",
+"M. c #E9E9D6D67575",
+"N. c #F4F4DCDC6767",
+"B. c #F0F0DADA6D6D",
+"V. c #F9F9DEDE6161",
+"C. c #FBFBE0E06363",
+"Z. c #8F8F9E9EA1A1",
+"A. c #9F9F9191B7B7",
+"S. c #A1A1ABABA2A2",
+"D. c #81819E9ED9D9",
+"F. c #81819E9EDADA",
+"G. c #9494A8A8C2C2",
+"H. c #9F9FB0B0C4C4",
+"J. c #BEBEC1C1A7A7",
+"K. c #C2C2C3C3AAAA",
+"L. c #F2F2E0E08686",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"2 1 2 4 3 , > : ; - = * & % $ $ ",
+"1 F.H.K.L.J.G.J G G F D S Z B + ",
+"1 F.M.B.N.n.m.N n c l r 0 9 M O ",
+"1 L S.C.n.b.Z.n c k t 0 9 7 v X ",
+"3 K A C V M b l j t w 8 6 5 l X ",
+"# A.v.c.x.z.g f s a p i u y f . ",
+"' l.g.i.u.y.0.3.8.8.$.+.O.| 3.~ ",
+"_ k.t.e.7.5.2.-.#.#.X. . .` >.U ",
+"_ j.e.7.5.1.-.*.#.X. .{ ] ` &.U ",
+") h.d.d.s.a.p.w.q.4.<.,.>.&.%.I ",
+") / / ~ ! ! Q Q E R R U U I P I ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/LK.xpm b/src/images/flags/LK.xpm
new file mode 100644
index 0000000..8278186
--- /dev/null
+++ b/src/images/flags/LK.xpm
@@ -0,0 +1,183 @@
+/* XPM */
+static const char *LK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 161 2",
+" c black",
+". c #44448C8C4444",
+"X c #4E4E90904646",
+"o c #4A4A90904949",
+"O c #4F4F94944F4F",
+"+ c #525293934C4C",
+"@ c #515194945151",
+"# c #545496965353",
+"$ c #555597975555",
+"% c #58589A9A5858",
+"& c #5A5A99995A5A",
+"* c #5D5D9C9C5C5C",
+"= c #5E5E9D9D5F5F",
+"- c #5F5F9D9D5F5F",
+"; c #63639F9F6363",
+": c #6666A2A26666",
+"> c #6868A2A26767",
+", c #6F6FA7A76868",
+"< c #7070A7A76868",
+"1 c #9B9B2D2D3F3F",
+"2 c #9C9C31313A3A",
+"3 c #9D9D32323838",
+"4 c #A0A038383D3D",
+"5 c #98982B2B4040",
+"6 c #98982B2B4141",
+"7 c #9A9A2F2F4444",
+"8 c #9A9A30304545",
+"9 c #9F9F34344343",
+"0 c #9C9C32324848",
+"q c #9C9C31314F4F",
+"w c #9D9D35354949",
+"e c #9F9F37374C4C",
+"r c #A0A038384747",
+"t c #A0A03A3A4E4E",
+"y c #A1A13C3C5050",
+"u c #A3A33F3F5353",
+"i c #A1A13B3B5A5A",
+"p c #A3A340403B3B",
+"a c #A3A341413C3C",
+"s c #B2B25A5A2B2B",
+"d c #B8B866662F2F",
+"f c #BBBB67673535",
+"g c #BFBF6D6D3A3A",
+"h c #ADAD4E4E4F4F",
+"j c #A5A541415F5F",
+"k c #A8A846465959",
+"l c #A9A948485B5B",
+"z c #AEAE50504A4A",
+"x c #AFAF52525D5D",
+"c c #B0B057575353",
+"v c #B1B15B5B5555",
+"b c #B2B259595454",
+"n c #A9A94A4A6262",
+"m c #ACAC4E4E6060",
+"M c #ACAC4E4E6464",
+"N c #AAAA4B4B6868",
+"B c #ACAC4D4D6E6E",
+"V c #AFAF53536565",
+"C c #ADAD50506868",
+"Z c #B0B057576969",
+"A c #B2B258586A6A",
+"S c #B3B35C5C6D6D",
+"D c #B4B45A5A6C6C",
+"F c #B5B55D5D6E6E",
+"G c #BBBB67674747",
+"H c #B8B866664D4D",
+"J c #B9B967674F4F",
+"K c #B7B764645E5E",
+"L c #B6B660607272",
+"P c #B8B865657676",
+"I c #C4C46F6F1717",
+"U c #C3C36E6E1B1B",
+"Y c #C5C571711E1E",
+"T c #C6C675752121",
+"R c #C9C978782424",
+"E c #CBCB7B7B2828",
+"W c #C7C77B7B3B3B",
+"Q c #C1C175757171",
+"! c #C5C57C7C7777",
+"~ c #CFCF82821010",
+"^ c #CCCC84842E2E",
+"/ c #D0D084842C2C",
+"( c #D6D696962E2E",
+") c #DCDC99992A2A",
+"_ c #D6D698983636",
+"` c #DDDDA2A21F1F",
+"' c #F9F982823A3A",
+"] c #F8F887873D3D",
+"[ c #FAFA87873F3F",
+"{ c #E1E1B1B11515",
+"} c #E1E1B3B31616",
+"| c #E2E2B3B31818",
+" . c #E3E3B6B61B1B",
+".. c #E5E5B9B91E1E",
+"X. c #E6E6BABA2121",
+"o. c #E7E7BBBB2525",
+"O. c #E8E8BFBF2828",
+"+. c #EDEDBDBD2929",
+"@. c #EDEDBEBE3030",
+"#. c #EDEDBFBF3535",
+"$. c #CBCB82824040",
+"%. c #CFCF8A8A4343",
+"&. c #CACA82825454",
+"*. c #D5D593934040",
+"=. c #D1D191914E4E",
+"-. c #D8D898984242",
+";. c #DBDB9E9E4545",
+":. c #C8C882826B6B",
+">. c #DEDEA7A74040",
+",. c #F8F888884040",
+"<. c #FBFB8B8B4545",
+"1. c #FBFB8E8E4949",
+"2. c #FCFC8E8E4B4B",
+"3. c #FCFC92924F4F",
+"4. c #FDFD92925050",
+"5. c #FDFD95955454",
+"6. c #FEFE97975959",
+"7. c #FEFE98985959",
+"8. c #FEFE9A9A5C5C",
+"9. c #E5E5B1B14C4C",
+"0. c #ECECBDBD4242",
+"q. c #FEFEA1A16666",
+"w. c #FEFEA2A26464",
+"e. c #EFEFC6C61B1B",
+"r. c #F4F4D4D41F1F",
+"t. c #EAEAC1C12C2C",
+"y. c #EBEBC3C32F2F",
+"u. c #ECECC5C53232",
+"i. c #ECECC5C53333",
+"p. c #EFEFC8C83737",
+"a. c #F1F1C6C62121",
+"s. c #F4F4CACA2525",
+"d. c #F4F4CACA2B2B",
+"f. c #F0F0CACA3B3B",
+"g. c #F1F1CDCD3E3E",
+"h. c #F6F6D5D53737",
+"j. c #F6F6D5D53838",
+"k. c #F2F2CECE4141",
+"l. c #F4F4CFCF4545",
+"z. c #F2F2D3D34B4B",
+"x. c #F2F2D3D34E4E",
+"c. c #F5F5D2D24949",
+"v. c #F5F5D3D34C4C",
+"b. c #F6F6D4D44C4C",
+"n. c #F6F6D5D54F4F",
+"m. c #F3F3D5D55050",
+"M. c #F7F7D5D55151",
+"N. c #F7F7D7D75252",
+"B. c #F4F4D7D75656",
+"V. c #F7F7D8D85353",
+"C. c #F5F5D9D95B5B",
+"Z. c #F9F9D8D85454",
+"A. c #F9F9D9D95454",
+"S. c #F9F9D9D95656",
+"D. c #F9F9D9D95757",
+"F. c #EBEBC0C06767",
+"G. c #F6F6DBDB6060",
+"H. c #F7F7DCDC6565",
+"J. c #F8F8DEDE6868",
+"K. c #F9F9DFDF7272",
+"L. c None",
+/* pixels */
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"D.D.D.D.D.V.M.n.n.c.l.k.g.f.p.i.",
+"D., < q.q.K.F.! P L S Z V K =.) ",
+"D.> - 7.7.J.Q :.D C M x k J v / ",
+"D.: * 7.5.H.F B 9.&.;.-.$.z u E ",
+"Z.; % 5.4.G.A N 0.j.#.h _ g t R ",
+"M.= # 4.3.C.V n h.%. at .+.r.^ w T ",
+"M.& O 1.<.D.l j *.d.s.a.e.4 8 Y ",
+"n.# o <.] n.l i G W ( f ` 2 6 U ",
+"c.# . ] ' z.b J q r 9 1 2 d a I ",
+"k.+ X ,.] x.>.c t t 0 8 1 4 s ~ ",
+"k.g.f.p.i.y.t.O.o.X... .} } } } ",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.",
+"L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L."
+};
diff --git a/src/images/flags/LR.xpm b/src/images/flags/LR.xpm
new file mode 100644
index 0000000..6555836
--- /dev/null
+++ b/src/images/flags/LR.xpm
@@ -0,0 +1,133 @@
+/* XPM */
+static const char *LR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 111 2",
+" c black",
+". c #000000005757",
+"X c #000000005959",
+"o c #000000005B5B",
+"O c #63636464A2A2",
+"+ c #66666868A5A5",
+"@ c #66666969A5A5",
+"# c #6A6A6C6CA7A7",
+"$ c #6B6B6D6DA8A8",
+"% c #999900000000",
+"& c #9B9B00000000",
+"* c #9D9D00000000",
+"= c #A1A100000000",
+"- c #A3A300000000",
+"; c #A5A500000000",
+": c #A7A700000000",
+"> c #A9A900000000",
+", c #ABAB00000000",
+"< c #AFAF00000000",
+"1 c #B3B300000000",
+"2 c #B7B700000000",
+"3 c #B9B900000000",
+"4 c #BDBD00000000",
+"5 c #BFBF00000000",
+"6 c #C3C300000000",
+"7 c #C5C500000000",
+"8 c #C7C700000000",
+"9 c #C9C900000000",
+"0 c #CDCD00000000",
+"q c #CFCF00000000",
+"w c #D0D03B3B3131",
+"e c #D1D13F3F3434",
+"r c #D3D343433838",
+"t c #D3D344443939",
+"y c #D4D447473D3D",
+"u c #D5D548483D3D",
+"i c #D5D54B4B4141",
+"p c #D6D64D4D4242",
+"a c #D7D74D4D4242",
+"s c #D7D74F4F4646",
+"d c #D7D759594F4F",
+"f c #D8D850504747",
+"g c #D9D952524848",
+"h c #D9D954544B4B",
+"j c #D9D955554B4B",
+"k c #DADA57574C4C",
+"l c #DBDB57574D4D",
+"z c #DBDB59594F4F",
+"x c #DBDB59595050",
+"c c #DBDB5A5A5151",
+"v c #D8D85F5F5555",
+"b c #DCDC5C5C5252",
+"n c #DCDC5E5E5555",
+"m c #DDDD5E5E5555",
+"M c #DDDD5F5F5656",
+"N c #DEDE61615757",
+"B c #DEDE62625959",
+"V c #DEDE63635A5A",
+"C c #DEDE63635B5B",
+"Z c #DCDC66665E5E",
+"A c #DFDF65655C5C",
+"S c #DFDF6F6F6666",
+"D c #E0E066665E5E",
+"F c #E0E067675F5F",
+"G c #E0E068685F5F",
+"H c #E0E068686060",
+"J c #E1E16B6B6363",
+"K c #E1E16C6C6363",
+"L c #E1E16C6C6464",
+"P c #E1E16D6D6565",
+"I c #E3E370706767",
+"U c #E3E370706868",
+"Y c #E3E371716969",
+"T c #E4E474746C6C",
+"R c #E4E475756D6D",
+"E c #E5E579797171",
+"W c #E8E886867F7F",
+"Q c #84848787B7B7",
+"! c #85858787B8B8",
+"~ c #A0A0A1A1C7C7",
+"^ c #B3B3B3B3D3D3",
+"/ c #B3B3B4B4D3D3",
+"( c #B3B3B5B5D3D3",
+") c #E9E98E8E8686",
+"_ c #D9D9C7C7C5C5",
+"` c #DBDBCBCBC9C9",
+"' c #E1E1CDCDCDCD",
+"] c #E5E5D3D3D1D1",
+"[ c #EBEBD9D9D7D7",
+"{ c #EFEFEFEFF5F5",
+"} c #F5F5E7E7E5E5",
+"| c #F7F7EBEBE9E9",
+" . c #FBFBEDEDEBEB",
+".. c gray95",
+"X. c #F2F2F2F2F3F3",
+"o. c #F3F3F3F3F3F3",
+"O. c #F4F4F4F4F4F4",
+"+. c #F4F4F5F5F5F5",
+"@. c gray96",
+"#. c #F6F6F6F6F6F6",
+"$. c gray97",
+"%. c #F7F7F7F7FAFA",
+"&. c #F8F8F8F8F8F8",
+"*. c #F9F9F9F9F9F9",
+"=. c gray98",
+"-. c #FBFBFBFBFBFB",
+";. c gray99",
+":. c #FDFDFDFDFDFD",
+">. c #FDFDFDFDFEFE",
+",. c #FEFEFEFEFEFE",
+"<. c None",
+/* pixels */
+"<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.",
+"<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.",
+"<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.",
+"o o o o o q 0 0 9 9 7 6 4 4 3 2 ",
+"o ( %.( ! ,.,.,.-.,.=.=.=.=.#.[ ",
+"o %.,.{ $ E R U L F Z N b l S < ",
+"o ^ { ~ + ,.,.=.=.=.=.#.#.#.#.] ",
+". Q # + O U S A V m c k f a Z : ",
+" .,.,.:.,.-.=.=.=.#.#.#.o.o.o.' ",
+"0 ) U P S A V m z j f a u t N = ",
+"| ,.=.=.=.$.=.#.#.#.#.X.....o.` ",
+"9 W S A V m z j s i t r e w d % ",
+"} :.=.=.=.=.#.#.#.#...#.X....._ ",
+"7 4 4 3 2 1 < > > : = = & % % % ",
+"<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.",
+"<.<.<.<.<.<.<.<.<.<.<.<.<.<.<.<."
+};
diff --git a/src/images/flags/LS.xpm b/src/images/flags/LS.xpm
new file mode 100644
index 0000000..9338143
--- /dev/null
+++ b/src/images/flags/LS.xpm
@@ -0,0 +1,165 @@
+/* XPM */
+static const char *LS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 143 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002D2D0000",
+"O c #00002F2F0000",
+"+ c #000031310000",
+"@ c #000033330000",
+"# c #000035350000",
+"$ c #000039390000",
+"% c #00003B3B0000",
+"& c #00003D3D0000",
+"* c #000001016565",
+"= c #000003036969",
+"- c #000013136B6B",
+"; c #000019197575",
+": c #000041410000",
+"> c #000043430000",
+", c #000047470000",
+"< c #00004B4B0000",
+"1 c #000031318383",
+"2 c #000041418D8D",
+"3 c #24247B7B9898",
+"4 c #29297D7D9E9E",
+"5 c #25257E7EB3B3",
+"6 c #25257E7EB5B5",
+"7 c #0B0B95950B0B",
+"8 c #0F0F97970E0E",
+"9 c #101097971010",
+"0 c #131399991313",
+"q c #141499991414",
+"w c #14149B9B1414",
+"e c #18189E9E1919",
+"r c #19199E9E1919",
+"t c #19199F9F1919",
+"y c #1A1A9B9B2121",
+"u c #1F1F9D9D2525",
+"i c #1F1F9B9B2D2D",
+"p c #1F1F99993535",
+"a c #1E1EA0A01E1E",
+"s c #23239C9C3232",
+"d c #2C2CA2A22C2C",
+"f c #2F2FA4A42F2F",
+"g c #3232A5A53232",
+"h c #3333A6A63232",
+"j c #3535A8A83535",
+"k c #3636A8A83636",
+"l c #3939A9A93939",
+"z c #3B3BADAD3B3B",
+"x c #3D3DACAC3D3D",
+"c c #20208D8D5A5A",
+"v c #242494945151",
+"b c #3F3FA9A94949",
+"n c #4242AFAF4242",
+"m c #4646AEAE4C4C",
+"M c #4B4BA6A67373",
+"N c #26268383B9B9",
+"B c #2A2A8181B5B5",
+"V c #2B2B8585B9B9",
+"C c #2A2A8585BABA",
+"Z c #2B2B8686BABA",
+"A c #2A2A8585BCBC",
+"S c #2D2D8787BABA",
+"D c #2F2F8787BCBC",
+"F c #2E2E8888BEBE",
+"G c #30308787BBBB",
+"H c #34348A8ABEBE",
+"J c #34348B8BBEBE",
+"K c #2F2F8A8AC0C0",
+"L c #31318B8BC0C0",
+"P c #38388E8EC0C0",
+"I c #3C3C9191C1C1",
+"U c #3D3D9292C2C2",
+"Y c #44449191BDBD",
+"T c #6F6F9D9DB3B3",
+"R c #40409494C3C3",
+"E c #47479898C6C6",
+"W c #49499797C3C3",
+"Q c #54549B9BC3C3",
+"! c #50509A9AC8C8",
+"~ c #54549F9FCBCB",
+"^ c #56569E9EC8C8",
+"/ c #5858A2A2CDCD",
+"( c #6767A7A7CBCB",
+") c #7171ADADD0D0",
+"_ c #7878B1B1D1D1",
+"` c #BDBD9D9D6464",
+"' c #BEBEA0A06868",
+"] c #C0C0A1A16B6B",
+"[ c #C1C1A3A36D6D",
+"{ c #C6C6AAAA7979",
+"} c #8E8EBEBEDADA",
+"| c #BDBDC9C9CDCD",
+" . c #B2B2CFCFDFDF",
+".. c #CBCBB3B38585",
+"X. c #CCCCB3B38383",
+"o. c #D1D1BABA8D8D",
+"O. c #D2D2BCBC9494",
+"+. c #D2D2BDBD9595",
+"@. c #D2D2BDBD9696",
+"#. c #D3D3BDBD9696",
+"$. c #D4D4BDBD9595",
+"%. c #D5D5C0C09B9B",
+"&. c #DFDFCFCFB1B1",
+"*. c #DFDFD0D0B2B2",
+"=. c #E1E1D2D2B7B7",
+"-. c #E1E1D3D3B7B7",
+";. c gray86",
+":. c #DDDDDDDDDDDD",
+">. c #DFDFDFDFDFDF",
+",. c #CACADDDDE7E7",
+"<. c #D1D1E1E1EAEA",
+"1. c #E3E3DDDDD5D5",
+"2. c #EDEDE6E6D7D7",
+"3. c gray89",
+"4. c gray90",
+"5. c #E7E7E7E7E7E7",
+"6. c #E9E9E9E9E9E9",
+"7. c gray92",
+"8. c #E8E8EDEDEEEE",
+"9. c #EDEDEBEBEBEB",
+"0. c gray93",
+"q. c #E7E7F0F0F2F2",
+"w. c #EDEDF2F2F4F4",
+"e. c #F5F5EFEFE5E5",
+"r. c #F7F7F2F2EAEA",
+"t. c #F1F1F4F4F5F5",
+"y. c #F7F7F9F9F9F9",
+"u. c #F8F8F6F6F1F1",
+"i. c #F9F9F7F7F1F1",
+"p. c #F8F8F6F6F3F3",
+"a. c #FBFBF9F9F5F5",
+"s. c #FBFBF9F9F7F7",
+"d. c #FAFAFAFAF7F7",
+"f. c #F9F9F9F9F9F9",
+"g. c gray98",
+"h. c #FBFBFAFAFAFA",
+"j. c #FBFBFBFBFBFB",
+"k. c #FCFCFBFBFBFB",
+"l. c #FCFCFCFCFBFB",
+"z. c gray99",
+"x. c #FDFDFDFDFDFD",
+"c. c #FDFDFDFDFEFE",
+"v. c None",
+/* pixels */
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"0.0.0.0.0.6.6.6.5.5.3.>.>.;.| 2 ",
+"0.-.r.e.&.l.x.x.j.j.j.g.h.} ^ * ",
+"0.i.o...&.x.x.x.j.h.h.w.E V W * ",
+"9.O.] ' [ x.x.h.j.h.,.U V N Y . ",
+"1.O.%...{ p.h.h.w.( L V 6 c b > ",
+"6.i.[ ` 2.g.g.<.U G N 5 p e z % ",
+"6.-.O.$.$.y.) P G A 3 i e w k # ",
+"5.h.h.p.8.Q L L B v u a q 9 h + ",
+"5.x.g. .U H D 4 s a a 0 8 7 f o ",
+"3.q._ ~ ~ ! M m n x l k h f d . ",
+"T 1 ; ; - % , < > & % + o o X # ",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v."
+};
diff --git a/src/images/flags/LT.xpm b/src/images/flags/LT.xpm
new file mode 100644
index 0000000..88f428b
--- /dev/null
+++ b/src/images/flags/LT.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *LT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #00002F2F0000",
+"X c #00003B3B0000",
+"o c #00007B7B0000",
+"O c #777700000000",
+"+ c #000083830000",
+"@ c #14149B9B1414",
+"# c #19199D9D1919",
+"$ c #1A1A9C9C1A1A",
+"% c #1F1F9F9F1F1F",
+"& c #1F1FA0A01F1F",
+"* c #20209F9F2020",
+"= c #2424A3A32424",
+"- c #2525A2A22525",
+"; c #2A2AA5A52A2A",
+": c #2A2AA5A52B2B",
+"> c #2B2BA5A52B2B",
+", c #2F2FA9A92F2F",
+"< c #3030A8A83030",
+"1 c #3535ABAB3535",
+"2 c #3636A9A93636",
+"3 c #3636ABAB3636",
+"4 c #3B3BAAAA3B3B",
+"5 c #3B3BADAD3B3B",
+"6 c #3B3BAEAE3A3A",
+"7 c #3B3BAEAE3C3C",
+"8 c #3F3FADAD3F3F",
+"9 c #4040B0B04040",
+"0 c #4141B0B04141",
+"q c #4545B2B24545",
+"w c #4646B2B24646",
+"e c #4646B3B34646",
+"r c #4949B5B54949",
+"t c #4B4BB5B54B4B",
+"y c #4F4FB7B74F4F",
+"u c #4F4FB8B84F4F",
+"i c #5050B7B75050",
+"p c #5353B9B95353",
+"a c #5454B9B95454",
+"s c #5858BCBC5858",
+"d c #6F6FC5C56F6F",
+"f c #7272C6C67373",
+"g c #7676C8C87676",
+"h c #ADAD00000000",
+"j c #B7B700000000",
+"k c #B9B900000000",
+"l c #BBBB00000000",
+"z c #BDBD00000000",
+"x c #BFBF00000000",
+"c c #BCBC26261010",
+"v c #BDBD2B2B1414",
+"b c #BFBF2E2E1919",
+"n c #C1C100000000",
+"m c #C3C300000000",
+"M c #C7C700000000",
+"N c #C9C900000000",
+"B c #CDCD00000000",
+"V c #CFCF00000000",
+"C c #D1D100000000",
+"Z c #D5D500000000",
+"A c #D7D700000000",
+"S c #DBDB00000000",
+"D c #DDDD00000000",
+"F c #C1C133331F1F",
+"G c #C3C338382424",
+"H c #C5C53D3D2A2A",
+"J c #E3E300000000",
+"K c #E1E10B0B0B0B",
+"L c #E2E20F0F0E0E",
+"P c #E3E313131313",
+"I c #E4E419191919",
+"U c #E6E61E1E1E1E",
+"Y c #E7E723232323",
+"T c #E1E12C2C2C2C",
+"R c #E2E22F2F2F2F",
+"E c #E5E52F2F2F2F",
+"W c #E8E829292929",
+"Q c #EAEA2E2E2E2E",
+"! c #E2E232323232",
+"~ c #E4E435353535",
+"^ c #E5E539393939",
+"/ c #E6E63D3D3D3D",
+"( c #EBEB34343434",
+") c #ECEC3A3A3A3A",
+"_ c #EEEE3F3F3F3F",
+"` c #C7C742422F2F",
+"' c #C5C545453232",
+"] c #C9C948483434",
+"[ c #CBCB4C4C3A3A",
+"{ c #CECE52523F3F",
+"} c #CFCF56564545",
+"| c #D1D15B5B4949",
+" . c #DADA7A7A6A6A",
+".. c #E7E742424242",
+"X. c #E8E846464646",
+"o. c #EFEF44444444",
+"O. c #E9E94B4B4B4B",
+"+. c #EAEA50505050",
+"@. c #ECEC54545555",
+"#. c #EDED58585858",
+"$. c #EEEE5D5D5D5D",
+"%. c #EFEF61616262",
+"&. c #F2F266666666",
+"*. c #ABAB9B9B0000",
+"=. c #E9E9B1B10000",
+"-. c #EDEDB7B70000",
+";. c #EBEBB9B90000",
+":. c #EFEFBBBB0000",
+">. c #F1F1BFBF0000",
+",. c #D1D1C7C70000",
+"<. c #D7D7CFCF3030",
+"1. c #D9D9D1D13636",
+"2. c #DADAD3D33B3B",
+"3. c #F1F1C1C10000",
+"4. c #F3F3C5C50000",
+"5. c #F5F5C5C50000",
+"6. c #F7F7C9C90000",
+"7. c #F7F7CBCB0000",
+"8. c #F7F7CDCD0000",
+"9. c #F9F9CDCD0000",
+"0. c #FBFBD1D10000",
+"q. c #FBFBD5D50000",
+"w. c #FFFFD3D30000",
+"e. c #F6F6DADA3838",
+"r. c #F7F7DCDC3D3D",
+"t. c #DCDCD5D54040",
+"y. c #DEDED6D64646",
+"u. c #DCDCD6D64D4D",
+"i. c #DFDFD8D84B4B",
+"p. c #E0E0DADA5050",
+"a. c #E1E1DBDB5454",
+"s. c #E3E3DDDD5959",
+"d. c #E4E4DEDE5D5D",
+"f. c #F8F8DEDE4242",
+"g. c #F9F9DFDF4848",
+"h. c #F7F7DFDF5353",
+"j. c #F7F7DEDE5757",
+"k. c #E5E5DFDF6161",
+"l. c #FAFAE0E04D4D",
+"z. c #F7F7E0E05C5C",
+"x. c #FBFBE1E15252",
+"c. c #FCFCE3E35757",
+"v. c #FDFDE4E45B5B",
+"b. c #FDFDE5E55E5E",
+"n. c #E6E6E0E06464",
+"m. c #EBEBE6E67F7F",
+"M. c #F8F8E1E16060",
+"N. c #F8F8E2E26565",
+"B. c #FEFEE6E66262",
+"V. c #FEFEE7E76666",
+"C. c #F9F9E4E46969",
+"Z. c #FAFAE5E56D6D",
+"A. c #FEFEE8E86969",
+"S. c #FBFBE6E67171",
+"D. c #FCFCE7E77575",
+"F. c #FCFCE8E87979",
+"G. c #FCFCE9E97B7B",
+"H. c #FCFCE9E97E7E",
+"J. c #FCFCEAEA8080",
+"K. c #FDFDEBEB8383",
+"L. c #FFFFECEC8383",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"q.0.0.0.0.9.8.7.7.5.4.3.>.:.-.;.",
+"0.K.K.K.G.G.G.D.S.Z.C.N.M.z.j.=.",
+"w.L.A.V.B.b.v.c.x.l.g.f.r.e.h.=.",
+",.m.n.k.d.s.a.p.i.y.t.2.1.<.u.*.",
+"+ g s a i t w 0 7 3 < > - * 8 X ",
+"o f p y t w 0 5 3 < > - % # 4 . ",
+"o d y r q 0 5 3 , > = & # @ 3 . ",
+"h .| } { [ ] ` H G F b v c ' O ",
+"J &.o._ ) ( Q W Y U I P L K E x ",
+"D %.$.#. at .+.O.X.../ ^ ~ ! R R j ",
+"D A A C V V N m m x x x l l j l ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/LU.xpm b/src/images/flags/LU.xpm
new file mode 100644
index 0000000..9627a9b
--- /dev/null
+++ b/src/images/flags/LU.xpm
@@ -0,0 +1,169 @@
+/* XPM */
+static const char *LU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 147 2",
+" c black",
+". c #00003B3BDFDF",
+"X c #00003F3FDDDD",
+"o c #00004141DDDD",
+"O c #00004343DDDD",
+"+ c #00004747DFDF",
+"@ c #00004949DDDD",
+"# c #00004949E1E1",
+"$ c #00004D4DE3E3",
+"% c #00005353E5E5",
+"& c #00005555E7E7",
+"* c #00005B5BE9E9",
+"= c #00005F5FEBEB",
+"- c #00006565EDED",
+"; c #00006969EDED",
+": c #00006F6FEFEF",
+"> c #00007575F1F1",
+", c #00007979F3F3",
+"< c #0F0F8181DFDF",
+"1 c #00008181F7F7",
+"2 c #01018585F5F5",
+"3 c #00008181F9F9",
+"4 c #37379C9CF1F1",
+"5 c #3B3B9E9EF1F1",
+"6 c #3F3FA0A0F2F2",
+"7 c #4444A2A2F3F3",
+"8 c #4848A5A5F4F4",
+"9 c #4C4CA8A8F5F5",
+"0 c #5151AAAAF6F6",
+"q c #5555A9A9F2F2",
+"w c #5555ADADF7F7",
+"e c #5B5BACACF2F2",
+"r c #5D5DAEAEF2F2",
+"t c #5A5AB0B0F8F8",
+"y c #5F5FB3B3F9F9",
+"u c #6060AFAFF3F3",
+"i c #6363B1B1F3F3",
+"p c #6666B3B3F4F4",
+"a c #6161B5B5FBFB",
+"s c #6363B5B5FAFA",
+"d c #6A6AB5B5F5F5",
+"f c #6D6DB7B7F6F6",
+"g c #6868B8B8FAFA",
+"h c #7070B9B9F7F7",
+"j c #7575BBBBF7F7",
+"k c #7878BDBDF8F8",
+"l c #7B7BBFBFF9F9",
+"z c #7F7FC2C2F9F9",
+"x c #E9E900000000",
+"c c #EBEB00000000",
+"v c #EDED00000000",
+"b c #EFEF00000000",
+"n c #E7E71F1F1717",
+"m c #F1F100000000",
+"M c #F3F300000000",
+"N c #F5F500000000",
+"B c #F7F705050000",
+"V c #F9F90B0B0000",
+"C c #FBFB11110505",
+"Z c #FDFD17170B0B",
+"A c #FDFD1D1D0F0F",
+"S c #FFFF1F1F1313",
+"D c #FDFD21211717",
+"F c #FDFD27271B1B",
+"G c #FFFF27271919",
+"H c #FFFF29291D1D",
+"J c #FFFF37372D2D",
+"K c #F6F65D5D5454",
+"L c #F7F762625959",
+"P c #F8F866665E5E",
+"I c #F9F96A6A6363",
+"U c #FAFA6F6F6767",
+"Y c #FFFF6D6D6767",
+"T c #F7F774746C6C",
+"R c #FBFB73736C6C",
+"E c #FCFC77776F6F",
+"W c #F7F77E7E7777",
+"Q c #FDFD7A7A7272",
+"! c #FDFD7D7D7676",
+"~ c #F8F881817A7A",
+"^ c #F9F985857F7F",
+"/ c #FEFE81817A7A",
+"( c #FEFE84847C7C",
+") c #FEFE86867F7F",
+"_ c #8686BFBFF2F2",
+"` c #8383C3C3FAFA",
+"' c #8686C5C5FBFB",
+"] c #8484C5C5FCFC",
+"[ c #8888C1C1F2F2",
+"{ c #8B8BC4C4F3F3",
+"} c #8E8EC6C6F4F4",
+"| c #9191C8C8F5F5",
+" . c #9797C8C8F3F3",
+".. c #9494CACAF6F6",
+"X. c #9797CBCBF7F7",
+"o. c #9B9BCDCDF8F8",
+"O. c #9E9ECFCFF9F9",
+"+. c #A1A1D1D1FAFA",
+"@. c #A4A4D2D2FBFB",
+"#. c #A7A7D4D4FBFB",
+"$. c #B7B7DDDDFCFC",
+"%. c #FAFA88888282",
+"&. c #FBFB8B8B8585",
+"*. c #FCFC8F8F8A8A",
+"=. c #F5F590908B8B",
+"-. c #F6F693938E8E",
+";. c #FCFC92928D8D",
+":. c #FDFD95958F8F",
+">. c #F7F797979292",
+",. c #F6F69F9F9A9A",
+"<. c #F8F899999595",
+"1. c #FDFD98989292",
+"2. c #FEFE99999494",
+"3. c #FFFF9B9B9595",
+"4. c #FEFE9D9D9797",
+"5. c #F9F99C9C9898",
+"6. c #FAFA9F9F9C9C",
+"7. c #FEFE9E9E9999",
+"8. c #FBFBA2A29F9F",
+"9. c #FFFFA0A09B9B",
+"0. c #FCFCA5A5A1A1",
+"q. c #FDFDA8A8A4A4",
+"w. c #FDFDABABA6A6",
+"e. c #FEFEACACA9A9",
+"r. c #FEFEAFAFABAB",
+"t. c #FEFEBDBDBABA",
+"y. c gainsboro",
+"u. c gray87",
+"i. c gray88",
+"p. c gray93",
+"a. c gray95",
+"s. c #F3F3F3F3F3F3",
+"d. c #F4F4F4F4F4F4",
+"f. c #F4F4F5F5F5F5",
+"g. c gray96",
+"h. c #F6F6F6F6F6F6",
+"j. c gray97",
+"k. c #F8F8F8F8F8F8",
+"l. c #F9F9F9F9F9F9",
+"z. c gray98",
+"x. c #FBFBFBFBFBFB",
+"c. c #FBFBFCFCFBFB",
+"v. c gray99",
+"b. c #FDFDFCFCFDFD",
+"n. c #FDFDFDFDFDFD",
+"m. c #FEFEFEFEFEFE",
+"M. c None",
+/* pixels */
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"J H H H G D A Z C V B N M M v v ",
+"G 9.9.7.4.3.1.:.;.*.%.%.%.W W c ",
+"S 3.) / ! ! Q E R R I P L K T c ",
+"Y t.r.r.w.q.0.8.6.5.<.>.=.=.,.n ",
+"p.m.m.m.m.v.x.z.z.k.k.h.h.f.f.i.",
+"p.m.m.x.x.z.z.z.h.h.f.f.f.s.f.u.",
+"p.m.x.x.z.z.z.z.k.h.f.f.d.a.d.y.",
+"a $.#. at .+.o.o.X...| } { [ _ .> ",
+"3 ' g s a t w 0 9 8 7 6 5 5 e o ",
+"1 ' ` z l k j h f d p i i r r X ",
+"2 , > : ; - = * & % $ # O O O @ ",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M."
+};
diff --git a/src/images/flags/LV.xpm b/src/images/flags/LV.xpm
new file mode 100644
index 0000000..076fec6
--- /dev/null
+++ b/src/images/flags/LV.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *LV_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #272700000000",
+"X c #292900000000",
+"o c #2B2B00000000",
+"O c #2D2D00000000",
+"+ c #2F2F00000000",
+"@ c #333300000000",
+"# c #353500000000",
+"$ c #393900000000",
+"% c #3D3D00000000",
+"& c #414100000000",
+"* c #474700000000",
+"= c #4B4B00000000",
+"- c #4D4D00000000",
+"; c #515100000000",
+": c #575700000000",
+"> c #5D5D00000000",
+", c #5F5F00000000",
+"< c #636300000000",
+"1 c #676700000000",
+"2 c #6D6D00000000",
+"3 c #6F6F00000000",
+"4 c #717100000000",
+"5 c #757500000000",
+"6 c #777700000000",
+"7 c #797900000000",
+"8 c #7D7D00000000",
+"9 c #818100000000",
+"0 c #838300000000",
+"q c #858500000000",
+"w c #878700000000",
+"e c #898900000000",
+"r c #919100000000",
+"t c #94940B0B0B0B",
+"y c #96960F0F0E0E",
+"u c #959510101010",
+"i c #979714141414",
+"p c #989813131313",
+"a c #999919191919",
+"s c #9B9B19191919",
+"d c #9C9C1F1F1F1F",
+"f c #9E9E1E1E1E1E",
+"g c #9F9F24242424",
+"h c #9E9E26262626",
+"j c #A1A123232323",
+"k c #A1A12B2B2B2B",
+"l c #A3A329292929",
+"z c #A2A22A2A2A2A",
+"x c #A2A22C2C2C2C",
+"c c #A3A32F2F2F2F",
+"v c #A4A42F2F2F2F",
+"b c #A5A52F2F2F2F",
+"n c #A6A62C2C2C2C",
+"m c #A6A62E2E2E2E",
+"M c #A4A431313131",
+"N c #A4A432323232",
+"B c #A5A532323232",
+"V c #A7A737373636",
+"C c #A9A931313131",
+"Z c #A8A834343434",
+"A c #A8A835353535",
+"S c #A9A934343434",
+"D c #ABAB37373737",
+"F c #A9A939393939",
+"G c #ABAB3A3A3A3A",
+"H c #AAAA3C3C3C3C",
+"J c #ACAC3D3D3D3D",
+"K c #ADAD3F3F3F3F",
+"L c #AEAE3C3C3D3D",
+"P c #AEAE3F3F3F3F",
+"I c #ADAD41414242",
+"U c #AEAE42424242",
+"Y c #ACAC44444444",
+"T c #AFAF47474747",
+"R c #B1B142424242",
+"E c #B0B045454545",
+"W c #B1B144444444",
+"Q c #B0B046464646",
+"! c #B3B347474747",
+"~ c #B1B149494949",
+"^ c #B2B249494949",
+"/ c #B2B24B4B4B4B",
+"( c #B4B44E4E4E4E",
+") c #B6B64C4C4C4C",
+"_ c #B4B450505050",
+"` c #B4B451515151",
+"' c #B7B753535353",
+"] c #B6B654545454",
+"[ c #B7B754545555",
+"{ c #B8B851515151",
+"} c #B9B957575757",
+"| c #BABA54545454",
+" . c #B8B859595959",
+".. c #B9B958585858",
+"X. c #BABA5C5C5C5C",
+"o. c #BBBB5C5C5C5C",
+"O. c #BBBB5D5D5D5D",
+"+. c #BCBC59595959",
+"@. c #BEBE5C5C5C5C",
+"#. c #BFBF5F5F5F5F",
+"$. c #BEBE60606060",
+"%. c #BEBE61616262",
+"&. c #BFBF66666666",
+"*. c #C0C065656565",
+"=. c #C1C16A6A6A6A",
+"-. c #C2C269696969",
+";. c #C3C36D6D6D6D",
+":. c #C5C570707171",
+">. c #C7C774747474",
+",. c #C6C679797979",
+"<. c #C8C877777777",
+"1. c #C9C979797979",
+"2. c #CACA7B7B7A7A",
+"3. c #CACA7B7B7B7B",
+"4. c #C7C79F9F9F9F",
+"5. c #C9C99D9D9D9D",
+"6. c #E4E4CFCFCFCF",
+"7. c #E9E9C9C9C9C9",
+"8. c #E9E9CBCBCBCB",
+"9. c #E5E5D0D0D0D0",
+"0. c #E5E5D1D1D1D1",
+"q. c #E6E6D2D2D2D2",
+"w. c #E7E7D3D3D3D3",
+"e. c #E8E8D3D3D3D3",
+"r. c #E8E8D5D5D5D5",
+"t. c #E9E9D5D5D5D5",
+"y. c #E8E8D6D6D6D6",
+"u. c #E9E9D6D6D6D6",
+"i. c #E9E9D7D7D7D7",
+"p. c #EAEAD7D7D7D7",
+"a. c #EBEBD8D8D8D8",
+"s. c #ECECD9D9D9D9",
+"d. c #EDEDDADADADA",
+"f. c #EDEDDBDBDBDB",
+"g. c #EEEEDCDCDCDC",
+"h. c #EEEEDDDDDDDD",
+"j. c #F0F0DEDEDEDE",
+"k. c #F1F1DEDEDEDE",
+"l. c gray90",
+"z. c #F1F1E0E0E0E0",
+"x. c #F1F1E1E1E1E1",
+"c. c #F2F2E1E1E1E1",
+"v. c #F4F4E7E7E7E7",
+"b. c #F5F5E7E7E7E7",
+"n. c #F3F3F3F3F3F3",
+"m. c #F4F4F4F4F4F4",
+"M. c #F4F4F5F5F5F5",
+"N. c gray96",
+"B. c #F6F6F6F6F6F6",
+"V. c gray97",
+"C. c #F8F8F8F8F8F8",
+"Z. c #F9F9F9F9F9F9",
+"A. c gray98",
+"S. c #FBFBFBFBFBFB",
+"D. c gray99",
+"F. c #FDFDFDFDFDFD",
+"G. c #FEFEFEFEFEFE",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"r e e e e 9 9 8 7 5 4 2 1 < , , ",
+"q 3.3.3.>.>.:.;.-.*.$.X.| ` ) - ",
+"e 3.#. at .@.| { ) ! R L D Z n / = ",
+"9 ,.X. .` ` / T I H D M k h T % ",
+"7.b.c.c.j.j.g.d.d.p.r.r.6.6.r.4.",
+"S.S.S.S.S.S.S.V.V.V.V.B.B.n.n.l.",
+"8.b.c.c.k.g.g.d.a.p.r.6.6.6.a.4.",
+"7 ;.^ ! I G B b k g f s i i N X ",
+"5 *.W P G B n k j f s i y t c X ",
+"4 %.X. .[ ` / ! I L F D M c k . ",
+"5 1 < , : ; - * & % # @ + + X # ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/LY.xpm b/src/images/flags/LY.xpm
new file mode 100644
index 0000000..37f7178
--- /dev/null
+++ b/src/images/flags/LY.xpm
@@ -0,0 +1,156 @@
+/* XPM */
+static const char *LY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 134 2",
+" c black",
+". c #000043430000",
+"X c #000045450000",
+"o c #000047470000",
+"O c #000049490000",
+"+ c #00004B4B0000",
+"@ c #00004D4D0000",
+"# c #000051510000",
+"$ c #000053530000",
+"% c #000057570000",
+"& c #000059590000",
+"* c #00005D5D0000",
+"= c #00005F5F0000",
+"- c #000063630000",
+"; c #000067670000",
+": c #00006D6D0000",
+"> c #000071710000",
+", c #000077770000",
+"< c #00007B7B0000",
+"1 c #000081810000",
+"2 c #000085850000",
+"3 c #000087870000",
+"4 c #000089890000",
+"5 c #00008B8B0000",
+"6 c #00008D8D0000",
+"7 c #00008F8F0000",
+"8 c #000091910000",
+"9 c #000093930000",
+"0 c #000095950000",
+"q c #000097970000",
+"w c #000099990000",
+"e c #1717A6A61818",
+"r c #1C1CA8A81B1B",
+"t c #1C1CA9A91C1C",
+"y c #2020ABAB2020",
+"u c #2121ABAB2121",
+"i c #2424ADAD2525",
+"p c #2525AEAE2525",
+"a c #2626AEAE2626",
+"s c #2A2AAFAF2A2A",
+"d c #2B2BB0B02B2B",
+"f c #2F2FB1B12F2F",
+"g c #2F2FB2B22F2F",
+"h c #3030B2B23030",
+"j c #3030B3B33030",
+"k c #3131B3B33131",
+"l c #3737B2B23737",
+"z c #3434B4B43434",
+"x c #3535B4B43535",
+"c c #3535B5B53636",
+"v c #3636B5B53636",
+"b c #3737B5B53737",
+"n c #3737B6B63737",
+"m c #3939B3B33939",
+"M c #3A3AB3B33A3A",
+"N c #3A3AB6B63A3A",
+"B c #3A3AB7B73A3A",
+"V c #3B3BB7B73B3B",
+"C c #3C3CB4B43C3C",
+"Z c #3D3DB4B43D3D",
+"A c #3B3BB8B83B3B",
+"S c #3C3CB8B83C3C",
+"D c #3F3FB9B93F3F",
+"F c #4040B6B64040",
+"G c #4141B7B74141",
+"H c #4040B9B94040",
+"J c #4040BABA4040",
+"K c #4141BABA4040",
+"L c #4141BBBB4141",
+"P c #4141BBBB4242",
+"I c #4444B9B94343",
+"U c #4444BBBB4444",
+"Y c #4646B9B94646",
+"T c #4747B9B94747",
+"R c #4545BCBC4545",
+"E c #4646BCBC4646",
+"W c #4646BDBD4646",
+"Q c #4747BDBD4747",
+"! c #4949BBBB4949",
+"~ c #4949BEBE4949",
+"^ c #4B4BBCBC4B4B",
+"/ c #4A4ABEBE4A4A",
+"( c #4B4BBEBE4B4B",
+") c #4C4CBFBF4C4C",
+"_ c #4E4EBEBE4E4E",
+"` c #5050BEBE5050",
+"' c #5252BFBF5252",
+"] c #4E4EC0C04E4E",
+"[ c #4F4FC0C04F4F",
+"{ c #5050C0C05050",
+"} c #5050C1C15050",
+"| c #5151C1C15151",
+" . c #5353C2C25353",
+".. c #5555C0C05555",
+"X. c #5454C3C35454",
+"o. c #5555C3C35555",
+"O. c #5656C3C35656",
+"+. c #5757C2C25757",
+"@. c #5959C2C25959",
+"#. c #5858C5C55858",
+"$. c #5858C5C55959",
+"%. c #5A5AC5C55A5A",
+"&. c #5C5CC3C35C5C",
+"*. c #5D5DC4C45E5E",
+"=. c #5D5DC7C75D5D",
+"-. c #5E5EC7C75E5E",
+";. c #6060C6C66060",
+":. c #6262C6C66262",
+">. c #6161C8C86161",
+",. c #6161C9C96161",
+"<. c #6262C9C96262",
+"1. c #6565C8C86565",
+"2. c #6565C8C86666",
+"3. c #6565CACA6565",
+"4. c #6969CACA6969",
+"5. c #6A6ACACA6A6A",
+"6. c #6868CCCC6868",
+"7. c #6D6DCCCC6D6D",
+"8. c #6F6FCCCC6F6F",
+"9. c #7171CDCD7171",
+"0. c #7373CDCD7373",
+"q. c #7575CECE7575",
+"w. c #7777D0D07676",
+"e. c #7979D0D07979",
+"r. c #7A7AD1D17A7A",
+"t. c #7B7BD2D27B7B",
+"y. c #7D7DD3D37D7D",
+"u. c #7E7ED3D37E7E",
+"i. c #8080D3D38080",
+"p. c #8080D4D48080",
+"a. c #8282D4D48282",
+"s. c #8282D4D48383",
+"d. c #8383D4D48383",
+"f. c None",
+/* pixels */
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"w w w w w q 9 7 5 3 3 < < < > : ",
+"w d.d.d.u.t.t.q.9.7.5.3.;.&.+.; ",
+"w d.3.3.<.-.$.o.| _ Q L S n ' - ",
+"w u.3.<.-.$.o.| ( Q L S n k _ * ",
+"q y.<.=.$.o.| ( Q D V v k d ! & ",
+"q t.-.$. .' ! Q S V v j d i T $ ",
+"9 w.o. ._ ( Q L B v j d i u L @ ",
+"7 9.| ] ( Q S B v f s i u r Z O ",
+"3 9._ ( Q S B v f s i y r e M o ",
+"3 5.3.;.=. at .' ' ( Q I F C B l . ",
+"< < , > : ; - * & $ # @ O o . . ",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f."
+};
diff --git a/src/images/flags/MA.xpm b/src/images/flags/MA.xpm
new file mode 100644
index 0000000..43d4d1c
--- /dev/null
+++ b/src/images/flags/MA.xpm
@@ -0,0 +1,146 @@
+/* XPM */
+static const char *MA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 124 2",
+" c black",
+". c #BDBD5F5F2F2F",
+"X c #B2B279793636",
+"o c #B5B57D7D3B3B",
+"O c #BEBE71713C3C",
+"+ c #DDDD00000000",
+"@ c #DFDF00000000",
+"# c #E1E100000000",
+"$ c #E3E300000000",
+"% c #E5E500000000",
+"& c #E7E700000000",
+"* c #E9E900000000",
+"= c #EBEB00000000",
+"- c #EDED00000000",
+"; c #EFEF00000000",
+": c #F1F100000000",
+"> c #F3F300000000",
+", c #F5F500000000",
+"< c #F7F700000000",
+"1 c #F1F10B0B0B0B",
+"2 c #F1F10F0F0E0E",
+"3 c #F9F900000000",
+"4 c #FBFB00000000",
+"5 c #FDFD00000000",
+"6 c red",
+"7 c #F2F210101010",
+"8 c #F2F213131313",
+"9 c #F2F214141414",
+"0 c #F3F319191919",
+"q c #F3F31A1A1A1A",
+"w c #F4F41E1E1E1E",
+"e c #F4F41F1F1F1F",
+"r c #F4F420202020",
+"t c #F5F523232323",
+"y c #F4F425252424",
+"u c #F5F524242424",
+"i c #F5F525252525",
+"p c #F5F526262626",
+"a c #F2F22D2D2A2A",
+"s c #F2F22C2C2C2C",
+"d c #F2F22F2F2F2F",
+"f c #F6F629292929",
+"g c #F6F62A2A2A2A",
+"h c #F6F62B2B2B2B",
+"j c #F6F62C2C2C2C",
+"k c #F7F72E2E2E2E",
+"l c #F7F72F2F2F2F",
+"z c #F2F232323232",
+"x c #F3F332323232",
+"c c #F3F335353535",
+"v c #F7F730303030",
+"b c #F7F731313131",
+"n c #F4F436363636",
+"m c #F1F13B3B3636",
+"M c #F4F439393939",
+"N c #F4F43B3B3B3B",
+"B c #F6F63D3D3A3A",
+"V c #F5F53D3D3D3D",
+"C c #F5F53F3F3F3F",
+"Z c #F8F834343434",
+"A c #F8F835353434",
+"S c #F8F837373636",
+"D c #F8F837373737",
+"F c #F9F93A3A3A3A",
+"G c #F9F93C3C3C3C",
+"H c #F9F93C3C3D3D",
+"J c #FAFA3F3F3F3F",
+"K c #C9C958583030",
+"L c #C0C063633535",
+"P c #C0C075754141",
+"I c #D0D064644040",
+"U c #F6F642424242",
+"Y c #F6F644444444",
+"T c #F7F746464646",
+"R c #F3F34A4A4646",
+"E c #F7F749494949",
+"W c #F7F74B4B4B4B",
+"Q c #F7F74E4E4E4E",
+"! c #F9F942424242",
+"~ c #FAFA40404040",
+"^ c #FAFA42424242",
+"/ c #FAFA44444444",
+"( c #FBFB45454545",
+") c #FAFA47474747",
+"_ c #FBFB46464646",
+"` c #FBFB47474747",
+"' c #FBFB49494949",
+"] c #FBFB4A4A4949",
+"[ c #FCFC4A4A4B4B",
+"{ c #FCFC4B4B4B4B",
+"} c #FCFC4C4C4C4C",
+"| c #FCFC4F4F4F4F",
+" . c #FDFD4F4F5050",
+".. c #F8F850505050",
+"X. c #F8F853535353",
+"o. c #F9F954545555",
+"O. c #F9F957575757",
+"+. c #FDFD51515151",
+"@. c #FDFD53535353",
+"#. c #FDFD54545454",
+"$. c #F9F958585858",
+"%. c #FAFA5C5C5C5C",
+"&. c #FAFA5D5D5D5D",
+"*. c #FEFE58585858",
+"=. c #FEFE59595959",
+"-. c #FEFE5C5C5C5C",
+";. c #FEFE5F5F5F5F",
+":. c #FBFB60606060",
+">. c #FBFB61616262",
+",. c #FCFC65656565",
+"<. c #FCFC66666666",
+"1. c #FCFC69696969",
+"2. c #FCFC6A6A6A6A",
+"3. c #FDFD6D6D6D6D",
+"4. c #FDFD6F6F6F6F",
+"5. c #FDFD70707171",
+"6. c #FEFE72727373",
+"7. c #FEFE74747474",
+"8. c #FEFE76767676",
+"9. c #FEFE77777777",
+"0. c #FEFE79797979",
+"q. c #FFFF7B7B7A7A",
+"w. c #FFFF7B7B7B7B",
+"e. c None",
+/* pixels */
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"6 6 6 6 4 6 6 6 4 4 < < > > - - ",
+"6 w.w.w.8.7.7.3.1.,.&.-.$.X.Q = ",
+"6 w.-.-.-. at .@.| ) ! J S b j E = ",
+"6 w.-.-. at .@.[ } ! J S b h p Y % ",
+"6 8.O. at .| [ R L O m v h p r C % ",
+"6 7. at .| [ ) I o X K j p e 0 C % ",
+"6 4.| ` ( ! J . . a r e 0 9 c $ ",
+"4 2.[ ) J F S b f p e 0 8 8 x @ ",
+"4 <.( J F b j f r e 0 8 2 1 d @ ",
+"< &.&.%.o.X.E Y U C M c x d a @ ",
+"> > > - - - = = % % $ $ @ @ + + ",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.",
+"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e."
+};
diff --git a/src/images/flags/MC.xpm b/src/images/flags/MC.xpm
new file mode 100644
index 0000000..a2ba320
--- /dev/null
+++ b/src/images/flags/MC.xpm
@@ -0,0 +1,130 @@
+/* XPM */
+static const char *MC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 108 2",
+" c black",
+". c #E5E500000000",
+"X c #E7E700000000",
+"o c #E9E900000000",
+"O c #EBEB00000000",
+"+ c #EDED00000000",
+"@ c #EFEF00000000",
+"# c #F1F100000000",
+"$ c #F3F300000000",
+"% c #F5F500000000",
+"& c #F7F700000000",
+"* c #F9F900000000",
+"= c #FBFB00000000",
+"- c #FDFD00000000",
+"; c red",
+": c #FDFD05050505",
+"> c #F4F420202020",
+", c #F5F525252525",
+"< c #F5F526262626",
+"1 c #F6F62B2B2B2B",
+"2 c #F6F62C2C2C2C",
+"3 c #F7F730303030",
+"4 c #F7F731313131",
+"5 c #F5F53F3F3F3F",
+"6 c #F8F836363636",
+"7 c #F8F837373636",
+"8 c #F8F837373737",
+"9 c #F9F93B3B3C3C",
+"0 c #F9F93C3C3C3C",
+"q c #F9F93C3C3D3D",
+"w c #F6F644444444",
+"e c #F3F34C4C4C4C",
+"r c #F7F749494949",
+"t c #F7F74E4E4E4E",
+"y c #FAFA41414141",
+"u c #FAFA41414242",
+"i c #FAFA42424242",
+"p c #FBFB46464646",
+"a c #FBFB47474747",
+"s c #FCFC4B4B4B4B",
+"d c #FCFC4C4C4C4C",
+"f c #FDFD4F4F5050",
+"g c #F4F451515151",
+"h c #F5F555555555",
+"j c #F6F65A5A5A5A",
+"k c #F7F75E5E5E5E",
+"l c #F8F853535353",
+"z c #F9F957575757",
+"x c #FDFD51515151",
+"c c #FDFD54545454",
+"v c #FAFA5C5C5C5C",
+"b c #FEFE58585858",
+"n c #FEFE59595959",
+"m c #FEFE5C5C5C5C",
+"M c #FEFE5F5F5F5F",
+"N c #F4F466666666",
+"B c #F8F863636363",
+"V c #FBFB60606060",
+"C c #F9F967676767",
+"Z c #FCFC65656565",
+"A c #FAFA6B6B6B6B",
+"S c #FCFC69696969",
+"D c #FDFD6D6D6D6D",
+"F c #FBFB70707070",
+"G c #FDFD70707171",
+"H c #FCFC74747474",
+"J c #FEFE74747474",
+"K c #FEFE76767676",
+"L c #FEFE77777777",
+"P c #FCFC77777878",
+"I c #FDFD7A7A7A7A",
+"U c #FEFE79797979",
+"Y c #FFFF7B7B7A7A",
+"T c #FFFF7B7B7B7B",
+"R c #FEFE93939393",
+"E c #C5C5C5C5C5C5",
+"W c gray78",
+"Q c gray79",
+"! c #C9C9CBCBC9C9",
+"~ c #CBCBCBCBCBCB",
+"^ c gray81",
+"/ c gray82",
+"( c LightGray",
+") c #D7D7D7D7D7D7",
+"_ c gray85",
+"` c gray86",
+"' c #DFDFDFDFDFDF",
+"] c gray89",
+"[ c gray90",
+"{ c #E7E7E7E7E7E7",
+"} c #E9E9E9E9E9E9",
+"| c gray92",
+" . c #F1F1F1F1F1F1",
+".. c gray95",
+"X. c #F2F2F2F2F3F3",
+"o. c #F3F3F3F3F3F3",
+"O. c #F4F4F4F4F4F4",
+"+. c gray96",
+"@. c #F6F6F6F6F6F6",
+"#. c gray97",
+"$. c #F8F8F8F8F8F8",
+"%. c #F9F9F9F9F9F9",
+"&. c gray98",
+"*. c #FBFBFBFBFBFB",
+"=. c #FBFBFCFCFBFB",
+"-. c gray99",
+";. c #FDFDFDFDFDFD",
+":. c None",
+/* pixels */
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+"; ; ; ; = ; ; ; = = & & $ $ + + ",
+"; T T T K J D D S Z V m z l t O ",
+"; T m m m c c s a u 5 6 4 2 r O ",
+"; T m m c c s a u 9 6 4 1 < w . ",
+"; K z c d s i y 9 6 3 1 < > 5 . ",
+": R T P K F A C V k j h g e N . ",
+"| -.-.-.%.%.%.%.#.#.O.O.O...O.! ",
+"} -.*.*.*.%.%.+. at .+.O.O.....X.! ",
+"{ -.%.%.%.%.%.+.+.O.O.........E ",
+"[ *.%.%.*.%.#.#.+.+.+.X.......E ",
+"] ] ' ` ) ) ) ( / ^ ~ ! ! E E E ",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:."
+};
diff --git a/src/images/flags/MD.xpm b/src/images/flags/MD.xpm
new file mode 100644
index 0000000..7346862
--- /dev/null
+++ b/src/images/flags/MD.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *MD_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000000009999",
+"X c #000000009D9D",
+"o c #00000000A1A1",
+"O c #00000000A5A5",
+"+ c #00000000A9A9",
+"@ c #00000000ABAB",
+"# c #00000000AFAF",
+"$ c #00000000B3B3",
+"% c #00000000B5B5",
+"& c #00000000B9B9",
+"* c #00000303BBBB",
+"= c #00000505BBBB",
+"- c #00000707BBBB",
+"; c #00000909BBBB",
+": c #3C3C5A5ACDCD",
+"> c #41415F5FCFCF",
+", c #46466363D0D0",
+"< c #4A4A6767D2D2",
+"1 c #4C4C6767D2D2",
+"2 c #4F4F6C6CD4D4",
+"3 c #51516C6CD4D4",
+"4 c #54547070D6D6",
+"5 c #55557171D6D6",
+"6 c #56567171D6D6",
+"7 c #59597474D7D7",
+"8 c #5A5A7575D8D8",
+"9 c #5E5E7878D6D6",
+"0 c #5E5E7979D9D9",
+"q c #5F5F7979D9D9",
+"w c #5F5F7979DADA",
+"e c #63637B7BD8D8",
+"r c #62627C7CDBDB",
+"t c #63637C7CDBDB",
+"y c #67677F7FD9D9",
+"u c #66667F7FDCDC",
+"i c #6B6B8383DBDB",
+"p c #69698282DDDD",
+"a c #6F6F8787DDDD",
+"s c #74748A8ADDDD",
+"d c #78788E8EDFDF",
+"f c #7B7B9090E1E1",
+"g c #7F7F9494E2E2",
+"h c #9F9F00000000",
+"j c #A1A100000000",
+"k c #A3A300000000",
+"l c #A5A500000000",
+"z c #A7A700000000",
+"x c #A9A900000000",
+"c c #ADAD00000000",
+"v c #B1B100000000",
+"b c #B3B300000000",
+"n c #B9B900000000",
+"m c #BBBB00000000",
+"M c #BFBF00000000",
+"N c #C1C100000000",
+"B c #C5C500000000",
+"V c #C7C700000000",
+"C c #D3D329291A1A",
+"Z c #D4D42C2C1D1D",
+"A c #D5D530302222",
+"S c #D6D631312222",
+"D c #D7D735352727",
+"F c #D7D736362727",
+"G c #D7D736362828",
+"H c #D8D83B3B2C2C",
+"J c #D8D83B3B2D2D",
+"K c #DADA40403232",
+"L c #DBDB41413333",
+"P c #D8D845453838",
+"I c #DCDC45453838",
+"U c #DCDC46463838",
+"Y c #DDDD46463939",
+"T c #D8D848483B3B",
+"R c #DADA4B4B3E3E",
+"E c #DADA4B4B3F3F",
+"W c #DEDE4B4B3D3D",
+"Q c #DEDE4B4B3E3E",
+"! c #DBDB4E4E4141",
+"~ c #DBDB4F4F4242",
+"^ c #DFDF50504343",
+"/ c #DDDD53534646",
+"( c #DEDE57574B4B",
+") c #DFDF5B5B5050",
+"_ c #E1E154544848",
+"` c #E2E259594C4C",
+"' c #E1E160605454",
+"] c #E2E264645959",
+"[ c #E4E469695D5D",
+"{ c #E5E56C6C6161",
+"} c #E6E670706666",
+"| c #979782823C3C",
+" . c #979783833D3D",
+".. c #9A9A86864242",
+"X. c #9A9A87874343",
+"o. c #9E9E8B8B4848",
+"O. c #A0A08D8D4C4C",
+"+. c #A4A491915252",
+"@. c #A7A794945757",
+"#. c #A9A996965252",
+"$. c #AFAF9E9E5757",
+"%. c #B1B1A1A15C5C",
+"&. c #E3E3BBBB0000",
+"*. c #E5E5BDBD0000",
+"=. c #E7E7BFBF0000",
+"-. c #D1D1BEBE5252",
+";. c #EDED9E9E4141",
+":. c #EEEEA0A04646",
+">. c #E9E9C1C10000",
+",. c #EDEDC7C70000",
+"<. c #EBEBC9C90000",
+"1. c #F7F7D9D90000",
+"2. c #FBFBD1D10000",
+"3. c #FDFDD3D30000",
+"4. c #F9F9DBDB0000",
+"5. c #FDFDDFDF0000",
+"6. c #F2F2D7D72323",
+"7. c #F4F4D9D92929",
+"8. c #FDFDE3E30000",
+"9. c #F4F4E3E31E1E",
+"0. c #F3F3E0E02626",
+"q. c #F4F4E1E12B2B",
+"w. c #F7F7EAEA2E2E",
+"e. c #F5F5E2E23030",
+"r. c #F5F5E3E33131",
+"t. c #F6F6E4E43636",
+"y. c #F5F5E4E43D3D",
+"u. c #F7F7E6E63C3C",
+"i. c #DEDED0D04242",
+"p. c #E7E7D8D84E4E",
+"a. c #F4F4E3E34444",
+"s. c #F6F6E5E54C4C",
+"d. c #F8F8E6E64040",
+"f. c #F8F8E8E84242",
+"g. c #F9F9E8E84545",
+"h. c #F9F9E9E94848",
+"j. c #FAFAE9E94B4B",
+"k. c #FAFAEAEA4D4D",
+"l. c #F7F7E7E75050",
+"z. c #F7F7E8E85555",
+"x. c #FBFBEBEB5151",
+"c. c #FCFCECEC5656",
+"v. c #F8F8E9E95A5A",
+"b. c #FDFDEDED5B5B",
+"n. c #FDFDEEEE5E5E",
+"m. c #FDFDF3F35151",
+"M. c #FCFCEEEE6565",
+"N. c #FBFBEDED6A6A",
+"B. c #FCFCEFEF7272",
+"V. c #FDFDF0F07575",
+"C. c #FDFDF1F17A7A",
+"Z. c #FEFEF2F27B7B",
+"A. c #81819595E2E2",
+"S. c #81819696E2E2",
+"D. c #84849797E2E2",
+"F. c #84849898E2E2",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"; ; ; ; = 5.8.3.2.4.1.V V N M m ",
+"; F.F.A.A.Z.Z.B.B.M.N.} { [ ] m ",
+"; D.p u r n.m.%.$.k.h.^ Q Y ' v ",
+"- A.u r q b.p.-.#.i.f.Q U L ) v ",
+"* g r q 8 c. at .` _ o.y.U K J ( c ",
+"* f q 8 6 x.+.:.;.X.t.K H G / x ",
+"% d 7 6 3 h.O.> : .e.H G A ^ x ",
+"% s 6 2 1 g.d... .e.q.D A Z E j ",
+"# a 2 < , d.w.7.6.9.0.A Z C T j ",
+"@ i y e 9 v.z.l.s.y.a.! R T U h ",
+"@ O X X . ,.<.>.=.*.&.l j j h h ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/ME.xpm b/src/images/flags/ME.xpm
new file mode 100644
index 0000000..7fdd06f
--- /dev/null
+++ b/src/images/flags/ME.xpm
@@ -0,0 +1,167 @@
+/* XPM */
+static const char *ME_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 145 2",
+" c black",
+". c #5D5D3B3B6868",
+"X c #0F0F6565B1B1",
+"o c #0E0E6666B1B1",
+"O c #21219C9C7C7C",
+"+ c #4242A6A66868",
+"@ c #C8C803030808",
+"# c #CACA03030808",
+"$ c #CBCB03030808",
+"% c #CCCC03030808",
+"& c #CDCD03030808",
+"* c #CFCF03030808",
+"= c #D0D003030909",
+"- c #D1D103030909",
+"; c #D2D203030909",
+": c #D4D403030909",
+"> c #D5D503030909",
+", c #D6D603030909",
+"< c #D7D703030909",
+"1 c #D8D803030909",
+"2 c #D9D903030909",
+"3 c #DBDB03030909",
+"4 c #DCDC03030909",
+"5 c #DDDD03030909",
+"6 c #DFDF03030909",
+"7 c #E4E400000606",
+"8 c #E0E003030909",
+"9 c #E1E103030909",
+"0 c #E3E303030909",
+"q c #E4E403030909",
+"w c #E5E504040909",
+"e c #E7E704040909",
+"r c #E8E804040909",
+"t c #EAEA04040A0A",
+"y c #EBEB04040A0A",
+"u c #ECEC04040A0A",
+"i c #EEEE04040A0A",
+"p c #EFEF04040A0A",
+"a c #F0F004040A0A",
+"s c #F1F104040A0A",
+"d c #F3F304040A0A",
+"f c #F4F404040A0A",
+"g c #F5F504040A0A",
+"h c #F6F604040A0A",
+"j c #F7F704040A0A",
+"k c #FAFA04040A0A",
+"l c #E3E324241212",
+"z c #ECEC21211212",
+"x c #D4D441413535",
+"c c #D5D541413535",
+"v c #D7D741413535",
+"b c #D8D841413535",
+"n c #D9D941413535",
+"m c #DBDB41413535",
+"M c #DCDC41413636",
+"N c #DDDD41413636",
+"B c #D8D864642626",
+"V c #DCDC68682626",
+"C c #DEDE77772B2B",
+"Z c #E0E041413636",
+"A c #E1E141413636",
+"S c #E2E241413636",
+"D c #E3E341413636",
+"F c #E5E541413636",
+"G c #E7E741413636",
+"H c #E8E841413636",
+"J c #EAEA41413636",
+"K c #ECEC42423636",
+"L c #EDED42423636",
+"P c #EEEE42423636",
+"I c #F0F042423737",
+"U c #F2F242423737",
+"Y c #F3F342423737",
+"T c #F4F442423737",
+"R c #F6F642423737",
+"E c #F8F842423737",
+"W c #FBFB42423737",
+"Q c #FCFC42423737",
+"! c #E9E96F6F2929",
+"~ c #DEDE9C9C3232",
+"^ c #D8D8A7A72A2A",
+"/ c #DADAA9A92A2A",
+"( c #DBDBAAAA2A2A",
+") c #DEDEADAD2A2A",
+"_ c #D5D5B2B23535",
+"` c #D6D6B3B33535",
+"' c #D8D8B3B33535",
+"] c #D8D8B5B53535",
+"[ c #D9D9B5B53535",
+"{ c #DBDBB7B73737",
+"} c #DDDDB8B83737",
+"| c #DFDFB9B93838",
+" . c #E2E294943333",
+".. c #E6E696963434",
+"X. c #E8E89C9C3333",
+"o. c #F0F088883131",
+"O. c #F3F38A8A3131",
+"+. c #E1E1AEAE2B2B",
+"@. c #E3E3A0A03434",
+"#. c #E8E8A4A43737",
+"$. c #EBEBAEAE3A3A",
+"%. c #E3E3B0B02C2C",
+"&. c #E7E7B3B32C2C",
+"*. c #EBEBB5B52E2E",
+"=. c #EFEFB9B92F2F",
+"-. c #E3E3B4B43D3D",
+";. c #E7E7B5B53D3D",
+":. c #E1E1BCBC3838",
+">. c #E3E3BDBD3939",
+",. c #E6E6B8B83F3F",
+"<. c #EDEDB6B63E3E",
+"1. c #EBEBBABA3F3F",
+"2. c #E8E8BCBC3B3B",
+"3. c #F2F2BCBC3030",
+"4. c #D3D3ACAC4444",
+"5. c #E3E3BCBC4040",
+"6. c #E9E9BCBC4040",
+"7. c #E6E6C0C03A3A",
+"8. c #E7E7C1C13A3A",
+"9. c #EBEBC3C33C3C",
+"0. c #EDEDC6C63C3C",
+"q. c #EFEFC7C73D3D",
+"w. c #F2F2CBCB3E3E",
+"e. c #F6F6CECE3F3F",
+"r. c #FEFED4D43838",
+"t. c #FFFFD8D83939",
+"y. c #FFFFDBDB3A3A",
+"u. c #FFFFDFDF3C3C",
+"i. c #FFFFE2E23D3D",
+"p. c #FFFFE6E63E3E",
+"a. c #FFFFE7E73E3E",
+"s. c #FFFFE9E93F3F",
+"d. c #FFFFEBEB3F3F",
+"f. c #FFFFEDED3F3F",
+"g. c #FAFAD0D04141",
+"h. c #FBFBD1D14141",
+"j. c #FEFED4D44141",
+"k. c #FFFFD6D64242",
+"l. c #FFFFD8D84343",
+"z. c #FFFFDADA4343",
+"x. c #FFFFDDDD4545",
+"c. c #FFFFDEDE4545",
+"v. c #FFFFDFDF4646",
+"b. c #FFFFE1E14646",
+"n. c None",
+/* pixels */
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"b.b.b.b.b.c.c.c.z.z.k.k.h.h.e.w.",
+"f.Q Q W W R W R R I I P P H H 3.",
+"d.Q k g g g s s y p e 0 8 5 G =.",
+"d.W g d d d p X.#.7 8 8 5 3 S *.",
+"p.W d d p o.z $. at .l ..5 3 : S &.",
+"p.R p p t o.<.X o ;. .3 : : N +.",
+"i.I p y y ! 1.O + -.V : = = m +.",
+"u.P e e 8 8 5 6.,.4.. = = * m ) ",
+"y.P 0 8 8 5 2.C 5.B ~ * # # c ( ",
+"y.H 5 3 3 3 : = = * * # # @ c ( ",
+"r.G F F S S N m m m m c c c c ^ ",
+"q.0.9.7.7.>.>.| | ] ] ] ' ` ` ` ",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n."
+};
diff --git a/src/images/flags/MG.xpm b/src/images/flags/MG.xpm
new file mode 100644
index 0000000..c76256f
--- /dev/null
+++ b/src/images/flags/MG.xpm
@@ -0,0 +1,156 @@
+/* XPM */
+static const char *MG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 134 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002D2D0000",
+"O c #00002F2F0000",
+"+ c #000031310000",
+"@ c #000033330000",
+"# c #000035350000",
+"$ c #000039390000",
+"% c #00003D3D0000",
+"& c #00003F3F0000",
+"* c #000041410000",
+"= c #000047470000",
+"- c #00005D5D0000",
+"; c #0B0B95950B0B",
+": c #0F0F97970E0E",
+"> c #101097971010",
+", c #131399991313",
+"< c #141499991414",
+"1 c #18189C9C1919",
+"2 c #19199C9C1919",
+"3 c #1E1E9F9F1E1E",
+"4 c #1F1F9F9F1F1F",
+"5 c #1414A3A31414",
+"6 c #1919A5A51919",
+"7 c #1F1FA8A81F1F",
+"8 c #2323A1A12323",
+"9 c #2424A2A22424",
+"0 c #2424ABAB2424",
+"q c #2929A4A42929",
+"w c #2A2AA4A42A2A",
+"e c #2C2CA2A22C2C",
+"r c #2F2FA4A42F2F",
+"t c #2E2EA6A62E2E",
+"y c #2F2FA7A72F2F",
+"u c #2A2AADAD2A2A",
+"i c #2F2FB0B02F2F",
+"p c #3232A5A53232",
+"a c #3333A6A63232",
+"s c #3434A9A93434",
+"d c #3535A8A83535",
+"f c #3535ADAD3535",
+"g c #3939A9A93939",
+"h c #3B3BAEAE3A3A",
+"j c #3D3DACAC3D3D",
+"k c #3636B0B03636",
+"l c #4242AEAE4242",
+"z c #4646B0B04646",
+"x c #4B4BB1B14B4B",
+"c c #4D4DB4B44D4D",
+"v c #5252B7B75252",
+"b c #5555BBBB5858",
+"n c #6464BDBD6464",
+"m c #9B9B00000000",
+"M c #CECE31311A1A",
+"N c #D1D135351F1F",
+"B c #D2D23A3A2525",
+"V c #D4D43F3F2B2B",
+"C c #E7E700000000",
+"Z c #E9E900000000",
+"A c #EBEB00000000",
+"S c #EDED00000000",
+"D c #EFEF00000000",
+"F c #F1F100000000",
+"G c #F3F300000000",
+"H c #F5F500000000",
+"J c #F7F700000000",
+"K c #F9F900000000",
+"L c #FBFB00000000",
+"P c #FDFD00000000",
+"I c #F4F420202020",
+"U c #F5F525252525",
+"Y c #F5F526262626",
+"T c #F6F62B2B2B2B",
+"R c #F6F62C2C2C2C",
+"E c #F7F730303030",
+"W c #F7F731313131",
+"Q c #F5F53F3F3F3F",
+"! c #F8F836363636",
+"~ c #F8F837373636",
+"^ c #F8F837373737",
+"/ c #F9F93B3B3C3C",
+"( c #F9F93C3C3C3C",
+") c #F9F93C3C3D3D",
+"_ c #D6D644443030",
+"` c #D5D54E4E3B3B",
+"' c #D8D849493636",
+"] c #D9D94E4E3B3B",
+"[ c #DBDB52524040",
+"{ c #F6F644444444",
+"} c #F7F749494949",
+"| c #F7F74E4E4E4E",
+" . c #FAFA41414141",
+".. c #FAFA41414242",
+"X. c #FAFA42424242",
+"o. c #FBFB46464646",
+"O. c #FBFB47474747",
+"+. c #FCFC4B4B4B4B",
+"@. c #FCFC4C4C4C4C",
+"#. c #F8F853535353",
+"$. c #F9F957575757",
+"%. c #FDFD51515151",
+"&. c #FAFA5C5C5C5C",
+"*. c #E7E767675D5D",
+"=. c #FBFB60606060",
+"-. c #FCFC60606262",
+";. c #FCFC65656565",
+":. c #FDFD66666666",
+">. c #FCFC69696969",
+",. c #FDFD6A6A6A6A",
+"<. c #FDFD6D6D6D6D",
+"1. c #FDFD70707171",
+"2. c #FEFE85858585",
+"3. c gray85",
+"4. c gray86",
+"5. c #DFDFDFDFDFDF",
+"6. c #E1E1E1E1E1E1",
+"7. c gray89",
+"8. c gray90",
+"9. c #E7E7E7E7E7E7",
+"0. c #E9E9E9E9E9E9",
+"q. c gray92",
+"w. c gray93",
+"e. c #EFEFEFEFEFEF",
+"r. c #F9F9F9F9F9F9",
+"t. c gray98",
+"y. c #FBFBFBFBFBFB",
+"u. c #FBFBFCFCFBFB",
+"i. c gray99",
+"p. c #FDFDFCFCFDFD",
+"a. c #FDFDFDFDFDFD",
+"s. c #FEFEFEFEFEFE",
+"d. c gray100",
+"f. c None",
+/* pixels */
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"e.e.e.e.e.P P P L L J J G G S S ",
+"e.d.d.t.d.2.1.<.>.;.=.&.$.#.| A ",
+"e.d.d.d.d.>.%. at .O...) ^ W R } A ",
+"e.d.d.d.d.;.+.o...) ^ W T Y { C ",
+"e.d.d.t.t.=.o...) ^ R T Y I Q C ",
+"0.d.d.u.d.*.] ] ' _ _ B M M ` m ",
+"0.d.u.u.u.b h f i u 0 8 6 5 k = ",
+"0.d.t.u.t.v s y q 8 4 1 < > a @ ",
+"9.y.t.t.t.c r q 8 7 1 > : ; r o ",
+"9.t.t.t.t.n x z l j g d a r e . ",
+"6.6.5.3.3.- * % * % $ @ o o X # ",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f."
+};
diff --git a/src/images/flags/MH.xpm b/src/images/flags/MH.xpm
new file mode 100644
index 0000000..b6de57a
--- /dev/null
+++ b/src/images/flags/MH.xpm
@@ -0,0 +1,181 @@
+/* XPM */
+static const char *MH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 159 2",
+" c black",
+". c #000000001313",
+"X c #000000001717",
+"o c #000000001919",
+"O c #000000001B1B",
+"+ c #000000001F1F",
+"@ c #000000002525",
+"# c #000000002727",
+"$ c #000000002D2D",
+"% c #000000003333",
+"& c #000000003939",
+"* c #000000003F3F",
+"= c #3B3B00000000",
+"- c #000000004545",
+"; c #000000004B4B",
+": c #000000004F4F",
+"> c #000000005151",
+", c #000000005555",
+"< c #000000005B5B",
+"1 c #000000005F5F",
+"2 c #000000006565",
+"3 c #000000006969",
+"4 c #000000006B6B",
+"5 c #000000006D6D",
+"6 c #000000006F6F",
+"7 c #000000007171",
+"8 c #000000007373",
+"9 c #000001017575",
+"0 c #000003037575",
+"q c #000007077777",
+"w c #000009097979",
+"e c #000009097B7B",
+"r c #0F0F29297373",
+"t c #474743436B6B",
+"y c #12123D3D8F8F",
+"u c #14143B3B8F8F",
+"i c #161641419292",
+"p c #171741419292",
+"a c #191940409292",
+"s c #181843439393",
+"d c #1B1B44449494",
+"f c #1E1E48489696",
+"g c #1E1E48489797",
+"h c #202049499797",
+"j c #232349499797",
+"k c #2C2C50509B9B",
+"l c #323257579E9E",
+"z c #353559599E9E",
+"x c #363659599F9F",
+"c c #34345A5AA2A2",
+"v c #36365B5BA1A1",
+"b c #37375C5CA1A1",
+"n c #38385C5CA1A1",
+"m c #3B3B6060A4A4",
+"M c #3C3C6464ADAD",
+"N c #3D3D6565B0B0",
+"B c #545467679C9C",
+"V c #5E5E67679595",
+"C c #40406262A4A4",
+"Z c #42426565A7A7",
+"A c #46466262A2A2",
+"S c #42426767AEAE",
+"D c #47476969A9A9",
+"F c #47476A6AADAD",
+"G c #4D4D6969A7A7",
+"H c #4A4A6A6AABAB",
+"J c #4B4B6A6AABAB",
+"K c #49496D6DAFAF",
+"L c #4C4C6E6EAFAF",
+"P c #41416868B2B2",
+"I c #42426969B0B0",
+"U c #45456868B2B2",
+"Y c #46466A6AB1B1",
+"T c #49496F6FB4B4",
+"R c #4E4E7171B0B0",
+"E c #4F4F7171B0B0",
+"W c #50507171B1B1",
+"Q c #51517272B1B1",
+"! c #53537474B2B2",
+"~ c #53537575B3B3",
+"^ c #54547575B3B3",
+"/ c #55557575B3B3",
+"( c #58587979B4B4",
+") c #58587979B5B5",
+"_ c #5C5C7A7AB2B2",
+"` c #58587A7AB9B9",
+"' c #5E5E7F7FB9B9",
+"] c #6F6F71719696",
+"[ c #727269698484",
+"{ c #7E7E7E7E9D9D",
+"} c #65658181B9B9",
+"| c #65658282B9B9",
+" . c #66668383BDBD",
+".. c #6B6B8383B1B1",
+"X. c #6A6A8686BCBC",
+"o. c #6C6C8686B9B9",
+"O. c #6E6E8A8ABEBE",
+"+. c #6F6F8B8BBEBE",
+"@. c #71718D8DC0C0",
+"#. c #72728E8EC0C0",
+"$. c #71718F8FC4C4",
+"%. c #75758F8FC2C2",
+"&. c #71719090C5C5",
+"*. c #75759090C2C2",
+"=. c #78789292C3C3",
+"-. c #7F7F9898C7C7",
+";. c #84846B6B7777",
+":. c #959575757777",
+">. c #AFAF6F6F5959",
+",. c #BBBB78785D5D",
+"<. c #A2A26E6E6262",
+"1. c #EBEB00000000",
+"2. c #D3D374743C3C",
+"3. c #E9E95D5D0000",
+"4. c #F2F276762C2C",
+"5. c #E2E27E7E4141",
+"6. c #F6F681812D2D",
+"7. c #F7F781813535",
+"8. c #D2D28A8A6262",
+"9. c #F7F792924B4B",
+"0. c #F5F5A5A56F6F",
+"q. c #F7F7A9A96B6B",
+"w. c #F6F6A8A86E6E",
+"e. c #F8F8A8A86A6A",
+"r. c #F1F1A6A67474",
+"t. c #B2B2A4A4ACAC",
+"y. c #84849B9BC8C8",
+"u. c #85859B9BC8C8",
+"i. c #8A8A9E9EC6C6",
+"p. c #9797A7A7CECE",
+"a. c #9090A7A7D1D1",
+"s. c #9D9DADADD1D1",
+"d. c #9C9CADADD2D2",
+"f. c #AEAEB8B8CFCF",
+"g. c #A3A3B3B3D5D5",
+"h. c #A9A9B6B6D6D6",
+"j. c #B6B6C2C2DDDD",
+"k. c #B9B9C3C3DCDC",
+"l. c #BFBFC7C7D9D9",
+"z. c #B5B5C5C5E1E1",
+"x. c #CFCF9D9D8282",
+"c. c #D8D8C1C1B9B9",
+"v. c #F5F5CDCDAEAE",
+"b. c #F7F7DEDEBFBF",
+"n. c #F8F8D8D8B8B8",
+"m. c #C3C3CBCBE2E2",
+"M. c #D6D6DADAE6E6",
+"N. c #D7D7E0E0EEEE",
+"B. c #F5F5DEDECCCC",
+"V. c #F6F6E3E3CCCC",
+"C. c #F6F6E2E2D3D3",
+"Z. c #E7E7E7E7E7E7",
+"A. c #EEEEEFEFF3F3",
+"S. c #EEEEF3F3F5F5",
+"D. c #F4F4F4F4F4F4",
+"F. c gray96",
+"G. c #FDFDFDFDFEFE",
+"H. c #FEFEFEFEFEFE",
+"J. c None",
+/* pixels */
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"e e e e q 0 7 5 3 2 1 < , > : = ",
+"e y.j.m.y.=.%.+.+.X.} ' ` { 8.1.",
+"e d.H.H.p.( / Q L F N A <.4.9.3.",
+"e g.H.H.d./ E L I M [ 2.6.0.C.Z.",
+"0 -.h.k.} E K P B >.7.w.B.D.S...",
+"7 *.) ~ R F S ;.5.q.V.D.N.i._ @ ",
+"5 $.Q R U V ,.q.b.A.z.o.k u v + ",
+"5 +.T G :.r.n.M.a.J j p s p n O ",
+"2 .] x.v.l.$.v j g g d p y x X ",
+"1 t.c.f.$.E J J D Z C m b x l . ",
+"t r 3 ; - - & % $ @ @ + O X . . ",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J."
+};
diff --git a/src/images/flags/MK.xpm b/src/images/flags/MK.xpm
new file mode 100644
index 0000000..912992e
--- /dev/null
+++ b/src/images/flags/MK.xpm
@@ -0,0 +1,187 @@
+/* XPM */
+static const char *MK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 165 2",
+" c black",
+". c #DDDD00000000",
+"X c #DDDD03030000",
+"o c #DFDF00000000",
+"O c #E1E100000000",
+"+ c #E3E300000000",
+"@ c #E5E500000000",
+"# c #E7E700000000",
+"$ c #E9E900000000",
+"% c #EBEB00000000",
+"& c #EDED00000000",
+"* c #EFEF00000000",
+"= c #F1F100000000",
+"- c #F3F300000000",
+"; c #F5F500000000",
+": c #F7F700000000",
+"> c #F9F900000000",
+", c #FBFB00000000",
+"< c #FDFD00000000",
+"1 c red",
+"2 c #F2F210101010",
+"3 c #F3F319191919",
+"4 c #F4F41E1E1E1E",
+"5 c #EFEF31310000",
+"6 c #EBEB3D3D0000",
+"7 c #F3F32C2C1919",
+"8 c #F4F42D2D1F1F",
+"9 c #FDFD35350000",
+"0 c #FDFD39390000",
+"q c #F5F526262626",
+"w c #F5F52D2D2424",
+"e c #F5F52E2E2525",
+"r c #F7F72E2E2E2E",
+"t c #F6F638382B2B",
+"y c #F3F332323232",
+"u c #F3F335353535",
+"i c #F4F439393939",
+"p c #F5F53E3E3D3D",
+"a c #F8F834343434",
+"s c #F8F83E3E3434",
+"d c #F9F93C3C3D3D",
+"f c #F3F34D4D0000",
+"g c #F7F74D4D0000",
+"h c #F2F240401414",
+"j c #F2F241411414",
+"k c #F2F25A5A1313",
+"l c #F4F440402020",
+"z c #F2F247472F2F",
+"x c #F2F24B4B3232",
+"c c #F9F942423C3C",
+"v c #F6F65D5D2B2B",
+"b c #FFFF67670000",
+"n c #FFFF77770000",
+"m c #F4F479791F1F",
+"M c #F5F565652424",
+"N c #F6F66F6F2A2A",
+"B c #F4F46E6E3636",
+"V c #F5F56C6C3F3F",
+"C c #F8F86C6C3737",
+"Z c #F6F676762A2A",
+"A c #F7F777772F2F",
+"S c #F7F772723030",
+"D c #F8F876763636",
+"F c #F9F979793A3A",
+"G c #F9F97C7C3A3A",
+"H c #F6F644444444",
+"J c #F7F74B4B4B4B",
+"K c #FAFA42424242",
+"L c #FBFB49494949",
+"P c #FBFB51514545",
+"I c #FCFC51514B4B",
+"U c #FBFB5A5A4949",
+"Y c #F8F850505050",
+"T c #F9F954545555",
+"R c #FDFD51515151",
+"E c #FDFD54545454",
+"W c #FDFD59595050",
+"Q c #FDFD5C5C5454",
+"! c #FAFA5C5C5C5C",
+"~ c #FEFE5C5C5C5C",
+"^ c #F7F765654949",
+"/ c #FBFB66664545",
+"( c #F9F968685757",
+") c #F9F96F6F5858",
+"_ c #FCFC71714F4F",
+"` c #FAFA79794040",
+"' c #FEFE71715858",
+"] c #FEFE7F7F5959",
+"[ c #FBFB60606060",
+"{ c #FCFC66666565",
+"} c #FCFC6A6A6A6A",
+"| c #FCFC78786666",
+" . c #FDFD70707171",
+".. c #FEFE74747474",
+"X. c #FEFE77777777",
+"o. c #FEFE79797979",
+"O. c #F1F194940B0B",
+"+. c #F3F39D9D1919",
+"@. c #F6F684842B2B",
+"#. c #F7F78F8F3030",
+"$. c #F8F884843636",
+"%. c #F9F98D8D3A3A",
+"&. c #F6F6A7A72929",
+"*. c #F5F5ACAC2323",
+"=. c #F6F6AEAE2C2C",
+"-. c #F7F7AEAE3131",
+";. c #FAFAAFAF3F3F",
+":. c #F5F5B6B62525",
+">. c #F2F2BEBE2F2F",
+",. c #F7F7BFBF2F2F",
+"<. c #F9F9BCBC3C3C",
+"1. c #FBFB83834646",
+"2. c #FCFC84844B4B",
+"3. c #FAFA89894242",
+"4. c #FBFB89894747",
+"5. c #FEFE88885959",
+"6. c #FAFA96964040",
+"7. c #FBFB96964646",
+"8. c #FDFD97975151",
+"9. c #FEFE88887979",
+"0. c #FFFF8F8F7A7A",
+"q. c #FDFD99996F6F",
+"w. c #FEFE97977676",
+"e. c #FAFAAFAF4444",
+"r. c #FAFABEBE4141",
+"t. c #FBFBBEBE4747",
+"y. c #FCFCBABA4C4C",
+"u. c #FDFDBFBF5454",
+"i. c #DDDDDDDD0000",
+"p. c #E7E7C5C50000",
+"a. c #E9E9C7C70000",
+"s. c #F1F1CACA0E0E",
+"d. c #F4F4D8D81F1F",
+"f. c #F8F8C0C03535",
+"g. c #F7F7D4D43131",
+"h. c #FAFADBDB3F3F",
+"j. c #E5E5E5E50000",
+"k. c #EDEDEFEF0000",
+"l. c #FBFBE3E30000",
+"z. c #FDFDE3E30000",
+"x. c #F3F3E6E61A1A",
+"c. c #F5F5F5F50000",
+"v. c #FDFDFDFD0000",
+"b. c yellow",
+"n. c #F2F2E3E32C2C",
+"m. c #F4F4F4F43B3B",
+"M. c #F8F8F8F83636",
+"N. c #F9F9F9F93B3B",
+"B. c #F6F6CFCF4242",
+"V. c #F7F7CDCD4646",
+"C. c #FCFCC8C84B4B",
+"Z. c #F8F8C7C75353",
+"A. c #FEFEC4C45F5F",
+"S. c #FAFAD3D35D5D",
+"D. c #FCFCDEDE6969",
+"F. c #FDFDDDDD6D6D",
+"G. c #FFFFD9D97B7B",
+"H. c #F7F7EFEF4E4E",
+"J. c #FCFCE7E74F4F",
+"K. c #FEFEE2E25C5C",
+"L. c #FDFDF3F35353",
+"P. c #FBFBF0F06262",
+"I. c #FFFFF7F77B7B",
+"U. c #FEFEFDFD7373",
+"Y. c None",
+/* pixels */
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"b.b 1 1 , 1 1 z.l., : : = = 5 k.",
+"n I.G.9.X.X. .F.D.{ [ ! ( Z.H.6 ",
+"1 0.A.K.5.R R y.t.K d C g.=.^ % ",
+"1 o.~ ] u.8.I 4.3.c $.-.v q H # ",
+"9 w.' Q W 2.1.r.<.D S t e l V # ",
+"b.U.L.J.C.7.6.N.M.#. at .:.d.x.m.j.",
+"0 q._ U P ` G f.,.N M 8 7 h B + ",
+", } L / ;.%.s A Z e m +.h 2 y o ",
+", | e.h.F a r &.*.4 3 k s.O.z o ",
+"f P.S.) T Y J V.B.p i u x >.n.o ",
+"c.f = & & & % a.p.# + + o o X i.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y."
+};
diff --git a/src/images/flags/ML.xpm b/src/images/flags/ML.xpm
new file mode 100644
index 0000000..1a55015
--- /dev/null
+++ b/src/images/flags/ML.xpm
@@ -0,0 +1,171 @@
+/* XPM */
+static const char *ML_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 149 2",
+" c black",
+". c #000053530000",
+"X c #00005B5B0000",
+"o c #000063630000",
+"O c #000067670000",
+"+ c #00006F6F0000",
+"@ c #000075750000",
+"# c #000077770000",
+"$ c #00007B7B0000",
+"% c #00007F7F0000",
+"& c #000083830000",
+"* c #000085850000",
+"= c #000087870000",
+"- c #000089890000",
+"; c #000091910000",
+": c #3A3AAAAA3A3A",
+"> c #3F3FAEAE3F3F",
+", c #4040ADAD3F3F",
+"< c #4444B1B14444",
+"1 c #4545B0B04545",
+"2 c #4545B1B14545",
+"3 c #4B4BB3B34B4B",
+"4 c #4949B4B44949",
+"5 c #4F4FB6B64F4F",
+"6 c #4F4FB7B74F4F",
+"7 c #5050B5B55050",
+"8 c #5454B5B55555",
+"9 c #5454B7B75454",
+"0 c #5353B9B95353",
+"q c #5454B9B95454",
+"w c #5858B9B95858",
+"e c #5858BBBB5959",
+"r c #5959BABA5959",
+"t c #5858BCBC5858",
+"y c #5C5CBDBD5C5C",
+"u c #5D5DBCBC5D5D",
+"i c #5F5FBFBF5F5F",
+"p c #6161BEBE6262",
+"a c #6666C0C06666",
+"s c #6A6AC3C36A6A",
+"d c #6F6FC4C46F6F",
+"f c #7272C6C67373",
+"g c #7777C7C77777",
+"h c #7676C8C87676",
+"j c #7979C8C87979",
+"k c #7B7BCACA7A7A",
+"l c #7B7BCACA7B7B",
+"z c #DDDD00000000",
+"x c #DFDF00000000",
+"c c #E1E100000000",
+"v c #E3E300000000",
+"b c #E5E500000000",
+"n c #E7E700000000",
+"m c #E9E900000000",
+"M c #EBEB00000000",
+"N c #EDED00000000",
+"B c #EFEF00000000",
+"V c #F1F100000000",
+"C c #F3F300000000",
+"Z c #F5F500000000",
+"A c #F1F10B0B0B0B",
+"S c #F1F10F0F0E0E",
+"D c #F2F210101010",
+"F c #F2F213131313",
+"G c #F2F214141414",
+"H c #F3F319191919",
+"J c #F3F31A1A1A1A",
+"K c #F4F41F1F1F1F",
+"L c #F4F420202020",
+"P c #F5F525252525",
+"I c #F5F526262626",
+"U c #F2F22C2C2C2C",
+"Y c #F2F22F2F2F2F",
+"T c #F6F62B2B2B2B",
+"R c #F6F62C2C2C2C",
+"E c #F2F232323232",
+"W c #F3F332323232",
+"Q c #F3F335353535",
+"! c #F7F731313131",
+"~ c #F4F436363636",
+"^ c #F4F43B3B3B3B",
+"/ c #F5F53F3F3F3F",
+"( c #F8F837373737",
+") c #F6F644444444",
+"_ c #F7F749494949",
+"` c #F7F74E4E4E4E",
+"' c #F8F853535353",
+"] c #F9F957575757",
+"[ c #FAFA5C5C5C5C",
+"{ c #E3E3A3A30000",
+"} c #CBCBDFDF0000",
+"| c #F7F7C5C50000",
+" . c #F3F3D3D31919",
+".. c #F4F4D5D51F1F",
+"X. c #F5F5D7D72424",
+"o. c #F6F6D9D92B2B",
+"O. c #F7F7DADA3030",
+"+. c #F4F4D8D83939",
+"@. c #F8F8DCDC3636",
+"#. c #F9F9DEDE3D3D",
+"$. c #E5E5E5E50000",
+"%. c #E7E7E7E70000",
+"&. c #E9E9E9E90000",
+"*. c #EBEBEBEB0000",
+"=. c #E3E3F3F30000",
+"-. c #F9F9F9F90000",
+";. c #FBFBFBFB0000",
+":. c #FDFDFDFD0000",
+">. c #F4F4F4F41E1E",
+",. c #E8E8F2F23434",
+"<. c #E9E9F3F33A3A",
+"1. c #F5F5F5F52323",
+"2. c #F5F5F5F52424",
+"3. c #F6F6F6F62929",
+"4. c #F6F6F6F62A2A",
+"5. c #F7F7F7F72E2E",
+"6. c #F7F7F7F72F2F",
+"7. c #F7F7F7F73030",
+"8. c #F5F5F5F53D3D",
+"9. c #F8F8F8F83434",
+"0. c #F8F8F8F83535",
+"q. c #F8F8F8F83636",
+"w. c #F9F9F9F93A3A",
+"e. c #F9F9F9F93B3B",
+"r. c #F9F9F9F93C3C",
+"t. c #EBEBF4F44040",
+"y. c #ECECF5F54646",
+"u. c #EDEDF6F64B4B",
+"i. c #EAEAF3F35050",
+"p. c #EEEEF7F75151",
+"a. c #F6F6F6F64242",
+"s. c #F7F7F7F74646",
+"d. c #F7F7F7F74B4B",
+"f. c #FAFAFAFA4040",
+"g. c #FAFAFAFA4141",
+"h. c #FAFAFAFA4242",
+"j. c #FBFBFBFB4646",
+"k. c #FBFBFBFB4747",
+"l. c #FCFCFCFC4B4B",
+"z. c #FCFCFCFC4C4C",
+"x. c #F0F0F8F85454",
+"c. c #FDFDFDFD5151",
+"v. c #FBFBE4E46060",
+"b. c #FCFCFCFC6565",
+"n. c #FCFCFCFC6969",
+"m. c #FDFDFDFD6D6D",
+"M. c #F3F3FAFA7474",
+"N. c #FDFDFDFD7171",
+"B. c None",
+/* pixels */
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"; - - = & =.:.:.;.-.| Z V V B B ",
+"= l l l g M.N.m.n.b.v.[ ] ' ` B ",
+"- l i y q x.c.z.j.j.#.( ! R _ n ",
+"= l r r q p.z.k.h.r. at .! T I ) n ",
+"= g r 0 7 u.k.g.r.q.o.T I L / n ",
+"& f 0 6 3 u.h.w.q.7.o.I K H ^ n ",
+"% d 6 4 1 <.w.q.7.4.X.K H F ~ c ",
+"$ s 4 1 , <.9.5.4.2...H F F W x ",
+"# a < > : ,.5.4.1.>. .F S A Y x ",
+"+ p u w 8 i.d.s.a.8.+.Q W Y U x ",
+"# O o X . } *.*.$.$.{ c x x z z ",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B."
+};
diff --git a/src/images/flags/MM.xpm b/src/images/flags/MM.xpm
new file mode 100644
index 0000000..ab80afa
--- /dev/null
+++ b/src/images/flags/MM.xpm
@@ -0,0 +1,154 @@
+/* XPM */
+static const char *MM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 132 2",
+" c black",
+". c #00000000B7B7",
+"X c #00000000C1C1",
+"o c #00000000C3C3",
+"O c #00000000C5C5",
+"+ c #00000000C7C7",
+"@ c #00000000C9C9",
+"# c #45453B3BCECE",
+"$ c #46464141D3D3",
+"% c #47474040D3D3",
+"& c #46464646DDDD",
+"* c #4B4B4646D3D3",
+"= c #4C4C4747D5D5",
+"- c #4B4B4B4BDBDB",
+"; c #51514C4CD7D7",
+": c #51515151DDDD",
+"> c #55555858DEDE",
+", c #5E5E5757D6D6",
+"< c #5D5D5858D7D7",
+"1 c #6C6C6565DADA",
+"2 c #71716D6DDFDF",
+"3 c #76767272DEDE",
+"4 c #70707070E4E4",
+"5 c #77777979E5E5",
+"6 c #79797979E3E3",
+"7 c #7D7D7D7DE4E4",
+"8 c #DDDD00000000",
+"9 c #DFDF00000000",
+"0 c #E1E100000000",
+"q c #E3E300000000",
+"w c #E5E500000000",
+"e c #E7E700000000",
+"r c #E9E900000000",
+"t c #EBEB00000000",
+"y c #EDED00000000",
+"u c #EFEF00000000",
+"i c #F1F100000000",
+"p c #F3F300000000",
+"a c #F5F500000000",
+"s c #F7F700000000",
+"d c #F1F10B0B0B0B",
+"f c #F1F10F0F0E0E",
+"g c #F9F900000000",
+"h c #FBFB00000000",
+"j c #F2F210101010",
+"k c #F2F213131313",
+"l c #F2F214141414",
+"z c #F3F319191919",
+"x c #F3F31A1A1A1A",
+"c c #F4F41E1E1E1E",
+"v c #F4F41F1F1F1F",
+"b c #F4F420202020",
+"n c #F5F523232323",
+"m c #F5F524242424",
+"M c #F5F525252525",
+"N c #F5F526262626",
+"B c #F2F22C2C2C2C",
+"V c #F2F22F2F2F2F",
+"C c #F6F629292929",
+"Z c #F6F62A2A2A2A",
+"A c #F6F62B2B2B2B",
+"S c #F6F62C2C2C2C",
+"D c #F7F72E2E2E2E",
+"F c #F7F72F2F2F2F",
+"G c #F2F232323232",
+"H c #F3F332323232",
+"J c #F3F335353535",
+"K c #F7F730303030",
+"L c #F7F731313131",
+"P c #F4F436363636",
+"I c #F2F235353939",
+"U c #F4F439393939",
+"Y c #F4F43B3B3B3B",
+"T c #F5F53D3D3D3D",
+"R c #F5F53F3F3F3F",
+"E c #F8F834343434",
+"W c #F8F836363636",
+"Q c #F8F837373636",
+"! c #F8F837373737",
+"~ c #F9F93A3A3A3A",
+"^ c #F9F93B3B3C3C",
+"/ c #F9F93C3C3C3C",
+"( c #F9F93C3C3D3D",
+") c #FAFA3F3F3F3F",
+"_ c #F0F03B3B4242",
+"` c #F1F140404747",
+"' c #F6F642424242",
+"] c #F6F644444444",
+"[ c #F7F746464646",
+"{ c #F1F145454C4C",
+"} c #F7F749494949",
+"| c #F7F74B4B4B4B",
+" . c #F7F74E4E4E4E",
+".. c #FAFA41414242",
+"X. c #FAFA42424242",
+"o. c #FAFA44444444",
+"O. c #FBFB45454545",
+"+. c #FBFB47474747",
+"@. c #FBFB49494949",
+"#. c #F1F14A4A5151",
+"$. c #F3F34F4F5656",
+"%. c #F8F850505050",
+"&. c #F8F853535353",
+"*. c #F9F954545555",
+"=. c #F9F957575757",
+"-. c #F9F958585858",
+";. c #FAFA5C5C5C5C",
+":. c #FAFA5D5D5D5D",
+">. c #FBFB60606060",
+",. c #FBFB61616262",
+"<. c #FCFC65656565",
+"1. c #FCFC66666666",
+"2. c #FCFC69696969",
+"3. c #FCFC6A6A6A6A",
+"4. c #F6F66F6F7474",
+"5. c #80808080E5E5",
+"6. c #81818383E7E7",
+"7. c #82828282E6E6",
+"8. c #94949595EAEA",
+"9. c #A9A9ABABEDED",
+"0. c #AEAEAFAFEDED",
+"q. c #B0B0B0B0EEEE",
+"w. c #B4B4B5B5F0F0",
+"e. c #B9B9B9B9F1F1",
+"r. c #BABABABAF0F0",
+"t. c #BABABABAF1F1",
+"y. c #C1C1C1C1F2F2",
+"u. c #DBDBDBDBF7F7",
+"i. c #DCDCDCDCF8F8",
+"p. c #DDDDDDDDF9F9",
+"a. c #DEDEDEDEF8F8",
+"s. c None",
+/* pixels */
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"+ o o @ o o + . h h s s p p y y ",
+"o 7 8.y.t.6 4 2 2.<.>.;.=.&. .t ",
+"o 7.t.a.a.q.: ; +.X.( Q L S } t ",
+"o 7.r.a.u.0.- = X.^ Q L A N ] w ",
+"+ 5 7.q.9.> & $ ^ Q F A N b R w ",
+". 3 , 1 , = $ # Q K A N c z T w ",
+"y 4.$. .{ ` _ I F A m v z k P w ",
+"h 2. at .+._ ~ Q S A m v z l j H 9 ",
+"h <.O.) ~ E S Z b c z k f d V 9 ",
+"s ,.:.-.=. .| ] ' R U J H V B 9 ",
+"s p p y y y y t t w 0 0 9 9 8 8 ",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s."
+};
diff --git a/src/images/flags/MN.xpm b/src/images/flags/MN.xpm
new file mode 100644
index 0000000..fc75f1a
--- /dev/null
+++ b/src/images/flags/MN.xpm
@@ -0,0 +1,165 @@
+/* XPM */
+static const char *MN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 143 2",
+" c black",
+". c #00000000D3D3",
+"X c #00000000D9D9",
+"o c #00000000E5E5",
+"O c #00000000E7E7",
+"+ c #00000000E9E9",
+"@ c #00000000EBEB",
+"# c #00000000EFEF",
+"$ c #00000000F9F9",
+"% c #00000000FBFB",
+"& c #00000000FDFD",
+"* c #1E1E1919EEEE",
+"= c #1E1E1E1EF4F4",
+"- c #24241F1FEFEF",
+"; c #23232323F5F5",
+": c #24242424F5F5",
+"> c #2A2A2424F0F0",
+", c #29292929F6F6",
+"< c #2A2A2A2AF6F6",
+"1 c #2E2E2E2EF7F7",
+"2 c #2F2F2F2FF7F7",
+"3 c #30302B2BF1F1",
+"4 c #30303030F7F7",
+"5 c #35353030F2F2",
+"6 c #34343434F8F8",
+"7 c #35353535F8F8",
+"8 c #36363636F8F8",
+"9 c #3C3C3737F3F3",
+"0 c #3E3E3939F0F0",
+"q c #3D3D3D3DF5F5",
+"w c #3B3B3B3BF9F9",
+"e c #3C3C3C3CF9F9",
+"r c #41413535ECEC",
+"t c #47473B3BEDED",
+"y c #41413C3CF5F5",
+"u c #4D4D4141EEEE",
+"i c #42424242F6F6",
+"p c #46464646F7F7",
+"a c #40404040FAFA",
+"s c #41414141FAFA",
+"d c #42424141FAFA",
+"f c #42424242FAFA",
+"g c #46464646FBFB",
+"h c #47474747FBFB",
+"j c #4B4B4B4BF7F7",
+"k c #4B4B4B4BFCFC",
+"l c #4C4C4C4CFCFC",
+"z c #52524646F0F0",
+"x c #57574C4CF1F1",
+"c c #5B5B5050EEEE",
+"v c #51515151FDFD",
+"b c #5B5B5151F2F2",
+"n c #60605555F2F2",
+"m c #65656060F7F7",
+"M c #65656565FCFC",
+"N c #69696969FCFC",
+"B c #6D6D6D6DFDFD",
+"V c #70707070FEFE",
+"C c #7D7D7575F5F5",
+"Z c #DDDD00000000",
+"A c #DFDF00000000",
+"S c #E1E100000000",
+"D c #E3E300000000",
+"F c #E5E500000000",
+"G c #E7E700000000",
+"H c #E9E900000000",
+"J c #EBEB00000000",
+"K c #EDED00000000",
+"L c #EFEF00000000",
+"P c #F1F100000000",
+"I c #F3F300000000",
+"U c #F5F500000000",
+"Y c #F7F700000000",
+"T c #F1F10B0B0B0B",
+"R c #F1F10F0F0E0E",
+"E c #F9F900000000",
+"W c #FBFB00000000",
+"Q c #FDFD00000000",
+"! c red",
+"~ c #F2F210101010",
+"^ c #F2F213131313",
+"/ c #F2F214141414",
+"( c #F3F319191919",
+") c #F3F31A1A1A1A",
+"_ c #F4F41F1F1F1F",
+"` c #F4F420202020",
+"' c #F5F525252525",
+"] c #F5F526262626",
+"[ c #F2F22C2C2C2C",
+"{ c #F2F22F2F2F2F",
+"} c #F6F62B2B2B2B",
+"| c #F6F62C2C2C2C",
+" . c #F2F232323232",
+".. c #F3F332323232",
+"X. c #F3F335353535",
+"o. c #F7F731313131",
+"O. c #F4F436363636",
+"+. c #F4F43B3B3B3B",
+"@. c #F5F53F3F3F3F",
+"#. c #F8F837373737",
+"$. c #F9F95B5B3A3A",
+"%. c #FAFA5F5F3F3F",
+"&. c #F6F644444444",
+"*. c #F7F749494949",
+"=. c #F7F74E4E4E4E",
+"-. c #F8F853535353",
+";. c #F9F957575757",
+":. c #FDFD56565050",
+">. c #FDFD54545454",
+",. c #F9F95B5B5555",
+"<. c #FAFA5C5C5C5C",
+"1. c #FEFE59595959",
+"2. c #FBFB65654545",
+"3. c #FCFC6A6A4B4B",
+"4. c #FAFA65655D5D",
+"5. c #F9F969695858",
+"6. c #FEFE6B6B5C5C",
+"7. c #FBFB71716262",
+"8. c #FEFE77777777",
+"9. c #FFFF7B7B7A7A",
+"0. c #FFFF7B7B7B7B",
+"q. c #FEFE7F7F7979",
+"w. c #FDFD83835454",
+"e. c #FEFE87877676",
+"r. c #FDFDACAC5353",
+"t. c #FEFEACAC5858",
+"y. c #FAFAB2B24444",
+"u. c #FFFFB5B57B7B",
+"i. c #FAFAD3D33F3F",
+"p. c #FBFBCCCC4949",
+"a. c #FEFEC3C35959",
+"s. c #FEFECECE5F5F",
+"d. c #FCFCD0D04F4F",
+"f. c #FCFCD6D64F4F",
+"g. c #FBFBDADA4545",
+"h. c #FBFBDADA4949",
+"j. c #FEFEDEDE5C5C",
+"k. c #FEFEC8C87979",
+"l. c #FCFCD8D86666",
+"z. c #FCFCDBDB6A6A",
+"x. c #FDFDDDDD6F6F",
+"c. c #FEFEDCDC7373",
+"v. c None",
+/* pixels */
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"! ! ! ! ! + & & % % # U I I K K ",
+"! 0.u.q.8.C V B N M m <.;.-.=.J ",
+"! 0.s.6.1.b v l h f y #.o.| *.J ",
+"! k.j.a.>.b l h f e 9 o.} ] &.F ",
+"! e.t.w.:.x h f e 8 5 } ] ` @.F ",
+"! c.r.f.3.z a q 8 3 > ] _ ( +.J ",
+"! c.p.g.2.u w 6 4 < > _ ( / O.D ",
+"E z.p.g.2.t 6 1 < : - ( ^ ^ .A ",
+"E l.y.i.$.r 1 , : = = ^ R T { A ",
+"U 7.4.5.,.c j p i q 0 X. .{ [ A ",
+"U I I K K . # + o o X D A A Z Z ",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.",
+"v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v."
+};
diff --git a/src/images/flags/MO.xpm b/src/images/flags/MO.xpm
new file mode 100644
index 0000000..3c8eae3
--- /dev/null
+++ b/src/images/flags/MO.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *MO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002D2D0000",
+"O c #00002F2F0000",
+"+ c #000031310000",
+"@ c #000033330000",
+"# c #000035350000",
+"$ c #000039390000",
+"% c #00003B3B0000",
+"& c #00003D3D0000",
+"* c #00003F3F0000",
+"= c #000045450000",
+"- c #00004B4B0000",
+"; c #00004D4D0000",
+": c #000051510000",
+"> c #000057570000",
+", c #00005D5D0000",
+"< c #000061610000",
+"1 c #000063630000",
+"2 c #000067670000",
+"3 c #00006D6D0000",
+"4 c #00006F6F0000",
+"5 c #000071710000",
+"6 c #000075750000",
+"7 c #000077770000",
+"8 c #00007B7B0000",
+"9 c #00007D7D0000",
+"0 c #00007F7F0000",
+"q c #000081810000",
+"w c #000083830000",
+"e c #000085850000",
+"r c #000087870000",
+"t c #000089890000",
+"y c #000091910000",
+"u c #0B0B95950B0B",
+"i c #0F0F97970E0E",
+"p c #101097971010",
+"a c #131398981313",
+"s c #141499991414",
+"d c #14149A9A1414",
+"f c #19199B9B1919",
+"g c #1A1A9C9C1A1A",
+"h c #1B1B9C9C1B1B",
+"j c #20209F9F2020",
+"k c #2525A1A12525",
+"l c #2626A2A22626",
+"z c #2828A2A22B2B",
+"x c #2B2BA5A52B2B",
+"c c #2C2CA2A22C2C",
+"v c #2C2CA6A62C2C",
+"b c #2F2FA4A42F2F",
+"n c #3939AAAA2B2B",
+"m c #3030A5A53030",
+"M c #3232A5A53232",
+"N c #3333A6A63232",
+"B c #3131A9A93131",
+"V c #3535A8A83535",
+"C c #3636A8A83636",
+"Z c #3737A9A93737",
+"A c #3737AAAA3737",
+"S c #3939A9A93939",
+"D c #3A3AABAB3A3A",
+"F c #3B3BAAAA3B3B",
+"G c #3D3DABAB3D3D",
+"H c #3E3EACAC3E3E",
+"J c #3F3FADAD3F3F",
+"K c #3F3FAFAF3F3F",
+"L c #4141AEAE3030",
+"P c #4040AEAE3F3F",
+"I c #4545B0B03636",
+"U c #4545B1B13D3D",
+"Y c #4B4BB3B33E3E",
+"T c #4242ADAD4242",
+"R c #4444AFAF4444",
+"E c #4545AEAE4545",
+"W c #4444B1B14444",
+"Q c #4545B0B04545",
+"! c #4545B2B24545",
+"~ c #4646B1B14646",
+"^ c #4747B0B04747",
+"/ c #4646B2B24747",
+"( c #4545B0B04949",
+") c #4949B0B04949",
+"_ c #4949B2B24949",
+"` c #4B4BB2B24B4B",
+"' c #4949B4B44949",
+"] c #4949B5B54949",
+"[ c #4E4EB4B44E4E",
+"{ c #4F4FB7B74F4F",
+"} c #5151B5B54242",
+"| c #5757B9B94B4B",
+" . c #5C5CBBBB4B4B",
+".. c #5F5FBDBD4C4C",
+"X. c #5050B3B35050",
+"o. c #5353B7B75353",
+"O. c #5454B7B75555",
+"+. c #5353B9B95353",
+"@. c #5656B9B95050",
+"#. c #5454B9B95454",
+"$. c #5757BABA5454",
+"%. c #5858B9B95757",
+"&. c #5858B9B95858",
+"*. c #5959BBBB5959",
+"=. c #5858BCBC5858",
+"-. c #5858BCBC5959",
+";. c #5C5CBBBB5C5C",
+":. c #5C5CBDBD5C5C",
+">. c #5D5DBCBC5D5D",
+",. c #5C5CBEBE5C5C",
+"<. c #5F5FBFBF5F5F",
+"1. c #6262BEBE5151",
+"2. c #6161BDBD6060",
+"3. c #6161BEBE6262",
+"4. c #6666BABA6767",
+"5. c #6565BEBE6565",
+"6. c #6666C0C06666",
+"7. c #6A6AC1C16A6A",
+"8. c #6A6AC3C36A6A",
+"9. c #6F6FC4C46F6F",
+"0. c #7171C5C56969",
+"q. c #7171C5C56D6D",
+"w. c #7070C3C37171",
+"e. c #7272C6C67373",
+"r. c #7474C7C77474",
+"t. c #7676C8C87676",
+"y. c #7777C8C87777",
+"u. c #7979C8C87979",
+"i. c #7979C9C97979",
+"p. c #7B7BCACA7A7A",
+"a. c #7B7BCACA7B7B",
+"s. c #7F7FC9C97E7E",
+"d. c #9C9CC0C02727",
+"f. c #A7A7C7C73737",
+"g. c #BEBED4D44D4D",
+"h. c #B2B2D0D05050",
+"j. c #B9B9D4D45656",
+"k. c #8686CBCB8888",
+"l. c #9393CDCD9393",
+"z. c #9797CFCF9797",
+"x. c #9A9AD1D19A9A",
+"c. c #A8A8D7D7AAAA",
+"v. c #ABABDADAABAB",
+"b. c #AEAEDCDCAFAF",
+"n. c #B4B4DCDCB4B4",
+"m. c #B8B8DEDEB7B7",
+"M. c #D1D1EAEAD1D1",
+"N. c #D6D6EAEAD6D6",
+"B. c #D8D8ECECD8D8",
+"V. c #DCDCECECDCDC",
+"C. c #E1E1EDEDE1E1",
+"Z. c #EEEEF4F4EEEE",
+"A. c #F3F3F6F6F3F3",
+"S. c #F3F3F7F7F4F4",
+"D. c #F6F6F6F6F6F6",
+"F. c #F9F9F9F9F9F9",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"y t t t t q q 9 7 7 5 3 2 < , < ",
+"e a.a.a.t.e.w.q.0.5.3.;.*.o.[ ; ",
+"t a.<.,.*.$.1...g.} U D B v _ - ",
+"e a.;.=.$.j.| 8.s.Y L f.x l R = ",
+"t t.=.+.| .( b.S.( L n l j J * ",
+"e e.+.{ h.k.v.B.S.n.c.z d.h D $ ",
+"9 9.{ ' E M.F.Z.B.D.V.l.f s C # ",
+"9 8.' W P E [ ) H T m h s p N + ",
+"8 5.W U D A x.n.C.z.4.a i u b o ",
+"3 3.;.*.O.X._ _ R H D C m m c . ",
+"7 2 < , > : ; = * * $ + o o X # ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/MP.xpm b/src/images/flags/MP.xpm
new file mode 100644
index 0000000..acf9d4a
--- /dev/null
+++ b/src/images/flags/MP.xpm
@@ -0,0 +1,176 @@
+/* XPM */
+static const char *MP_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 154 2",
+" c black",
+". c #000000001D1D",
+"X c #000000001F1F",
+"o c #000000002323",
+"O c #000000002727",
+"+ c #000000002929",
+"@ c #000000002B2B",
+"# c #000000002F2F",
+"$ c #000000003131",
+"% c #000000003333",
+"& c #000000003737",
+"* c #000000003939",
+"= c #000000003B3B",
+"- c #000000003F3F",
+"; c #000000004141",
+": c #000000004545",
+"> c #000000004B4B",
+", c #000000005151",
+"< c #000000005757",
+"1 c #000000005D5D",
+"2 c #000003036161",
+"3 c #000007076767",
+"4 c #00000B0B6767",
+"5 c #00000F0F6B6B",
+"6 c #000011116D6D",
+"7 c #000017177171",
+"8 c #00001D1D7373",
+"9 c #00001F1F7777",
+"0 c #000023237777",
+"q c #000023237979",
+"w c #000025257B7B",
+"e c #000029297D7D",
+"r c #00002B2B7D7D",
+"t c #00002D2D7F7F",
+"y c #00002D2D8181",
+"u c #303057579494",
+"i c #34345B5B9696",
+"p c #37375E5E9898",
+"a c #38385F5F9999",
+"s c #39395F5F9999",
+"d c #36365858A3A3",
+"f c #3C3C62629B9B",
+"g c #3D3D63639C9C",
+"h c #414167679E9E",
+"j c #424267679E9E",
+"k c #47476A6AA1A1",
+"l c #48486C6CA1A1",
+"z c #4B4B6E6EA1A1",
+"x c #4E4E6F6FA3A3",
+"c c #47476B6BB2B2",
+"v c #46466A6AB9B9",
+"b c #4C4C7070A5A5",
+"n c #4D4D7070A5A5",
+"m c #4D4D7878ACAC",
+"M c #50507272A5A5",
+"N c #51517272A5A5",
+"B c #54547575A7A7",
+"V c #55557575A7A7",
+"C c #52527474A8A8",
+"Z c #57577777A9A9",
+"A c #59597979A9A9",
+"S c #58587979ABAB",
+"D c #5D5D7C7CACAC",
+"F c #5D5D7D7DAEAE",
+"G c #51517B7BC4C4",
+"H c #6B6B9F9F9D9D",
+"J c #61618080AEAE",
+"K c #62628181B1B1",
+"L c #65658484B1B1",
+"P c #66668484B2B2",
+"I c #66668585B4B4",
+"U c #67678585B4B4",
+"Y c #60608A8AB3B3",
+"T c #6A6A8787B3B3",
+"R c #6A6A8888B3B3",
+"E c #6B6B8989B6B6",
+"W c #6E6E8A8AB6B6",
+"Q c #6F6F8B8BB6B6",
+"! c #6F6F8C8CB9B9",
+"~ c #77778E8EA6A6",
+"^ c #72728484B5B5",
+"/ c #70708D8DB9B9",
+"( c #72728E8EB9B9",
+") c #73738F8FB9B9",
+"_ c #72728F8FBBBB",
+"` c #76769191BABA",
+"' c #76769292BBBB",
+"] c #76769292BDBD",
+"[ c #79799595BEBE",
+"{ c #7A7A9595BDBD",
+"} c #7E7E9797BABA",
+"| c #7F7F9999BFBF",
+" . c #7D7DA1A1A3A3",
+".. c #7A7A9595C6C6",
+"X. c #7F7F9797C1C1",
+"o. c #F4F4DBDB7F7F",
+"O. c #828294948888",
+"+. c #80809A9ABBBB",
+"@. c #86869C9CB9B9",
+"#. c #8989A4A48888",
+"$. c #8F8FA2A2B7B7",
+"%. c #9494A6A6B9B9",
+"&. c #9E9EB5B5A6A6",
+"*. c #A6A6B8B8BDBD",
+"=. c #ADADBCBCB5B5",
+"-. c #A9A9BBBBBFBF",
+";. c #83839B9BC2C2",
+":. c #84849A9AC1C1",
+">. c #85859E9EC3C3",
+",. c #8989A1A1C6C6",
+"<. c #8B8BA4A4C7C7",
+"1. c #8D8DA4A4C8C8",
+"2. c #8F8FA5A5C8C8",
+"3. c #8F8FA6A6C8C8",
+"4. c #9191A6A6C7C7",
+"5. c #9090A7A7C9C9",
+"6. c #9090A7A7CACA",
+"7. c #A1A1B2B2C3C3",
+"8. c #ACACBDBDC1C1",
+"9. c #B2B2C2C2C5C5",
+"0. c #B4B4C3C3C8C8",
+"q. c #B4B4C5C5CACA",
+"w. c #B8B8C5C5E2E2",
+"e. c #C9C9B9B98080",
+"r. c #C0C0B8B89797",
+"t. c #E6E6BFBF9999",
+"y. c #F4F4BFBFAAAA",
+"u. c #D7D7CACA8A8A",
+"i. c #D0D0D0D09595",
+"p. c #C3C3C1C1A6A6",
+"a. c #C0C0CCCCBEBE",
+"s. c #CDCDD4D4AAAA",
+"d. c #CFCFD4D4BABA",
+"f. c #D3D3CFCFB1B1",
+"g. c #DDDDDCDCBBBB",
+"h. c #E5E5C8C88181",
+"j. c #E9E9CECE9090",
+"k. c #EFEFD5D58D8D",
+"l. c #EFEFDFDF8787",
+"z. c #E0E0DDDD9F9F",
+"x. c #EEEED1D19090",
+"c. c #F4F4D6D68D8D",
+"v. c #E3E3D4D4A2A2",
+"b. c #E6E6DFDFA5A5",
+"n. c #F4F4E4E48686",
+"m. c #F7F7E5E59B9B",
+"M. c #FAFAE2E29595",
+"N. c #FDFDEDEDA4A4",
+"B. c #F3F3E8E8B8B8",
+"V. c #FCFCE8E8B4B4",
+"C. c #FAFAF0F0A6A6",
+"Z. c #CCCCD5D5D8D8",
+"A. c #F8F8F8F8F8F8",
+"S. c None",
+/* pixels */
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"y y y y e w 0 8 7 5 3 2 1 < , > ",
+"y 6.5.6.1.7.a.B.V.g.%.` _ W T : ",
+"y 6.] ] $.s.e.t.y.M.u.~ C n J - ",
+"t 2.] _ =.N.&.+.q.^ h.b.n z J * ",
+"e <._ _ v.i.v | w.d .l.k j F % ",
+"w ,.! E z.d...4.A.:.c n.h f A # ",
+"9 >.E U f.N.m +.Z.G #.k.f s V + ",
+"7 ;.U K @.x.x.-.-.p.o.O.s i N o ",
+"6 | K F S H m.-.*.c.r.p i u n X ",
+"4 ] ' ` Q R J q.9.Y A A N n j . ",
+"2 1 < , > : : = & % + O o X . . ",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S."
+};
diff --git a/src/images/flags/MQ.xpm b/src/images/flags/MQ.xpm
new file mode 100644
index 0000000..a0c68e6
--- /dev/null
+++ b/src/images/flags/MQ.xpm
@@ -0,0 +1,173 @@
+/* XPM */
+static const char *MQ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 151 2",
+" c black",
+". c #000000001515",
+"X c #000000001717",
+"o c #000000001919",
+"O c #000000001D1D",
+"+ c #000000002727",
+"@ c #000000003131",
+"# c #000000003535",
+"$ c #000000003737",
+"% c #000000004141",
+"& c #000000004545",
+"* c #000000004D4D",
+"= c #000000005151",
+"- c #000000005353",
+"; c #000000005D5D",
+": c #000000006363",
+"> c #000000006565",
+", c #000000006969",
+"< c #000000006B6B",
+"1 c #000000007171",
+"2 c #000001017373",
+"3 c #000005057575",
+"4 c #00000F0F7B7B",
+"5 c #000011117D7D",
+"6 c #000017177F7F",
+"7 c #00001B1B8383",
+"8 c #00001D1D8383",
+"9 c #000025258787",
+"0 c #2F2F50509A9A",
+"q c #333352529C9C",
+"w c #353555559D9D",
+"e c #373755559D9D",
+"r c #383858589F9F",
+"t c #37375555A3A3",
+"y c #41415E5EA2A2",
+"u c #43435F5FA1A1",
+"i c #42425E5EA2A2",
+"p c #48486464A7A7",
+"a c #48486565A6A6",
+"s c #49496565A8A8",
+"d c #49496666A8A8",
+"f c #4E4E6868A8A8",
+"g c #4E4E6969ABAB",
+"h c #4F4F6A6AA8A8",
+"j c #50506B6BAAAA",
+"k c #50506B6BACAC",
+"l c #59596F6FAFAF",
+"z c #56567171AFAF",
+"x c #5B5B7171A5A5",
+"c c #5B5B7373A5A5",
+"v c #58587272B0B0",
+"b c #58587373B1B1",
+"n c #5D5D7676B1B1",
+"m c #5C5C7676B2B2",
+"M c #5E5E7777B1B1",
+"N c #5F5F7777B1B1",
+"B c #5F5F7878B1B1",
+"V c #60607979B2B2",
+"C c #61617A7AB6B6",
+"Z c #66667C7CB1B1",
+"A c #69698181B9B9",
+"S c #71718787BDBD",
+"D c #71718888BCBC",
+"F c #74748A8ABEBE",
+"G c #76768C8CBEBE",
+"H c #77778C8CBEBE",
+"J c #77778C8CBFBF",
+"K c #78788E8EC1C1",
+"L c #7A7A8F8FC1C1",
+"P c #80809494C3C3",
+"I c #81819595C5C5",
+"U c #82829696C5C5",
+"Y c #85859898C3C3",
+"T c #85859898C7C7",
+"R c #8B8B9D9DC5C5",
+"E c #8C8C9C9CC2C2",
+"W c #8A8A9C9CC9C9",
+"Q c #8A8A9D9DC9C9",
+"! c #9393A4A4CDCD",
+"~ c #9696A6A6CCCC",
+"^ c #9B9BA9A9CFCF",
+"/ c #9B9BABABCFCF",
+"( c #9F9FAEAECECE",
+") c #A1A1AFAFCECE",
+"_ c #A5A5B2B2D0D0",
+"` c #A7A7B5B5D7D7",
+"' c #B2B2BCBCD4D4",
+"] c #B3B3BDBDD6D6",
+"[ c #B3B3BEBED7D7",
+"{ c #B6B6C0C0D9D9",
+"} c #B6B6C1C1DADA",
+"| c #B6B6C1C1DCDC",
+" . c #B9B9C2C2D8D8",
+".. c #B8B8C2C2DBDB",
+"X. c #B9B9C5C5DEDE",
+"o. c #BABAC4C4DEDE",
+"O. c #BBBBC5C5DEDE",
+"+. c #BCBCC5C5DBDB",
+"@. c #BDBDC6C6DDDD",
+"#. c #BEBEC7C7DDDD",
+"$. c #BEBEC8C8DEDE",
+"%. c #BFBFC8C8DFDF",
+"&. c #C3C3CBCBDCDC",
+"*. c #C3C3CBCBDDDD",
+"=. c #C2C2CACAE0E0",
+"-. c #C7C7CFCFE3E3",
+";. c #C9C9D1D1E1E1",
+":. c #C8C8D0D0E2E2",
+">. c #C8C8D1D1E4E4",
+",. c #CACAD2D2E5E5",
+"<. c #CBCBD3D3E6E6",
+"1. c #CDCDD4D4E5E5",
+"2. c #CFCFD5D5E4E4",
+"3. c #D0D0D6D6E2E2",
+"4. c #D0D0D7D7E7E7",
+"5. c #D5D5D9D9E6E6",
+"6. c #D6D6DBDBE7E7",
+"7. c #D0D0D8D8E9E9",
+"8. c #D1D1D8D8EAEA",
+"9. c #D6D6DBDBE8E8",
+"0. c #D5D5DDDDECEC",
+"q. c #D9D9DEDEE7E7",
+"w. c #DBDBDEDEE8E8",
+"e. c #DDDDE2E2EFEF",
+"r. c gray90",
+"t. c #E7E7E7E7E7E7",
+"y. c #E1E1E6E6EDED",
+"u. c #E9E9E9E9E9E9",
+"i. c #E0E0E5E5F0F0",
+"p. c #E7E7E9E9F0F0",
+"a. c #E6E6E9E9F3F3",
+"s. c #E6E6EAEAF1F1",
+"d. c #E6E6EAEAF3F3",
+"f. c #EAEAEDEDF3F3",
+"g. c #ECECEDEDF1F1",
+"h. c #EFEFF0F0F1F1",
+"j. c #F4F4F4F4F4F4",
+"k. c #F4F4F5F5F5F5",
+"l. c gray96",
+"z. c #F6F6F6F6F6F6",
+"x. c gray97",
+"c. c #F6F6F7F7FAFA",
+"v. c #F7F7F7F7FAFA",
+"b. c #F8F8F8F8F8F8",
+"n. c #F9F9F9F9F9F9",
+"m. c gray98",
+"M. c #FBFBFBFBFBFB",
+"N. c gray99",
+"B. c #FDFDFDFDFDFD",
+"V. c #FEFEFEFEFEFE",
+"C. c None",
+/* pixels */
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"9 8 I ` t 5 5 N.N.1 > l R < = = ",
+"7 Q ! e.0.I L N.N.H S H w.#.B & ",
+"8 Q K O.a.S C N.M.b g z } 2.M % ",
+"6 T <.a.f.S b M.m.g p ;.6.;.M $ ",
+"/ 8.| O.O.-.%.M.m...} ( _ ) #.c ",
+"N.N.N.c.m.m.m.m.m.z.z.j.u.h.z.r.",
+"/ 8.i.a.<.%.+.m.z.} ] 6.w.[ ..x ",
+"3 L A 7.*.p p x.z.w q h &.Z i O ",
+"2 L m ~ 2.b p z.z.w q w E ] i o ",
+"< H <.a.y.Y B x.z.j g *.q.3.u . ",
+"< ; ; : ; * % u.r.@ + @ $ $ . . ",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C."
+};
diff --git a/src/images/flags/MR.xpm b/src/images/flags/MR.xpm
new file mode 100644
index 0000000..051ac64
--- /dev/null
+++ b/src/images/flags/MR.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *MR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000025250000",
+"X c #000029290000",
+"o c #000031310000",
+"O c #000033330000",
+"+ c #000037370000",
+"@ c #000039390000",
+"# c #00003B3B0000",
+"$ c #00003D3D0000",
+"% c #00003F3F0000",
+"& c #000043430000",
+"* c #000045450000",
+"= c #000049490000",
+"- c #00004B4B0000",
+"; c #00004F4F0000",
+": c #000055550000",
+"> c #00005B5B0000",
+", c #00005D5D0000",
+"< c #00005F5F0000",
+"1 c #000065650000",
+"2 c #000067670000",
+"3 c #00006B6B0000",
+"4 c #00006D6D0000",
+"5 c #00006F6F0000",
+"6 c #000073730000",
+"7 c #000077770000",
+"8 c #000079790000",
+"9 c #00007D7D0000",
+"0 c #000081810000",
+"q c #000085850000",
+"w c #000087870000",
+"e c #000089890000",
+"r c #00008B8B0000",
+"t c #000095950000",
+"y c #0B0B95950B0B",
+"u c #0F0F97970E0E",
+"i c #1F1F89891F1F",
+"p c #1F1F8B8B1F1F",
+"a c #1E1E8E8E1E1E",
+"s c #101097971010",
+"d c #13139A9A1313",
+"f c #14149A9A1414",
+"g c #1F1F94941F1F",
+"h c #191999991919",
+"j c #19199B9B1919",
+"k c #18189C9C1919",
+"l c #1A1A9D9D1A1A",
+"z c #232390902323",
+"x c #252596962525",
+"c c #292993932929",
+"v c #2E2E99992E2E",
+"b c #30308D8D3030",
+"n c #363694943636",
+"m c #3B3B97973B3B",
+"M c #3A3A9A9A3A3A",
+"N c #2020A0A02020",
+"B c #2626A2A22626",
+"V c #2B2BA3A32B2B",
+"C c #2C2CA2A22C2C",
+"Z c #2C2CA6A62C2C",
+"A c #2F2FA4A42F2F",
+"S c #3030A6A63030",
+"D c #3232A5A53232",
+"F c #3333A6A63232",
+"G c #3636A4A43636",
+"H c #3131A9A93131",
+"J c #3434A9A93434",
+"K c #3535A8A83535",
+"L c #3636A8A83636",
+"P c #3737A8A83737",
+"I c #3737A9A93636",
+"U c #3C3CA0A03C3C",
+"Y c #3939A9A93939",
+"T c #3B3BAAAA3B3B",
+"R c #3A3AADAD3A3A",
+"E c #3B3BAEAE3C3C",
+"W c #3D3DACAC3D3D",
+"Q c #3D3DAEAE3D3D",
+"! c #3F3FADAD3F3F",
+"~ c #3F3FAFAF3F3F",
+"^ c #4040AEAE3F3F",
+"/ c #4343B0B03131",
+"( c #40409A9A4040",
+") c #4545A1A14545",
+"_ c #4242ADAD4242",
+"` c #4444AFAF4444",
+"' c #4646ACAC4646",
+"] c #4646AFAF4646",
+"[ c #4B4BA8A84B4B",
+"{ c #4F4FAEAE4F4F",
+"} c #4141B2B24141",
+"| c #4444B1B14444",
+" . c #4545B2B24545",
+".. c #4949B2B24949",
+"X. c #4B4BB3B34B4B",
+"o. c #4949B4B44949",
+"O. c #4949B5B54949",
+"+. c #4B4BB5B54B4B",
+"@. c #4E4EB4B44E4E",
+"#. c #4F4FB7B74F4F",
+"$. c #5454AFAF5454",
+"%. c #5050B4B45050",
+"&. c #5151B4B45151",
+"*. c #5151B7B75151",
+"=. c #5353B7B75353",
+"-. c #5454B7B75555",
+";. c #5353BABA5353",
+":. c #5454B8B85454",
+">. c #5858B9B95757",
+",. c #5858B9B95858",
+"<. c #5959B9B95959",
+"1. c #5858BABA5959",
+"2. c #5858BCBC5858",
+"3. c #5C5CBBBB5C5C",
+"4. c #5C5CBDBD5C5C",
+"5. c #5D5DBCBC5D5D",
+"6. c #5C5CBEBE5C5C",
+"7. c #5F5FBFBF5F5F",
+"8. c #6161BEBE6060",
+"9. c #6161BEBE6262",
+"0. c #6565BEBE6565",
+"q. c #6969BABA6969",
+"w. c #6D6DBCBC6D6D",
+"e. c #6B6BC0C02525",
+"r. c #6363C0C05454",
+"t. c #7A7AC8C84B4B",
+"y. c #6666C0C06666",
+"u. c #6A6AC3C36A6A",
+"i. c #6F6FC4C46F6F",
+"p. c #7070C3C37171",
+"a. c #7272C6C67373",
+"s. c #7474C7C77474",
+"d. c #7676C8C87676",
+"f. c #7777C8C87777",
+"g. c #7979C8C87979",
+"h. c #7979C9C97979",
+"j. c #7B7BCACA7A7A",
+"k. c #7B7BCACA7B7B",
+"l. c #8080C8C82424",
+"z. c #8C8CCDCD2F2F",
+"x. c #8282C9C93434",
+"c. c #9090CFCF3535",
+"v. c #9D9DD3D32B2B",
+"b. c #A2A2D8D84747",
+"n. c #A3A3D9D94C4C",
+"m. c #ADADDDDD5050",
+"M. c #D9D9ECEC2424",
+"N. c #DDDDEDED2B2B",
+"B. c #EFEFF5F52A2A",
+"V. c #EFEFF6F62F2F",
+"C. c #F6F6F6F62A2A",
+"Z. c #F9F9F9F93A3A",
+"A. c #D2D2EBEB4040",
+"S. c #EFEFF7F74646",
+"D. c #FAFAFAFA4242",
+"F. c #FAFAFBFB4747",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"t r r r r q q 0 9 7 6 5 3 1 , 1 ",
+"q k.k.k.d.d.p.w.q.0.8.5.>.=. at .- ",
+"r k.5.5.<.=.*.n.b._ ! P H Z ..; ",
+"r k.4.<.r.=.[ F.D.M Y / V B ' - ",
+"q d.:.-.m.+.' ~ E G Z v.x N ! & ",
+"q a.=.{ t.S.( m n b N.e.g l / $ ",
+"0 i.#.+.) A.Z.c.z.C.M.p h f P + ",
+"9 u.+.| ~ M x.V.B.e.z h f s F O ",
+"9 y.| ~ E K v c z g l f s y A O ",
+"5 8.5.<.:.*...' _ Q Y K F S C . ",
+"9 1 1 , , : ; - & $ $ + O X X $ ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/MS.xpm b/src/images/flags/MS.xpm
new file mode 100644
index 0000000..9ea540a
--- /dev/null
+++ b/src/images/flags/MS.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *MS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000000001111",
+"X c #000000001515",
+"o c #000000001717",
+"O c #000000001919",
+"+ c #000000001D1D",
+"@ c #000000002323",
+"# c #000000002525",
+"$ c #000000002929",
+"% c #000000002B2B",
+"& c #000000002F2F",
+"* c #000000003131",
+"= c #000000003535",
+"- c #000000003737",
+"; c #000000003D3D",
+": c #000000004343",
+"> c #000000004949",
+", c #000000004F4F",
+"< c #000000005555",
+"1 c #000000005959",
+"2 c #000000005B5B",
+"3 c #000000005D5D",
+"4 c #000000005F5F",
+"5 c #000000006363",
+"6 c #000000006767",
+"7 c #000000006969",
+"8 c #000000006D6D",
+"9 c #7F7F19194747",
+"0 c #676723235D5D",
+"q c #6B6B33337171",
+"w c #000003038383",
+"e c #000017179595",
+"r c #1E1E2A2A8E8E",
+"t c #2F2F25258383",
+"y c #23232E2E9191",
+"u c #272732329393",
+"i c #2C2C37379696",
+"p c #28283A3A9898",
+"a c #2D2D3F3F9B9B",
+"s c #2E2E3F3F9B9B",
+"d c #31313C3C9999",
+"f c #333344449E9E",
+"g c #333344449F9F",
+"h c #363645459D9D",
+"j c #3B3B45459F9F",
+"k c #383848489E9E",
+"l c #38384848A1A1",
+"z c #38384949A2A2",
+"x c #39394A4AA2A2",
+"c c #3D3D4D4DA4A4",
+"v c #3E3E4E4EA5A5",
+"b c #42424B4B9D9D",
+"n c #43434C4C9D9D",
+"m c #4E4E50509E9E",
+"M c #40404B4BA0A0",
+"N c #40404B4BA1A1",
+"B c #42424C4CA3A3",
+"V c #46464F4FA3A3",
+"C c #42425151A4A4",
+"Z c #43435252A7A7",
+"A c #44445353A7A7",
+"S c #46465555A6A6",
+"D c #49495050A0A0",
+"F c #4E4E5555A1A1",
+"G c #4D4D5656A6A6",
+"H c #4E4E5656A4A4",
+"J c #48485757AAAA",
+"K c #49495858AAAA",
+"L c #4A4A5959A9A9",
+"P c #4D4D5B5BAAAA",
+"I c #4F4F5E5EABAB",
+"U c #4D4D5C5CADAD",
+"Y c #4E4E5C5CADAD",
+"T c #4E4E5C5CAEAE",
+"R c #52525959A4A4",
+"E c #53535C5CAAAA",
+"W c #5A5A5C5CA7A7",
+"Q c #51516060ADAD",
+"! c #53536060AEAE",
+"~ c #52526060B0B0",
+"^ c #52526161B0B0",
+"/ c #57576464B0B0",
+"( c #57576565B2B2",
+") c #58586565B0B0",
+"_ c #5B5B6C6CB7B7",
+"` c #5C5C6969B3B3",
+"' c #63636161A7A7",
+"] c #60606767ADAD",
+"[ c #64646969AEAE",
+"{ c #6D6D6969ABAB",
+"} c #60606D6DB5B5",
+"| c #64647070B7B7",
+" . c #65657272B8B8",
+".. c #68687575B9B9",
+"X. c #69697575BABA",
+"o. c #6E6E7A7ABDBD",
+"O. c #71717A7AB9B9",
+"+. c #71717E7EBEBE",
+"@. c #74747A7ABABA",
+"#. c #77777F7FBCBC",
+"$. c #5E5E7F7FD7D7",
+"%. c #64648282D9D9",
+"&. c #68688686DBDB",
+"*. c #6C6C8989DDDD",
+"=. c #6D6D8989DDDD",
+"-. c #75758181C0C0",
+";. c #70708C8CDFDF",
+":. c #71718D8DDFDF",
+">. c #7F7F9A9AC2C2",
+",. c #74749090E0E0",
+"<. c #75759191E0E0",
+"1. c #79799494E2E2",
+"2. c #8D8D1D1D4343",
+"3. c #818121214F4F",
+"4. c #B1B15D5D7575",
+"5. c #CDCD15151717",
+"6. c #C3C36B6B7D7D",
+"7. c #D6D66C6C7171",
+"8. c #E2E268686767",
+"9. c #E4E472727171",
+"0. c #E0E075757878",
+"q. c #E0E07B7B7E7E",
+"w. c #E8E87A7A7676",
+"e. c #8B8B6C6C9D9D",
+"r. c #83836D6DA3A3",
+"t. c #8B8B7070A1A1",
+"y. c #9A9A7F7FA6A6",
+"u. c #9B9B7E7EA7A7",
+"i. c #ABAB75759494",
+"p. c #9B9B8A8A5555",
+"a. c #9E9E8C8C5757",
+"s. c #9E9E8D8D5858",
+"d. c #9D9D96964A4A",
+"f. c #9191A5A57171",
+"g. c #9494A7A77575",
+"h. c #A4A493936060",
+"j. c #C5C59E9E4444",
+"k. c #EAEA81817E7E",
+"l. c #94948A8AB9B9",
+"z. c #9F9F9090B9B9",
+"x. c #86869E9ED2D2",
+"c. c #8E8EA3A3CCCC",
+"v. c #9191A1A1C5C5",
+"b. c #9D9DA4A4D0D0",
+"n. c #9C9CAAAAD5D5",
+"m. c #C6C684849696",
+"M. c #C1C184849999",
+"N. c #D3D380808B8B",
+"B. c #D8D89E9EA9A9",
+"V. c #D7D7ACACB7B7",
+"C. c #D8D8AAAAB6B6",
+"Z. c #E0E083838484",
+"A. c #E6E693939494",
+"S. c #EEEE9E9E9C9C",
+"D. c #EEEEA1A19F9F",
+"F. c #E1E1B2B2BABA",
+"G. c #D7D7B6B6C4C4",
+"H. c #DFDFB9B9C3C3",
+"J. c #DFDFD3D3DEDE",
+"K. c #E3E3C2C2CACA",
+"L. c #E2E2CBCBD4D4",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"6.r.e 9 2.w 0 4.6 5 3 2 < , > : ",
+"t H.J.C.B.G.L.b.#. at ...| [ ] / ; ",
+"5.A.k.9.8.w.0.7.' E 1.,.:.=.Q = ",
+"3.F.S.q.Z.D.N.i.W H ,.c.v.&.P & ",
+"{ K.z.M.m.n.V.u.H D :.x.g.%.R $ ",
+"q l._ t.e.T o.y.m n =.>.f.$.F @ ",
+"8 -./ ~ T L C c x l h.j.a.p.V + ",
+"7 +.~ U J Z c z g s d a.d.y N O ",
+"6 o.T J Z v l l s p i u y r j X ",
+"3 ..| } ` ) Q E L S C B c b h . ",
+"2 < , > : ; - * $ # @ + X X . . ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/MT.xpm b/src/images/flags/MT.xpm
new file mode 100644
index 0000000..1885c1f
--- /dev/null
+++ b/src/images/flags/MT.xpm
@@ -0,0 +1,135 @@
+/* XPM */
+static const char *MT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 113 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #F2F210101010",
+"2 c #F2F213131313",
+"3 c #F2F214141414",
+"4 c #F3F319191919",
+"5 c #F3F31A1A1A1A",
+"6 c #F4F41E1E1E1E",
+"7 c #F4F41F1F1F1F",
+"8 c #F4F420202020",
+"9 c #F5F524242424",
+"0 c #F5F525252525",
+"q c #F5F526262626",
+"w c #F2F22C2C2C2C",
+"e c #F2F22F2F2F2F",
+"r c #F6F62A2A2A2A",
+"t c #F6F62B2B2B2B",
+"y c #F6F62C2C2C2C",
+"u c #F2F232323232",
+"i c #F3F332323232",
+"p c #F3F335353535",
+"a c #F5F530303030",
+"s c #F7F730303030",
+"d c #F7F731313131",
+"f c #F4F436363636",
+"g c #F6F636363636",
+"h c #F4F439393939",
+"j c #F4F43B3B3B3B",
+"k c #F7F73B3B3B3B",
+"l c #F5F53D3D3D3D",
+"z c #F5F53F3F3F3F",
+"x c #F8F836363636",
+"c c #F8F837373636",
+"v c #F8F837373737",
+"b c #F9F93C3C3C3C",
+"n c #F9F93C3C3D3D",
+"m c #F6F644444444",
+"M c #F7F749494949",
+"N c #F6F64C4C4C4C",
+"B c #F7F74E4E4E4E",
+"V c #F8F841414141",
+"C c #FAFA42424242",
+"Z c #F9F947474747",
+"A c #FAFA4C4C4C4C",
+"S c #F8F853535353",
+"D c #FBFB52525252",
+"F c #F9F957575757",
+"G c #FAFA5C5C5C5C",
+"H c #FBFB60606060",
+"J c #FCFC65656565",
+"K c #FCFC72727272",
+"L c #BDBDB8B8B8B8",
+"P c #C9C9C8C8C8C8",
+"I c #CFCFCDCDCDCD",
+"U c #D9D9C5C5C5C5",
+"Y c #D3D3D2D2D2D2",
+"T c #D6D6D4D4D3D3",
+"R c gray86",
+"E c #DDDDDDDDDDDD",
+"W c #EFEFDDDDDDDD",
+"Q c #E1E1E1E1E1E1",
+"! c gray89",
+"~ c gray90",
+"^ c #E7E7E7E7E7E7",
+"/ c gray92",
+"( c gray93",
+") c #EFEFEFEFEFEF",
+"_ c #F1F1EFEFEFEF",
+"` c #F6F6EAEAEAEA",
+"' c #F7F7EBEBECEC",
+"] c #F7F7EDEDEDED",
+"[ c #F8F8EDEDEDED",
+"{ c #F9F9EEEEEEEE",
+"} c #FAFAEFEFEFEF",
+"| c #F1F1F1F1F1F1",
+" . c #F3F3F1F1F1F1",
+".. c #F3F3F3F3F3F3",
+"X. c gray96",
+"o. c gray97",
+"O. c #FBFBF0F0F0F0",
+"+. c #FCFCF2F2F2F2",
+"@. c #FDFDF5F5F5F5",
+"#. c #F8F8F8F8F8F8",
+"$. c #F9F9F9F9F9F9",
+"%. c #FAFAF9F9F9F9",
+"&. c gray98",
+"*. c #FBFBFBFBFBFB",
+"=. c #FBFBFCFCFBFB",
+"-. c gray99",
+";. c #FDFDFCFCFDFD",
+":. c #FDFDFDFDFDFD",
+">. c #FDFDFDFDFEFE",
+",. c #FEFEFCFCFCFC",
+"<. c #FEFEFDFDFCFC",
+"1. c #FEFEFEFEFEFE",
+"2. c None",
+/* pixels */
+"2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.",
+"2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.",
+"2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.",
+"| _ | | | | | W < , , - = = % % ",
+"X.%.Y ,.1.1.1. at .K J H G F S B $ ",
+"| T L I 1.1.1.} D C n x d y M $ ",
+"X.1.P 1.,.1.*.} A n x d y q m + ",
+"..1.1.1.-.*.*.} Z x s t q 8 z + ",
+"| 1.1.=.=.=.%.} V d t q 7 4 j + ",
+") 1.=.=.*.%.%.] k t 9 7 4 2 f O ",
+") *.*.*.*.o.%.' x q 7 4 2 2 u X ",
+"( =.%.*.*.o.o.` y 7 4 2 > : e X ",
+"( *.*.%.%.%.X.] B l h p u e w X ",
+"/ ^ ~ ! Q E R U + + O O X X . . ",
+"2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.",
+"2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2."
+};
diff --git a/src/images/flags/MU.xpm b/src/images/flags/MU.xpm
new file mode 100644
index 0000000..1d8cded
--- /dev/null
+++ b/src/images/flags/MU.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *MU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000017170000",
+"X c #000019190000",
+"o c #00001B1B0000",
+"O c #00001F1F0000",
+"+ c #000000003F3F",
+"@ c #000025250000",
+"# c #000029290000",
+"$ c #00002D2D0000",
+"% c #000033330000",
+"& c #000039390000",
+"* c #00003D3D0000",
+"= c #000000004949",
+"- c #000019194B4B",
+"; c #000043430000",
+": c #000049490000",
+"> c #00004D4D0000",
+", c #000053530000",
+"< c #000059590000",
+"1 c #00005F5F0000",
+"2 c #000063630000",
+"3 c #494900000000",
+"4 c #49495C5C7B7B",
+"5 c #4E4E60607E7E",
+"6 c #000000008383",
+"7 c #000000008B8B",
+"8 c #20204242A7A7",
+"9 c #26264242A2A2",
+"0 c #25254646AAAA",
+"q c #2B2B4646A5A5",
+"w c #2B2B4B4BADAD",
+"e c #31314C4CA8A8",
+"r c #37375151ABAB",
+"t c #3C3C5555AEAE",
+"y c #30305050B0B0",
+"u c #36365555B2B2",
+"i c #3B3B5A5AB5B5",
+"p c #3F3F5D5DB4B4",
+"a c #44445C5CAFAF",
+"s c #42425A5AB0B0",
+"d c #41415F5FB7B7",
+"f c #47475F5FB3B3",
+"g c #525264648282",
+"h c #565668688585",
+"j c #5A5A6C6C8888",
+"k c #5F5F70708C8C",
+"l c #46466363BABA",
+"z c #4B4B6363B6B6",
+"x c #4B4B6767BCBC",
+"c c #51516767B7B7",
+"v c #50506C6CBFBF",
+"b c #54546B6BBABA",
+"n c #58586E6EBCBC",
+"m c #5C5C7171BEBE",
+"M c #636373738D8D",
+"N c #646475758F8F",
+"B c #686879799292",
+"V c #6D6D7C7C9696",
+"C c #71717F7F9999",
+"Z c #54547070C0C0",
+"A c #58587272C2C2",
+"S c #0F0F8B8B0000",
+"D c #2C2C9E9E2C2C",
+"F c #2F2F9F9F2F2F",
+"G c #3232A2A23232",
+"H c #3535A4A43535",
+"J c #3939A5A53939",
+"K c #3D3DA8A83D3D",
+"L c #6161B9B90000",
+"P c #4242AAAA4242",
+"I c #4646ADAD4646",
+"U c #4B4BAFAF4B4B",
+"Y c #5050B2B25050",
+"T c #5454B4B45555",
+"R c #5858B7B75858",
+"E c #5D5DB9B95D5D",
+"W c #6161BBBB6262",
+"Q c #757583839C9C",
+"! c #797987879F9F",
+"~ c #76768B8BCDCD",
+"^ c #79798A8AC9C9",
+"/ c #878700000000",
+"( c #A7A700000000",
+") c #ABAB00000000",
+"_ c #AFAF00000000",
+"` c #B1B100000000",
+"' c #B3B300000000",
+"] c #B7B700000000",
+"[ c #B9B900000000",
+"{ c #BDBD00000000",
+"} c #A5A52C2C4141",
+"| c #A8A831314646",
+" . c #AAAA37374B4B",
+".. c #ADAD3C3C5050",
+"X. c #B0B042425454",
+"o. c #B3B347475959",
+"O. c #B1B149495B5B",
+"+. c #B5B54C4C5E5E",
+"@. c #B8B851516262",
+"#. c #B9B954546666",
+"$. c #BBBB59596969",
+"%. c #BDBD5C5C6D6D",
+"&. c #BEBE5F5F7070",
+"*. c #C1C100000000",
+"=. c #C3C300000000",
+"-. c #C7C700000000",
+";. c #CDCD00000000",
+":. c #DCDC4E4E4E4E",
+">. c #DDDD53535353",
+",. c #DEDE57575757",
+"<. c #E0E05C5C5C5C",
+"1. c #E1E160606060",
+"2. c #E2E265656565",
+"3. c #E3E369696969",
+"4. c #E5E56D6D6D6D",
+"5. c #E6E670707171",
+"6. c #E7E774747474",
+"7. c #E8E877777777",
+"8. c #E8E879797979",
+"9. c #E8E87B7B7B7B",
+"0. c #E9E97B7B7B7B",
+"q. c #C9C97B7B8888",
+"w. c #8888C5C50B0B",
+"e. c #8B8BC7C70E0E",
+"r. c #8E8EC8C81313",
+"t. c #9191CACA1919",
+"y. c #9494CCCC1E1E",
+"u. c #9696CECE2323",
+"i. c #9A9ACDCD2F2F",
+"p. c #9999D0D02929",
+"a. c #9C9CD1D12E2E",
+"s. c #9F9FD3D33434",
+"d. c #A2A2D5D53A3A",
+"f. c #A6A6D7D73F3F",
+"g. c #A8A8D9D94444",
+"h. c #B9B9E0E06666",
+"j. c #DFDFDFDF0000",
+"k. c #E3E3E3E30000",
+"l. c #FBFBFBFB0000",
+"z. c #FDFDFDFD0000",
+"x. c #F2F2F2F21010",
+"c. c #F2F2F2F21414",
+"v. c #F3F3F3F31919",
+"b. c #F4F4F4F41F1F",
+"n. c #F5F5F5F52424",
+"m. c #F6F6F6F62A2A",
+"M. c #F7F7F7F72F2F",
+"N. c #F3F3F3F33232",
+"B. c #F4F4F4F43636",
+"V. c #F8F8F8F83434",
+"C. c #F8F8F8F83535",
+"Z. c #F9F9F9F93A3A",
+"A. c #FAFAFAFA3F3F",
+"S. c #FAFAFAFA4040",
+"D. c #FBFBFBFB4545",
+"F. c #FBFBFBFB4949",
+"G. c #FBFBFCFC4949",
+"H. c #FCFCFCFC4F4F",
+"J. c #FCFCFCFC6A6A",
+"K. c #FDFDFDFD6F6F",
+"L. c #90909D9DB0B0",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"-.=.=.=.=.=.{ { [ ] ' ' _ ) ( ( ",
+";.0.0.0.6.6.5.4.3.2.1.<.,.>.:.) ",
+"/ q.&.%.$.#. at .+.o.X... .| } O.3 ",
+"6 ^ m n b c z f s t r e q 9 a + ",
+"7 ~ A Z v x l d i u y w 0 8 p = ",
+"- L.! Q C V B N k j h g 5 4 M ",
+"z.K.H.G.D.S.Z.C.M.m.n.b.v.c.B.k.",
+"l.J.F.D.A.Z.C.M.m.n.b.v.c.x.N.j.",
+"L h.g.f.d.s.a.p.u.y.t.r.e.w.i.S ",
+"2 W E R T Y U I P K J H G F D . ",
+"1 < , > : ; * & % $ # @ O o o o ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/MV.xpm b/src/images/flags/MV.xpm
new file mode 100644
index 0000000..48c47f4
--- /dev/null
+++ b/src/images/flags/MV.xpm
@@ -0,0 +1,171 @@
+/* XPM */
+static const char *MV_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 149 2",
+" c black",
+". c #4F4FD4D44C4C",
+"X c #4F4FDADA5151",
+"o c #5252D7D75151",
+"O c #5656D8D85454",
+"+ c #5858D7D75555",
+"@ c #5B5BDADA5A5A",
+"# c #5858DDDD5B5B",
+"$ c #5858DFDF5B5B",
+"% c #5D5DDFDF5D5D",
+"& c #5F5FDEDE5F5F",
+"* c #5151E0E05757",
+"= c #5C5CE3E36060",
+"- c #5F5FE6E66565",
+"; c #6060DDDD5F5F",
+": c #6262DFDF6262",
+"> c #6363DEDE6262",
+", c #6363E1E16363",
+"< c #6565E4E46868",
+"1 c #6A6AE5E56C6C",
+"2 c #6C6CE1E16A6A",
+"3 c #6C6CE4E46C6C",
+"4 c #6D6DE5E56F6F",
+"5 c #6C6CE6E66F6F",
+"6 c #7373E7E77575",
+"7 c #7474E2E27272",
+"8 c #7070E9E97575",
+"9 c #7272E9E97575",
+"0 c #7575E9E97878",
+"q c #7878E5E57777",
+"w c #7D7DE6E67B7B",
+"e c #7979EBEB7C7C",
+"r c #7A7AEAEA7D7D",
+"t c #7B7BEEEE8181",
+"y c #B9B900000000",
+"u c #BBBB00000000",
+"i c #BDBD00000000",
+"p c #BFBF00000000",
+"a c #C1C100000000",
+"s c #C3C300000000",
+"d c #C5C500000000",
+"f c #C9C900000000",
+"g c #CBCB00000000",
+"h c #CFCF00000000",
+"j c #D1D100000000",
+"k c #D3D300000000",
+"l c #D7D700000000",
+"z c #D9D900000000",
+"x c #DBDB00000000",
+"c c #DDDD00000000",
+"v c #DFDF00000000",
+"b c #DDDD15151111",
+"n c #DADA19191111",
+"m c #DBDB1D1D1616",
+"M c #DEDE1A1A1616",
+"N c #DDDD22221B1B",
+"B c #DEDE27272222",
+"V c #DFDF2C2C2626",
+"C c #E1E100000000",
+"Z c #E3E300000000",
+"A c #E5E500000000",
+"S c #E7E700000000",
+"D c #E1E10B0B0B0B",
+"F c #E9E900000000",
+"G c #EBEB00000000",
+"H c #E0E01F1F1C1C",
+"J c #E1E125252222",
+"K c #E3E32B2B2727",
+"L c #E2E22C2C2C2C",
+"P c #E2E22F2F2F2F",
+"I c #E5E52F2F2F2F",
+"U c #E9E92C2C2C2C",
+"Y c #E0E031312A2A",
+"T c #E2E237373030",
+"R c #E6E632323232",
+"E c #E2E23C3C3535",
+"W c #E4E43C3C3636",
+"Q c #E8E832323232",
+"! c #E9E935353535",
+"~ c #E8E836363636",
+"^ c #E8E83B3B3B3B",
+"/ c #EBEB39393939",
+"( c #E9E93F3F3F3F",
+") c #EBEB3D3D3D3D",
+"_ c #E3E343433B3B",
+"` c #E5E542423B3B",
+"' c #E7E747474141",
+"] c #E4E448484141",
+"[ c #E5E54D4D4646",
+"{ c #EBEB44444444",
+"} c #ECEC42424242",
+"| c #EFEF44444444",
+" . c #EEEE46464646",
+".. c #EBEB49494949",
+"X. c #EFEF4B4B4B4B",
+"o. c #ECEC4D4D4A4A",
+"O. c #EDED4E4E4E4E",
+"+. c #E6E652524A4A",
+"@. c #E7E756564E4E",
+"#. c #EEEE52524F4F",
+"$. c #EDED53535353",
+"%. c #EFEF50505050",
+"&. c #EFEF57575454",
+"*. c #E9E95B5B5454",
+"=. c #EAEA5E5E5858",
+"-. c #EFEF5B5B5959",
+";. c #F1F154545555",
+":. c #F0F057575757",
+">. c #F1F158585858",
+",. c #F0F05D5D5D5D",
+"<. c #F0F05F5F5D5D",
+"1. c #F2F25C5C5C5C",
+"2. c #F4F45F5F5F5F",
+"3. c #EBEB63635C5C",
+"4. c #EDED65655E5E",
+"5. c #F1F161616262",
+"6. c #F2F260606060",
+"7. c #F2F265656565",
+"8. c #F2F266666666",
+"9. c #F3F36A6A6A6A",
+"0. c #F4F469696969",
+"q. c #F5F56D6D6D6D",
+"w. c #F4F46F6F6F6F",
+"e. c #F5F570707171",
+"r. c #F5F572727373",
+"t. c #F6F674747474",
+"y. c #F6F676767676",
+"u. c #F7F777777777",
+"i. c #F6F679797979",
+"p. c #F7F779797979",
+"a. c #F7F77B7B7A7A",
+"s. c #F7F77B7B7B7B",
+"d. c #8080E7E77E7E",
+"f. c #8383E9E98383",
+"g. c #8989E3E38787",
+"h. c #8888E9E98A8A",
+"j. c #8D8DEBEB8F8F",
+"k. c #9393EDED9595",
+"l. c #9B9BE9E99C9C",
+"z. c #A2A2ECECA3A3",
+"x. c #B2B2EEEEB2B2",
+"c. c #B5B5ECECB5B5",
+"v. c #BFBFF3F3C1C1",
+"b. c #CBCBF1F1CDCD",
+"n. c #D0D0F4F4D1D1",
+"m. c #D6D6F4F4D7D7",
+"M. c #D6D6F5F5D7D7",
+"N. c #DADAF6F6DADA",
+"B. c None",
+/* pixels */
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"F F S S S S Z S Z c c x x l k k ",
+"G s.i.s.u.y.w.q.0.7.6.<.&.$.O.h ",
+"G s.2.4.3.=.=. at .+.[ ' _ E U ..g ",
+"F i.<.f.r r 9 k.v.5 < - ; K { g ",
+"F y.-.d.e 6 j.N.n.z., = @ J ( s ",
+"S r.&.w 0 1 x.m.% : # # O H ^ s ",
+"S w.%.q 8 1 h.m.b.l.$ $ o M ~ p ",
+"Z 0.o.7 4 2 : g.c.@ O X . b R p ",
+"Z 8.| ' ` W T Y V B N m n D P p ",
+"c 5.-.1.&.%.X. .} ) / ~ R P L u ",
+"x x l k k k g g s s s p p u u u ",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B."
+};
diff --git a/src/images/flags/MW.xpm b/src/images/flags/MW.xpm
new file mode 100644
index 0000000..38276a9
--- /dev/null
+++ b/src/images/flags/MW.xpm
@@ -0,0 +1,171 @@
+/* XPM */
+static const char *MW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 149 2",
+" c black",
+". c #000007070000",
+"X c #070700000000",
+"o c #000023230000",
+"O c #000029290000",
+"+ c #00002B2B0000",
+"@ c #00002D2D0000",
+"# c #00002F2F0000",
+"$ c #000033330000",
+"% c #000039390000",
+"& c #00003D3D0000",
+"* c #2C2C2C2C2C2C",
+"= c #313131313131",
+"- c #000041410000",
+"; c #000047470000",
+": c #00004D4D0000",
+"> c #000051510000",
+", c #000057570000",
+"< c #00005B5B0000",
+"1 c #00005D5D0000",
+"2 c #000063630000",
+"3 c #000067670000",
+"4 c #00006D6D0000",
+"5 c #000075750000",
+"6 c #404026262626",
+"7 c #45452B2B2B2B",
+"8 c #6D6D00000000",
+"9 c #6F6F00000000",
+"0 c #616137373737",
+"q c #494949494949",
+"w c #4E4E4E4E4E4E",
+"e c #5B5B44444444",
+"r c #535353535353",
+"t c #585857575757",
+"y c gray36",
+"u c #5E5E5C5C5C5C",
+"i c #5F5F5F5F5F5F",
+"p c #737342424242",
+"a c #707051515151",
+"s c #717151515151",
+"d c #71715C5C5C5C",
+"f c #787877777777",
+"g c #797979797979",
+"h c #7B7B7B7B7A7A",
+"j c #7B7B7B7B7B7B",
+"k c #0B0B97970B0B",
+"l c #0F0F9A9A0E0E",
+"z c #13139C9C1313",
+"x c #18189F9F1919",
+"c c #1E1EA1A11E1E",
+"v c #2F2F85851010",
+"b c #343488881414",
+"n c #38388A8A1919",
+"m c #3D3D8D8D1F1F",
+"M c #2323A3A32323",
+"N c #2929A6A62929",
+"B c #2C2CA2A22C2C",
+"V c #2F2FA4A42F2F",
+"C c #2F2FA6A62F2F",
+"Z c #2E2EA9A92E2E",
+"A c #3232A5A53232",
+"S c #3535A8A83535",
+"D c #3434ACAC3434",
+"F c #3939A9A93939",
+"G c #3A3AAEAE3A3A",
+"H c #3D3DACAC3D3D",
+"J c #3F3FB1B13F3F",
+"K c #424290902424",
+"L c #464693932A2A",
+"P c #4B4B96962F2F",
+"I c #4D4D96963232",
+"U c #50509A9A3434",
+"Y c #55559D9D3A3A",
+"T c #5858A1A13F3F",
+"R c #4242AEAE4242",
+"E c #4646B0B04646",
+"W c #4444B4B44444",
+"Q c #4B4BB2B24B4B",
+"! c #5D5DA4A44545",
+"~ c #5050B4B45050",
+"^ c #5454B7B75555",
+"/ c #5858B9B95858",
+"( c #5D5DBCBC5D5D",
+") c #6161A7A74949",
+"_ c #6161BEBE6262",
+"` c #7F7FB7B76A6A",
+"' c #6666C2C26666",
+"] c #888837373636",
+"[ c #9A9A59595959",
+"{ c #8A8A79797979",
+"} c #999960606060",
+"| c #989869696969",
+" . c #99996D6D6D6D",
+".. c #A1A159595959",
+"X. c #A4A474747474",
+"o. c #C7C731313131",
+"O. c #C6C63C3C3C3C",
+"+. c #C6C63C3C3D3D",
+"@. c #E3E300000000",
+"#. c #E5E500000000",
+"$. c #E7E700000000",
+"%. c #FDFD00000000",
+"&. c #F2F214141414",
+"*. c #F3F319191919",
+"=. c #F3F31A1A1A1A",
+"-. c #F4F41F1F1F1F",
+";. c #F4F420202020",
+":. c #F5F524242424",
+">. c #F5F525252525",
+",. c #F6F62A2A2A2A",
+"<. c #F6F62B2B2B2B",
+"1. c #F7F72F2F2F2F",
+"2. c #F2F236363636",
+"3. c #F6F630303030",
+"4. c #F7F730303030",
+"5. c #F4F436363636",
+"6. c #F1F13B3B3C3C",
+"7. c #F4F43B3B3B3B",
+"8. c #F5F53F3F3F3F",
+"9. c #F8F835353535",
+"0. c #F8F836363636",
+"q. c #F9F93B3B3A3A",
+"w. c #F9F93B3B3B3B",
+"e. c #CDCD41414242",
+"r. c #CFCF47474747",
+"t. c #CACA4B4B4B4B",
+"y. c #D0D054545454",
+"u. c #D4D454545454",
+"i. c #C4C465656565",
+"p. c #D9D970707171",
+"a. c #EEEE47474747",
+"s. c #EEEE4C4C4C4C",
+"d. c #F2F241414141",
+"f. c #F4F446464646",
+"g. c #FAFA40404040",
+"h. c #FBFB45454545",
+"j. c #FBFB46464646",
+"k. c #FBFB4A4A4949",
+"l. c #FAFA4B4B4B4B",
+"z. c #FCFC4A4A4B4B",
+"x. c #FCFC4F4F4F4F",
+"c. c #FCFC4F4F5050",
+"v. c #FDFD53535353",
+"b. c #FDFD54545454",
+"n. c #FEFE58585858",
+"m. c #FDFD6F6F6F6F",
+"M. c #FEFE72727373",
+"N. c #FEFE76767676",
+"B. c None",
+/* pixels */
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+" X 9 9 ",
+" j j j f X.p. .| i.} y t r w ",
+" j y y ..y.s s.a.p +.0 = * q ",
+" { d [ u.s t.r.e.+.] o.7 6 e ",
+"%.N.n.b.c.l.f.d.6.5.3.<.>.;.8.$.",
+"%.M.b.c.z.j.g.q.0.3.<.>.-.*.7.$.",
+"%.m.x.z.j.g.q.0.1.<.:.-.*.&.5. at .",
+"< ` ! ! Y Y U P L K m n b v I . ",
+"5 ' W W G D Z N M c x z l k C + ",
+"4 _ ( / ^ ~ Q E R H F S A C B o ",
+"5 3 2 1 , > : ; - & % $ # # O $ ",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.",
+"B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B."
+};
diff --git a/src/images/flags/MX.xpm b/src/images/flags/MX.xpm
new file mode 100644
index 0000000..529a4b7
--- /dev/null
+++ b/src/images/flags/MX.xpm
@@ -0,0 +1,177 @@
+/* XPM */
+static const char *MX_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 155 2",
+" c black",
+". c #00001F1F0000",
+"X c #00002F2F0000",
+"o c #000031310000",
+"O c #000039390000",
+"+ c #00003D3D0000",
+"@ c #000043430000",
+"# c #000049490000",
+"$ c #00004F4F0000",
+"% c #000053530000",
+"& c #000057570101",
+"* c #00005D5D0707",
+"= c #00005D5D0B0B",
+"- c #00005F5F0B0B",
+"; c #00005F5F0D0D",
+": c #000061610F0F",
+"> c #3C3C94946060",
+", c #424297976464",
+"< c #48489A9A6969",
+"1 c #48489C9C6A6A",
+"2 c #4D4D9D9D6E6E",
+"3 c #4E4E9E9E6E6E",
+"4 c #4E4E9E9E6F6F",
+"5 c #5252A0A07272",
+"6 c #5252A1A17272",
+"7 c #5353A1A17272",
+"8 c #5656A2A27575",
+"9 c #5757A3A37676",
+"0 c #5757A4A47676",
+"q c #5B5BA6A67A7A",
+"w c #5C5CA6A67A7A",
+"e c #5C5CA7A77A7A",
+"r c #6060A7A77C7C",
+"t c #6060A9A97D7D",
+"y c #6060AAAA7E7E",
+"u c #6464ABAB8080",
+"i c #6464ABAB8181",
+"p c #6565AAAA8181",
+"a c #6767ADAD8383",
+"s c #6969ADAD8484",
+"d c #6E6EAFAF8888",
+"f c #7171B3B38B8B",
+"g c #7575B5B58F8F",
+"h c #7979B7B79191",
+"j c #7979B7B79292",
+"k c #7C7CB9B99494",
+"l c #7F7FBABA9696",
+"z c #A9A900000000",
+"x c #ABAB00000000",
+"c c #ADAD00000000",
+"v c #AFAF00000000",
+"b c #B1B100000000",
+"n c #B3B300000000",
+"m c #B7B700000000",
+"M c #B9B900000000",
+"N c #BDBD00000000",
+"B c #BFBF00000000",
+"V c #83835F5F3F3F",
+"C c #8D8D7D7D6A6A",
+"Z c #C5C500000000",
+"A c #C7C700000000",
+"S c #C9C900000000",
+"D c #CDCD00000000",
+"F c #D6D627272C2C",
+"G c #D7D729292F2F",
+"H c #D8D82A2A2F2F",
+"J c #D7D72A2A3030",
+"K c #D9D92E2E3434",
+"L c #D9D92F2F3535",
+"P c #D9D930303535",
+"I c #DADA33333939",
+"U c #DADA34343A3A",
+"Y c #DCDC35353A3A",
+"T c #DCDC38383E3E",
+"R c #DCDC39393F3F",
+"E c #DEDE3B3B4040",
+"W c #DEDE3E3E4343",
+"Q c #DEDE3F3F4444",
+"! c #DFDF3F3F4444",
+"~ c #DADA42424646",
+"^ c #DCDC46464B4B",
+"/ c #DDDD48484C4C",
+"( c #DDDD49494D4D",
+") c #DEDE4D4D5050",
+"_ c #DFDF51515555",
+"` c #E0E043434848",
+"' c #E0E044444949",
+"] c #E0E045454A4A",
+"[ c #E1E149494E4E",
+"{ c #E2E24A4A5050",
+"} c #E0E055555959",
+"| c #E2E25A5A5D5D",
+" . c #E3E35E5E6262",
+".. c #E5E562626666",
+"X. c #E6E667676B6B",
+"o. c #E8E86A6A6F6F",
+"O. c #E8E86C6C7070",
+"+. c #8181BBBB9898",
+"@. c #8181BCBC9898",
+"#. c #8181BCBC9999",
+"$. c #9A9AAAAA9696",
+"%. c #9B9BAAAA9696",
+"&. c #9D9DADAD9999",
+"*. c #9E9EADAD9999",
+"=. c #9F9FB9B9ACAC",
+"-. c #A3A3B2B29F9F",
+";. c #BABAB1B19A9A",
+":. c #C6C6AFAF8C8C",
+">. c #D1D1C5C5AEAE",
+",. c #D8D8CECEBABA",
+"<. c #DADAD0D0BCBC",
+"1. c #C9C9C3C3C3C3",
+"2. c gray81",
+"3. c #DFDFD5D5C4C4",
+"4. c gray82",
+"5. c LightGray",
+"6. c #D1D1D5D5D1D1",
+"7. c #D7D7D7D7D7D7",
+"8. c #DEDEE4E4DEDE",
+"9. c #E3E3DFDFDFDF",
+"0. c #E1E1E0E0D5D5",
+"q. c #E5E5E5E5DADA",
+"w. c #E5E5E7E7E2E2",
+"e. c #E7E7E7E7E7E7",
+"r. c #E9E9E9E9E9E9",
+"t. c #E9E9EBEBE9E9",
+"y. c gray92",
+"u. c #F2F2EEEEEEEE",
+"i. c #F3F3F0F0F0F0",
+"p. c #F4F4F1F1F1F1",
+"a. c #F6F6F2F2F2F2",
+"s. c #F4F4F4F4F4F4",
+"d. c gray96",
+"f. c #F4F4F6F6F5F5",
+"g. c #F5F5F6F6F5F5",
+"h. c #F5F5F7F7F6F6",
+"j. c #F7F7F4F4F4F4",
+"k. c #F6F6F6F6F6F6",
+"l. c gray97",
+"z. c #F5F5F8F8F6F6",
+"x. c #F6F6F8F8F7F7",
+"c. c #F7F7F9F9F8F8",
+"v. c #F8F8F4F4F4F4",
+"b. c #F9F9F5F5F6F6",
+"n. c #FBFBF7F7F7F7",
+"m. c #F8F8FAFAF9F9",
+"M. c #F9F9FBFBFAFA",
+"N. c gray98",
+"B. c #FAFAFBFBFBFB",
+"V. c #FBFBFBFBFBFB",
+"C. c #FBFBFCFCFCFC",
+"Z. c gray99",
+"A. c #FDFDFDFDFDFD",
+"S. c #FDFDFDFDFEFE",
+"D. c None",
+/* pixels */
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"- : : : - y.y.y.r.e.9.D D A A Z ",
+"; @. at .@.j C.C.C.C.C.n.O.o.X...Z ",
+"; +.p p q C.C.V.Z.m.b.{ [ ' .N ",
+"- k p y 0 C.C.<.,.b.v.' ` ~ | m ",
+"* k y e 6 m.3.:.V >.v.! ! E _ m ",
+"& j q 9 4 c.q.;.C 9.a.R T I _ m ",
+"% g 0 6 1 k.-.=.%.$.i.Y Y P ( b ",
+"$ f 6 2 , k.e.&.%.8.u.P K G ( b ",
+"# d 2 1 > f.k.k.g.g.u.H G G ( x ",
+"@ s p r 8 a.b.k.s.s.a.( / ^ ~ x ",
+"+ O o X X 6.7.5.4.2.1.b b x x x ",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D."
+};
diff --git a/src/images/flags/MY.xpm b/src/images/flags/MY.xpm
new file mode 100644
index 0000000..e4bfea0
--- /dev/null
+++ b/src/images/flags/MY.xpm
@@ -0,0 +1,181 @@
+/* XPM */
+static const char *MY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 159 2",
+" c black",
+". c #0B0B03039797",
+"X c #0D0D07079797",
+"o c #111109099999",
+"O c #00000000C1C1",
+"+ c #00000000C3C3",
+"@ c #00000000C5C5",
+"# c #00000000C9C9",
+"$ c #3B3B3B3BD9D9",
+"% c #72726F6FBDBD",
+"& c #41414141D7D7",
+"* c #40404040DADA",
+"= c #47474747DBDB",
+"- c #46464646DCDC",
+"; c #4B4B4A4ADDDD",
+": c #4C4C4C4CDBDB",
+"> c #7C7C7A7AC6C6",
+", c #6D6D6D6DE1E1",
+"< c #B1B100000000",
+"1 c #B7B700000000",
+"2 c #BBBB00000000",
+"3 c #878777774B4B",
+"4 c #C3C300000000",
+"5 c #C9C900000000",
+"6 c #CBCB00000000",
+"7 c #CFCF00000000",
+"8 c #D1D100000000",
+"9 c #D5D500000000",
+"0 c #D7D700000000",
+"q c #D9D900000000",
+"w c #DADA1A1A1A1A",
+"e c #DCDC1D1D1D1D",
+"r c #DDDD22222222",
+"t c #DDDD25252525",
+"y c #DFDF26262626",
+"u c #DFDF2A2A2A2A",
+"i c #E0E02B2B2B2B",
+"p c #E0E02F2F2F2F",
+"a c #E1E131313131",
+"s c #E2E231313232",
+"d c #E1E134343434",
+"f c #E2E234343434",
+"g c #E2E236363636",
+"h c #E0E03B3B3B3B",
+"j c #E2E238383939",
+"k c #E3E339393939",
+"l c #E3E33E3E3E3E",
+"z c #E4E43B3B3B3B",
+"x c #E4E43C3C3C3C",
+"c c #DADA36364040",
+"v c #DCDC3C3C4545",
+"b c #DDDD42424A4A",
+"n c #DEDE46464F4F",
+"m c #DEDE47474E4E",
+"M c #E2E244444444",
+"N c #E5E542424242",
+"B c #E5E543434343",
+"V c #E6E641414141",
+"C c #E7E746464646",
+"Z c #E7E747474747",
+"A c #E8E84A4A4A4A",
+"S c #E8E84C4C4D4D",
+"D c #EAEA4F4F4F4F",
+"F c #E0E04A4A5454",
+"G c #E0E04F4F5959",
+"H c #E4E450505050",
+"J c #E1E151515858",
+"K c #E7E758585757",
+"L c #E9E951515151",
+"P c #EEEE6F6F6F6F",
+"I c #E7E76F6F7777",
+"U c #C3C3ADAD2525",
+"Y c #E8E8DADA7E7E",
+"T c #F2F2E3E37B7B",
+"R c #F2F2E3E37C7C",
+"E c #F2F2E5E57F7F",
+"W c #F4F4E7E77C7C",
+"Q c #A0A09A9AB6B6",
+"! c #B8B8B1B1AAAA",
+"~ c #92928F8FCFCF",
+"^ c #94949191D0D0",
+"/ c #B1B1ADADC3C3",
+"( c #D5D59D9D9D9D",
+") c #D7D79D9D9D9D",
+"_ c #D7D79F9F9F9F",
+"` c #D7D7A1A1A1A1",
+"' c #DBDBA5A5A3A3",
+"] c #DDDDA7A7A7A7",
+"[ c #DDDDA9A9A9A9",
+"{ c #DFDFABABABAB",
+"} c #DDDDBBBBBBBB",
+"| c #E3E3AFAFAFAF",
+" . c #E5E5B3B3B3B3",
+".. c #E7E7B7B7B7B7",
+"X. c #E9E9B9B9B9B9",
+"o. c #EBEBBDBDBDBD",
+"O. c #DBDBCFCF8282",
+"+. c #DCDCCFCF8181",
+"@. c #DCDCD0D08484",
+"#. c #DCDCD0D08585",
+"$. c #DDDDD1D18787",
+"%. c #DEDED3D38B8B",
+"&. c #DDDDD4D4A5A5",
+"*. c #E6E6DBDB8989",
+"=. c #E3E3DADA9E9E",
+"-. c #F5F5EAEA9595",
+";. c #F2F2E8E89999",
+":. c #F2F2E8E89B9B",
+">. c #F2F2E8E89C9C",
+",. c #DFDFC3C3C3C3",
+"<. c #E5E5C5C5C5C5",
+"1. c #E7E7C7C7C7C7",
+"2. c #EDEDC1C1C1C1",
+"3. c #EFEFC3C3C3C3",
+"4. c #EBEBD3D3D3D3",
+"5. c #F1F1C7C7C5C5",
+"6. c #F7F7DFDFDFDF",
+"7. c #EEEEE5E5EEEE",
+"8. c #F2F2E2E2E2E2",
+"9. c #F2F2E3E3E3E3",
+"0. c #F3F3E4E4E4E4",
+"q. c #F3F3E5E5E5E5",
+"w. c #F3F3E6E6E6E6",
+"e. c #F4F4E4E4E4E4",
+"r. c #F4F4E5E5E5E5",
+"t. c #F5F5E5E5E5E5",
+"y. c #F4F4E6E6E6E6",
+"u. c #F4F4E7E7E7E7",
+"i. c #F5F5E6E6E6E6",
+"p. c #F5F5E7E7E7E7",
+"a. c #F6F6E6E6E6E6",
+"s. c #F6F6E7E7E7E7",
+"d. c #F1F1E7E7EEEE",
+"f. c #F7F7E8E8E7E7",
+"g. c #F6F6E8E8E8E8",
+"h. c #F6F6E9E9E9E9",
+"j. c #F7F7E8E8E8E8",
+"k. c #F7F7EAEAEAEA",
+"l. c #F7F7EBEBEBEB",
+"z. c #F7F7EDEDEDED",
+"x. c #FBFBE7E7E5E5",
+"c. c #F8F8E9E9E8E8",
+"v. c #F8F8EBEBEBEB",
+"b. c #F9F9EAEAEAEA",
+"n. c #F8F8EDEDECEC",
+"m. c #F9F9EDEDEDED",
+"M. c #F9F9EEEEEDED",
+"N. c #F8F8EEEEEEEE",
+"B. c #F9F9EFEFEFEF",
+"V. c #FAFAEEEEEEEE",
+"C. c #FAFAEFEFEEEE",
+"Z. c #F5F5EFEFF5F5",
+"A. c #FAFAF0F0F0F0",
+"S. c #FBFBF0F0F0F0",
+"D. c #FBFBF1F1F0F0",
+"F. c #FBFBF2F2F2F2",
+"G. c #FCFCF2F2F2F2",
+"H. c #FCFCF4F4F3F3",
+"J. c None",
+/* pixels */
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"# o U U X @ O O 5 q 0 0 8 8 5 5 ",
+"o >.:./ &.=.~ , Z.G.F.D.B.N.z.4.",
+"3 :.! *.E T #.: J L S Z B x K 4 ",
+"3 :.Q %.T Y O.= d.b.f.f.f.a.g.1.",
+". -.W > #.+.% & m Z N l k f F 2 ",
+"@ ^ #.+.; - * $ 7.a.a.a.q.w.w.<.",
+"5 I G F n b v c s k f p u r M 1 ",
+"x.H.D.D.D.N.N.b.k.a.a.q.q.q.w.,.",
+"q P D A C V k f s u y r w w h < ",
+"6.S.N.N.N.N.b.b.g.r.r.q.q.8.8.} ",
+"5.3.2.o..... .| { [ ] ' ` ` ( ( ",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J."
+};
diff --git a/src/images/flags/MZ.xpm b/src/images/flags/MZ.xpm
new file mode 100644
index 0000000..5912bdd
--- /dev/null
+++ b/src/images/flags/MZ.xpm
@@ -0,0 +1,193 @@
+/* XPM */
+static const char *MZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 171 2",
+" c black",
+". c gray10",
+"X c gray12",
+"o c #141416162222",
+"O c #19191B1B2626",
+"+ c #1F1F21212B2B",
+"@ c #252525252525",
+"# c #2A2A2B2B2B2B",
+"$ c #242426263131",
+"% c #2A2A2C2C3636",
+"& c #2F2F31313B3B",
+"* c #313128283131",
+"= c #36362D2D3636",
+"- c gray19",
+"; c gray21",
+": c #3B3B33333B3B",
+"> c gray23",
+", c #353536364040",
+"< c #363637374141",
+"1 c #00004D4D0000",
+"2 c #000051510000",
+"3 c #00005D5D0000",
+"4 c #000061610000",
+"5 c #000063630000",
+"6 c #000067670000",
+"7 c #00006D6D0000",
+"8 c #000071710000",
+"9 c #000075750000",
+"0 c #000079790000",
+"q c #00007D7D0000",
+"w c #404037374040",
+"e c #46463C3C4545",
+"r c #55553C3C4646",
+"t c #4B4B42424B4B",
+"y c #4E4E46464E4E",
+"u c #505047475050",
+"i c #6A6A4C4C5454",
+"p c #6C6C72726E6E",
+"a c #000081810000",
+"s c #000083830000",
+"d c #000085850000",
+"f c #000087870000",
+"g c #000089890000",
+"h c #000091910000",
+"j c #2C2CA8A82C2C",
+"k c #3131ABAB3131",
+"l c #3737AEAE3737",
+"z c #3D3DB0B03D3D",
+"x c #4242B3B34242",
+"c c #4747B5B54747",
+"v c #4949B3B34949",
+"b c #4C4CB7B74C4C",
+"n c #4E4EB4B44E4E",
+"m c #5353B7B75353",
+"M c #5151BABA5151",
+"N c #5454BCBC5454",
+"B c #5858B9B95757",
+"V c #5C5CBBBB5C5C",
+"C c #6161BEBE6060",
+"Z c #5959C1C15959",
+"A c #6565C0C06565",
+"S c #6969C2C26969",
+"D c #6D6DC3C36D6D",
+"F c #7070C5C57171",
+"G c #7474C7C77474",
+"H c #7777C8C87777",
+"J c #7979CECE7979",
+"K c #8D8D2F2F0000",
+"L c #91917E7E7474",
+"P c #BCBC40404040",
+"I c #E7E700000000",
+"U c #EFEF00000000",
+"Y c #F5F500000000",
+"T c #F7F700000000",
+"R c #F9F900000000",
+"E c red",
+"W c #F5F515150000",
+"Q c #C2C242424B4B",
+"! c #CFCF51515959",
+"~ c #FBFB46464646",
+"^ c #FAFA45454848",
+"/ c #FAFA4D4D4444",
+"( c #FBFB4A4A4949",
+") c #FBFB55554545",
+"_ c #FCFC57574B4B",
+"` c #FDFD56565555",
+"' c #F9F959595959",
+"] c #E5E56A6A5454",
+"[ c #F0F067675F5F",
+"{ c #FEFE68685C5C",
+"} c #FCFC66666666",
+"| c #FBFB7B7B6262",
+" . c #FCFC7A7A6A6A",
+".. c #FEFE79797979",
+"X. c #FFFF7B7B7A7A",
+"o. c #8F8FA0A05C5C",
+"O. c #9191BEBE7B7B",
+"+. c #BBBBAFAF7F7F",
+"@. c #DDDD81810000",
+"#. c #DDDD83830000",
+"$. c #DDDD87870000",
+"%. c #DFDF87870000",
+"&. c #DDDD89890000",
+"*. c #DFDF95950000",
+"=. c #E1E18B8B0000",
+"-. c #E3E38F8F0000",
+";. c #E5E591910000",
+":. c #E7E793930000",
+">. c #E9E999990000",
+",. c #EBEB9D9D0000",
+"<. c #EDED9F9F0000",
+"1. c #FAFA9E9E3F3F",
+"2. c #EDEDA3A30000",
+"3. c #EFEFA7A70000",
+"4. c #F3F3A1A10000",
+"5. c #F1F1B7B70000",
+"6. c #CDCD83837676",
+"7. c #DFDF8F8F7B7B",
+"8. c #E2E287876666",
+"9. c #F1F1CACA0B0B",
+"0. c #F1F1CBCB0E0E",
+"q. c #F2F2CCCC1313",
+"w. c #F3F3CECE1919",
+"e. c #F4F4D0D01E1E",
+"r. c #F2F2CACA2C2C",
+"t. c #F2F2CACA2F2F",
+"y. c #F2F2CCCC3232",
+"u. c #F3F3CDCD3535",
+"i. c #F4F4CFCF3939",
+"p. c #F5F5D2D22323",
+"a. c #F2F2D1D12F2F",
+"s. c #F6F6D4D42929",
+"d. c #F7F7D6D62E2E",
+"f. c #F5F5D0D03D3D",
+"g. c #F8F8D8D83434",
+"h. c #F9F9DBDB3A3A",
+"j. c #EEEEC5C55858",
+"k. c #F2F2C9C95E5E",
+"l. c #FAFAC4C45D5D",
+"z. c #F6F6D2D24242",
+"x. c #F7F7D3D34646",
+"c. c #F7F7D5D54B4B",
+"v. c #F8F8D7D75050",
+"b. c #F9F9D9D95555",
+"n. c #E6E6C9C97777",
+"m. c #F4F4CFCF6464",
+"M. c #F9F9E1E15858",
+"N. c #B9B9CDCDB9B9",
+"B. c #DFDFD8D8BFBF",
+"V. c #DEDEE7E7DEDE",
+"C. c #E0E0DADAC1C1",
+"Z. c #E2E2DBDBC4C4",
+"A. c #E2E2DDDDC6C6",
+"S. c #E2E2DDDDC8C8",
+"D. c #E4E4D8D8CACA",
+"F. c #E4E4DEDEC8C8",
+"G. c #F9F9D5D5C2C2",
+"H. c #E5E5E0E0CACA",
+"J. c #E6E6E2E2CCCC",
+"K. c #E6E6E3E3CDCD",
+"L. c #EAEAE5E5CFCF",
+"P. c #E0E0E9E9E0E0",
+"I. c #E1E1EAEAE1E1",
+"U. c #E2E2EBEBE2E2",
+"Y. c #E3E3EBEBE3E3",
+"T. c #E4E4EDEDE4E4",
+"R. c #E5E5EEEEE5E5",
+"E. c #E7E7EFEFE7E7",
+"W. c #E8E8F0F0E8E8",
+"Q. c #E9E9F1F1E9E9",
+"!. c None",
+/* pixels */
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"K d h g g a a q 0 9 8 7 6 4 3 4 ",
+"E 7.O.J G G F D D C C V B M b 1 ",
+"E X.[ o.Z N M b c x z l k j n 1 ",
+"E X.{ ' D.Q.Q.E.T.T.T.U.U.V.U.N.",
+"Y 6.j.] ` ! i u t e : : = * y ",
+"U n.p k._ ~ P > ; - # @ X . > ",
+"I L m.8.~ Q r < & % $ $ o o < ",
+"T .( ) G.L.K.J.J.F.S.A.C.B.S.+.",
+"T } / 1.h.g.d.s.p.w.w.q.0.9.a.;.",
+"T | l.M.b.v.c.x.z.f.i.u.y.t.t. at .",
+"W 4.5.4.2.<.,.>.:.;.-.=.&.&. at .&.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!."
+};
diff --git a/src/images/flags/NA.xpm b/src/images/flags/NA.xpm
new file mode 100644
index 0000000..237e9cb
--- /dev/null
+++ b/src/images/flags/NA.xpm
@@ -0,0 +1,182 @@
+/* XPM */
+static const char *NA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 160 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002D2D0000",
+"O c #00002F2F0000",
+"+ c #000031310000",
+"@ c #000033330000",
+"# c #000035350000",
+"$ c #000039390000",
+"% c #00003B3B0000",
+"& c #00003D3D0000",
+"* c #00003F3F0000",
+"= c #000000007373",
+"- c #000000007979",
+"; c #000000007D7D",
+": c #000041410000",
+"> c #000047470000",
+", c #000049490000",
+"< c #00005B5B0000",
+"1 c #000065650000",
+"2 c #000000008181",
+"3 c #000000008383",
+"4 c #000000008787",
+"5 c #000000008989",
+"6 c #000000008D8D",
+"7 c #000000009191",
+"8 c #51515151B7B7",
+"9 c #53535353BBBB",
+"0 c #56565555BCBC",
+"q c #58585757B5B5",
+"w c #5A5A5A5ABABA",
+"e c #6F6F6A6AAEAE",
+"r c #79797070A3A3",
+"t c #7D7D7575A1A1",
+"y c #7C7C7575A6A6",
+"u c #67676767C6C6",
+"i c #69696969C0C0",
+"p c #6D6D6D6DC3C3",
+"a c #6F6F6F6FC3C3",
+"s c #70707070C5C5",
+"d c #72727272C6C6",
+"f c #74747474C7C7",
+"g c #75757777CACA",
+"h c #77777676C8C8",
+"j c #7D7D7B7BC5C5",
+"k c #7E7E7D7DCACA",
+"l c #0B0B95950B0B",
+"z c #0F0F97970E0E",
+"x c #101097971010",
+"c c #131399991313",
+"v c #141499991414",
+"b c #14149A9A1414",
+"n c #19199B9B1919",
+"m c #1A1A9A9A1A1A",
+"M c #18189C9C1919",
+"N c #19199C9C1919",
+"B c #1F1F9C9C1F1F",
+"V c #1E1E9E9E1E1E",
+"C c #2525A1A12525",
+"Z c #2C2CA2A22C2C",
+"A c #2F2FA4A42F2F",
+"S c #3232A5A53232",
+"D c #3232A6A63232",
+"F c #3333A6A63232",
+"G c #3535A8A83535",
+"H c #3636A8A83636",
+"J c #3939A9A93939",
+"K c #3B3BAAAA3B3B",
+"L c #3F3FABAB3F3F",
+"P c #3D3DACAC3D3D",
+"I c #3F3FB1B14242",
+"U c #4242AEAE4242",
+"Y c #4646AEAE4646",
+"T c #5555BCBC5C5C",
+"R c #7C7CCBCB8383",
+"E c #EBEB00000000",
+"W c #EDED00000000",
+"Q c #EFEF00000000",
+"! c #F1F100000000",
+"~ c #F3F300000000",
+"^ c #F5F500000000",
+"/ c #F7F70D0D0707",
+"( c #F6F62C2C2D2D",
+") c #F7F730303030",
+"_ c #F7F731313131",
+"` c #F8F835353535",
+"' c #F8F836363636",
+"] c #F8F837373636",
+"[ c #F8F837373737",
+"{ c #F9F93A3A3A3A",
+"} c #F9F93B3B3A3A",
+"| c #F9F93B3B3B3B",
+" . c #F9F93B3B3C3C",
+".. c #FAFA3F3F3F3F",
+"X. c #F8F83D3D4343",
+"o. c #F7F741414848",
+"O. c #F7F74E4E4E4E",
+"+. c #FAFA42424040",
+"@. c #FAFA4B4B4545",
+"#. c #F6F64C4C5353",
+"$. c #F9F950504A4A",
+"%. c #F8F853535353",
+"&. c #FAFA5D5D5656",
+"*. c #F9F95B5B5F5F",
+"=. c #FAFA5D5D5D5D",
+"-. c #F9F961615F5F",
+";. c #FBFB61616262",
+":. c #F8F866666D6D",
+">. c #FBFB70706B6B",
+",. c #F7F777777A7A",
+"<. c #F9F978787474",
+"1. c #F7F7DADA5D5D",
+"2. c #EDEDD2D26666",
+"3. c #ECECD2D26B6B",
+"4. c #F4F4D9D96262",
+"5. c #94948F8FB9B9",
+"6. c #85858282C3C3",
+"7. c #84848282C5C5",
+"8. c #8C8C8888C1C1",
+"9. c #8F8F9595D6D6",
+"0. c #91919595D3D3",
+"q. c #9B9B9F9FD8D8",
+"w. c #A3A3A8A8DEDE",
+"e. c #B5B5BABAE3E3",
+"r. c #8181C9C98989",
+"t. c #8888D0D08D8D",
+"y. c #9696D5D59C9C",
+"u. c #ABABDDDDAFAF",
+"i. c #B9B9C7C7ADAD",
+"p. c #CBCBA9A99393",
+"a. c #F6F686868888",
+"s. c #FAFA8C8C8A8A",
+"d. c #F9F99F9F9F9F",
+"f. c #EDEDB2B2ADAD",
+"g. c #F7F7A9A9ABAB",
+"h. c #F3F3B2B2AEAE",
+"j. c #D7D7BBBBCDCD",
+"k. c #ECECC0C0BBBB",
+"l. c #DDDDD7D7E7E7",
+"z. c #C5C5E2E2C5C5",
+"x. c #C7C7E3E3C7C7",
+"c. c #D1D1E5E5D0D0",
+"v. c #DEDEE2E2D5D5",
+"b. c #DDDDEAEADCDC",
+"n. c #E9E9CBCBC4C4",
+"m. c #E2E2D8D8CCCC",
+"M. c #E2E2DFDFD3D3",
+"N. c #F9F9C1C1C2C2",
+"B. c #F3F3D0D0D3D3",
+"V. c #F1F1D3D3D7D7",
+"C. c #F2F2DDDDE1E1",
+"Z. c #EBEBE1E1EBEB",
+"A. c #ECECE7E7EFEF",
+"S. c #E0E0E1E1F2F2",
+"D. c #E1E1E2E2F2F2",
+"F. c #E4E4E4E4F2F2",
+"G. c #EAEAEAEAF4F4",
+"H. c #EDEDE9E9F1F1",
+"J. c #F2F2E4E4E9E9",
+"K. c None",
+/* pixels */
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"7 5 6 7 5 3 3 ; - = 4 0.j.~ W W ",
+"4 k 8.5.j f s p i q.G.B.-.%.O.E ",
+"6 7.3.4.y 0 8 w e.Z.<.] _ ( g.i.",
+"6 6.2.1.t 8 h F.V.$.] _ #.n.z.< ",
+"4 h e r q w.A.s. .] _ a.v.R L * ",
+"4 d 9 u D.C.&.{ ] X.k.x.I m K * ",
+"- p 9.H.d.+.{ ] ,.M.y.C m v H @ ",
+"5 D.J.>...{ X.f.c.T V M v x D + ",
+"l.N. at ...{ :.m.u.D V M v x l A o ",
+"/ ;.=.*.h.b.t.Y U P J H S A Z X ",
+"^ ^ ~ p.r.1 , > * * % @ o o X @ ",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K."
+};
diff --git a/src/images/flags/NC.xpm b/src/images/flags/NC.xpm
new file mode 100644
index 0000000..f04eaee
--- /dev/null
+++ b/src/images/flags/NC.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *NC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000005050000",
+"X c #00000D0D0000",
+"o c #000015150000",
+"O c #00001B1B0000",
+"+ c #000023230000",
+"@ c #000029290000",
+"# c #000031310000",
+"$ c #000037370000",
+"% c #252500003535",
+"& c #0B0B6D6D3939",
+"* c #0F0F6F6F3C3C",
+"= c #10106F6F3D3D",
+"- c #131372724040",
+"; c #141472724141",
+": c #181875754545",
+"> c #191975754545",
+", c #1E1E79794949",
+"< c #1F1F79794949",
+"1 c #23237C7C4E4E",
+"2 c #24247D7D4E4E",
+"3 c #2C2C7F7F5353",
+"4 c #71711D1D7D7D",
+"5 c #474747473434",
+"6 c #484848483A3A",
+"7 c #4D4D4D4D3A3A",
+"8 c #545455552F2F",
+"9 c #535352523F3F",
+"0 c #5C5C5E5E4040",
+"q c #50507F7F6A6A",
+"w c #6D6D6D6D4646",
+"e c #727271714B4B",
+"r c #767676765050",
+"t c #767676765151",
+"y c #00000000A5A5",
+"u c #00000000A9A9",
+"i c #00000505ADAD",
+"p c #00000D0DAFAF",
+"a c #00001515B3B3",
+"s c #00001B1BB7B7",
+"d c #00002323B9B9",
+"f c #00002929BDBD",
+"g c #00002F2FBFBF",
+"h c #00003535C3C3",
+"j c #00003939C3C3",
+"k c #00003F3FC7C7",
+"l c #00004343C9C9",
+"z c #00004747C9C9",
+"x c #00004B4BCBCB",
+"c c #0F0F4B4BC3C3",
+"v c #2F2F81815555",
+"b c #2F2F81815656",
+"n c #323283835858",
+"m c #333384845959",
+"M c #353585855B5B",
+"N c #393989895F5F",
+"B c #3D3D8B8B6262",
+"V c #42428E8E6565",
+"C c #4B4B8A8A6C6C",
+"Z c #464691916969",
+"A c #545484846E6E",
+"S c #585891917878",
+"D c #5D5DA0A07D7D",
+"F c #7676ACAC4343",
+"G c #7979A8A84040",
+"H c #6161A3A38080",
+"J c #6666A6A68484",
+"K c #4B4B8282D5D5",
+"L c #50508686D7D7",
+"P c #55558989D9D9",
+"I c #5A5A8D8DDBDB",
+"U c #5E5E9090DCDC",
+"Y c #62629494DEDE",
+"T c #64649393DBDB",
+"R c #69699696DCDC",
+"E c #6D6D9999DDDD",
+"W c #71719C9CDFDF",
+"Q c #75759F9FE1E1",
+"! c #7979A2A2E2E2",
+"~ c #7C7CA5A5E3E3",
+"^ c #7F7FA8A8E4E4",
+"/ c #E3E300000000",
+"( c #E5E500000000",
+") c #E7E700000000",
+"_ c #FDFD00000505",
+"` c #FDFD00000707",
+"' c #FDFD00000B0B",
+"] c #F2F214144141",
+"[ c #F3F319194545",
+"{ c #F3F31A1A4545",
+"} c #F4F41F1F4949",
+"| c #F4F41F1F4A4A",
+" . c #F4F420204545",
+".. c #F5F525254A4A",
+"X. c #F5F524244F4F",
+"o. c #F5F525254E4E",
+"O. c #F6F62B2B4F4F",
+"+. c #F6F62B2B5353",
+"@. c #F6F62A2A5454",
+"#. c #F7F730305353",
+"$. c #F7F730305959",
+"%. c #F4F436365C5C",
+"&. c #F8F836365959",
+"*. c #F4F43B3B6060",
+"=. c #F5F53F3F6060",
+"-. c #98986161A0A0",
+";. c #9B9B6565A3A3",
+":. c #9E9E6969A6A6",
+">. c #A1A16D6DA9A9",
+",. c #A4A47171ABAB",
+"<. c #A6A67777ADAD",
+"1. c #919191913434",
+"2. c #989898984040",
+"3. c #9B9B9B9B4545",
+"4. c #9E9E9E9E4B4B",
+"5. c #A0A0A0A04F4F",
+"6. c #A4A4A4A45454",
+"7. c #A8A8C7C75353",
+"8. c #B7B7D4D47979",
+"9. c #FCFCB9B97B7B",
+"0. c #F5F5C1C13A3A",
+"q. c #F5F5F5F52F2F",
+"w. c #F8F8F1F13737",
+"e. c #F8F8F8F83535",
+"r. c #F9F9F9F93A3A",
+"t. c #F9F9F9F93B3B",
+"y. c #D3D3D7D75050",
+"u. c #DEDEE2E27070",
+"i. c #F7F7C6C64444",
+"p. c #ECECEEEE5B5B",
+"a. c #FAFAFAFA4141",
+"s. c #FBFBFBFB4646",
+"d. c #F9F9F9F94848",
+"f. c #FBFBF9F94F4F",
+"g. c #FBFBFCFC4949",
+"h. c #FCFCFCFC4B4B",
+"j. c #F1F1F1F15A5A",
+"k. c #FDFDFDFD5353",
+"l. c #FCFCFCFC5454",
+"z. c #FDFDFDFD5454",
+"x. c #FBFBF9F95858",
+"c. c #FEFEFEFE5959",
+"v. c #FCFCEEEE7575",
+"b. c #F5F5F5F56161",
+"n. c #9F9FBCBCA8A8",
+"m. c #9898ADADCACA",
+"M. c #9999AEAEC9C9",
+"N. c #8383AAAAE5E5",
+"B. c #8989A4A4E1E1",
+"V. c #8F8FAAAAE2E2",
+"C. c #8F8FB3B3E8E8",
+"Z. c #8F8FB3B3E9E9",
+"A. c #C6C6A8A88686",
+"S. c #FDFDBEBE8383",
+"D. c #C2C2CFCF9595",
+"F. c #E2E2D0D09E9E",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"x x x x z l k j h g f d s a p i ",
+"c Z.Z.V.M.M.B.N.^ ~ ! Q W E R u ",
+"x Z.D.u.j.l.p.n.Y U I P L K T y ",
+"4 F.b.c.6.t h.d.A.,.>.:.;.-.<.% ",
+"` S.x.k.t 4.s.a.i.&.#.O... .=.) ",
+"' v.l.5.e w 1.t.w.$.+.X.| { %.) ",
+"` 9.l.d.3.3.t.e.0. at .X.| { ] %./ ",
+"$ 8.y.3.0 6 1.q.F 2 , > ; = m ",
+"# J 7.0 6 5 8 G 1 , > - = & b ",
+"@ D D S A A C Z V B N M m v v ",
+"+ O o X . ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/NE.xpm b/src/images/flags/NE.xpm
new file mode 100644
index 0000000..9e4c608
--- /dev/null
+++ b/src/images/flags/NE.xpm
@@ -0,0 +1,178 @@
+/* XPM */
+static const char *NE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 156 2",
+" c black",
+". c #000021210000",
+"X c #000027270000",
+"o c #000029290000",
+"O c #00002D2D0000",
+"+ c #00002F2F0000",
+"@ c #000033330000",
+"# c #000035350000",
+"$ c #000039390000",
+"% c #00003D3D0000",
+"& c #000041410000",
+"* c #000047470000",
+"= c #00004D4D0000",
+"- c #000051510000",
+"; c #000057570000",
+": c #00005D5D0000",
+"> c #000063630000",
+", c #000065650000",
+"< c #00006F6F0000",
+"1 c #000071710000",
+"2 c #000075750000",
+"3 c #0B0B8F8F0B0B",
+"4 c #0F0F92920E0E",
+"5 c #131394941313",
+"6 c #181896961919",
+"7 c #1E1E99991E1E",
+"8 c #23239D9D2323",
+"9 c #2F2F9F9F2F2F",
+"0 c #2929A0A02929",
+"q c #2C2CA2A22C2C",
+"w c #2E2EA2A22E2E",
+"e c #2F2FA4A42F2F",
+"r c #3232A5A53232",
+"t c #3434A5A53434",
+"y c #3535A8A83535",
+"u c #3939A9A93939",
+"i c #3A3AA8A83A3A",
+"p c #3F3FABAB3F3F",
+"a c #3D3DACAC3D3D",
+"s c #4242AEAE4242",
+"d c #4444AEAE4444",
+"f c #4646B0B04646",
+"g c #4B4BB2B24B4B",
+"h c #5050B4B45050",
+"j c #5454B7B75555",
+"k c #5858B9B95858",
+"l c #5D5DBCBC5D5D",
+"z c #6161BEBE6262",
+"x c #6666BDBD6666",
+"c c #E9E900000000",
+"v c #EBEB03030000",
+"b c #EFEF0F0F0000",
+"n c #EDED1B1B0000",
+"m c #F1F119190000",
+"M c #F3F321210000",
+"N c #F5F527270000",
+"B c #F7F72D2D0000",
+"V c #F9F935350000",
+"C c #FBFB39390000",
+"Z c #FDFD3D3D0000",
+"A c #FDFD43430000",
+"S c #FFFF43430000",
+"D c #FDFD45450000",
+"F c #FDFD4B4B0000",
+"G c #FFFF4B4B0000",
+"H c #FFFF4D4D0000",
+"J c #FFFF59590000",
+"K c #F6F676762C2C",
+"L c #F7F77B7B3131",
+"P c #F8F875753636",
+"I c #F8F87F7F3737",
+"U c #F9F97C7C3B3B",
+"Y c #F9F982823D3D",
+"T c #F7F78A8A4949",
+"R c #FAFA86864242",
+"E c #FBFB8A8A4747",
+"W c #FCFC8D8D4C4C",
+"Q c #FDFD8F8F5151",
+"! c #F7F793934E4E",
+"~ c #F8F896965353",
+"^ c #FDFD93935454",
+"/ c #FEFE96965959",
+"( c #F9F998985757",
+") c #FAFA9B9B5C5C",
+"_ c #FEFE98985C5C",
+"` c #FEFE9A9A5F5F",
+"' c #FBFB9E9E6060",
+"] c #FCFCA1A16565",
+"[ c #FCFCA4A46969",
+"{ c #FDFDA7A76D6D",
+"} c #F7F7A4A47171",
+"| c #FDFDA9A97171",
+" . c #FEFEABAB7474",
+".. c #FEFEADAD7777",
+"X. c #F8F8A9A97878",
+"o. c #F9F9AEAE7F7F",
+"O. c #FFFFABAB7A7A",
+"+. c #FEFEAEAE7979",
+"@. c #FFFFB0B07B7B",
+"#. c #A1A1C7C7A1A1",
+"$. c #DBDBB5B59D9D",
+"%. c #F7F7B1B18686",
+"&. c #FAFAB2B28686",
+"*. c #FAFABDBD9898",
+"=. c #F6F6C8C8ACAC",
+"-. c #F8F8CDCDB3B3",
+";. c #F9F9CFCFB7B7",
+":. c #FBFBD4D4BDBD",
+">. c #C5C5DFDFC5C5",
+",. c LightGray",
+"<. c #D5D5D5D5D5D5",
+"1. c #D7D7D7D7D7D7",
+"2. c #D0D0E4E4D0D0",
+"3. c #D2D2E6E6D2D2",
+"4. c #D4D4E7E7D4D4",
+"5. c #D5D5E8E8D5D5",
+"6. c #D7D7E8E8D7D7",
+"7. c #D7D7EAEAD8D8",
+"8. c #D8D8ECECDCDC",
+"9. c #DADAEDEDDDDD",
+"0. c #DCDCEEEEDDDD",
+"q. c #DDDDEFEFDDDD",
+"w. c #DFDFF0F0DFDF",
+"e. c #F5F5D9D9C9C9",
+"r. c #F5F5E3E3D6D6",
+"t. c #F6F6E4E4D8D8",
+"y. c #F6F6E6E6DBDB",
+"u. c #F7F7E6E6DADA",
+"i. c #F8F8E8E8DBDB",
+"p. c #F9F9E9E9DEDE",
+"a. c #E0E0F0F0E0E0",
+"s. c #E2E2F1F1E2E2",
+"d. c #E8E8F4F4E8E8",
+"f. c #FAFAEAEAE0E0",
+"g. c #FBFBEBEBE1E1",
+"h. c #FCFCECECE1E1",
+"j. c #FDFDEDEDE2E2",
+"k. c #FDFDEEEEE3E3",
+"l. c #FEFEEFEFE5E5",
+"z. c #FEFEF2F2EAEA",
+"x. c #F1F1F1F1F1F1",
+"c. c gray95",
+"v. c #F3F3F3F3F3F3",
+"b. c #F4F4F4F4F4F4",
+"n. c #F4F4F5F5F5F5",
+"m. c gray96",
+"M. c #F6F6F6F6F6F6",
+"N. c gray97",
+"B. c gray98",
+"V. c #FBFBFBFBFBFB",
+"C. c #FBFBFCFCFBFB",
+"Z. c gray99",
+"A. c #FDFDFCFCFDFD",
+"S. c #FDFDFDFDFDFD",
+"D. c #FEFEFEFEFEFE",
+"F. c None",
+/* pixels */
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"J G H H G D S Z C V B N M m b n ",
+"H @.+.+.+. .| { [ ] ' ) ( ~ ! v ",
+"S O.' / / ^ Q W E R Y I L K T v ",
+"e.z.l.l.l.h.h.h.f.i.i.y.t.r.y.$.",
+"m.D.D.D.A.A.:.&.&.-.N.m.m.v.m.1.",
+"v.D.D.D.D.B.*.U P %.M.m.b.v.m.1.",
+"x.D.B.B.B.B.;.X.} =.M.m.v.v.v.,.",
+">.d.s.a.a.q.q.q.8.4.4.4.3.2.4.#.",
+"< x d p i t q 0 8 7 6 5 4 3 9 . ",
+"< z l k j h g f s a u y t w q o ",
+"2 , > : ; - = * & % $ @ O O X # ",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F."
+};
diff --git a/src/images/flags/NF.xpm b/src/images/flags/NF.xpm
new file mode 100644
index 0000000..7e0ac82
--- /dev/null
+++ b/src/images/flags/NF.xpm
@@ -0,0 +1,169 @@
+/* XPM */
+static const char *NF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 147 2",
+" c black",
+". c #000005050000",
+"X c #00000D0D0000",
+"o c #000013130000",
+"O c #000019190000",
+"+ c #000021210000",
+"@ c #000027270000",
+"# c #00002F2F0000",
+"$ c #000035350000",
+"% c #00003B3B0000",
+"& c #00003D3D0000",
+"* c #000041410000",
+"= c #000043430000",
+"- c #0B0B67670B0B",
+"; c #0F0F6A6A0E0E",
+": c #10106A6A1010",
+"> c #14146E6E1414",
+", c #191970701919",
+"< c #1A1A70701A1A",
+"1 c #1F1F74741F1F",
+"2 c #202075752020",
+"3 c #252578782525",
+"4 c #26267A7A2626",
+"5 c #2A2A73732A2A",
+"6 c #2F2F77772F2F",
+"7 c #2B2B7C7C2B2B",
+"8 c #2C2C7B7B2C2C",
+"9 c #2C2C7C7C2C2C",
+"0 c #2F2F7C7C2F2F",
+"q c #2F2F7D7D2F2F",
+"w c #32327F7F3232",
+"e c #33337F7F3232",
+"r c #35357C7C3535",
+"t c #35357E7E3535",
+"y c #3A3A7F7F3A3A",
+"u c #313181813131",
+"i c #363682823636",
+"p c #3B3B85853B3B",
+"a c #3D3D83833D3D",
+"s c #3F3F89893F3F",
+"d c #3F3F8A8A3F3F",
+"f c #414185854141",
+"g c #434386864343",
+"h c #44448C8C4444",
+"j c #44448E8E4444",
+"k c #45458E8E4545",
+"l c #4A4A8A8A4A4A",
+"z c #49498F8F4949",
+"x c #494991914949",
+"c c #4E4E93934E4E",
+"v c #4F4F95954F4F",
+"b c #50508E8E5050",
+"n c #535396965353",
+"m c #535397975353",
+"M c #545497975454",
+"N c #5A5A92925A5A",
+"B c #595994945959",
+"V c #5D5D91915D5D",
+"C c #5C5C93935C5C",
+"Z c #585898985757",
+"A c #585899995858",
+"S c #58589A9A5858",
+"D c #58589B9B5959",
+"F c #5D5D98985D5D",
+"G c #5C5C9D9D5C5C",
+"H c #5D5D9D9D5D5D",
+"J c #5F5F9F9F5F5F",
+"K c #61619F9F6262",
+"L c #63639C9C6363",
+"P c #6A6A9F9F6A6A",
+"I c #6666A3A36666",
+"U c #6A6AA5A56A6A",
+"Y c #6D6DA0A06D6D",
+"T c #6F6FA8A86F6F",
+"R c #7575A6A67575",
+"E c #7272AAAA7373",
+"W c #7676ADAD7676",
+"Q c #7B7BA7A77B7B",
+"! c #7979A9A97979",
+"~ c #7A7AA8A87A7A",
+"^ c #7979AEAE7979",
+"/ c #7E7EACAC7E7E",
+"( c #7B7BB0B07A7A",
+") c #7B7BB0B07B7B",
+"_ c #8080AAAA8080",
+"` c #8585AFAF8585",
+"' c #8686AEAE8686",
+"] c #8B8BB5B58B8B",
+"[ c #9090B3B39090",
+"{ c #9B9BBCBC9B9B",
+"} c #9B9BBDBD9B9B",
+"| c #A1A1C1C1A1A1",
+" . c #B2B2CBCBB2B2",
+".. c #B4B4CCCCB4B4",
+"X. c #B6B6CFCFB6B6",
+"o. c #B9B9D1D1B9B9",
+"O. c #BBBBD3D3BBBB",
+"+. c #BCBCD2D2BCBC",
+"@. c #BEBED5D5BEBE",
+"#. c #BFBFD5D5BFBF",
+"$. c #C3C3CBCBC3C3",
+"%. c #CBCBCFCFCBCB",
+"&. c #C0C0D6D6C0C0",
+"*. c #C4C4D6D6C4C4",
+"=. c #C2C2D8D8C2C2",
+"-. c #C4C4D9D9C4C4",
+";. c #C6C6DBDBC6C6",
+":. c #CBCBD1D1CBCB",
+">. c #C8C8DDDDC9C9",
+",. c #C9C9DDDDC9C9",
+"<. c #CACADDDDCACA",
+"1. c #CCCCDFDFCCCC",
+"2. c #CDCDDEDECDCD",
+"3. c #CECEDFDFCECE",
+"4. c #D7D7D7D7D7D7",
+"5. c #D7D7D9D9D5D5",
+"6. c #DDDDDDDDDDDD",
+"7. c #CECEE0E0CECE",
+"8. c #D7D7E7E7D7D7",
+"9. c #D9D9E3E3D9D9",
+"0. c #E2E2EDEDE2E2",
+"q. c #E5E5E9E9E5E5",
+"w. c #E9E9EEEEE9E9",
+"e. c #EBEBEDEDEBEB",
+"r. c #EBEBEFEFEBEB",
+"t. c #EFEFEFEFEFEF",
+"y. c #F1F1F1F1F1F1",
+"u. c #F0F0F2F2F0F0",
+"i. c #F3F3F3F3F3F3",
+"p. c #F1F1F6F6F1F1",
+"a. c gray96",
+"s. c #F5F5F6F6F5F5",
+"d. c #F5F5F7F7F5F5",
+"f. c #F6F6F6F6F6F6",
+"g. c #F6F6F7F7F6F6",
+"h. c gray97",
+"j. c #F7F7F8F8F7F7",
+"k. c #F8F8F9F9F7F7",
+"l. c #F9F9FAFAF9F9",
+"z. c gray98",
+"x. c #FAFAFBFBFAFA",
+"c. c #FBFBFBFBFBFB",
+"v. c #FBFBFCFCFBFB",
+"b. c gray99",
+"n. c #FDFDFDFDFDFD",
+"m. c #FDFDFDFDFEFE",
+"M. c None",
+/* pixels */
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"= = = = } r.i.y.r.t.q.] o X . ",
+"= ) ) ^ 8.v.n.p.0.x.x.2.Z n c ",
+"= ) J G 7.v.n./ R x.f.&.u 9 z ",
+"= ^ G D 7.x.x.L F f.h. at .7 4 h ",
+"% W Z M >.v. at .l g ` f.O.4 2 s ",
+"% E m v >.b.Q g y P f.O.1 < p ",
+"$ T v x ;.| P a r B [ X.> > i ",
+"$ U x h *.} b 8 5 r ` ..> : t ",
+"@ I j s *.r.7.C N *.9. .; ; 9 ",
+"O L G Z >.f.f._ Q f.y.+.w 9 8 ",
+"O O X . ! 5.6.%.$.4.%.V ",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M."
+};
diff --git a/src/images/flags/NG.xpm b/src/images/flags/NG.xpm
new file mode 100644
index 0000000..f2dea55
--- /dev/null
+++ b/src/images/flags/NG.xpm
@@ -0,0 +1,156 @@
+/* XPM */
+static const char *NG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 134 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002D2D0000",
+"O c #00002F2F0000",
+"+ c #000031310000",
+"@ c #000035350000",
+"# c #00003B3B0000",
+"$ c #00003F3F0000",
+"% c #000045450000",
+"& c #00004B4B0000",
+"* c #00004D4D0000",
+"= c #000053530000",
+"- c #00005B5B0000",
+"; c #00005D5D0000",
+": c #000061610000",
+"> c #000063630000",
+", c #000065650000",
+"< c #000067670000",
+"1 c #000069690000",
+"2 c #00006F6F0000",
+"3 c #000075750000",
+"4 c #000077770000",
+"5 c #00007B7B0000",
+"6 c #00007F7F0000",
+"7 c #000083830000",
+"8 c #000085850000",
+"9 c #000087870000",
+"0 c #000089890000",
+"q c #000091910000",
+"w c #0B0B95950B0B",
+"e c #0F0F96960E0E",
+"r c #101097971010",
+"t c #131397971313",
+"y c #141499991414",
+"u c #14149A9A1414",
+"i c #19199A9A1919",
+"p c #19199B9B1919",
+"a c #1A1A9C9C1A1A",
+"s c #1F1F9D9D1F1F",
+"d c #1F1F9E9E1F1F",
+"f c #20209F9F2020",
+"g c #2525A0A02525",
+"h c #2525A1A12525",
+"j c #2626A2A22626",
+"k c #2B2BA4A42B2B",
+"l c #2B2BA5A52B2B",
+"z c #2C2CA2A22C2C",
+"x c #2C2CA6A62C2C",
+"c c #2F2FA4A42F2F",
+"v c #3131A7A73131",
+"b c #3232A5A53232",
+"n c #3333A6A63232",
+"m c #3535A6A63535",
+"M c #3131A8A83131",
+"N c #3636A8A83636",
+"B c #3737AAAA3737",
+"V c #3A3AAAAA3A3A",
+"C c #3B3BAAAA3B3B",
+"Z c #3F3FADAD3F3F",
+"A c #3F3FAEAE3F3F",
+"S c #4040ADAD3F3F",
+"D c #4444AFAF4444",
+"F c #4444B1B14444",
+"G c #4545B0B04545",
+"H c #4545B1B14545",
+"J c #4949B2B24949",
+"K c #4B4BB3B34B4B",
+"L c #4949B4B44949",
+"P c #4E4EB4B44E4E",
+"I c #4F4FB6B64F4F",
+"U c #4F4FB7B74F4F",
+"Y c #5050B5B55050",
+"T c #5353B7B75353",
+"R c #5454B5B55555",
+"E c #5454B7B75454",
+"W c #5353B9B95353",
+"Q c #5454B9B95454",
+"! c #5858B9B95757",
+"~ c #5858B9B95858",
+"^ c #5858BBBB5959",
+"/ c #5959BABA5959",
+"( c #5858BCBC5858",
+") c #5C5CB9B95C5C",
+"_ c #5C5CBDBD5C5C",
+"` c #5D5DBCBC5D5D",
+"' c #5F5FBFBF5F5F",
+"] c #6161BEBE6262",
+"[ c #6666C0C06666",
+"{ c #6A6AC3C36A6A",
+"} c #6F6FC4C46F6F",
+"| c #7272C6C67373",
+" . c #7777C7C77777",
+".. c #7676C8C87676",
+"X. c #7979C8C87979",
+"o. c #7B7BCACA7A7A",
+"O. c #7B7BCACA7B7B",
+"+. c #BDBDC7C7BDBD",
+"@. c #C7C7D3D3C7C7",
+"#. c LightGray",
+"$. c #D7D7D7D7D7D7",
+"%. c gray85",
+"&. c #D9D9E3E3D9D9",
+"*. c #DFDFE9E9DFDF",
+"=. c #E7E7EEEEE7E7",
+"-. c gray92",
+";. c #E8E8EFEFE8E8",
+":. c gray93",
+">. c #EFEFEFEFEFEF",
+",. c #EAEAF0F0EAEA",
+"<. c #EBEBF1F1EBEB",
+"1. c #ECECF2F2ECEC",
+"2. c #EEEEF3F3EEEE",
+"3. c #EEEEF4F4EEEE",
+"4. c #EFEFF4F4EFEF",
+"5. c #EFEFF5F5EFEF",
+"6. c #F0F0F6F6F0F0",
+"7. c #F1F1F7F7F1F1",
+"8. c #F2F2F7F7F2F2",
+"9. c #F4F4F4F4F4F4",
+"0. c gray96",
+"q. c #F6F6F6F6F6F6",
+"w. c gray97",
+"e. c #F3F3F8F8F3F3",
+"r. c #F4F4F9F9F4F4",
+"t. c #F6F6FBFBF6F6",
+"y. c #F8F8F8F8F8F8",
+"u. c #F9F9F9F9F9F9",
+"i. c gray98",
+"p. c #FBFBFBFBFBFB",
+"a. c gray99",
+"s. c #FDFDFDFDFDFD",
+"d. c #FDFDFDFDFEFE",
+"f. c None",
+/* pixels */
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"q 0 0 9 7 *.>.>.>.-.&.1 < : ; : ",
+"9 O.O.O. .t.a.a.a.a.8.) ! Y I * ",
+"0 O.' _ ^ e.a.p.p.p.3.B M x J & ",
+"9 O./ / W e.a.p.p.p.3.v l h D % ",
+"9 ./ W Y 8.p.p.p.q.<.l h d D $ ",
+"9 | W I J 8.p.p.q.q.<.h d d V # ",
+"6 } I L D 8.w.w.q.q.:.f y u B @ ",
+"5 { L F Z 3.p.q.q.q.=.y t t v O ",
+"4 ] F D C <.w.q.q.q.=.t e w c O ",
+"2 ] ) ^ R 3.w.w.q.q.<.m v c c . ",
+"4 < : - = @.%.$.$.#.+.O X O X + ",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f."
+};
diff --git a/src/images/flags/NI.xpm b/src/images/flags/NI.xpm
new file mode 100644
index 0000000..e539d9d
--- /dev/null
+++ b/src/images/flags/NI.xpm
@@ -0,0 +1,170 @@
+/* XPM */
+static const char *NI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 148 2",
+" c black",
+". c #00000000DDDD",
+"X c #00000000DFDF",
+"o c #00000505DDDD",
+"O c #00000505DFDF",
+"+ c #00000909E1E1",
+"@ c #00000D0DE3E3",
+"# c #00001313E5E5",
+"$ c #00001919E7E7",
+"% c #00001F1FE9E9",
+"& c #00002525EBEB",
+"* c #00002929EBEB",
+"= c #00002B2BEDED",
+"- c #00003333EDED",
+"; c #00003737EFEF",
+": c #00003D3DF1F1",
+"> c #00005757DFDF",
+", c #00004343F3F3",
+"< c #00004949F5F5",
+"1 c #00004D4DF7F7",
+"2 c #00004F4FF5F5",
+"3 c #00004F4FF7F7",
+"4 c #00005F5FE7E7",
+"5 c #00005151F9F9",
+"6 c #00005555F9F9",
+"7 c #00005959FBFB",
+"8 c #00005D5DFDFD",
+"9 c #00006161FDFD",
+"0 c #00006565FDFD",
+"q c #00006767FFFF",
+"w c #00006969FDFD",
+"e c #00006B6BFFFF",
+"r c #00007171FFFF",
+"t c #12127E7EF1F1",
+"y c #16168181F1F1",
+"u c #1B1B8484F2F2",
+"i c #1F1F8787F3F3",
+"p c #25258989F4F4",
+"a c #2A2A8D8DF5F5",
+"s c #2F2F9191F6F6",
+"d c #2F2F9797FBFB",
+"f c #32329292F2F2",
+"g c #33339393F6F6",
+"h c #36369191F2F2",
+"j c #34349393F7F7",
+"k c #35359494F2F2",
+"l c #37379595F3F3",
+"z c #35359B9BFFFF",
+"x c #38389696F7F7",
+"c c #3A3A9696F8F8",
+"v c #3B3B9898F3F3",
+"b c #3E3E9999F8F8",
+"n c #3F3F9A9AF9F9",
+"m c #40409999F4F4",
+"M c #42429C9CF5F5",
+"N c #47479E9EF6F6",
+"B c #43439D9DF9F9",
+"V c #45459D9DFAFA",
+"C c #48489F9FFAFA",
+"Z c #4B4BA1A1F7F7",
+"A c #4F4FA2A2F7F7",
+"S c #4A4AA0A0FAFA",
+"D c #4C4CA2A2FBFB",
+"F c #5050A4A4F7F7",
+"G c #5454A7A7F7F7",
+"H c #5151A5A5FCFC",
+"J c #5555A7A7F8F8",
+"K c #5656A7A7FDFD",
+"L c #5858A9A9F8F8",
+"P c #5959A9A9F9F9",
+"I c #5A5AAAAAFDFD",
+"U c #5D5DABABF9F9",
+"Y c #5E5EACACF9F9",
+"T c #5E5EACACFEFE",
+"R c #6363AAAAF2F2",
+"E c #6666ADADF2F2",
+"W c #6161AEAEFAFA",
+"Q c #6262AFAFFAFA",
+"! c #6161AEAEFEFE",
+"~ c #6A6AAEAEF3F3",
+"^ c #6565B0B0FBFB",
+"/ c #6666B2B2FBFB",
+"( c #6464B0B0FEFE",
+") c #6A6AB0B0F5F5",
+"_ c #6E6EB1B1F4F4",
+"` c #6E6EB2B2F6F6",
+"' c #6A6AB3B3FCFC",
+"] c #6B6BB2B2FCFC",
+"[ c #6E6EB5B5FCFC",
+"{ c #7A7AB5B5E5E5",
+"} c #7D7DB6B6E7E7",
+"| c #7F7FBCBCEFEF",
+" . c #7171B3B3F4F4",
+".. c #7272B5B5F7F7",
+"X. c #7676B7B7F8F8",
+"o. c #7171B8B8FDFD",
+"O. c #7575BABAFEFE",
+"+. c #7A7AB6B6F3F3",
+"@. c #7C7CBBBBF7F7",
+"#. c #7F7FBABAF6F6",
+"$. c #7A7ABABAF9F9",
+"%. c #7878BBBBFEFE",
+"&. c #7B7BBDBDFEFE",
+"*. c #7D7DBEBEFEFE",
+"=. c #7F7FBEBEFFFF",
+"-. c #7F7FBFBFFFFF",
+";. c #CECE91917777",
+":. c #EBEBE0E07F7F",
+">. c #8282BEBEF3F3",
+",. c #8080BDBDF9F9",
+"<. c #ADADC3C3B1B1",
+"1. c #8484C0C0FAFA",
+"2. c #8585C0C0FCFC",
+"3. c #8888C2C2FBFB",
+"4. c #8888C2C2FDFD",
+"5. c #8B8BC4C4FBFB",
+"6. c #8B8BC4C4FDFD",
+"7. c #8E8EC6C6FEFE",
+"8. c #9090C7C7FEFE",
+"9. c #A0A0CFCFFCFC",
+"0. c #A4A4D2D2FEFE",
+"q. c #EEEEE2E28181",
+"w. c #F4F4E2E28686",
+"e. c #F6F6E4E48B8B",
+"r. c #F6F6E9E98989",
+"t. c #F7F7E9E98A8A",
+"y. c #F8F8ECEC8F8F",
+"u. c #FAFAEDED9393",
+"i. c #F9F9ECEC9494",
+"p. c #FBFBF0F09999",
+"a. c gray89",
+"s. c gray90",
+"d. c #E7E7E7E7E7E7",
+"f. c gray95",
+"g. c #F3F3F3F3F3F3",
+"h. c #F4F4F4F4F4F4",
+"j. c #F4F4F5F5F5F5",
+"k. c gray96",
+"l. c #F6F6F6F6F6F6",
+"z. c gray97",
+"x. c gray98",
+"c. c #FBFBFBFBFBFB",
+"v. c #FBFBFCFCFBFB",
+"b. c gray99",
+"n. c #FDFDFCFCFDFD",
+"m. c #FDFDFDFDFDFD",
+"M. c #FEFEFEFEFEFE",
+"N. c None",
+/* pixels */
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"r e e e e q 9 8 7 6 3 < , : ; ; ",
+"e -.-.*.*.O.O.o.[ ' ^ W U L G * ",
+"q -.( ( T I J H D V B n x g A % ",
+"z 0.8.8.6.2.2.1.>.$.X...` ~ #.4 ",
+"n.n.n.n.n.b.p.e.w.y.z.k.k.k.k.d.",
+"n.n.n.n.n.c.u.<.;.r.k.k.k.g.k.d.",
+"n.n.v.v.c.c.i.:.:.r.k.h.g.f.g.a.",
+"z 8.5.2.1.#.#.} { ._ ~ E R +.> ",
+"6 ..D V n c g s a p i u y t h . ",
+"3 ' W Y L J H Z N M m v l l f . ",
+"3 , : ; - = & % $ # @ + O . . O ",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N."
+};
diff --git a/src/images/flags/NL.xpm b/src/images/flags/NL.xpm
new file mode 100644
index 0000000..15954a7
--- /dev/null
+++ b/src/images/flags/NL.xpm
@@ -0,0 +1,160 @@
+/* XPM */
+static const char *NL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 138 2",
+" c black",
+". c #000000003B3B",
+"X c #000000003D3D",
+"o c #000000004141",
+"O c #000000004343",
+"+ c #000000004747",
+"@ c #000000004D4D",
+"# c #000000005151",
+"$ c #000000005757",
+"% c #000000005B5B",
+"& c #000000005F5F",
+"* c #000000006565",
+"= c #000000006B6B",
+"- c #000000006F6F",
+"; c #000000007575",
+": c #000000007B7B",
+"> c #000001017F7F",
+", c #000007078181",
+"< c #000021218F8F",
+"1 c #0B0B5050A1A1",
+"2 c #0F0F5252A3A3",
+"3 c #13135656A5A5",
+"4 c #18185A5AA8A8",
+"5 c #1E1E5E5EAAAA",
+"6 c #23236060A9A9",
+"7 c #23236262ADAD",
+"8 c #28286363ACAC",
+"9 c #29296666AFAF",
+"0 c #2C2C6767ADAD",
+"q c #2C2C6767AEAE",
+"w c #2F2F6969AEAE",
+"e c #2F2F6A6AAEAE",
+"r c #2E2E6A6AB2B2",
+"t c #31316B6BB0B0",
+"y c #32326C6CB0B0",
+"u c #35356F6FB2B2",
+"i c #36366F6FB2B2",
+"p c #34346F6FB5B5",
+"a c #39397171B3B3",
+"s c #3B3B7373B5B5",
+"d c #3A3A7373B7B7",
+"f c #3D3D7575B6B6",
+"g c #3F3F7676B9B9",
+"h c #40407777B7B7",
+"j c #43437777B5B5",
+"k c #42427878B8B8",
+"l c #44447A7ABBBB",
+"z c #45457B7BBABA",
+"x c #46467C7CBABA",
+"c c #4A4A7E7EBCBC",
+"v c #4B4B7F7FBCBC",
+"b c #50508282BEBE",
+"n c #50508282BFBF",
+"m c #54548585C0C0",
+"M c #54548585C1C1",
+"N c #58588989C2C2",
+"B c #59598989C3C3",
+"V c #5D5D8D8DC4C4",
+"C c #61619090C6C6",
+"Z c #66669393C8C8",
+"A c #77779E9ECECE",
+"S c #E7E700000000",
+"D c #E9E900000000",
+"F c #EBEB00000000",
+"G c #EDED00000000",
+"H c #EFEF00000000",
+"J c #F1F100000000",
+"K c #F3F300000000",
+"L c #F5F500000000",
+"P c #F7F700000000",
+"I c #F9F900000000",
+"U c #FBFB00000000",
+"Y c #FDFD00000000",
+"T c red",
+"R c #FFFF15153131",
+"E c #F6F62C2C3C3C",
+"W c #F7F731314242",
+"Q c #F8F837374747",
+"! c #F9F93C3C4D4D",
+"~ c #F7F749495757",
+"^ c #FAFA42425151",
+"/ c #FBFB47475656",
+"( c #FCFC4C4C5A5A",
+") c #FDFD51515E5E",
+"_ c #F7F74E4E6060",
+"` c #F5F556566A6A",
+"' c #F6F65A5A6E6E",
+"] c #F8F853536565",
+"[ c #FDFD54546363",
+"{ c #F9F957576868",
+"} c #FEFE59596767",
+"| c #FAFA5C5C6D6D",
+" . c #FEFE5C5C6969",
+".. c #FEFE5F5F6C6C",
+"X. c #F7F75F5F7272",
+"o. c #F6F66D6D7F7F",
+"O. c #FBFB60607070",
+"+. c #F8F864647676",
+"@. c #FCFC65657474",
+"#. c #F9F968687A7A",
+"$. c #FAFA6C6C7D7D",
+"%. c #FCFC69697878",
+"&. c #FDFD6D6D7B7B",
+"*. c #FDFD70707F7F",
+"=. c #FBFB70708181",
+"-. c #FEFE74748181",
+";. c #FCFC74748585",
+":. c #FEFE77778484",
+">. c #FEFE79798787",
+",. c #FFFF7B7B8585",
+"<. c #FDFD78788888",
+"1. c #FDFD7B7B8B8B",
+"2. c #FFFF7B7B8989",
+"3. c #FEFE7F7F8F8F",
+"4. c #FEFE82829191",
+"5. c #FEFE9797A4A4",
+"6. c gray82",
+"7. c #D5D5D5D5D5D5",
+"8. c #EDEDEFEFEFEF",
+"9. c #EFEFEFEFEFEF",
+"0. c #F1F1F1F1F1F1",
+"q. c gray95",
+"w. c #F3F3F3F3F3F3",
+"e. c #F4F4F4F4F4F4",
+"r. c #F4F4F5F5F5F5",
+"t. c gray96",
+"y. c #F6F6F6F6F6F6",
+"u. c gray97",
+"i. c #F8F8F8F8F8F8",
+"p. c #F9F9F9F9F9F9",
+"a. c gray98",
+"s. c #FBFBFBFBFBFB",
+"d. c #FBFBFCFCFBFB",
+"f. c gray99",
+"g. c #FDFDFCFCFDFD",
+"h. c #FDFDFDFDFDFD",
+"j. c #FEFEFEFEFEFE",
+"k. c None",
+/* pixels */
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"T T T T U T T T U U P P K K G G ",
+"T 2.2.,.;.-.=.&.%. at .O.| { ] _ F ",
+"T ,... .} [ ( ( / ^ ! Q W E ~ F ",
+"R 5.4.3.2.<.;.=.$.%.+.X.' ` =.S ",
+"0.j.j.j.j.s.s.s.p.u.u.r.r.r.r.7.",
+"9.j.j.j.j.s.i.i.u.u.r.r.r.e.e.6.",
+"9.j.i.f.i.j.i.i.u.u.r.r.e.e.e.6.",
+"< A B m n v z h d u r q 8 6 j @ ",
+", Z l g d p r 9 7 5 4 3 2 1 w . ",
+"> C V N m b v x k f a u y w q . ",
+": ; - = * & % $ # @ + O X X . X ",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k."
+};
diff --git a/src/images/flags/NO.xpm b/src/images/flags/NO.xpm
new file mode 100644
index 0000000..f62a78c
--- /dev/null
+++ b/src/images/flags/NO.xpm
@@ -0,0 +1,149 @@
+/* XPM */
+static const char *NO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 127 2",
+" c black",
+". c #00000000A5A5",
+"X c #00001D1DB7B7",
+"o c #03035353CFCF",
+"O c #09095959D1D1",
+"+ c #4B4B8383D5D5",
+"@ c #50508686D7D7",
+"# c #54548A8AD8D8",
+"$ c #59598D8DD9D9",
+"% c #5D5D9090DBDB",
+"& c #62629494DDDD",
+"* c #65659494DADA",
+"= c #65659696DEDE",
+"- c #66669797DEDE",
+"; c #6A6A9999E0E0",
+": c #6B6B9A9AE0E0",
+"> c #6F6F9C9CE1E1",
+", c #6F6F9D9DE1E1",
+"< c #73739F9FE3E3",
+"1 c #7777A3A3E4E4",
+"2 c #7A7AA4A4E2E2",
+"3 c #7A7AA5A5E5E5",
+"4 c #7B7BA6A6E5E5",
+"5 c #7E7EA8A8E7E7",
+"6 c #B1B100000000",
+"7 c #B5B500000000",
+"8 c #B9B900000000",
+"9 c #BBBB00000000",
+"0 c #BDBD00000000",
+"q c #BFBF00000000",
+"w c #C3C300000000",
+"e c #C5C500000000",
+"r c #C9C900000000",
+"t c #CBCB00000000",
+"y c #CFCF00000000",
+"u c #D1D100000000",
+"i c #D5D500000000",
+"p c #D7D700000000",
+"a c #D9D900000000",
+"s c #DBDB00000000",
+"d c #DDDD00000000",
+"f c #DADA0E0E0B0B",
+"g c #DCDC11110E0E",
+"h c #DCDC12121010",
+"j c #DDDD16161313",
+"k c #DDDD17171414",
+"l c #DFDF1B1B1919",
+"z c #DFDF1C1C1919",
+"x c #DEDE2E2E2C2C",
+"c c #E1E100000000",
+"v c #E0E021211E1E",
+"b c #E0E021211F1F",
+"n c #E1E126262323",
+"m c #E2E227272424",
+"M c #E2E229292626",
+"N c #E2E22B2B2929",
+"B c #E2E22C2C2A2A",
+"V c #E4E42E2E2B2B",
+"C c #E4E42E2E2C2C",
+"Z c #E0E031312F2F",
+"A c #E4E430302E2E",
+"S c #E4E431312F2F",
+"D c #E0E034343232",
+"F c #E0E035353232",
+"G c #E2E237373535",
+"H c #E5E534343131",
+"J c #E6E637373434",
+"K c #E7E739393636",
+"L c #E7E73A3A3737",
+"P c #E2E23B3B3939",
+"I c #E8E83E3E3C3C",
+"U c #E8E83F3F3D3D",
+"Y c #E4E440403D3D",
+"T c #E4E444444242",
+"R c #E6E646464444",
+"E c #E6E649494646",
+"W c #E7E74B4B4949",
+"Q c #E7E74C4C4B4B",
+"! c #E9E943434242",
+"~ c #E9E944444242",
+"^ c #EAEA46464444",
+"/ c #EAEA49494747",
+"( c #EBEB49494747",
+") c #EBEB4B4B4949",
+"_ c #EBEB4E4E4B4B",
+"` c #EBEB4E4E4C4C",
+"' c #E8E850504E4E",
+"] c #E9E955555353",
+"[ c #ECEC52525151",
+"{ c #EBEB5A5A5757",
+"} c #ECEC5E5E5C5C",
+"| c #ECEC5F5F5D5D",
+" . c #EFEF5D5D5C5C",
+".. c #F0F061615F5F",
+"X. c #EDED63636060",
+"o. c #EDED64646262",
+"O. c #EEEE67676565",
+"+. c #EEEE68686666",
+"@. c #EFEF6B6B6969",
+"#. c #EFEF6D6D6A6A",
+"$. c #EFEF6F6F6D6D",
+"%. c #F0F072727171",
+"&. c #F2F27A7A7979",
+"*. c #F2F27D7D7A7A",
+"=. c #F2F27D7D7B7B",
+"-. c #9292B6B6EAEA",
+";. c #9595B9B9EBEB",
+":. c gray89",
+">. c #E7E7E7E7E7E7",
+",. c gray93",
+"<. c #EFEFEFEFEFEF",
+"1. c gray95",
+"2. c #F3F3F3F3F3F3",
+"3. c #F4F4F4F4F4F4",
+"4. c gray96",
+"5. c #F6F6F6F6F6F6",
+"6. c gray97",
+"7. c #F8F8F8F8F8F8",
+"8. c #F9F9F9F9F9F9",
+"9. c gray98",
+"0. c #FBFBFBFBFBFB",
+"q. c #FBFBFCFCFBFB",
+"w. c gray99",
+"e. c #FDFDFDFDFDFD",
+"r. c #FEFEFEFEFEFE",
+"t. c gray100",
+"y. c None",
+/* pixels */
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"c c c t.O t.d s s s p p u u r r ",
+"c =.=.t.;.t.%.$. at .+.X.| { ] ' e ",
+"c =.| t.5 0.[ _ ( ~ Y J H C W w ",
+"c &. .t.2 t.) R ! I J H B M R q ",
+"t.t.t.0.1 t.0.0.0.0.0.4.4.4.4.>.",
+"o -.2 1 < : : = & $ $ # @ + * . ",
+"q.t.t.0.: 0.0.6.5.5.4.4.2.1.3.:.",
+"s #.( 0.: 0.J H N m v l k g F 7 ",
+"s O.~ 0.& 0.C N m v l j g f Z 6 ",
+"p X.| 0.2 0.W E T Y P G F Z x 6 ",
+"u u y <.X ,.w q q 9 9 7 7 6 6 6 ",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y."
+};
diff --git a/src/images/flags/NP.xpm b/src/images/flags/NP.xpm
new file mode 100644
index 0000000..d84335a
--- /dev/null
+++ b/src/images/flags/NP.xpm
@@ -0,0 +1,89 @@
+/* XPM */
+static const char *NP_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 67 1",
+" c black",
+". c #060609093636",
+"X c #07070A0A3737",
+"o c #07070B0B3838",
+"O c #08080C0C3838",
+"+ c #08080D0D3A3A",
+"@ c #09090E0E3C3C",
+"# c #0A0A0F0F3E3E",
+"$ c #161612123636",
+"% c #1A1A15153E3E",
+"& c #0A0A10104444",
+"* c #0B0B10104747",
+"= c #0B0B11114949",
+"- c #0E0E16165D5D",
+"; c #1E1E18185555",
+": c #11111A1A7272",
+"> c #11111B1B7575",
+", c #12121C1C7878",
+"< c #13131D1D7F7F",
+"1 c #18181E1E7F7F",
+"2 c #22221C1C6C6C",
+"3 c #1A1A24249D9D",
+"4 c #1D1D2D2D9696",
+"5 c #1C1C2A2AB7B7",
+"6 c #27271F1F8383",
+"7 c #2A2A22229999",
+"8 c #2E2E2525ABAB",
+"9 c #30302727B9B9",
+"0 c #1D1D2D2DC9C9",
+"q c #1F1F3030D6D6",
+"w c #33332929C6C6",
+"e c #32322929C9C9",
+"r c #2C2C4444B4B4",
+"t c #ABAB00000000",
+"y c #B3B300000000",
+"u c #C1C100000000",
+"i c #C2C200000000",
+"p c #C7C700000000",
+"a c #D0D000000000",
+"s c #D8D800000000",
+"d c #DCDC00000000",
+"f c #DDDD00000000",
+"g c #DEDE00000000",
+"h c #E7E701010101",
+"j c #ECEC00000000",
+"k c #F0F000000000",
+"l c #DFDF4B4B4B4B",
+"z c #E3E352525252",
+"x c #E4E457575757",
+"c c #E4E45D5D5D5D",
+"v c #E7E76D6D6D6D",
+"b c #EAEA7D7D7D7D",
+"n c #EAEA82828282",
+"m c #ECEC88888888",
+"M c #F2F2AEAEAEAE",
+"N c #F6F6D3D3D3D3",
+"B c #F9F9DBDBDBDB",
+"V c #F9F9DCDCDCDC",
+"C c #F9F9DDDDDDDD",
+"Z c #F9F9DFDFDFDF",
+"A c #F9F9E0E0E0E0",
+"S c #FAFAE4E4E4E4",
+"D c #FAFAE6E6E6E6",
+"F c #FBFBEAEAEAEA",
+"G c #FBFBEBEBEBEB",
+"H c #FCFCF0F0F0F0",
+"J c None",
+/* pixels */
+"JJJJJJJJJJJJJJJJ",
+"JJJJJJJJJJJJJJJJ",
+"JJJJJJJJJJJJJJJJ",
+"JJJJeqqJJJJJJJJJ",
+"JJJJwkh0JJJJJJJJ",
+"JJJJ9jSN5JJJJJJJ",
+"JJJJ8HCBS3JJJJJJ",
+"JJJJ7MGGfa1JJJJJ",
+"JJJJ6ffr46,:JJJJ",
+"JJJJ2smn>JJJJJJJ",
+"JJJJ;bZCl-JJJJJJ",
+"JJJJ%vCCct*JJJJJ",
+"JJJJ$pxziit+JJJJ",
+"JJJJ**#+++o..JJJ",
+"JJJJJJJJJJJJJJJJ",
+"JJJJJJJJJJJJJJJJ"
+};
diff --git a/src/images/flags/NR.xpm b/src/images/flags/NR.xpm
new file mode 100644
index 0000000..2e58656
--- /dev/null
+++ b/src/images/flags/NR.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *NR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #000000000101",
+"X c #000000000303",
+"o c #000000000707",
+"O c #000000000D0D",
+"+ c #000000001313",
+"@ c #000000001919",
+"# c #000000001B1B",
+"$ c #000000002121",
+"% c #000000002323",
+"& c #000000002727",
+"* c #000000002D2D",
+"= c #000000002F2F",
+"- c #000000003333",
+"; c #000000003535",
+": c #000000003939",
+"> c #000000003B3B",
+", c #000000003F3F",
+"< c #000000004141",
+"1 c #000000004747",
+"2 c #000000004B4B",
+"3 c #000000004D4D",
+"4 c #000003035151",
+"5 c #000005055151",
+"6 c #000009095555",
+"7 c #00000D0D5959",
+"8 c #000013135D5D",
+"9 c #000013135F5F",
+"0 c #000015155F5F",
+"q c #000019195F5F",
+"w c #00001D1D5B5B",
+"e c #101045457A7A",
+"r c #131347477D7D",
+"t c #141448487C7C",
+"y c #19194B4B7F7F",
+"u c #1C1C4D4D7F7F",
+"i c #18184B4B8080",
+"p c #1D1D4F4F8383",
+"a c #1E1E50508282",
+"s c #212151518282",
+"d c #222253538686",
+"f c #242454548585",
+"g c #262656568585",
+"h c #282857578585",
+"j c #282858588989",
+"k c #282858588A8A",
+"l c #2A2A5A5A8989",
+"z c #2A2A5A5A8B8B",
+"x c #2D2D5B5B8989",
+"c c #2D2D5C5C8C8C",
+"v c #2D2D5C5C8D8D",
+"b c #31315D5D8A8A",
+"n c #30305E5E8C8C",
+"m c #30305E5E8E8E",
+"M c #31315F5F8E8E",
+"N c #32325F5F8F8F",
+"B c #333360608C8C",
+"V c #343460608D8D",
+"C c #353563638F8F",
+"Z c #363662628F8F",
+"A c #323261619191",
+"S c #353562629292",
+"D c #363662629090",
+"F c #363663639191",
+"G c #373763639292",
+"H c #373764649090",
+"J c #3A3A65659191",
+"K c #3B3B66669292",
+"L c #3B3B66669393",
+"P c #3B3B67679595",
+"I c #3C3C66669090",
+"U c #3D3D68689393",
+"Y c #3C3C68689595",
+"T c #3E3E68689494",
+"R c #40406B6B9696",
+"E c #42426B6B9696",
+"W c #42426D6D9797",
+"Q c #46466F6F9696",
+"! c #40406B6B9898",
+"~ c #41416C6C9898",
+"^ c #43436E6E9A9A",
+"/ c #46466F6F9999",
+"( c #45456F6F9C9C",
+") c #464670709999",
+"_ c #464670709B9B",
+"` c #474770709A9A",
+"' c #484870709A9A",
+"] c #4A4A72729C9C",
+"[ c #4A4A73739F9F",
+"{ c #4B4B74749E9E",
+"} c #4C4C74749D9D",
+"| c #4D4D75759D9D",
+" . c #4F4F76769E9E",
+".. c #535379799F9F",
+"X. c #4E4E7777A1A1",
+"o. c #50507878A1A1",
+"O. c #52527979A0A0",
+"+. c #53537979A0A0",
+"@. c #54547B7BA0A0",
+"#. c #55557B7BA3A3",
+"$. c #54547A7AA4A4",
+"%. c #56567C7CA2A2",
+"&. c #57577D7DA3A3",
+"*. c #5A5A7E7EA2A2",
+"=. c #58587E7EA6A6",
+"-. c #59597F7FA6A6",
+";. c #5E5E8282A3A3",
+":. c #5C5C8080A6A6",
+">. c #5B5B8181A9A9",
+",. c #5D5D8282A8A8",
+"<. c #5F5F8484ABAB",
+"1. c #62628484A6A6",
+"2. c #60608484A9A9",
+"3. c #61618585A9A9",
+"4. c #60608585ABAB",
+"5. c #62628484A9A9",
+"6. c #63638787ACAC",
+"7. c #65658787AAAA",
+"8. c #65658787ACAC",
+"9. c #65658888ABAB",
+"0. c #69698B8BAEAE",
+"q. c #6A6A8B8BAEAE",
+"w. c #6D6D8F8FB0B0",
+"e. c #6E6E8F8FB1B1",
+"r. c #70709191B2B2",
+"t. c #73739494B3B3",
+"y. c #76769494B3B3",
+"u. c #74749494B4B4",
+"i. c #77779696B6B6",
+"p. c #7E7E9B9BB6B6",
+"a. c #7A7A9999B9B9",
+"s. c #7B7B9999BABA",
+"d. c #7C7C9A9AB9B9",
+"f. c #7E7E9C9CBABA",
+"g. c #7E7E9D9DBBBB",
+"h. c #BBBB81810000",
+"j. c #DFDFB5B51D1D",
+"k. c #DEDEC1C15858",
+"l. c #E0E0C3C35C5C",
+"z. c #E1E1C5C56060",
+"x. c #E3E3C7C76565",
+"c. c #E4E4C9C96969",
+"v. c #E6E6CBCB6D6D",
+"b. c #E2E2C9C97070",
+"n. c #E7E7CDCD7272",
+"m. c #E8E8CFCF7676",
+"M. c #E9E9D1D17A7A",
+"N. c #E8E8D1D17D7D",
+"B. c #8F8FA8A8BFBF",
+"V. c #9393ABABC4C4",
+"C. c #B8B8C7C7D6D6",
+"Z. c #E8E8D3D38080",
+"A. c #ECECD6D68484",
+"S. c #F1F1DDDD9A9A",
+"D. c #DBDBE3E3ECEC",
+"F. c #E4E4E8E8EEEE",
+"G. c #FBFBFBFBFBFB",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"q 0 0 0 9 7 6 4 2 1 < > ; = & % ",
+"0 g.g.d.s.i.i.e.w.0.7.4.:.#.o.@ ",
+"0 g.6.4.:.=.#.o.{ ` ~ Y F M | + ",
+"9 s.<.>.=.$.X.[ ( T P F M z ] O ",
+"w p.1.;.*...| ` ~ Y H B x h Q ",
+"j.S.A.N.N.M.m.n.v.c.x.z.l.k.v.h.",
+"5 t.*.B.+.` E L H B z g s p K ",
+"3 e.V.G.D.~ G A v k d a t r F ",
+"1 q.4.F.C.Y M x k f a t t e N ",
+", 7.4.y.7.+. .[ ' E Y K K N b ",
+"> - = & % @ + O o ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/NU.xpm b/src/images/flags/NU.xpm
new file mode 100644
index 0000000..66ab2d6
--- /dev/null
+++ b/src/images/flags/NU.xpm
@@ -0,0 +1,172 @@
+/* XPM */
+static const char *NU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 150 2",
+" c black",
+". c #36363131B1B1",
+"X c #6E6E6464B4B4",
+"o c #56565656CACA",
+"O c #57577575EBEB",
+"+ c #5F5F7D7DF1F1",
+"@ c #67677171D7D7",
+"# c #65657676D4D4",
+"$ c #6F6F7777DFDF",
+"% c #73737373D7D7",
+"& c #7F7F8585DEDE",
+"* c #7F7F8B8BE9E9",
+"= c #71718484F5F5",
+"- c #DFDF59595757",
+"; c #E6E657575A5A",
+": c #F1F149494D4D",
+"> c #F9F94D4D4343",
+", c #F5F550504C4C",
+"< c #FDFD53534545",
+"1 c #E2E25C5C6868",
+"2 c #EDED5F5F6767",
+"3 c #FDFD77776F6F",
+"4 c #83837A7AC9C9",
+"5 c #FDFD82827E7E",
+"6 c #DFDFC0C03333",
+"7 c #DFDFC1C13434",
+"8 c #DFDFC1C13535",
+"9 c #DFDFC2C23636",
+"0 c #DFDFC3C33737",
+"q c #E1E1C5C53838",
+"w c #E4E4C8C83B3B",
+"e c #E4E4C8C83C3C",
+"r c #E6E6CACA3E3E",
+"t c #E6E6CACA3F3F",
+"y c #E6E6DCDC3C3C",
+"u c #E6E6DCDC3D3D",
+"i c #E7E7DEDE3F3F",
+"p c #E9E9DFDF3C3C",
+"a c #EAEAE0E03E3E",
+"s c #EAEAE1E13F3F",
+"d c #E8E8CDCD4141",
+"f c #E8E8CDCD4242",
+"g c #E8E8CECE4343",
+"h c #E8E8CECE4444",
+"j c #E7E7DFDF4040",
+"k c #E7E7DFDF4141",
+"l c #E8E8D0D04646",
+"z c #EAEAD1D14646",
+"x c #EAEAD3D34949",
+"c c #EBEBD3D34949",
+"v c #ECECD5D54C4C",
+"b c #EDEDD5D54D4D",
+"n c #EFEFD6D64F4F",
+"m c #EFEFD7D75050",
+"M c #EFEFD6D65454",
+"N c #EFEFD9D95555",
+"B c #F0F0D9D95252",
+"V c #F0F0D9D95656",
+"C c #F2F2DCDC5555",
+"Z c #F3F3DBDB5A5A",
+"A c #F3F3DBDB5B5B",
+"S c #F4F4DFDF5858",
+"D c #FDFDCBCB6060",
+"F c #FEFED3D36969",
+"G c #FBFBDADA6969",
+"H c #FCFCDFDF7171",
+"J c #E7E7E0E04141",
+"K c #E6E6E2E24949",
+"L c #E8E8E1E14343",
+"P c #E9E9E1E14343",
+"I c #EBEBE2E24141",
+"U c #E9E9E1E14444",
+"Y c #EBEBE4E44646",
+"T c #EBEBE4E44747",
+"R c #ECECE4E44343",
+"E c #ECECE4E44444",
+"W c #EDEDE6E64747",
+"Q c #EEEEE6E64747",
+"! c #ECECE5E54848",
+"~ c #ECECE6E64949",
+"^ c #ECECE6E64A4A",
+"/ c #EDEDE7E74A4A",
+"( c #EEEEE7E74949",
+") c #EFEFE7E74949",
+"_ c #EFEFE6E64E4E",
+"` c #EEEEE8E84B4B",
+"' c #EEEEE8E84C4C",
+"] c #EEEEE9E94C4C",
+"[ c #EEEEE9E94D4D",
+"{ c #EFEFEAEA4D4D",
+"} c #EFEFEAEA4E4E",
+"| c #EFEFEAEA4F4F",
+" . c #F0F0EAEA4D4D",
+".. c #F2F2EBEB4D4D",
+"X. c #F2F2ECEC4F4F",
+"o. c #F6F6E2E25B5B",
+"O. c #F1F1E9E95353",
+"+. c #F0F0EBEB5050",
+"@. c #F1F1ECEC5151",
+"#. c #F2F2ECEC5050",
+"$. c #F2F2EDED5252",
+"%. c #F3F3EEEE5353",
+"&. c #F2F2EFEF5757",
+"*. c #F3F3EFEF5656",
+"=. c #F4F4EFEF5353",
+"-. c #F4F4EBEB5858",
+";. c #F5F5F0F05555",
+":. c #F4F4F0F05757",
+">. c #F6F6F1F15555",
+",. c #F6F6F1F15757",
+"<. c #F4F4F1F15858",
+"1. c #F5F5F2F25959",
+"2. c #F5F5F3F35B5B",
+"3. c #F6F6F2F25858",
+"4. c #F6F6F3F35B5B",
+"5. c #FDFDF3F35252",
+"6. c #F8F8F4F45A5A",
+"7. c #F8F8F4F45B5B",
+"8. c #F9F9F6F65D5D",
+"9. c #F8F8F6F65E5E",
+"0. c #FBFBF8F86060",
+"q. c #FBFBF9F96161",
+"w. c #FCFCFAFA6363",
+"e. c #FEFEFAFA7C7C",
+"r. c #83838383DFDF",
+"t. c #90908B8BD9D9",
+"y. c #82829494EBEB",
+"u. c #9D9DA9A9EEEE",
+"i. c #BDBDCACAF7F7",
+"p. c #EFEF95959C9C",
+"a. c #FDFD95958F8F",
+"s. c #FEFE96969494",
+"d. c #F0F0A2A2A8A8",
+"f. c #FEFEA4A4A0A0",
+"g. c #FEFEABABA9A9",
+"h. c #FBFBB4B4B3B3",
+"j. c #C7C7B5B5DEDE",
+"k. c #FEFEC0C0BEBE",
+"l. c #FEFEE8E88080",
+"z. c #FEFEEAEA8383",
+"x. c #DEDED1D1E8E8",
+"c. c #D6D6D3D3F2F2",
+"v. c #D5D5DFDFFBFB",
+"b. c #D9D9E2E2FCFC",
+"n. c #FDFDC6C6C5C5",
+"m. c #FBFBD3D3D6D6",
+"M. c #FCFCD0D0D3D3",
+"N. c #FFFFD8D8D7D7",
+"B. c #E5E5E1E1F5F5",
+"V. c None",
+/* pixels */
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"% 3 r.* < $ @ < . N o.S C V m b ",
+"+ b.N.B.e.c.n.i.= *.8.3.3.=.$.x ",
+"2 m.l.g.F s.G d.1 -.*.$.| | $.l ",
+": M.l.s.D 5 G p.; O.$.| | Q .g ",
+"O v.k.x.5.j.h.u.# K | | ^ T Q g ",
+"o f.t.y., & 4 - X _ | ^ T U W t ",
+"A w.9.2.3.3.$.$.| / Q T J J I t ",
+"A w.2.3.<.$...../ ^ T J i i J q ",
+"V 9.:.:.*.+.` ` Q J k i i y a 9 ",
+"V 9.6.=.>.>.....) Q W J a a p 6 ",
+"M C B B v v l g t r w q 9 9 6 6 ",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V."
+};
diff --git a/src/images/flags/NZ.xpm b/src/images/flags/NZ.xpm
new file mode 100644
index 0000000..9cebd07
--- /dev/null
+++ b/src/images/flags/NZ.xpm
@@ -0,0 +1,186 @@
+/* XPM */
+static const char *NZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 164 2",
+" c black",
+". c #000000000101",
+"X c #000000000303",
+"o c #000000000707",
+"O c #000000000909",
+"+ c #000000000B0B",
+"@ c #000000000F0F",
+"# c #000000001111",
+"$ c #000000001515",
+"% c #000000001717",
+"& c #000000001919",
+"* c #000000001D1D",
+"= c #000000001F1F",
+"- c #000000002323",
+"; c #000000002525",
+": c #000000002929",
+"> c #000000002D2D",
+", c #000000003333",
+"< c #000000003939",
+"1 c #000000003D3D",
+"2 c #000000003F3F",
+"3 c #000000004545",
+"4 c #000000004747",
+"5 c #000000004D4D",
+"6 c #000000004F4F",
+"7 c #000000005151",
+"8 c #000000005353",
+"9 c #000000005555",
+"0 c #000000005959",
+"q c #000000005D5D",
+"w c #000000005F5F",
+"e c #000000006161",
+"r c #000000006767",
+"t c #2D2D17176B6B",
+"y c #7F7F15153B3B",
+"u c #5D5D23235D5D",
+"i c #65651F1F5353",
+"p c #7F7F23234949",
+"a c #6E6E36366363",
+"s c #75753D3D6A6A",
+"d c #797942426E6E",
+"f c #101029298686",
+"g c #14142E2E8989",
+"h c #181831318A8A",
+"j c #191931318B8B",
+"k c #1E1E35358E8E",
+"l c #1F1F36368E8E",
+"z c #1F1F37378E8E",
+"x c #23233A3A9191",
+"c c #24243B3B9090",
+"v c #24243B3B9191",
+"b c #25253C3C9292",
+"n c #29293F3F9494",
+"m c #2A2A40409494",
+"M c #2B2B41419595",
+"N c #2C2C41419393",
+"B c #2C2C42429494",
+"V c #2C2C43439696",
+"C c #2F2F44449494",
+"Z c #2E2E45459797",
+"A c #2F2F45459797",
+"S c #2F2F45459898",
+"D c #333347479797",
+"F c #35354A4A9999",
+"G c #34344A4A9A9A",
+"H c #34344A4A9B9B",
+"J c #36364B4B9999",
+"K c #37374C4C9999",
+"L c #37374C4C9B9B",
+"P c #39394D4D9A9A",
+"I c #3A3A4F4F9D9D",
+"U c #3B3B4F4F9C9C",
+"Y c #3A3A4F4F9E9E",
+"T c #3B3B50509C9C",
+"R c #3D3D51519D9D",
+"E c #3C3C51519F9F",
+"W c #3F3F5454A1A1",
+"Q c #464646468E8E",
+"! c #434352529999",
+"~ c #424255559F9F",
+"^ c #4B4B55559B9B",
+"/ c #535353539A9A",
+"( c #40405454A1A1",
+") c #40405555A0A0",
+"_ c #42425656A2A2",
+"` c #44445757A2A2",
+"' c #46465A5AA2A2",
+"] c #44445858A4A4",
+"[ c #45455959A4A4",
+"{ c #48485A5AA1A1",
+"} c #4B4B5B5BA3A3",
+"| c #49495D5DA4A4",
+" . c #49495E5EA7A7",
+".. c #4B4B5E5EA5A5",
+"X. c #4E4E6161A8A8",
+"o. c #4F4F6161A9A9",
+"O. c #50506262A8A8",
+"+. c #53536565A9A9",
+"@. c #54546666AAAA",
+"#. c #58586A6AADAD",
+"$. c #5D5D6F6FB0B0",
+"%. c #6B6B61619999",
+"&. c #7B7B63639595",
+"*. c #62626464A1A1",
+"=. c #60606E6EADAD",
+"-. c #61617171B1B1",
+";. c #61617272B3B3",
+":. c #65657575B3B3",
+">. c #66667676B4B4",
+",. c #6A6A7A7AB5B5",
+"<. c #6A6A7A7AB7B7",
+"1. c #6F6F7F7FB9B9",
+"2. c #858517173D3D",
+"3. c #80804D4D7676",
+"4. c #898953537878",
+"5. c #888856567F7F",
+"6. c #8E8E59597D7D",
+"7. c #A8A848485B5B",
+"8. c #B9B946465050",
+"9. c #AEAE52526565",
+"0. c #AFAF5F5F7979",
+"q. c #B1B159596D6D",
+"w. c #B6B662627575",
+"e. c #CFCF19191919",
+"r. c #C3C360606A6A",
+"t. c #C8C866667070",
+"y. c #D7D76E6E7272",
+"u. c #E4E46B6B6A6A",
+"i. c #E5E574747272",
+"p. c #E1E177777878",
+"a. c #E9E97C7C7A7A",
+"s. c #80805E5E8C8C",
+"d. c #8F8F5F5F8686",
+"f. c #94945D5D8080",
+"g. c #818162629090",
+"h. c #919161618585",
+"j. c #929276769C9C",
+"k. c #989879799E9E",
+"l. c #88887C7CA9A9",
+"z. c #A4A47B7B9A9A",
+"x. c #A8A873739090",
+"c. c #C3C371718181",
+"v. c #97978787AFAF",
+"b. c #93939C9CC6C6",
+"n. c #9A9A9C9CC3C3",
+"m. c #C3C382829393",
+"M. c #C1C183839595",
+"N. c #D5D589899191",
+"B. c #D8D8A1A1AAAA",
+"V. c #D8D8AAAAB4B4",
+"C. c #D9D9B2B2BABA",
+"Z. c #E0E082828484",
+"A. c #E2E287878989",
+"S. c #EBEB85858282",
+"D. c #E7E794949595",
+"F. c #E2E2B8B8BEBE",
+"G. c #F1F1A8A8A6A6",
+"H. c #F1F1ACACA9A9",
+"J. c #D8D8BABAC5C5",
+"K. c #E3E3C4C4CCCC",
+"L. c #E4E4C0C0C8C8",
+"P. c #E6E6CFCFD7D7",
+"I. c #E0E0D4D4DFDF",
+"U. c None",
+/* pixels */
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"c.&.r y 2.9 i 0.w 9 7 5 4 1 < 1 ",
+"t L.I.V.B.J.P.n.<.:.$.z.=.+.X.: ",
+"e.D.S.i.u.a.p.y.| ] f.r.f.B | ; ",
+"p F.G.Z.A.H.N.x.] Y L d.B 4.{ = ",
+"%.K.v.M.m.b.C.k.W w.^ M 3.9.h.& ",
+"u l./ g.&.Q *.j.F r.q.b z d R $ ",
+"e 1.O. .~ _ U F S n v z h g F @ ",
+"w <. .[ ~ U F S n v k h s f D O ",
+"0 >.] W U F S n x k h 7.8.a D ",
+"5 $.-.#. at .O.| ' _ R P ! 6.C M ",
+"9 4 3 < , > : - = $ # @ o O ",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U."
+};
diff --git a/src/images/flags/OM.xpm b/src/images/flags/OM.xpm
new file mode 100644
index 0000000..849760a
--- /dev/null
+++ b/src/images/flags/OM.xpm
@@ -0,0 +1,158 @@
+/* XPM */
+static const char *OM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 136 2",
+" c black",
+". c #00002D2D0000",
+"X c #000031310000",
+"o c #000033330000",
+"O c #000037370000",
+"+ c #00003D3D0000",
+"@ c #00003F3F0000",
+"# c #000041410000",
+"$ c #00004B4B0000",
+"% c #00004F4F0000",
+"& c #000055550000",
+"* c #0B0B9C9C0B0B",
+"= c #0F0F9E9E0E0E",
+"- c #10109E9E1010",
+"; c #1313A0A01313",
+": c #1414A1A11414",
+"> c #1818A2A21919",
+", c #1919A3A31919",
+"< c #1E1EA5A51E1E",
+"1 c #1F1FA5A51F1F",
+"2 c #2323A8A82323",
+"3 c #2424A8A82424",
+"4 c #2929AAAA2929",
+"5 c #2A2AABAB2A2A",
+"6 c #2C2CA9A92C2C",
+"7 c #2F2FA9A92F2F",
+"8 c #2E2EADAD2E2E",
+"9 c #2F2FADAD2F2F",
+"0 c #3232ABAB3232",
+"q c #3333ACAC3232",
+"w c #3535AEAE3535",
+"e c #3939AFAF3939",
+"r c #3434B0B03434",
+"t c #3A3AB3B33A3A",
+"y c #3D3DB1B13D3D",
+"u c #4242B3B34242",
+"i c #4646B5B54646",
+"p c #4B4BB8B84B4B",
+"a c #5050BABA5050",
+"s c #919100000000",
+"d c #939300000000",
+"f c #9F9F00000000",
+"g c #A3A300000000",
+"h c #A5A500000000",
+"j c #A9A900000000",
+"k c #ADAD00000000",
+"l c #B1B100000000",
+"z c #B5B500000000",
+"x c #B9B900000000",
+"c c #BDBD00000000",
+"v c #BFBF00000000",
+"b c #CACA14141414",
+"n c #C9C91A1A1A1A",
+"m c #CBCB19191919",
+"M c #CBCB1F1F1F1F",
+"N c #CDCD1F1F1F1F",
+"B c #CACA20202020",
+"V c #CCCC25252525",
+"C c #CFCF24242424",
+"Z c #CDCD2B2B2B2B",
+"A c #CECE2B2B2B2B",
+"S c #CFCF30303030",
+"D c #D1D12A2A2A2A",
+"F c #D3D32F2F2F2F",
+"G c #D0D030303030",
+"H c #D1D136363636",
+"J c #D2D236363636",
+"K c #D4D435353535",
+"L c #D0D03B3B3B3B",
+"P c #D3D33A3A3A3A",
+"I c #D2D23B3B3C3C",
+"U c #D1D13F3F3F3F",
+"Y c #D4D43B3B3B3B",
+"T c #D6D63B3B3A3A",
+"R c #D4D43F3F3F3F",
+"E c #D5D53F3F3F3F",
+"W c #D4D441414141",
+"Q c #D6D640404040",
+"! c #D6D644444444",
+"~ c #D6D645454545",
+"^ c #D6D646464646",
+"/ c #D7D746464646",
+"( c #D7D74B4B4B4B",
+") c #D8D840404040",
+"_ c #D8D849494949",
+"` c #D8D84A4A4949",
+"' c #D8D84A4A4B4B",
+"] c #DADA4F4F4F4F",
+"[ c #DADA4F4F5050",
+"{ c #DBDB53535353",
+"} c #D8D854545555",
+"| c #DBDB54545454",
+" . c #DADA58585858",
+".. c #DBDB5D5D5D5D",
+"X. c #DCDC58585858",
+"o. c #DDDD59595959",
+"O. c #DDDD61616262",
+"+. c #DEDE66666666",
+"@. c #E0E06A6A6A6A",
+"#. c #E1E16F6F6F6F",
+"$. c #E2E272727373",
+"%. c #E3E376767676",
+"&. c #E3E377777777",
+"*. c #EEEEB0B0B0B0",
+"=. c #F2F2BEBEBEBE",
+"-. c #D7D7D7D7D7D7",
+";. c gray85",
+":. c #DDDDDDDDDDDD",
+">. c #DFDFDFDFDFDF",
+",. c #F7F7D7D7D7D7",
+"<. c #E1E1E1E1E1E1",
+"1. c gray89",
+"2. c gray90",
+"3. c #E7E7E7E7E7E7",
+"4. c #E9E9E9E9E9E9",
+"5. c gray92",
+"6. c gray93",
+"7. c #EFEFEFEFEFEF",
+"8. c #EFEFEFEFF1F1",
+"9. c #F9F9E1E1E1E1",
+"0. c gray96",
+"q. c #F6F6F6F6F6F6",
+"w. c gray97",
+"e. c #FCFCF0F0F0F0",
+"r. c #FCFCF7F7F7F7",
+"t. c #F8F8F8F8F8F8",
+"y. c #F9F9F9F9F9F9",
+"u. c gray98",
+"i. c #FBFBFBFBFBFB",
+"p. c #FDFDF9F9F9F9",
+"a. c #FEFEFAFAFAFA",
+"s. c gray99",
+"d. c #FDFDFDFDFDFD",
+"f. c #FDFDFDFDFEFE",
+"g. c #FEFEFEFEFEFE",
+"h. c None",
+/* pixels */
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"v v v v v 8.6.6.6.6.4.3.3.<.<.>.",
+"v e.=.p.%.g.g.s.s.s.s.s.u.u.q.>.",
+"v 9.p.,.X.g.g.s.u.s.w.w.q.q.q.-.",
+"v r.*.p.| g.g.u.u.u.u.w.q.q.q.-.",
+"v %.X.| [ ( ! W U S A Z V B U s ",
+"v $.{ ] ' / E Y H G D V M m L s ",
+"z #.] ` / ) T H G D V N m b H s ",
+"z @.' ! E t r 9 5 3 1 , : - q o ",
+"z +.! E P w 7 4 3 1 , ; = * 7 o ",
+"l O... .| a p i u y e w 0 7 7 . ",
+"k j g g f & & $ # + + O o o . . ",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h."
+};
diff --git a/src/images/flags/PA.xpm b/src/images/flags/PA.xpm
new file mode 100644
index 0000000..e76ccb0
--- /dev/null
+++ b/src/images/flags/PA.xpm
@@ -0,0 +1,155 @@
+/* XPM */
+static const char *PA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 133 2",
+" c black",
+". c #00001717DDDD",
+"X c #00001D1DDFDF",
+"o c #00002525E1E1",
+"O c #00002B2BE3E3",
+"+ c #00003131E5E5",
+"@ c #00003737E9E9",
+"# c #00003F3FEBEB",
+"$ c #00004545EDED",
+"% c #00004B4BEFEF",
+"& c #00004F4FF1F1",
+"* c #00005555F1F1",
+"= c #00005B5BF3F3",
+"- c #1B1B7F7FF5F5",
+"; c #45459292F0F0",
+": c #49499595F1F1",
+"> c #4A4A9696F1F1",
+", c #4C4C9696F3F3",
+"< c #4F4F9999F3F3",
+"1 c #53539C9CF4F4",
+"2 c #54549C9CF4F4",
+"3 c #54549D9DF4F4",
+"4 c #58589F9FF5F5",
+"5 c #59599F9FF5F5",
+"6 c #5959A0A0F5F5",
+"7 c #5E5EA1A1F2F2",
+"8 c #5D5DA2A2F6F6",
+"9 c #5E5EA3A3F6F6",
+"0 c #6262A4A4F2F2",
+"q c #6262A5A5F7F7",
+"w c #6666A6A6F3F3",
+"e c #6767A8A8F8F8",
+"r c #6A6AA9A9F5F5",
+"t c #6F6FABABF6F6",
+"y c #7373AEAEF7F7",
+"u c #7878ADADF2F2",
+"i c #7777B1B1F7F7",
+"p c #7878B1B1F6F6",
+"a c #7C7CB3B3F7F7",
+"s c #7A7AB3B3F8F8",
+"d c #7F7FB6B6F9F9",
+"f c #D1D100000000",
+"g c #D5D500000000",
+"h c #D7D700000000",
+"j c #DBDB00000000",
+"k c #DDDD00000000",
+"l c #DFDF00000000",
+"z c #E1E100000000",
+"x c #E3E300000000",
+"c c #E7E700000000",
+"v c #E9E900000000",
+"b c #EBEB00000000",
+"n c #EDED00000000",
+"m c #E9E920202020",
+"M c #EBEB25252525",
+"N c #ECEC26262626",
+"B c #ECEC2B2B2B2B",
+"V c #EDED2B2B2B2B",
+"C c #EDED2C2C2C2C",
+"Z c #E8E832323131",
+"A c #EDED30303030",
+"S c #EEEE31313131",
+"D c #EFEF36363636",
+"F c #EFEF37373636",
+"G c #EFEF37373737",
+"H c #ECEC3F3F3F3F",
+"J c #F1F13B3B3C3C",
+"K c #F1F13C3C3C3C",
+"L c #F1F13C3C3D3D",
+"P c #EDED44444444",
+"I c #E9E949494949",
+"U c #EFEF49494949",
+"Y c #F2F242424242",
+"T c #F2F24A4A4A4A",
+"R c #F0F04E4E4E4E",
+"E c #F4F44F4F5050",
+"W c #F1F153535353",
+"Q c #F2F257575757",
+"! c #F3F35C5C5C5C",
+"~ c #EDED68686868",
+"^ c #EEEE6D6D6D6D",
+"/ c #EFEF71717171",
+"( c #EEEE7E7E7E7E",
+") c #F4F460606060",
+"_ c #F5F565656565",
+"` c #F0F074747474",
+"' c #F7F770707070",
+"] c #F1F178787878",
+"[ c #F2F27D7D7E7E",
+"{ c #8080B6B6F7F7",
+"} c #8383B8B8F9F9",
+"| c #8484B8B8F8F8",
+" . c #8585B9B9FAFA",
+".. c #8787BBBBF9F9",
+"X. c #9191C0C0FBFB",
+"o. c #9D9DC8C8FAFA",
+"O. c #B2B2D3D3FBFB",
+"+. c #BEBEDADAFBFB",
+"@. c #EDED83838383",
+"#. c #EEEE8C8C8C8C",
+"$. c #CBCBCBCBCBCB",
+"%. c #CFCFCDCDCDCD",
+"&. c gray81",
+"*. c gray82",
+"=. c LightGray",
+"-. c #D7D7D7D7D7D7",
+";. c #EFEFC7C7C7C7",
+":. c #F1F1CBCBCBCB",
+">. c #F2F2D3D3D3D3",
+",. c #F2F2D5D5D5D5",
+"<. c gray93",
+"1. c #EFEFEFEFEFEF",
+"2. c #E3E3EFEFFCFC",
+"3. c #EFEFEFEFF1F1",
+"4. c #E5E5F1F1FEFE",
+"5. c #EBEBF3F3FEFE",
+"6. c #EDEDF5F5FEFE",
+"7. c #F1F1F1F1F1F1",
+"8. c gray95",
+"9. c #F3F3F3F3F3F3",
+"0. c #F4F4F4F4F4F4",
+"q. c gray96",
+"w. c #F6F6F6F6F6F6",
+"e. c gray97",
+"r. c gray98",
+"t. c #FBFBFBFBFBFB",
+"y. c gray99",
+"u. c #FDFDFCFCFDFD",
+"i. c #FDFDFDFDFDFD",
+"p. c #FDFDFDFDFEFE",
+"a. c #FEFEFEFEFEFE",
+"s. c gray100",
+"d. c None",
+/* pixels */
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"7.7.7.7.7.1.1.<.n b b c x x k k ",
+"7.s.s.6.6.s.s.t.' _ ) ! Q W R j ",
+"7.s.5...} 2.t.t.E Y H D S C U h ",
+"7.s.s.+.O.s.t.t.T J D S C N P h ",
+"7.s.s.t.s.t.t.t.J D A B N m H f ",
+"- o...} { a p u [ ] ` ^ ^ ~ ( h ",
+"= } e q 9 6 3 < w.w.w.0.0.7.w.*.",
+"* { q 8 6 3 , : w.w.0.#. at .9.7.&.",
+"& s 8 4 2 < : ; w.0.:.I Z ;.7.$.",
+"& y y y r w 0 7 w.w.w.,.>.7.9.$.",
+"$ # @ O O o X . -.*.*.&.%.$.$.$.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d."
+};
diff --git a/src/images/flags/PE.xpm b/src/images/flags/PE.xpm
new file mode 100644
index 0000000..7be7e06
--- /dev/null
+++ b/src/images/flags/PE.xpm
@@ -0,0 +1,123 @@
+/* XPM */
+static const char *PE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 101 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c red",
+"3 c #F2F210101010",
+"4 c #F2F213131313",
+"5 c #F2F214141414",
+"6 c #F3F319191919",
+"7 c #F3F31A1A1A1A",
+"8 c #F4F41F1F1F1F",
+"9 c #F4F420202020",
+"0 c #F5F525252525",
+"q c #F5F526262626",
+"w c #F2F22C2C2C2C",
+"e c #F2F22F2F2F2F",
+"r c #F6F62B2B2B2B",
+"t c #F6F62C2C2C2C",
+"y c #F2F232323232",
+"u c #F3F332323232",
+"i c #F3F335353535",
+"p c #F7F731313131",
+"a c #F4F436363636",
+"s c #F4F43B3B3B3B",
+"d c #F5F53F3F3F3F",
+"f c #F8F837373737",
+"g c #F9F93A3A3A3A",
+"h c #FAFA3F3F3F3F",
+"j c #F6F644444444",
+"k c #F7F749494949",
+"l c #F7F74E4E4E4E",
+"z c #FAFA44444444",
+"x c #FBFB45454545",
+"c c #FBFB49494949",
+"v c #FBFB4A4A4949",
+"b c #FCFC4A4A4B4B",
+"n c #FCFC4F4F4F4F",
+"m c #FDFD4F4F5050",
+"M c #F8F853535353",
+"N c #F9F954545555",
+"B c #F9F957575757",
+"V c #FDFD53535353",
+"C c #FDFD54545454",
+"Z c #F9F958585858",
+"A c #FAFA5C5C5C5C",
+"S c #FAFA5D5D5D5D",
+"D c #FEFE58585858",
+"F c #FEFE59595959",
+"G c #FEFE5C5C5C5C",
+"H c #FEFE5F5F5F5F",
+"J c #FBFB61616262",
+"K c #FCFC66666666",
+"L c #FCFC6A6A6A6A",
+"P c #FDFD6F6F6F6F",
+"I c #FEFE72727373",
+"U c #FEFE76767676",
+"Y c #FEFE77777777",
+"T c #FEFE79797979",
+"R c #FFFF7B7B7A7A",
+"E c #FFFF7B7B7B7B",
+"W c #E3E3C3C3C3C3",
+"Q c #E5E5C5C5C5C5",
+"! c #E7E7C7C7C7C7",
+"~ c #E9E9CBCBCBCB",
+"^ c #EBEBCDCDCDCD",
+"/ c #EDEDCFCFCFCF",
+"( c #F7F7DFDFDFDF",
+") c #F9F9E1E1E1E1",
+"_ c #FBFBE3E3E3E3",
+"` c #FDFDE5E5E5E5",
+"' c #FDFDE7E7E7E7",
+"] c #F3F3F3F3F3F3",
+"[ c #F4F4F4F4F4F4",
+"{ c gray96",
+"} c #F6F6F6F6F6F6",
+"| c gray97",
+" . c #F8F8F8F8F8F8",
+".. c #F9F9F9F9F9F9",
+"X. c gray98",
+"o. c #FBFBFBFBFBFB",
+"O. c gray99",
+"+. c #FDFDFDFDFDFD",
+"@. c #FDFDFDFDFEFE",
+"#. c #FEFEFEFEFEFE",
+"$. c None",
+/* pixels */
+"$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.",
+"$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.",
+"$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.",
+"2 2 2 2 2 ` ` ` _ ) ( - = = % % ",
+"2 E E E U #.#.O.#.#...G B M l $ ",
+"2 E G G G #.#.O...o...f p t k $ ",
+"2 E G G V #.o.o.......e r q j + ",
+"2 U B V n o.o.........r q 9 d + ",
+"2 I V n b O.......} } 0 8 6 s O ",
+"2 P n b x ......} } } 8 6 3 a O ",
+", L b z h ....} } } ] 6 5 3 i . ",
+", K z h s ..| } } } ] 3 > : e . ",
+"- J S B M .. .| } } [ i u e e . ",
+"- - = % % / ^ ~ Q Q W O O . . . ",
+"$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.",
+"$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$."
+};
diff --git a/src/images/flags/PF.xpm b/src/images/flags/PF.xpm
new file mode 100644
index 0000000..e26ca38
--- /dev/null
+++ b/src/images/flags/PF.xpm
@@ -0,0 +1,157 @@
+/* XPM */
+static const char *PF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 135 2",
+" c black",
+". c #999900000000",
+"X c #9B9B00000000",
+"o c #9D9D00000000",
+"O c #9F9F00000000",
+"+ c #A3A300000000",
+"@ c #A5A500000000",
+"# c #A7A700000000",
+"$ c #A9A900000000",
+"% c #ADAD00000000",
+"& c #B1B100000000",
+"* c #B3B300000000",
+"= c #B5B500000000",
+"- c #B7B700000000",
+"; c #BBBB00000000",
+": c #BFBF00000000",
+"> c #C1C100000000",
+", c #C5C500000000",
+"< c #C7C700000000",
+"1 c #C9C900000000",
+"2 c #CBCB00000000",
+"3 c #CDCD00000000",
+"4 c #CFCF00000000",
+"5 c #CFCF0B0B0B0B",
+"6 c #D1D100000000",
+"7 c #D3D300000000",
+"8 c #D7D700000000",
+"9 c #D0D00F0F0E0E",
+"0 c #D2D213131313",
+"q c #D3D319191919",
+"w c #D5D51E1E1E1E",
+"e c #D7D723232323",
+"r c #D3D32C2C2C2C",
+"t c #D4D42F2F2F2F",
+"y c #D6D62F2F2F2F",
+"u c #D8D829292929",
+"i c #DADA2C2C2C2C",
+"p c #DADA2E2E2E2E",
+"a c #D5D532323232",
+"s c #D6D635353535",
+"d c #DBDB31313131",
+"f c #DCDC34343434",
+"g c #DDDD37373737",
+"h c #D8D839393939",
+"j c #D9D93D3D3D3D",
+"k c #DDDD3A3A3A3A",
+"l c #DFDF3C3C3D3D",
+"z c #DFDF3F3F3F3F",
+"x c #DBDB42424242",
+"c c #DDDD46464646",
+"v c #DDDD4B4B4B4B",
+"b c #DEDE49494949",
+"n c #DFDF4E4E4E4E",
+"m c #DEDE50505050",
+"M c #D0D069696161",
+"N c #E0E042424242",
+"B c #E0E044444444",
+"V c #E1E147474747",
+"C c #E2E24C4C4C4C",
+"Z c #E1E153535353",
+"A c #E0E054545555",
+"S c #E2E257575757",
+"D c #E4E451515151",
+"F c #E5E554545454",
+"G c #E2E258585858",
+"H c #E2E25D5D5D5D",
+"J c #E3E35C5C5C5C",
+"K c #E6E659595959",
+"L c #E6E65C5C5C5C",
+"P c #E7E75F5F5F5F",
+"I c #E3E368684848",
+"U c #E4E460606060",
+"Y c #E4E461616262",
+"T c #E6E665656565",
+"R c #E7E766666666",
+"E c #E6E669696969",
+"W c #E8E86D6D6D6D",
+"Q c #E8E870707171",
+"! c #E9E974747474",
+"~ c #EAEA77777777",
+"^ c #EBEB79797979",
+"/ c #EBEB7B7B7B7B",
+"( c #ECEC7B7B7A7A",
+") c #E8E89B9B5151",
+"_ c #E8E8DEDE5959",
+"` c #EBEBDADA6262",
+"' c #EEEED4D47B7B",
+"] c #EBEBE9E96464",
+"[ c #EFEFEDED7070",
+"{ c #969682829696",
+"} c #999986869A9A",
+"| c #9F9FB1B1BFBF",
+" . c #BDBD91918282",
+".. c #9292AFAFC2C2",
+"X. c #9090B4B4CCCC",
+"o. c #9393B6B6CECE",
+"O. c #EFEFE2E28282",
+"+. c #EFEFEEEE8A8A",
+"@. c #F3F3F3F39A9A",
+"#. c #DFDFDFDFDFDF",
+"$. c #CACADDDDEBEB",
+"%. c #D1D1E2E2EEEE",
+"&. c #F9F9F9F9C8C8",
+"*. c #F7F7F7F7DFDF",
+"=. c #FCFCFCFCD0D0",
+"-. c gray89",
+";. c gray90",
+":. c #E7E7E7E7E7E7",
+">. c #E5E5EFEFECEC",
+",. c gray91",
+"<. c #E9E9E9E9E9E9",
+"1. c #EBEBE9E9E9E9",
+"2. c #ECECF5F5F2F2",
+"3. c #FCFCFCFCE7E7",
+"4. c gray95",
+"5. c #F3F3F3F3F3F3",
+"6. c #F4F4F4F4F4F4",
+"7. c #F4F4F5F5F5F5",
+"8. c #F5F5F4F4F4F4",
+"9. c gray96",
+"0. c #F6F6F5F5F5F5",
+"q. c #F6F6F6F6F6F6",
+"w. c gray97",
+"e. c #F8F8F8F8F8F8",
+"r. c #F9F9F9F9F9F9",
+"t. c gray98",
+"y. c #FBFBFBFBFBFB",
+"u. c #FBFBFCFCFBFB",
+"i. c gray99",
+"p. c #FDFDFCFCFCFC",
+"a. c #FDFDFCFCFDFD",
+"s. c #FDFDFDFDFDFD",
+"d. c #FEFEFDFDFDFD",
+"f. c #FEFEFEFEFEFE",
+"g. c None",
+/* pixels */
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"8 7 7 7 7 7 7 4 2 2 , , > : ; ; ",
+"7 / / / ! ! Q W E T U J G Z n * ",
+"7 ( P L L F F C V N l g d i b % ",
+"<.f.f.f.y.p.&.' O.&.w.w.q.6.q.:.",
+"<.f.f.f.p.3.[ I ) ] *.q.q.6.q.:.",
+",.d.d.r.d. at .` M ._ +.q.6.5.q.;.",
+"<.d.d.d.d.5...} { ..>.6.4.4.5.-.",
+",.r.d.r.r.r.%.o.X.$.6.5.4.4.5.#.",
+"2 R c z k f p u e w q 0 5 5 y X ",
+", Y H G A m b c x j h s s t t . ",
+", > : ; - - * % $ @ @ + O O X O ",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g."
+};
diff --git a/src/images/flags/PG.xpm b/src/images/flags/PG.xpm
new file mode 100644
index 0000000..23d84fd
--- /dev/null
+++ b/src/images/flags/PG.xpm
@@ -0,0 +1,163 @@
+/* XPM */
+static const char *PG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 141 2",
+" c black",
+". c #181819191919",
+"X c #1E1E1E1E1E1E",
+"o c #212113131313",
+"O c #232323232323",
+"+ c gray14",
+"@ c gray16",
+"# c #2A2A2A2A2A2A",
+"$ c gray18",
+"% c #2F2F2F2F2F2F",
+"& c #39392F2F2F2F",
+"* c #323232323232",
+"= c #343434343434",
+"- c #353535353535",
+"; c #393939393939",
+": c gray24",
+"> c #4D4D00000000",
+", c #54541F1F1F1F",
+"< c #6F6F00000000",
+"1 c #6B6B2F2F2F2F",
+"2 c #60603B3B3B3B",
+"3 c gray25",
+"4 c gray26",
+"5 c #444444444444",
+"6 c gray27",
+"7 c #464646464646",
+"8 c #46464B4B4B4B",
+"9 c #494949494949",
+"0 c #4B4B4A4A4B4B",
+"q c #4B4B4B4B4B4B",
+"w c #4C4C4C4C4C4C",
+"e c #505050505050",
+"r c gray33",
+"t c #585858585858",
+"y c gray36",
+"u c #5D5D5D5D5D5D",
+"i c #5B5B61616161",
+"p c #60605F5F5F5F",
+"a c #79795C5C5C5C",
+"s c #616161616262",
+"d c gray39",
+"f c gray40",
+"g c #6A6A6A6A6A6A",
+"h c #747474747474",
+"j c #767676767676",
+"k c #797979797979",
+"l c gray48",
+"z c #7B7B7B7B7A7A",
+"x c #97970F0F0E0E",
+"c c #98982A2A2A2A",
+"v c #9B9B46464646",
+"b c #9E9E5C5C5C5C",
+"n c #8D8D7B7B7B7B",
+"m c #CDCD19191919",
+"M c #DDDD00000000",
+"N c #DFDF00000000",
+"B c #CFCF36363636",
+"V c #D8D82C2C2C2C",
+"C c #E3E300000000",
+"Z c #E5E500000000",
+"A c #E7E700000000",
+"S c #E9E900000000",
+"D c #EBEB00000000",
+"F c #EDED00000000",
+"G c #EFEF00000000",
+"H c #F1F100000000",
+"J c #F3F300000000",
+"K c #F5F500000000",
+"L c #F7F700000000",
+"P c #F0F00B0B0B0B",
+"I c #F9F900000000",
+"U c #FBFB00000000",
+"Y c #FDFD00000000",
+"T c red",
+"R c #F2F210101010",
+"E c #F2F214141414",
+"W c #F2F217171414",
+"Q c #F4F41F1F1F1F",
+"! c #F1F124242424",
+"~ c #F5F52B2B2626",
+"^ c #F2F22F2F2F2F",
+"/ c #F6F62B2B2B2B",
+"( c #F6F62C2C2C2C",
+") c #F3F332323232",
+"_ c #F7F730303030",
+"` c #F4F436363636",
+"' c #F4F43B3B3B3B",
+"] c #F5F53F3F3F3F",
+"[ c #F3F342421A1A",
+"{ c #F8F85E5E3636",
+"} c #F3F37A7A1919",
+"| c #F7F769693131",
+" . c #F9F969693C3C",
+".. c #F5F576762525",
+"X. c #D2D251515151",
+"o. c #D8D87B7B7B7B",
+"O. c #F2F242424141",
+"+. c #F6F644444444",
+"@. c #F7F749494949",
+"#. c #F7F74E4E4E4E",
+"$. c #FBFB47474747",
+"%. c #FBFB4B4B4747",
+"&. c #FCFC4B4B4B4B",
+"*. c #FCFC4C4C4C4C",
+"=. c #F3F359595959",
+"-. c #F8F853535353",
+";. c #F9F957575757",
+":. c #FDFD51515151",
+">. c #FDFD54545454",
+",. c #FAFA63635C5C",
+"<. c #FCFC69696969",
+"1. c #FDFD6D6D6D6D",
+"2. c #FCFC73736565",
+"3. c #FDFD70707171",
+"4. c #FEFE74747474",
+"5. c #FEFE77777777",
+"6. c #FEFE79797979",
+"7. c #F5F584842525",
+"8. c #F4F491912020",
+"9. c #F7F790903030",
+"0. c #F4F4B6B61F1F",
+"q. c #F6F6AAAA2B2B",
+"w. c #F6F6BCBC2B2B",
+"e. c #F8F8BCBC3737",
+"r. c #FAFA86864242",
+"t. c #FAFA89894242",
+"y. c #FBFBADAD6060",
+"u. c #F9F9CACA3C3C",
+"i. c #F7F7DADA3131",
+"p. c #F9F9D3D33D3D",
+"a. c #F8F8DBDB3636",
+"s. c gray55",
+"d. c #909090909090",
+"f. c #9A9A9A9A9A9A",
+"g. c #9B9B9D9D9D9D",
+"h. c gray61",
+"j. c gray69",
+"k. c #B1B1B1B1B1B1",
+"l. c #BCBCBDBDBDBD",
+"z. c #C1C1C1C1C1C1",
+"x. c None",
+/* pixels */
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"> A T T U T T T U U L L J J F F ",
+" n o.6.5.5.3.1.<.2.y.,.;.-.#.D ",
+" z s b =.:.:.*.%.r.p.e.| ( @.D ",
+" z y i a X.&.$.t.u.a.i.q.~ +.A ",
+" j r l.g.q v O. .{ 9.w...8.] A ",
+" z z.r q j.8 2 B _ / 7.0.[ ' D ",
+" h f.w 7 j 4 - & c ! Q } E ` A ",
+" g q 5 7 f.= $ # + , m W P ) M ",
+" f 5 j.s.= $ # O X . . x P ^ M ",
+" s u d.d e w 7 4 : ; - = 1 V M ",
+" < ",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x."
+};
diff --git a/src/images/flags/PH.xpm b/src/images/flags/PH.xpm
new file mode 100644
index 0000000..d43fc4a
--- /dev/null
+++ b/src/images/flags/PH.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *PH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #000000003535",
+"X c #000000003B3B",
+"o c #000000004141",
+"O c #000000004747",
+"+ c #000000004D4D",
+"@ c #000000005353",
+"# c #000000005959",
+"$ c #000000005D5D",
+"% c #000000006363",
+"& c #000000006969",
+"* c #000000006D6D",
+"= c #000000007373",
+"- c #000000007575",
+"; c #000000007979",
+": c #000000007D7D",
+"> c #000000007F7F",
+", c #5F5F1A1A7373",
+"< c #63631F1F7777",
+"1 c #676725257B7B",
+"2 c #6C6C2B2B7E7E",
+"3 c #000000008181",
+"4 c #000000008D8D",
+"5 c #202020209F9F",
+"6 c #25252525A2A2",
+"7 c #26262626A2A2",
+"8 c #2B2B2B2BA5A5",
+"9 c #2C2C2C2CA6A6",
+"0 c #30303030A8A8",
+"q c #31313131A8A8",
+"w c #31313131A9A9",
+"e c #36363636ABAB",
+"r c #37373737ABAB",
+"t c #3B3B3B3BAEAE",
+"y c #3C3C3C3CAEAE",
+"u c #3D3D3C3CAEAE",
+"i c #3F3F3F3FADAD",
+"p c #707030308282",
+"a c #747436368585",
+"s c #75753B3B8888",
+"d c #44444444AFAF",
+"f c #41414141B0B0",
+"g c #42424141B0B0",
+"h c #42424242B1B1",
+"j c #47474747B3B3",
+"k c #47474747B4B4",
+"l c #49494949B1B1",
+"z c #4B4B4B4BB6B6",
+"x c #4C4C4C4CB6B6",
+"c c #4E4E4E4EB4B4",
+"v c #51515151B7B7",
+"b c #53535353B7B7",
+"n c #54545454B7B7",
+"m c #58585757B9B9",
+"M c #5C5C5C5CBBBB",
+"N c #5E5E5E5EBDBD",
+"B c #61616060BEBE",
+"V c #65656565C0C0",
+"C c #69696969C2C2",
+"Z c #6D6D6D6DC3C3",
+"A c #70707070C5C5",
+"S c #71717171C4C4",
+"D c #77777777C3C3",
+"F c #74747474C7C7",
+"G c #77777777C8C8",
+"H c #79797979C9C9",
+"J c #DDDD00000000",
+"K c #DFDF00000000",
+"L c #E1E100000000",
+"P c #E3E300000000",
+"I c #E5E500000000",
+"U c #E7E700000000",
+"Y c #E9E900000000",
+"T c #EBEB00000000",
+"R c #EDED00000000",
+"E c #EFEF00000000",
+"W c #F1F100000000",
+"Q c #F3F300000000",
+"! c #F1F10B0B0B0B",
+"~ c #F1F10F0F0E0E",
+"^ c #F2F210101010",
+"/ c #F2F213131313",
+"( c #F2F214141414",
+") c #F3F319191919",
+"_ c #F4F41E1E1E1E",
+"` c #F4F41F1F1F1F",
+"' c #F5F523232323",
+"] c #F5F524242424",
+"[ c #F2F22C2C2C2C",
+"{ c #F2F22F2F2F2F",
+"} c #F6F629292929",
+"| c #F6F62A2A2A2A",
+" . c #F7F72E2E2E2E",
+".. c #F7F72F2F2F2F",
+"X. c #F2F232323232",
+"o. c #F3F332323232",
+"O. c #F3F335353535",
+"+. c #F4F436363636",
+"@. c #F4F439393939",
+"#. c #F5F53D3D3D3D",
+"$. c #F8F834343434",
+"%. c #F8F835353535",
+"&. c #F6F642424242",
+"*. c #F7F746464646",
+"=. c #F7F74B4B4B4B",
+"-. c #F9F944444545",
+";. c #F8F850505050",
+":. c #F9F954545555",
+">. c #F9F958585858",
+",. c #F9F965656666",
+"<. c #F5F59B9B4949",
+"1. c #EFEFEFEF1A1A",
+"2. c #FFFFFFFF3737",
+"3. c #FDFDFDFD5353",
+"4. c #FCFCFCFC5D5D",
+"5. c #FAFAFAFA6B6B",
+"6. c #FEFEFEFE7373",
+"7. c #FCFCFCFC7777",
+"8. c #FDFDFDFD7E7E",
+"9. c #A6A68D8D9696",
+"0. c #ADADADAD9797",
+"q. c #9F9F9F9FDADA",
+"w. c #B2B2B2B2E2E2",
+"e. c #FAFA8F8F9191",
+"r. c #F9F995958D8D",
+"t. c #FAFAAAAAADAD",
+"y. c #FBFBFCFC8D8D",
+"u. c #FEFEFEFEB9B9",
+"i. c #D2D2D2D2E7E7",
+"p. c #FAFAD1D1CBCB",
+"a. c #EDEDEDEDD3D3",
+"s. c #FBFBEAEAC1C1",
+"d. c #FCFCFCFCC9C9",
+"f. c #FBFBFBFBD3D3",
+"g. c #FDFDFDFDD5D5",
+"h. c #FEFEFEFED8D8",
+"j. c #FEFEFEFEDCDC",
+"k. c #F1F1F1F1E8E8",
+"l. c #F5F5F5F5E8E8",
+"z. c #F7F7F7F7E9E9",
+"x. c #FBFBFBFBE3E3",
+"c. c #FEFEFEFEE7E7",
+"v. c #FBFBFBFBECEC",
+"b. c #FDFDFCFCEAEA",
+"n. c #F3F3F3F3F3F3",
+"m. c #F5F5F5F5F3F3",
+"M. c gray96",
+"N. c gray97",
+"B. c #F0F0F0F0F8F8",
+"V. c #FAFAF2F2F2F2",
+"C. c #FCFCFCFCF1F1",
+"Z. c #FEFEFEFEF5F5",
+"A. c #FBFBFBFBF9F9",
+"S. c gray98",
+"D. c gray99",
+"F. c #FCFCFCFCFEFE",
+"G. c gray100",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"0.4 3 3 3 : : - = * & % $ # @ + ",
+"2.a.q.G G F Z Z Z B B M m b c O ",
+"z.G.G.w.N b b x k h u r w 9 l o ",
+"N.Z.j.c.i.Z x k h u r w 8 7 d X ",
+"N.g.6.8.c.B.D h t r 0 8 7 5 i . ",
+"z.u.3.4.d.A.5.9.a p 2 1 < , s ",
+"n.g.7.y.v.V.r.%...} ] _ ) ( +.P ",
+"n.C.f.x.p.,.+. .} ] _ ) ( ^ o.K ",
+"k.D.A.t.-.$...} ' _ ) ( ~ ! { K ",
+"1.s.e.>.:.;.=.*.&.#. at .O.o.{ [ J ",
+"<.Q E E E E T T P P P P K K J J ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/PK.xpm b/src/images/flags/PK.xpm
new file mode 100644
index 0000000..d9f0f0c
--- /dev/null
+++ b/src/images/flags/PK.xpm
@@ -0,0 +1,169 @@
+/* XPM */
+static const char *PK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 147 2",
+" c black",
+". c #000021210000",
+"X c #000023230000",
+"o c #000025250000",
+"O c #000029290000",
+"+ c #00002B2B0000",
+"@ c #00002D2D0000",
+"# c #00002F2F0000",
+"$ c #000033330000",
+"% c #000035350000",
+"& c #000039390000",
+"* c #00003B3B0000",
+"= c #00003F3F0000",
+"- c #000043430000",
+"; c #000045450000",
+": c #000047470000",
+"> c #000049490000",
+", c #000057570000",
+"< c #00005B5B0000",
+"1 c #000061610000",
+"2 c #000067670000",
+"3 c #00006B6B0000",
+"4 c #000071710000",
+"5 c #000073730000",
+"6 c #000077770000",
+"7 c #00007B7B0000",
+"8 c #00007D7D0000",
+"9 c #000089890000",
+"0 c #0B0B90900B0B",
+"q c #131393931313",
+"w c #151597971515",
+"e c #1A1A99991A1A",
+"r c #1F1F98981F1F",
+"t c #1E1E9A9A1E1E",
+"y c #20209A9A2020",
+"u c #24249A9A2424",
+"i c #26269E9E2626",
+"p c #2A2A9B9B2A2A",
+"a c #2C2C9F9F2C2C",
+"s c #2F2F9D9D2F2F",
+"d c #2A2AA1A12B2B",
+"f c #2B2BA0A02A2A",
+"g c #2C2CA2A22C2C",
+"h c #2F2FA0A02F2F",
+"j c #2E2EA3A32E2E",
+"k c #3030A2A23030",
+"l c #3232A2A23232",
+"z c #3333A3A33232",
+"x c #3131A4A43131",
+"c c #3535A2A23535",
+"v c #3434A4A43434",
+"b c #3434A5A53434",
+"n c #3636A5A53636",
+"m c #3737A6A63737",
+"M c #3C3CA7A73C3C",
+"N c #3D3DA7A73D3D",
+"B c #3E3EA7A73E3E",
+"V c #3A3AA8A83A3A",
+"C c #3B3BA8A83B3B",
+"Z c #3D3DABAB3D3D",
+"A c #3F3FA9A93F3F",
+"S c #4242A7A74242",
+"D c #4040AAAA4040",
+"F c #4141ACAC4141",
+"G c #4646ABAB4646",
+"H c #4444ACAC4444",
+"J c #4545ADAD4545",
+"K c #4545AEAE4545",
+"L c #4646ADAD4646",
+"P c #4646AEAE4646",
+"I c #4949AEAE4949",
+"U c #4A4AADAD4A4A",
+"Y c #4B4BB0B04A4A",
+"T c #4B4BB0B04B4B",
+"R c #4E4EB1B14E4E",
+"E c #5757AFAF5757",
+"W c #5050B1B15050",
+"Q c #5050B3B35050",
+"! c #5353B3B35353",
+"~ c #5050B4B45050",
+"^ c #5151B4B45151",
+"/ c #5454B6B65454",
+"( c #5555B6B65555",
+") c #5858B6B65757",
+"_ c #5C5CB4B45C5C",
+"` c #5D5DB7B75D5D",
+"' c #5A5AB9B95A5A",
+"] c #5C5CB9B95C5C",
+"[ c #5E5EB9B95E5E",
+"{ c #5E5EBBBB5E5E",
+"} c #5F5FB9B96060",
+"| c #6161BBBB6060",
+" . c #6262BDBD6262",
+".. c #6565BEBE6565",
+"X. c #6969BEBE6969",
+"o. c #6B6BBFBF6C6C",
+"O. c #6D6DB9B96D6D",
+"+. c #6D6DC1C16D6D",
+"@. c #7070C3C37171",
+"#. c #7474C3C37474",
+"$. c #7C7CC4C47B7B",
+"%. c #7F7FC8C87F7F",
+"&. c #8787C6C68787",
+"*. c #8585C9C98585",
+"=. c #9090CACA9090",
+"-. c #9292CECE9292",
+";. c #9494CCCC9494",
+":. c #A3A3D3D3A3A3",
+">. c #A7A7D3D3A7A7",
+",. c #A6A6D4D4A6A6",
+"<. c #A7A7D6D6A7A7",
+"1. c #ACACD6D6ACAC",
+"2. c #ACACD7D7ACAC",
+"3. c #BBBBDFDFBBBB",
+"4. c #D0D0E4E4D0D0",
+"5. c #D5D5E8E8D5D5",
+"6. c #DBDBE7E7DBDB",
+"7. c #DCDCEAEADCDC",
+"8. c #E3E3EBEBE3E3",
+"9. c #E1E1EFEFE1E1",
+"0. c #E5E5EDEDE5E5",
+"q. c #E7E7EFEFE7E7",
+"w. c #E5E5F3F3E5E5",
+"e. c #E9E9F1F1E9E9",
+"r. c #EAEAF2F2EAEA",
+"t. c #EBEBF3F3EBEB",
+"y. c #EDEDF3F3EDED",
+"u. c #EDEDF5F5EFEF",
+"i. c #EFEFF4F4EFEF",
+"p. c #EFEFF5F5EFEF",
+"a. c #EFEFF7F7EFEF",
+"s. c #F0F0F5F5F0F0",
+"d. c #F0F0F6F6F0F0",
+"f. c #F1F1F7F7F1F1",
+"g. c #F1F1F9F9F1F1",
+"h. c #F2F2F8F8F2F2",
+"j. c #F3F3F9F9F3F3",
+"k. c #F4F4F9F9F4F4",
+"l. c #F5F5FAFAF5F5",
+"z. c #F7F7FCFCF7F7",
+"x. c gray98",
+"c. c #FBFBFBFBFBFB",
+"v. c gray99",
+"b. c #FDFDFDFDFDFD",
+"n. c #FEFEFEFEFEFE",
+"m. c gray100",
+"M. c None",
+/* pixels */
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"g.g.g.w.9 8 7 6 5 5 3 2 1 < , < ",
+"g.m.m.l.*. at .@.+...+.{ [ ) ! R > ",
+"g.m.m.l. ./ ^ ^ X.H A m x g I - ",
+"g.m.m.g.[ ^ Y 3.>.A F 1.I i H = ",
+"g.m.m.f.' Y *.9.[ m ` 5.>.y A & ",
+"u.m.m.g.( G -.e.K g d _ B e V $ ",
+"u.m.x.f.! A $.f.>.p u r r w m # ",
+"t.c.c.f.Y V m 1.u.;.&.,.E q z + ",
+"e.m.x.f.H x j f =.4.7.O.s 0 g o ",
+"e.x.x.i.[ ! I H S A B c z z a . ",
+"q.q.8.6.< > ; = & $ # # o o . # ",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M."
+};
diff --git a/src/images/flags/PL.xpm b/src/images/flags/PL.xpm
new file mode 100644
index 0000000..29c75a9
--- /dev/null
+++ b/src/images/flags/PL.xpm
@@ -0,0 +1,130 @@
+/* XPM */
+static const char *PL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 108 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c #F2F210101010",
+"3 c #F2F213131313",
+"4 c #F2F214141414",
+"5 c #F3F319191919",
+"6 c #F4F41E1E1E1E",
+"7 c #F4F41F1F1F1F",
+"8 c #F5F523232323",
+"9 c #F5F524242424",
+"0 c #F2F22C2C2C2C",
+"q c #F2F22F2F2F2F",
+"w c #F6F629292929",
+"e c #F6F62A2A2A2A",
+"r c #F7F72E2E2E2E",
+"t c #F7F72F2F2F2F",
+"y c #F2F232323232",
+"u c #F3F332323232",
+"i c #F3F335353535",
+"p c #F4F436363636",
+"a c #F4F439393939",
+"s c #F5F53D3D3D3D",
+"d c #F8F834343434",
+"f c #F8F835353535",
+"g c #F9F93A3A3A3A",
+"h c #F9F93B3B3A3A",
+"j c #FAFA3F3F3F3F",
+"k c #F3F344444444",
+"l c #F6F642424242",
+"z c #F7F746464646",
+"x c #F4F448484848",
+"c c #F7F74B4B4B4B",
+"v c #F5F54D4D4D4D",
+"b c #FAFA40404040",
+"n c #FAFA44444444",
+"m c #FBFB45454545",
+"M c #FBFB49494949",
+"N c #FBFB4A4A4949",
+"B c #FCFC4F4F4F4F",
+"V c #F6F652525252",
+"C c #F7F756565757",
+"Z c #F4F45F5F5F5F",
+"A c #F8F850505050",
+"S c #F9F954545555",
+"D c #F9F958585858",
+"F c #F8F85B5B5B5B",
+"G c #FAFA5D5D5D5D",
+"H c #F9F960606060",
+"J c #FBFB61616262",
+"K c #FAFA64646464",
+"L c #FCFC66666666",
+"P c #FBFB68686868",
+"I c #FCFC6A6A6A6A",
+"U c #FCFC6C6C6C6C",
+"Y c #FDFD6F6F6F6F",
+"T c #FCFC70707070",
+"R c #FDFD74747474",
+"E c #FEFE8E8E8E8E",
+"W c #E7E7D5D5D5D5",
+"Q c #E7E7D7D7D7D7",
+"! c #E9E9D9D9D9D9",
+"~ c #EBEBDDDDDDDD",
+"^ c #EDEDDFDFDFDF",
+"/ c #EFEFE1E1E1E1",
+"( c #F1F1E3E3E3E3",
+") c #F3F3E5E5E5E5",
+"_ c #F5F5E7E7E7E7",
+"` c #F7F7E9E9E9E9",
+"' c #F9F9EBEBEBEB",
+"] c #FBFBEDEDEDED",
+"[ c #FDFDEDEDEDED",
+"{ c #FDFDEFEFEFEF",
+"} c #FDFDEFEFF1F1",
+"| c #F4F4F4F4F4F4",
+" . c gray96",
+".. c #F6F6F6F6F6F6",
+"X. c gray97",
+"o. c #FDFDF1F1F1F1",
+"O. c #FFFFF1F1F1F1",
+"+. c #F8F8F8F8F8F8",
+"@. c #F9F9F9F9F9F9",
+"#. c gray98",
+"$. c #FBFBFBFBFBFB",
+"%. c gray99",
+"&. c #FDFDFCFCFDFD",
+"*. c #FDFDFDFDFDFD",
+"=. c #FDFDFDFDFEFE",
+"-. c #FEFEFEFEFEFE",
+";. c gray100",
+":. c None",
+/* pixels */
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+"O.O.O.O.O.O.] ] ] ' ` _ ) ( / ^ ",
+"O.;.;.;.;.;.;.$.$.$.$.$.$.$...~ ",
+"O.;.$.;.;.$.;.$.$.$.X.$.....X.Q ",
+"O.;.;.;.$.$.$.$.$.$.X.........Q ",
+"O.;.;.$.;.$.$.$.$.........| ..W ",
+"1 E R T U P K G C C V v x k Z O ",
+"1 U B M m j s d t e 9 6 5 4 p O ",
+"1 U M m j g d t e 9 6 5 4 2 y X ",
+", L m j g d t e 8 6 5 4 > : q X ",
+"; J G D S V c z l s a p y q 0 X ",
+"; * * & & & & @ O O O O X X . . ",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:."
+};
diff --git a/src/images/flags/PM.xpm b/src/images/flags/PM.xpm
new file mode 100644
index 0000000..4654671
--- /dev/null
+++ b/src/images/flags/PM.xpm
@@ -0,0 +1,193 @@
+/* XPM */
+static const char *PM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 171 2",
+" c black",
+". c #000000001111",
+"X c #000000001717",
+"o c #000000001B1B",
+"O c #000000001D1D",
+"+ c #000000002727",
+"@ c #000000002929",
+"# c #000000002B2B",
+"$ c #000000003131",
+"% c #000000003333",
+"& c #000000003535",
+"* c #000000003939",
+"= c #000000003D3D",
+"- c #000000004141",
+"; c #000000004545",
+": c #000000004747",
+"> c #000000004949",
+", c #000000004D4D",
+"< c #000000005D5D",
+"1 c #000000005F5F",
+"2 c #000000006161",
+"3 c #000000006363",
+"4 c #000000006565",
+"5 c #000000006767",
+"6 c #000000006F6F",
+"7 c #000000007777",
+"8 c #000000007B7B",
+"9 c #15154F4F0D0D",
+"0 c #252563630000",
+"q c #2F2F6D6D0303",
+"w c #616159596060",
+"e c #61615C5C7171",
+"r c #6C6C63635353",
+"t c #77776D6D5D5D",
+"y c #6B6B62627070",
+"u c #696964647676",
+"i c #6A6A64647474",
+"p c #79796F6F7171",
+"a c #000000008383",
+"s c #000000008585",
+"d c #000000008D8D",
+"f c #353537379F9F",
+"g c #3C3C3F3F9D9D",
+"h c #33333434A4A4",
+"j c #33333232AEAE",
+"k c #36363838ADAD",
+"l c #3B3B3F3FB2B2",
+"z c #404041419898",
+"x c #444445459C9C",
+"c c #4B4B4C4C9B9B",
+"v c #4E4E4C4C9E9E",
+"b c #525252529F9F",
+"n c #41414343A3A3",
+"m c #48484A4AA3A3",
+"M c #4C4C4F4FA9A9",
+"N c #40404242B4B4",
+"B c #4A4A4C4CB0B0",
+"V c #4D4D4D4DB0B0",
+"C c #4A4A4C4CB8B8",
+"Z c #4E4E5050A3A3",
+"A c #4C4C5050B8B8",
+"S c #4F4F5353B8B8",
+"D c #50504F4FB7B7",
+"F c #53535555AFAF",
+"G c #55555656A8A8",
+"H c #56565757A9A9",
+"J c #5A5A5A5AA1A1",
+"K c #5A5A5A5AA4A4",
+"L c #51515151BDBD",
+"P c #54545555BCBC",
+"I c #57575959B3B3",
+"U c #57575B5BB3B3",
+"Y c #54545858BCBC",
+"T c #59595D5DB6B6",
+"R c #59595A5ABEBE",
+"E c #61615C5C8A8A",
+"W c #696966669090",
+"Q c #6D6D6C6C9C9C",
+"! c #7B7B7A7AA8A8",
+"~ c #78787878AEAE",
+"^ c #75757575BABA",
+"/ c #75757777C7C7",
+"( c #77777878C8C8",
+") c #7F7F8080BEBE",
+"_ c #999900000000",
+"` c #818173735858",
+"' c #82827B7B7070",
+"] c #D7D700000000",
+"[ c #D9D900000000",
+"{ c #E3E300000000",
+"} c #E7E700000000",
+"| c #E9E900000000",
+" . c #D1D14D4D5C5C",
+".. c #D2D256566464",
+"X. c #D6D665657171",
+"o. c #EBEB7D7D6B6B",
+"O. c #EFEF7F7F6B6B",
+"+. c #F1F169696161",
+"@. c #B7B7A0A02A2A",
+"#. c #BCBCA6A62929",
+"$. c #B4B4A0A03434",
+"%. c #B8B8A3A33636",
+"&. c #BBBBA6A63939",
+"*. c #BBBBAAAA3D3D",
+"=. c #9B9B8F8F5A5A",
+"-. c #92928B8B7F7F",
+";. c #9A9A91917676",
+":. c #A4A499996767",
+">. c #BEBEAEAE4242",
+",. c #BFBFAFAF4747",
+"<. c #BDBDADAD5353",
+"1. c #BFBFAFAF5050",
+"2. c #BFBFAEAE5656",
+"3. c #C2C2A9A91D1D",
+"4. c #C3C3ACAC2323",
+"5. c #C0C0AFAF3636",
+"6. c #C6C6AFAF3737",
+"7. c #CBCBB7B72828",
+"8. c #C6C6B3B33838",
+"9. c #D1D1BDBD3838",
+"0. c #D8D89E9E6868",
+"q. c #C1C1AFAF5252",
+"w. c #C0C0B1B14D4D",
+"e. c #CCCCB8B84545",
+"r. c #C5C5B5B55151",
+"t. c #C2C2B2B25858",
+"y. c #CFCFBFBF5858",
+"u. c #C8C8BBBB7272",
+"i. c #DBDBA3A36666",
+"p. c #E0E082824444",
+"a. c #E4E48C8C6060",
+"s. c #F1F181816D6D",
+"d. c #F2F288887F7F",
+"f. c #D8D8C4C43838",
+"g. c #DEDECACA3A3A",
+"h. c #E3E3CCCC2727",
+"j. c #E3E3CCCC3232",
+"k. c #E3E3CECE3434",
+"l. c #EEEED8D82B2B",
+"z. c #E7E7D3D33939",
+"x. c #E7E7D3D33F3F",
+"c. c #F1F1DBDB3636",
+"v. c #D6D6C7C76464",
+"b. c #DEDED1D17373",
+"n. c #E4E4D1D14444",
+"m. c #E6E6D4D44F4F",
+"M. c #E6E6D5D55454",
+"N. c #E1E1D0D05959",
+"B. c #E2E2D5D57A7A",
+"V. c #898983838181",
+"C. c #8383A2A28181",
+"Z. c #F2F2B9B9B3B3",
+"A. c #F7F7BDBDB3B3",
+"S. c #C9C9D3D3D7D7",
+"D. c #D7D7D3D3D3D3",
+"F. c #DBDBE0E0E6E6",
+"G. c #DDDDE1E1E7E7",
+"H. c #DDDDE3E3E8E8",
+"J. c #F5F5C6C6C1C1",
+"K. c #FAFACACAC1C1",
+"L. c #E0E0E0E0E1E1",
+"P. c #E1E1E0E0E0E0",
+"I. c #E1E1E3E3E3E3",
+"U. c #E2E2E1E1E5E5",
+"Y. c #E7E7E5E5E6E6",
+"T. c #E7E7E7E7E7E7",
+"R. c #E7E7E8E8E6E6",
+"E. c #E8E8E7E7E8E8",
+"W. c #E8E8E8E8E5E5",
+"Q. c #EEEEEAEAE7E7",
+"!. c None",
+/* pixels */
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"0 s.o.9 d s a 7 8 5 5 6 2 5 < < ",
+"s.E.T.J.( / ) B.^ b.~ ! u.U A , ",
+"O.T.P.Z.R Y v.N.H y.W v 1.z C > ",
+"q K.A.C.P L M.m.;.n.r.E f.u K : ",
+"D.T.Q.G.D A Q V.n.z.w.l.>.y q.> ",
+"I.P.R.G.V -.b :.c.k.w.h.&.` 1.: ",
+"S.U.R.G.V t.r.e.' =.i e t #.c = ",
+"| d.+...N b g.j.9.8.5.7.4.w j # ",
+"} i.p. .l k p 6.&.%.$. at .3.r h # ",
+"{ 0.a.X.T U F G M Z m n x g f O ",
+"} ] [ _ : - = $ & + @ + o O . o ",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.",
+"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!."
+};
diff --git a/src/images/flags/PN.xpm b/src/images/flags/PN.xpm
new file mode 100644
index 0000000..33a6fb5
--- /dev/null
+++ b/src/images/flags/PN.xpm
@@ -0,0 +1,185 @@
+/* XPM */
+static const char *PN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 163 2",
+" c black",
+". c #000000002525",
+"X c #000000002727",
+"o c #000000002B2B",
+"O c #000000002D2D",
+"+ c #000000002F2F",
+"@ c #000000003333",
+"# c #000000003535",
+"$ c #000000003939",
+"% c #000000003B3B",
+"& c #000000004141",
+"* c #000000004545",
+"= c #000000004747",
+"- c #000000004B4B",
+"; c #000000004D4D",
+": c #000000005353",
+"> c #000000005757",
+", c #000000005D5D",
+"< c #000000006363",
+"1 c #000000006767",
+"2 c #000000006D6D",
+"3 c #000000007373",
+"4 c #000000007777",
+"5 c #313149497D7D",
+"6 c #333350507575",
+"7 c #474772725050",
+"8 c #4B4B75755353",
+"9 c #4B4B75755555",
+"0 c #4F4F78785757",
+"q c #505079795858",
+"w c #54547C7C5C5C",
+"e c #5A5A76767474",
+"r c #616173734848",
+"t c #6A6A73735151",
+"y c #000000008181",
+"u c #1B1B3939C7C7",
+"i c #29294646A4A4",
+"p c #2E2E4A4AA6A6",
+"a c #31314C4CA3A3",
+"s c #37375050A5A5",
+"d c #36365050A6A6",
+"f c #36365151A6A6",
+"g c #36365454ACAC",
+"h c #39395353A0A0",
+"j c #39395555A1A1",
+"k c #3B3B5454A9A9",
+"l c #3A3A5555ABAB",
+"z c #3C3C5555A9A9",
+"x c #3C3C5656A9A9",
+"c c #3B3B5D5DDBDB",
+"v c #41415A5A9898",
+"b c #40405757A3A3",
+"n c #40405959A1A1",
+"m c #43435B5BA4A4",
+"M c #40405E5EA3A3",
+"N c #41415959ACAC",
+"B c #40405A5AADAD",
+"V c #41415A5AACAC",
+"C c #46465D5DABAB",
+"Z c #46465E5EAEAE",
+"A c #46465E5EAFAF",
+"S c #59595353B9B9",
+"D c #444463638282",
+"F c #494969698686",
+"G c #4F4F68689999",
+"H c #505065659797",
+"J c #5D5D6E6E9F9F",
+"K c #4D4D6464A1A1",
+"L c #48486060AEAE",
+"P c #4E4E6464A9A9",
+"I c #4C4C6565AFAF",
+"U c #4A4A6262B1B1",
+"Y c #49496666B6B6",
+"T c #4C4C6363B1B1",
+"R c #4D4D6666B2B2",
+"E c #4F4F6767B4B4",
+"W c #4D4D6A6AB9B9",
+"Q c #54546767A7A7",
+"! c #54546E6EAEAE",
+"~ c #50506868B2B2",
+"^ c #55556C6CB4B4",
+"/ c #54546C6CB7B7",
+"( c #58586E6EB7B7",
+") c #5A5A6F6FB7B7",
+"_ c #59596F6FB8B8",
+"` c #5C5C7272BBBB",
+"' c #5E5E7474B9B9",
+"] c #7F7F5D5DABAB",
+"[ c #62627676B6B6",
+"{ c #62627777BBBB",
+"} c #66667B7BB7B7",
+"| c #66667B7BBEBE",
+" . c #7B7B6969BFBF",
+".. c #79797676B9B9",
+"X. c #5F5F7171DFDF",
+"o. c #4F4F7171E7E7",
+"O. c #51516F6FE7E7",
+"+. c #63636161CBCB",
+"@. c #69697D7DC2C2",
+"#. c #6A6A7F7FC0C0",
+"$. c #595980806060",
+"%. c #666681815A5A",
+"&. c #757582825F5F",
+"*. c #7C7C89896464",
+"=. c #7C7C8C8C7D7D",
+"-. c #7777ACAC5E5E",
+";. c #7A7AA9A97575",
+":. c #656594948686",
+">. c #6D6DA0A09292",
+",. c #6E6E8282C2C2",
+"<. c #6F6F8383C2C2",
+"1. c #73738787C4C4",
+"2. c #77778282CECE",
+"3. c #73738989C7C7",
+"4. c #C4C46A6A7979",
+"5. c #D5D567677F7F",
+"6. c #EDED65656767",
+"7. c #EDED67677171",
+"8. c #FDFD73737373",
+"9. c #AEAE61618585",
+"0. c #C3C363638787",
+"q. c #C1C164648181",
+"w. c #CCCC6E6E8484",
+"e. c #ACACB9B92323",
+"r. c #BCBCBFBF4040",
+"t. c #ABABB4B46060",
+"y. c #87878D8D9E9E",
+"u. c #8E8E93939393",
+"i. c #9B9B8E8ECACA",
+"p. c #84849292E1E1",
+"a. c #88889A9AE6E6",
+"s. c #9999A4A4E8E8",
+"d. c #9B9BB0B0EDED",
+"f. c #A2A29898CFCF",
+"g. c #AEAEBFBFF5F5",
+"h. c #B5B5B3B3E3E3",
+"j. c #DBDB9E9EABAB",
+"k. c #DDDDA2A2B4B4",
+"l. c #FEFE89898686",
+"z. c #F7F799999999",
+"x. c #F8F895959797",
+"c. c #FEFE98989797",
+"v. c #FDFDA2A29F9F",
+"b. c #FEFEA1A19E9E",
+"n. c #EAEAB1B1BBBB",
+"m. c #EAEAB8B8BEBE",
+"M. c #F0F0A2A2ABAB",
+"N. c #FDFDA9A9A4A4",
+"B. c #F5F5B3B3B6B6",
+"V. c #CACAB5B5D7D7",
+"C. c #CECED3D3F3F3",
+"Z. c #CECED7D7F7F7",
+"A. c #D6D6CFCFE8E8",
+"S. c #D7D7CECEE8E8",
+"D. c #FDFDCECECECE",
+"F. c #FEFED0D0D1D1",
+"G. c #FCFCD8D8D5D5",
+"H. c #F0F0E0E0E8E8",
+"J. c #F7F7E5E5E9E9",
+"K. c #FAFAE2E2E4E4",
+"L. c #FEFEE1E1E0E0",
+"P. c #FFFFEEEEEEEE",
+"I. c None",
+/* pixels */
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"+.z.X. .6.c ] 0.u 4 2 1 < , > : ",
+"O.Z.P.S.G.S.H.g.s.<. at .} [ ` ( - ",
+"7.K.D.b.l.N.B.M.q.R Q G y.j ! * ",
+"5.J.F.c.8.b.n.k.9.P -.e u.&.;.& ",
+"o.C.L.V.x.h.j.d.2.x F t r %.J % ",
+"S m.a.f.w.p.i.4...x h w :.0 K % ",
+"y 3.( W Y T N g x j e w >.9 H + ",
+"4 3./ E T A N z f p r.0 8 7 t.o ",
+"3 <.E U A N z s a i *.6 e.5 =.X ",
+"2 @.| { ' ) ^ ~ I L C m j m s X ",
+"1 < , > : ; * & % % @ + o X . X ",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.",
+"I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I."
+};
diff --git a/src/images/flags/PR.xpm b/src/images/flags/PR.xpm
new file mode 100644
index 0000000..3b2be96
--- /dev/null
+++ b/src/images/flags/PR.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *PR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #00000000D5D5",
+"X c #00000000D9D9",
+"o c #00000000F7F7",
+"O c #00000000F9F9",
+"+ c #00000000FBFB",
+"@ c #00000000FDFD",
+"# c blue",
+"$ c #40404040FAFA",
+"% c #44444444FAFA",
+"& c #45454545FBFB",
+"* c #49494646FBFB",
+"= c #4A4A4646FBFB",
+"- c #49494949FBFB",
+"; c #4B4B4B4BFCFC",
+": c #4D4D4E4EFAFA",
+"> c #54545151FCFC",
+", c #58585959FEFE",
+"< c #5F5F5D5DFDFD",
+"1 c #5F5F5F5FFEFE",
+"2 c #5D5D6060FDFD",
+"3 c #68685151E0E0",
+"4 c #6D6D6161F0F0",
+"5 c #68686666FCFC",
+"6 c #6C6C6868FEFE",
+"7 c #7F7F6B6BE8E8",
+"8 c #70706A6AFCFC",
+"9 c #78787474FBFB",
+"0 c #79797979FEFE",
+"q c #7D7D7B7BFFFF",
+"w c #7E7E7A7AFDFD",
+"e c #818100000000",
+"r c #838300000000",
+"t c #858500000000",
+"y c #878700000000",
+"u c #898900000000",
+"i c #8D8D00000000",
+"p c #8F8F00000000",
+"a c #919100000000",
+"s c #979700000000",
+"d c #9B9B00000000",
+"f c #9D9D00000000",
+"g c #9F9F00000000",
+"h c #A1A100000000",
+"j c #A5A500000000",
+"k c #A7A700000000",
+"l c #A3A300000909",
+"z c #A9A900000000",
+"x c #ABAB00000000",
+"c c #ADAD00000000",
+"v c #B1B100000000",
+"b c #B5B500000000",
+"n c #B9B900000000",
+"m c #BBBB00000000",
+"M c #BDBD00000000",
+"N c #BFBF00000000",
+"B c #C1C100000000",
+"V c #C7C700000000",
+"C c #CFCF00000000",
+"Z c #C3C31A1A1A1A",
+"A c #C5C51F1F1F1F",
+"S c #C7C725252525",
+"D c #C9C92B2B2B2B",
+"F c #CBCB30303030",
+"G c #CBCB33333333",
+"H c #CDCD35353636",
+"J c #CECE36363939",
+"K c #CBCB3B3B3B3B",
+"L c #CECE39393939",
+"P c #D1D130303030",
+"I c #D0D03D3D3D3D",
+"U c #D1D13C3C3C3C",
+"Y c #D1D141414141",
+"T c #D3D341414141",
+"R c #D3D345454545",
+"E c #D4D446464646",
+"W c #D4D44A4A4A4A",
+"Q c #D6D64B4B4B4B",
+"! c #D6D64E4E4E4E",
+"~ c #D3D353535353",
+"^ c #D7D752525252",
+"/ c #D5D556565656",
+"( c #D7D758585858",
+") c #D6D65A5A5A5A",
+"_ c #D8D850505050",
+"` c #D8D853535353",
+"' c #D9D955555757",
+"] c #D8D856565656",
+"[ c #DFDF5D5D5757",
+"{ c #DADA5B5B5B5B",
+"} c #D8D85E5E5E5E",
+"| c #CCCC5A5A6D6D",
+" . c #D9D95D5D6262",
+".. c #DADA63636363",
+"X. c #DCDC60606060",
+"o. c #DDDD64646464",
+"O. c #DBDB67676868",
+"+. c #D8D86B6B6B6B",
+"@. c #DEDE68686868",
+"#. c #DFDF6C6C6C6C",
+"$. c #D8D86B6B7373",
+"%. c #E1E16F6F6F6F",
+"&. c #E2E273737474",
+"*. c #E3E377777676",
+"=. c #E8E87E7E7979",
+"-. c #9C9C3D3D8383",
+";. c #A4A45F5FA3A3",
+":. c #A4A45D5DA7A7",
+">. c #AAAA6868AAAA",
+",. c #B7B77B7BB8B8",
+"<. c #85857B7BF5F5",
+"1. c #E3E37D7D8080",
+"2. c #8F8F8F8FFEFE",
+"3. c #91918D8DFDFD",
+"4. c #D9D9BFBFBFBF",
+"5. c #D9D9C9C9C9C9",
+"6. c #C2C2C0C0FCFC",
+"7. c #C5C5C3C3FEFE",
+"8. c #D2D2D1D1FEFE",
+"9. c #D8D8D9D9F9F9",
+"0. c #DDDDDBDBFCFC",
+"q. c #DFDFDFDFFDFD",
+"w. c #E5E5CDCDCDCD",
+"e. c #E3E3D1D1D1D1",
+"r. c #E9E9DDDDECEC",
+"t. c #F0F0ECECECEC",
+"y. c #F1F1EDEDEDED",
+"u. c #F1F1EEEEEEEE",
+"i. c #F2F2EEEEEEEE",
+"p. c #F0F0E6E6F2F2",
+"a. c #F3F3F0F0F0F0",
+"s. c gray95",
+"d. c #F3F3F3F3F3F3",
+"f. c #F4F4F1F1F1F1",
+"g. c #F6F6F3F3F3F3",
+"h. c #F4F4F4F4F4F4",
+"j. c gray96",
+"k. c #F6F6F5F5F5F5",
+"l. c #F6F6F6F6F6F6",
+"z. c #F7F7F6F6F6F6",
+"x. c #F7F7F7F7F6F6",
+"c. c gray97",
+"v. c #F5F5F7F7F8F8",
+"b. c #F8F8F4F4F4F4",
+"n. c #F9F9F5F5F5F5",
+"m. c #FAFAF6F6F6F6",
+"M. c #FAFAF7F7F7F7",
+"N. c #F8F8F8F8F7F7",
+"B. c #F8F8F8F8F8F8",
+"V. c #F9F9F9F9F9F9",
+"C. c #FBFBF8F8F8F8",
+"Z. c gray98",
+"A. c #FBFBFBFBFBFB",
+"S. c #F9F9FAFAFCFC",
+"D. c #FBFBFBFBFDFD",
+"F. c #FCFCF8F8F8F8",
+"G. c #FDFDFAFAF9F9",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"X l C V B M M M m b v v c k k k ",
+"# <.,.=.=.*.&.%.%. at .o. .{ / _ g ",
+"# q 1 7 p.S.C.C.n.m.n.b.x.x.g.w.",
+"# 0 6 , 1 q.S.S.C.V.B.c.x.x.x.e.",
+"# 2.8.3.1 - >.| / _ Q R Y U ( f ",
+"# 7.S.q.> & $ -.J P D S A Z K r ",
+"+ q 6.9 * $ ;.$.O.o.} ( / ~ +.g ",
+"+ 8 * & : 9.x.x.n.x.s.s.a.a.x.5.",
+"+ 5 % 3 r.B.x.x.s.s.i.i.y.t.i.4.",
+"o 4 :. .[ ` _ Q R Y I L H G F r ",
+". r m c g f f s a p p u r r r r ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/PS.xpm b/src/images/flags/PS.xpm
new file mode 100644
index 0000000..535f896
--- /dev/null
+++ b/src/images/flags/PS.xpm
@@ -0,0 +1,137 @@
+/* XPM */
+static const char *PS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 115 2",
+" c black",
+". c #000029290000",
+"X c #00002D2D0000",
+"o c #00002F2F0000",
+"O c #000033330000",
+"+ c #000039390000",
+"@ c #00003D3D0000",
+"# c #2C2C2C2C2C2C",
+"$ c #313131313131",
+"% c #373737373737",
+"& c #3D3D3C3C3D3D",
+"* c #000041410000",
+"= c #000047470000",
+"- c #00004D4D0000",
+"; c #000051510000",
+": c #000057570000",
+"> c #00005D5D0000",
+", c #000063630000",
+"< c gray26",
+"1 c gray28",
+"2 c #494949494949",
+"3 c #4C4C4C4C4C4C",
+"4 c #4E4E4E4E4E4E",
+"5 c #515151515151",
+"6 c #535353535353",
+"7 c gray33",
+"8 c #585857575757",
+"9 c gray36",
+"0 c #636359595959",
+"q c #616160606060",
+"w c #656565656565",
+"e c DimGray",
+"r c #6D6D6D6D6D6D",
+"t c #707070707171",
+"y c #747474747474",
+"u c #777777777777",
+"i c #797979797979",
+"p c #18189A9A1919",
+"a c #1C1C9C9C1C1C",
+"s c #21219F9F2121",
+"d c #2525A1A12626",
+"f c #2A2AA3A32A2A",
+"g c #3030A6A63030",
+"h c #3535A9A93535",
+"j c #3838A7A73838",
+"k c #3A3AA8A83A3A",
+"l c #3B3BA9A93B3B",
+"z c #3A3AACAC3A3A",
+"x c #3D3DA9A93D3D",
+"c c #4040ACAC4040",
+"v c #4040AEAE4040",
+"b c #4545AEAE4444",
+"n c #4848AFAF4848",
+"m c #4545B1B14545",
+"M c #4C4CB2B24C4C",
+"N c #5050B4B45050",
+"B c #5555B6B65555",
+"V c #5A5AB9B95A5A",
+"C c #5E5EBBBB5E5E",
+"Z c #6262BEBE6262",
+"A c #898900000000",
+"S c #9B9B00000000",
+"D c #B5B569693F3F",
+"F c #BCBC5C5C5C5C",
+"G c #A4A47B7B7B7B",
+"H c #F7F700000000",
+"J c #F9F900000000",
+"K c #FBFB00000000",
+"L c #FDFD00000000",
+"P c red",
+"I c #DCDC51513F3F",
+"U c #DDDD54545454",
+"Y c #FAFA40404040",
+"T c #FAFA44444444",
+"R c #FBFB45454545",
+"E c #FBFB46464646",
+"W c #FAFA44444949",
+"Q c #FBFB49494949",
+"! c #FBFB4E4E4E4E",
+"~ c #FCFC4A4A4B4B",
+"^ c #FDFD4F4F5050",
+"/ c #FCFC55555555",
+"( c #FDFD57575757",
+") c #FEFE59595959",
+"_ c #FEFE5C5C5C5C",
+"` c #FEFE5F5F5F5F",
+"' c #E8E86C6C6262",
+"] c #EBEB7B7B7B7B",
+"[ c #FCFC66666666",
+"{ c #FCFC6A6A6A6A",
+"} c #FDFD6F6F6F6F",
+"| c #FEFE79797979",
+" . c #FFFF7B7B7A7A",
+".. c #94949B9B5D5D",
+"X. c #F9F988888989",
+"o. c #F9F98E8E9191",
+"O. c #FBFB9E9E9E9E",
+"+. c #FDFD9C9C9F9F",
+"@. c gray81",
+"#. c gray82",
+"$. c #D5D5D5D5D5D5",
+"%. c #D7D7D7D7D7D7",
+"&. c gray95",
+"*. c #F3F3F3F3F3F3",
+"=. c #F4F4F4F4F4F4",
+"-. c #F4F4F5F5F5F5",
+";. c gray96",
+":. c #F6F6F6F6F6F6",
+">. c gray97",
+",. c #F8F8F8F8F8F8",
+"<. c #F9F9F9F9F9F9",
+"1. c gray98",
+"2. c #FBFBFBFBFBFB",
+"3. c gray99",
+"4. c None",
+/* pixels */
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"S ",
+"P ] G u u y t r e w q 9 8 5 3 ",
+"P .` F 0 7 5 3 1 < & % $ # 3 ",
+"P ._ _ U +.3.1.2.1.>.;.;.;.>.%.",
+"P } _ / ^ / O.1.1.1.1.;.;.;.;.$.",
+"P } ` ^ ~ R Y X.;.;.;.;.;.*.;.#.",
+"P } ! ! R W o.1.>.>.;.;.*.*.*.#.",
+"J { Q R I o.1.;.;.;.;.*.*.*.*. at .",
+"J [ R D m c z h g f d s a p l X ",
+"H ' ..Z C V B N M n b c j l j . ",
+"A ; , > : ; - = * @ + O X X . . ",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.",
+"4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4."
+};
diff --git a/src/images/flags/PT.xpm b/src/images/flags/PT.xpm
new file mode 100644
index 0000000..fbbd6b4
--- /dev/null
+++ b/src/images/flags/PT.xpm
@@ -0,0 +1,168 @@
+/* XPM */
+static const char *PT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 146 2",
+" c black",
+". c #00000B0B0000",
+"X c #00000D0D0000",
+"o c #000013130000",
+"O c #000019190000",
+"+ c #000021210000",
+"@ c #00002B2B0000",
+"# c #000033330000",
+"$ c #000035350000",
+"% c #00003B3B0000",
+"& c #00003F3F0000",
+"* c #000045450000",
+"= c #00004B4B0000",
+"- c #00004D4D0000",
+"; c #00004F4F0000",
+": c #000059590000",
+"> c #3A3A84843A3A",
+", c #3F3F8A8A3F3F",
+"< c #414191913434",
+"1 c #44448E8E4444",
+"2 c #494991914949",
+"3 c #4F4F94944F4F",
+"4 c #535391914545",
+"5 c #505095955050",
+"6 c #535396965353",
+"7 c #545496965555",
+"8 c #585899995858",
+"9 c #5C5C9D9D5C5C",
+"0 c #5D5D9D9D5D5D",
+"q c #5F5F9F9F5F5F",
+"w c #61619F9F6262",
+"e c #6969A2A25C5C",
+"r c #6666A3A36666",
+"t c #6A6AA5A56A6A",
+"y c #6F6FA8A86F6F",
+"u c #7272AAAA7373",
+"i c #7474AEAE7474",
+"p c #7676ADAD7676",
+"a c #7777ADAD7777",
+"s c #7979AEAE7979",
+"d c #7B7BB0B07A7A",
+"f c #7B7BB0B07B7B",
+"g c #DDDD00000000",
+"h c #DFDF00000000",
+"j c #E1E100000000",
+"k c #E3E300000000",
+"l c #E5E500000000",
+"z c #E7E700000000",
+"x c #E9E900000000",
+"c c #EBEB00000000",
+"v c #EDED00000000",
+"b c #EFEF00000000",
+"n c #F1F100000000",
+"m c #F3F300000000",
+"M c #F5F500000000",
+"N c #F7F700000000",
+"B c #F1F10B0B0B0B",
+"V c #F1F10F0F0E0E",
+"C c #F9F900000000",
+"Z c #FBFB00000000",
+"A c #FDFD00000000",
+"S c #F2F210101010",
+"D c #F2F213131313",
+"F c #F2F214141414",
+"G c #F3F319191919",
+"H c #F3F31A1A1A1A",
+"J c #F4F41E1E1E1E",
+"K c #F4F41F1F1F1F",
+"L c #F4F420202020",
+"P c #F5F523232323",
+"I c #F5F524242424",
+"U c #F5F525252525",
+"Y c #F5F526262626",
+"T c #F3F32F2F2A2A",
+"R c #F2F22C2C2C2C",
+"E c #F2F22F2F2F2F",
+"W c #F6F62B2B2B2B",
+"Q c #F6F62C2C2C2C",
+"! c #F7F72E2E2E2E",
+"~ c #F3F335352929",
+"^ c #F2F232323232",
+"/ c #F3F332323232",
+"( c #F3F335353535",
+") c #F7F730303030",
+"_ c #F7F731313131",
+"` c #F4F436363636",
+"' c #F5F53C3C3636",
+"] c #F4F439393939",
+"[ c #F4F43B3B3B3B",
+"{ c #F5F53D3D3D3D",
+"} c #F5F53F3F3F3F",
+"| c #F8F837373636",
+" . c #F8F837373737",
+".. c #F9F93C3C3C3C",
+"X. c #F9F93C3C3D3D",
+"o. c #F0F041413030",
+"O. c #EAEA69692A2A",
+"+. c #F6F642424242",
+"@. c #F6F644444444",
+"#. c #F7F746464646",
+"$. c #F7F749494949",
+"%. c #F7F74B4B4B4B",
+"&. c #F7F74E4E4E4E",
+"*. c #FAFA42424242",
+"=. c #FBFB53534747",
+"-. c #F8F853535353",
+";. c #F9F957575757",
+":. c #FAFA5C5C5C5C",
+">. c #E8E876764B4B",
+",. c #E7E778785858",
+"<. c #EFEF70705151",
+"1. c #EDED76765B5B",
+"2. c #F4F467674C4C",
+"3. c #E6E678786060",
+"4. c #FBFB60606060",
+"5. c #FCFC65656565",
+"6. c #FCFC69696969",
+"7. c #FDFD6D6D6D6D",
+"8. c #FDFD70707171",
+"9. c #9A9AB3B34949",
+"0. c #9B9BB5B55959",
+"q. c #ADADBBBB4040",
+"w. c #BFBFB9B94646",
+"e. c #E7E7A3A33232",
+"r. c #E9E9AFAF3737",
+"t. c #EEEEBABA3636",
+"y. c #F0F0B8B83D3D",
+"u. c #F1F181815151",
+"i. c #EAEA83837676",
+"p. c #EFEFB1B14242",
+"a. c #F3F3ABAB4747",
+"s. c #F5F5ACAC4C4C",
+"d. c #D9D9C2C23C3C",
+"f. c #E0E0C8C83030",
+"g. c #E1E1C9C93939",
+"h. c #CECEC8C84F4F",
+"j. c #C7C7C8C85454",
+"k. c #CACAC8C85454",
+"l. c #DADAD3D35959",
+"z. c #E9E9CCCC5555",
+"x. c #F9F9C1C15151",
+"c. c #D6D6E8E8FAFA",
+"v. c #E6E6D0D0D4D4",
+"b. c #EEEEDDDDDDDD",
+"n. c #F5F5DBDBD4D4",
+"m. c None",
+/* pixels */
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+": - - - - ; A A Z Z N N m m v v ",
+"= f f s s p 8.7.6.5.4.:.;.-.&.c ",
+"- f 9 e 0.j.x.s.=.*.X.| _ Q $.c ",
+"- s 9 l.z.<.2.a.p.X.| ) W Y @.l ",
+"= p 8 k.u.n.v.1.y.' ) W Y L } l ",
+"* u 6 k.>.b.c.3.t.o.W Y K G [ l ",
+"* y 5 9.w.,.i.g.f.T Y K G D ` l ",
+"% t 2 4 q.d.r.e.O.Y K G F S _ g ",
+"# r 1 , > < Q ~ L K G D V B E g ",
+"@ w 9 8 7 5 %. at .+.} [ ( / E E g ",
+"# + O o . X v c l l k k g g g g ",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.",
+"m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m."
+};
diff --git a/src/images/flags/PW.xpm b/src/images/flags/PW.xpm
new file mode 100644
index 0000000..0fe93d5
--- /dev/null
+++ b/src/images/flags/PW.xpm
@@ -0,0 +1,174 @@
+/* XPM */
+static const char *PW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 152 2",
+" c black",
+". c #00002929DDDD",
+"X c #00002B2BDDDD",
+"o c #00002F2FDDDD",
+"O c #00002F2FDFDF",
+"+ c #00003131DFDF",
+"@ c #00003333DFDF",
+"# c #00003939DDDD",
+"$ c #00003535E1E1",
+"% c #00003737E3E3",
+"& c #00003B3BE3E3",
+"* c #00003D3DE5E5",
+"= c #00003F3FE5E5",
+"- c #00004141E7E7",
+"; c #00004747E7E7",
+": c #00004545E9E9",
+"> c #00004B4BEBEB",
+", c #00004D4DE9E9",
+"< c #00004F4FEBEB",
+"1 c #00005151EDED",
+"2 c #00005959EDED",
+"3 c #00005D5DEFEF",
+"4 c #00005F5FEFEF",
+"5 c #00006161EFEF",
+"6 c #00006363F1F1",
+"7 c #00006767F3F3",
+"8 c #00006969F3F3",
+"9 c #00006D6DF5F5",
+"0 c #00007171F7F7",
+"q c #00007777F5F5",
+"w c #00007575F9F9",
+"e c #00007979F9F9",
+"r c #00007979FBFB",
+"t c #00007B7BFBFB",
+"y c #00007D7DFDFD",
+"u c #00008181FDFD",
+"i c #00008383FDFD",
+"p c #00008787FDFD",
+"a c #00008787FFFF",
+"s c #00008989FDFD",
+"d c #00008989FFFF",
+"f c #00009393FFFF",
+"g c #0B0B9595F1F1",
+"h c #0F0F9797F1F1",
+"j c #10109797F2F2",
+"k c #13139999F2F2",
+"l c #14149999F2F2",
+"z c #14149A9AF2F2",
+"x c #18189B9BF3F3",
+"c c #19199C9CF3F3",
+"v c #1A1A9C9CF3F3",
+"b c #1F1F9B9BF4F4",
+"n c #1E1E9D9DF4F4",
+"m c #1F1F9E9EF4F4",
+"M c #1F1F9F9FF4F4",
+"N c #20209F9FF4F4",
+"B c #2B2BA4A4EEEE",
+"V c #2525A0A0F5F5",
+"C c #2525A2A2F5F5",
+"Z c #2626A2A2F5F5",
+"A c #2B2BA4A4F6F6",
+"S c #2B2BA5A5F6F6",
+"D c #2C2CA2A2F2F2",
+"F c #2F2FA4A4F2F2",
+"G c #2C2CA6A6F6F6",
+"H c #3C3CACACE5E5",
+"J c #3232A5A5F3F3",
+"K c #3333A6A6F3F3",
+"L c #3131A8A8F7F7",
+"P c #3131A9A9F7F7",
+"I c #3535A8A8F3F3",
+"U c #3737ABABF2F2",
+"Y c #3636A8A8F4F4",
+"T c #3737A8A8F8F8",
+"R c #3737ABABF8F8",
+"E c #3939A9A9F4F4",
+"W c #3B3BAAAAF5F5",
+"Q c #3D3DABABF5F5",
+"! c #3F3FADADF5F5",
+"~ c #3A3AAAAAF9F9",
+"^ c #3D3DADADF9F9",
+"/ c #3F3FAEAEFAFA",
+"( c #4242ABABF6F6",
+") c #4444AFAFF6F6",
+"_ c #4242AEAEFAFA",
+"` c #4747B0B0F6F6",
+"' c #4444B1B1FAFA",
+"] c #4545B0B0FBFB",
+"[ c #4949B2B2F7F7",
+"{ c #4B4BB2B2F7F7",
+"} c #4E4EB4B4F7F7",
+"| c #4E4EB6B6F7F7",
+" . c #4949B4B4FBFB",
+".. c #4F4FB6B6FCFC",
+"X. c #5050B3B3F8F8",
+"o. c #5353B7B7F8F8",
+"O. c #5454B7B7F9F9",
+"+. c #5353B8B8FDFD",
+"@. c #5959BBBBF2F2",
+"#. c #5858B9B9F9F9",
+"$. c #5858BBBBF9F9",
+"%. c #5858B9B9FEFE",
+"&. c #5858BBBBFEFE",
+"*. c #5959BABAFEFE",
+"=. c #5C5CBBBBFAFA",
+"-. c #5D5DBCBCFAFA",
+";. c #5C5CBDBDFEFE",
+":. c #5C5CBEBEFEFE",
+">. c #5F5FBFBFFEFE",
+",. c #6161BEBEFBFB",
+"<. c #6969BFBFFCFC",
+"1. c #7575C1C1A3A3",
+"2. c #7878C3C3A1A1",
+"3. c #7B7BC6C6B2B2",
+"4. c #6565C0C0FCFC",
+"5. c #6666C0C0FCFC",
+"6. c #6A6AC3C3FCFC",
+"7. c #6D6DC3C3FDFD",
+"8. c #6F6FC4C4FDFD",
+"9. c #7070C4C4FEFE",
+"0. c #7272C6C6FEFE",
+"q. c #7474C4C4FEFE",
+"w. c #7676C8C8FEFE",
+"e. c #7777C8C8FEFE",
+"r. c #7979C8C8FEFE",
+"t. c #7979C9C9FEFE",
+"y. c #7B7BCACAFFFF",
+"u. c #FFFFFCFC0000",
+"i. c #FFFFFCFC0303",
+"p. c #FEFEFCFC0505",
+"a. c #FFFFFCFC0404",
+"s. c #FCFCFAFA1212",
+"d. c #FDFDFBFB1616",
+"f. c #FEFEFCFC1A1A",
+"g. c #FEFEFCFC1E1E",
+"h. c #F2F2F7F72626",
+"j. c #F2F2F8F82A2A",
+"k. c #F8F8F7F72121",
+"l. c #F1F1F5F53636",
+"z. c #FBFBFAFA3434",
+"x. c #C4C4E1E15B5B",
+"c. c #DBDBEBEB4545",
+"v. c #DDDDEDED5353",
+"b. c #C4C4E2E26161",
+"n. c #CACAE8E87F7F",
+"m. c #9E9ED5D58E8E",
+"M. c #8484CACAB2B2",
+"N. c #8585CCCCBDBD",
+"B. c #A7A7DADA9999",
+"V. c #8B8BCFCFC7C7",
+"C. c #C9C9E9E98383",
+"Z. c None",
+/* pixels */
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"f d d d d u u y t w 0 9 7 6 3 5 ",
+"a y.y.y.w.q.8.7.<.4.,.=.#.o.} < ",
+"d y.>.;.%.V.C.C.N._ ^ T P G [ < ",
+"d y.;.%.B.g.u.f.z.M.T P S Z ) ; ",
+"a w.%.$.j.u.u.u.d.v.U S Z N ! = ",
+"a q.+. at .a.u.u.u.u.l.H Z n x Q * ",
+"u 8...| h.u.u.u.s.c.B N x z Y % ",
+"t <. .] m.d.a.s.k.1.N x z h K @ ",
+"t 4._ / ~ 3.b.x.1.n x k h g J O ",
+"0 ,.-.#.$.} [ ) ( ! E Y J F D . ",
+"q 8 7 3 2 1 > : = = & $ @ X . # ",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z."
+};
diff --git a/src/images/flags/PY.xpm b/src/images/flags/PY.xpm
new file mode 100644
index 0000000..fbd809d
--- /dev/null
+++ b/src/images/flags/PY.xpm
@@ -0,0 +1,170 @@
+/* XPM */
+static const char *PY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 148 2",
+" c black",
+". c #00000000A7A7",
+"X c #00000000ABAB",
+"o c #00000000ADAD",
+"O c #00000000AFAF",
+"+ c #00000000B1B1",
+"@ c #00000000B5B5",
+"# c #00000000B9B9",
+"$ c #00000000BBBB",
+"% c #00000000BDBD",
+"& c #00000000C1C1",
+"* c #00000000C3C3",
+"= c #00000000C7C7",
+"- c #00000000C9C9",
+"; c #00000303CDCD",
+": c #00000B0BCFCF",
+"> c #00001111D1D1",
+", c #36365858D6D6",
+"< c #39395C5CD7D7",
+"1 c #3D3D5E5ED9D9",
+"2 c #42426262DADA",
+"3 c #46466666DCDC",
+"4 c #4B4B6A6ADDDD",
+"5 c #50506F6FDADA",
+"6 c #50506E6EDFDF",
+"7 c #53537070DCDC",
+"8 c #54547070DCDC",
+"9 c #55557373DDDD",
+"0 c #59597575DDDD",
+"q c #5C5C7878DFDF",
+"w c #54547272E1E1",
+"e c #59597676E2E2",
+"r c #5D5D7A7AE4E4",
+"t c #60607B7BE0E0",
+"y c #62627E7EE4E4",
+"u c #64647F7FE2E2",
+"i c #70708181CACA",
+"p c #66668282E6E6",
+"a c #68688282E2E2",
+"s c #6B6B8585E4E4",
+"d c #6F6F8989E6E6",
+"f c #73738C8CE7E7",
+"g c #77778F8FE8E8",
+"h c #7A7A9393E8E8",
+"j c #7F7F9696EAEA",
+"k c #E9E900000000",
+"l c #EBEB00000000",
+"z c #EDED00000000",
+"x c #EFEF00000000",
+"c c #F1F100000000",
+"v c #F3F300000000",
+"b c #F5F500000000",
+"n c #F7F700000000",
+"m c #F9F900000000",
+"M c #FBFB00000000",
+"N c #FDFD00000000",
+"B c red",
+"V c #F6F62C2C2C2C",
+"C c #F7F731313131",
+"Z c #F8F837373737",
+"A c #F9F93C3C3D3D",
+"S c #F7F749494949",
+"D c #F7F74E4E4E4E",
+"F c #FAFA42424242",
+"G c #FBFB47474747",
+"H c #FCFC4C4C4C4C",
+"J c #F8F853535353",
+"K c #F9F957575757",
+"L c #FDFD51515151",
+"P c #FDFD54545454",
+"I c #FAFA5C5C5C5C",
+"U c #FEFE59595959",
+"Y c #FEFE5C5C5C5C",
+"T c #FEFE5F5F5F5F",
+"R c #EAEA79797373",
+"E c #FBFB60606060",
+"W c #FCFC65656565",
+"Q c #FCFC69696969",
+"! c #FDFD6D6D6D6D",
+"~ c #FDFD70707171",
+"^ c #FEFE74747474",
+"/ c #FEFE77777777",
+"( c #FEFE79797979",
+") c #FFFF7B7B7A7A",
+"_ c #FFFF7B7B7B7B",
+"` c #9A9ABDBD7A7A",
+"' c #EAEA80807979",
+"] c #83839999EBEB",
+"[ c #F1F18D8D8787",
+"{ c #F3F392928C8C",
+"} c #CFCFD3D3DBDB",
+"| c #CFCFD1D1DFDF",
+" . c #CFCFD3D3E1E1",
+".. c #D3D3D7D7E3E3",
+"X. c #E7E7DDDDDDDD",
+"o. c #F6F6CCCCC8C8",
+"O. c #F6F6D4D4D1D1",
+"+. c #F7F7D9D9D9D9",
+"@. c #F9F9D2D2D0D0",
+"#. c #F9F9DBDBD8D8",
+"$. c #FAFADEDEDEDE",
+"%. c #E7E7E9E9F0F0",
+"&. c #E9E9EAEAF0F0",
+"*. c #EAEAECECF1F1",
+"=. c #EBEBECECF2F2",
+"-. c #EBEBEDEDF2F2",
+";. c #ECECEEEEF4F4",
+":. c #EFEFEFEFF5F5",
+">. c #EDEDEFEFF9F9",
+",. c #EDEDF1F1F7F7",
+"<. c #EFEFF0F0F7F7",
+"1. c #EFEFF1F1F7F7",
+"2. c #EFEFF1F1FBFB",
+"3. c #EFEFF3F3FBFB",
+"4. c #F5F5EFEFEFEF",
+"5. c gray95",
+"6. c #F3F3F3F3F3F3",
+"7. c #F6F6F0F0F0F0",
+"8. c #F6F6F1F1F1F1",
+"9. c #F7F7F2F2F2F2",
+"0. c #F4F4F4F4F4F4",
+"q. c #F4F4F5F5F5F5",
+"w. c gray96",
+"e. c #F6F6F6F6F6F6",
+"r. c gray97",
+"t. c #F0F0F2F2F8F8",
+"y. c #F2F2F3F3F9F9",
+"u. c #F3F3F4F4FAFA",
+"i. c #F4F4F5F5FAFA",
+"p. c #F7F7F7F7FCFC",
+"a. c #F8F8F3F3F3F3",
+"s. c #F9F9F4F4F4F4",
+"d. c #FAFAF4F4F5F5",
+"f. c #FBFBF5F5F5F5",
+"g. c #FCFCF6F6F6F6",
+"h. c #FDFDF7F7F7F7",
+"j. c #FFFFF5F5F5F5",
+"k. c gray98",
+"l. c #FBFBFBFBFBFB",
+"z. c #FBFBFCFCFBFB",
+"x. c #FDFDF8F8F8F8",
+"c. c #FEFEF9F9F9F9",
+"v. c #FEFEFBFBFBFB",
+"b. c gray99",
+"n. c #FDFDFCFCFDFD",
+"m. c #FDFDFDFDFDFD",
+"M. c #FEFEFEFEFEFE",
+"N. c None",
+/* pixels */
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"B B B B M B B M M M n n v v z z ",
+"B _ _ _ ^ ^ ~ ! Q W E I K L D k ",
+"B _ T U U P L H G F A Z C V S k ",
+"j.v.v.v.v.j.g.g.g.a.a.9.6.4.6.X.",
+"3.M.M.M.v.k.$.{ [ +.r.w.9.w.w...",
+"3.M.M.z.z.k. at .` i o.e.w.w.6.6. .",
+";.M.z.l.z.v.#.' R O.w.w.6.5.w. .",
+"3.i.i.i.y.t.t.t.:.:.&.&.&.%.&.} ",
+"> ] p y r e w 4 4 3 2 1 < , 8 . ",
+": j h g f f s a u r r 0 9 7 7 . ",
+"; - - * & % $ $ @ + X X X . . . ",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.",
+"N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N."
+};
diff --git a/src/images/flags/QA.xpm b/src/images/flags/QA.xpm
new file mode 100644
index 0000000..37f1382
--- /dev/null
+++ b/src/images/flags/QA.xpm
@@ -0,0 +1,130 @@
+/* XPM */
+static const char *QA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 108 2",
+" c black",
+". c #050500000000",
+"X c #0D0D00000000",
+"o c #131300000000",
+"O c #171700000000",
+"+ c #1B1B00000000",
+"@ c #212100000000",
+"# c #252500000000",
+"$ c #57570D0D0505",
+"% c #5A5A1A1A1111",
+"& c #5E5E1D1D1515",
+"* c #5E5E1D1D1616",
+"= c #606022221A1A",
+"- c #606022221B1B",
+"; c #626222221B1B",
+": c #646426261F1F",
+"> c #646427271F1F",
+", c #646427272020",
+"< c #68682B2B2424",
+"1 c #68682C2C2525",
+"2 c #68682D2D2525",
+"3 c #69692D2D2626",
+"4 c #6C6C31312929",
+"5 c #6C6C32322A2A",
+"6 c #6D6D32322B2B",
+"7 c #6D6D33332C2C",
+"8 c #707036362E2E",
+"9 c #707036362F2F",
+"0 c #707037372F2F",
+"q c #707037373131",
+"w c #707038383131",
+"e c #717138383131",
+"r c #727239393232",
+"t c #72723B3B3434",
+"y c #72723B3B3535",
+"u c #74743B3B3434",
+"i c #74743C3C3434",
+"p c #74743C3C3535",
+"a c #75753C3C3636",
+"s c #75753D3D3636",
+"d c #75753E3E3737",
+"f c #75753F3F3737",
+"g c #76763E3E3737",
+"h c #777741413B3B",
+"j c #787841413939",
+"k c #787841413A3A",
+"l c #787842423B3B",
+"z c #797942423A3A",
+"x c #797942423C3C",
+"c c #797943433C3C",
+"v c #7A7A43433D3D",
+"b c #7A7A45453F3F",
+"n c #7C7C47473F3F",
+"m c #7B7B46464040",
+"M c #7D7D47474040",
+"N c #7D7D47474141",
+"B c #7C7C49494242",
+"V c #7D7D48484242",
+"C c #7E7E48484242",
+"Z c #7F7F4B4B4545",
+"A c #7F7F4D4D4646",
+"S c #81814C4C4545",
+"D c #81814D4D4747",
+"F c #828250504949",
+"G c #838351514B4B",
+"H c #858552524B4B",
+"J c #858552524D4D",
+"K c #848454544E4E",
+"L c #868655555050",
+"P c #888857575050",
+"I c #898957575151",
+"U c #8A8A59595353",
+"Y c #8C8C5B5B5555",
+"T c #8C8C5D5D5858",
+"R c #8F8F61615C5C",
+"E c #929266666161",
+"W c #939366666161",
+"Q c #96966A6A6565",
+"! c #99996E6E6A6A",
+"~ c #99996F6F6A6A",
+"^ c #9C9C73736D6D",
+"/ c #9E9E76767070",
+"( c #A0A077777373",
+") c #A1A179797575",
+"_ c #A6A680807C7C",
+"` c #E3E3E3E3E1E1",
+"' c #E7E7E5E5E5E5",
+"] c #E9E9E7E7E7E7",
+"[ c #EBEBE9E9E9E9",
+"{ c #EFEFEDEDEBEB",
+"} c #F1F1EFEFEDED",
+"| c #F1F1EFEFEFEF",
+" . c #F1F1F1F1F1F1",
+".. c #F3F3F1F1F1F1",
+"X. c #F5F5F3F3F3F3",
+"o. c #F5F5F5F5F3F3",
+"O. c #F7F7F5F5F5F5",
+"+. c #F9F9F5F5F5F5",
+"@. c #F8F8F8F8F8F8",
+"#. c #F9F9F9F9F9F9",
+"$. c gray98",
+"%. c #FBFBFBFBFBFB",
+"&. c #FBFBFCFCFBFB",
+"*. c gray99",
+"=. c #FDFDFDFDFDFD",
+"-. c #FEFEFEFEFEFE",
+";. c gray100",
+":. c None",
+/* pixels */
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+"+.O.O.O.O.$ # @ + o X . ",
+"+.;.;.;.%.;.) / ^ ~ Q W R T U ",
+"O.;.;.;.;.) Y I J S C v g r K ",
+"O.;.;.;.;.;.L H D C l g r 7 F ",
+"O.;.;.%.%./ H S N v g q 5 3 Z ",
+"..;.;.$.*.$.S n l g 7 7 3 , C ",
+"| ;.$.%.$.! n l g 7 5 3 , ; l ",
+"..$.%.%.%.+.h i 9 5 < : = * g ",
+"{ ;.%.%.%.E g 9 5 < : = * % y ",
+"| $.$.%.%. at .K F A C b h g y r ",
+"{ [ ' ' ` O ",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:."
+};
diff --git a/src/images/flags/RE.xpm b/src/images/flags/RE.xpm
new file mode 100644
index 0000000..d7a26cf
--- /dev/null
+++ b/src/images/flags/RE.xpm
@@ -0,0 +1,153 @@
+/* XPM */
+static const char *RE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 131 2",
+" c black",
+". c #17174747A5A5",
+"X c #23234F4FABAB",
+"o c #2D2D5757AFAF",
+"O c #35355F5FB5B5",
+"+ c #3F3F6767B9B9",
+"@ c #49497171BDBD",
+"# c #53537777C3C3",
+"$ c #5B5B7F7FC7C7",
+"% c #63638585CBCB",
+"& c #69698989CDCD",
+"* c #6F6F8F8FD1D1",
+"= c #71719191D1D1",
+"- c #73739393D3D3",
+"; c #73739595D3D3",
+": c #C5C500000000",
+"> c #C7C700000000",
+", c #CBCB00000000",
+"< c #CDCD00000000",
+"1 c #D3D300000000",
+"2 c #D5D500000000",
+"3 c #DBDB00000000",
+"4 c #DDDD00000000",
+"5 c #E1E100000000",
+"6 c #E5E500000000",
+"7 c #E7E700000000",
+"8 c #EBEB00000000",
+"9 c #EFEF07070000",
+"0 c #F1F113130000",
+"q c #E6E64D4D3E3E",
+"w c #E8E852524343",
+"e c #E9E956564848",
+"r c #EAEA57574848",
+"t c #EAEA57574A4A",
+"y c #EBEB5D5D4F4F",
+"u c #ECEC5E5E5050",
+"i c #E8E863635555",
+"p c #EEEE63635555",
+"a c #EEEE64645656",
+"s c #EEEE64645757",
+"d c #E9E966665959",
+"f c #E9E966665A5A",
+"g c #EAEA69695D5D",
+"h c #EAEA6A6A5D5D",
+"j c #EFEF69695C5C",
+"k c #F0F06A6A5C5C",
+"l c #F0F06C6C5D5D",
+"z c #ECEC6D6D6161",
+"x c #ECEC6E6E6262",
+"c c #EDED74746868",
+"v c #EFEF78786C6C",
+"b c #F1F170706363",
+"n c #F1F170706464",
+"m c #F2F271716464",
+"M c #F3F377776A6A",
+"N c #F3F377776B6B",
+"B c #F1F17E7E7272",
+"V c #F5F57D7D7272",
+"C c #F2F284847878",
+"Z c #F4F488887E7E",
+"A c #9F9F9F9F9F9F",
+"S c #A7A7A7A7A7A7",
+"D c gray68",
+"F c #B3B3B0B0B0B0",
+"G c gray72",
+"H c gray",
+"J c #9797ACACD8D8",
+"K c #9C9CB0B0DADA",
+"L c #A0A0B4B4DDDD",
+"P c #A0A0B5B5DDDD",
+"I c #A1A1B5B5DDDD",
+"U c #A3A3B5B5DCDC",
+"Y c #A5A5B8B8DFDF",
+"T c #A5A5B9B9DFDF",
+"R c #A7A7B9B9DDDD",
+"E c #A6A6B9B9E0E0",
+"W c #A9A9BCBCE1E1",
+"Q c #A9A9BDBDE1E1",
+"! c #AAAABDBDE0E0",
+"~ c #AAAABDBDE1E1",
+"^ c #AEAEBFBFE3E3",
+"/ c #AFAFBFBFE2E2",
+"( c #AEAEBFBFE4E4",
+") c #AEAEC0C0E4E4",
+"_ c #B1B1C2C2E5E5",
+"` c #B1B1C3C3E5E5",
+"' c #B2B2C3C3E5E5",
+"] c #B3B3C3C3E4E4",
+"[ c #B4B4C5C5E7E7",
+"{ c #B7B7C7C7E6E6",
+"} c #B7B7C8C8E8E8",
+"| c #BABAC9C9E8E8",
+" . c #BEBECCCCE9E9",
+".. c #F5F58D8D8383",
+"X. c #F7F793938989",
+"o. c #F8F897978E8E",
+"O. c #CECECECECECE",
+"+. c gray81",
+"@. c #D2D2D2D2D2D2",
+"#. c #D5D5D5D5D5D5",
+"$. c gainsboro",
+"%. c #DFDFDFDFDFDF",
+"&. c #C0C0CECEEAEA",
+"*. c #C1C1CFCFEBEB",
+"=. c #C3C3D0D0ECEC",
+"-. c #C3C3D1D1ECEC",
+";. c #C4C4D2D2EDED",
+":. c #C4C4D3D3EDED",
+">. c #E2E2E2E2E2E2",
+",. c #E4E4E4E4E4E4",
+"<. c gray90",
+"1. c #E6E6E6E6E6E6",
+"2. c #E7E7E7E7E7E7",
+"3. c gray91",
+"4. c #E9E9E9E9E9E9",
+"5. c #E9E9E9E9EAEA",
+"6. c #EAEAEAEAEAEA",
+"7. c gray92",
+"8. c #ECECEBEBEBEB",
+"9. c #ECECECECECEC",
+"0. c gray93",
+"q. c #EEEEEEEEEEEE",
+"w. c #EFEFEFEFEFEF",
+"e. c gray94",
+"r. c #F1F1F1F1F1F1",
+"t. c #F3F3F3F3F3F3",
+"y. c #F4F4F4F4F4F4",
+"u. c #F6F6F6F6F6F6",
+"i. c gray97",
+"p. c #F8F8F8F8F8F8",
+"a. c None",
+/* pixels */
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"; ; ; ; - $.$.#. at .O.@.0 9 8 6 6 ",
+"; :.:.*.*.p.i.i.i.i.t.o.X...Z 5 ",
+"; :.} [ ' q.7.6.6.6.<.V N m C 4 ",
+"- *.[ ' ) w.7.q.6.6.<.M m l B 4 ",
+"* &.' ( ~ q.q.8.6.<.<.b j s v 2 ",
+"& .) Q Y t.q.q.q.6.6.j s u c 2 ",
+"% } Q E U q.q.q.6.6.<.p y e x < ",
+"$ { E U K q.q.6.2.<.<.y e w h , ",
+"# ' K K J 7.6.<.<.<.>.e w q f > ",
+"@ / ~ Y U q.q.6.6.<.<.x h f i > ",
+"+ O o X . H G F D S A < , > : > ",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.",
+"a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a."
+};
diff --git a/src/images/flags/RO.xpm b/src/images/flags/RO.xpm
new file mode 100644
index 0000000..9182d59
--- /dev/null
+++ b/src/images/flags/RO.xpm
@@ -0,0 +1,175 @@
+/* XPM */
+static const char *RO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 153 2",
+" c black",
+". c #00000000A9A9",
+"X c #00000000ABAB",
+"o c #00000000ADAD",
+"O c #00000000AFAF",
+"+ c #00000000B3B3",
+"@ c #00000000B5B5",
+"# c #00000000B7B7",
+"$ c #00000707BBBB",
+"% c #00000D0DBDBD",
+"& c #00001313BFBF",
+"* c #00001919C1C1",
+"= c #00001919C3C3",
+"- c #00001D1DC3C3",
+"; c #00001D1DC5C5",
+": c #00001D1DC9C9",
+"> c #00002B2BC7C7",
+", c #3F3F6B6BD5D5",
+"< c #3A3A6868D8D8",
+"1 c #44446F6FD6D6",
+"2 c #40406C6CD9D9",
+"3 c #45457070D7D7",
+"4 c #45457171DBDB",
+"5 c #49497474D8D8",
+"6 c #49497474D9D9",
+"7 c #4B4B7575DDDD",
+"8 c #4F4F7878DADA",
+"9 c #4F4F7878DBDB",
+"0 c #50507979DEDE",
+"q c #53537C7CDBDB",
+"w c #54547C7CDCDC",
+"e c #54547C7CDDDD",
+"r c #54547D7DDFDF",
+"t c #58587F7FDADA",
+"y c #58588080DCDC",
+"u c #58588080DDDD",
+"i c #5D5D8383DBDB",
+"p c #5C5C8383DEDE",
+"a c #5F5F8585DFDF",
+"s c #59598181E0E0",
+"d c #61618686DDDD",
+"f c #66668A8ADEDE",
+"g c #6A6A8E8EE0E0",
+"h c #6F6F9191E0E0",
+"j c #72729494E2E2",
+"k c #76769797E3E3",
+"l c #77779898E7E7",
+"z c #79799999E4E4",
+"x c #79799999E5E5",
+"c c #7B7B9A9AE4E4",
+"v c #7B7B9B9BE4E4",
+"b c #DDDD00000000",
+"n c #DFDF00000000",
+"m c #E1E100000000",
+"M c #E3E300000000",
+"N c #E5E500000000",
+"B c #E7E700000000",
+"V c #E9E900000000",
+"C c #EBEB00000000",
+"Z c #EDED00000000",
+"A c #EFEF00000000",
+"S c #F1F100000000",
+"D c #F3F300000000",
+"F c #F5F500000000",
+"G c #F1F10B0B0B0B",
+"H c #F1F10F0F0E0E",
+"J c #F2F210101010",
+"K c #F2F213131313",
+"L c #F2F214141414",
+"P c #F3F319191919",
+"I c #F3F31A1A1A1A",
+"U c #F4F41F1F1F1F",
+"Y c #F4F420202020",
+"T c #F5F525252525",
+"R c #F5F526262626",
+"E c #F2F22C2C2C2C",
+"W c #F2F22F2F2F2F",
+"Q c #F6F62B2B2B2B",
+"! c #F6F62C2C2C2C",
+"~ c #F2F232323232",
+"^ c #F3F332323232",
+"/ c #F3F335353535",
+"( c #F7F731313131",
+") c #F4F436363636",
+"_ c #F4F43B3B3B3B",
+"` c #F5F53F3F3F3F",
+"' c #F8F837373737",
+"] c #F6F644444444",
+"[ c #F7F749494949",
+"{ c #F7F74E4E4E4E",
+"} c #F8F853535353",
+"| c #F9F957575757",
+" . c #FAFA5C5C5C5C",
+".. c #E3E3A9A90000",
+"X. c #E5E5B9B90000",
+"o. c #E7E7BDBD0000",
+"O. c #E9E9BDBD0000",
+"+. c #EBEBC1C10000",
+"@. c #EFEFDDDD0000",
+"#. c #F7F7D5D50000",
+"$. c #F3F3DDDD0000",
+"%. c #F5F5DFDF0000",
+"&. c #F7F7E1E10000",
+"*. c #F7F7E3E30000",
+"=. c #F3F3E3E31919",
+"-. c #F4F4E5E51F1F",
+";. c #F4F4F4F41E1E",
+":. c #F5F5E6E62424",
+">. c #F6F6E8E82B2B",
+",. c #F4F4E7E73939",
+"<. c #F7F7E9E93030",
+"1. c #F8F8EAEA3636",
+"2. c #F9F9ECEC3D3D",
+"3. c #F5F5F5F52323",
+"4. c #F5F5F5F52424",
+"5. c #F6F6F6F62929",
+"6. c #F6F6F6F62A2A",
+"7. c #F7F7F7F72E2E",
+"8. c #F7F7F7F72F2F",
+"9. c #F7F7F7F73030",
+"0. c #F0F0F0F03A3A",
+"q. c #F5F5F5F53D3D",
+"w. c #F8F8F8F83434",
+"e. c #F8F8F8F83535",
+"r. c #F8F8F8F83636",
+"t. c #F9F9F9F93A3A",
+"y. c #F9F9F9F93B3B",
+"u. c #F9F9F9F93C3C",
+"i. c #F1F1F1F14040",
+"p. c #F2F2F2F24646",
+"a. c #F6F6F6F64242",
+"s. c #F7F7F7F74646",
+"d. c #F3F3F3F34B4B",
+"f. c #F7F7F7F74B4B",
+"g. c #FAFAFAFA4040",
+"h. c #FAFAFAFA4141",
+"j. c #FAFAFAFA4242",
+"k. c #FBFBFBFB4646",
+"l. c #FBFBFBFB4747",
+"z. c #FCFCFCFC4B4B",
+"x. c #FCFCFCFC4C4C",
+"c. c #F2F2F2F25555",
+"v. c #F4F4F4F45050",
+"b. c #F5F5F5F55656",
+"n. c #F6F6F6F65A5A",
+"m. c #FDFDFDFD5151",
+"M. c #FBFBF0F06060",
+"N. c #FCFCFCFC6565",
+"B. c #FCFCFCFC6969",
+"V. c #FDFDFDFD6D6D",
+"C. c #FDFDFDFD7171",
+"Z. c #F8F8F8F87878",
+"A. c None",
+/* pixels */
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"> - - ; : $.*.*.%.$.#.F D D Z Z ",
+"= v v v l Z.C.V.B.N.M. .| } { C ",
+"- v a p r n.m.x.l.h.2.' ( ! [ C ",
+"- z p u r b.x.l.h.u.1.( Q R ] N ",
+"= k t w 0 v.l.h.u.r.<.Q R Y ` N ",
+"& j q 8 7 d.u.t.r.9.>.R U P _ N ",
+"% h 8 6 4 p.t.r.9.6.:.U P K ) N ",
+"$ f 6 4 2 i.r.7.6.4.-.P K K ^ n ",
+"# f 1 , < 0.7.6.3.;.=.K H G W n ",
+"+ d i i w c.f.s.a.q.,./ ^ W E n ",
+"+ + . . o o.+.O.o.X...m n n b b ",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.",
+"A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A."
+};
diff --git a/src/images/flags/RS.xpm b/src/images/flags/RS.xpm
new file mode 100644
index 0000000..dcf7def
--- /dev/null
+++ b/src/images/flags/RS.xpm
@@ -0,0 +1,142 @@
+/* XPM */
+static const char *RS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 120 2",
+" c black",
+". c #00001A1A6C6C",
+"X c #00001D1D7676",
+"o c #00001D1D7878",
+"O c #00001E1E7A7A",
+"+ c #000054549696",
+"@ c #000054549797",
+"# c #000055559797",
+"$ c #000055559898",
+"% c #000056569999",
+"& c #000056569A9A",
+"* c #000056569B9B",
+"= c #000056569C9C",
+"- c #000057579C9C",
+"; c #000057579E9E",
+": c #000059599F9F",
+"> c #00005A5AA1A1",
+", c #00005A5AA2A2",
+"< c #00005B5BA4A4",
+"1 c #00005C5CA4A4",
+"2 c #00005D5DA7A7",
+"3 c #30307373A4A4",
+"4 c #30307373A5A5",
+"5 c #34347E7EB3B3",
+"6 c #35357F7FB6B6",
+"7 c #36368282B8B8",
+"8 c #BFBF00000000",
+"9 c #C1C100000000",
+"0 c #C3C300000000",
+"q c #C5C500000000",
+"w c #C7C700000000",
+"e c #C9C900000000",
+"r c #CBCB00000000",
+"t c #CDCD00000000",
+"y c #D0D000000000",
+"u c #D2D200000000",
+"i c #D5D500000000",
+"p c #D7D700000000",
+"a c #D9D900000000",
+"s c #DADA00000000",
+"d c #DBDB00000000",
+"f c #DDDD00000000",
+"g c #C4C43C3C3F3F",
+"h c #D0D031313131",
+"j c #D2D231313131",
+"k c #D3D332323232",
+"l c #D4D432323232",
+"z c #D5D532323232",
+"x c #D6D632323232",
+"c c #D7D732323232",
+"v c #D7D733333333",
+"b c #D2D235353B3B",
+"n c #D8D833333333",
+"m c #D9D933333333",
+"M c #DBDB34343434",
+"N c #DDDD34343434",
+"B c #E0E000000000",
+"V c #E1E100000000",
+"C c #E2E200000000",
+"Z c #E4E400000000",
+"A c #E5E536363636",
+"S c #E7E736363636",
+"D c #E9E937373737",
+"F c #EBEB37373737",
+"G c #C8C83D3D4141",
+"H c #CDCD3E3E4242",
+"J c #CECE3E3E4343",
+"K c #D0D03F3F4343",
+"L c #D0D03F3F4545",
+"P c #D5D541414545",
+"I c #D8D857574E4E",
+"U c #D9D958584F4F",
+"Y c #DCDC59595050",
+"T c #DEDE5A5A5151",
+"R c #D1D15D5D6060",
+"E c #D2D25E5E6161",
+"W c #CECE6E6E7272",
+"Q c #D0D071717474",
+"! c #D7D777777979",
+"~ c #DDDD7A7A7C7C",
+"^ c #E0E05B5B5151",
+"/ c #E3E35C5C5252",
+"( c #E5E55D5D5353",
+") c #E7E75E5E5454",
+"_ c #E9E95F5F5555",
+"` c #EBEB60605656",
+"' c #EDED61615656",
+"] c #E5E57E7E5454",
+"[ c #F0F062625757",
+"{ c #F3F363635757",
+"} c #F5F564645858",
+"| c #F5F564645959",
+" . c #F5F565655959",
+".. c #F5F566665A5A",
+"X. c #E8E880805555",
+"o. c #F5F5F5F57676",
+"O. c #F5F5F5F57777",
+"+. c #EDEDA3A3A4A4",
+"@. c #EEEEB8B8B8B8",
+"#. c #F1F1BABABABA",
+"$. c #EBEBC2C2C3C3",
+"%. c #EDEDC3C3C4C4",
+"&. c #E9E9CCCCCECE",
+"*. c #EDEDD0D0D1D1",
+"=. c #F0F0C7C7C7C7",
+"-. c gray90",
+";. c #E6E6E6E6E6E6",
+":. c #E7E7E7E7E7E7",
+">. c #E9E9E9E9E9E9",
+",. c gray92",
+"<. c gray93",
+"1. c #EFEFEFEFEFEF",
+"2. c gray94",
+"3. c #F1F1F1F1F1F1",
+"4. c gray95",
+"5. c #F3F3F3F3F3F3",
+"6. c #F5F5F1F1F1F1",
+"7. c #F4F4F4F4F4F4",
+"8. c gray96",
+"9. c None",
+/* pixels */
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"Z B B f f p p i u u u r r r q q ",
+"B .. .} } { ' ' ) ) / / ^ T T 9 ",
+"f ..S S b ] ] L M M M z z k I 9 ",
+"f { S S P o.o.H M n z z k k I 9 ",
+"O 7 2 2 +.K H @.* * * $ $ $ 4 . ",
+"X 6 < , #.8.6.=.* * $ $ $ @ 3 . ",
+"X 5 , : ~ E E ! * $ $ $ @ @ 3 . ",
+"8.8.8.8.G %.$.g 8.5.3.3.3.1.8.-.",
+"8.8.8.8.*.Q W &.5.3.3.3.1.3.3.-.",
+"3.8.8.8.8.8.8.3.3.3.3.3.3.3.3.-.",
+"1.:.:.:.:.:.-.-.-.-.-.-.-.-.-.-.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9."
+};
diff --git a/src/images/flags/RU.xpm b/src/images/flags/RU.xpm
new file mode 100644
index 0000000..4db6e82
--- /dev/null
+++ b/src/images/flags/RU.xpm
@@ -0,0 +1,159 @@
+/* XPM */
+static const char *RU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 137 2",
+" c black",
+". c #7B7B00000000",
+"X c #00000000E3E3",
+"o c #00000000E5E5",
+"O c #00000000E7E7",
+"+ c #00000000FDFD",
+"@ c #14141414F2F2",
+"# c #19191919F3F3",
+"$ c #1A1A1A1AF3F3",
+"% c #1F1F1F1FF4F4",
+"& c #20202020F4F4",
+"* c #24242424F5F5",
+"= c #25252525F5F5",
+"- c #2A2A2A2AF6F6",
+"; c #2A2A2B2BF6F6",
+": c #2B2B2B2BF6F6",
+"> c #2F2F2F2FF7F7",
+", c #30303030F7F7",
+"< c #36363636F4F4",
+"1 c #35353535F8F8",
+"2 c #36363636F8F8",
+"3 c #3B3B3B3BF5F5",
+"4 c #3F3F3F3FF5F5",
+"5 c #3B3B3B3BF9F9",
+"6 c #40404040FAFA",
+"7 c #41414141FAFA",
+"8 c #45454545FBFB",
+"9 c #46464646FBFB",
+"0 c #49494A4AFBFB",
+"q c #49494949FFFF",
+"w c #4B4B4A4AFCFC",
+"e c #4B4B4B4BFCFC",
+"r c #4F4F4F4FFCFC",
+"t c #50504F4FFDFD",
+"y c #53535353FDFD",
+"u c #54545454FDFD",
+"i c #58585858FEFE",
+"p c #6F6F6F6FFDFD",
+"a c #72727272FEFE",
+"s c #76767676FEFE",
+"d c #7D7D7D7DF5F5",
+"f c #B3B300000000",
+"g c #BDBD10104343",
+"h c #BFBF14144646",
+"j c #DDDD00000000",
+"k c #DFDF00000000",
+"l c #E1E100000000",
+"z c #E3E300000000",
+"x c #E5E500000000",
+"c c #E7E700000000",
+"v c #E9E900000000",
+"b c #EBEB00000000",
+"n c #EDED00000000",
+"m c #EFEF00000000",
+"M c #F1F100000000",
+"N c #F3F300000000",
+"B c #F5F500000000",
+"V c #F7F700000000",
+"C c #F1F10B0B0B0B",
+"Z c #F1F10F0F0E0E",
+"A c #F9F900000000",
+"S c #F2F213131313",
+"D c #F3F319191919",
+"F c #F4F41E1E1E1E",
+"G c #F5F523232323",
+"H c #F2F22C2C2C2C",
+"J c #F2F22F2F2F2F",
+"K c #F6F629292929",
+"L c #F7F72E2E2E2E",
+"P c #F2F232323232",
+"I c #F3F335353535",
+"U c #F4F439393939",
+"Y c #F5F53D3D3D3D",
+"T c #F8F834343434",
+"R c #F9F93A3A3A3A",
+"E c #FAFA3F3F3F3F",
+"W c #C2C219194B4B",
+"Q c #C4C41F1F4F4F",
+"! c #C6C624245353",
+"~ c #C8C82A2A5858",
+"^ c #CACA2F2F5D5D",
+"/ c #C8C832325E5E",
+"( c #CCCC34346161",
+") c #CECE3A3A6666",
+"_ c #D0D03F3F6A6A",
+"` c #D1D145456E6E",
+"' c #D3D349497272",
+"] c #F6F642424242",
+"[ c #F7F746464646",
+"{ c #F7F74B4B4B4B",
+"} c #FAFA44444444",
+"| c #F8F850505050",
+" . c #F9F954545555",
+".. c #F9F958585858",
+"X. c #FAFA5D5D5D5D",
+"o. c #FBFB61616262",
+"O. c #FCFC66666666",
+"+. c #DCDC6A6A8C8C",
+"@. c #81818181F6F6",
+"#. c #85858585F7F7",
+"$. c #8F8F8F8FF6F6",
+"%. c #88888888F8F8",
+"&. c #8C8C8C8CF9F9",
+"*. c #8F8F8F8FFAFA",
+"=. c #93939393FBFB",
+"-. c #96969696FCFC",
+";. c #98989898FDFD",
+":. c #9B9B9B9BFDFD",
+">. c #9E9E9E9EFEFE",
+",. c #A0A0A0A0FEFE",
+"<. c #B1B1B1B1FEFE",
+"1. c #DDDDDDDDE9E9",
+"2. c #DFDFDFDFEBEB",
+"3. c #E1E1E3E3EFEF",
+"4. c #E5E5E5E5EFEF",
+"5. c #E7E7E7E7F1F1",
+"6. c #E9E9E9E9F3F3",
+"7. c #EBEBEBEBF5F5",
+"8. c #EDEDEDEDF7F7",
+"9. c #EFEFEFEFF9F9",
+"0. c #EFEFEFEFFBFB",
+"q. c #F6F6F6F6F6F6",
+"w. c gray97",
+"e. c #F1F1F1F1FDFD",
+"r. c #F3F3F3F3FDFD",
+"t. c #F5F5F5F5FDFD",
+"y. c #F5F5F5F5FFFF",
+"u. c #F8F8F8F8F8F8",
+"i. c #F9F9F9F9F9F9",
+"p. c gray98",
+"a. c #FBFBFBFBFBFB",
+"s. c gray99",
+"d. c #FDFDFDFDFDFD",
+"f. c #FDFDFDFDFEFE",
+"g. c #FEFEFEFEFEFE",
+"h. c gray100",
+"j. c None",
+/* pixels */
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"y.y.y.y.y.y.e.e.0.0.8.7.6.5.4.3.",
+"y.h.h.h.h.h.h.a.p.h.p.p.p.p.q.2.",
+"y.h.h.h.h.p.h.a.p.p.p.p.q.q.q.2.",
+"q <.,.>.;.;.-.=.*.%.%.#. at .d $.o ",
+"+ s i u t e 9 7 5 2 , : = % 4 o ",
+"+ a y t q 9 4 5 2 , : = % # 3 o ",
+"+ p r e 9 6 5 2 > : = % # @ < o ",
+"f +.' ` _ ) ( ^ ~ ! Q W h g / . ",
+"A O.[ E R T L K G F D S Z C J k ",
+"A o.X. . .| { [ ] Y U I P J J j ",
+"B N N n n n n c c x x k k j j j ",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j."
+};
diff --git a/src/images/flags/RW.xpm b/src/images/flags/RW.xpm
new file mode 100644
index 0000000..039248b
--- /dev/null
+++ b/src/images/flags/RW.xpm
@@ -0,0 +1,182 @@
+/* XPM */
+static const char *RW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 160 2",
+" c black",
+". c #000017170000",
+"X c #00001B1B0000",
+"o c #00001D1D0000",
+"O c #00001F1F0000",
+"+ c #000021210000",
+"@ c #000027270000",
+"# c #000029290000",
+"$ c #00002F2F0000",
+"% c #000035350000",
+"& c #000039390000",
+"* c #00003F3F0000",
+"= c #000043430000",
+"- c #000049490000",
+"; c #00004F4F0000",
+": c #000055550000",
+"> c #00005B5B0000",
+", c #000063630000",
+"< c #000079790000",
+"1 c #00003535E7E7",
+"2 c #00004343E7E7",
+"3 c #00004949E9E9",
+"4 c #00004949EBEB",
+"5 c #00005555EFEF",
+"6 c #00005757EFEF",
+"7 c #00005B5BF1F1",
+"8 c #00006161F3F3",
+"9 c #00006767F5F5",
+"0 c #00006B6BF7F7",
+"q c #00007171F9F9",
+"w c #00007373FBFB",
+"e c #00007777FDFD",
+"r c #00007B7BFDFD",
+"t c #00007D7DFDFD",
+"y c #1E1E99990B0B",
+"u c #23239B9B0E0E",
+"i c #27279E9E1313",
+"p c #2C2C9E9E2C2C",
+"a c #2F2F9F9F2F2F",
+"s c #2C2CA1A11919",
+"d c #3030A2A21E1E",
+"f c #3535A5A52323",
+"g c #3A3AA8A82929",
+"h c #3F3FABAB2E2E",
+"j c #3232A2A23232",
+"k c #3535A4A43535",
+"l c #3939A5A53939",
+"z c #3D3DA8A83D3D",
+"x c #4040A8A82F2F",
+"c c #4545ADAD3434",
+"v c #4A4AB0B03A3A",
+"b c #4F4FB3B33F3F",
+"n c #4242AAAA4242",
+"m c #4646ADAD4646",
+"M c #4B4BAFAF4B4B",
+"N c #5454B5B54444",
+"B c #5050B2B25050",
+"V c #5454B4B45555",
+"C c #5858B7B75858",
+"Z c #5D5DB9B95D5D",
+"A c #6161BBBB6262",
+"S c #7474C3C36666",
+"D c #03038181FDFD",
+"F c #05058383FFFF",
+"G c #07078383FFFF",
+"H c #0D0D8585FFFF",
+"J c #4D4D9F9FF2F2",
+"K c #5151A1A1F3F3",
+"L c #5050A4A4F6F6",
+"P c #5555A6A6F7F7",
+"I c #5A5AA9A9F8F8",
+"U c #5B5BAAAAF8F8",
+"Y c #5E5EACACF9F9",
+"T c #5F5FACACF9F9",
+"R c #6B6BADADE1E1",
+"E c #6161ABABF5F5",
+"W c #6262AEAEF9F9",
+"Q c #6666AFAFFAFA",
+"! c #6767B0B0FAFA",
+"~ c #6767B1B1FAFA",
+"^ c #6969B2B2FBFB",
+"/ c #6A6AB3B3FBFB",
+"( c #6B6BB3B3FBFB",
+") c #6C6CB4B4FCFC",
+"_ c #6E6EB6B6FCFC",
+"` c #6F6FB6B6FCFC",
+"' c #7A7AB6B6EDED",
+"] c #7070B6B6FDFD",
+"[ c #7272B7B7FDFD",
+"{ c #7373B7B7FDFD",
+"} c #7373B8B8FDFD",
+"| c #7676BABAFDFD",
+" . c #7676BABAFEFE",
+".. c #7E7EBCBCF7F7",
+"X. c #7979BCBCFEFE",
+"o. c #7A7ABCBCFEFE",
+"O. c #7F7FBEBEFBFB",
+"+. c #7C7CBDBDFEFE",
+"@. c #7C7CBEBEFEFE",
+"#. c #7F7FBFBFFEFE",
+"$. c #D5D5DDDD0000",
+"%. c #DFDFDFDF0000",
+"&. c #E3E3E3E30000",
+"*. c #F3F3F9F90000",
+"=. c #FBFBFBFB0000",
+"-. c #FDFDFDFD0000",
+";. c #F2F2F2F21010",
+":. c #F2F2F2F21414",
+">. c #F3F3F3F31919",
+",. c #F4F4F4F41F1F",
+"<. c #ECECF0F02424",
+"1. c #EDEDF1F12828",
+"2. c #EEEEF2F22D2D",
+"3. c #EFEFF3F33333",
+"4. c #F5F5F5F52424",
+"5. c #F6F6F6F62A2A",
+"6. c #F7F7F7F72F2F",
+"7. c #F3F3F3F33232",
+"8. c #F4F4F4F43636",
+"9. c #F1F1F4F43939",
+"0. c #F2F2F5F53E3E",
+"q. c #F8F8F8F83434",
+"w. c #F8F8F8F83535",
+"e. c #F9F9F9F93A3A",
+"r. c #FAFAFAFA3F3F",
+"t. c #CACAC2C25D5D",
+"y. c #D6D6C6C65454",
+"u. c #DFDFCACA5252",
+"i. c #C4C4C5C57979",
+"p. c #CFCFCACA7B7B",
+"a. c #E1E1C8C84848",
+"s. c #EDEDF2F24343",
+"d. c #F2F2F6F64343",
+"f. c #F3F3F7F74848",
+"g. c #F4F4F8F84E4E",
+"h. c #FAFAFAFA4040",
+"j. c #FBFBFBFB4545",
+"k. c #FBFBFBFB4949",
+"l. c #FBFBFCFC4949",
+"z. c #FCFCFCFC4F4F",
+"x. c #F5F5F9F95252",
+"c. c #F6F6FAFA5757",
+"v. c #F7F7FAFA5B5B",
+"b. c #FCFCFCFC6A6A",
+"n. c #FDFDFDFD6F6F",
+"m. c #F8F8FCFC7979",
+"M. c #8A8AB7B7CCCC",
+"N. c #8484C0C0FCFC",
+"B. c #8787C2C2FCFC",
+"V. c #8A8AC3C3FDFD",
+"C. c #8D8DC5C5FEFE",
+"Z. c #8F8FC7C7FEFE",
+"A. c #9090C7C7FEFE",
+"S. c #9191C8C8FEFE",
+"D. c #9494C8C8FEFE",
+"F. c #9494C9C9FEFE",
+"G. c #9595CACAFFFF",
+"H. c #D4D4CFCF8181",
+"J. c #D3D3D0D08787",
+"K. c None",
+/* pixels */
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"H G G G D t r e w q 0 9 8 7 5 5 ",
+"G G.G.G.Z.Z.Z.V.B.N.O...J.J.' 3 ",
+"G G. at .+.+.| { ` ( ~ T i.u.a.p.3 ",
+"G G.+.+.| { ` / ~ W U R y.t.M.2 ",
+"t Z.| { ` ) ~ Q T U P L K J E 1 ",
+"*.m.v.c.x.g.f.d.0.9.7.2.1.1.s.$.",
+"-.n.z.l.j.h.e.q.6.5.4.,.:.:.9.&.",
+"=.b.k.j.r.e.q.6.5.4.4.>.:.;.7.%.",
+"< S N b v c h g f s s i u y x $ ",
+", A Z C V B M m n z l k j a a . ",
+", > : ; - = * & % $ # @ + o X o ",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.",
+"K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K."
+};
diff --git a/src/images/flags/SA.xpm b/src/images/flags/SA.xpm
new file mode 100644
index 0000000..ff68f31
--- /dev/null
+++ b/src/images/flags/SA.xpm
@@ -0,0 +1,161 @@
+/* XPM */
+static const char *SA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 139 2",
+" c black",
+". c #000007070000",
+"X c #00000F0F0000",
+"o c #000017170000",
+"O c #00001D1D0000",
+"+ c #000023230000",
+"@ c #00002B2B0000",
+"# c #000031310000",
+"$ c #000033330000",
+"% c #000037370000",
+"& c #000039390000",
+"* c #00003B3B0000",
+"= c #00003F3F0000",
+"- c #000041410000",
+"; c #000045450000",
+": c #000047470000",
+"> c #000049490000",
+", c #00004B4B0000",
+"< c #14146E6E1313",
+"1 c #181870701717",
+"2 c #1C1C72721B1B",
+"3 c #1F1F73731E1E",
+"4 c #202075751F1F",
+"5 c #212175752020",
+"6 c #222276762121",
+"7 c #232378782323",
+"8 c #26267A7A2626",
+"9 c #29297B7B2727",
+"0 c #29297B7B2929",
+"q c #2F2F7E7E2F2F",
+"w c #353582823333",
+"e c #353580803434",
+"r c #343482823434",
+"t c #363682823636",
+"y c #373782823636",
+"u c #383884843838",
+"i c #3A3A84843A3A",
+"p c #3A3A85853A3A",
+"a c #3B3B85853A3A",
+"s c #3E3E86863D3D",
+"d c #3F3F87873E3E",
+"f c #3C3C88883C3C",
+"g c #404088883F3F",
+"h c #40408A8A3F3F",
+"j c #41418A8A4040",
+"k c #43438A8A4242",
+"l c #44448A8A4545",
+"z c #44448C8C4343",
+"x c #45458C8C4444",
+"c c #47478D8D4646",
+"v c #47478F8F4646",
+"b c #49498F8F4848",
+"n c #4A4A91914949",
+"m c #4B4B91914A4A",
+"M c #4C4C90904B4B",
+"N c #4C4C91914C4C",
+"B c #4D4D91914D4D",
+"V c #4C4C92924C4C",
+"C c #4E4E91914D4D",
+"Z c #505094944F4F",
+"A c #515194945050",
+"S c #515196965151",
+"D c #525294945151",
+"F c #535397975252",
+"G c #545496965353",
+"H c #565697975555",
+"J c #575797975656",
+"K c #565699995656",
+"L c #57579A9A5656",
+"P c #5C5C97975C5C",
+"I c #5B5B9A9A5A5A",
+"U c #5B5B9A9A5B5B",
+"Y c #5B5B9B9B5B5B",
+"T c #5B5B9D9D5B5B",
+"R c #5C5C9B9B5B5B",
+"E c #5E5E9C9C5D5D",
+"W c #5F5FA0A05E5E",
+"Q c #60609E9E5F5F",
+"! c #60609A9A6262",
+"~ c #61619E9E6060",
+"^ c #6464A0A06464",
+"/ c #6464A2A26464",
+"( c #6666A2A26565",
+") c #6666A2A26666",
+"_ c #6666A4A46666",
+"` c #6868A0A06969",
+"' c #6868A4A46868",
+"] c #6A6AA4A46A6A",
+"[ c #6D6DA6A66C6C",
+"{ c #6E6EA7A76D6D",
+"} c #7070A3A37373",
+"| c #7171A9A97070",
+" . c #7272AAAA7171",
+".. c #7575ACAC7474",
+"X. c #7676ACAC7575",
+"o. c #7878AEAE7777",
+"O. c #7878A9A97979",
+"+. c #7A7AABAB7D7D",
+"@. c #7878AEAE7878",
+"#. c #7B7BB0B07A7A",
+"$. c #7B7BB0B07B7B",
+"%. c #7F7FB2B27F7F",
+"&. c #7F7FB3B37E7E",
+"*. c #8080ADAD8181",
+"=. c #8080B3B38080",
+"-. c #8181B3B38080",
+";. c #8A8AB3B38C8C",
+":. c #8989B4B48A8A",
+">. c #8989B4B48B8B",
+",. c #8A8AB5B58C8C",
+"<. c #8C8CB4B48D8D",
+"1. c #9191B7B79393",
+"2. c #9494BDBD9595",
+"3. c #9696BBBB9898",
+"4. c #9999BDBD9999",
+"5. c #9999BDBD9A9A",
+"6. c #9999C1C19A9A",
+"7. c #A3A3C2C2A4A4",
+"8. c #A1A1C4C4A4A4",
+"9. c #A8A8C8C8A9A9",
+"0. c #AAAAC9C9ACAC",
+"q. c #ADADC9C9ADAD",
+"w. c #AEAECBCBAFAF",
+"e. c #ADADCCCCACAC",
+"r. c #AFAFCCCCB1B1",
+"t. c #B1B1CBCBB1B1",
+"y. c #B0B0CBCBB2B2",
+"u. c #B3B3CDCDB3B3",
+"i. c #B3B3CCCCB4B4",
+"p. c #B3B3CCCCB5B5",
+"a. c #B6B6CDCDB6B6",
+"s. c #B6B6CFCFB6B6",
+"d. c #B6B6CECEB8B8",
+"f. c #B7B7D0D0B7B7",
+"g. c #B6B6D0D0B8B8",
+"h. c #BBBBD0D0BBBB",
+"j. c #BCBCD4D4BFBF",
+"k. c #CECEDFDFCFCF",
+"l. c None",
+/* pixels */
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+", , , , , ; - * % # @ + O o X . ",
+", -.-.%.$.X.X. .{ ] / ~ E U H ",
+", -._ / / _ R H R J N N j w A ",
+", %.W 6.j.w.+.0.y.p.O.d.:.9 M ",
+"; $.T 2.w.g.5.p.1.;.` 7.<.7 c ",
+"- X.L 9.k.8.<.:.5.! } *.x 4 k ",
+"- ..L F G Z n x g u u 8 6 4 g ",
+"* .F n e.f.g.p.y.q.h.a.4 1 a ",
+"# { V v g f d q q 0 5.P 2 < y ",
+"@ ] ^ E R J A N b c j k u y q ",
+"+ O o o . ",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l."
+};
diff --git a/src/images/flags/SB.xpm b/src/images/flags/SB.xpm
new file mode 100644
index 0000000..fa68506
--- /dev/null
+++ b/src/images/flags/SB.xpm
@@ -0,0 +1,167 @@
+/* XPM */
+static const char *SB_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 145 2",
+" c black",
+". c #000009090000",
+"X c #0B0B67670B0B",
+"o c #0F0F6A6A0E0E",
+"O c #10106A6A1010",
+"+ c #13136C6C1313",
+"@ c #14146E6E1414",
+"# c #181870701919",
+"$ c #191970701919",
+"% c #1A1A70701A1A",
+"& c #1E1E74741E1E",
+"* c #1F1F74741F1F",
+"= c #202075752020",
+"- c #232377772323",
+"; c #252576762525",
+": c #252577772525",
+"> c #262676762626",
+", c #242478782424",
+"< c #29297B7B2929",
+"1 c #2A2A79792B2B",
+"2 c #2A2A7A7A2A2A",
+"3 c #2A2A7B7B2A2A",
+"4 c #2C2C7A7A2B2B",
+"5 c #2C2C7B7B2C2C",
+"6 c #2E2E7C7C2E2E",
+"7 c #2F2F7C7C2F2F",
+"8 c #2F2F7D7D2F2F",
+"9 c #32327F7F3232",
+"0 c #33337F7F3232",
+"q c #595935353F3F",
+"w c #434367670000",
+"e c #67676B6B0000",
+"r c #000000009F9F",
+"t c #00000000B1B1",
+"y c #00000000B3B3",
+"u c #00000000B7B7",
+"i c #00000000B9B9",
+"p c #00000000BBBB",
+"a c #00000000BDBD",
+"s c #00000000BFBF",
+"d c #00000000C3C3",
+"f c #00000000C7C7",
+"g c #03030303CDCD",
+"h c #3B3B3B3BD7D7",
+"j c #78786F6FBABA",
+"k c #45454242D3D3",
+"l c #46464444D5D5",
+"z c #47474747D7D7",
+"x c #42424141DEDE",
+"c c #42424242DCDC",
+"v c #47474747D9D9",
+"b c #46464646DDDD",
+"n c #4B4B4B4BD7D7",
+"m c #4B4B4B4BD8D8",
+"M c #49494A4ADDDD",
+"N c #4C4C4C4CD8D8",
+"B c #4F4F4F4FDADA",
+"V c #51515151D9D9",
+"C c #51515151DADA",
+"Z c #53535353DBDB",
+"A c #52525252DCDC",
+"S c #54545454DBDB",
+"D c #58585959DBDB",
+"F c #5C5C5C5CDDDD",
+"G c #46464646E0E0",
+"H c #49494949E0E0",
+"J c #5C5C5C5CE2E2",
+"K c #61616060DEDE",
+"L c #65656565DDDD",
+"P c #69696969DFDF",
+"I c #6B6B6B6BDFDF",
+"U c #6A6A6A6AE0E0",
+"Y c #6D6D6D6DE0E0",
+"T c #6F6F6F6FE0E0",
+"R c #70707171E1E1",
+"E c #70707070E2E2",
+"W c #74747474E3E3",
+"Q c #75757575E2E2",
+"! c #7B7B7B7BE5E5",
+"~ c #353582823535",
+"^ c #363682823636",
+"/ c #393984843939",
+"( c #3B3B85853B3B",
+") c #3D3D86863D3D",
+"_ c #3F3F89893F3F",
+"` c #55558F8F3636",
+"' c #42428A8A4242",
+"] c #44448B8B4444",
+"[ c #46468D8D4646",
+"{ c #49498C8C4949",
+"} c #4B4B90904B4B",
+"| c #505092925050",
+" . c #545493935555",
+".. c #70709C9C4040",
+"X. c #919157570000",
+"o. c #8E8E7E7EA6A6",
+"O. c #90907F7FA0A0",
+"+. c #9F9FADAD3F3F",
+"@. c #AFAF99990000",
+"#. c #A2A2B0B04343",
+"$. c #AAAAB5B54747",
+"%. c #BFBFBEBE4343",
+"&. c #BCBCA1A17878",
+"*. c #BEBEC5C56868",
+"=. c #C7C793930000",
+"-. c #C3C39B9B0000",
+";. c #D5D5B8B86C6C",
+":. c #D3D3C8C83A3A",
+">. c #E8E8CCCC3F3F",
+",. c #C8C8C0C04444",
+"<. c #C8C8C2C24747",
+"1. c #CFCFC7C74B4B",
+"2. c #D8D8CACA4040",
+"3. c #E4E4C7C74F4F",
+"4. c #E4E4CECE4949",
+"5. c #E8E8CCCC4747",
+"6. c #E9E9CCCC4E4E",
+"7. c #E4E4C4C45D5D",
+"8. c #E1E1D4D45D5D",
+"9. c #E3E3C4C46161",
+"0. c #E4E4C9C96F6F",
+"q. c #E3E3D2D26363",
+"w. c #AAAA98989999",
+"e. c #B7B79D9D8282",
+"r. c #A6A69797A8A8",
+"t. c #BFBFA8A88888",
+"y. c #AEAEA2A2B5B5",
+"u. c #87878787E7E7",
+"i. c #8C8C8C8CE7E7",
+"p. c #8F8F8F8FE8E8",
+"a. c #9E9E9E9EEAEA",
+"s. c #A1A1A1A1EAEA",
+"d. c #A1A1A1A1EBEB",
+"f. c #A3A3A3A3EBEB",
+"g. c #A9A9A9A9EDED",
+"h. c #B5B5B5B5F0F0",
+"j. c #C4C4ABAB8181",
+"k. c #C7C7B2B29292",
+"l. c #D2D2D2D2F5F5",
+"z. c #E3E3E3E3F8F8",
+"x. c #F7F7F7F7FBFB",
+"c. c #F7F7F7F7FCFC",
+"v. c #F7F7F7F7FDFD",
+"b. c #FAFAFAFAFDFD",
+"n. c None",
+/* pixels */
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"g u.s ! g s s s i u y y i r X.-.",
+"d.v.i.b.g.Q R I P L F J r.0.8.e ",
+"d a.l.Q F S V N z x k t.5.,.{ ",
+"f i.z.R I V m v x O.9.2.+.; ] ",
+"h v.D x.f.N b l e.5.%.1 ; & ` ",
+"d h.A d.A b o.9.2.#.2 > * $ ( ",
+"s T B M j j.6.<.` 2 - * $ @ ^ ",
+"i U H w.;.:.$.7 2 - = $ + + 0 ",
+"s y.t.3.1...7 < - * $ + o X 8 ",
+"q k.8.*. .| } [ ' ) / ^ 9 7 4 ",
+"=. at .w . ",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n."
+};
diff --git a/src/images/flags/SC.xpm b/src/images/flags/SC.xpm
new file mode 100644
index 0000000..c58b6b2
--- /dev/null
+++ b/src/images/flags/SC.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *SC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #050501012F2F",
+"X c #000021210000",
+"o c #000027270000",
+"O c #000029290000",
+"+ c #00002D2D0000",
+"@ c #00002F2F0000",
+"# c #000033330000",
+"$ c #000035350000",
+"% c #000039390000",
+"& c #00003B3B0000",
+"* c #00003D3D0000",
+"= c #000000007979",
+"- c #000041410000",
+"; c #000051510000",
+": c #000067670000",
+"> c #000000008181",
+", c #000000008383",
+"< c #000000008585",
+"1 c #000000008787",
+"2 c #000000008989",
+"3 c #000000008B8B",
+"4 c #000000009191",
+"5 c #5C5C5C5CBBBB",
+"6 c #61616161BCBC",
+"7 c #5C5C5C5CC2C2",
+"8 c #5F5F5F5FC0C0",
+"9 c #70707070C4C4",
+"0 c #72727272CACA",
+"q c #76767676C8C8",
+"w c #79797979C9C9",
+"e c #7B7B7B7BC9C9",
+"r c #7B7B7B7BCACA",
+"t c #79797979CDCD",
+"y c #000083830000",
+"u c #000095950000",
+"i c #151597971515",
+"p c #2B2B95952525",
+"a c #2C2CA1A12C2C",
+"s c #2F2FA3A32F2F",
+"d c #3232A4A43232",
+"f c #3535A4A43535",
+"g c #3939A6A63939",
+"h c #3C3CA8A83C3C",
+"j c #4242AEAE4242",
+"k c #5B5BB8B85B5B",
+"l c #7171BDBD7171",
+"z c #85854D4D0F0F",
+"x c #838357570B0B",
+"c c #E7E700000000",
+"v c #E9E900000000",
+"b c #EBEB00000000",
+"n c #EDED00000000",
+"m c #EFEF00000000",
+"M c #F1F100000000",
+"N c #F3F300000000",
+"B c #F5F500000000",
+"V c #F7F707070000",
+"C c #F5F525252525",
+"Z c #F5F526262626",
+"A c #F6F62B2B2B2B",
+"S c #F6F62C2C2C2C",
+"D c #F6F62D2D2D2D",
+"F c #F7F730303030",
+"G c #F7F731313131",
+"H c #F7F73A3A3A3A",
+"J c #F8F835353535",
+"K c #F8F836363636",
+"L c #F8F837373636",
+"P c #F8F837373737",
+"I c #F9F93A3A3A3A",
+"U c #F9F93B3B3A3A",
+"Y c #F9F93B3B3B3B",
+"T c #F9F93B3B3C3C",
+"R c #F9F93C3C3C3C",
+"E c #F9F93C3C3D3D",
+"W c #FAFA3F3F3F3F",
+"Q c #F6F644444444",
+"! c #F7F749494949",
+"~ c #F7F74E4E4E4E",
+"^ c #FAFA40404040",
+"/ c #FAFA41414141",
+"( c #FAFA41414242",
+") c #FAFA42424242",
+"_ c #F8F848484848",
+"` c #F4F452525252",
+"' c #F8F853535353",
+"] c #F9F953535757",
+"[ c #F9F957575757",
+"{ c #FAFA5C5C5C5C",
+"} c #F5F564646464",
+"| c #FBFB60606060",
+" . c #F6F675757575",
+".. c #FAFA7D7D8585",
+"X. c #FBFB85854747",
+"o. c #FBFB8B8B4747",
+"O. c #FBFB8C8C4646",
+"+. c #FBFB8F8F4646",
+"@. c #FBFB95954545",
+"#. c #FBFB97974545",
+"$. c #FAFA9F9F4444",
+"%. c #FCFC96966565",
+"&. c #FBFBB2B26767",
+"*. c #C9C9C9C90000",
+"=. c #F9F9EDED0000",
+"-. c #FBFBFBFB0000",
+";. c #FDFDFDFD0000",
+":. c #D4D4D7D76767",
+">. c #DBDBDBDB6868",
+",. c #D6D6DBDB7C7C",
+"<. c #FBFBFBFB4949",
+"1. c #FBFBFCFC4949",
+"2. c #FCFCF9F94B4B",
+"3. c #FCFCFAFA4B4B",
+"4. c #FCFCFBFB4B4B",
+"5. c #FCFCF8F84C4C",
+"6. c #FCFCFCFC4F4F",
+"7. c #FDFDFCFC5050",
+"8. c #FDFDFDFD5151",
+"9. c #FDFDFDFD5454",
+"0. c #E0E0E0E06A6A",
+"q. c #FCFCF7F76969",
+"w. c #FDFDFDFD6D6D",
+"e. c #FDFDFDFD7171",
+"r. c #FEFEFEFE7474",
+"t. c #8C8C8B8B9797",
+"y. c #919191919999",
+"u. c #97979999A8A8",
+"i. c #A9A9A9A9A9A9",
+"p. c #8383C8C88383",
+"a. c #A1A1D2D2A1A1",
+"s. c #A8A8DBDBACAC",
+"d. c #B3B3D9D9B3B3",
+"f. c #F7F78B8B8C8C",
+"g. c #F8F89B9B9F9F",
+"h. c #F5F5B2B2B2B2",
+"j. c #F4F4B7B7B7B7",
+"k. c #F9F9B7B7B7B7",
+"l. c #CFCFE6E6CFCF",
+"z. c #CBCBEEEED3D3",
+"x. c #D3D3E4E4D3D3",
+"c. c #E7E7CFCFCFCF",
+"v. c #F5F5C2C2C2C2",
+"b. c #F6F6D6D6D7D7",
+"n. c #EBEBE7E7DFDF",
+"m. c gray89",
+"M. c gray90",
+"N. c #EEEEF0F0EEEE",
+"B. c #ECECF5F5F3F3",
+"V. c #F7F7E6E6EDED",
+"C. c #F3F3F0F0F1F1",
+"Z. c gray95",
+"A. c #F3F3F3F3F3F3",
+"S. c #F4F4F4F4F4F4",
+"D. c #F4F4F5F5F5F5",
+"F. c gray96",
+"G. c #F6F6F6F6F6F6",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"4 3 3 3 > *.;.;.-.=.V B B m m m ",
+"< r r t i.r.e.w.q.%.| { [ ' ~ m ",
+"3 r 8 5 0.9.8.5.X.) E K G S ! c ",
+"< r 7 y.9.8.4.O.) E K G A Z Q c ",
+"< q 5 >.8.4.O.^ T K F A Z ` h.c.",
+"> 0 t.6.5. at .) U K G S } j.A.S.M.",
+"> 9 :.4. at .E U K H .v.D.A.Z.A.m.",
+"< u.4.#.E U _ f.b.D.D.Z.N.x.d.y ",
+"= ,.$.^ ] g.V.G.B.l.a.l h i s X ",
+". &...k.n.z.s.p.k j g f d s s o ",
+"z x p u : ; - * % * % # + + O # ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/SD.xpm b/src/images/flags/SD.xpm
new file mode 100644
index 0000000..64a9f04
--- /dev/null
+++ b/src/images/flags/SD.xpm
@@ -0,0 +1,159 @@
+/* XPM */
+static const char *SD_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 137 2",
+" c black",
+". c #0B0B0B0B0B0B",
+"X c #0F0F0F0F0E0E",
+"o c #131313131313",
+"O c #181819191919",
+"+ c #1E1E1E1E1E1E",
+"@ c #00003D3D0000",
+"# c #232323232323",
+"$ c gray16",
+"% c #2C2C2C2C2C2C",
+"& c gray18",
+"* c #2F2F2F2F2F2F",
+"= c #323232323232",
+"- c #343434343434",
+"; c #353535353535",
+": c #393939393939",
+"> c #3A3A3A3A3A3A",
+", c gray24",
+"< c #19195F5F0000",
+"1 c #00006D6D0000",
+"2 c #000079790000",
+"3 c #00007B7B0000",
+"4 c #00007F7F0000",
+"5 c #3F3F46463F3F",
+"6 c gray26",
+"7 c #464646464646",
+"8 c #4B4B4B4B4B4B",
+"9 c #505050505050",
+"0 c #545454545555",
+"q c #585858585858",
+"w c #5D5D61615D5D",
+"e c #000083830000",
+"r c #000087870000",
+"t c #00008B8B0000",
+"y c #00008F8F0000",
+"u c #53539F9F5353",
+"i c #4949B5B54949",
+"p c #4949B6B64949",
+"a c #4B4BB4B44B4B",
+"s c #4F4FB7B74F4F",
+"d c #5454A1A15454",
+"f c #5C5CA9A95C5C",
+"g c #5353B9B95353",
+"h c #5454BCBC5454",
+"j c #5858BCBC5858",
+"k c #6E6EACAC6F6F",
+"l c #6262B1B16262",
+"z c #6868B0B06868",
+"x c #7070AFAF6B6B",
+"c c #7878B2B27171",
+"v c #5C5CC2C25C5C",
+"b c #6666C2C26666",
+"n c #6A6AC3C36A6A",
+"m c #6F6FC4C46F6F",
+"M c #7272C6C67373",
+"N c #7676C8C87676",
+"B c #7979C9C97979",
+"V c #7B7BCFCF7A7A",
+"C c #E9E900000000",
+"Z c #EBEB00000000",
+"A c #EDED00000000",
+"S c #EFEF00000000",
+"D c #F1F100000000",
+"F c #F3F300000000",
+"G c #F5F500000000",
+"H c #F7F700000000",
+"J c #F9F900000000",
+"K c #FBFB00000000",
+"L c #FDFD00000000",
+"P c red",
+"I c #F6F62C2C2C2C",
+"U c #F7F731313131",
+"Y c #F8F837373737",
+"T c #F9F93C3C3D3D",
+"R c #F7F749494949",
+"E c #F7F74E4E4E4E",
+"W c #FAFA42424242",
+"Q c #FBFB47474747",
+"! c #FCFC4C4C4C4C",
+"~ c #F8F853535353",
+"^ c #F9F957575757",
+"/ c #FDFD51515151",
+"( c #FDFD54545454",
+") c #FAFA5C5C5C5C",
+"_ c #FEFE59595959",
+"` c #FCFC5E5E5C5C",
+"' c #FBFB60606060",
+"] c #FCFC65656565",
+"[ c #FCFC69696969",
+"{ c #FDFD6D6D6D6D",
+"} c #FDFD70707171",
+"| c #FEFE74747474",
+" . c #FEFE77777777",
+".. c #FEFE79797979",
+"X. c #FCFC7D7D7B7B",
+"o. c #9090BFBF8A8A",
+"O. c gray74",
+"+. c #CBCBCBCBCBCB",
+"@. c #CDCDCDCDCDCD",
+"#. c gray81",
+"$. c #DEDEF2F2DEDE",
+"%. c #E7E7C7C7C7C7",
+"&. c gray88",
+"*. c #E1E1E1E1E1E1",
+"=. c #E2E2E2E2E2E2",
+"-. c gray89",
+";. c #E4E4E4E4E4E4",
+":. c #E6E6E6E6E6E6",
+">. c #E7E7E7E7E7E7",
+",. c #E9E9E9E9E9E9",
+"<. c #E9E9EBEBE9E9",
+"1. c gray92",
+"2. c #E0E0F4F4E4E4",
+"3. c #F5F5E5E5E5E5",
+"4. c #F6F6E6E6E6E6",
+"5. c #F7F7E8E8E7E7",
+"6. c #F6F6E8E8E8E8",
+"7. c #F8F8E9E9E8E8",
+"8. c #F9F9EAEAEAEA",
+"9. c #FAFAEBEBEBEB",
+"0. c #FBFBECECECEC",
+"q. c #FBFBEFEFEEEE",
+"w. c #FCFCEDEDEDED",
+"e. c #FDFDEEEEEFEF",
+"r. c gray95",
+"t. c #F3F3F3F3F3F3",
+"y. c #F4F4F4F4F4F4",
+"u. c #F4F4F5F5F5F5",
+"i. c gray96",
+"p. c #F6F6F6F6F6F6",
+"a. c gray97",
+"s. c #F8F8F8F8F8F8",
+"d. c #F9F9F9F9F9F9",
+"f. c #F8F8FAFAF9F9",
+"g. c gray98",
+"h. c #FBFBFBFBFBFB",
+"j. c None",
+/* pixels */
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"< P P P K P P P K K H H F F A A ",
+"y o.X... . .} { [ ] ' ` ^ ~ E Z ",
+"t V c ` _ / ! ! Q W T Y U I R Z ",
+"r B v x q.e.e.q.6.e.6.6.3.3.6.%.",
+"r N j h z 2.g.g.g.s.a.a.u.u.u.#.",
+"e M g s i f g.g.a.a.a.u.y.y.y.+.",
+"4 m s i l $.g.g.a.u.u.y.y.r.y.+.",
+"3 n i d ,.,.1.:.:.;.-.-.&.&.-.O.",
+"3 b u 5 > ; % $ # + O o X . * ",
+"1 k w q 0 9 8 7 6 , > ; = * % ",
+"@ ",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j."
+};
diff --git a/src/images/flags/SE.xpm b/src/images/flags/SE.xpm
new file mode 100644
index 0000000..44d8b2e
--- /dev/null
+++ b/src/images/flags/SE.xpm
@@ -0,0 +1,167 @@
+/* XPM */
+static const char *SE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 145 2",
+" c black",
+". c #000000001F1F",
+"X c #000000002121",
+"o c #000000002525",
+"O c #000000002727",
+"+ c #000000002D2D",
+"@ c #000000003333",
+"# c #000000003939",
+"$ c #000000003B3B",
+"% c #000000003D3D",
+"& c #000000004141",
+"* c #000000004747",
+"= c #000000004D4D",
+"- c #000005055353",
+"; c #00000D0D5959",
+": c #000013135D5D",
+"> c #000019196363",
+", c #000021216969",
+"< c #000027276D6D",
+"1 c #000027276F6F",
+"2 c #00002D2D7373",
+"3 c #00002F2F7373",
+"4 c #000033337575",
+"5 c #000041417F7F",
+"6 c #000043438181",
+"7 c #0B0B67679595",
+"8 c #0F0F6A6A9797",
+"9 c #101065659D9D",
+"0 c #13136C6C9999",
+"q c #181870709C9C",
+"w c #1E1E74749F9F",
+"e c #14146969A0A0",
+"r c #19196C6CA2A2",
+"t c #1F1F7070A4A4",
+"y c #23237777A1A1",
+"u c #24247878A2A2",
+"i c #26267A7AA2A2",
+"p c #29297B7BA4A4",
+"a c #2A2A7B7BA4A4",
+"s c #2B2B7C7CA5A5",
+"d c #2C2C7B7BA2A2",
+"f c #2C2C7C7CA6A6",
+"g c #2F2F7C7CA4A4",
+"h c #2F2F7D7DA4A4",
+"j c #2F2F7F7FA8A8",
+"k c #32327F7FA6A6",
+"l c #33337B7BABAB",
+"z c #31318080A8A8",
+"x c #31318181A9A9",
+"c c #35358282A8A8",
+"v c #37378484ABAB",
+"b c #39398484A9A9",
+"n c #3D3D8686ACAC",
+"m c #3C3C8888AEAE",
+"M c #3D3D8888AEAE",
+"N c #3F3F8A8AAFAF",
+"B c #42428A8AAEAE",
+"V c #44448C8CAFAF",
+"C c #42428B8BB0B0",
+"Z c #42428B8BB1B1",
+"A c #44448E8EB1B1",
+"S c #45458E8EB2B2",
+"D c #46468D8DB0B0",
+"F c #47478F8FB4B4",
+"G c #49498F8FB1B1",
+"H c #49499191B4B4",
+"J c #4C4C9292B6B6",
+"K c #4E4E9393B4B4",
+"L c #50509393AEAE",
+"P c #53539696B7B7",
+"I c #58589898B9B9",
+"U c #58589999B9B9",
+"Y c #5C5C9B9BBBBB",
+"T c #5D5D9D9DBCBC",
+"R c #5C5C9D9DBEBE",
+"E c #5F5F9F9FBFBF",
+"W c #61619E9EBEBE",
+"Q c #61619F9FBEBE",
+"! c #58589696C3C3",
+"~ c #6565A1A1C0C0",
+"^ c #6666A3A3C0C0",
+"/ c #6969A4A4C2C2",
+"( c #6A6AA5A5C3C3",
+") c #6D6DA7A7C3C3",
+"_ c #7979AEAEC9C9",
+"` c #7B7BB0B0C9C9",
+"' c #7B7BB0B0CACA",
+"] c #E3E387870000",
+"[ c #E5E58B8B0000",
+"{ c #E7E78F8F0000",
+"} c #EBEB99990000",
+"| c #EDED9D9D0000",
+" . c #EDEDA1A10000",
+".. c #FDFDBBBB0000",
+"X. c #FDFDBDBD0000",
+"o. c #FDFDBFBF0000",
+"O. c #FDFDC1C10000",
+"+. c #F2F2C7C71414",
+"@. c #F3F3C9C91919",
+"#. c #F3F3C9C91A1A",
+"$. c #F4F4CACA1F1F",
+"%. c #F4F4CBCB1F1F",
+"&. c #F4F4CBCB2020",
+"*. c #F5F5CCCC2424",
+"=. c #F5F5CCCC2525",
+"-. c #F6F6CECE2A2A",
+";. c #F6F6CECE2B2B",
+":. c #F4F4CECE3636",
+">. c #F7F7D0D02E2E",
+",. c #F7F7D0D02F2F",
+"<. c #F7F7D0D03030",
+"1. c #F4F4D0D03B3B",
+"2. c #F5F5D2D23F3F",
+"3. c #F8F8D2D23434",
+"4. c #F8F8D2D23535",
+"5. c #F8F8D2D23636",
+"6. c #F9F9D3D33A3A",
+"7. c #F9F9D4D43A3A",
+"8. c #F9F9D4D43B3B",
+"9. c #F9F9D4D43C3C",
+"0. c #FAFAD5D53F3F",
+"q. c #F7F7D6D64B4B",
+"w. c #FAFAD5D54040",
+"e. c #FAFAD6D64040",
+"r. c #FAFAD6D64141",
+"t. c #FBFBD7D74545",
+"y. c #FBFBD7D74646",
+"u. c #FBFBD9D94949",
+"i. c #FCFCD9D94B4B",
+"p. c #FCFCDADA4F4F",
+"a. c #F8F8D8D85050",
+"s. c #F9F9D9D95555",
+"d. c #FDFDDBDB5050",
+"f. c #FDFDDBDB5151",
+"g. c #FDFDDCDC5353",
+"h. c #FDFDDCDC5454",
+"j. c #FEFEDDDD5858",
+"k. c #FEFEDDDD5959",
+"l. c #FDFDE1E16F6F",
+"z. c #FDFDE2E27171",
+"x. c #FEFEE2E27373",
+"c. c #FEFEE2E27474",
+"v. c #FEFEE3E37676",
+"b. c #FEFEE4E47777",
+"n. c None",
+/* pixels */
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"6 6 6 6 O.O.O.4 2 < , > : ; - = ",
+"6 ' ' ` b.v.x.) ( ~ W Y U P K * ",
+"6 ' ! R j.g.p.K F Z n v x f G & ",
+"5 _ R ! h.g.i.L Z n v x s i V $ ",
+"O.v.h.h.p.i.t.r.9.5.<.;.=.&.2.{ ",
+"o.x.p.p.i.t.r.9.5.<.;.=.%. at .1.[ ",
+"o.x.p.i.t.r.7.5.,.;.=.%. at .+.:.] ",
+"2 ( H S 9.7.5.h s u t r e 9 l $ ",
+"1 ~ V N 7.5.,.s y w q 0 8 7 f X ",
+", Q R U s.a.q.V B n v v k k d . ",
+"> : ; - .| } $ # @ + o o X . . ",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n."
+};
diff --git a/src/images/flags/SG.xpm b/src/images/flags/SG.xpm
new file mode 100644
index 0000000..e42640f
--- /dev/null
+++ b/src/images/flags/SG.xpm
@@ -0,0 +1,144 @@
+/* XPM */
+static const char *SG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 122 2",
+" c black",
+". c #C3C300000000",
+"X c #C7C700000000",
+"o c #C9C900000000",
+"O c #CBCB00000000",
+"+ c #CFCF00000000",
+"@ c #D3D300000000",
+"# c #D7D700000000",
+"$ c #D9D900000000",
+"% c #DBDB00000000",
+"& c #DDDD00000000",
+"* c #DFDF00000000",
+"= c #E1E100000000",
+"- c #E3E300000000",
+"; c #E5E500000000",
+": c #E7E700000000",
+"> c #E9E900000000",
+", c #EBEB03030303",
+"< c #EBEB09090909",
+"1 c #E3E320202020",
+"2 c #E5E525252525",
+"3 c #E6E626262626",
+"4 c #E6E62B2B2B2B",
+"5 c #E7E72B2B2B2B",
+"6 c #E7E72C2C2C2C",
+"7 c #E7E730303030",
+"8 c #E4E43C3C3D3D",
+"9 c #E7E73F3F3F3F",
+"0 c #E8E831313131",
+"q c #E8E836363636",
+"w c #E9E937373636",
+"e c #EAEA37373737",
+"r c #EAEA3B3B3C3C",
+"t c #EAEA3C3C3C3C",
+"y c #EBEB3C3C3D3D",
+"u c #E6E641414141",
+"i c #E7E745454545",
+"p c #EBEB41414141",
+"a c #E8E844444444",
+"s c #ECEC41414242",
+"d c #ECEC42424242",
+"f c #ECEC46464646",
+"g c #EDED47474747",
+"h c #E9E94A4A4A4A",
+"j c #EAEA49494949",
+"k c #EAEA4F4F4F4F",
+"l c #EBEB4E4E4E4E",
+"z c #EBEB54545454",
+"x c #ECEC53535353",
+"c c #EFEF53535353",
+"v c #EDED57575757",
+"b c #E8E858585858",
+"n c #ECEC59595959",
+"m c #EEEE5C5C5C5C",
+"M c #EEEE5D5D5D5D",
+"N c #F1F159595959",
+"B c #F0F059595A5A",
+"V c #F0F05A5A5A5A",
+"C c #EFEF61616161",
+"Z c #F0F060606060",
+"A c #F0F065656565",
+"S c #F0F065656666",
+"D c #F1F169696969",
+"F c #F2F26D6D6D6D",
+"G c #F1F172727373",
+"H c #F2F272727272",
+"J c #F4F472727272",
+"K c #F2F278787878",
+"L c #F5F587878787",
+"P c #F3F388888989",
+"I c #F6F689898989",
+"U c #F6F6A2A2A2A2",
+"Y c #F6F6A5A5A5A5",
+"T c #F8F8B3B3B3B3",
+"R c #F8F8B4B4B4B4",
+"E c #F8F8B6B6B6B6",
+"W c #F8F8BABABABA",
+"Q c #F9F9BDBDBDBD",
+"! c #DBDBCFCFCFCF",
+"~ c #DDDDCFCFCFCF",
+"^ c #DDDDD1D1D1D1",
+"/ c #DDDDD3D3D3D3",
+"( c #E1E1D3D3D3D3",
+") c #E1E1D5D5D5D5",
+"_ c #E3E3D7D7D7D7",
+"` c #E5E5D9D9D9D9",
+"' c #E7E7DBDBDBDB",
+"] c #E9E9DDDDDDDD",
+"[ c #EBEBDFDFDFDF",
+"{ c #F7F7C9C9C9C9",
+"} c #FBFBCACACACA",
+"| c #F8F8CDCDCDCD",
+" . c #FCFCDCDCDCDC",
+".. c #EDEDE3E3E1E1",
+"X. c #EFEFE5E5E5E5",
+"o. c #F1F1E7E7E7E7",
+"O. c #F3F3E9E9E9E9",
+"+. c #F5F5EBEBEBEB",
+"@. c #F5F5EDEDEDED",
+"#. c #F7F7EFEFEFEF",
+"$. c #FCFCEEEEEEEE",
+"%. c #F1F1F1F1F1F1",
+"&. c gray95",
+"*. c #F2F2F2F2F3F3",
+"=. c #F3F3F3F3F3F3",
+"-. c #F4F4F4F4F4F4",
+";. c gray96",
+":. c #F6F6F6F6F6F6",
+">. c gray97",
+",. c #F9F9F1F1F1F1",
+"<. c #FBFBF1F1F1F1",
+"1. c #FDFDF2F2F2F2",
+"2. c #FEFEF5F5F5F5",
+"3. c #FEFEF6F6F6F6",
+"4. c #F8F8F8F8F8F8",
+"5. c #F9F9F9F9F9F9",
+"6. c gray98",
+"7. c #FBFBFBFBFBFB",
+"8. c #FBFBFCFCFBFB",
+"9. c gray99",
+"0. c #FDFDFDFDFDFD",
+"q. c None",
+/* pixels */
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+", : < , : : - : - & & % % # @ @ ",
+": } 2.E I E Y F D S C M v z l + ",
+": 2.Q J W n K P g s y e 7 6 j O ",
+": <. .n J | } g s t w 7 4 3 i O ",
+": T $.U n c g s t w 6 4 3 1 9 . ",
+", L G G S C M n z l j i u 8 b . ",
+"<.9.9.7.7.5.5.5.>.:.:.-.=.*.:.( ",
+"<.7.7.7.5.5.5.:.:.:.-.=.*.*.*./ ",
+"#.7.7.5.5.5.>.:.:.-.*.*.%.%.*.~ ",
+"@.7.5.5.5.5.:.>.:.:.:.=.*.*.*.! ",
+"+.O.o.o...[ ] ' ` _ / ( ~ ~ ! ! ",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.",
+"q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q."
+};
diff --git a/src/images/flags/SH.xpm b/src/images/flags/SH.xpm
new file mode 100644
index 0000000..31b1cf5
--- /dev/null
+++ b/src/images/flags/SH.xpm
@@ -0,0 +1,187 @@
+/* XPM */
+static const char *SH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 165 2",
+" c black",
+". c #000000002B2B",
+"X c #000000002F2F",
+"o c #000000003333",
+"O c #000000003535",
+"+ c #000000003939",
+"@ c #000000003B3B",
+"# c #000000003F3F",
+"$ c #000000004141",
+"% c #000000004545",
+"& c #000000004747",
+"* c #000000004B4B",
+"= c #000000004D4D",
+"- c #000000005151",
+"; c #000000005353",
+": c #000000005757",
+"> c #000000005B5B",
+", c #000000006161",
+"< c #000000006565",
+"1 c #000000006767",
+"2 c #000000006D6D",
+"3 c #000000006F6F",
+"4 c #000000007373",
+"5 c #000000007575",
+"6 c #000000007979",
+"7 c #000000007B7B",
+"8 c #000000007F7F",
+"9 c #000000008383",
+"0 c #000000008585",
+"q c #13132E2E9797",
+"w c #171732329E9E",
+"e c #1B1B3636A1A1",
+"r c #20203A3A9F9F",
+"t c #25253E3EA1A1",
+"y c #2A2A4343A3A3",
+"u c #2B2B4444A4A4",
+"i c #30304848A6A6",
+"p c #30304949A6A6",
+"a c #33334A4AA4A4",
+"s c #35354C4CA6A6",
+"d c #36364D4DA6A6",
+"f c #31314949A9A9",
+"g c #32324A4AA9A9",
+"h c #31314B4BAFAF",
+"j c #35354B4BADAD",
+"k c #35354D4DA9A9",
+"l c #36364D4DA9A9",
+"z c #36364E4EA9A9",
+"x c #35354F4FADAD",
+"c c #35354E4EAFAF",
+"v c #38384F4FA8A8",
+"b c #37374E4EB1B1",
+"n c #39395050A8A8",
+"m c #3B3B5252ACAC",
+"M c #3D3D5151AAAA",
+"N c #3C3C5252A9A9",
+"B c #3D3D5353A9A9",
+"V c #3C3C5353ADAD",
+"C c #3D3D5353ACAC",
+"Z c #3F3F5656ADAD",
+"A c #3F3F5656B1B1",
+"S c #3D3D5555B4B4",
+"D c #42425757ABAB",
+"F c #40405656ACAC",
+"G c #40405757AEAE",
+"H c #41415757AFAF",
+"J c #43435959AEAE",
+"K c #47475D5DAFAF",
+"L c #4B4B5757AFAF",
+"P c #42425858B1B1",
+"I c #42425959B1B1",
+"U c #45455C5CB1B1",
+"Y c #46465C5CB1B1",
+"T c #45455F5FB6B6",
+"R c #46465E5EB4B4",
+"E c #47475E5EB4B4",
+"W c #48485D5DB2B2",
+"Q c #4B4B6060B4B4",
+"! c #4B4B6262B4B4",
+"~ c #4C4C6161B2B2",
+"^ c #4F4F6262B5B5",
+"/ c #49496363B9B9",
+"( c #51516161B3B3",
+") c #50506565B3B3",
+"_ c #50506565B4B4",
+"` c #50506565B7B7",
+"' c #55556969B6B6",
+"] c #55556969B7B7",
+"[ c #55556969B8B8",
+"{ c #59596D6DB9B9",
+"} c #5A5A6D6DB9B9",
+"| c #5C5C6F6FBCBC",
+" . c #5F5F7171BBBB",
+".. c #60607373BEBE",
+"X. c #63637575BEBE",
+"o. c #65657979BFBF",
+"O. c #7D7D7777B5B5",
+"+. c #67677A7AC0C0",
+"@. c #6A6A7C7CC2C2",
+"#. c #6A6A7D7DC5C5",
+"$. c #6C6C7D7DC2C2",
+"%. c #6D6D7F7FC3C3",
+"&. c #5C5C93933A3A",
+"*. c #60608F8F3A3A",
+"=. c #5C5C91914343",
+"-. c #656591916565",
+";. c #70708181C4C4",
+":. c #71718484C7C7",
+">. c #7B7B8585C3C3",
+",. c #A1A105052F2F",
+"<. c #8E8E78786868",
+"1. c #93937C7C6F6F",
+"2. c #C1C100001515",
+"3. c #C9C905051F1F",
+"4. c #C1C117173333",
+"5. c #E1E107071515",
+"6. c #FFFF07070303",
+"7. c #E5E52D2D3939",
+"8. c #E8E861616A6A",
+"9. c #ECEC75757B7B",
+"0. c #FCFC66666666",
+"q. c #FEFE67676565",
+"w. c #FEFE69696868",
+"e. c #FCFC6D6D6D6D",
+"r. c #FBFB70706F6F",
+"t. c #FDFD71716F6F",
+"y. c #F0F07B7B7F7F",
+"u. c #FEFE79797575",
+"i. c #FEFE7D7D7C7C",
+"p. c #B8B864648282",
+"a. c #BABA64648282",
+"s. c #C2C26B6B8585",
+"d. c #C8C86A6A8080",
+"f. c #E0E075758282",
+"g. c #9E9E83836161",
+"h. c #BABAA2A24A4A",
+"j. c #BFBFAAAA5252",
+"k. c #CCCCADAD3737",
+"l. c #D1D1B1B13A3A",
+"z. c #D3D3B4B43E3E",
+"x. c #C2C2ACAC5757",
+"c. c #CFCFB1B14040",
+"v. c #D2D2B4B44444",
+"b. c #8F8F8A8ABDBD",
+"n. c #84849797C6C6",
+"m. c #8C8C9D9DC8C8",
+"M. c #8B8B9D9DD3D3",
+"N. c #9A9AA6A6D4D4",
+"B. c #A0A0ADADD9D9",
+"V. c #ADADB9B9DEDE",
+"C. c #B2B2BCBCDFDF",
+"Z. c #B9B9C1C1E2E2",
+"A. c #EBEB86868C8C",
+"S. c #FDFD86868484",
+"D. c #FEFE8B8B8B8B",
+"F. c #F1F194949999",
+"G. c #F7F799999B9B",
+"H. c #F0F0A4A4AAAA",
+"J. c #F8F8A0A0A3A3",
+"K. c #F9F9A9A9ABAB",
+"L. c #F2F2AEAEB3B3",
+"P. c #CDCDC9C9E2E2",
+"I. c #CCCCD4D4E4E4",
+"U. c #CDCDD2D2E9E9",
+"Y. c None",
+/* pixels */
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"7.>.h 5.2.b O.4.0 6 5 3 3 < , < ",
+"L K.U.G.F.P.L.N.%. at .+. . .{ ] ; ",
+"6.D.u.w.q.t.q.8.^ T I D B g ^ ; ",
+"3.J.i.e.r.S.9.d.W S x.v.c.h.Q * ",
+"( H.C.y.f.V.A.b.A b j.z.l.k.I $ ",
+",.Z.M.s.p.#.N.p.B b g.m.I.n.D # ",
+"0 :.{ / T R C x k g 1.1.&.-.C + ",
+"9 ;.` W R G m k i y ! *.=.Z n O ",
+"6 $.E U G B k a y t w e w q d o ",
+"4 o.X...{ ] _ ~ W J C B n d a . ",
+"6 3 1 > > : ; * % $ # + O o X + ",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.",
+"Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y."
+};
diff --git a/src/images/flags/SI.xpm b/src/images/flags/SI.xpm
new file mode 100644
index 0000000..9282c0f
--- /dev/null
+++ b/src/images/flags/SI.xpm
@@ -0,0 +1,173 @@
+/* XPM */
+static const char *SI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 151 2",
+" c black",
+". c #3F3F00000000",
+"X c #000000008181",
+"o c #000000008383",
+"O c #000000008585",
+"+ c #000000009797",
+"@ c #00000000B5B5",
+"# c #00000000B7B7",
+"$ c #00000000B9B9",
+"% c #03031111C3C3",
+"& c #14142626C3C3",
+"* c #1A1A2828C1C1",
+"= c #19192B2BC6C6",
+"- c #1F1F2E2EC3C3",
+"; c #1F1F3030C7C7",
+": c #20202C2CC1C1",
+"> c #25253131C4C4",
+", c #25253333C5C5",
+"< c #24243535CACA",
+"1 c #2B2B3737C6C6",
+"2 c #2A2A3838C7C7",
+"3 c #2A2A3A3ACBCB",
+"4 c #30303C3CC8C8",
+"5 c #30303D3DC9C9",
+"6 c #2F2F4040CDCD",
+"7 c #36364141CACA",
+"8 c #36364343CBCB",
+"9 c #36364545CBCB",
+"0 c #35354444CFCF",
+"q c #3B3B4747C9C9",
+"w c #3B3B4747CCCC",
+"e c #3B3B4848CDCD",
+"r c #3F3F4A4AC9C9",
+"t c #3B3B4949D0D0",
+"y c #41414C4CCECE",
+"u c #40404E4ECFCF",
+"i c #40404E4ED2D2",
+"p c #45454F4FD3D3",
+"a c #46464F4FD0D0",
+"s c #4B4B5050CDCD",
+"d c #4F4F5858CECE",
+"f c #46465050D0D0",
+"g c #49495454D5D5",
+"h c #4F4F5C5CD7D7",
+"j c #53535C5CD0D0",
+"k c #58586161D2D2",
+"l c #5D5D6565D4D4",
+"z c #61616969D6D6",
+"x c #66666D6DD7D7",
+"c c #67676F6FD5D5",
+"v c #6A6A7272D9D9",
+"b c #6E6E7676DBDB",
+"n c #6F6F7A7ADFDF",
+"m c #78787A7ACECE",
+"M c #70707777DBDB",
+"N c #75757C7CD1D1",
+"B c #72727C7CDDDD",
+"V c #76767D7DDDDD",
+"C c #7C7C8383DEDE",
+"Z c #858500001515",
+"A c #9E9E16165050",
+"S c #A1A11B1B5353",
+"D c #A3A31F1F5757",
+"F c #A5A525255B5B",
+"G c #A8A829295F5F",
+"H c #ABAB2F2F6363",
+"J c #ACAC37376969",
+"K c #AEAE34346868",
+"L c #B0B039396C6C",
+"P c #B3B33F3F7070",
+"I c #B5B544447474",
+"U c #B8B84A4A7878",
+"Y c #BABA4E4E7C7C",
+"T c #DDDD00000000",
+"R c #DFDF00000000",
+"E c #E1E100000000",
+"W c #E3E300000000",
+"Q c #E5E500000000",
+"! c #E7E700000000",
+"~ c #E9E900000000",
+"^ c #EBEB00000000",
+"/ c #EDED00000000",
+"( c #EFEF00000000",
+") c #F1F100000000",
+"_ c #F3F300000000",
+"` c #F5F500000000",
+"' c #F7F700000000",
+"] c #F1F10B0B0B0B",
+"[ c #F1F10F0F0E0E",
+"{ c #F9F900000000",
+"} c #F2F213131313",
+"| c #F3F319191919",
+" . c #F4F41E1E1E1E",
+".. c #F5F523232323",
+"X. c #F2F22C2C2C2C",
+"o. c #F2F22F2F2F2F",
+"O. c #F6F629292929",
+"+. c #F7F72E2E2E2E",
+"@. c #F2F232323232",
+"#. c #F3F335353535",
+"$. c #F4F439393939",
+"%. c #F5F53D3D3D3D",
+"&. c #F8F834343434",
+"*. c #F9F93A3A3A3A",
+"=. c #FAFA3F3F3F3F",
+"-. c #F6F642424242",
+";. c #F7F746464646",
+":. c #F7F74B4B4B4B",
+">. c #FAFA44444444",
+",. c #F8F850505050",
+"<. c #F9F954545555",
+"1. c #F9F958585858",
+"2. c #FAFA5D5D5D5D",
+"3. c #FBFB61616262",
+"4. c #FCFC66666666",
+"5. c #96965959A3A3",
+"6. c #A6A65F5F9A9A",
+"7. c #AAAA64649D9D",
+"8. c #C8C86F6F9494",
+"9. c #86868C8CE1E1",
+"0. c #8D8D9292E2E2",
+"q. c #93939999E5E5",
+"w. c #F3F3AFAFB5B5",
+"e. c #F4F4B2B2B9B9",
+"r. c #E1E1E3E3E3E3",
+"t. c gray90",
+"y. c #E7E7E7E7E7E7",
+"u. c #E9E9E9E9E9E9",
+"i. c gray92",
+"p. c gray93",
+"a. c #EFEFEFEFEFEF",
+"s. c #E0E0E0E0F4F4",
+"d. c #F1F1EEEEF6F6",
+"f. c #F1F1F1F1F1F1",
+"g. c #F3F3F3F3F3F3",
+"h. c gray96",
+"j. c #F6F6F6F6F6F6",
+"k. c gray97",
+"l. c #F6F6F7F7FBFB",
+"z. c #F6F6F6F6FCFC",
+"x. c #F8F8F8F8F8F8",
+"c. c #F9F9F9F9F9F9",
+"v. c gray98",
+"b. c #FBFBFBFBFBFB",
+"n. c #FDFDFBFBFBFB",
+"m. c gray99",
+"M. c #FDFDFDFDFDFD",
+"N. c #FDFDFDFDFEFE",
+"B. c #FEFEFEFEFFFF",
+"V. c gray100",
+"C. c None",
+/* pixels */
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"h.h.h.h.h.g.g.d.a.a.p.i.u.y.t.r.",
+"h.V.V.z.l.V.V.b.b.V.b.c.c.c.k.i.",
+"h.V.0.N m v.b.V.c.c.c.c.k.h.k.u.",
+"% q.9.s.C M b v x z l k j d c + ",
+"# V e.d.w.s a y w 8 4 1 > : r o ",
+"# B 5.7.7.f u e 8 4 2 > - * q o ",
+"$ n j g i i t 0 6 3 < ; = & 9 O ",
+"Z 8.Y U I L L K H G F D S A J . ",
+"{ 4.>.>.*.&.+.O... .| } [ ] o.R ",
+"{ 3.2.1.<.,.:.;.-.%.$.#. at .o.X.T ",
+"` _ _ / / / / ! ! Q Q R R T T T ",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.",
+"C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C."
+};
diff --git a/src/images/flags/SJ.xpm b/src/images/flags/SJ.xpm
new file mode 100644
index 0000000..05220e8
--- /dev/null
+++ b/src/images/flags/SJ.xpm
@@ -0,0 +1,149 @@
+/* XPM */
+static const char *SJ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 127 2",
+" c black",
+". c #00000000A5A5",
+"X c #00001D1DB7B7",
+"o c #03035353CFCF",
+"O c #09095959D1D1",
+"+ c #4B4B8383D5D5",
+"@ c #50508686D7D7",
+"# c #54548A8AD8D8",
+"$ c #59598D8DD9D9",
+"% c #5D5D9090DBDB",
+"& c #62629494DDDD",
+"* c #65659494DADA",
+"= c #65659696DEDE",
+"- c #66669797DEDE",
+"; c #6A6A9999E0E0",
+": c #6B6B9A9AE0E0",
+"> c #6F6F9C9CE1E1",
+", c #6F6F9D9DE1E1",
+"< c #73739F9FE3E3",
+"1 c #7777A3A3E4E4",
+"2 c #7A7AA4A4E2E2",
+"3 c #7A7AA5A5E5E5",
+"4 c #7B7BA6A6E5E5",
+"5 c #7E7EA8A8E7E7",
+"6 c #B1B100000000",
+"7 c #B5B500000000",
+"8 c #B9B900000000",
+"9 c #BBBB00000000",
+"0 c #BDBD00000000",
+"q c #BFBF00000000",
+"w c #C3C300000000",
+"e c #C5C500000000",
+"r c #C9C900000000",
+"t c #CBCB00000000",
+"y c #CFCF00000000",
+"u c #D1D100000000",
+"i c #D5D500000000",
+"p c #D7D700000000",
+"a c #D9D900000000",
+"s c #DBDB00000000",
+"d c #DDDD00000000",
+"f c #DADA0E0E0B0B",
+"g c #DCDC11110E0E",
+"h c #DCDC12121010",
+"j c #DDDD16161313",
+"k c #DDDD17171414",
+"l c #DFDF1B1B1919",
+"z c #DFDF1C1C1919",
+"x c #DEDE2E2E2C2C",
+"c c #E1E100000000",
+"v c #E0E021211E1E",
+"b c #E0E021211F1F",
+"n c #E1E126262323",
+"m c #E2E227272424",
+"M c #E2E229292626",
+"N c #E2E22B2B2929",
+"B c #E2E22C2C2A2A",
+"V c #E4E42E2E2B2B",
+"C c #E4E42E2E2C2C",
+"Z c #E0E031312F2F",
+"A c #E4E430302E2E",
+"S c #E4E431312F2F",
+"D c #E0E034343232",
+"F c #E0E035353232",
+"G c #E2E237373535",
+"H c #E5E534343131",
+"J c #E6E637373434",
+"K c #E7E739393636",
+"L c #E7E73A3A3737",
+"P c #E2E23B3B3939",
+"I c #E8E83E3E3C3C",
+"U c #E8E83F3F3D3D",
+"Y c #E4E440403D3D",
+"T c #E4E444444242",
+"R c #E6E646464444",
+"E c #E6E649494646",
+"W c #E7E74B4B4949",
+"Q c #E7E74C4C4B4B",
+"! c #E9E943434242",
+"~ c #E9E944444242",
+"^ c #EAEA46464444",
+"/ c #EAEA49494747",
+"( c #EBEB49494747",
+") c #EBEB4B4B4949",
+"_ c #EBEB4E4E4B4B",
+"` c #EBEB4E4E4C4C",
+"' c #E8E850504E4E",
+"] c #E9E955555353",
+"[ c #ECEC52525151",
+"{ c #EBEB5A5A5757",
+"} c #ECEC5E5E5C5C",
+"| c #ECEC5F5F5D5D",
+" . c #EFEF5D5D5C5C",
+".. c #F0F061615F5F",
+"X. c #EDED63636060",
+"o. c #EDED64646262",
+"O. c #EEEE67676565",
+"+. c #EEEE68686666",
+"@. c #EFEF6B6B6969",
+"#. c #EFEF6D6D6A6A",
+"$. c #EFEF6F6F6D6D",
+"%. c #F0F072727171",
+"&. c #F2F27A7A7979",
+"*. c #F2F27D7D7A7A",
+"=. c #F2F27D7D7B7B",
+"-. c #9292B6B6EAEA",
+";. c #9595B9B9EBEB",
+":. c gray89",
+">. c #E7E7E7E7E7E7",
+",. c gray93",
+"<. c #EFEFEFEFEFEF",
+"1. c gray95",
+"2. c #F3F3F3F3F3F3",
+"3. c #F4F4F4F4F4F4",
+"4. c gray96",
+"5. c #F6F6F6F6F6F6",
+"6. c gray97",
+"7. c #F8F8F8F8F8F8",
+"8. c #F9F9F9F9F9F9",
+"9. c gray98",
+"0. c #FBFBFBFBFBFB",
+"q. c #FBFBFCFCFBFB",
+"w. c gray99",
+"e. c #FDFDFDFDFDFD",
+"r. c #FEFEFEFEFEFE",
+"t. c gray100",
+"y. c None",
+/* pixels */
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"c c c t.O t.d s s s p p u u r r ",
+"c =.=.t.;.t.%.$. at .+.X.| { ] ' e ",
+"c =.| t.5 0.[ _ ( ~ Y J H C W w ",
+"c &. .t.2 t.) R ! I J H B M R q ",
+"t.t.t.0.1 t.0.0.0.0.0.4.4.4.4.>.",
+"o -.2 1 < : : = & $ $ # @ + * . ",
+"q.t.t.0.: 0.0.6.5.5.4.4.2.1.3.:.",
+"s #.( 0.: 0.J H N m v l k g F 7 ",
+"s O.~ 0.& 0.C N m v l j g f Z 6 ",
+"p X.| 0.2 0.W E T Y P G F Z x 6 ",
+"u u y <.X ,.w q q 9 9 7 7 6 6 6 ",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.",
+"y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y."
+};
diff --git a/src/images/flags/SK.xpm b/src/images/flags/SK.xpm
new file mode 100644
index 0000000..42fdaa7
--- /dev/null
+++ b/src/images/flags/SK.xpm
@@ -0,0 +1,176 @@
+/* XPM */
+static const char *SK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 154 2",
+" c black",
+". c #000000009D9D",
+"X c #00000000A3A3",
+"o c #00000303B5B5",
+"O c #00001F1FC9C9",
+"+ c #00001F1FCFCF",
+"@ c #03032323C9C9",
+"# c #3E3E5757CFCF",
+"$ c #38385555D2D2",
+"% c #3C3C5959D4D4",
+"& c #3F3F5959D9D9",
+"* c #42425A5ACFCF",
+"= c #43435A5AD1D1",
+"- c #40405D5DD6D6",
+"; c #48485E5ED1D1",
+": c #48485E5ED2D2",
+"> c #45456161D7D7",
+", c #4C4C6363D3D3",
+"< c #4D4D6363D4D4",
+"1 c #4A4A6565D8D8",
+"2 c #4D4D6969DBDB",
+"3 c #51516666D4D4",
+"4 c #51516767D6D6",
+"5 c #56566A6AD6D6",
+"6 c #52526C6CD9D9",
+"7 c #54546E6ED8D8",
+"8 c #56566E6EDADA",
+"9 c #5B5B6F6FD5D5",
+"0 c #5E5E7171D5D5",
+"q c #59597373DDDD",
+"w c #6B6B6E6ECECE",
+"e c #60607676DDDD",
+"r c #6B6B7575D5D5",
+"t c #70707878D4D4",
+"y c #7D7D7E7ED2D2",
+"u c #76768787DBDB",
+"i c #7A7A8A8ADDDD",
+"p c #7E7E8E8EDFDF",
+"a c #8D8D00000000",
+"s c #BFBF00000000",
+"d c #DDDD00000000",
+"f c #DFDF00000000",
+"g c #C7C723233F3F",
+"h c #E1E100000000",
+"j c #E3E300000000",
+"k c #E5E500000000",
+"l c #E7E700000000",
+"z c #E9E900000000",
+"x c #EBEB00000000",
+"c c #EDED00000000",
+"v c #EFEF00000000",
+"b c #F1F100000000",
+"n c #F3F300000000",
+"m c #F5F500000000",
+"M c #F7F700000000",
+"N c #F1F10B0B0B0B",
+"B c #F1F10F0F0E0E",
+"V c #F9F900000000",
+"C c #F2F213131313",
+"Z c #F3F319191919",
+"A c #F4F41E1E1E1E",
+"S c #F5F523232323",
+"D c #F2F22C2C2C2C",
+"F c #F2F22F2F2F2F",
+"G c #F6F629292929",
+"H c #F7F72E2E2E2E",
+"J c #F2F232323232",
+"K c #F3F335353535",
+"L c #F4F439393939",
+"P c #F5F53D3D3D3D",
+"I c #C9C928284343",
+"U c #CACA2C2C4848",
+"Y c #CCCC31314B4B",
+"T c #CECE36365050",
+"R c #D0D03B3B5555",
+"E c #CECE43435B5B",
+"W c #D2D240405959",
+"Q c #F6F642424242",
+"! c #F7F746464646",
+"~ c #F7F74B4B4B4B",
+"^ c #FAFA44444444",
+"/ c #F7F758585B5B",
+"( c #F8F850505050",
+") c #F9F954545555",
+"_ c #F9F958585858",
+"` c #F9F95A5A5A5A",
+"' c #FAFA5A5A5B5B",
+"] c #FAFA5D5D5D5D",
+"[ c #EFEF69697272",
+"{ c #FBFB61616262",
+"} c #FEFE63636161",
+"| c #FCFC65656060",
+" . c #FCFC66666666",
+".. c #F1F16C6C7474",
+"X. c #F3F374747C7C",
+"o. c #F1F17B7B7F7F",
+"O. c #FAFA74747272",
+"+. c #86867575C3C3",
+"@. c #E1E177778A8A",
+"#. c #E1E17F7F8E8E",
+"$. c #89899797DFDF",
+"%. c #82829191E0E0",
+"&. c #85859494E2E2",
+"*. c #82829898E9E9",
+"=. c #83839999EBEB",
+"-. c #84849B9BECEC",
+";. c #88889898E4E4",
+":. c #90909A9AE1E1",
+">. c #ACACB7B7EEEE",
+",. c #E6E686869494",
+"<. c #F4F48B8B8F8F",
+"1. c #FDFD85858484",
+"2. c #FBFB89898686",
+"3. c #F4F48B8B9191",
+"4. c #F5F58F8F9494",
+"5. c #F6F690909696",
+"6. c #F6F69E9EA2A2",
+"7. c #F0F0ADADB3B3",
+"8. c #E0E0B3B3C3C3",
+"9. c #D2D2C1C1DDDD",
+"0. c #D7D7C2C2D9D9",
+"q. c #DDDDC5C5D8D8",
+"w. c #E7E7DDDDDFDF",
+"e. c #FDFDCDCDCCCC",
+"r. c #FCFCDEDEDEDE",
+"t. c #FDFDDEDEDEDE",
+"y. c #EBEBE1E1E3E3",
+"u. c #EDEDE3E3E5E5",
+"i. c #EFEFE5E5E5E5",
+"p. c #F1F1E7E7E9E9",
+"a. c #F3F3E9E9EBEB",
+"s. c #F5F5EBEBEDED",
+"d. c #F5F5EDEDEFEF",
+"f. c #F7F7EFEFEFEF",
+"g. c #FCFCE2E2E1E1",
+"h. c #FDFDEDEDECEC",
+"j. c #F9F9EFEFF1F1",
+"k. c #F6F6F6F6F6F6",
+"l. c gray97",
+"z. c #FBFBF1F1F3F3",
+"x. c #FBFBF3F3F3F3",
+"c. c #FDFDF3F3F3F3",
+"v. c #FDFDF5F5F5F5",
+"b. c #FDFDF5F5F7F7",
+"n. c #F8F8F8F8F8F8",
+"m. c #F9F9F9F9F9F9",
+"M. c gray98",
+"N. c #FBFBFBFBFBFB",
+"B. c gray99",
+"V. c #FDFDFDFDFDFD",
+"C. c #FDFDFDFDFEFE",
+"Z. c #FEFEFEFEFEFE",
+"A. c gray100",
+"S. c None",
+/* pixels */
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"v.v.v.v.v.c.x.h.j.f.f.s.a.p.i.u.",
+"b.A.A.A.A.A.A.A.N.A.N.m.m.m.l.y.",
+"v.A.6.5.4.<.<.B.m.m.m.m.l.k.l.w.",
+"& >.X.} r.1.` ;.;.&.%.p i u $.o ",
+"@ -...e.h.g./ y 8 5 3 , ; * 0 . ",
+"O -.[ | r.1.` t 6 3 < : = % 9 . ",
+"+ *.9.+.r w 8.q 2 1 > - % $ 7 X ",
+"s @.,.q.q q.#.E R T Y U I g E a ",
+"V .^ O.7.o.H G S A Z C B N F h ",
+"M { ] ` ) ( ~ ! Q P L K J F F d ",
+"M b b c c c x x l l h h h d d d ",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S."
+};
diff --git a/src/images/flags/SL.xpm b/src/images/flags/SL.xpm
new file mode 100644
index 0000000..681f6e6
--- /dev/null
+++ b/src/images/flags/SL.xpm
@@ -0,0 +1,161 @@
+/* XPM */
+static const char *SL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 139 2",
+" c black",
+". c #000000007979",
+"X c #000000007B7B",
+"o c #000000007D7D",
+"O c #000000007F7F",
+"+ c #000000008383",
+"@ c #000000008787",
+"# c #000000008989",
+"$ c #000000008D8D",
+"% c #000000009191",
+"& c #000000009595",
+"* c #000000009999",
+"= c #000000009D9D",
+"- c #00000000A1A1",
+"; c #00000000A5A5",
+": c #00000000A7A7",
+"> c #00000000A9A9",
+", c #00000000ABAB",
+"< c #00000000AFAF",
+"1 c #0B0B0B0BBFBF",
+"2 c #0F0F0F0FC1C1",
+"3 c #13131313C3C3",
+"4 c #18181919C5C5",
+"5 c #1E1E1E1EC7C7",
+"6 c #23232323C8C8",
+"7 c #29292929CACA",
+"8 c #2C2C2C2CC8C8",
+"9 c #2F2F2F2FC8C8",
+"0 c #2E2E2E2ECCCC",
+"q c #2D2D2D2DD1D1",
+"w c #32323232C9C9",
+"e c #35353535CBCB",
+"r c #34343434CECE",
+"t c #39393939CDCD",
+"y c #3D3D3D3DCECE",
+"u c #3A3A3A3AD0D0",
+"i c #3F3F3F3FD2D2",
+"p c #42424242CFCF",
+"a c #46464646D1D1",
+"s c #44444444D4D4",
+"d c #4B4B4B4BD3D3",
+"f c #50505050D4D4",
+"g c #54545454D6D6",
+"h c #58585858D8D8",
+"j c #5D5D5D5DD9D9",
+"k c #63636363D5D5",
+"l c #66666666D6D6",
+"z c #61616161DBDB",
+"x c #66666666DDDD",
+"c c #6A6A6A6AD7D7",
+"v c #6E6E6E6ED9D9",
+"b c #71717171DBDB",
+"n c #75757575DDDD",
+"m c #7A7A7A7ADBDB",
+"M c #79797878DEDE",
+"N c #7C7C7C7CE0E0",
+"B c #00009B9B0000",
+"V c #00009F9F0000",
+"C c #0000A3A30000",
+"Z c #0000A7A70000",
+"A c #0000ABAB0000",
+"S c #0000AFAF0000",
+"D c #0000B1B10000",
+"F c #0000B3B30000",
+"G c #0000B5B50000",
+"H c #0000B7B70000",
+"J c #0000B9B90000",
+"K c #0000BDBD0000",
+"L c #0000C1C10000",
+"P c #0000C3C30000",
+"I c #3838D0D03838",
+"U c #3D3DD2D23D3D",
+"Y c #3D3DD9D93D3D",
+"T c #4242D4D44242",
+"R c #4848D6D64848",
+"E c #4D4DD7D74D4D",
+"W c #5353D7D75353",
+"Q c #5252D9D95252",
+"! c #5757DBDB5757",
+"~ c #5858D8D85858",
+"^ c #5B5BDCDC5B5B",
+"/ c #5C5CDADA5C5C",
+"( c #5E5EDEDE5E5E",
+") c #6161DBDB6060",
+"_ c #6262DEDE6262",
+"` c #6565DDDD6565",
+"' c #6A6ADDDD6A6A",
+"] c #6D6DDBDB6D6D",
+"[ c #6E6EDFDF6E6E",
+"{ c #7171DCDC7171",
+"} c #7676DEDE7575",
+"| c #7979DFDF7979",
+" . c #6666E0E06666",
+".. c #6868E1E16969",
+"X. c #7272E1E17272",
+"o. c #7575E2E27575",
+"O. c #7979E3E37A7A",
+"+. c #7B7BE3E37B7B",
+"@. c #7D7DE1E17D7D",
+"#. c #7F7FE5E57F7F",
+"$. c #80808080E1E1",
+"%. c #84848484E3E3",
+"&. c #88888888E4E4",
+"*. c #8B8B8B8BE6E6",
+"=. c #A0A0A0A0EAEA",
+"-. c #8282DFDF8181",
+";. c #8181E2E28181",
+":. c #8080E6E68080",
+">. c #8383E6E68383",
+",. c #8585E4E48585",
+"<. c #8888E5E58888",
+"1. c #8C8CE6E68C8C",
+"2. c #8E8EE8E88E8E",
+"3. c #9191E8E89191",
+"4. c #9494E9E99494",
+"5. c #A7A7EDEDA7A7",
+"6. c #D3D3D3D3DFDF",
+"7. c #D5D5D5D5E1E1",
+"8. c #D7D7D7D7E3E3",
+"9. c gray95",
+"0. c #F3F3F3F3F3F3",
+"q. c #F4F4F4F4F4F4",
+"w. c #F4F4F5F5F5F5",
+"e. c gray96",
+"r. c #F6F6F6F6F6F6",
+"t. c gray97",
+"y. c #F1F1F1F1F9F9",
+"u. c #F3F3F3F3FBFB",
+"i. c #F5F5F5F5FBFB",
+"p. c #F8F8F8F8F8F8",
+"a. c #F9F9F9F9F9F9",
+"s. c gray98",
+"d. c #FBFBFBFBFBFB",
+"f. c #FBFBFCFCFBFB",
+"g. c gray99",
+"h. c #FDFDFCFCFDFD",
+"j. c #FDFDFDFDFDFD",
+"k. c #FEFEFEFEFEFE",
+"l. c None",
+/* pixels */
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"P P P P P P K K J H F F S A Z C ",
+"P >.>.>.#.O.O.o.X.[ ' ` ) / ~ V ",
+"P >...` _ ( ^ ! Q E R T U I W B ",
+"Y 5.4.3.2.1.,.,.;. at .| } { ] -.H ",
+"i.k.k.k.k.f.k.a.a.a.t.e.e.q.e.8.",
+"u.k.k.d.a.k.a.a.t.t.e.e.e.9.e.8.",
+"u.k.d.k.k.a.a.a.t.e.e.e.q.9.0.6.",
+"0 =.*.&.%.N N M n b v c l k m : ",
+"< x s i u e 0 7 6 5 4 3 2 1 9 X ",
+", z j g g f d a p y t e w 9 9 X ",
+", : - = * & % $ # # + o o X . X ",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l."
+};
diff --git a/src/images/flags/SM.xpm b/src/images/flags/SM.xpm
new file mode 100644
index 0000000..fd0bcdd
--- /dev/null
+++ b/src/images/flags/SM.xpm
@@ -0,0 +1,158 @@
+/* XPM */
+static const char *SM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 136 2",
+" c black",
+". c #00001F1FDDDD",
+"X c #00002121DDDD",
+"o c #00002121DFDF",
+"O c #00002525DFDF",
+"+ c #00002727DFDF",
+"@ c #00002929E1E1",
+"# c #00002B2BE3E3",
+"$ c #00002D2DE3E3",
+"% c #00002F2FE5E5",
+"& c #00003333E5E5",
+"* c #00003939E7E7",
+"= c #00003D3DE9E9",
+"- c #00004141EBEB",
+"; c #00004747EDED",
+": c #00004D4DEDED",
+"> c #00005353EFEF",
+", c #00005959F1F1",
+"< c #00005D5DF3F3",
+"1 c #00006363F5F5",
+"2 c #00006969F7F7",
+"3 c #00006F6FF9F9",
+"4 c #00007373FBFB",
+"5 c #00007777FDFD",
+"6 c #00007B7BFDFD",
+"7 c #40406D6D9E9E",
+"8 c #474773739F9F",
+"9 c #55558D8D4848",
+"0 c #7575A2A26565",
+"q c #7575A4A46666",
+"w c #38389595F1F1",
+"e c #3C3C9797F1F1",
+"r c #3D3D9797F2F2",
+"t c #48489393D5D5",
+"y c #40409999F2F2",
+"u c #41419999F2F2",
+"i c #41419A9AF2F2",
+"p c #45459C9CF3F3",
+"a c #45459D9DF3F3",
+"s c #45459E9EF3F3",
+"d c #46469C9CF3F3",
+"f c #4A4A9F9FF4F4",
+"g c #4F4FA2A2F5F5",
+"h c #5353A2A2F2F2",
+"j c #5555A4A4F2F2",
+"k c #5656A4A4F2F2",
+"l c #5858A5A5F3F3",
+"z c #5959A6A6F3F3",
+"x c #5B5BA8A8F3F3",
+"c c #5C5CA8A8F4F4",
+"v c #5F5FA9A9F4F4",
+"b c #5959A9A9F8F8",
+"n c #65659D9DD3D3",
+"m c #6A6AACACD2D2",
+"M c #6060AAAAF5F5",
+"N c #6161ACACF5F5",
+"B c #6565AEAEF6F6",
+"V c #6060ACACF9F9",
+"C c #6464AFAFFAFA",
+"Z c #6565AFAFFAFA",
+"A c #6868B0B0F7F7",
+"S c #6C6CB2B2F7F7",
+"D c #6969B1B1FAFA",
+"F c #6969B2B2FBFB",
+"G c #6D6DB4B4FBFB",
+"H c #6D6DB5B5FBFB",
+"J c #6E6EB5B5FCFC",
+"K c #7E7EB3B3E1E1",
+"L c #7171B4B4F8F8",
+"P c #7171B7B7FCFC",
+"I c #7272B7B7FCFC",
+"U c #7575B7B7F9F9",
+"Y c #7676B9B9FDFD",
+"T c #7979B9B9F9F9",
+"R c #7D7DBCBCFAFA",
+"E c #9B9B92926969",
+"W c #9292B0B07171",
+"Q c #9C9CB9B97474",
+"! c #AFAF9D9D6464",
+"~ c #BFBFACAC5858",
+"^ c #BDBDABAB6868",
+"/ c #DADAB2B25F5F",
+"( c #DFDFB6B65B5B",
+") c #C2C2B1B16060",
+"_ c #C1C1B9B96A6A",
+"` c #E9E9CDCD6E6E",
+"' c #E9E9CECE7070",
+"] c #8E8EB8B88181",
+"[ c #8686BCBCB3B3",
+"{ c #9090A9A9ADAD",
+"} c #8080BEBEFBFB",
+"| c #9191C1C1B4B4",
+" . c #8484C0C0FCFC",
+".. c #8A8AC0C0F4F4",
+"X. c #8888C3C3FCFC",
+"o. c #8B8BC4C4FDFD",
+"O. c #8E8EC6C6FEFE",
+"+. c #9494C6C6F7F7",
+"@. c #A3A3CCCCD2D2",
+"#. c #DDDDC8C89595",
+"$. c #E2E2D0D09E9E",
+"%. c #D5D5DBDBE7E7",
+"&. c #D7D7DFDFE7E7",
+"*. c #D9D9E1E1E9E9",
+"=. c #DDDDE3E3EBEB",
+"-. c #DDDDE7E7EFEF",
+";. c #DFDFE7E7EFEF",
+":. c #E3E3E9E9F1F1",
+">. c #E5E5EBEBF3F3",
+",. c #E7E7EDEDF5F5",
+"<. c #E9E9EFEFF7F7",
+"1. c #EBEBF1F1F9F9",
+"2. c #EDEDF1F1FBFB",
+"3. c #EDEDF3F3FDFD",
+"4. c #EFEFF5F5FDFD",
+"5. c #F4F4F4F4F4F4",
+"6. c gray96",
+"7. c #F6F6F6F6F6F6",
+"8. c gray97",
+"9. c #F1F1F7F7FDFD",
+"0. c #F1F1F7F7FFFF",
+"q. c #F1F1F9F9FFFF",
+"w. c #F8F8F8F8F8F8",
+"e. c #F9F9F9F9F9F9",
+"r. c #FAFAFAFAF8F8",
+"t. c #FAFAFAFAF9F9",
+"y. c #FBFBFBFBF8F8",
+"u. c gray98",
+"i. c #FBFBFBFBFBFB",
+"p. c gray99",
+"a. c #FDFDFCFCFDFD",
+"s. c #FDFDFDFDFDFD",
+"d. c #FDFDFDFDFEFE",
+"f. c #FEFEFEFEFEFE",
+"g. c gray100",
+"h. c None",
+/* pixels */
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"q.0.0.0.q.4.4.3.2.1.<.,.>.:.-.-.",
+"0.g.g.g.g.g.d.d.i.i.i.i.i.8.8.=.",
+"0.g.i.g.g.i.d.u.i.i.8.8.8.8.8.*.",
+"0.g.g.g.i.d.u.' ` i.8.8.8.5.8.&.",
+"0.g.g.i.g.W $.( / #.0 8.5.5.8.%.",
+"6 O.Y I J @.^ | [ ! { h f s M $ ",
+"5 o.I G F q _ Q W E 9 f s u x $ ",
+"4 X.G F Z m K ) ~ n t d u r z + ",
+"3 .F Z V b +.8 7 } d u e w k X ",
+"2 R R T U L S A B N v x z k h . ",
+"1 < , > : ; - = * & $ @ + . . . ",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.",
+"h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h."
+};
diff --git a/src/images/flags/SN.xpm b/src/images/flags/SN.xpm
new file mode 100644
index 0000000..b3bf8bd
--- /dev/null
+++ b/src/images/flags/SN.xpm
@@ -0,0 +1,176 @@
+/* XPM */
+static const char *SN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 154 2",
+" c black",
+". c #00004D4D0000",
+"X c #000053530000",
+"o c #000059590000",
+"O c #00005D5D0000",
+"+ c #000063630000",
+"@ c #000069690000",
+"# c #00006F6F0000",
+"$ c #000073730000",
+"% c #000077770000",
+"& c #00007B7B0000",
+"* c #00007D7D0000",
+"= c #00007F7F0000",
+"- c #000081810000",
+"; c #3A3AACAC3A3A",
+": c #3F3FAFAF3F3F",
+"> c #4040AFAF3F3F",
+", c #4848B1B13636",
+"< c #5555B6B63B3B",
+"1 c #4444B1B14444",
+"2 c #4545B2B24545",
+"3 c #4949B4B44949",
+"4 c #4949B5B54949",
+"5 c #4B4BB5B54B4B",
+"6 c #4F4FB7B74F4F",
+"7 c #5050B7B75050",
+"8 c #5454B7B75555",
+"9 c #5353B9B95353",
+"0 c #5454B9B95454",
+"q c #5454BABA5454",
+"w c #5858B9B95858",
+"e c #5858BCBC5858",
+"r c #5858BCBC5959",
+"t c #5959BCBC5959",
+"y c #5C5CBDBD5C5C",
+"u c #5D5DBCBC5D5D",
+"i c #5C5CBEBE5C5C",
+"p c #5F5FBFBF5F5F",
+"a c #6161BEBE6262",
+"s c #6666C0C06666",
+"d c #6A6AC3C36A6A",
+"f c #6F6FC4C46F6F",
+"g c #7272C6C67373",
+"h c #7676C8C87676",
+"j c #7777C8C87777",
+"k c #7979C8C87979",
+"l c #7979C9C97979",
+"z c #7B7BCACA7A7A",
+"x c #7B7BCACA7B7B",
+"c c #DDDD00000000",
+"v c #DFDF00000000",
+"b c #E1E100000000",
+"n c #E3E300000000",
+"m c #E5E500000000",
+"M c #E7E700000000",
+"N c #E9E900000000",
+"B c #EBEB00000000",
+"V c #EDED00000000",
+"C c #EFEF00000000",
+"Z c #F1F100000000",
+"A c #F3F300000000",
+"S c #F5F500000000",
+"D c #F1F10B0B0B0B",
+"F c #F1F10F0F0E0E",
+"G c #F2F210101010",
+"H c #F2F213131313",
+"J c #F2F214141414",
+"K c #F3F319191919",
+"L c #F3F31A1A1A1A",
+"P c #F4F41F1F1F1F",
+"I c #F4F420202020",
+"U c #F5F525252525",
+"Y c #F5F526262626",
+"T c #F2F22C2C2C2C",
+"R c #F2F22F2F2F2F",
+"E c #F6F62B2B2B2B",
+"W c #F6F62C2C2C2C",
+"Q c #F2F232323232",
+"! c #F3F332323232",
+"~ c #F3F335353535",
+"^ c #F7F731313131",
+"/ c #F4F436363636",
+"( c #F4F43B3B3B3B",
+") c #F5F53F3F3F3F",
+"_ c #F8F837373737",
+"` c #F6F644444444",
+"' c #F7F749494949",
+"] c #F7F74E4E4E4E",
+"[ c #F8F853535353",
+"{ c #F9F957575757",
+"} c #FAFA5C5C5C5C",
+"| c #8282C8C82F2F",
+" . c #8C8CCECE3535",
+".. c #9797D1D13C3C",
+"X. c #B1B1DEDE3030",
+"o. c #9E9ED4D44141",
+"O. c #E3E3D1D10000",
+"+. c #E5E5D7D70000",
+"@. c #E7E7D9D90000",
+"#. c #E9E9DBDB0000",
+"$. c #EBEBDDDD0000",
+"%. c #F7F7D7D70000",
+"&. c #F9F9DBDB0000",
+"*. c #FBFBDDDD0000",
+"=. c #FBFBDFDF0000",
+"-. c #FDFDDFDF0000",
+";. c #FDFDE1E10000",
+":. c #F3F3F1F11919",
+">. c #F4F4F2F21F1F",
+",. c #F4F4F4F41E1E",
+"<. c #EFEFF6F62A2A",
+"1. c #E7E7F3F33636",
+"2. c #F3F3F5F52424",
+"3. c #F5F5F5F52323",
+"4. c #F5F5F4F42424",
+"5. c #F6F6F5F52B2B",
+"6. c #F6F6F6F62929",
+"7. c #F6F6F6F62A2A",
+"8. c #F7F7F7F72E2E",
+"9. c #F7F7F7F72F2F",
+"0. c #F7F7F6F63030",
+"q. c #F4F4F2F23939",
+"w. c #F5F5F5F53D3D",
+"e. c #F7F7F8F83434",
+"r. c #F8F8F7F73636",
+"t. c #F8F8F8F83434",
+"y. c #F8F8F9F93A3A",
+"u. c #F9F9F9F93A3A",
+"i. c #F9F9F8F83D3D",
+"p. c #F9F9F9F93C3C",
+"a. c #C3C3E4E44040",
+"s. c #EFEFF6F64646",
+"d. c #F6F6F6F64242",
+"f. c #F7F7F7F74646",
+"g. c #F7F7F7F74B4B",
+"h. c #F9F9F9F94040",
+"j. c #F8F8FAFA4242",
+"k. c #FAFAFAFA4242",
+"l. c #FAFAFAFA4646",
+"z. c #FBFBFBFB4747",
+"x. c #FAFAFBFB4B4B",
+"c. c #FCFCFCFC4B4B",
+"v. c #FCFCFCFC4C4C",
+"b. c #F7F7F7F75050",
+"n. c #FBFBFCFC5151",
+"m. c #FDFDFDFD5151",
+"M. c #FCFCFCFC5454",
+"N. c #FCFCF2F26565",
+"B. c #FCFCF4F46969",
+"V. c #FBFBFAFA6060",
+"C. c #FDFDFDFD6D6D",
+"Z. c #FDFDFDFD7171",
+"A. c #FCFCFDFD7474",
+"S. c None",
+/* pixels */
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"- - - - = -.;.;.-.&.%.S A A V V ",
+"- x x x j A.Z.C.B.N.V.} { [ ] B ",
+"- x y y t M.n.c.z.k.i._ ^ W ' B ",
+"= k y e 0 n.c.z.k.i.r.^ W Y ` m ",
+"= h e 0 7 x.s.o...1.0.E Y I ) m ",
+"= g 7 6 5 l.a.< , X.7.Y P K ( m ",
+"% f 6 5 1 k.u. .| <.4.P K H / n ",
+"$ d 5 1 > u.t.8.7.2.>.K H H ! v ",
+"# a 1 : ; e.8.7.3.,.:.H F D R v ",
+"@ a y e 8 b.g.f.d.w.q.~ ! R T v ",
+"+ O o X . $.$.#. at .+.O.n v v c c ",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.",
+"S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S."
+};
diff --git a/src/images/flags/SO.xpm b/src/images/flags/SO.xpm
new file mode 100644
index 0000000..399f520
--- /dev/null
+++ b/src/images/flags/SO.xpm
@@ -0,0 +1,121 @@
+/* XPM */
+static const char * SO_xpm[] = {
+"16 16 102 2",
+" c None",
+". c #2191FF",
+"+ c #1389FF",
+"@ c #0F85FF",
+"# c #0B83FD",
+"$ c #0581FD",
+"% c #007DFD",
+"& c #007BFB",
+"* c #0075F9",
+"= c #0071F7",
+"- c #006DF5",
+"; c #0067F3",
+"> c #0063F1",
+", c #005DEF",
+"' c #0061EF",
+") c #95CAFF",
+"! c #91C8FE",
+"~ c #8FC7FE",
+"{ c #8EC6FE",
+"] c #8AC3FD",
+"^ c #84C0FC",
+"/ c #80BEFB",
+"( c #79B9F9",
+"_ c #75B7F8",
+": c #70B4F7",
+"< c #004DEB",
+"[ c #7FBFFE",
+"} c #7ABCFE",
+"| c #76BAFD",
+"1 c #71B7FC",
+"2 c #70B6FC",
+"3 c #6DB4FB",
+"4 c #67B1FA",
+"5 c #64AFFA",
+"6 c #5EABF8",
+"7 c #59A9F7",
+"8 c #55A6F6",
+"9 c #6DB2F7",
+"0 c #004BE9",
+"a c #1187FF",
+"b c #7CBEFE",
+"c c #63B0FC",
+"d c #AED4FB",
+"e c #55A7F9",
+"f c #5BA9F8",
+"g c #50A2F5",
+"h c #68AFF6",
+"i c #0045E7",
+"j c #A6D1FC",
+"k c #B8DAFB",
+"l c #D7E9FA",
+"m c #D8E9F9",
+"n c #B2D5F8",
+"o c #98C8F7",
+"p c #51A4F6",
+"q c #4FA2F5",
+"r c #4B9FF4",
+"s c #64ADF5",
+"t c #003FE7",
+"u c #6CB4FC",
+"v c #6DB3FB",
+"w c #C1DDFA",
+"x c #F1F5F9",
+"y c #F0F3F8",
+"z c #BEDAF7",
+"A c #57A7F6",
+"B c #469CF3",
+"C c #60AAF5",
+"D c #69B2FB",
+"E c #5FADFA",
+"F c #90C4F9",
+"G c #E2EDF8",
+"H c #E1ECF7",
+"I c #8CC0F6",
+"J c #49A0F5",
+"K c #3D97F2",
+"L c #5CA8F4",
+"M c #0035E3",
+"N c #AED3F8",
+"O c #81BBF7",
+"P c #7AB8F6",
+"Q c #419AF2",
+"R c #59A6F3",
+"S c #0031DF",
+"T c #60ACF9",
+"U c #3895F1",
+"V c #56A4F2",
+"W c #002DDD",
+"X c #7DBCFA",
+"Y c #75B7F9",
+"Z c #71B4F8",
+"` c #62ACF5",
+" . c #53A2F2",
+".. c #0027DD",
+"+. c #0075F5",
+"@. c #0057ED",
+"#. c #0051ED",
+"$. c #0041E7",
+"%. c #003DE5",
+"&. c #0033E1",
+"*. c #0029DD",
+"=. c #0035DD",
+" ",
+" ",
+" ",
+". + + + @ # $ % & * = - ; > , ' ",
+"@ ) ) ) ! ~ { ] ^ ^ / ( ( _ : < ",
+"+ ) [ } } | 1 2 3 4 5 6 7 8 9 0 ",
+"a ! b } | 1 c d d e f 7 8 g h i ",
+"@ ! } | 2 j k l m n o p q r s t ",
+"$ { | 2 u v w x y z A q r B C t ",
+"$ { 2 3 D E F G H I B J B K L M ",
+"& ] v D 5 6 N O P o B B Q K R S ",
+"* / D 5 T f e q J B B Q K U V W ",
+"= / X ( Y Z 9 h s ` C 7 R V ...",
+"+.; > , @.#.< 0 $.%.M &.W W *.=.",
+" ",
+" "};
diff --git a/src/images/flags/SR.xpm b/src/images/flags/SR.xpm
new file mode 100644
index 0000000..ec41109
--- /dev/null
+++ b/src/images/flags/SR.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *SR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000027270000",
+"X c #00002B2B0000",
+"o c #00002D2D0000",
+"O c #000031310000",
+"+ c #000033330000",
+"@ c #000037370000",
+"# c #00003D3D0000",
+"$ c #00003F3F0000",
+"% c #000045450000",
+"& c #00004B4B0000",
+"* c #00004F4F0000",
+"= c #000051510000",
+"- c #000055550000",
+"; c #00005B5B0000",
+": c #00005F5F0000",
+"> c #000061610000",
+", c #000065650000",
+"< c #00006B6B0000",
+"1 c #00006F6F0000",
+"2 c #000073730000",
+"3 c #000075750000",
+"4 c #000077770000",
+"5 c #00007D7D0000",
+"6 c #000081810000",
+"7 c #000083830000",
+"8 c #000085850000",
+"9 c #000087870000",
+"0 c #000089890000",
+"q c #00008F8F0000",
+"w c #3030A5A53131",
+"e c #3333A7A73434",
+"r c #3535A8A83737",
+"t c #3939AAAA3B3B",
+"y c #3D3DADAD3F3F",
+"u c #4141AEAE4242",
+"i c #4545B0B04646",
+"p c #4A4AB3B34B4B",
+"a c #4E4EB5B55050",
+"s c #5050B6B65050",
+"d c #5353B8B85454",
+"f c #5454B8B85555",
+"g c #5757B9B95959",
+"h c #5959BABA5A5A",
+"j c #5B5BBCBC5D5D",
+"k c #5E5EBDBD5E5E",
+"l c #6060BEBE6262",
+"z c #6262BEBE6363",
+"x c #6565C0C06666",
+"c c #6666C1C16767",
+"v c #6A6AC3C36B6B",
+"b c #6F6FC4C46E6E",
+"n c #7171C6C67272",
+"m c #7575C8C87575",
+"M c #7878C8C87979",
+"N c #7A7ACACA7A7A",
+"B c #7C7CCBCB7D7D",
+"V c #DFDF00000000",
+"C c #E3E300000000",
+"Z c #E5E500000000",
+"A c #E7E700000000",
+"S c #FBFB00000000",
+"D c #FDFD00000000",
+"F c red",
+"G c #F2F214141414",
+"H c #F3F319191919",
+"J c #F3F31A1A1A1A",
+"K c #F4F41F1F1F1F",
+"L c #F4F420202020",
+"P c #F5F524242424",
+"I c #F5F525252525",
+"U c #F2F22A2A2B2B",
+"Y c #F6F62B2B2B2B",
+"T c #F6F62D2D2B2B",
+"R c #F2F22E2E3030",
+"E c #F3F333333535",
+"W c #F7F730303030",
+"Q c #F4F436363636",
+"! c #F4F437373939",
+"~ c #F4F43B3B3B3B",
+"^ c #F5F53F3F3F3F",
+"/ c #F5F543433E3E",
+"( c #F7F77C7C3030",
+") c #F5F542424343",
+"_ c #F6F646464848",
+"` c #F6F648484343",
+"' c #F3F349494B4B",
+"] c #F7F74D4D4949",
+"[ c #F7F74C4C4D4D",
+"{ c #FAFA40404040",
+"} c #FBFB45454545",
+"| c #FBFB47474646",
+" . c #FBFB4A4A4949",
+".. c #FCFC4A4A4B4B",
+"X. c #FCFC4B4B4B4B",
+"o. c #FCFC4F4F4F4F",
+"O. c #FDFD4F4F5050",
+"+. c #F8F851514D4D",
+"@. c #F6F65C5C5D5D",
+"#. c #F8F851515252",
+"$. c #F9F950505252",
+"%. c #F9F955555757",
+"&. c #FAFA56565656",
+"*. c #FDFD53535353",
+"=. c #FDFD54545454",
+"-. c #FBFB5A5A5B5B",
+";. c #FBFB5E5E5F5F",
+":. c #FEFE58585858",
+">. c #FCFC63636464",
+",. c #FDFD67676868",
+"<. c #FDFD6B6B6C6C",
+"1. c #FDFD6F6F6F6F",
+"2. c #FEFE6E6E7070",
+"3. c #FEFE71717373",
+"4. c #FEFE72727373",
+"5. c #FEFE76767676",
+"6. c #FCFC7C7C7D7D",
+"7. c #F7F7B5B52F2F",
+"8. c #F8F8B7B73535",
+"9. c #FAFA82824040",
+"0. c #FAFAAAAA4F4F",
+"q. c #FBFBADAD5454",
+"w. c #F6F6C2C22A2A",
+"e. c #F8F8C7C73636",
+"r. c #F9F9C8C83A3A",
+"t. c #F9F9D7D73C3C",
+"y. c #F8F8F3F33636",
+"u. c #F9F9F2F23B3B",
+"i. c #FBFBCDCD4646",
+"p. c #FAFAD8D84141",
+"a. c #FEFE8A8A8C8C",
+"s. c #C9C9D9D9CBCB",
+"d. c #D3D3E5E5D5D5",
+"f. c #E6E6EEEEE7E7",
+"g. c #E6E6EFEFE7E7",
+"h. c #E8E8EFEFE9E9",
+"j. c #E9E9EFEFEAEA",
+"k. c #E9E9F0F0EAEA",
+"l. c #EAEAF1F1EBEB",
+"z. c #EBEBF5F5EBEB",
+"x. c #ECECF1F1ECEC",
+"c. c #EDEDF2F2EDED",
+"v. c #EDEDF9F9F1F1",
+"b. c #F1F1F5F5F2F2",
+"n. c #F2F2F6F6F3F3",
+"m. c #F2F2F7F7F3F3",
+"M. c #F4F4F7F7F4F4",
+"N. c #F3F3F8F8F4F4",
+"B. c #F4F4F9F9F5F5",
+"V. c #F5F5F8F8F5F5",
+"C. c #F5F5F9F9F6F6",
+"Z. c #F6F6F9F9F6F6",
+"A. c #F6F6FAFAF7F7",
+"S. c #F7F7FBFBF8F8",
+"D. c #F8F8FBFBF8F8",
+"F. c #F8F8FBFBF9F9",
+"G. c #F9F9FCFCF9F9",
+"H. c #F9F9FCFCFAFA",
+"J. c #F9F9FDFDFAFA",
+"K. c #FAFAFDFDFBFB",
+"L. c #FBFBFEFEFCFC",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"q 9 9 9 9 6 6 5 4 2 1 < , > ; : ",
+"0 B B N M m n b v c z k h d s = ",
+"v.L.J.J.J.J.S.S.S.V.V.M.n.n.n.d.",
+"F a.3.2.<.,.>.q.0.%.#.[ _ ) @.A ",
+"F 5.:.=.O...i.p.t.e.W Y I L ^ A ",
+"F 3.#.o...| 9.u.y.( T I L J ~ A ",
+"F 1.o. .| { r.8.7.w.L K J G Q C ",
+"S 6.;.-.%.O.+.] ` / ! E R U ' V ",
+"z.S.S.S.N.N.M.x.x.l.l.h.f.f.l.s.",
+"4 z z j h f a p u u y t r e w o ",
+"2 , > ; - = & % # # @ + o X . + ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/ST.xpm b/src/images/flags/ST.xpm
new file mode 100644
index 0000000..5ee49c2
--- /dev/null
+++ b/src/images/flags/ST.xpm
@@ -0,0 +1,191 @@
+/* XPM */
+static const char *ST_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 169 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002D2D0000",
+"O c #00002F2F0000",
+"+ c #000033330000",
+"@ c #000035350000",
+"# c #000039390000",
+"$ c #00003D3D0000",
+"% c #2E2E2E2E1F1F",
+"& c #000041410000",
+"* c #000047470000",
+"= c #00004D4D0000",
+"- c #00004F4F0000",
+"; c #000051510000",
+": c #000057570000",
+"> c #00005D5D0000",
+", c #000061610000",
+"< c #000063630000",
+"1 c #000067670000",
+"2 c #00006D6D0000",
+"3 c #000071710000",
+"4 c #000073730000",
+"5 c #000075750000",
+"6 c #000079790000",
+"7 c #00007D7D0000",
+"8 c #424242423636",
+"9 c #000081810000",
+"0 c #000083830000",
+"q c #000087870000",
+"w c #000089890000",
+"e c #000093930000",
+"r c #131398980B0B",
+"t c #17179A9A0E0E",
+"y c #1C1C9D9D1313",
+"u c #2020A0A01919",
+"i c #2525A1A11E1E",
+"p c #2A2AA4A42323",
+"a c #3030A7A72929",
+"s c #3131A4A42C2C",
+"d c #3030A7A72C2C",
+"f c #3434A5A52F2F",
+"g c #3636A7A72F2F",
+"h c #3535AAAA2E2E",
+"j c #3636A7A73232",
+"k c #3636ABAB3131",
+"l c #3A3AA9A93535",
+"z c #3B3BADAD3434",
+"x c #3C3CAEAE3737",
+"c c #3E3EABAB3939",
+"v c #4040AFAF3A3A",
+"b c #4242AEAE3D3D",
+"n c #4141B0B03D3D",
+"m c #4545B4B43F3F",
+"M c #4646AEAE4242",
+"N c #4646B2B24242",
+"B c #4A4AB1B14646",
+"V c #4B4BB5B54747",
+"C c #4C4CB3B34949",
+"Z c #4F4FB3B34B4B",
+"A c #5050B7B74C4C",
+"S c #5252B6B64E4E",
+"D c #5353B6B65050",
+"F c #5454B9B95151",
+"G c #5757B8B85353",
+"H c #5858B9B95555",
+"J c #5858BBBB5454",
+"K c #5C5CBABA5757",
+"L c #5C5CBABA5858",
+"P c #5C5CBDBD5959",
+"I c #6060BDBD5C5C",
+"U c #6565BEBE6060",
+"Y c #5D5DC0C05D5D",
+"T c #5F5FC0C05C5C",
+"R c #6969C1C16565",
+"E c #6D6DC3C36969",
+"W c #7070C4C46D6D",
+"Q c #7474C6C67171",
+"! c #7777C8C87474",
+"~ c #7A7AC8C87777",
+"^ c #7B7BCDCD7B7B",
+"/ c #7C7CCACA7979",
+"( c #ADAD00000000",
+") c #BBBB00000000",
+"_ c #BABA6F6F4444",
+"` c #E5E500000000",
+"' c #F5F500000000",
+"] c #F9F900000000",
+"[ c #FBFB00000000",
+"{ c #FDFD00000000",
+"} c red",
+"| c #CCCC7F7F6262",
+" . c #FCFC50504F4F",
+".. c #FDFD53535353",
+"X. c #FEFE59595858",
+"o. c #E8E86E6E5F5F",
+"O. c #F4F463634949",
+"+. c #FCFC65654B4B",
+"@. c #FCFC6D6D4F4F",
+"#. c #FBFB77774949",
+"$. c #F5F575755C5C",
+"%. c #E0E077776666",
+"&. c #FCFC6A6A6A6A",
+"*. c #FDFD6F6F6F6F",
+"=. c #FEFE72727373",
+"-. c #FEFE76767676",
+";. c #FEFE79797979",
+":. c #959593931919",
+">. c #9E9E9B9B1A1A",
+",. c #8C8C8A8A2525",
+"<. c #999998983B3B",
+"1. c #9595BFBF0000",
+"2. c #A0A09E9E2F2F",
+"3. c #A4A4A1A12525",
+"4. c #AAAAA7A73030",
+"5. c #AEAEABAB3C3C",
+"6. c #9D9DC7C70000",
+"7. c #B5B5D1D10000",
+"8. c #B7B7D1D10000",
+"9. c #BBBBD5D50000",
+"0. c #F0F088884545",
+"q. c #FBFB8C8C4545",
+"w. c #FDFD80805454",
+"e. c #F1F196965959",
+"r. c #FDFD93935050",
+"t. c #EEEE85857B7B",
+"y. c #F4F482827A7A",
+"u. c #E6E6E5E51F1F",
+"i. c #E2E2EAEA1010",
+"p. c #E6E6EDED1414",
+"a. c #E6E6EEEE1919",
+"s. c #E6E6EEEE1F1F",
+"d. c #F2F2F2F21414",
+"f. c #E5E5EDED2626",
+"g. c #E7E7EEEE2424",
+"h. c #EBEBEAEA2B2B",
+"j. c #E6E6EDED3232",
+"k. c #EBEBEAEA3535",
+"l. c #E7E7F0F02B2B",
+"z. c #EBEBF1F12A2A",
+"x. c #ECECF2F22F2F",
+"c. c #E8E8F1F13131",
+"v. c #E9E9F1F13636",
+"b. c #EBEBF2F23434",
+"n. c #EAEAF2F23C3C",
+"m. c #ECECF3F33A3A",
+"M. c #EEEEF4F43F3F",
+"N. c #F4F4F4F42020",
+"B. c #F5F5F5F52424",
+"V. c #F4F4F4F42B2B",
+"C. c #F6F6F6F62A2A",
+"Z. c #F7F7F7F73030",
+"A. c #F4F4F4F43636",
+"S. c #F4F4F5F53B3B",
+"D. c #F5F5F5F53F3F",
+"F. c #F8F8F8F83636",
+"G. c #F9F9F9F93A3A",
+"H. c #E8E8EFEF4444",
+"J. c #ECECF4F44242",
+"K. c #EDEDF4F44747",
+"L. c #EDEDF4F44B4B",
+"P. c #EEEEF5F55151",
+"I. c #F0F0EFEF4141",
+"U. c #F7F7F7F74040",
+"Y. c #FAFAFAFA4040",
+"T. c #FBFBFBFB4646",
+"R. c #FCFCFCFC4B4B",
+"E. c #F0F0F6F65454",
+"W. c None",
+/* pixels */
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+") e w w w 0 9 7 6 5 3 2 1 , > , ",
+"' t.^ / ~ ! Q W E R U P K F S = ",
+"} y.o.T P J F A V N N x k d Z = ",
+"} ;.$.e.P.P.L.L.J.n.v.l.l.f.J.6.",
+"} -.X.w.r.R.T.I.5.A.C.h.2.N.U.9.",
+"} =... at .+.T.U.<.8 4.C.,.% >.S.8.",
+"} *. .#.q.Y.G.k.2.C.B.u.:.d.A.7.",
+"] &.O.0.M.m.b.x.z.g.s.a.p.i.j.1.",
+"] %._ m v z h a p i u y t r j + ",
+"` t.A F H D Z B M b c l j f s . ",
+"( 3 < , : ; = * & $ # + O O X @ ",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W."
+};
diff --git a/src/images/flags/SV.xpm b/src/images/flags/SV.xpm
new file mode 100644
index 0000000..ed42519
--- /dev/null
+++ b/src/images/flags/SV.xpm
@@ -0,0 +1,166 @@
+/* XPM */
+static const char *SV_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 144 2",
+" c black",
+". c #000000009F9F",
+"X c #00000000A1A1",
+"o c #00000000A3A3",
+"O c #00000000A5A5",
+"+ c #00000000A9A9",
+"@ c #00000000ABAB",
+"# c #00000000ADAD",
+"$ c #00000000B1B1",
+"% c #00000000B3B3",
+"& c #00000000B5B5",
+"* c #00000000B9B9",
+"= c #00000000BBBB",
+"- c #00000000BFBF",
+"; c #00000000C1C1",
+": c #00000000C5C5",
+"> c #00000000C7C7",
+", c #00000303C5C5",
+"< c #00000505C9C9",
+"1 c #00000707CBCB",
+"2 c #00000B0BCBCB",
+"3 c #00001111CFCF",
+"4 c #00001717D1D1",
+"5 c #00001D1DD1D1",
+"6 c #00002121D3D3",
+"7 c #00002727D5D5",
+"8 c #00002929D7D7",
+"9 c #00002F2FD7D7",
+"0 c #29294E4ED1D1",
+"q c #2D2D5151D2D2",
+"w c #31315454D4D4",
+"e c #36365858D5D5",
+"r c #3B3B5C5CD6D6",
+"t c #40406161D9D9",
+"y c #45456666DBDB",
+"u c #47476767DBDB",
+"i c #49496767D7D7",
+"p c #49496868D8D8",
+"a c #48486969DCDC",
+"s c #4C4C6A6AD8D8",
+"d c #4E4E6C6CD9D9",
+"f c #4C4C6C6CDDDD",
+"g c #4E4E6D6DDDDD",
+"h c #52526F6FDADA",
+"j c #51517070DFDF",
+"k c #53537171DFDF",
+"l c #55557272DBDB",
+"z c #58587575DCDC",
+"x c #5C5C7979DDDD",
+"c c #56567474E0E0",
+"v c #58587575E0E0",
+"b c #5B5B7878E1E1",
+"n c #5C5C7979E2E2",
+"m c #5F5F7C7CE3E3",
+"M c #60607C7CDFDF",
+"N c #60607C7CE0E0",
+"B c #65657F7FE1E1",
+"V c #64648080E4E4",
+"C c #67678383E5E5",
+"Z c #68688282E2E2",
+"A c #69698383E2E2",
+"S c #6B6B8686E6E6",
+"D c #6C6C8585E3E3",
+"F c #6D6D8686E3E3",
+"G c #6F6F8989E7E7",
+"H c #70708989E4E4",
+"J c #70708A8AE5E5",
+"K c #74748D8DE6E6",
+"L c #75758E8EE6E6",
+"P c #72728C8CE8E8",
+"I c #74748E8EE9E9",
+"U c #78789090E7E7",
+"Y c #79799090E8E8",
+"T c #7A7A9191E8E8",
+"R c #7C7C9494E8E8",
+"E c #7F7F9797E8E8",
+"W c #8D8DADAD5F5F",
+"Q c #9191AFAF6464",
+"! c #E9E9D6D67979",
+"~ c #87879999D3D3",
+"^ c #82829999EAEA",
+"/ c #85859B9BEBEB",
+"( c #89899E9EEBEB",
+") c #9393A1A1DBDB",
+"_ c #8B8BA0A0EDED",
+"` c #8C8CA2A2EDED",
+"' c #8D8DA2A2EDED",
+"] c #8F8FA4A4EDED",
+"[ c #B7B7CBCB9E9E",
+"{ c #BABACDCDA1A1",
+"} c #BBBBC7C7F1F1",
+"| c #BFBFCBCBF5F5",
+" . c #DEDED4D48080",
+".. c #C1C1CBCBECEC",
+"X. c #C4C4CDCDEAEA",
+"o. c #C6C6CECEEBEB",
+"O. c #C8C8D0D0EDED",
+"+. c #C9C9D2D2EEEE",
+"@. c #CACAD2D2EFEF",
+"#. c #CBCBD4D4EFEF",
+"$. c #CBCBD5D5EFEF",
+"%. c #CCCCD4D4EDED",
+"&. c #CDCDD7D7EFEF",
+"*. c #C8C8D2D2F2F2",
+"=. c #CCCCD4D4F0F0",
+"-. c #CECED5D5F2F2",
+";. c #D0D0D7D7F3F3",
+":. c #D1D1D8D8F1F1",
+">. c #D1D1D8D8F2F2",
+",. c #D3D3DADAF3F3",
+"<. c #D2D2D9D9F4F4",
+"1. c #D3D3DADAF4F4",
+"2. c #D4D4DCDCF4F4",
+"3. c #D5D5DCDCF4F4",
+"4. c #D6D6DDDDF5F5",
+"5. c #D6D6DEDEF6F6",
+"6. c #D8D8DFDFF6F6",
+"7. c #D8D8DFDFF7F7",
+"8. c #DADAE0E0F8F8",
+"9. c #DBDBE1E1F9F9",
+"0. c #DCDCE2E2F9F9",
+"q. c gray89",
+"w. c gray90",
+"e. c #E7E7E7E7E7E7",
+"r. c #E0E0E5E5F8F8",
+"t. c #E2E2E8E8FBFB",
+"y. c gray95",
+"u. c #F3F3F3F3F3F3",
+"i. c #F4F4F4F4F4F4",
+"p. c #F4F4F5F5F5F5",
+"a. c gray96",
+"s. c #F6F6F6F6F5F5",
+"d. c #F6F6F6F6F6F6",
+"f. c gray97",
+"g. c #F8F8F8F8F8F8",
+"h. c #F9F9F9F9F8F8",
+"j. c gray98",
+"k. c #FBFBFBFBFBFB",
+"l. c #FBFBFCFCFBFB",
+"z. c gray99",
+"x. c #FDFDFCFCFDFD",
+"c. c #FDFDFDFDFDFD",
+"v. c #FEFEFEFEFEFE",
+"b. c None",
+/* pixels */
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"9 8 8 8 7 6 5 4 4 1 < > : ; ; = ",
+"8 ] ] ` ` ( / ^ ^ R I K H D Z * ",
+"7 ` I P G S C B m b c c f u N % ",
+"| t.0.0.7.7.5.3.;.3.;.#.#.+.>.) ",
+"c.c.c.c.c.c.k.! ! g.g.a.a.a.a.e.",
+"c.c.c.k.c.c.*.Q W } d.a.p.u.p.e.",
+"c.c.c.c.h.h.h.{ [ a.a.p.u.y.u.q.",
+"} r.7.3.3.3.>.&.=.=.O.+.X.X.%.~ ",
+"< T b c c f a u t r e q q 0 i X ",
+"< T L G D A V N x z l h d s p X ",
+": : ; = = * % $ # + + O X X . . ",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b."
+};
diff --git a/src/images/flags/SY.xpm b/src/images/flags/SY.xpm
new file mode 100644
index 0000000..7ab4471
--- /dev/null
+++ b/src/images/flags/SY.xpm
@@ -0,0 +1,130 @@
+/* XPM */
+static const char *SY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 108 2",
+" c black",
+". c #0B0B0B0B0B0B",
+"X c #0F0F0F0F0E0E",
+"o c #131313131313",
+"O c #181819191919",
+"+ c #1E1E1E1E1E1E",
+"@ c #232323232323",
+"# c gray16",
+"$ c #2C2C2C2C2C2C",
+"% c gray18",
+"& c #2F2F2F2F2F2F",
+"* c #323232323232",
+"= c #343434343434",
+"- c #353535353535",
+"; c #393939393939",
+": c #3A3A3A3A3A3A",
+"> c gray24",
+", c #3F3F3F3F3F3F",
+"< c gray26",
+"1 c #444444444444",
+"2 c #464646464646",
+"3 c #4B4B4B4B4B4B",
+"4 c #505050505050",
+"5 c #545454545555",
+"6 c #585858585858",
+"7 c #5D5D5D5D5D5D",
+"8 c #616161616262",
+"9 c gray40",
+"0 c #5252B5B55454",
+"q c #6666BFBF6767",
+"w c #E9E900000000",
+"e c #EBEB00000000",
+"r c #EDED00000000",
+"t c #EFEF00000000",
+"y c #F1F100000000",
+"u c #F3F300000000",
+"i c #F5F500000000",
+"p c #F7F700000000",
+"a c #F9F900000000",
+"s c #FBFB00000000",
+"d c #FDFD00000000",
+"f c red",
+"g c #F6F62C2C2C2C",
+"h c #F7F731313131",
+"j c #F8F837373737",
+"k c #F9F93C3C3D3D",
+"l c #F7F749494949",
+"z c #F7F74E4E4E4E",
+"x c #FAFA42424242",
+"c c #FBFB47474747",
+"v c #FCFC4C4C4C4C",
+"b c #F8F853535353",
+"n c #F9F957575757",
+"m c #FDFD51515151",
+"M c #FDFD54545454",
+"N c #FAFA5C5C5C5C",
+"B c #FEFE59595959",
+"V c #FEFE5C5C5C5C",
+"C c #FEFE5F5F5F5F",
+"Z c #FBFB60606060",
+"A c #FCFC65656565",
+"S c #FCFC69696969",
+"D c #FDFD6D6D6D6D",
+"F c #FDFD70707171",
+"G c #FEFE74747474",
+"H c #FEFE77777777",
+"J c #FEFE79797979",
+"K c #FFFF7B7B7A7A",
+"L c #FFFF7B7B7B7B",
+"P c #8080C8C88282",
+"I c #8585CACA8686",
+"U c #9595D3D39696",
+"Y c #9797D3D39A9A",
+"T c #9D9DD4D49F9F",
+"R c #9D9DD6D69F9F",
+"E c #A3A3DADAA5A5",
+"W c #A7A7DBDBA9A9",
+"Q c gray81",
+"! c gray82",
+"~ c #D5D5D5D5D5D5",
+"^ c #D7D7D7D7D7D7",
+"/ c gray93",
+"( c #EDEDEFEFEFEF",
+") c #EFEFEFEFEFEF",
+"_ c #E1E1F0F0E1E1",
+"` c #E9E9F3F3EBEB",
+"' c #F1F1F1F1F1F1",
+"] c gray95",
+"[ c #F3F3F3F3F3F3",
+"{ c #F4F4F4F4F4F4",
+"} c #F4F4F5F5F5F5",
+"| c gray96",
+" . c #F6F6F6F6F6F6",
+".. c gray97",
+"X. c #F1F1F9F9F0F0",
+"o. c #F3F3F8F8F6F6",
+"O. c #F3F3FBFBF7F7",
+"+. c #F5F5FBFBF5F5",
+"@. c #F4F4FBFBF6F6",
+"#. c #F8F8F8F8F8F8",
+"$. c #F9F9F9F9F9F9",
+"%. c gray98",
+"&. c #FBFBFBFBFBFB",
+"*. c #FBFBFCFCFBFB",
+"=. c gray99",
+"-. c #FDFDFDFDFDFD",
+";. c #FEFEFEFEFEFE",
+":. c None",
+/* pixels */
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+"f f f f s f f f s s p p u u r r ",
+"f L L L G G F D S A Z N n b z e ",
+"f L C V V M m v c x k j h g l e ",
+"' ;.;.;.;.*.*.&.%.%... . . . .^ ",
+"' ;.;.;.o.W O.%.%.o.Y ` .[ [ ^ ",
+"/ ;.;.;.E q T %...T 0 P .[ .! ",
+"/ ;.&.*.O.U X.%. . .I _ ' ' [ ! ",
+"/ ;.*.*.%.#.%... . .[ [ [ ' [ Q ",
+" 9 1 > : = $ # @ + O o X . & ",
+" 8 7 6 5 4 3 2 < > : - * & $ ",
+" ",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:.",
+":.:.:.:.:.:.:.:.:.:.:.:.:.:.:.:."
+};
diff --git a/src/images/flags/SZ.xpm b/src/images/flags/SZ.xpm
new file mode 100644
index 0000000..335b398
--- /dev/null
+++ b/src/images/flags/SZ.xpm
@@ -0,0 +1,192 @@
+/* XPM */
+static const char *SZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 170 2",
+" c black",
+". c #353500000000",
+"X c #393900000000",
+"o c #3F3F00000000",
+"O c #37372F2F2F2F",
+"+ c #3F3F38383838",
+"@ c #00003D3D7777",
+"# c #4F4F00000000",
+"$ c #4E4E34343434",
+"% c #7D7D00000000",
+"& c #7F7F00000000",
+"* c #7A7A20202020",
+"= c #474740404040",
+"- c #4B4B43434343",
+"; c #4C4C45454545",
+": c #53534C4C4B4B",
+"> c #56564B4B4B4B",
+", c #56564F4F4F4F",
+"< c #545451515353",
+"1 c #585850505151",
+"2 c #666661616262",
+"3 c #000027278989",
+"4 c #00002B2B8B8B",
+"5 c #00002D2D8D8D",
+"6 c #000033338D8D",
+"7 c #000031319191",
+"8 c #000037379393",
+"9 c #00003D3D9595",
+"0 c #00003F3F9999",
+"q c #000045459D9D",
+"w c #0B0B5D5D9797",
+"e c #00004B4BA1A1",
+"r c #01014F4FA5A5",
+"t c #07075555A7A7",
+"y c #0F0F5B5BABAB",
+"u c #17175F5FADAD",
+"i c #17176161AFAF",
+"p c #1D1D6565B1B1",
+"a c #23236B6BB5B5",
+"s c #2B2B6F6FB9B9",
+"d c #37377F7FABAB",
+"f c #31317373B9B9",
+"g c #31317373BBBB",
+"h c #37377777BFBF",
+"j c #3B3B7D7DC1C1",
+"k c #3F3F8181C3C3",
+"l c #53539393BDBD",
+"z c #79798D8DB5B5",
+"x c #45458383C5C5",
+"c c #49498585C5C5",
+"v c #4B4B8787C7C7",
+"b c #55558F8FCBCB",
+"n c #818100000000",
+"m c #858500000000",
+"M c #878700000000",
+"N c #969617171717",
+"B c #9A9A15151414",
+"V c #9A9A19191919",
+"C c #93933A3A3A3A",
+"Z c #A2A226262626",
+"A c #AAAA2D2D2B2B",
+"S c #A7A73A3A3A3A",
+"D c #A8A832323232",
+"F c #ADAD32323131",
+"G c #ACAC35353333",
+"H c #ADAD38383535",
+"J c #AEAE3F3F3F3F",
+"K c #B7B73F3F3F3F",
+"L c #B2B24A4A3D3D",
+"P c #9A9A45454646",
+"I c #A2A251515151",
+"U c #B3B344444444",
+"Y c #B0B04B4B4C4C",
+"T c #B4B44C4C4C4C",
+"R c #BCBC53534C4C",
+"E c #BEBE59595959",
+"W c #BFBF5D5D5858",
+"Q c #BFBF5C5C5C5C",
+"! c #D1D145450000",
+"~ c #DDDD61610000",
+"^ c #C2C258585454",
+"/ c #C5C572727272",
+"( c #C7C776767676",
+") c #C8C876767373",
+"_ c #C8C876767575",
+"` c #CCCC79797979",
+"' c #838372729090",
+"] c #BABA80804242",
+"[ c #F1F189890000",
+"{ c #F5F599990303",
+"} c #E9E9A3A33636",
+"| c #EAEAA6A63838",
+" . c #EBEBA9A93C3C",
+".. c #C1C189895252",
+"X. c #D4D48C8C4B4B",
+"o. c #D4D498985F5F",
+"O. c #DDDDA5A57171",
+"+. c #DADAABAB7878",
+"@. c #E3E39B9B6363",
+"#. c #EDEDABAB4040",
+"$. c #EDEDADAD4646",
+"%. c #EEEEB0B04C4C",
+"&. c #EEEEB2B24F4F",
+"*. c #EDEDB2B25353",
+"=. c #F0F0B5B55454",
+"-. c #F1F1B5B55454",
+";. c #F2F2B7B75858",
+":. c #F3F3B7B75959",
+">. c #F3F3BABA5C5C",
+",. c #F3F3BABA5D5D",
+"<. c #F4F4BBBB6161",
+"1. c #F4F4BCBC6262",
+"2. c #F5F5BEBE6666",
+"3. c #F5F5BFBF6666",
+"4. c #F2F2BEBE6B6B",
+"5. c #F5F5C1C16B6B",
+"6. c #F6F6C2C26F6F",
+"7. c #F7F7C4C47272",
+"8. c #F8F8C6C67676",
+"9. c #F9F9C8C87979",
+"0. c #F9F9C9C97C7C",
+"q. c #FAFACBCB7E7E",
+"w. c #8F8F8B8B8989",
+"e. c #A2A29A9A9797",
+"r. c #A3A39C9C9999",
+"t. c #A1A19D9DB6B6",
+"y. c #8383ACACC4C4",
+"u. c #8484ADADC5C5",
+"i. c #8686AEAEC7C7",
+"p. c #8989B0B0C8C8",
+"a. c #8C8CB2B2C9C9",
+"s. c #8E8EB3B3CACA",
+"d. c #9B9BA8A8C7C7",
+"f. c #9090B3B3CACA",
+"g. c #9696B9B9CFCF",
+"h. c #9898BBBBD1D1",
+"j. c #9898BBBBD3D3",
+"k. c #9999BDBDD2D2",
+"l. c #9B9BBDBDD5D5",
+"z. c #9D9DBFBFD3D3",
+"x. c #9E9EBFBFD7D7",
+"c. c #9F9FC1C1D5D5",
+"v. c #A3A3C3C3D7D7",
+"b. c #A1A1C1C1D8D8",
+"n. c #A4A4C3C3DADA",
+"m. c #A5A5C5C5D8D8",
+"M. c #A6A6C4C4DADA",
+"N. c #A8A8C4C4DADA",
+"B. c #ABABC8C8DDDD",
+"V. c #AEAECBCBDFDF",
+"C. c #AFAFCCCCE0E0",
+"Z. c #B1B1CDCDE1E1",
+"A. c #B3B3CECEE2E2",
+"S. c #B3B3CFCFE2E2",
+"D. c #C7C7AEAEAFAF",
+"F. c #C1C1BDBDBABA",
+"G. c #CACABEBEBCBC",
+"H. c #E4E4B6B6B2B2",
+"J. c #C5C5C1C1BEBE",
+"K. c #DFDFC1C1B6B6",
+"L. c #F7F7CBCB8282",
+"P. c #FBFBD4D49494",
+"I. c #EAEAC2C2BCBC",
+"U. c #CCCCC8C8C5C5",
+"Y. c #DFDFCECEC8C8",
+"T. c #DFDFCFCFCBCB",
+"R. c #E3E3E0E0DEDE",
+"E. c #F2F2E9E9E5E5",
+"W. c #F6F6EDEDE9E9",
+"Q. c None",
+/* pixels */
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"b v v v v x k j h g s a p i y u ",
+"l S.S.S.S.C.V.B.N.n.n.b.x.l.j.w ",
+"{ P.0.0.9.8.7.6.6.3.1.,.;.=.4.~ ",
+"M ` Q E ^ I 1 : W.I.R F A Z U # ",
+"M ( W @.o., < ; U.E.Y.X.Y.* J o ",
+"M _ O.+.> r.r.= F.2 w.I.W ] L X ",
+"% _ t.d.P - = + J.R.D.H z z L . ",
+"% / T Y L C $ O G.H.H V N N A . ",
+"[ L.2.<.:.:.=.&.%.$. . .| } *.! ",
+"d m.v.c.z.k.j.h.f.a.a.p.u.u.y.@ ",
+"g p i y t r q q q 9 8 7 5 4 3 6 ",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.",
+"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q."
+};
diff --git a/src/images/flags/TC.xpm b/src/images/flags/TC.xpm
new file mode 100644
index 0000000..35dc6ea
--- /dev/null
+++ b/src/images/flags/TC.xpm
@@ -0,0 +1,186 @@
+/* XPM */
+static const char *TC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 164 2",
+" c black",
+". c #000000000B0B",
+"X c #000000000D0D",
+"o c #000000000F0F",
+"O c #000000001111",
+"+ c #000000001515",
+"@ c #000000001717",
+"# c #000000001D1D",
+"$ c #000000001F1F",
+"% c #000000002121",
+"& c #000000002525",
+"* c #000000002B2B",
+"= c #000000003131",
+"- c #000000003737",
+"; c #000000003D3D",
+": c #000000003F3F",
+"> c #000000004343",
+", c #000000004949",
+"< c #000000004F4F",
+"1 c #000000005555",
+"2 c #000000005B5B",
+"3 c #000000005F5F",
+"4 c #000000006161",
+"5 c #000000006363",
+"6 c #000000006565",
+"7 c #000000006969",
+"8 c #27274E4E7D7D",
+"9 c #2E2E52527E7E",
+"0 c #5D5D2D2D5D5D",
+"q c #5B5B3F3F7171",
+"w c #737321214747",
+"e c #7F7F35355B5B",
+"r c #4C4C62627474",
+"t c #57576D6D7D7D",
+"y c #00001D1D8787",
+"u c #00002F2F9595",
+"i c #1D1D37378383",
+"p c #1E1E4E4E9696",
+"a c #232352529999",
+"s c #242451519999",
+"d c #292957579C9C",
+"f c #2A2A57579C9C",
+"g c #2C2C58589A9A",
+"h c #2F2F5A5A9D9D",
+"j c #2E2E5B5B9F9F",
+"k c #2F2F5B5B9F9F",
+"l c #303055558181",
+"z c #333358588686",
+"x c #33335B5B9E9E",
+"c c #32325D5D9E9E",
+"v c #3A3A5F5F9F9F",
+"b c #2A2A5151A2A2",
+"n c #2F2F5C5CA0A0",
+"m c #30305757A9A9",
+"M c #36365B5BA6A6",
+"N c #35356060A0A0",
+"B c #34346060A2A2",
+"V c #35356161A2A2",
+"C c #39396363A3A3",
+"Z c #3A3A6464A5A5",
+"A c #3A3A6565A5A5",
+"S c #3B3B6565A5A5",
+"D c #3D3D6666A4A4",
+"F c #3E3E6565A6A6",
+"G c #3B3B6060AAAA",
+"H c #3C3C6363A8A8",
+"J c #3F3F6666ABAB",
+"K c #3F3F6969A8A8",
+"L c #525270709494",
+"P c #5F5F7B7B9E9E",
+"I c #41416666AEAE",
+"U c #42426A6AA6A6",
+"Y c #40406969A8A8",
+"T c #40406A6AA8A8",
+"R c #42426969ACAC",
+"E c #47476B6BA8A8",
+"W c #44446A6AAEAE",
+"Q c #44446D6DABAB",
+"! c #45456E6EABAB",
+"~ c #46466E6EA9A9",
+"^ c #45456D6DAEAE",
+"/ c #46466C6CAEAE",
+"( c #49496F6FACAC",
+") c #49497272AEAE",
+"_ c #4B4B7171ACAC",
+"` c #4E4E7575AEAE",
+"' c #4F4F7575AFAF",
+"] c #49497171B0B0",
+"[ c #50506F6FA8A8",
+"{ c #50507575AEAE",
+"} c #5F5F7373A9A9",
+"| c #53537979B0B0",
+" . c #53537A7AB7B7",
+".. c #54547979B1B1",
+"X. c #58587B7BB3B3",
+"o. c #58587D7DB3B3",
+"O. c #5C5C7F7FB5B5",
+"+. c #77777777A3A3",
+"@. c #7F7F7878A1A1",
+"#. c #5D5D8181B5B5",
+"$. c #727284848C8C",
+"%. c #747486868E8E",
+"&. c #61618383B8B8",
+"*. c #61618484B9B9",
+"=. c #62628585B9B9",
+"-. c #65658787BABA",
+";. c #66668888BABA",
+":. c #69698A8ABCBC",
+">. c #6A6A8B8BBDBD",
+",. c #6F6F8F8FBFBF",
+"<. c #838325254343",
+"1. c #ADAD5F5F7373",
+"2. c #BFBF6F6F7D7D",
+"3. c #CDCD19191919",
+"4. c #D5D56F6F7474",
+"5. c #E2E268686969",
+"6. c #E5E573737272",
+"7. c #E0E079797A7A",
+"8. c #E9E97C7C7979",
+"9. c #808074749C9C",
+"0. c #E0E07F7F8181",
+"q. c #B1B19B9B3E3E",
+"w. c #BCBCA3A33F3F",
+"e. c #8383BFBF4D4D",
+"r. c #B7B79F9F4747",
+"t. c #B8B8A2A24F4F",
+"y. c #9090C3C34444",
+"u. c #C8C8ACAC2E2E",
+"i. c #C8C8AEAE3535",
+"p. c #C7C7B3B33737",
+"a. c #CBCBBFBF3B3B",
+"s. c #E3E3AEAE3030",
+"d. c #E7E7BBBB3434",
+"f. c #C3C3A5A54343",
+"g. c #D2D2B2B24141",
+"h. c #DDDDBABA5050",
+"j. c #F0F0CBCB5E5E",
+"k. c #8A8A9494B9B9",
+"l. c #91918686A7A7",
+"z. c #94948686A7A7",
+"x. c #97979797B9B9",
+"c. c #A9A982829B9B",
+"v. c #BCBC85859797",
+"b. c #9696ACACD0D0",
+"n. c #9393B0B0D5D5",
+"m. c #C3C384849393",
+"M. c #D3D38A8A9292",
+"N. c #D6D69F9FA9A9",
+"B. c #D5D5AEAEB7B7",
+"V. c #D6D6ACACB6B6",
+"C. c #E1E185858787",
+"Z. c #ECEC83838181",
+"A. c #E6E694949595",
+"S. c #F1F1A6A6A4A4",
+"D. c #F0F0A8A8A7A7",
+"F. c #D4D4B9B9C4C4",
+"G. c #DDDDBABAC3C3",
+"H. c #E0E0B9B9C0C0",
+"J. c #E4E4D2D2A1A1",
+"K. c #DDDDD4D4DEDE",
+"L. c #E2E2C3C3CACA",
+"P. c #E2E2CCCCD3D3",
+"I. c #F6F6E9E9CDCD",
+"U. c None",
+/* pixels */
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"2.+.u w <.y 0 1.5 3 2 1 < , > : ",
+"i G.K.V.N.F.P.b.:.-.&.O.o.| ` - ",
+"3.A.Z.6.5.8.7.4.[ R P %.$.L ( = ",
+"e H.S.0.C.D.M.c.E H h.j.d.t.W * ",
+"} L.x.v.m.n.V.z.F I J.I.s.r.J & ",
+"q k. . at .9.^ =.l.v m g.a.p.w.G $ ",
+"7 ,.] ] ^ T A N n b f.e.y.q.M @ ",
+"6 ,._ Q T A B n f s t i.u.r x @ ",
+"5 ;.^ K A N h f a p z l 9 8 h o ",
+"2 =.#.o.| { _ ~ U F C N c h g o ",
+"1 < , > : - = * & $ $ @ O o . . ",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U."
+};
diff --git a/src/images/flags/TD.xpm b/src/images/flags/TD.xpm
new file mode 100644
index 0000000..a7e2a27
--- /dev/null
+++ b/src/images/flags/TD.xpm
@@ -0,0 +1,186 @@
+/* XPM */
+static const char *TD_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 164 2",
+" c black",
+". c #000000009393",
+"X c #000000009595",
+"o c #000003039999",
+"O c #00000F0FA1A1",
+"+ c #00001919A3A3",
+"@ c #00001B1BA5A5",
+"# c #00002121A9A9",
+"$ c #00002929ADAD",
+"% c #00002D2DAFAF",
+"& c #00002D2DB7B7",
+"* c #00003131B1B1",
+"= c #01013333B3B3",
+"- c #03033535B3B3",
+"; c #03033535B5B5",
+": c #05053737B3B3",
+"> c #15154343B9B9",
+", c #51517373CBCB",
+"< c #57577777CDCD",
+"1 c #5B5B7A7ACBCB",
+"2 c #5B5B7B7BCFCF",
+"3 c #60607E7ECDCD",
+"4 c #60607F7FCDCD",
+"5 c #61617F7FD2D2",
+"6 c #64648282CFCF",
+"7 c #65658383CECE",
+"8 c #65658484D4D4",
+"9 c #69698585D2D2",
+"0 c #69698686D1D1",
+"q c #6A6A8787D0D0",
+"w c #69698787D5D5",
+"e c #6D6D8A8AD3D3",
+"r c #6E6E8A8AD2D2",
+"t c #6E6E8A8AD6D6",
+"y c #70708C8CD2D2",
+"u c #71718E8ED3D3",
+"i c #70708D8DD4D4",
+"p c #74748F8FD5D5",
+"a c #75759090D3D3",
+"s c #75759090D5D5",
+"d c #78789393D6D6",
+"f c #7A7A9393D4D4",
+"g c #7D7D9696D6D6",
+"h c #BFBF00000000",
+"j c #C1C100000000",
+"k c #C3C300000000",
+"l c #C5C500000000",
+"z c #C9C900000000",
+"x c #CBCB00000000",
+"c c #CDCD00000000",
+"v c #CFCF00000000",
+"b c #D3D300000000",
+"n c #D7D700000000",
+"m c #D9D900000000",
+"M c #DBDB00000000",
+"N c #DFDF00000000",
+"B c #E1E125252525",
+"V c #E2E228282828",
+"C c #E2E22A2A2A2A",
+"Z c #E3E32A2A2C2C",
+"A c #E3E32C2C2D2D",
+"S c #E4E42E2E2E2E",
+"D c #E4E42E2E3131",
+"F c #E4E431313232",
+"G c #E4E432323333",
+"H c #E6E634343636",
+"J c #E6E637373737",
+"K c #E6E638383838",
+"L c #E7E739393C3C",
+"P c #E7E73C3C3D3D",
+"I c #E7E73E3E3D3D",
+"U c #E9E93E3E4141",
+"Y c #E4E442424242",
+"T c #E5E545454545",
+"R c #E6E647474848",
+"E c #E6E648484848",
+"W c #E7E748484B4B",
+"Q c #E9E941414242",
+"! c #E9E942424242",
+"~ c #EAEA45454747",
+"^ c #EAEA47474848",
+"/ c #EBEB4A4A4C4C",
+"( c #E8E84C4C4C4C",
+") c #E8E850505050",
+"_ c #E9E954545454",
+"` c #EBEB59595858",
+"' c #EBEB5D5D5D5D",
+"] c #EDED61616161",
+"[ c #EDED65656565",
+"{ c #EEEE69696A6A",
+"} c #F0F06C6C6E6E",
+"| c #CDCD97970000",
+" . c #C1C1ABAB0000",
+".. c #D1D1B7B70000",
+"X. c #D5D5B5B50000",
+"o. c #D7D7B9B90000",
+"O. c #DBDBBDBD0000",
+"+. c #E7E7BBBB0000",
+"@. c #DBDBC9C92121",
+"#. c #EBEBD5D50000",
+"$. c #EDEDD3D30101",
+"%. c #EDEDD5D50707",
+"&. c #F1F1D9D90B0B",
+"*. c #E9E9CDCD5050",
+"=. c #EAEAD0D05454",
+"-. c #ECECD1D15959",
+";. c #EDEDD3D35E5E",
+":. c #EBEBDEDE5757",
+">. c #ECECDDDD5A5A",
+",. c #EEEEDFDF5F5F",
+"<. c #EEEED5D56363",
+"1. c #EFEFD7D76767",
+"2. c #ECECD3D36868",
+"3. c #E3E3D8D87070",
+"4. c #E5E5DADA7474",
+"5. c #E6E6DCDC7979",
+"6. c #E7E7DDDD7D7D",
+"7. c #F1F1D9D96C6C",
+"8. c #ECECE0E05B5B",
+"9. c #EFEFE1E16363",
+"0. c #EEEEE2E26060",
+"q. c #EFEFE1E16464",
+"w. c #EFEFE3E36565",
+"e. c #EDEDE2E26E6E",
+"r. c #EEEEE2E27070",
+"t. c #EEEEE2E27575",
+"y. c #F0F0E2E26161",
+"u. c #F1F1E4E46666",
+"i. c #F0F0E2E26868",
+"p. c #F0F0E5E56969",
+"a. c #F2F2E5E56B6B",
+"s. c #F1F1E4E46D6D",
+"d. c #F1F1E4E46E6E",
+"f. c #F1F1E6E66F6F",
+"g. c #F3F3E7E76F6F",
+"h. c #F2F2E5E57171",
+"j. c #F2F2E5E57272",
+"k. c #F1F1E5E57777",
+"l. c #F3F3E7E77575",
+"z. c #F4F4E7E77777",
+"x. c #F2F2E8E87373",
+"c. c #F4F4E8E87474",
+"v. c #F5F5E8E87A7A",
+"b. c #F5F5EAEA7878",
+"n. c #F6F6EAEA7C7C",
+"m. c #81819A9AD8D8",
+"M. c #85859D9DD8D8",
+"N. c #87879E9EDADA",
+"B. c #88889F9FDEDE",
+"V. c #8A8AA2A2DCDC",
+"C. c #8D8DA4A4DDDD",
+"Z. c #8E8EA4A4DDDD",
+"A. c #8F8FA5A5DDDD",
+"S. c #E6E6DDDD8383",
+"D. c #E9E9DFDF8181",
+"F. c #E9E9E1E18585",
+"G. c #EBEBE2E28888",
+"H. c #EFEFE8E89E9E",
+"J. c #F4F4E1E18888",
+"K. c #F6F6EDED8E8E",
+"L. c #F7F7ECEC8F8F",
+"P. c #F7F7EDED9393",
+"I. c #F8F8EEEE9494",
+"U. c None",
+/* pixels */
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"> : : ; & @.&.%.$.#.+.N N n n n ",
+"= A.A.A.B.H.I.I.K.K.J.{ { [ ] b ",
+": A.d p t G.n.v.v.l.7./ ^ ! ' v ",
+"- C.p y 8 F.c.c.j.f.1.~ ! I ` c ",
+"= V.u r 8 F.c.j.f.p.<.U P K _ c ",
+"% N.r 9 5 6.g.f.i.w.;.L H G ) z ",
+"$ M.9 6 2 5.p.i.i.8.-.H G S ( l ",
+"# m.7 3 < 4.u.y.,.8.=.D A C E l ",
+"@ g 3 1 , 3.i.8.>.:.*.Z C B T j ",
+"O f a u 9 S.k.t.r.e.2.W T T Y j ",
+"+ o X . X .O.o.X...| l j j h j ",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.",
+"U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U."
+};
diff --git a/src/images/flags/TF.xpm b/src/images/flags/TF.xpm
new file mode 100644
index 0000000..c3fc06c
--- /dev/null
+++ b/src/images/flags/TF.xpm
@@ -0,0 +1,167 @@
+/* XPM */
+static const char *TF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 145 2",
+" c black",
+". c #000000000B0B",
+"X c #000000000D0D",
+"o c #000000000F0F",
+"O c #000000001111",
+"+ c #000000001515",
+"@ c #000000001717",
+"# c #000000001919",
+"$ c #000000001B1B",
+"% c #000000001D1D",
+"& c #000000002121",
+"* c #000000002525",
+"= c #000000002727",
+"- c #000000002B2B",
+"; c #000000002D2D",
+": c #000000003333",
+"> c #000000003939",
+", c #000000003F3F",
+"< c #000000004343",
+"1 c #000000004545",
+"2 c #000000004949",
+"3 c #000000004B4B",
+"4 c #000000005151",
+"5 c #000000005757",
+"6 c #000000005D5D",
+"7 c #000000006161",
+"8 c #000000006363",
+"9 c #000000006565",
+"0 c #000000006B6B",
+"q c #000000006F6F",
+"w c #000003037373",
+"e c #000009097575",
+"r c #000009097777",
+"t c #2D2D41419090",
+"y c #303043439191",
+"u c #313144449292",
+"i c #353548489494",
+"p c #363649499494",
+"a c #37374A4A9696",
+"s c #3A3A4D4D9595",
+"d c #3B3B4D4D9797",
+"f c #3A3A4D4D9898",
+"g c #3B3B4E4E9999",
+"h c #3C3C4E4E9999",
+"j c #3C3C4F4F9999",
+"k c #3E3E50509898",
+"l c #3F3F52529B9B",
+"z c #404051519999",
+"x c #404052529A9A",
+"c c #404053539B9B",
+"v c #424253539999",
+"b c #414153539C9C",
+"n c #424255559B9B",
+"m c #414154549C9C",
+"M c #454556569D9D",
+"N c #454557579D9D",
+"B c #444458589F9F",
+"V c #464658589F9F",
+"C c #4A4A5B5B9E9E",
+"Z c #48485A5AA0A0",
+"A c #4A4A5B5BA0A0",
+"S c #4A4A5D5DA3A3",
+"D c #4C4C5D5DA2A2",
+"F c #4E4E5F5FA1A1",
+"G c #4E4E5F5FA3A3",
+"H c #4E4E6060A3A3",
+"J c #4F4F6060A3A3",
+"K c #4F4F6262A6A6",
+"L c #50506060A2A2",
+"P c #52526363A4A4",
+"I c #53536464A2A2",
+"U c #53536464A6A6",
+"Y c #54546464A6A6",
+"T c #56566565A4A4",
+"R c #57576767A7A7",
+"E c #5A5A6969A7A7",
+"W c #58586868A8A8",
+"Q c #58586868A9A9",
+"! c #58586969A9A9",
+"~ c #5C5C6B6BA9A9",
+"^ c #5E5E6D6DA9A9",
+"/ c #5C5C6D6DACAC",
+"( c #5D5D6D6DACAC",
+") c #60606F6FACAC",
+"_ c #61617171ADAD",
+"` c #61617171AEAE",
+"' c #65657474AEAE",
+"] c #65657575AFAF",
+"[ c #66667575B1B1",
+"{ c #69697777B2B2",
+"} c #6A6A7878B2B2",
+"| c #6A6A7979B4B4",
+" . c #6D6D7B7BB3B3",
+".. c #6E6E7C7CB3B3",
+"X. c #6E6E7C7CB5B5",
+"o. c #6F6F7F7FB7B7",
+"O. c #71717F7FB7B7",
+"+. c #72728080B6B6",
+"@. c #75758181B3B3",
+"#. c #77778484B4B4",
+"$. c #74748383BABA",
+"%. c #76768484B9B9",
+"&. c #7B7B8888B7B7",
+"*. c #7A7A8888BBBB",
+"=. c #7D7D8989B8B8",
+"-. c #7D7D8989B9B9",
+";. c #7F7F8B8BBEBE",
+":. c #FBFB00000000",
+">. c #FDFD00000000",
+",. c #F8F836363636",
+"<. c #F9F93B3B3B3B",
+"1. c #F9F93B3B3C3C",
+"2. c #FAFA40404040",
+"3. c #FAFA41414141",
+"4. c #FAFA41414242",
+"5. c #FBFB46464646",
+"6. c #FBFB47474747",
+"7. c #FCFC4B4B4B4B",
+"8. c #FCFC4C4C4C4C",
+"9. c #FDFD51515151",
+"0. c #FCFC69696969",
+"q. c #FDFD6D6D6D6D",
+"w. c #FDFD70707171",
+"e. c #82828E8EBFBF",
+"r. c #85859191C1C1",
+"t. c #88889494C3C3",
+"y. c #8A8A9595C5C5",
+"u. c #8C8C9898C5C5",
+"i. c #8C8C9898C6C6",
+"p. c #8D8D9898C6C6",
+"a. c #91919B9BC2C2",
+"s. c #BBBBC1C1D5D5",
+"d. c #BCBCC2C2D7D7",
+"f. c #DCDCDEDEE7E7",
+"g. c #DFDFE1E1E7E7",
+"h. c #E2E2E4E4EAEA",
+"j. c #E6E6E8E8EDED",
+"k. c #E8E8E9E9EEEE",
+"l. c #FBFBFBFBFBFB",
+"z. c gray99",
+"x. c #FDFDFCFCFDFD",
+"c. c #FDFDFDFDFDFD",
+"v. c #FEFEFEFEFEFE",
+"b. c gray100",
+"n. c None",
+/* pixels */
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"r r r b.b.b.:.:.:.7 6 5 4 2 < 2 ",
+"r p.p.b.b.b.w.q.0.o. .{ ] ) ~ > ",
+"r p.+.b.b.l.9.8.6.K F N b h R : ",
+"r t.O.b.b.b.6.5.3.S N b g a P - ",
+"w t.X.b.l.l.5.3.1.Z l g a u F * ",
+"q r.{ b.l.l.2.1.,.j h a y t C % ",
+"0 r.[ / / ~ P P Z Z =.k.j.f.&.$ ",
+"9 ;.[ / R U F Z M l n =.d.l l + ",
+"7 *./ Q U G Z N h g I h.d.g. at .O ",
+"6 $.O...} ] _ ^ ~ Y I a.h.#.s o ",
+"5 4 2 1 < > : - * % % $ O o . $ ",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n."
+};
diff --git a/src/images/flags/TG.xpm b/src/images/flags/TG.xpm
new file mode 100644
index 0000000..c7a73c7
--- /dev/null
+++ b/src/images/flags/TG.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *TG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000027270000",
+"X c #000029290000",
+"o c #00002B2B0000",
+"O c #00002D2D0000",
+"+ c #00002F2F0000",
+"@ c #000031310000",
+"# c #000033330000",
+"$ c #000037370000",
+"% c #00003D3D0000",
+"& c #00003F3F0000",
+"* c #000045450000",
+"= c #00004B4B0000",
+"- c #00004D4D0000",
+"; c #00004F4F0000",
+": c #000051510000",
+"> c #000055550000",
+", c #00005B5B0000",
+"< c #00005F5F0000",
+"1 c #000061610000",
+"2 c #000065650000",
+"3 c #00006B6B0000",
+"4 c #00006F6F0000",
+"5 c #000071710000",
+"6 c #000073730000",
+"7 c #000077770000",
+"8 c #000087870000",
+"9 c #1A1A97971A1A",
+"0 c #1F1F9A9A1F1F",
+"q c #25259D9D2525",
+"w c #2A2AA0A02B2B",
+"e c #3030A3A32C2C",
+"r c #3333A4A42F2F",
+"t c #3030A3A33030",
+"y c #3535A6A63232",
+"u c #3636A6A63636",
+"i c #3B3BA6A63B3B",
+"p c #3939A8A83535",
+"a c #3D3DAAAA3939",
+"s c #3B3BB1B13B3B",
+"d c #4B4BA3A31414",
+"f c #4F4FA5A51919",
+"g c #5454A8A81F1F",
+"h c #4141ADAD3D3D",
+"j c #5B5BA9A92020",
+"k c #5858ABAB2424",
+"l c #5F5FACAC2525",
+"z c #5D5DADAD2A2A",
+"x c #5555B0B03535",
+"c c #6363AEAE2B2B",
+"v c #6161B0B02F2F",
+"b c #6767B1B13030",
+"n c #6565B0B03636",
+"m c #6B6BB4B43636",
+"M c #6F6FB6B63C3C",
+"N c #7272B5B53F3F",
+"B c #4545AEAE4242",
+"V c #4A4AB0B04646",
+"C c #4E4EB3B34B4B",
+"Z c #5050B4B44E4E",
+"A c #5353B5B55050",
+"S c #5454B7B75353",
+"D c #5757B8B85555",
+"F c #5959B9B95757",
+"G c #5B5BBABA5858",
+"H c #5E5EBBBB5C5C",
+"J c #6060BCBC5D5D",
+"K c #7474BEBE4141",
+"L c #6262BEBE6060",
+"P c #6565BEBE6262",
+"I c #6666C0C06565",
+"U c #6A6AC2C26969",
+"Y c #6F6FC9C96D6D",
+"T c #ABAB7D7D0000",
+"R c #FDFD00000000",
+"E c red",
+"W c #F9F946464646",
+"Q c #FBFB46464646",
+"! c #FAFA4B4B4B4B",
+"~ c #FCFC4B4B4B4B",
+"^ c #FBFB50505050",
+"/ c #FBFB51515151",
+"( c #FBFB55555454",
+") c #FCFC55555555",
+"_ c #FCFC56565656",
+"` c #FCFC59595959",
+"' c #FDFD5B5B5B5B",
+"] c #FDFD5E5E5E5E",
+"[ c #FEFE71717272",
+"{ c #FDFD77777777",
+"} c #FEFE76767676",
+"| c #FEFE77777777",
+" . c #FDFD79797A7A",
+".. c #FEFE7B7B7B7B",
+"X. c #FFFF7B7B7B7B",
+"o. c #FEFE7D7D7D7D",
+"O. c #FEFE7E7E7E7E",
+"+. c #DFDF8D8D0000",
+"@. c #D5D597970000",
+"#. c #D3D3B1B10000",
+"$. c #D6D6BEBE0B0B",
+"%. c #E7E79D9D0000",
+"&. c #D7D7C0C00E0E",
+"*. c #D9D9C2C21313",
+"=. c #DADAC4C41919",
+"-. c #DCDCC6C61E1E",
+";. c #DDDDC7C72323",
+":. c #DFDFCACA2929",
+">. c #DCDCC8C82F2F",
+",. c #FBFBC5C50000",
+"<. c #F2F2C7C71010",
+"1. c #F2F2C9C91414",
+"2. c #F3F3CACA1919",
+"3. c #F4F4CCCC1F1F",
+"4. c #E1E1CCCC2E2E",
+"5. c #EBEBCECE2C2C",
+"6. c #E2E2CECE3434",
+"7. c #E4E4CFCF3A3A",
+"8. c #E4E4D1D13F3F",
+"9. c #EDEDD0D03131",
+"0. c #EEEED2D23737",
+"q. c #EFEFD4D43D3D",
+"w. c #F5F5CECE2424",
+"e. c #F5F5CFCF2626",
+"r. c #F3F3CECE3232",
+"t. c #F6F6D0D02A2A",
+"y. c #F6F6D1D12B2B",
+"u. c #F7F7D2D22F2F",
+"i. c #F7F7D3D33131",
+"p. c #F8F8D5D53434",
+"a. c #F8F8D5D53636",
+"s. c #F9F9D6D63C3C",
+"d. c #F9F9D9D93A3A",
+"f. c #FAFADADA3F3F",
+"g. c #E6E6D3D34444",
+"h. c #EDEDD5D54949",
+"j. c #EDEDDADA4C4C",
+"k. c #F0F0D5D54242",
+"l. c #F1F1D7D74747",
+"z. c #F6F6D6D64444",
+"x. c #FAFAD8D84242",
+"c. c #FBFBDCDC4545",
+"v. c #FBFBDDDD4949",
+"b. c #EBEBDCDC6666",
+"n. c #FBFBE3E34747",
+"m. c #FCFCE4E46A6A",
+"M. c #FFFF83838383",
+"N. c #FEFE87878787",
+"B. c #FEFE9B9B9B9B",
+"V. c #FDFDB3B3B4B4",
+"C. c #FEFEB7B7B7B7",
+"Z. c #FEFED0D0D0D0",
+"A. c #FEFEDADADADA",
+"S. c #FDFDDEDEDEDE",
+"D. c #FDFDE4E4E4E4",
+"F. c #FEFEFEFEFEFE",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"E E E E R E E 8 7 6 4 3 2 1 , < ",
+"E X.X.o.} o.X.Y U I L H F S Z - ",
+"E M.B.Z.[ ] ' j.l.k.q.0.9.5.h. at .",
+"E o.A.F.S.' _ n.x.s.a.i.y.e.z.%.",
+"E } C.D.V.! / K M m b c l j N : ",
+"E N.] ' _ Q ! s u t w q 0 9 i + ",
+"E { ` ( ~ ! W x v z j g f d n * ",
+",.m.c.c.x.d.a.u.y.w.3.2.1.<.r.+.",
+"#.b.g.8.8.6.4.:.;.-.=.*.&.$.>.T ",
+"6 P H G F A C V B h a p y t e o ",
+"6 2 1 , > : = * % % $ @ + o . @ ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/TH.xpm b/src/images/flags/TH.xpm
new file mode 100644
index 0000000..af48aef
--- /dev/null
+++ b/src/images/flags/TH.xpm
@@ -0,0 +1,166 @@
+/* XPM */
+static const char *TH_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 144 2",
+" c black",
+". c #000000002525",
+"X c #000000003131",
+"o c #000000003333",
+"O c #000000005B5B",
+"+ c #000000007373",
+"@ c #000000007B7B",
+"# c #000000007D7D",
+"$ c #000000007F7F",
+"% c #0B0B0D0D9999",
+"& c #141414149494",
+"* c #191919199696",
+"= c #1A1A1A1A9A9A",
+"- c #1F1F1F1F9999",
+"; c #1F1F1F1F9D9D",
+": c #202020209B9B",
+"> c #242424249C9C",
+", c #252525259E9E",
+"< c #252525259F9F",
+"1 c #2A2A2A2A9F9F",
+"2 c #2B2B2B2BA1A1",
+"3 c #2A2A2B2BA3A3",
+"4 c #2F2F2F2FA2A2",
+"5 c #30303030A4A4",
+"6 c #30303030A5A5",
+"7 c #36363636A3A3",
+"8 c #35353535A5A5",
+"9 c #36363636A7A7",
+"0 c #36363636A8A8",
+"q c #3B3B3B3BA7A7",
+"w c #3B3B3B3BA9A9",
+"e c #3B3B3B3BAAAA",
+"r c #3B3B3B3BABAB",
+"t c #3F3F3F3FA9A9",
+"y c #40404040AAAA",
+"u c #41414141ACAC",
+"i c #40404040AEAE",
+"p c #45454545ADAD",
+"a c #46464646AFAF",
+"s c #41414545B1B1",
+"d c #46464646B1B1",
+"f c #49494A4AB0B0",
+"g c #4B4B4A4AB3B3",
+"h c #4B4B4B4BB2B2",
+"j c #4F4F4F4FB2B2",
+"k c #4F4F4F4FB5B5",
+"l c #4E4E5050AFAF",
+"z c #50504F4FB4B4",
+"x c #51515353B1B1",
+"c c #53535353B7B7",
+"v c #55555757B3B3",
+"b c #54545454B6B6",
+"n c #59595B5BB5B5",
+"m c #58585858B8B8",
+"M c #5D5D5F5FB8B8",
+"N c #62626363BABA",
+"B c #66666767BCBC",
+"V c #67676969BABA",
+"C c #6A6A6C6CBFBF",
+"Z c #6F6F6F6FC0C0",
+"A c #6E6E7070C1C1",
+"S c #72727272C4C4",
+"D c #73737474C3C3",
+"F c #76767676C5C5",
+"G c #77777979C2C2",
+"H c #77777878C6C6",
+"J c #7B7B7B7BC4C4",
+"K c #7B7B7C7CC7C7",
+"L c #7F7F8080C6C6",
+"P c #DDDD00000000",
+"I c #DFDF00000000",
+"U c #E1E100000000",
+"Y c #E3E300000000",
+"T c #E5E500000000",
+"R c #E7E700000000",
+"E c #E9E900000000",
+"W c #EBEB00000000",
+"Q c #EDED00000000",
+"! c #EFEF00000000",
+"~ c #F1F100000000",
+"^ c #F3F300000000",
+"/ c #F5F500000000",
+"( c #F7F700000000",
+") c #F9F900000000",
+"_ c #FBFB00000000",
+"` c #FDFD00000000",
+"' c red",
+"] c #F2F243434343",
+"[ c #F2F246464646",
+"{ c #F2F249494949",
+"} c #F3F34B4B4B4B",
+"| c #F4F44F4F4F4F",
+" . c #F5F553535353",
+".. c #F6F657575757",
+"X. c #F7F758585858",
+"o. c #F7F75B5B5B5B",
+"O. c #F8F85C5C5C5C",
+"+. c #F7F760606060",
+"@. c #F9F960606060",
+"#. c #F8F863636464",
+"$. c #FAFA65656565",
+"%. c #F9F968686868",
+"&. c #F9F96B6B6B6B",
+"*. c #FBFB6A6A6A6A",
+"=. c #FAFA6F6F6F6F",
+"-. c #FCFC6E6E6E6E",
+";. c #FBFB74747474",
+":. c #FCFC72727272",
+">. c #FDFD75757575",
+",. c #FDFD79797A7A",
+"<. c #FEFE7B7B7B7B",
+"1. c #FEFE7F7F7F7F",
+"2. c #82828383C8C8",
+"3. c #85858787CACA",
+"4. c #8A8A8B8BCBCB",
+"5. c #89898A8ACCCC",
+"6. c #8C8C8E8ECFCF",
+"7. c #90909191D0D0",
+"8. c #93939494D2D2",
+"9. c #93939595D2D2",
+"0. c #96969797D4D4",
+"q. c #98989A9AD5D5",
+"w. c #9B9B9C9CD6D6",
+"e. c #ADADAEAEDDDD",
+"r. c #FEFE81818080",
+"t. c #FFFF83838383",
+"y. c #DFDFDFDFDFDF",
+"u. c #E9E9E9E9E9E9",
+"i. c #F1F1F1F1F1F1",
+"p. c gray95",
+"a. c #F3F3F3F3F3F3",
+"s. c #F4F4F4F4F4F4",
+"d. c gray96",
+"f. c #F6F6F6F6F6F6",
+"g. c gray97",
+"h. c #F8F8F8F8F8F8",
+"j. c #F9F9F9F9F9F9",
+"k. c gray98",
+"l. c #FBFBFBFBFBFB",
+"z. c gray99",
+"x. c #FDFDFDFDFDFD",
+"c. c #FEFEFEFEFEFE",
+"v. c gray100",
+"b. c None",
+/* pixels */
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"' ' ' ' _ ' ' ' _ _ ( ( ^ ^ Q Q ",
+"' t.t.1.1.<.<.;.:.-.*.$. at .o.X.W ",
+"v.v.v.v.v.v.l.v.v.h.h.h.g.g.g.u.",
+"s e.w.q.9.9.7.6.5.3.2.L J G 4.# ",
+"# F m b j h a u w 9 6 2 < : t o ",
+"@ S c k g d i r 0 4 3 < : = w X ",
+"+ A j f p y w 8 4 2 > - * & 7 . ",
+"% 9.K H D A Z N N M n b x l V O ",
+"h.v.l.l.h.g.g.f.g.a.p.p.p.p.p.y.",
+"( ;.=.&.*.+.+.o... . .{ { [ ] P ",
+"( ^ ^ Q Q Q W W R R U U P P P P ",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b."
+};
diff --git a/src/images/flags/TJ.xpm b/src/images/flags/TJ.xpm
new file mode 100644
index 0000000..55ebbd5
--- /dev/null
+++ b/src/images/flags/TJ.xpm
@@ -0,0 +1,138 @@
+/* XPM */
+static const char *TJ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 116 2",
+" c black",
+". c #000007070000",
+"X c #00000F0F0000",
+"o c #000017170000",
+"O c #00001D1D0000",
+"+ c #000025250000",
+"@ c #0B0B64640B0B",
+"# c #0F0F67670E0E",
+"$ c #13136A6A1313",
+"% c #18186D6D1919",
+"& c #1E1E71711E1E",
+"* c #232375752323",
+"= c #292978782929",
+"- c #2C2C79792C2C",
+"; c #2F2F7A7A2F2F",
+": c #2F2F7B7B2F2F",
+"> c #2E2E7C7C2E2E",
+", c #32327D7D3232",
+"< c #35357F7F3535",
+"1 c #343480803434",
+"2 c #393982823939",
+"3 c #3A3A84843A3A",
+"4 c #3D3D84843D3D",
+"5 c #3F3F87873F3F",
+"6 c #424288884242",
+"7 c #44448B8B4444",
+"8 c #46468A8A4646",
+"9 c #4B4B8E8E4B4B",
+"0 c #505091915050",
+"q c #545494945555",
+"w c #585897975858",
+"e c #5D5D9A9A5D5D",
+"r c #61619E9E6262",
+"t c #6666A1A16666",
+"y c #959500000000",
+"u c #999900000000",
+"i c #9D9D00000000",
+"p c #A1A100000000",
+"a c #A5A500000000",
+"s c #A7A700000000",
+"d c #ABAB00000000",
+"f c #AFAF00000000",
+"g c #B1B100000000",
+"h c #B3B300000000",
+"j c #B7B700000000",
+"k c #BBBB00000000",
+"l c #BDBD00000000",
+"z c #BFBF00000000",
+"x c #CECE2C2C2C2C",
+"c c #D0D031313131",
+"v c #D1D137373737",
+"b c #D3D33C3C3D3D",
+"n c #D5D542424242",
+"m c #D6D647474747",
+"M c #D4D449494949",
+"N c #D6D64E4E4E4E",
+"B c #D8D84C4C4C4C",
+"V c #D9D951515151",
+"C c #D8D853535353",
+"Z c #D9D957575757",
+"A c #DBDB54545454",
+"S c #DADA5C5C5C5C",
+"D c #DDDD59595959",
+"F c #DDDD5C5C5C5C",
+"G c #DEDE5F5F5F5F",
+"H c #DCDC60606060",
+"J c #DDDD65656565",
+"K c #DEDE69696969",
+"L c #DFDF6D6D6D6D",
+"P c #E1E170707171",
+"I c #E2E274747474",
+"U c #E2E277777777",
+"Y c #E3E379797979",
+"T c #E4E47B7B7A7A",
+"R c #E4E47B7B7B7B",
+"E c #F5F5CFCF5D5D",
+"W c #F6F6D1D16161",
+"Q c #F3F3D4D47575",
+"! c #F5F5D6D67373",
+"~ c #F4F4D6D67878",
+"^ c #F5F5D8D87E7E",
+"/ c #F7F7D9D97D7D",
+"( c #F7F7DBDB8383",
+") c #F8F8DDDD8C8C",
+"_ c #F8F8DEDE8D8D",
+"` c #F6F6DFDF9797",
+"' c #F7F7E1E19A9A",
+"] c #F7F7E1E19B9B",
+"[ c #F8F8E2E29E9E",
+"{ c #F9F9E5E5A8A8",
+"} c #F8F8E5E5ABAB",
+"| c #F9F9E9E9B6B6",
+" . c LightGray",
+".. c #D5D5D5D5D5D5",
+"X. c #D7D7D7D7D7D7",
+"o. c gray86",
+"O. c #F8F8F2F2DDDD",
+"+. c #F8F8F6F6EEEE",
+"@. c #F1F1F1F1F1F1",
+"#. c gray95",
+"$. c #F3F3F3F3F3F3",
+"%. c #F4F4F4F4F4F4",
+"&. c #F4F4F5F5F5F5",
+"*. c gray96",
+"=. c #F6F6F6F6F6F6",
+"-. c gray97",
+";. c #F8F8F8F8F8F8",
+":. c #F9F9F9F9F9F9",
+">. c gray98",
+",. c #FBFBFBFBFBFB",
+"<. c #FBFBFCFCFBFB",
+"1. c gray99",
+"2. c #FDFDFCFCFDFD",
+"3. c #FDFDFDFDFDFD",
+"4. c #FEFEFEFEFEFE",
+"5. c None",
+/* pixels */
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"z z z z z j z j h h f d a a p i ",
+"z R R Y U I P L K J H S Z A N u ",
+"z R G F F A A B M n b v c x M y ",
+"*.4.4.4.,.4.~ { } ! +.:.*.*.*.o.",
+"*.4.4.4.2.) | [ [ O.~ *.*.*.*.X.",
+"#.4.4.,.) ;.;.] ` -.*.! $.$.*...",
+"#.4.,.4.4.4.( W E ~ *.*.$.$.$. .",
+"#.;.4.;.;.;.;.-.*.*.*.$.$.$.$. .",
+"+ t 7 5 3 1 > = * & % $ # @ ; ",
+"O r e w q 0 9 8 6 4 2 < , ; - ",
+"o o . ",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.",
+"5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5."
+};
diff --git a/src/images/flags/TK.xpm b/src/images/flags/TK.xpm
new file mode 100644
index 0000000..46bd968
--- /dev/null
+++ b/src/images/flags/TK.xpm
@@ -0,0 +1,179 @@
+/* XPM */
+static const char *TK_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 157 2",
+" c black",
+". c #000000007171",
+"X c #000000007373",
+"o c #000000007777",
+"O c #000000007979",
+"+ c #000000007B7B",
+"@ c #000000007D7D",
+"# c #000000007F7F",
+"$ c #40407C7C6868",
+"% c #000000008181",
+"& c #000000008383",
+"* c #000000008585",
+"= c #000000008787",
+"- c #000000008D8D",
+"; c #000000009191",
+": c #000000009393",
+"> c #000000009999",
+", c #000000009D9D",
+"< c #00000000A1A1",
+"1 c #00000000A5A5",
+"2 c #00000000A7A7",
+"3 c #00000000A9A9",
+"4 c #00000000ABAB",
+"5 c #00000000ADAD",
+"6 c #00000000AFAF",
+"7 c #00000000B3B3",
+"8 c #00000000B5B5",
+"9 c #00000000B9B9",
+"0 c #00000000BBBB",
+"q c #0B0B2C2CBEBE",
+"w c #10103030BFBF",
+"e c #13133434BBBB",
+"r c #00000000C3C3",
+"t c #00000101C3C3",
+"y c #00000303C5C5",
+"u c #00000505C5C5",
+"i c #00000B0BC5C5",
+"p c #14143535C1C1",
+"a c #1A1A3A3AC4C4",
+"s c #20203F3FC6C6",
+"d c #2A2A5656B9B9",
+"f c #2D2D5A5AB1B1",
+"g c #26264545C8C8",
+"h c #2C2C4848C6C6",
+"j c #2F2F4B4BC7C7",
+"k c #2C2C4949CACA",
+"l c #2F2F4B4BC8C8",
+"z c #2F2F4C4CCFCF",
+"x c #32324D4DC8C8",
+"c c #33334E4EC8C8",
+"v c #36365151C9C9",
+"b c #36365151CFCF",
+"n c #3B3B5656CCCC",
+"m c #3F3F5A5ACDCD",
+"M c #35355151D0D0",
+"N c #3B3B5656D1D1",
+"B c #3B3B5656D2D2",
+"V c #46465D5DBCBC",
+"C c #44446161BEBE",
+"Z c #44445E5ECFCF",
+"A c #41415B5BD2D2",
+"S c #44445F5FD2D2",
+"D c #49496363D1D1",
+"F c #49496363D4D4",
+"G c #4E4E6767D3D3",
+"H c #4F4F6868D6D6",
+"J c #52526868C3C3",
+"K c #51516C6CC5C5",
+"L c #53536B6BD4D4",
+"P c #55556E6ED3D3",
+"I c #53536C6CD8D8",
+"U c #58586F6FD6D6",
+"Y c #5D5D7777D2D2",
+"T c #5F5F7676D4D4",
+"R c #58587171D9D9",
+"E c #58587070DADA",
+"W c #5D5D7575D8D8",
+"Q c #5C5C7A7ADFDF",
+"! c #5F5F7D7DE0E0",
+"~ c #65657878C8C8",
+"^ c #6D6D7F7FCCCC",
+"/ c #61617878D9D9",
+"( c #60607C7CDCDC",
+") c #66667C7CDBDB",
+"_ c #5252A0A03B3B",
+"` c #5757A3A33F3F",
+"' c #434380806B6B",
+"] c #49498A8A6565",
+"[ c #5A5A8E8E7E7E",
+"{ c #5B5BA4A45050",
+"} c #6060A4A44848",
+"| c #7A7A83838D8D",
+" . c #7B7B8B8BBEBE",
+".. c #6A6A8080DDDD",
+"X. c #6F6F8484DEDE",
+"o. c #72728686DFDF",
+"O. c #7F7F9191DADA",
+"+. c #76768A8AE0E0",
+"@. c #79799191E5E5",
+"#. c #79799292E5E5",
+"$. c #7B7B9494E6E6",
+"%. c #969696966262",
+"&. c #A3A3A6A65E5E",
+"*. c #AFAFB0B05D5D",
+"=. c #A7A7A4A46464",
+"-. c #A4A4A5A56B6B",
+";. c #A6A6A6A67979",
+":. c #A7A7A8A87A7A",
+">. c #B0B0B1B16161",
+",. c #B0B0B1B16464",
+"<. c #B4B4B5B56868",
+"1. c #B7B7B9B96B6B",
+"2. c #B0B0B2B27D7D",
+"3. c #B4B4B4B47F7F",
+"4. c #B7B7B8B87272",
+"5. c #B8B8B6B67F7F",
+"6. c #BABAB8B87171",
+"7. c #BABABCBC7A7A",
+"8. c #C5C5BABA4545",
+"9. c #C1C1BBBB5A5A",
+"0. c #CACAC2C25555",
+"q. c #CCCCC4C45959",
+"w. c #CECEC8C85D5D",
+"e. c #D9D9CECE4D4D",
+"r. c #D3D3CBCB5858",
+"t. c #DDDDD2D25858",
+"y. c #CFCFC8C86060",
+"u. c #C9C9C6C67979",
+"i. c #D6D6CDCD6E6E",
+"p. c #D8D8D0D06565",
+"a. c #DFDFD9D97C7C",
+"s. c #EAEADBDB4B4B",
+"d. c #EBEBDDDD5050",
+"f. c #F3F3E6E67070",
+"g. c #F4F4E8E87474",
+"h. c #82828E8E8282",
+"j. c #81818E8E8888",
+"k. c #898990908E8E",
+"l. c #8B8B97978E8E",
+"z. c #8B8B93939C9C",
+"x. c #8C8C99999191",
+"c. c #91919E9E8181",
+"v. c #91919C9C9999",
+"b. c #8C8C9696A7A7",
+"n. c #9D9DA9A98E8E",
+"m. c #9797A2A29B9B",
+"M. c #A0A0A5A59595",
+"N. c #A1A1A7A79B9B",
+"B. c #A0A0ABAB9292",
+"V. c #A4A4B0B09393",
+"C. c #AAAAAFAFA1A1",
+"Z. c #B3B3B8B8AEAE",
+"A. c #E3E3DCDC8686",
+"S. c #E2E2E7E7F6F6",
+"D. c #E7E7EAEAF8F8",
+"F. c #E9E9EBEBF7F7",
+"G. c None",
+/* pixels */
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"i u u u r 0 8 2 < 5 5 4 2 < , , ",
+"y $.$.$.O.Z.A.g.f.a.V...R L G : ",
+"u $.Q ( D. .u.V.B.n.r.:.V h D : ",
+"y @.Q E T F.Y 3.2.6.1.0.| g Z - ",
+"r +.E N.b.P S.A N l.<.| =.g m * ",
+"0 +.I i.m.7.K m b C ,.| 8.s n # ",
+"8 X.L 5.v.t.x.v x d { } %.e v # ",
+"7 ) G z.6.w.e.*.-.f ] ` $ w v + ",
+"7 ) D C :.q.n.>.*.=.' _ e q j + ",
+"4 / T R ..n.t.d.s.t.| | c j h o ",
+"4 2 < , > > - X . # # + + + + + ",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.",
+"G.G.G.G.G.G.G.G.G.G.G.G.G.G.G.G."
+};
diff --git a/src/images/flags/TL.xpm b/src/images/flags/TL.xpm
new file mode 100644
index 0000000..4f91f07
--- /dev/null
+++ b/src/images/flags/TL.xpm
@@ -0,0 +1,157 @@
+/* XPM */
+static const char *TL_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 135 2",
+" c black",
+". c #454500000000",
+"X c #717119190000",
+"o c #494949494949",
+"O c #4B4B4A4A4B4B",
+"+ c #4C4C4C4C5252",
+"@ c #545454545858",
+"# c gray36",
+"$ c #717171714545",
+"% c gray40",
+"& c #6D6D6D6D6D6D",
+"* c #797979797979",
+"= c #7B7B7B7B7A7A",
+"- c #7A7A80804545",
+"; c #7F7F81815050",
+": c #DDDD00000000",
+"> c #DFDF00000000",
+", c #E1E100000000",
+"< c #E3E300000000",
+"1 c #E5E500000000",
+"2 c #E7E700000000",
+"3 c #E9E900000000",
+"4 c #EBEB00000000",
+"5 c #EDED00000000",
+"6 c #EFEF00000000",
+"7 c #F1F100000000",
+"8 c #F3F300000000",
+"9 c #F5F500000000",
+"0 c #F7F700000000",
+"q c #F1F10B0B0B0B",
+"w c #F1F10F0F0E0E",
+"e c #F9F900000000",
+"r c #FBFB00000000",
+"t c #FDFD00000000",
+"y c red",
+"u c #FFFF09090000",
+"i c #F2F210101010",
+"p c #F2F213131313",
+"a c #F2F214141414",
+"s c #F3F319191919",
+"d c #F3F31A1A1A1A",
+"f c #F4F41E1E1E1E",
+"g c #F4F41F1F1F1F",
+"h c #F4F420202020",
+"j c #F5F523232323",
+"k c #F5F524242424",
+"l c #F5F525252525",
+"z c #F5F526262626",
+"x c #F2F22C2C2C2C",
+"c c #F2F22F2F2F2F",
+"v c #F6F629292929",
+"b c #F6F62A2A2A2A",
+"n c #F6F62B2B2B2B",
+"m c #F6F62C2C2C2C",
+"M c #F7F72E2E2E2E",
+"N c #F7F72F2F2F2F",
+"B c #F2F232323232",
+"V c #F3F332323232",
+"C c #F3F335353535",
+"Z c #F7F730303030",
+"A c #F7F731313131",
+"S c #F4F436363636",
+"D c #F7F73A3A3030",
+"F c #F4F439393939",
+"G c #F4F43B3B3B3B",
+"H c #F5F53D3D3D3D",
+"J c #F5F53F3F3F3F",
+"K c #F8F834343434",
+"L c #F8F836363636",
+"P c #F8F837373636",
+"I c #F8F837373737",
+"U c #F9F93C3C3C3C",
+"Y c #F9F93C3C3D3D",
+"T c #F9F943433D3D",
+"R c #F8F84C4C3535",
+"E c #F9F976763B3B",
+"W c #F6F642424242",
+"Q c #F6F644444444",
+"! c #F7F746464646",
+"~ c #F7F749494949",
+"^ c #F7F74B4B4B4B",
+"/ c #F7F74E4E4E4E",
+"( c #FAFA41414242",
+") c #FAFA42424242",
+"_ c #FBFB47474747",
+"` c #FCFC4C4C4C4C",
+"' c #FCFC5C5C4C4C",
+"] c #F8F850505050",
+"[ c #F8F853535353",
+"{ c #F9F954545555",
+"} c #F9F957575757",
+"| c #FDFD51515151",
+" . c #FDFD54545454",
+".. c #FAFA5C5C5C5C",
+"X. c #F9F966665959",
+"o. c #FBFB60606060",
+"O. c #FCFC65656565",
+"+. c #FCFC69696969",
+"@. c #FDFD6D6D6D6D",
+"#. c #FDFD70707171",
+"$. c #FEFE74747474",
+"%. c #FEFE77777777",
+"&. c #81818A8A4444",
+"*. c #8E8E8D8D4747",
+"=. c #8F8F96965959",
+"-. c #9D9D96966262",
+";. c #9A9AA2A25F5F",
+":. c #B3B3ABAB7C7C",
+">. c #F8F887873636",
+",. c #F8F88B8B3838",
+"<. c #F9F9B3B33C3C",
+"1. c #FAFA86864242",
+"2. c #FEFE85855A5A",
+"3. c #FEFE81817A7A",
+"4. c #F7F7ADAD5E5E",
+"5. c #FDFDB6B65151",
+"6. c #FDFDBABA7C7C",
+"7. c #F2F2D7D73F3F",
+"8. c #F9F9E5E53B3B",
+"9. c #F9F9F9F93C3C",
+"0. c #F9F9DDDD5D5D",
+"q. c #E1E1E8E84141",
+"w. c #E8E8EFEF4C4C",
+"e. c #EEEEF0F04040",
+"r. c #FBFBE1E14747",
+"t. c #F9F9FAFA4040",
+"y. c #F6F6F3F35555",
+"u. c #A3A3A3A3A2A2",
+"i. c #A4A4A4A4A4A4",
+"p. c #D5D5D5D5D5D5",
+"a. c #D7D7D7D7D7D7",
+"s. c #D7D7D7D7D8D8",
+"d. c #EEEEEDEDEDED",
+"f. c gray96",
+"g. c None",
+/* pixels */
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"X u y y r y y y r r 0 0 8 8 5 5 ",
+" :.6.%.%.%.#. at .+.O.o...} [ / 4 ",
+" = ;.0.2. .| ` _ ( Y I A M ~ 4 ",
+" = # =.y.5.' _ ( U S A n z Q 1 ",
+" i.a.@ ; w.r.1.T I Z n z h T 1 ",
+" d.f.a.O *.t.9.,.N n z f s G 1 ",
+" i.a.+ $ q.8.>.D n z f s p S 1 ",
+" & o $ e.<.R A n j f s p p B > ",
+" % &.7.E I M n j f s p w q c > ",
+" -.4.X.{ ] ~ Q ( H F C B c c > ",
+". 8 7 7 5 5 4 4 1 1 , , > > : : ",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g."
+};
diff --git a/src/images/flags/TM.xpm b/src/images/flags/TM.xpm
new file mode 100644
index 0000000..710eec6
--- /dev/null
+++ b/src/images/flags/TM.xpm
@@ -0,0 +1,166 @@
+/* XPM */
+static const char *TM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 144 2",
+" c black",
+". c #000007070000",
+"X c #00000F0F0000",
+"o c #000015150000",
+"O c #000017170000",
+"+ c #00001D1D0000",
+"@ c #000023230000",
+"# c #000025250000",
+"$ c #00002B2B0000",
+"% c #00002D2D0000",
+"& c #00002F2F0000",
+"* c #000031310000",
+"= c #000035350000",
+"- c #000037370000",
+"; c #000039390000",
+": c #0B0B63632D2D",
+"> c #0D0D60602D2D",
+", c #101062623131",
+"< c #111163633131",
+"1 c #151566663535",
+"2 c #161666663535",
+"3 c #161666663636",
+"4 c #1A1A69693A3A",
+"5 c #1B1B6A6A3A3A",
+"6 c #1B1B6A6A3B3B",
+"7 c #20206D6D3D3D",
+"8 c #20206E6E3E3E",
+"9 c #21216E6E3F3F",
+"0 c #22226E6E4040",
+"q c #252571714242",
+"w c #262671714343",
+"e c #262672724343",
+"r c #272772724444",
+"t c #272772724545",
+"y c #282873734545",
+"u c #2B2B74744747",
+"i c #2C2C75754747",
+"p c #2B2B75754848",
+"a c #2C2C75754848",
+"s c #2C2C76764949",
+"d c #2D2D76764A4A",
+"f c #2E2E76764A4A",
+"g c #303076764B4B",
+"h c #303077774B4B",
+"j c #303078784C4C",
+"k c #313178784C4C",
+"l c #31317A7A4D4D",
+"z c #333379794E4E",
+"x c #33337B7B4F4F",
+"c c #34347A7A4E4E",
+"v c #33337B7B5050",
+"b c #36367B7B5151",
+"n c #36367C7C5151",
+"m c #37377C7C5151",
+"M c #36367D7D5252",
+"N c #39397F7F5454",
+"B c #3A3A7E7E5555",
+"V c #3B3B7F7F5656",
+"C c #3C3C80805656",
+"Z c #3C3C81815656",
+"A c #3D3D81815757",
+"S c #3E3E81815757",
+"D c #404082825A5A",
+"F c #424284845B5B",
+"G c #424284845C5C",
+"H c #424285855C5C",
+"J c #434386865D5D",
+"K c #454586865E5E",
+"L c #474787876060",
+"P c #474788886161",
+"I c #484889896161",
+"U c #48488A8A6262",
+"Y c #4A4A8A8A6363",
+"T c #4C4C8A8A6565",
+"R c #4D4D8C8C6565",
+"E c #4F4F8D8D6767",
+"W c #50508E8E6969",
+"Q c #51518F8F6A6A",
+"! c #52528F8F6A6A",
+"~ c #545490906C6C",
+"^ c #595994946F6F",
+"/ c #5B5B95957272",
+"( c #5E5E96967474",
+") c #626299997878",
+"_ c #63639A9A7979",
+"` c #646499997979",
+"' c #64649A9A7979",
+"] c #67679E9E7D7D",
+"[ c #6C6CA0A08181",
+"{ c #6F6FA1A18282",
+"} c #6F6FA2A28282",
+"| c #7070A4A48484",
+" . c #7474A6A68787",
+".. c #7575A7A78989",
+"X. c #7676A8A88A8A",
+"o. c #7A7AAAAA8D8D",
+"O. c #7C7CABAB8F8F",
+"+. c #7C7CACAC8F8F",
+"@. c #7E7EACAC8F8F",
+"#. c #898900000000",
+"$. c #919100000000",
+"%. c #9F9F00000000",
+"&. c #ABAB00000000",
+"*. c #ADAD00000000",
+"=. c #BBBB27271919",
+"-. c #959568685959",
+";. c #9D9D63635454",
+":. c #B7B760605E5E",
+">. c #C5C55B5B5454",
+",. c #CDCD65655353",
+"<. c #C8C864645E5E",
+"1. c #C9C964645F5F",
+"2. c #CECE69695B5B",
+"3. c #CECE6A6A5C5C",
+"4. c #D1D169695454",
+"5. c #C1C163636060",
+"6. c #CCCC6C6C6767",
+"7. c #CCCC6D6D6767",
+"8. c #CFCF71716767",
+"9. c #CFCF75756565",
+"0. c #CFCF73736D6D",
+"q. c #CFCF77776C6C",
+"w. c #D1D171716464",
+"e. c #D2D272726565",
+"r. c #D4D479796C6C",
+"t. c #D3D37F7F7575",
+"y. c #D5D585857E7E",
+"u. c #DEDE8A8A7070",
+"i. c #8080AEAE9292",
+"p. c #8585B0B09595",
+"a. c #8E8EB5B59E9E",
+"s. c #8F8FB6B69E9E",
+"d. c #B5B5CECEBEBE",
+"f. c #BFBFD4D4C8C8",
+"g. c #DDDD93938888",
+"h. c #DCDC91918F8F",
+"j. c #DCDC9A9A9292",
+"k. c #E2E2A1A19999",
+"l. c #C1C1D6D6C9C9",
+"z. c #D3D3E2E2DADA",
+"x. c #D8D8E5E5DDDD",
+"c. c #E2E2EBEBE5E5",
+"v. c #E4E4ECECE7E7",
+"b. c None",
+/* pixels */
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"; ; =.&.&.* % < @ + o X . ",
+"; +.g.h.k...i.] f.a._ ( ^ ~ E ",
+"; O.0.u.7.i.! i.Y c./ N v f Y ",
+"- o.r.8.e.! d.T f.v._ x f y K ",
+"- ..6.5.6.T ] x.z.a.J f t 0 D ",
+"% .8.:.3.L J Z _ F s r 8 6 Z ",
+"% | <.-.>.J Z m x f q 9 6 2 m ",
+"# [ 2.;.,.Z b h y y 8 5 2 < c ",
+"+ ] j.4.y.b x y q 6 5 2 < > h ",
+"o _ q.t.e.W R L J Z N b x h i ",
+"o . $.*.#. ",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.",
+"b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b."
+};
diff --git a/src/images/flags/TN.xpm b/src/images/flags/TN.xpm
new file mode 100644
index 0000000..8c17fd2
--- /dev/null
+++ b/src/images/flags/TN.xpm
@@ -0,0 +1,160 @@
+/* XPM */
+static const char *TN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 138 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c red",
+"3 c #F2F210101010",
+"4 c #F2F213131313",
+"5 c #F2F214141414",
+"6 c #F3F319191919",
+"7 c #F3F31A1A1A1A",
+"8 c #F4F41F1F1F1F",
+"9 c #F4F420202020",
+"0 c #F5F525252525",
+"q c #F5F526262626",
+"w c #F2F22C2C2C2C",
+"e c #F2F22F2F2F2F",
+"r c #F6F62B2B2B2B",
+"t c #F6F62C2C2C2C",
+"y c #F2F232323232",
+"u c #F3F332323232",
+"i c #F3F335353535",
+"p c #F7F731313131",
+"a c #F4F436363636",
+"s c #F4F439393939",
+"d c #F4F43B3B3B3B",
+"f c #F5F53D3D3D3D",
+"g c #F5F53F3F3F3F",
+"h c #F7F73C3C3C3C",
+"j c #F8F837373737",
+"k c #F9F93A3A3A3A",
+"l c #FAFA3F3F3F3F",
+"z c #F6F642424242",
+"x c #F6F644444444",
+"c c #F7F746464646",
+"v c #F7F749494949",
+"b c #F7F74B4B4B4B",
+"n c #F7F74E4E4E4E",
+"m c #F8F842424242",
+"M c #FAFA44444444",
+"N c #FBFB45454545",
+"B c #FBFB49494949",
+"V c #FBFB4A4A4949",
+"C c #FCFC4F4F4F4F",
+"Z c #F3F355555555",
+"A c #F3F35D5D5D5D",
+"S c #F4F459595959",
+"D c #F5F55E5E5E5E",
+"F c #F6F65C5C5C5C",
+"G c #F8F850505050",
+"H c #F8F853535353",
+"J c #FBFB51515151",
+"K c #FBFB52525252",
+"L c #F9F954545555",
+"P c #F9F957575757",
+"I c #FDFD53535353",
+"U c #FDFD54545454",
+"Y c #F9F958585858",
+"T c #FAFA5C5C5C5C",
+"R c #FAFA5D5D5D5D",
+"E c #FEFE58585858",
+"W c #FEFE59595959",
+"Q c #FEFE5C5C5C5C",
+"! c #FEFE5F5F5F5F",
+"~ c #F6F663636363",
+"^ c #F7F768686767",
+"/ c #FBFB60606060",
+"( c #FBFB61616262",
+") c #F8F865656565",
+"_ c #FCFC65656565",
+"` c #FCFC66666666",
+"' c #FAFA6D6D6D6D",
+"] c #FAFA6F6F6F6F",
+"[ c #FCFC69696969",
+"{ c #FCFC6A6A6A6A",
+"} c #FDFD6D6D6D6D",
+"| c #FDFD6F6F6F6F",
+" . c #F6F67C7C7C7C",
+".. c #F9F977777777",
+"X. c #FDFD70707171",
+"o. c #FEFE72727373",
+"O. c #FCFC76767676",
+"+. c #FCFC77777777",
+"@. c #FEFE74747474",
+"#. c #FEFE76767676",
+"$. c #FEFE77777777",
+"%. c #F9F978787878",
+"&. c #FEFE79797979",
+"*. c #FFFF7B7B7A7A",
+"=. c #FFFF7B7B7B7B",
+"-. c #F9F982828282",
+";. c #F8F884848484",
+":. c #F7F79D9D9D9D",
+">. c #F8F894949393",
+",. c #F9F999999898",
+"<. c #FBFB9F9F9F9F",
+"1. c #F4F4A1A1A1A1",
+"2. c #F4F4ABABABAB",
+"3. c #F9F9A9A9A9A9",
+"4. c #FAFAACACACAC",
+"5. c #F5F5B2B2B2B2",
+"6. c #F7F7B5B5B5B5",
+"7. c #F8F8B2B2B2B2",
+"8. c #FAFAB1B1B1B1",
+"9. c #FBFBB0B0B0B0",
+"0. c #FCFCB2B2B2B2",
+"q. c #FDFDB4B4B4B4",
+"w. c #FDFDB5B5B5B5",
+"e. c #FDFDB7B7B7B7",
+"r. c #F9F9BDBDBDBD",
+"t. c #FDFDC1C1C1C1",
+"y. c #F7F7D6D6D6D6",
+"u. c #F5F5D9D9D9D9",
+"i. c #F7F7DCDCDCDC",
+"p. c #FDFDDFDFDFDF",
+"a. c #F5F5EBEBEBEB",
+"s. c #F6F6E9E9E9E9",
+"d. c #F6F6ECECECEC",
+"f. c #F8F8E7E7E7E7",
+"g. c #FAFAE9E9E9E9",
+"h. c #FBFBEEEEEEEE",
+"j. c #FCFCEFEFEFEF",
+"k. c None",
+/* pixels */
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"2 2 2 2 < 2 2 2 < < ; ; = = % % ",
+"2 =.=.=.O.o.o.} [ _ / R P H n $ ",
+"2 =.! Q Q t.p.h.h.8.%.j p t v $ ",
+"2 =.Q Q w.0.O.I ] r.>.) r q x + ",
+"2 O.U U w.O.<.g.-.;.i.~ q 9 g + ",
+"2 o.I C 0.J g...m 6.s.F 9 7 d + ",
+"2 | C V 4.] ,.f.:. .u.S 7 5 a o ",
+"< { V N 4.3.) h F 5.2.Z 5 3 y X ",
+"< ) N l k 7.u.d.a.1.F 5 > : e X ",
+"; ~ R Y P n V x m g s i y e e X ",
+"; = = = % % $ $ + + o o X X . . ",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.",
+"k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k."
+};
diff --git a/src/images/flags/TO.xpm b/src/images/flags/TO.xpm
new file mode 100644
index 0000000..3e624c3
--- /dev/null
+++ b/src/images/flags/TO.xpm
@@ -0,0 +1,141 @@
+/* XPM */
+static const char *TO_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 119 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c #F2F210101010",
+"3 c #F2F213131313",
+"4 c #F2F214141414",
+"5 c #F3F319191919",
+"6 c #F3F31A1A1A1A",
+"7 c #F4F41E1E1E1E",
+"8 c #F4F41F1F1F1F",
+"9 c #F4F420202020",
+"0 c #F5F523232323",
+"q c #F5F524242424",
+"w c #F5F525252525",
+"e c #F5F526262626",
+"r c #F2F22C2C2C2C",
+"t c #F2F22F2F2F2F",
+"y c #F6F629292929",
+"u c #F6F62A2A2A2A",
+"i c #F6F62B2B2B2B",
+"p c #F6F62C2C2C2C",
+"a c #F7F72E2E2E2E",
+"s c #F7F72F2F2F2F",
+"d c #F2F232323232",
+"f c #F3F332323232",
+"g c #F3F335353535",
+"h c #F7F730303030",
+"j c #F7F731313131",
+"k c #F4F436363636",
+"l c #F4F439393939",
+"z c #F4F43B3B3B3B",
+"x c #F5F53D3D3D3D",
+"c c #F5F53F3F3F3F",
+"v c #F8F834343434",
+"b c #F8F835353535",
+"n c #F8F836363636",
+"m c #F8F837373636",
+"M c #F8F837373737",
+"N c #F9F93A3A3A3A",
+"B c #F9F93B3B3A3A",
+"V c #F9F93B3B3B3B",
+"C c #F9F93B3B3C3C",
+"Z c #F9F93C3C3C3C",
+"A c #F9F93C3C3D3D",
+"S c #FAFA3F3F3F3F",
+"D c #F6F642424242",
+"F c #F6F644444444",
+"G c #F7F746464646",
+"H c #F7F749494949",
+"J c #F7F74B4B4B4B",
+"K c #F7F74E4E4E4E",
+"L c #FAFA40404040",
+"P c #FAFA41414141",
+"I c #FAFA41414242",
+"U c #FAFA42424242",
+"Y c #FAFA44444444",
+"T c #FBFB45454545",
+"R c #FBFB46464646",
+"E c #FBFB47474747",
+"W c #FBFB49494949",
+"Q c #FBFB4A4A4949",
+"! c #FCFC4A4A4B4B",
+"~ c #FCFC4C4C4C4C",
+"^ c #FCFC4F4F4F4F",
+"/ c #F8F850505050",
+"( c #F8F853535353",
+") c #F9F954545555",
+"_ c #F9F957575757",
+"` c #FDFD53535353",
+"' c #F9F958585858",
+"] c #FAFA5C5C5C5C",
+"[ c #FAFA5D5D5D5D",
+"{ c #FEFE5C5C5C5C",
+"} c #FEFE5E5E5F5F",
+"| c #FEFE5F5F5F5F",
+" . c #FBFB60606060",
+".. c #FBFB61616262",
+"X. c #FEFE60606060",
+"o. c #FCFC65656565",
+"O. c #FCFC66666666",
+"+. c #FCFC69696969",
+"@. c #FCFC6A6A6A6A",
+"#. c #FDFD6D6D6D6D",
+"$. c #FDFD6F6F6F6F",
+"%. c #FEFE72727373",
+"&. c #FEFE85858585",
+"*. c #FDFDCFCFCFCF",
+"=. c #FEFED2D2D2D2",
+"-. c #FEFED9D9D9D9",
+";. c #FFFFDBDBDBDB",
+":. c #EFEFEFEFEFEF",
+">. c #EFEFEFEFF1F1",
+",. c #F1F1F1F1F1F1",
+"<. c #FBFBFBFBFBFB",
+"1. c gray99",
+"2. c #FDFDFCFCFCFC",
+"3. c #FDFDFCFCFDFD",
+"4. c #FDFDFDFDFDFD",
+"5. c #FDFDFDFDFEFE",
+"6. c #FEFEFEFEFEFE",
+"7. c gray100",
+"8. c None",
+/* pixels */
+"8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.",
+"8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.",
+"8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.",
+",.,.,.,.,.:.:.1 < < ; ; = = % % ",
+",.7.;.&.;.7.7. at .+.o. .[ ' ( K $ ",
+",.7.[ { [ <.7.~ R U A n j p H $ ",
+",.7.=.[ *.2.2.R U A n j p e F + ",
+",.7.7.7.7.<.<.L C n h u e 9 c + ",
+"1 %.` ^ ! R S N n j u e 8 5 z + ",
+"1 $.^ ! R L N n s u q 8 5 4 k + ",
+"1 +.! U S N k s u e 8 5 4 2 j . ",
+"< o.R L N j s u 9 8 5 3 > : t . ",
+"; ..[ ' ) / J F D x z k f t r . ",
+"; = = % % % % $ + + O O . . . . ",
+"8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.",
+"8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8."
+};
diff --git a/src/images/flags/TR.xpm b/src/images/flags/TR.xpm
new file mode 100644
index 0000000..5ecbd23
--- /dev/null
+++ b/src/images/flags/TR.xpm
@@ -0,0 +1,157 @@
+/* XPM */
+static const char *TR_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 135 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c red",
+"3 c #F2F210101010",
+"4 c #F2F213131313",
+"5 c #F2F214141414",
+"6 c #F3F319191919",
+"7 c #F3F31A1A1A1A",
+"8 c #F4F41E1E1E1E",
+"9 c #F4F41F1F1F1F",
+"0 c #F4F420202020",
+"q c #F5F523232323",
+"w c #F5F524242424",
+"e c #F5F525252525",
+"r c #F5F526262626",
+"t c #F2F22C2C2C2C",
+"y c #F2F22F2F2F2F",
+"u c #F6F62B2B2B2B",
+"i c #F6F62C2C2C2C",
+"p c #F2F232323232",
+"a c #F3F332323232",
+"s c #F3F335353535",
+"d c #F6F630303030",
+"f c #F7F731313131",
+"g c #F6F633333333",
+"h c #F4F436363636",
+"j c #F4F439393939",
+"k c #F4F43B3B3B3B",
+"l c #F5F53D3D3D3D",
+"z c #F5F53F3F3F3F",
+"x c #F8F837373636",
+"c c #F8F837373737",
+"v c #F9F93A3A3A3A",
+"b c #F9F93B3B3A3A",
+"n c #F9F93B3B3B3B",
+"m c #F9F93C3C3C3C",
+"M c #F9F93C3C3D3D",
+"N c #F9F93D3D3D3D",
+"B c #FAFA3F3F3F3F",
+"V c #F6F642424242",
+"C c #F7F743434343",
+"Z c #F6F644444444",
+"A c #F7F746464646",
+"S c #F7F749494949",
+"D c #F7F74B4B4B4B",
+"F c #F7F74E4E4E4E",
+"G c #FAFA40404040",
+"H c #FAFA42424242",
+"J c #FAFA44444444",
+"K c #FBFB45454545",
+"L c #FBFB46464646",
+"P c #FBFB47474747",
+"I c #FAFA48484848",
+"U c #FBFB49494949",
+"Y c #FCFC4F4F4F4F",
+"T c #F8F850505050",
+"R c #F8F853535353",
+"E c #F9F954545555",
+"W c #F9F957575757",
+"Q c #FDFD53535353",
+"! c #FCFC55555555",
+"~ c #F9F958585858",
+"^ c #FAFA5C5C5C5C",
+"/ c #FAFA5D5D5D5D",
+"( c #FEFE58585858",
+") c #FEFE59595959",
+"_ c #FEFE5C5C5C5C",
+"` c #FEFE5F5F5F5F",
+"' c #F5F562626262",
+"] c #F8F861616161",
+"[ c #FBFB60606060",
+"{ c #FBFB65656565",
+"} c #FCFC65656565",
+"| c #FCFC66666666",
+" . c #FCFC69696969",
+".. c #FCFC6A6A6A6A",
+"X. c #FDFD6D6D6D6D",
+"o. c #FDFD6F6F6F6F",
+"O. c #F6F67D7D7D7D",
+"+. c #FAFA70707070",
+"@. c #FAFA71717171",
+"#. c #FDFD70707171",
+"$. c #FEFE72727373",
+"%. c #FEFE74747474",
+"&. c #FEFE77777777",
+"*. c #FDFD7A7A7A7A",
+"=. c #FEFE79797979",
+"-. c #FEFE7A7A7A7A",
+";. c #FFFF7B7B7B7B",
+":. c #FEFE7D7D7D7D",
+">. c #FFFF7E7E7E7E",
+",. c #FFFF7F7F7F7F",
+"<. c #F7F78C8C8C8C",
+"1. c #F8F887878787",
+"2. c #FCFC80808080",
+"3. c #FDFD9D9D9D9D",
+"4. c #FDFD9F9F9F9F",
+"5. c #FBFBA2A2A2A2",
+"6. c #F7F7B7B7B7B7",
+"7. c #FAFAB0B0B0B0",
+"8. c #FDFDB4B4B4B4",
+"9. c #FCFCBEBEBFBF",
+"0. c #FBFBC0C0C0C0",
+"q. c #F5F5D1D1D1D1",
+"w. c #F7F7D7D7D7D7",
+"e. c #F8F8D8D8D8D8",
+"r. c #F6F6EFEFEFEF",
+"t. c #F8F8E3E3E3E3",
+"y. c #F9F9E3E3E3E3",
+"u. c #F8F8E5E5E5E5",
+"i. c #FCFCE4E4E4E4",
+"p. c #FDFDE9E9E9E9",
+"a. c #F7F7F5F5F5F5",
+"s. c #FBFBF3F3F3F3",
+"d. c #FCFCF3F3F3F3",
+"f. c #FDFDF6F6F6F6",
+"g. c None",
+/* pixels */
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"2 2 2 2 < 2 2 2 < < ; ; = = % % ",
+"2 >.>.*.&.&.#.X...{ [ _ W R F $ ",
+"2 >._ _ ( 3.3.! L H N c f i S $ ",
+"2 >._ ( 8.p.i.0.I N h f u r Z + ",
+"2 *.( *.f.2.L +.N t.H u r 0 z + ",
+"2 #.Q 9.f.P N z u.a.r.' 9 6 k + ",
+"2 X.Y 5.s.+.n [ 6.O.q.9 6 5 h O ",
+"< ..U P 7.t.e.w.f r 9 6 4 4 a X ",
+"< { H N n 1.<.h 0 9 6 4 > : y X ",
+"; | / ~ W F I Z V z j s a y y X ",
+"; = = % % % $ $ + + O O X X . . ",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g."
+};
diff --git a/src/images/flags/TT.xpm b/src/images/flags/TT.xpm
new file mode 100644
index 0000000..8313eb4
--- /dev/null
+++ b/src/images/flags/TT.xpm
@@ -0,0 +1,169 @@
+/* XPM */
+static const char *TT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 147 2",
+" c black",
+". c #131313131313",
+"X c gray9",
+"o c #181819191919",
+"O c #191919191919",
+"+ c gray12",
+"@ c gray14",
+"# c #2A2A2A2A2A2A",
+"$ c #2F2F2F2F2F2F",
+"% c #323232323232",
+"& c #353535353535",
+"* c gray21",
+"= c gray23",
+"- c #414141414141",
+"; c #464646464646",
+": c #4B4B4B4B4B4B",
+"> c #4C4C4C4C4C4C",
+", c #515151515151",
+"< c gray33",
+"1 c #555555555555",
+"2 c #585858585858",
+"3 c gray35",
+"4 c gray36",
+"5 c gray38",
+"6 c gray39",
+"7 c #656565656666",
+"8 c DimGray",
+"9 c #6C6C6C6C6C6C",
+"0 c #6F6F6F6F6F6F",
+"q c #727272727272",
+"w c #777777777777",
+"e c #797979797979",
+"r c #7B7B7B7B7B7B",
+"t c gray50",
+"y c #DDDD00000000",
+"u c #DFDF00000000",
+"i c #E3E300000000",
+"p c #E5E500000000",
+"a c #E7E700000000",
+"s c #E5E505050505",
+"d c #E9E900000000",
+"f c #EBEB00000000",
+"g c #EDED00000000",
+"h c #EFEF00000000",
+"j c #F1F100000000",
+"k c #F3F300000000",
+"l c #F5F500000000",
+"z c #F7F700000000",
+"x c #F9F900000000",
+"c c #FBFB00000000",
+"v c #FDFD00000000",
+"b c red",
+"n c #F2F214141414",
+"m c #F3F31A1A1A1A",
+"M c #F4F41F1F1F1F",
+"N c #F4F420202020",
+"B c #F5F525252525",
+"V c #F5F526262626",
+"C c #F6F62B2B2B2B",
+"Z c #F6F62C2C2C2C",
+"A c #F7F72E2E2E2E",
+"S c #FFFF25252525",
+"D c #F3F332323232",
+"F c #F7F731313131",
+"G c #F4F436363636",
+"H c #F4F43B3B3B3B",
+"J c #F5F53F3F3F3F",
+"K c #F8F834343434",
+"L c #F8F837373636",
+"P c #F8F837373737",
+"I c #F9F93A3A3A3A",
+"U c #F9F93C3C3D3D",
+"Y c #FAFA3F3F3F3F",
+"T c #F6F644444444",
+"R c #F7F746464646",
+"E c #F7F749494949",
+"W c #F7F74B4B4B4B",
+"Q c #F7F74E4E4E4E",
+"! c #FAFA42424242",
+"~ c #FAFA44444444",
+"^ c #FBFB45454545",
+"/ c #FBFB49494949",
+"( c #FBFB4A4A4949",
+") c #FCFC4F4F4F4F",
+"_ c #F8F850505050",
+"` c #F8F853535353",
+"' c #F9F954545555",
+"] c #F9F957575757",
+"[ c #FDFD53535353",
+"{ c #F9F958585858",
+"} c #FAFA5C5C5C5C",
+"| c #FAFA5D5D5D5D",
+" . c #FDFD59595959",
+".. c #FEFE58585858",
+"X. c #FBFB60606060",
+"o. c #FBFB61616262",
+"O. c #FCFC65656565",
+"+. c #FCFC66666666",
+"@. c #FCFC69696969",
+"#. c #FCFC6A6A6A6A",
+"$. c #FDFD6F6F6F6F",
+"%. c #F2F27A7A7A7A",
+"&. c #F3F37F7F7F7F",
+"*. c #FEFE72727373",
+"=. c #FEFE76767676",
+"-. c #FEFE79797979",
+";. c gray51",
+":. c #888888888888",
+">. c gray60",
+",. c gray62",
+"<. c #DBDBBBBBBBBB",
+"1. c #F5F586868686",
+"2. c #F2F28A8A8A8A",
+"3. c #F6F68A8A8A8A",
+"4. c #F7F78D8D8D8D",
+"5. c #F6F696969696",
+"6. c #F8F891919191",
+"7. c #F9F994949494",
+"8. c #FAFA98989898",
+"9. c #FBFB9B9B9B9B",
+"0. c #FCFC9E9E9E9E",
+"q. c #FDFDA3A3A3A3",
+"w. c #FEFEA8A8A9A9",
+"e. c #FDFDB0B0B0B0",
+"r. c #FFFFB9B9B9B9",
+"t. c #E3E3C1C1C1C1",
+"y. c #F1F1DEDEDEDE",
+"u. c #F1F1E2E2E2E2",
+"i. c #F2F2E1E1E1E1",
+"p. c #F4F4E3E3E2E2",
+"a. c #F5F5E4E4E4E4",
+"s. c #F4F4E6E6E6E6",
+"d. c #F6F6E6E6E6E6",
+"f. c #F7F7E6E6E6E6",
+"g. c #FDFDE5E5E5E5",
+"h. c #F8F8E8E8E8E8",
+"j. c #F9F9EAEAEAEA",
+"k. c #FAFAEBEBEBEB",
+"l. c #FAFAEDEDEDED",
+"z. c #FDFDEBEBEBEB",
+"x. c #FCFCEDEDEDED",
+"c. c #FCFCEFEFEFEF",
+"v. c #FDFDF1F1F1F1",
+"b. c #FDFDF2F2F2F2",
+"n. c #FEFEF3F3F3F3",
+"m. c #FEFEF5F5F5F5",
+"M. c None",
+/* pixels */
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"z.O o g...b c c z z k k g g ",
+"S m.,.e w >.v.e. at .O.X.} ] ` Q f ",
+"b r.v.:.3 1 t l.9.! U L F Z E f ",
+"b -.w.v.;., : w k.7.L F C V T p ",
+"b =...q.c.r ; - 0 h.4.C V N J p ",
+"b *.[ ) 0.l.q = * 7 a.1.N m H p ",
+"b $.) ( ^ 8.l.8 $ # 4 p.&.n G p ",
+"c #.( ^ U I 7.a.5 @ + 1 i.%.D u ",
+"c +.^ U I L Z 3.a.3 O . > y.2.u ",
+"z o.| { ] ` E T 5.a.9 * % 5 u.u ",
+"k k k g g g f f p s t. <.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.",
+"M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M."
+};
diff --git a/src/images/flags/TV.xpm b/src/images/flags/TV.xpm
new file mode 100644
index 0000000..e2e1c4b
--- /dev/null
+++ b/src/images/flags/TV.xpm
@@ -0,0 +1,162 @@
+/* XPM */
+static const char *TV_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 140 2",
+" c black",
+". c #010100000000",
+"X c #050500000000",
+"o c #1B1B00000000",
+"O c #212100000000",
+"+ c #272700000000",
+"@ c #292900000000",
+"# c #2F2F00000000",
+"$ c #353500000000",
+"% c #3B3B00000000",
+"& c #00000D0D7B7B",
+"* c #000013137F7F",
+"= c #414100000000",
+"- c #474700000000",
+"; c #4B4B00000000",
+": c #515100000000",
+"> c #575700000000",
+", c #595900000000",
+"< c #5D5D00000000",
+"1 c #5F5F00000000",
+"2 c #636300000000",
+"3 c #676700000000",
+"4 c #696900000000",
+"5 c #000017178181",
+"6 c #00001D1D8787",
+"7 c #000023238B8B",
+"8 c #28288D8DC2C2",
+"9 c #2C2C9090C5C5",
+"0 c #2D2D9090C5C5",
+"q c #31319393C7C7",
+"w c #32329494C7C7",
+"e c #36369696C9C9",
+"r c #37379696C9C9",
+"t c #38389797C9C9",
+"y c #3B3B9A9ACBCB",
+"u c #3C3C9A9ACBCB",
+"i c #3D3D9A9ACBCB",
+"p c #6D6DA2A28181",
+"a c #7878A9A98B8B",
+"s c #43439B9BC8C8",
+"d c #40409C9CCCCC",
+"f c #40409D9DCCCC",
+"g c #41419D9DCDCD",
+"h c #42429D9DCDCD",
+"j c #43439D9DCDCD",
+"k c #46469E9ECACA",
+"l c #45459F9FCECE",
+"z c #4646A0A0CDCD",
+"x c #4646A0A0CFCF",
+"c c #4747A0A0CECE",
+"v c #4848A0A0CFCF",
+"b c #4B4BA3A3CFCF",
+"n c #4C4CA3A3CFCF",
+"m c #4C4CA4A4CFCF",
+"M c #4D4DA4A4CFCF",
+"N c #4A4AA2A2D0D0",
+"B c #4D4DA3A3D1D1",
+"V c #5050A3A3CECE",
+"C c #5050A5A5D1D1",
+"Z c #5151A6A6D1D1",
+"A c #5353A7A7D1D1",
+"S c #5252A6A6D3D3",
+"D c #5555A9A9D3D3",
+"F c #5656A9A9D4D4",
+"G c #5A5AABABD5D5",
+"H c #5B5BACACD4D4",
+"J c #5F5FAEAED7D7",
+"K c #5D5DB1B1DBDB",
+"L c #6363B0B0D9D9",
+"P c #7171BDBDE2E2",
+"I c #919121210000",
+"U c #939346463131",
+"Y c #94944A4A3434",
+"T c #96964C4C3737",
+"R c #A3A35D5D0000",
+"E c #9F9F5A5A4646",
+"W c #A2A25E5E4B4B",
+"Q c #A5A562625050",
+"! c #A8A866665454",
+"~ c #A9A96A6A5858",
+"^ c #AAAA6A6A5959",
+"/ c #ADAD6F6F5D5D",
+"( c #AFAF73736262",
+") c #B1B176766565",
+"_ c #B2B277776666",
+"` c #B3B37A7A6A6A",
+"' c #B6B67E7E6D6D",
+"] c #C1C163630000",
+"[ c #BDBD84844040",
+"{ c #BEBE8E8E5757",
+"} c #B9B980807070",
+"| c #BABA84847575",
+" . c #BCBC86867777",
+".. c #BEBE89897A7A",
+"X. c #BEBE8B8B7D7D",
+"o. c #A7A7B9B96868",
+"O. c #C3C38E8E3838",
+"+. c #DDDDB2B23B3B",
+"@. c #C0C08D8D7F7F",
+"#. c #D3D3AFAF6565",
+"$. c #DEDEC7C72C2C",
+"%. c #E4E4C7C71F1F",
+"&. c #E7E7CACA2A2A",
+"*. c #E8E8CDCD3030",
+"=. c #E4E4CDCD6565",
+"-. c #FEFEE0E05858",
+";. c #FEFEE6E67676",
+":. c #FCFCE6E67C7C",
+">. c #8888B3B39898",
+",. c #8F8FB7B79E9E",
+"<. c #A1A1C3C3A2A2",
+"1. c #B3B3CECEB3B3",
+"2. c #FDFDE7E78585",
+"3. c #FDFDEBEB9494",
+"4. c #E7E7E6E6B7B7",
+"5. c #FBFBF1F1BCBC",
+"6. c #DFDFDFDFDFDF",
+"7. c #C4C4E0E0EEEE",
+"8. c #CDCDE4E4F0F0",
+"9. c #FCFCF3F3C8C8",
+"0. c #E9E9E9E9E9E9",
+"q. c #E4E4F0F0F5F5",
+"w. c #E9E9F5F5F9F9",
+"e. c #F1F1F1F1F1F1",
+"r. c gray95",
+"t. c #F3F3F3F3F3F3",
+"y. c #F4F4F4F4F4F4",
+"u. c gray96",
+"i. c #F6F6F6F6F6F6",
+"p. c gray97",
+"a. c #F8F8F8F8F8F8",
+"s. c #F9F9F9F9F9F9",
+"d. c gray98",
+"f. c #FBFBFBFBFBFB",
+"g. c gray99",
+"h. c #FCFCFDFDFDFD",
+"j. c #FDFDFDFDFDFD",
+"k. c #FEFEFEFEFEFE",
+"l. c gray100",
+"z. c None",
+/* pixels */
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"4 4 4 4 4 2 < < > : ; - = % R # ",
+"4 @.X.X... .| ' ' ` ) #.=.~ { + ",
+"l.l.l.l.l.l.l.l.d.d.s.s.p.p.p.0.",
+"l.l.q.P J J G F S B l j i *.,.7 ",
+"l.;.-.l.7.H D V M l j i t a M 6 ",
+"l.1.<.g.l.q.M M l j i e w $.>.5 ",
+"2.3.:.5.8.D l z j i o.&.9 8 k * ",
+"d.9.4.K M l j j y e q 9 %.p s & ",
+"s.g.d.d.d.d.p.p.p.t.r.r.r.r.r.6.",
+"; ) ( / ^ ! Q W E [ +.O.Y Y U ",
+"; = % $ # @ O o I ] , X ",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.",
+"z.z.z.z.z.z.z.z.z.z.z.z.z.z.z.z."
+};
diff --git a/src/images/flags/TW.xpm b/src/images/flags/TW.xpm
new file mode 100644
index 0000000..10a23b0
--- /dev/null
+++ b/src/images/flags/TW.xpm
@@ -0,0 +1,155 @@
+/* XPM */
+static const char *TW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 133 2",
+" c black",
+". c #00001111A9A9",
+"X c #00001B1BABAB",
+"o c #00001919ADAD",
+"O c #00001F1FAFAF",
+"+ c #00002121AFAF",
+"@ c #00002323B1B1",
+"# c #00002525B3B3",
+"$ c #00002727B3B3",
+"% c #4A4A7575C9C9",
+"& c #4F4F7979CBCB",
+"* c #4E4E7B7BCDCD",
+"= c #52527C7CCECE",
+"- c #53537D7DCFCF",
+"; c #53537E7ECFCF",
+": c #58587F7FCFCF",
+"> c #57578181D1D1",
+", c #57578282D1D1",
+"< c #58588181D1D1",
+"1 c #5C5C8383D1D1",
+"2 c #5C5C8585D3D3",
+"3 c #60608787D2D2",
+"4 c #63638B8BD5D5",
+"5 c #71719393D8D8",
+"6 c #75759595DADA",
+"7 c #77779999D9D9",
+"8 c #7A7A9C9CDCDC",
+"9 c #7D7D9D9DDBDB",
+"0 c #7D7D9E9EDCDC",
+"q c #7F7F9F9FDDDD",
+"w c #DDDD00000000",
+"e c #DFDF00000000",
+"r c #E1E100000000",
+"t c #E3E300000000",
+"y c #E5E500000000",
+"u c #E7E700000000",
+"i c #E9E900000000",
+"p c #EBEB00000000",
+"a c #EDED00000000",
+"s c #EFEF00000000",
+"d c #F1F100000000",
+"f c #F3F300000000",
+"g c #F5F500000000",
+"h c #F7F700000000",
+"j c #F1F10B0B0B0B",
+"k c #F1F10F0F0E0E",
+"l c #F9F900000000",
+"z c #FBFB00000000",
+"x c #FDFD00000000",
+"c c #F2F210101010",
+"v c #F2F213131313",
+"b c #F2F214141414",
+"n c #F3F319191919",
+"m c #F3F31A1A1A1A",
+"M c #F4F41E1E1E1E",
+"N c #F4F41F1F1F1F",
+"B c #F4F420202020",
+"V c #F5F523232323",
+"C c #F5F524242424",
+"Z c #F5F525252525",
+"A c #F5F526262626",
+"S c #F2F22C2C2C2C",
+"D c #F2F22F2F2F2F",
+"F c #F6F629292929",
+"G c #F6F62A2A2A2A",
+"H c #F6F62B2B2B2B",
+"J c #F6F62C2C2C2C",
+"K c #F7F72E2E2E2E",
+"L c #F7F72F2F2F2F",
+"P c #F2F232323232",
+"I c #F3F332323232",
+"U c #F3F335353535",
+"Y c #F7F730303030",
+"T c #F7F731313131",
+"R c #F4F436363636",
+"E c #F1F136363A3A",
+"W c #F4F439393939",
+"Q c #F4F43B3B3B3B",
+"! c #F5F53D3D3D3D",
+"~ c #F5F53F3F3F3F",
+"^ c #F8F834343434",
+"/ c #F8F835353535",
+"( c #F8F836363636",
+") c #F8F837373636",
+"_ c #F8F837373737",
+"` c #F9F93A3A3A3A",
+"' c #F9F93B3B3A3A",
+"] c #F9F93C3C3C3C",
+"[ c #F9F93C3C3D3D",
+"{ c #FAFA3F3F3F3F",
+"} c #EAEA3B3B4646",
+"| c #ECEC41414B4B",
+" . c #EDED47475050",
+".. c #F6F642424242",
+"X. c #F6F644444444",
+"o. c #F7F746464646",
+"O. c #F7F749494949",
+"+. c #F7F74B4B4B4B",
+"@. c #F7F74E4E4E4E",
+"#. c #FAFA40404040",
+"$. c #FAFA42424242",
+"%. c #FAFA44444444",
+"&. c #FBFB45454545",
+"*. c #FBFB49494949",
+"=. c #FBFB4A4A4949",
+"-. c #FCFC4F4F4F4F",
+";. c #F8F850505050",
+":. c #F8F853535353",
+">. c #F9F954545555",
+",. c #F9F957575757",
+"<. c #F9F958585858",
+"1. c #FAFA5C5C5C5C",
+"2. c #FAFA5D5D5D5D",
+"3. c #FBFB60606060",
+"4. c #FBFB61616262",
+"5. c #FCFC65656565",
+"6. c #FCFC66666666",
+"7. c #FCFC6A6A6A6A",
+"8. c #FDFD6F6F6F6F",
+"9. c #F1F169697070",
+"0. c #90909090D8D8",
+"q. c #93939393DADA",
+"w. c #98989999DDDD",
+"e. c #99999999DCDC",
+"r. c #8282A2A2DDDD",
+"t. c #8484A4A4DFDF",
+"y. c #B6B6B7B7E6E6",
+"u. c #B9B9B9B9E8E8",
+"i. c #F9F9F9F9FBFB",
+"p. c #F9F9F9F9FCFC",
+"a. c #F9F9F9F9FDFD",
+"s. c #FEFEFEFEFEFE",
+"d. c None",
+/* pixels */
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"$ $ $ $ @ O o . r l h h f f a a ",
+"$ t.t.y.u.q 8 7 9.5.3.1.,.:. at .p ",
+"$ t.w.p.s.w.2 > .$.[ ) T J O.p ",
+"$ r.q.p.i.q.> = | [ ) T H A X.y ",
+"O q 4 6 5 > = * } ) L H A B ~ y ",
+"X q 3 3 : : & % E Y H A M n Q y ",
+"x 8.-.&.&.} ` ) L H A M n v R y ",
+"x 7.&.&.{ ` R Y H A M n b c T w ",
+"l 5.&.{ ` ^ J H B M n v k j D w ",
+"h 4.2.<.,. at .=.X...~ Q R I D S w ",
+"h f f a a a p p y y y r w w w w ",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.",
+"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d."
+};
diff --git a/src/images/flags/TZ.xpm b/src/images/flags/TZ.xpm
new file mode 100644
index 0000000..b3a451e
--- /dev/null
+++ b/src/images/flags/TZ.xpm
@@ -0,0 +1,180 @@
+/* XPM */
+static const char *TZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 158 2",
+" c black",
+". c #2C2C2C2C2C2C",
+"X c #373733332B2B",
+"o c gray19",
+"O c #313131313131",
+"+ c #343431313030",
+"@ c #353535353535",
+"# c #363634343434",
+"$ c gray21",
+"% c #383838383636",
+"& c #3A3A3A3A3A3A",
+"* c #3B3B3B3B3A3A",
+"= c #3E3E3E3E3B3B",
+"- c #3F3F3F3F3F3F",
+"; c #00006F6F0000",
+": c #000079790000",
+"> c #00007B7B0000",
+", c #00007D7D0000",
+"< c #40403F3F3F3F",
+"1 c #444444443737",
+"2 c #4A4A4A4A3C3C",
+"3 c #51514D4D3434",
+"4 c #575751512F2F",
+"5 c #5C5C57572B2B",
+"6 c #7D7D7B7B3C3C",
+"7 c #4E4E4E4E4E4E",
+"8 c #535352524040",
+"9 c #555555554444",
+"0 c #535353535353",
+"q c #585858585858",
+"w c #5D5D5D5D5D5D",
+"e c #797974744949",
+"r c #656564646262",
+"t c #00002727DDDD",
+"y c #00002929DDDD",
+"u c #00002D2DDDDD",
+"i c #00002D2DDFDF",
+"p c #00002F2FDFDF",
+"a c #00003131DFDF",
+"s c #00003535DDDD",
+"d c #00003333E1E1",
+"f c #00003535E3E3",
+"g c #00003939E3E3",
+"h c #00003B3BE5E5",
+"j c #00003D3DE5E5",
+"k c #00004747C1C1",
+"l c #00004B4BD7D7",
+"z c #00004141E7E7",
+"x c #00004747E9E9",
+"c c #000081810000",
+"v c #000083830000",
+"b c #000085850000",
+"n c #000087870000",
+"m c #000089890000",
+"M c #000091910000",
+"N c #000093930000",
+"B c #5353ADAD0000",
+"V c #5151B8B84C4C",
+"C c #5151B4B45151",
+"Z c #5151B5B55151",
+"A c #5353B5B55353",
+"S c #5454B7B75454",
+"D c #5252B9B95050",
+"F c #5454B9B95454",
+"G c #5454BABA5454",
+"H c #5858BCBC5858",
+"J c #5858BCBC5959",
+"K c #5959BCBC5959",
+"L c #5C5CBDBD5C5C",
+"P c #5C5CBEBE5C5C",
+"I c #5F5FBFBF5F5F",
+"U c #6969BFBF6969",
+"Y c #5F5FC1C10000",
+"T c #6D6DC6C64F4F",
+"R c #6F6FC8C84B4B",
+"E c #6D6DC3C36D6D",
+"W c #6F6FC4C46F6F",
+"Q c #7070C5C57171",
+"! c #7272C6C67373",
+"~ c #7474C7C77474",
+"^ c #7676C8C87676",
+"/ c #7777C8C87777",
+"( c #7979C8C87979",
+") c #7979C9C97979",
+"_ c #7B7BCACA7A7A",
+"` c #7B7BCACA7B7B",
+"' c #0B0B9595F1F1",
+"] c #0F0F9797F1F1",
+"[ c #10109797F2F2",
+"{ c #13139999F2F2",
+"} c #14149999F2F2",
+"| c #14149A9AF2F2",
+" . c #1A1A9999F2F2",
+".. c #18189C9CF3F3",
+"X. c #1C1C9B9BF0F0",
+"o. c #3333A2A2DFDF",
+"O. c #2C2CA2A2F2F2",
+"+. c #2F2FA4A4F2F2",
+"@. c #3232A5A5F3F3",
+"#. c #3333A6A6F3F3",
+"$. c #3535A8A8F3F3",
+"%. c #3636A8A8F4F4",
+"&. c #3939A9A9F4F4",
+"*. c #3B3BA9A9F5F5",
+"=. c #3D3DACACF5F5",
+"-. c #5353B0B0BBBB",
+";. c #5555B1B1BDBD",
+":. c #4242ADADF6F6",
+">. c #7474C0C0C9C9",
+",. c #818181810000",
+"<. c #89899D9D0000",
+"1. c #91918B8B2F2F",
+"2. c #92928C8C2B2B",
+"3. c #989893932626",
+"4. c #BFBFBDBD0000",
+"5. c #BBBBB7B73D3D",
+"6. c #898987874040",
+"7. c #8B8B88884545",
+"8. c #8F8F8E8E5757",
+"9. c #969690905555",
+"0. c #9D9DC9C90000",
+"q. c #9D9DDBDB4F4F",
+"w. c #8B8BD3D36565",
+"e. c #9A9AD0D07C7C",
+"r. c #A4A4DEDE4B4B",
+"t. c #AEAEE0E04747",
+"y. c #CBCBDFDF0000",
+"u. c #D1D1DBDB0000",
+"i. c #C0C0C0C03232",
+"p. c #C2C2C5C53232",
+"a. c #C4C4CBCB3535",
+"s. c #D9D9E5E53F3F",
+"d. c #E5E5EDED3737",
+"f. c #CFCFCBCB4141",
+"g. c #D5D5D1D14545",
+"h. c #D5D5D2D26666",
+"j. c #CFCFE6E64A4A",
+"k. c #C1C1E1E15B5B",
+"l. c #D2D2E5E54444",
+"z. c #D7D7E4E44242",
+"x. c #D4D4E8E84747",
+"c. c #D4D4EAEA4B4B",
+"v. c #D7D7EAEA4A4A",
+"b. c #DADAE8E86060",
+"n. c #DBDBE9E96060",
+"m. c #D8D8EDED6A6A",
+"M. c #E1E1DEDE4242",
+"N. c #E1E1DEDE4646",
+"B. c #E3E3E3E34242",
+"V. c #E7E7E8E84646",
+"C. c #E6E6E9E94949",
+"Z. c #EFEFEDED5C5C",
+"A. c #E6E6F0F05D5D",
+"S. c #F5F5F3F34949",
+"D. c #E0E0E8E86060",
+"F. c #9898D0D08383",
+"G. c #A2A2D3D39494",
+"H. c None",
+/* pixels */
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"M m m m b v v , > ; > Y 4. ",
+"b ` ` ` ^ ! Q E U w.n.Z.8.0 7 ",
+"m ` I L L G Z V t.B.5.1 O . e <.",
+"b ` L L G C R l.M.6 $ O X 3.b.0.",
+"m ^ G S V r.V.f.2 $ O 5 a.j.G.k ",
+"b ^ Z T v.g.1.= $ + 2.z.l.-.*.h ",
+"> E q.C.g.7 & $ 4 p.d.e.X.| %.f ",
+"M m.S.7.7 $ $ 1.z.k.;.X.| [ #.a ",
+"u.h.9 = % 3 i.v.F.o...{ ] ' +.i ",
+" r w q 9.D.A.>.:.=.*.%.#.+.O.t ",
+" ,.y.B l x z j h a i u y s ",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.",
+"H.H.H.H.H.H.H.H.H.H.H.H.H.H.H.H."
+};
diff --git a/src/images/flags/UA.xpm b/src/images/flags/UA.xpm
new file mode 100644
index 0000000..151437e
--- /dev/null
+++ b/src/images/flags/UA.xpm
@@ -0,0 +1,172 @@
+/* XPM */
+static const char *UA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 150 2",
+" c black",
+". c #00003535E7E7",
+"X c #00004F4F9999",
+"o c #00004545E7E7",
+"O c #00004545E9E9",
+"+ c #00004D4DEBEB",
+"@ c #00005757EFEF",
+"# c #00005D5DF1F1",
+"$ c #00006363F3F3",
+"% c #00006767F5F5",
+"& c #00006D6DF7F7",
+"* c #00007171F9F9",
+"= c #00007575FBFB",
+"- c #00007979FDFD",
+"; c #00007D7DFDFD",
+": c #00007F7FFDFD",
+"> c #00009191C7C7",
+", c #00008383FDFD",
+"< c #00008383FFFF",
+"1 c #00008585FFFF",
+"2 c #20209F9FF4F4",
+"3 c #3E3EABABCFCF",
+"4 c #2525A1A1F5F5",
+"5 c #2626A2A2F5F5",
+"6 c #2B2BA4A4F6F6",
+"7 c #2B2BA5A5F6F6",
+"8 c #2C2CA6A6F6F6",
+"9 c #3030A7A7F7F7",
+"0 c #3131A8A8F7F7",
+"q c #3131A9A9F7F7",
+"w c #3636AAAAF8F8",
+"e c #3737ABABF8F8",
+"r c #3F3FADADF5F5",
+"t c #3B3BADADF9F9",
+"y c #3C3CAEAEF9F9",
+"u c #3D3DAEAEF9F9",
+"i c #4343AEAED1D1",
+"p c #4848B0B0D2D2",
+"a c #4D4DB3B3D4D4",
+"s c #5151B5B5D6D6",
+"d c #5656B8B8D8D8",
+"f c #5B5BB7B7D5D5",
+"g c #5B5BBABAD9D9",
+"h c #4444AFAFF6F6",
+"j c #4141AFAFFAFA",
+"k c #4242B0B0FAFA",
+"l c #4242B1B1FAFA",
+"z c #4646B2B2FBFB",
+"x c #4747B3B3FBFB",
+"c c #4949B2B2F7F7",
+"v c #4E4EB4B4F7F7",
+"b c #4B4BB5B5FCFC",
+"n c #4B4BB6B6FCFC",
+"m c #4C4CB6B6FCFC",
+"M c #5353B7B7F8F8",
+"N c #5050B6B6FDFD",
+"B c #5151B7B7FDFD",
+"V c #5454B9B9FDFD",
+"C c #5454BABAFDFD",
+"Z c #5858B9B9F9F9",
+"A c #5858BBBBFEFE",
+"S c #5858BCBCFEFE",
+"D c #5959BCBCFEFE",
+"F c #5C5CBBBBFAFA",
+"G c #5C5CBDBDFEFE",
+"H c #5C5CBEBEFEFE",
+"J c #5F5FBFBFFEFE",
+"K c #6060BCBCDBDB",
+"L c #6464BEBEDDDD",
+"P c #6161BEBEFBFB",
+"I c #6969C0C0DDDD",
+"U c #6D6DC2C2DFDF",
+"Y c #6565C0C0FCFC",
+"T c #6969C2C2FCFC",
+"R c #6D6DC3C3FDFD",
+"E c #7070C4C4E0E0",
+"W c #7070C5C5FEFE",
+"Q c #7474C7C7FEFE",
+"! c #7676C7C7FEFE",
+"~ c #7777C8C8FEFE",
+"^ c #7979C8C8FEFE",
+"/ c #7979C9C9FEFE",
+"( c #7B7BCACAFFFF",
+") c #DDDDB5B50000",
+"_ c #DDDDB7B70000",
+"` c #DFDFB7B70000",
+"' c #DFDFB9B90000",
+"] c #DFDFBBBB0000",
+"[ c #E1E1BBBB0000",
+"{ c #E3E3BBBB0000",
+"} c #E3E3BFBF0000",
+"| c #E5E5BFBF0000",
+" . c #E7E7C3C30000",
+".. c #E9E9C5C50000",
+"X. c #EBEBC7C70000",
+"o. c #EDEDCBCB0000",
+"O. c #EDEDCDCD0000",
+"+. c #EFEFD1D10000",
+"@. c #F1F1D3D30000",
+"#. c #F3F3D7D70000",
+"$. c #F5F5D9D90000",
+"%. c #F7F7DBDB0000",
+"&. c #F9F9DDDD0000",
+"*. c #FBFBDFDF0000",
+"=. c #FDFDE1E10000",
+"-. c #F1F1F1F10B0B",
+";. c #F1F1F1F10E0E",
+":. c #F2F2F2F21010",
+">. c #F2F2F2F21313",
+",. c #F2F2F2F21414",
+"<. c #F3F3F3F31919",
+"1. c #F4F4F4F41E1E",
+"2. c #F4F4F4F41F1F",
+"3. c #F5F5F5F52323",
+"4. c #F5F5F5F52424",
+"5. c #F2F2F2F22C2C",
+"6. c #F2F2F2F22F2F",
+"7. c #F6F6F6F62929",
+"8. c #F6F6F6F62A2A",
+"9. c #F7F7F7F72E2E",
+"0. c #F7F7F7F72F2F",
+"q. c #F2F2F2F23232",
+"w. c #F3F3F3F33232",
+"e. c #F3F3F3F33535",
+"r. c #F4F4F4F43636",
+"t. c #F4F4F4F43939",
+"y. c #F5F5F5F53D3D",
+"u. c #F8F8F8F83434",
+"i. c #F8F8F8F83535",
+"p. c #F9F9F9F93A3A",
+"a. c #FAFAFAFA3F3F",
+"s. c #F6F6F6F64242",
+"d. c #F7F7F7F74646",
+"f. c #F7F7F7F74B4B",
+"g. c #FAFAFAFA4040",
+"h. c #FAFAFAFA4444",
+"j. c #FBFBFBFB4545",
+"k. c #FBFBFBFB4949",
+"l. c #FBFBFCFC4949",
+"z. c #FCFCFCFC4F4F",
+"x. c #F8F8F8F85050",
+"c. c #F9F9F9F95555",
+"v. c #F9F9F9F95858",
+"b. c #FAFAFAFA5D5D",
+"n. c #FBFBFBFB6262",
+"m. c #FCFCFCFC6666",
+"M. c #FCFCFCFC6A6A",
+"N. c #FDFDFDFD6F6F",
+"B. c #8A8AD0D0E7E7",
+"V. c None",
+/* pixels */
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"1 1 1 1 1 ; ; - = * & % $ # @ @ ",
+"< ( ( ( ~ Q R R T Y P F Z M v + ",
+"1 ( P G G C C m c l u e q 8 c O ",
+"< ( G A C N b x l u e 9 7 5 h O ",
+"; ! C C m b z j t w 8 7 5 2 r . ",
+"> B.E U I L K g d s a p i 3 f X ",
+"=.N.z.k.j.a.p.r.u.8.4.1.<.,.r.{ ",
+"=.M.k.j.a.p.u.9.8.3.1.<.>.>.w.] ",
+"&.m.j.a.p.u.9.8.3.1.<.>.;.-.6.` ",
+"%.n.b.v.c.x.f.d.s.y.t.e.w.6.6.) ",
+"%.#.#.O.O.o.X.X. .} } { ] ` ) ) ",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.",
+"V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V."
+};
diff --git a/src/images/flags/UG.xpm b/src/images/flags/UG.xpm
new file mode 100644
index 0000000..c852bea
--- /dev/null
+++ b/src/images/flags/UG.xpm
@@ -0,0 +1,174 @@
+/* XPM */
+static const char *UG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 152 2",
+" c black",
+". c #151500000000",
+"X c gray8",
+"o c #191919191919",
+"O c gray12",
+"+ c gray14",
+"@ c gray21",
+"# c #717100000000",
+"$ c #73737D7D0000",
+"% c gray25",
+"& c gray27",
+"* c #49494A4A4949",
+"= c gray31",
+"- c #606060605555",
+"; c #646464645959",
+": c #686868685E5E",
+"> c #6C6C6C6C6262",
+", c gray42",
+"< c #6F6F6F6F6F6F",
+"1 c #70706F6F6666",
+"2 c #747474746A6A",
+"3 c #787878786E6E",
+"4 c #7B7B7B7B7272",
+"5 c #7F7F7F7F7575",
+"6 c #90901A1A1A1A",
+"7 c #93931F1F1F1F",
+"8 c #969625252525",
+"9 c #99992B2B2B2B",
+"0 c #9F9F3B3B3B3B",
+"q c #A7A746464646",
+"w c #AAAA4A4A4B4B",
+"e c #ADAD4F4F4F4F",
+"r c #AFAF53535353",
+"t c #BEBE72727373",
+"y c #DDDD00000000",
+"u c #DFDF00000000",
+"i c #E1E100000000",
+"p c #E3E300000000",
+"a c #E5E500000000",
+"s c #E7E700000000",
+"d c #E9E900000000",
+"f c #EBEB00000000",
+"g c #EDED00000000",
+"h c #EFEF00000000",
+"j c #F1F100000000",
+"k c #F3F300000000",
+"l c #F5F500000000",
+"z c #F7F700000000",
+"x c #FDFD00000000",
+"c c #F4F420202020",
+"v c #F5F525252525",
+"b c #F6F62B2B2B2B",
+"n c #F7F730303030",
+"m c #F5F53F3F3F3F",
+"M c #F2F25B5B2C2C",
+"N c #F2F25C5C2F2F",
+"B c #F2F260603232",
+"V c #F3F362623535",
+"C c #F4F465653939",
+"Z c #F5F569693D3D",
+"A c #D6D645454545",
+"S c #FCFC4B4B4B4B",
+"D c #FDFD4F4F5050",
+"F c #FDFD54545454",
+"G c #FEFE58585858",
+"H c #F6F66C6C4242",
+"J c #F7F76F6F4646",
+"K c #F7F774744B4B",
+"L c #F8F877775050",
+"P c #F9F97B7B5555",
+"I c #F9F97F7F5858",
+"U c #FEFE76767676",
+"Y c #ABABB3B30000",
+"T c #BABABDBD1010",
+"R c #BCBCBFBF1414",
+"E c #818181817979",
+"W c #848484847B7B",
+"Q c #868686867E7E",
+"! c #888888887F7F",
+"~ c #BDBDC2C21919",
+"^ c #BFBFC4C41F1F",
+"/ c #E3E39F9F0000",
+"( c #FAFA82825D5D",
+") c #FBFB85856262",
+"_ c #DFDFDFDF0000",
+"` c #C1C1C6C62424",
+"' c #C4C4C8C82A2A",
+"] c #C6C6CACA2F2F",
+"[ c #C3C3C7C73232",
+"{ c #C8C8CCCC3434",
+"} c #CACACECE3A3A",
+"| c #CCCCCFCF3F3F",
+" . c #DDDDE9E90000",
+".. c #FBFBCDCD0000",
+"X. c #F4F4D3D32626",
+"o. c #F4F4D4D42B2B",
+"O. c #F5F5D6D63131",
+"+. c #F6F6D8D83636",
+"@. c #F7F7DADA3C3C",
+"#. c #F1F1F1F10B0B",
+"$. c #F1F1F1F10E0E",
+"%. c #F5F5FFFF0000",
+"&. c #F9F9F9F90000",
+"*. c #F2F2F2F21313",
+"=. c #F3F3F3F31919",
+"-. c #F4F4F4F41E1E",
+";. c #F5F5F5F52323",
+":. c #F2F2F2F22F2F",
+">. c #F0F0F6F62C2C",
+",. c #F6F6F6F62929",
+"<. c #F7F7F7F72E2E",
+"1. c #F1F1F7F73131",
+"2. c #F2F2F8F83737",
+"3. c #F3F3F9F93D3D",
+"4. c #F8F8F8F83434",
+"5. c #F9F9F9F93A3A",
+"6. c #FAFAFAFA3F3F",
+"7. c #CECED1D14545",
+"8. c #D0D0D3D34949",
+"9. c #D8D8DCDC6A6A",
+"0. c #F4F4D8D84444",
+"q. c #F8F8DBDB4242",
+"w. c #F9F9DDDD4747",
+"e. c #FAFADEDE4B4B",
+"r. c #FBFBDFDF5151",
+"t. c #FBFBE0E05454",
+"y. c #FBFBE2E25959",
+"u. c #FCFCE3E35C5C",
+"i. c #F1F1F7F74949",
+"p. c #F4F4FAFA4242",
+"a. c #F5F5FAFA4747",
+"s. c #F6F6FBFB4C4C",
+"d. c #FAFAFAFA4444",
+"f. c #F6F6FDFD5151",
+"g. c #F7F7FDFD5454",
+"h. c #F8F8FEFE5959",
+"j. c #F8F8FEFE5C5C",
+"k. c #F9F9FEFE5F5F",
+"l. c #FCFCE8E87979",
+"z. c #FCFCFCFC6666",
+"x. c #FAFAFFFF7A7A",
+"c. c gray61",
+"v. c #9F9F9E9E9E9E",
+"b. c #B6B6B6B6B6B6",
+"n. c gray74",
+"m. c #F8F8BBBBBBBB",
+"M. c #FBFBC2C2C2C2",
+"N. c #F6F6F4F4F4F4",
+"B. c #F9F9F7F7F7F7",
+"V. c #F8F8F8F8F8F8",
+"C. c #F9F9F9F9F9F9",
+"Z. c None",
+/* pixels */
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+" ",
+" ! c.4 5 5 5 4 3 2 1 > : ; - ",
+"%.x.j.j.h.f.f.s.a.p.3.2.1.>.i. .",
+"..l.u.y.r.r.e.e.q. at .+.O.o.X.0./ ",
+"x U G F D S M.v.C.m.n b v c m s ",
+"# t r e w q N.c., N.9 8 7 6 0 . ",
+" < = * & % n.V.A b.+ O o X @ ",
+"Y 9.7.7.7.} { ] ' ` ^ ~ R T [ $ ",
+"&.z.d.6.5.4.<.,.;.-.=.*.$.#.:._ ",
+"z ) ( ( P L K J H Z C V B N M u ",
+"l l j g g g f f s s i i u u y y ",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.",
+"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z."
+};
diff --git a/src/images/flags/UM.xpm b/src/images/flags/UM.xpm
new file mode 100644
index 0000000..13c0554
--- /dev/null
+++ b/src/images/flags/UM.xpm
@@ -0,0 +1,154 @@
+/* XPM */
+static const char *UM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 132 2",
+" c black",
+". c #717100000000",
+"X c #7B7B00000000",
+"o c #7E7E00000000",
+"O c #4C4C4C4C4C4C",
+"+ c #5C5C59595959",
+"@ c gray47",
+"# c #4F4F7777C9C9",
+"$ c #53537B7BCDCD",
+"% c #55557D7DCFCF",
+"& c #57577D7DCFCF",
+"* c #57577F7FD1D1",
+"= c #59598181D3D3",
+"- c #59598383D3D3",
+"; c #5B5B8383D5D5",
+": c #60609595D9D9",
+"> c #6B6BA4A4DADA",
+", c #6E6EA7A7DADA",
+"< c #7B7BB4B4DCDC",
+"1 c #7C7CB4B4DDDD",
+"2 c #8B8B00000000",
+"3 c #959500000000",
+"4 c #9F9F00000000",
+"5 c #A6A600000000",
+"6 c #B2B200000000",
+"7 c #BABA00000000",
+"8 c #C0C000000000",
+"9 c #CCCC00000000",
+"0 c #CDCD00000000",
+"q c #CFCF00000000",
+"w c #CDCD1C1C1C1C",
+"e c #D2D200000000",
+"r c #D3D300000000",
+"t c #D6D600000000",
+"y c #D9D900000000",
+"u c #DCDC00000000",
+"i c #DDDD02020101",
+"p c #DDDD02020202",
+"a c #D4D41F1F1F1F",
+"s c #D9D922222222",
+"d c #DBDB24242424",
+"f c #D3D337373737",
+"g c #DBDB3C3C3C3C",
+"h c #E0E026262626",
+"j c #E0E028282828",
+"k c #E3E328282828",
+"l c #E6E62A2A2A2A",
+"z c #E6E62C2C2C2C",
+"x c #E6E62D2D2D2D",
+"c c #E7E72F2F2F2F",
+"v c #E3E333333333",
+"b c #E7E731313131",
+"n c #E8E832323232",
+"m c #E8E836363636",
+"M c #E8E838383838",
+"N c #E9E939393939",
+"B c #E9E93A3A3A3A",
+"V c #E9E93D3D3D3D",
+"C c #E9E942424242",
+"Z c #EAEA41414141",
+"A c #EBEB42424242",
+"S c #EBEB46464646",
+"D c #EBEB49494949",
+"F c #EBEB4D4D4C4C",
+"G c #ECEC4B4B4C4C",
+"H c #ECEC4F4F4F4F",
+"J c #EEEE56565757",
+"K c #EEEE5C5C5C5C",
+"L c #EEEE64646464",
+"P c #EFEF6F6F6F6F",
+"I c gray52",
+"U c #A7A7A7A7A7A7",
+"Y c #8D8DB5B5DEDE",
+"T c #8E8EB5B5DEDE",
+"R c #9292B6B6DEDE",
+"E c #9393B6B6DFDF",
+"W c #A3A3B7B7E0E0",
+"Q c #A3A3B8B8E0E0",
+"! c #A4A4B9B9E1E1",
+"~ c #A5A5B9B9E2E2",
+"^ c #A6A6BABAE2E2",
+"/ c #A6A6BABAE3E3",
+"( c #A7A7BBBBE3E3",
+") c #A8A8BCBCE5E5",
+"_ c #A9A9BDBDE6E6",
+"` c #A9A9BEBEE7E7",
+"' c #AAAABEBEE7E7",
+"] c #ABABBFBFE8E8",
+"[ c #ACACC0C0E9E9",
+"{ c #B4B4C5C5E7E7",
+"} c #B6B6C7C7E9E9",
+"| c #B6B6C8C8EAEA",
+" . c #B9B9C9C9EBEB",
+".. c #B9B9C9C9ECEC",
+"X. c #B9B9CACAEDED",
+"o. c #BABACBCBEDED",
+"O. c #F2F29F9F9F9F",
+"+. c gray76",
+"@. c gray81",
+"#. c #D0D0D0D0D0D0",
+"$. c gray83",
+"%. c #D9D9D9D9DADA",
+"&. c #DCDCDADADADA",
+"*. c gainsboro",
+"=. c #E1E1E1E1E1E1",
+"-. c gray90",
+";. c #E7E7E7E7E7E7",
+":. c gray91",
+">. c #E9E9E9E9E9E9",
+",. c #E9E9EAEAEAEA",
+"<. c #EAEAEAEAEAEA",
+"1. c #EBEBEBEBEAEA",
+"2. c #ECECECECECEC",
+"3. c gray93",
+"4. c #EEEEEEEEEEEE",
+"5. c #EFEFEFEFEFEF",
+"6. c gray94",
+"7. c #F1F1F1F1F1F1",
+"8. c gray95",
+"9. c #F3F3F3F3F3F3",
+"0. c #F4F4F4F4F4F4",
+"q. c #F4F4F5F5F5F5",
+"w. c gray96",
+"e. c #F6F6F6F6F6F6",
+"r. c gray97",
+"t. c #F8F8F8F8F8F8",
+"y. c #F9F9F9F9F9F9",
+"u. c gray98",
+"i. c gray99",
+"p. c #FDFDFEFEFDFD",
+"a. c #FEFEFEFEFEFE",
+"s. c None",
+/* pixels */
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"; ; ; ; - - $ $ # v j p p p r r ",
+"; a.o.a.o.i.| u.{ r.r.w.7.7.7.@ ",
+"; o.] ` ` ) ~ ~ W L J G A N F 0 ",
+"- o.i.` u.^ r.~ E 7.5.3.3.1.3.U ",
+"- .) ) ) ~ W E 1 D C N n x C 7 ",
+"$ a.) t.~ w.T 7., 3.3.<.<.;.<.I ",
+"$ | / ~ Q Y 1 > : N n l h d g 4 ",
+"@.t.w.w.9.7.3.3.3.<.:.;.-.&.&.O ",
+"v O.P K H S V m c l h s a w f o ",
+"+.w.w.9.9.7.3.3.2.<.<.=.%.$.#.+ ",
+"p p u r r r e 0 7 6 5 3 2 X . . ",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.",
+"s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s."
+};
diff --git a/src/images/flags/US.xpm b/src/images/flags/US.xpm
new file mode 100644
index 0000000..d5d8faf
--- /dev/null
+++ b/src/images/flags/US.xpm
@@ -0,0 +1,159 @@
+/* XPM */
+static const char *US_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 137 2",
+" c black",
+". c #00002B2BB3B3",
+"X c #00004949B6B6",
+"o c #00004F4FB5B5",
+"O c #00006868B9B9",
+"+ c #00006969BCBC",
+"@ c #03036F6FE1E1",
+"# c #03037171E5E5",
+"$ c #04047373F1F1",
+"% c #04047474F8F8",
+"& c #2F2F7373F8F8",
+"* c #30307070F8F8",
+"= c #32327575F8F8",
+"- c #36367474F9F9",
+"; c #37377777F9F9",
+": c #39397676F9F9",
+"> c #3A3A7979F9F9",
+", c #3D3D7A7AF9F9",
+"< c #3F3F7E7EFAFA",
+"1 c #63636363B1B1",
+"2 c #63636363B7B7",
+"3 c #63636363B8B8",
+"4 c #63636363BEBE",
+"5 c #63636767BFBF",
+"6 c #40407C7CFAFA",
+"7 c #43437E7EFAFA",
+"8 c #63636565C2C2",
+"9 c #63636767C4C4",
+"0 c #46468080FAFA",
+"q c #49498282FAFA",
+"w c #9A9A63634A4A",
+"e c #9E9E63634A4A",
+"r c #A0A063634A4A",
+"t c #A6A663634A4A",
+"y c #ABAB63634A4A",
+"u c #AFAF63634A4A",
+"i c #B5B563634A4A",
+"p c #BFBF63634A4A",
+"a c #F8F80B0B0B0B",
+"s c #F9F910101010",
+"d c #F9F916161616",
+"f c #FAFA1B1B1B1B",
+"g c #FAFA20202020",
+"h c #FBFB23232323",
+"j c #FBFB28282828",
+"k c #FBFB2A2A2A2A",
+"l c #FBFB2C2C2C2C",
+"z c #FBFB2E2E2E2E",
+"x c #FBFB31313131",
+"c c #FBFB32323232",
+"v c #FCFC38383838",
+"b c #FCFC39393939",
+"n c #FCFC3A3A3A3A",
+"m c #FCFC3D3D3D3D",
+"M c #C5C563634A4A",
+"N c #CCCC63634A4A",
+"B c #D4D463634A4A",
+"V c #D5D563634A4A",
+"C c #D8D863634A4A",
+"Z c #DADA63634A4A",
+"A c #DEDE63634A4A",
+"S c #FCFC40404040",
+"D c #FCFC46464646",
+"F c #FCFC47474747",
+"G c #FCFC4C4C4C4C",
+"H c #FCFC50505050",
+"J c #FCFC53535454",
+"K c #FCFC58585858",
+"L c #E0E063634A4A",
+"P c #E2E263634A4A",
+"I c #E5E564644A4A",
+"U c #E8E863634A4A",
+"Y c #F4F474745E5E",
+"T c #FCFC61616363",
+"R c #FCFC68686868",
+"E c #FCFC78786262",
+"W c #FBFB7F7F6B6B",
+"Q c #FCFC73737373",
+"! c #FDFD7F7F7F7F",
+"~ c #FDFD82826D6D",
+"^ c #FCFC86867272",
+"/ c #FDFD8E8E7C7C",
+"( c #FDFDFDFD5B5B",
+") c #919191918080",
+"_ c #ACACACAC9F9F",
+"` c #B4B4B4B4A8A8",
+"' c #9898B9B9FCFC",
+"] c #9B9BBBBBFCFC",
+"[ c #9C9CBDBDFCFC",
+"{ c #A1A1BEBEFCFC",
+"} c #A2A2C0C0FCFC",
+"| c #FDFD97978686",
+" . c #C9C9C9C9C1C1",
+".. c #DADADADAD3D3",
+"X. c gainsboro",
+"o. c #D7D7FEFEFDFD",
+"O. c #FEFECACAC1C1",
+"+. c #E2E2E2E2DDDD",
+"@. c #E2E2E2E2DEDE",
+"#. c #FDFDE1E1DCDC",
+"$. c gray89",
+"%. c #E5E5E5E5E0E0",
+"&. c gray90",
+"*. c #E7E7E7E7E7E7",
+"=. c gray91",
+"-. c #E9E9E9E9E9E9",
+";. c #EAEAEAEAEAEA",
+":. c gray92",
+">. c #EDEDEDEDEAEA",
+",. c #ECECECECECEC",
+"<. c #EEEEEEEEEEEE",
+"1. c #EFEFEFEFEFEF",
+"2. c #E5E5E5E5FCFC",
+"3. c #ECECFEFEFEFE",
+"4. c #F1F1F1F1EFEF",
+"5. c gray94",
+"6. c #F1F1F1F1F1F1",
+"7. c #F2F2F2F2F0F0",
+"8. c #F3F3F3F3F1F1",
+"9. c gray95",
+"0. c #F3F3F3F3F3F3",
+"q. c #F4F4F4F4F2F2",
+"w. c #F5F5F5F5F3F3",
+"e. c #F4F4F4F4F4F4",
+"r. c gray96",
+"t. c #F6F6F6F6F4F4",
+"y. c #F6F6F6F6F6F6",
+"u. c #F7F7F7F7F6F6",
+"i. c #F8F8F8F8F6F6",
+"p. c #F8F8F8F8F7F7",
+"a. c #F9F9F9F9F8F8",
+"s. c #F9F9F9F9F9F9",
+"d. c #FAFAFAFAF9F9",
+"f. c #FBFBFBFBFBFB",
+"g. c #FBFBFFFFFAFA",
+"h. c #FEFEFEFEFDFD",
+"j. c None",
+/* pixels */
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"9 9 9 9 8 4 2 2 1 ~ E U L L A Z ",
+"9 h.} g.{ s.[ g.' f.s.s.i.i.y._ ",
+"9 } q 0 7 , > - & Q T J F m | V ",
+"5 { s.< y.> 1.& % 8.1.,.,.( 8. .",
+"8 { 6 , > - & $ + H F n c k / M ",
+"3 f., 1.- :.# &.o ,.,.=.:.=.o.` ",
+"3 [ : & & @ O X . n c j h f ^ u ",
+"@.f.u.y.8.1.1.,.,.:.=.*.&.X.#.) ",
+"~ O.! R K G S v z j g d s a W r ",
+"..s.3.i.p.p.q.q.7.7.1.>.2.%. at .Y ",
+"U L L A Z Z V V N M i y t e w w ",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.",
+"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j."
+};
diff --git a/src/images/flags/UY.xpm b/src/images/flags/UY.xpm
new file mode 100644
index 0000000..e5d1af6
--- /dev/null
+++ b/src/images/flags/UY.xpm
@@ -0,0 +1,184 @@
+/* XPM */
+static const char *UY_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 162 2",
+" c black",
+". c #000000007F7F",
+"X c #000000008F8F",
+"o c #00003333A3A3",
+"O c #00003F3FB5B5",
+"+ c #00004343B3B3",
+"@ c #07075757A9A9",
+"# c #19196767B3B3",
+"$ c #29297979CACA",
+"% c #2C2C7C7CCBCB",
+"& c #31317F7FCCCC",
+"* c #36368282CFCF",
+"= c #37378383CFCF",
+"- c #3B3B8686D0D0",
+"; c #3C3C8686D1D1",
+": c #40408989D2D2",
+"> c #41418A8AD3D3",
+", c #45458C8CD4D4",
+"< c #46468D8DD4D4",
+"1 c #48488C8CD1D1",
+"2 c #4B4B8E8ED0D0",
+"3 c #4A4A9090D6D6",
+"4 c #4B4B9191D6D6",
+"5 c #4E4E9090D1D1",
+"6 c #4F4F9393D8D8",
+"7 c #50509191D3D3",
+"8 c #54549494D3D3",
+"9 c #54549494D5D5",
+"0 c #57579797D4D4",
+"q c #50509494D8D8",
+"w c #54549797D9D9",
+"e c #55559696D9D9",
+"r c #5D5D9797D3D3",
+"t c #5B5B9999D6D6",
+"y c #59599A9ADBDB",
+"u c #5F5F9B9BD8D8",
+"i c #5E5E9C9CDCDC",
+"p c #63639E9ED9D9",
+"a c #62629E9EDDDD",
+"s c #6666A1A1DBDB",
+"d c #6A6AA4A4DCDC",
+"f c #6F6FA6A6DDDD",
+"g c #7373A9A9DEDE",
+"h c #7A7AACACDFDF",
+"j c #7676ACACE0E0",
+"k c #7A7AAEAEE2E2",
+"l c #7D7DAEAEE1E1",
+"z c #F4F4F4F45959",
+"x c #F5F5F5F55C5C",
+"c c #F5F5F5F55F5F",
+"v c #EDEDEDED7777",
+"b c #EEEEEFEF7B7B",
+"n c #F3F3F3F36868",
+"m c #8D8DB6B6DEDE",
+"M c #8181B1B1E2E2",
+"N c #8484B3B3E3E3",
+"B c #8989B6B6E4E4",
+"V c #8F8FB8B8E0E0",
+"C c #8C8CB9B9E6E6",
+"Z c #8F8FBBBBE6E6",
+"A c #9292BABAE1E1",
+"S c #9191BBBBE7E7",
+"D c #9595BCBCE3E3",
+"F c #9797BDBDE3E3",
+"G c #9999BFBFE3E3",
+"H c #9999BFBFE4E4",
+"J c #9D9DBFBFE2E2",
+"K c #ADADB9B9C5C5",
+"L c #9C9CC1C1E5E5",
+"P c #9D9DC1C1E6E6",
+"I c #9F9FC2C2E7E7",
+"U c #9999C2C2EAEA",
+"Y c #B7B7C1C1CBCB",
+"T c #BDBDC3C3C9C9",
+"R c #BFBFC3C3C9C9",
+"E c #BFBFC9C9D5D5",
+"W c #A0A0C3C3E7E7",
+"Q c #A4A4C5C5E6E6",
+"! c #A2A2C4C4E8E8",
+"~ c #A3A3C6C6E9E9",
+"^ c #A5A5C7C7E9E9",
+"/ c #A6A6C8C8EAEA",
+"( c #A7A7C9C9EAEA",
+") c #A9A9CACAEBEB",
+"_ c #AAAACBCBECEC",
+"` c #ABABCBCBECEC",
+"' c #ADADCDCDEDED",
+"] c #BCBCD7D7F1F1",
+"[ c #F1F1F1F19696",
+"{ c #F3F3F3F39494",
+"} c #F2F2F2F29D9D",
+"| c #F3F3F3F39F9F",
+" . c #F4F4F4F49F9F",
+".. c #C1C1C7C7CDCD",
+"X. c #C3C3C9C9CDCD",
+"o. c #C3C3C9C9CFCF",
+"O. c #C7C7CDCDD1D1",
+"+. c #C9C9CFCFD5D5",
+"@. c #CDCDD1D1D5D5",
+"#. c #CFCFD5D5D7D7",
+"$. c #D1D1D5D5DBDB",
+"%. c #D5D5D7D7DDDD",
+"&. c #D7D7DBDBDFDF",
+"*. c #DFDFDFDFDFDF",
+"=. c #D7D7DFDFE7E7",
+"-. c #D9D9DDDDE1E1",
+";. c #DBDBDFDFE3E3",
+":. c #DFDFE1E1E7E7",
+">. c #E1E1E1E1E1E1",
+",. c gray89",
+"<. c gray90",
+"1. c #E7E7E7E7E7E7",
+"2. c #E1E1E7E7EEEE",
+"3. c #E2E2E8E8EFEF",
+"4. c #E3E3E9E9EFEF",
+"5. c #E5E5EBEBEFEF",
+"6. c #E9E9E9E9E9E9",
+"7. c #EBEBEBEBE9E9",
+"8. c gray92",
+"9. c #EBEBEDEDEFEF",
+"0. c gray93",
+"q. c #EFEFEFEFEFEF",
+"w. c #E4E4EBEBF0F0",
+"e. c #E6E6ECECF1F1",
+"r. c #E7E7ECECF3F3",
+"t. c #E7E7EDEDF2F2",
+"y. c #E8E8EDEDF2F2",
+"u. c #E9E9EFEFF3F3",
+"i. c #E8E8EEEEF4F4",
+"p. c #E9E9EFEFF4F4",
+"a. c #EAEAEFEFF5F5",
+"s. c #EFEFEFEFF1F1",
+"d. c #EAEAF0F0F4F4",
+"f. c #EAEAF0F0F5F5",
+"g. c #EBEBF1F1F5F5",
+"h. c #EBEBF0F0F6F6",
+"j. c #EBEBF1F1F6F6",
+"k. c #ECECF1F1F7F7",
+"l. c #ECECF2F2F6F6",
+"z. c #EDEDF2F2F7F7",
+"x. c #EEEEF2F2F8F8",
+"c. c #EEEEF3F3F8F8",
+"v. c #EFEFF3F3F9F9",
+"b. c #EFEFF4F4F9F9",
+"n. c #EFEFF4F4FBFB",
+"m. c #F5F5F3F3E0E0",
+"M. c #F5F5F4F4E6E6",
+"N. c #F7F7F7F7EDED",
+"B. c #F8F8F7F7EDED",
+"V. c #F1F1F1F1F1F1",
+"C. c #F3F3F5F5F6F6",
+"Z. c #F0F0F5F5FAFA",
+"A. c #F1F1F5F5FBFB",
+"S. c #F2F2F6F6FAFA",
+"D. c #F2F2F6F6FBFB",
+"F. c #F5F5F5F5F8F8",
+"G. c #F6F6F6F6F9F9",
+"H. c #F4F4F8F8FDFD",
+"J. c #F8F8F9F9FAFA",
+"K. c #FAFAFBFBFCFC",
+"L. c #FCFCFCFCFEFE",
+"P. c None",
+/* pixels */
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"V.V.V.s.V.s.s.0.0.7.7.1.<.,.>.;.",
+"V.N. .| N.H.U Z Z C B N M l h o ",
+"0.| x x [ D.D.D.v.D.j.j.g.a.a.O.",
+"7.[ x z n C._ _ ^ W I P H F W # ",
+"V.M.b v m.D.a 9 6 6 < > ; = 9 X ",
+"s.K.G.G.K.J.v.j.l.l.t.e.e.e.t.Y ",
+"r ] ' _ _ ^ W P L F F A m m L @ ",
+"O k i y 9 6 < < ; ; * & % $ 1 . ",
+"=.A.v.n.j.j.l.a.u.e.e.3.3.3.5.K ",
+"+ k j g f d s p u t 0 8 7 5 2 . ",
+":.;.-.-.%.$.#. at .+.O.X.X...R T R ",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.",
+"P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P."
+};
diff --git a/src/images/flags/UZ.xpm b/src/images/flags/UZ.xpm
new file mode 100644
index 0000000..b49ed35
--- /dev/null
+++ b/src/images/flags/UZ.xpm
@@ -0,0 +1,163 @@
+/* XPM */
+static const char *UZ_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 141 2",
+" c black",
+". c #000001010000",
+"X c #000007070000",
+"o c #00000B0B0000",
+"O c #000000001515",
+"+ c #000000001D1D",
+"@ c #000011110000",
+"# c #000019190000",
+"$ c #00001F1F0000",
+"% c #151500000000",
+"& c #000000002525",
+"* c #000000002B2B",
+"= c #000000003131",
+"- c #000000003939",
+"; c #000000003F3F",
+": c #000027270000",
+"> c #00002D2D0000",
+", c #000033330000",
+"< c #000039390000",
+"1 c #00003F3F0000",
+"2 c #000000004545",
+"3 c #000000004949",
+"4 c #000000005B5B",
+"5 c #000000005F5F",
+"6 c #000000006161",
+"7 c #000047470000",
+"8 c #00004F4F0000",
+"9 c #0B0B7D7D0B0B",
+"0 c #535300000000",
+"q c #656500000000",
+"w c #2C2C2C2C9191",
+"e c #313131319494",
+"r c #373737379898",
+"t c #3D3D3C3C9B9B",
+"y c #424242429E9E",
+"u c #49494949A0A0",
+"i c #4E4E4E4EA3A3",
+"p c #53535353A6A6",
+"a c #58585757A9A9",
+"s c #5C5C5C5CABAB",
+"d c #5F5F5F5FAFAF",
+"f c #61616060AEAE",
+"g c #65656565B0B0",
+"h c #77777777BABA",
+"j c #79797979BCBC",
+"k c #0F0F80800E0E",
+"l c #131383831313",
+"z c #181886861919",
+"x c #1E1E88881E1E",
+"c c #23238C8C2323",
+"v c #29298F8F2929",
+"b c #2C2C8E8E2C2C",
+"n c #2F2F90902F2F",
+"m c #2E2E92922E2E",
+"M c #323291913232",
+"N c #343495953434",
+"B c #353594943535",
+"V c #393997973939",
+"C c #3A3A99993A3A",
+"Z c #3D3D99993D3D",
+"A c #3F3F9C9C3F3F",
+"S c #42429B9B4242",
+"D c #44449F9F4444",
+"F c #46469E9E4646",
+"G c #4B4BA1A14B4B",
+"H c #5050A4A45050",
+"J c #5454A6A65555",
+"K c #5858A9A95858",
+"L c #5D5DACAC5D5D",
+"P c #6161AEAE6262",
+"I c #6666B1B16666",
+"U c #838310103030",
+"Y c #868614143535",
+"T c #888819193939",
+"R c #8B8B1F1F3E3E",
+"E c #8F8F24244242",
+"W c #909026264444",
+"Q c #92922A2A4747",
+"! c #93932B2B4949",
+"~ c #95952F2F4C4C",
+"^ c #949432324E4E",
+"/ c #979731314E4E",
+"( c #989834345151",
+") c #999937375353",
+"_ c #9C9C3A3A5555",
+"` c #9C9C3C3C5858",
+"' c #9F9F3F3F5A5A",
+"] c #9F9F44445E5E",
+"[ c #A0A041415D5D",
+"{ c #A2A245455F5F",
+"} c #A2A247476060",
+"| c #A4A449496363",
+" . c #A5A54B4B6565",
+".. c #A8A851516969",
+"X. c #ABAB54546D6D",
+"o. c #ACAC59597171",
+"O. c #AFAF5C5C7474",
+"+. c #B5B56A6A8080",
+"@. c #BEBE79798C8C",
+"#. c #8F8F8D8DC3C3",
+"$. c #97979797CACA",
+"%. c #ABABABABD4D4",
+"&. c #ADADADADD7D7",
+"*. c #B3B3B3B3D7D7",
+"=. c #BDBDBDBDD1D1",
+"-. c #B9B9B9B9D9D9",
+";. c #C1C1C1C1D1D1",
+":. c #C3C3C3C3D5D5",
+">. c #C2C2C2C2DFDF",
+",. c #C6C6C6C6E1E1",
+"<. c #CCCCCCCCE4E4",
+"1. c #D5D5D5D5E8E8",
+"2. c #D5D5D5D5EBEB",
+"3. c #D9D9D8D8EAEA",
+"4. c #D9D9D9D9ECEC",
+"5. c #DCDCDCDCECEC",
+"6. c #DDDDDDDDEDED",
+"7. c #DFDFDFDFEDED",
+"8. c #E2E2E2E2EFEF",
+"9. c #EAEAEAEAF4F4",
+"0. c #EDEDEFEFF5F5",
+"q. c #EFEFEFEFF7F7",
+"w. c gray95",
+"e. c #F3F3F3F3F3F3",
+"r. c #F2F2F2F2F7F7",
+"t. c #F4F4F4F4F4F4",
+"y. c #F4F4F5F5F5F5",
+"u. c gray96",
+"i. c #F6F6F6F6F6F6",
+"p. c gray97",
+"a. c #F1F1F1F1F9F9",
+"s. c #F8F8F8F8F8F8",
+"d. c #F9F9F9F9F9F9",
+"f. c gray98",
+"g. c #FBFBFBFBFBFB",
+"h. c #FBFBFCFCFBFB",
+"j. c gray99",
+"k. c #FDFDFCFCFDFD",
+"l. c #FDFDFDFDFDFD",
+"z. c #FEFEFEFEFEFE",
+"x. c None",
+/* pixels */
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"6 &.2.d 5 4 -.#.*.3 2 ; - = * & ",
+"6 r.%.j h 8.4.7.<.g f s a p i + ",
+"6 6.9.$.6.,.3.>.2.y t r e w u O ",
+"q @.O.o.X. . .} ] _ ) / ! E ] % ",
+"a.z.z.z.g.z.z.d.d.d.p.p.u.u.u.:.",
+"0.z.z.h.z.h.d.d.p.u.u.u.u.e.u.;.",
+"0.z.h.h.d.d.d.p.p.p.u.u.e.e.e.=.",
+"0 O.{ { ' _ ) ~ Q E R T Y U / ",
+"8 I G A V B n v c x z l k 9 n ",
+"8 I L K J H G F S Z V B M n b ",
+"7 < , > : $ # @ o o ",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.",
+"x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x."
+};
diff --git a/src/images/flags/VA.xpm b/src/images/flags/VA.xpm
new file mode 100644
index 0000000..ded40b8
--- /dev/null
+++ b/src/images/flags/VA.xpm
@@ -0,0 +1,167 @@
+/* XPM */
+static const char *VA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 145 2",
+" c black",
+". c #BBBBB7B73232",
+"X c #A9A988886E6E",
+"o c #A8A8ACAC6E6E",
+"O c #BEBEA3A36161",
+"+ c #CDCDA7A70000",
+"@ c #CFCFA7A70000",
+"# c #D1D1ABAB0000",
+"$ c #D5D5AFAF0000",
+"% c #D7D7B3B30000",
+"& c #D9D9B7B70000",
+"* c #DBDBB7B70000",
+"= c #DDDDBFBF0000",
+"- c #DFDFBFBF0000",
+"; c #CCCCBCBC5F5F",
+": c #C9C9BFBF7D7D",
+"> c #E3E3C3C30000",
+", c #E5E5C5C50000",
+"< c #E7E7C7C70000",
+"1 c #E5E5C9C90101",
+"2 c #E7E7C9C90000",
+"3 c #E9E9C9C90000",
+"4 c #E9E9CBCB0101",
+"5 c #E9E9CDCD0303",
+"6 c #EBEBCDCD0303",
+"7 c #EBEBCDCD0505",
+"8 c #EBEBCDCD0707",
+"9 c #EBEBCFCF1515",
+"0 c #C4C4C2C27C7C",
+"q c #DDDDD0D06363",
+"w c #F4F4DFDF4E4E",
+"e c #F3F3E0E05757",
+"r c #F5F5E1E15353",
+"t c #F5F5E1E15656",
+"y c #F6F6E2E25858",
+"u c #F6F6E3E35B5B",
+"i c #F4F4E2E25C5C",
+"p c #F7F7E4E45E5E",
+"a c #F7F7E4E45F5F",
+"s c #F5F5E3E36161",
+"d c #F5F5E2E26666",
+"f c #F7F7E4E46060",
+"g c #F6F6E5E56565",
+"h c #F4F4E3E36E6E",
+"j c #F7F7E6E66A6A",
+"k c #F6F6E5E56D6D",
+"l c #F8F8E5E56262",
+"z c #F8F8E5E56464",
+"x c #F8F8E6E66464",
+"c c #F8F8E6E66565",
+"v c #F9F9E7E76767",
+"b c #F9F9E6E66868",
+"n c #F9F9E7E76969",
+"m c #F9F9E7E76A6A",
+"M c #FAFAE8E86B6B",
+"N c #F8F8E8E86F6F",
+"B c #FAFAE8E86D6D",
+"V c #FAFAE8E86E6E",
+"C c #FAFAE9E96E6E",
+"Z c #F7F7E6E67171",
+"A c #F7F7E7E77575",
+"S c #F9F9E9E97373",
+"D c #FAFAE9E97171",
+"F c #FBFBE9E97171",
+"G c #FBFBEAEA7575",
+"H c #F8F8E8E87979",
+"J c #F9F9E9E97C7C",
+"K c #FCFCEBEB7878",
+"L c #FCFCECEC7B7B",
+"P c #BDBDBCBC8181",
+"I c #BBBBB6B6AFAF",
+"U c #D9D9A4A4B6B6",
+"Y c #DFDFADADB9B9",
+"T c #E0E0B1B19D9D",
+"R c #E0E0A7A7A6A6",
+"E c #FAFAEAEA8080",
+"W c #FBFBECEC8484",
+"Q c #FBFBEDED8787",
+"! c #FCFCEDED8787",
+"~ c #FBFBEDED8D8D",
+"^ c #FCFCEDED8A8A",
+"/ c #FCFCEDED8B8B",
+"( c #FCFCEEEE8E8E",
+") c #FCFCEFEF8F8F",
+"_ c #FCFCF0F09292",
+"` c #EAEAE6E6AEAE",
+"' c #ECECE7E7A9A9",
+"] c gray81",
+"[ c #CDCDD0D0CCCC",
+"{ c #D9D9D7D7C3C3",
+"} c gray82",
+"| c #D3D3D3D3D1D1",
+" . c LightGray",
+".. c #D5D5D5D5D5D5",
+"X. c #D7D7D7D7D7D7",
+"o. c gray86",
+"O. c #DDDDDDDDDDDD",
+"+. c #DFDFDFDFDFDF",
+"@. c #DBDBDCDCEAEA",
+"#. c #E5E5E2E2C3C3",
+"$. c #E5E5E3E3CCCC",
+"%. c #EFEFEDEDDFDF",
+"&. c #F3F3F0F0DDDD",
+"*. c #E1E1E3E3E3E3",
+"=. c gray90",
+"-. c #E7E7E7E7E7E7",
+";. c #EAEAE1E1E1E1",
+":. c #EBEBE3E3E2E2",
+">. c #E9E9E9E9E9E9",
+",. c #EAEAEBEBEAEA",
+"<. c gray92",
+"1. c gray93",
+"2. c #EFEFEDEDEDED",
+"3. c #EFEFEFEFEFEF",
+"4. c #F1F1EFEFE1E1",
+"5. c #F1F1F1F1E2E2",
+"6. c #F0F0F0F0EBEB",
+"7. c #F5F5F3F3E9E9",
+"8. c #F6F6F4F4EBEB",
+"9. c #F5F5F5F5EFEF",
+"0. c #F6F6F5F5EFEF",
+"q. c #F8F8F6F6EDED",
+"w. c #F1F1F1F1F1F1",
+"e. c gray95",
+"r. c #F2F2F2F2F3F3",
+"t. c #F3F3F3F3F3F3",
+"y. c #F1F1F1F1F6F6",
+"u. c #F4F4F4F4F4F4",
+"i. c #F4F4F5F5F4F4",
+"p. c gray96",
+"a. c #F7F7F7F7F4F4",
+"s. c #F7F7F7F7F5F5",
+"d. c #F6F6F6F6F6F6",
+"f. c gray97",
+"g. c #FBFBF9F9F0F0",
+"h. c #FAFAFAFAF2F2",
+"j. c #F8F8F8F8F6F6",
+"k. c #F9F9F9F9F6F6",
+"l. c #FCFCFCFCF4F4",
+"z. c #F8F8F8F8F8F8",
+"x. c #F9F9F9F9F9F9",
+"c. c gray98",
+"v. c #FBFBFBFBFBFB",
+"b. c gray99",
+"n. c None",
+/* pixels */
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"9 6 8 8 6 4 < 1 %.3.3.,.,.=.=.*.",
+"8 _ _ ) ( ^ Q ~ l.b.b.x.x.x.d.+.",
+"8 _ L K G F C F g.x.x.j.s.d.f.O.",
+"8 ( K G F C v C g.y.$.0 P #.&.o.",
+"4 ( G F C m l j x. at .o : ; . ` X.",
+"4 ^ F B v v p g q.x.i.O X 6.i...",
+"< Q B m v l y s d.' q T U I ] | ",
+"< W v l i y r i 0.5.4.U R 2.,.| ",
+"> J v p p e w e 7.i.e.%.%.e.e.] ",
+"- J H A Z k d h 8.d.u.u.3.y.3.] ",
+"- & & % $ # @ + { X.....] ] ] ] ",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n."
+};
diff --git a/src/images/flags/VC.xpm b/src/images/flags/VC.xpm
new file mode 100644
index 0000000..228017e
--- /dev/null
+++ b/src/images/flags/VC.xpm
@@ -0,0 +1,188 @@
+/* XPM */
+static const char *VC_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 166 2",
+" c black",
+". c #00001B1B0000",
+"X c #00001D1D0000",
+"o c #00001F1F0000",
+"O c #000021210000",
+"+ c #000023230000",
+"@ c #000027270000",
+"# c #00002D2D0000",
+"$ c #000031310000",
+"% c #000037370000",
+"& c #00003D3D0000",
+"* c #000043430000",
+"= c #000049490000",
+"- c #00004F4F0000",
+"; c #000055550000",
+": c #00005B5B0000",
+"> c #000000008F8F",
+", c #000000009393",
+"< c #00000000AFAF",
+"1 c #00000000B1B1",
+"2 c #00000000B3B3",
+"3 c #00000000B5B5",
+"4 c #00000000B7B7",
+"5 c #00000000BBBB",
+"6 c #00000000BDBD",
+"7 c #00000000BFBF",
+"8 c #00000000C1C1",
+"9 c #00000000C3C3",
+"0 c #00000000C7C7",
+"q c #4A4A4A4ACCCC",
+"w c #4E4E4E4ECECE",
+"e c #4F4F4F4FCECE",
+"r c #54545454D0D0",
+"t c #54545555D0D0",
+"y c #59595959D2D2",
+"u c #5E5E5E5ED3D3",
+"i c #62626262D3D3",
+"p c #62626262D5D5",
+"a c #65656565D6D6",
+"s c #66666666D4D4",
+"d c #66666666D6D6",
+"f c #61616161DDDD",
+"g c #66666666DEDE",
+"h c #68686969D8D8",
+"j c #6A6A6A6AE0E0",
+"k c #6F6F6F6FE0E0",
+"l c #72727272E2E2",
+"z c #76767676E3E3",
+"x c #79797979E4E4",
+"c c #7B7B7B7BE4E4",
+"v c #0B0B93930B0B",
+"b c #0F0F95950E0E",
+"n c #101095951010",
+"m c #141498981414",
+"M c #19199A9A1919",
+"N c #1A1A9B9B1A1A",
+"B c #1F1F9D9D1F1F",
+"V c #20209E9E2020",
+"C c #2525A0A02525",
+"Z c #2626A1A12626",
+"A c #2B2BA4A42B2B",
+"S c #2C2CA0A02C2C",
+"D c #2F2FA2A22F2F",
+"F c #2F2FA3A32F2F",
+"G c #2C2CA4A42C2C",
+"H c #3030A7A73030",
+"J c #3131A7A73131",
+"K c #3232A4A43232",
+"L c #3333A4A43232",
+"P c #3636A7A73636",
+"I c #3B3BA9A93B3B",
+"U c #3F3FABAB3F3F",
+"Y c #4343AFAF2A2A",
+"T c #5353B5B52F2F",
+"R c #6262BCBC2F2F",
+"E c #6565BDBD3535",
+"W c #6A6ABFBF3636",
+"Q c #4444AEAE4444",
+"! c #4343B1B14040",
+"~ c #4949B0B04949",
+"^ c #4E4EB3B34E4E",
+"/ c #5353B5B55353",
+"( c #5858B8B85757",
+") c #7B7BC8C84646",
+"_ c #8686CBCB2B2B",
+"` c #9595CFCF2323",
+"' c #9494CFCF2A2A",
+"] c #9E9ED3D32929",
+"[ c #A3A3D7D73A3A",
+"{ c #B7B7DDDD2424",
+"} c #B2B2DDDD3C3C",
+"| c #B9B9DFDF3030",
+" . c #9999D5D54646",
+".. c #ADADDCDC4141",
+"X. c #E1E1AFAF0000",
+"o. c #E3E3B3B30000",
+"O. c #E5E5B5B50000",
+"+. c #E7E7B9B90000",
+"@. c #E9E9BBBB0000",
+"#. c #EBEBBDBD0000",
+"$. c #DFDFEFEF3636",
+"%. c #DFDFEFEF3B3B",
+"&. c #EDEDC1C10000",
+"*. c #EDEDC5C50000",
+"=. c #F5F5CFCF0000",
+"-. c #F7F7D1D10000",
+";. c #F9F9D5D50000",
+":. c #FBFBD7D70000",
+">. c #FDFDD7D70000",
+",. c #FDFDD9D90000",
+"<. c #FDFDDBDB0000",
+"1. c #FDFDDDDD0000",
+"2. c #E5E5EDED1313",
+"3. c #E6E6EEEE1919",
+"4. c #E8E8F0F01F1F",
+"5. c #F3F3F3F31919",
+"6. c #F4F4F4F41E1E",
+"7. c #F4F4F4F41F1F",
+"8. c #E8E8EFEF3535",
+"9. c #EEEEF2F22525",
+"0. c #EDEDF2F22B2B",
+"q. c #ECECF3F33131",
+"w. c #EDEDF4F43737",
+"e. c #E8E8F2F23C3C",
+"r. c #F1F1F4F42424",
+"t. c #F7F7F7F72E2E",
+"y. c #F4F4F4F43939",
+"u. c #F5F5F5F53D3D",
+"i. c #F7F7F8F83434",
+"p. c #F8F8F8F83434",
+"a. c #F8F8F8F83636",
+"s. c #F9F9F9F93A3A",
+"d. c #F9F9F9F93D3D",
+"f. c #C3C3E4E44040",
+"g. c #C5C5E7E74B4B",
+"h. c #EEEEEEEE4343",
+"j. c #EFEFEFEF4848",
+"k. c #ECECF5F54B4B",
+"l. c #F3F3F5F54242",
+"z. c #F5F5F6F64646",
+"x. c #F0F0F0F04E4E",
+"c. c #F7F7F7F74B4B",
+"v. c #F6F6F9F94242",
+"b. c #F6F6F9F94747",
+"n. c #FAFAFAFA4242",
+"m. c #FBFBFBFB4747",
+"M. c #FCFCFCFC4C4C",
+"N. c #F4F4F1F15353",
+"B. c #F3F3F2F25858",
+"V. c #F0F0F0F05C5C",
+"C. c #F3F3F3F35D5D",
+"Z. c #F1F1F7F75C5C",
+"A. c #F8F8F8F85050",
+"S. c #FDFDFDFD5151",
+"D. c #FDFDFDFD5454",
+"F. c #F4F4F4F46060",
+"G. c #FBFBFBFB6060",
+"H. c #FCFCFCFC6565",
+"J. c #FCFCFCFC6969",
+"K. c #FDFDFDFD6D6D",
+"L. c #F7F7F7F77D7D",
+"P. c #FDFDFDFD7171",
+"I. c #FEFEFEFE7474",
+"U. c #80808181DDDD",
+"Y. c #83838383DEDE",
+"T. c None",
+/* pixels */
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"0 9 1 1 1.1.>.>.>.;.-.-.: ; - = ",
+"9 c Y.U.L.I.P.K.J.H.G.Z.( / ^ * ",
+"9 c h a F.D.S.M.m.n.d.w.J G ~ & ",
+"9 x a i C.S.k.b.v.e.a.q.G Z Q % ",
+"9 z i u B.g.) ..} W | 0.Z V U $ ",
+"7 l u y B. .Y %.$.H _ 9.B N I # ",
+"7 k y r N.....W R ' { 4.M m P @ ",
+"5 g r e j.d.p.T Y 9.6.3.m n J O ",
+"4 g e q h.p.t.] ` 6.5.2.n v F o ",
+"2 g s i C.A.c.z.l.l.u.w.J F V . ",
+"4 < , > *.&.#. at .@.O.X.o.o o . . ",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T."
+};
diff --git a/src/images/flags/VE.xpm b/src/images/flags/VE.xpm
new file mode 100644
index 0000000..44af4af
--- /dev/null
+++ b/src/images/flags/VE.xpm
@@ -0,0 +1,181 @@
+/* XPM */
+static const char *VE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 159 2",
+" c black",
+". c #434300003B3B",
+"X c #777710107272",
+"o c #7B7B14147575",
+"O c #7D7D19197878",
+"+ c #000000008989",
+"@ c #000000008D8D",
+"# c #000000009191",
+"$ c #00000000BBBB",
+"% c #00000000BFBF",
+"& c #00000000C1C1",
+"* c #14141414C8C8",
+"= c #19191919C9C9",
+"- c #1A1A1A1ACACA",
+"; c #1F1F1F1FCBCB",
+": c #20202020CCCC",
+"> c #25252525CDCD",
+", c #2A2A2A2ACFCF",
+"< c #2B2B2B2BCFCF",
+"1 c #2F2F2F2FD1D1",
+"2 c #36363636CFCF",
+"3 c #30303030D1D1",
+"4 c #35353535D3D3",
+"5 c #36363636D3D3",
+"6 c #3B3B3B3BD1D1",
+"7 c #3B3B3B3BD4D4",
+"8 c #3B3B3B3BD5D5",
+"9 c #3F3F3F3FD3D3",
+"0 c #49494A4ADADA",
+"q c #4B4B4A4ADADA",
+"w c #4B4B4B4BDADA",
+"e c #4F4F4F4FDBDB",
+"r c #50504F4FDBDB",
+"t c #53535353DCDC",
+"y c #54545454DDDD",
+"u c #58585858DDDD",
+"i c #67676969D8D8",
+"p c #6F6F6F6FE2E2",
+"a c #72727272E2E2",
+"s c #76767676E4E4",
+"d c #414197970000",
+"f c #434395950000",
+"g c #80801F1F7C7C",
+"h c #DDDD00000000",
+"j c #DFDF00000000",
+"k c #E1E100000000",
+"l c #E3E300000000",
+"z c #E5E500000000",
+"x c #E7E700000000",
+"c c #E9E900000000",
+"v c #EBEB00000000",
+"b c #EDED00000000",
+"n c #EFEF00000000",
+"m c #F1F100000000",
+"M c #F3F300000000",
+"N c #F5F500000000",
+"B c #F7F700000000",
+"V c #F1F10B0B0B0B",
+"C c #F1F10F0F0E0E",
+"Z c #F9F900000000",
+"A c #F2F213131313",
+"S c #F3F319191919",
+"D c #F4F41E1E1E1E",
+"F c #F5F523232323",
+"G c #F2F22C2C2C2C",
+"H c #F2F22F2F2F2F",
+"J c #F6F629292929",
+"K c #F7F72E2E2E2E",
+"L c #F2F232323232",
+"P c #F3F335353535",
+"I c #F4F439393939",
+"U c #F5F53D3D3D3D",
+"Y c #F8F834343434",
+"T c #F9F93A3A3A3A",
+"R c #FAFA3F3F3F3F",
+"E c #F6F642424242",
+"W c #F7F746464646",
+"Q c #F7F74B4B4B4B",
+"! c #FAFA44444444",
+"~ c #F8F850505050",
+"^ c #F9F954545555",
+"/ c #F9F958585858",
+"( c #FAFA5D5D5D5D",
+") c #FBFB61616262",
+"_ c #FCFC66666666",
+"` c #848424248080",
+"' c #87872A2A8282",
+"] c #8B8B2F2F8686",
+"[ c #8B8B32328686",
+"{ c #8E8E34348989",
+"} c #92923A3A8D8D",
+"| c #95953F3F9090",
+" . c #989845459494",
+".. c #9B9B49499797",
+"X. c #AEAE6A6AAAAA",
+"o. c #B7B7D3D30000",
+"O. c #B7B7D5D50000",
+"+. c #B9B9DADA6969",
+"@. c #E7E7B9B90000",
+"#. c #E9E9BDBD0000",
+"$. c #F3F38A8A7F7F",
+"%. c #EBEBC1C10000",
+"&. c #EDEDCDCD0000",
+"*. c #EFEFD1D10000",
+"=. c #F1F1D5D50000",
+"-. c #F3F3D7D70000",
+";. c #F5F5DBDB0000",
+":. c #F7F7DBDB0000",
+">. c #F9F9DDDD0000",
+",. c #FBFBDFDF0000",
+"<. c #FFFFDDDD0000",
+"1. c #FDFDE1E10000",
+"2. c #FDFDE3E30000",
+"3. c #FDFDE5E50000",
+"4. c #FFFFE7E70000",
+"5. c #FDFDEBEB0000",
+"6. c #F5F5F5F52626",
+"7. c #F6F6F6F62B2B",
+"8. c #F6F6F6F62C2C",
+"9. c #F7F7F7F73131",
+"0. c #F8F8F8F83636",
+"q. c #F8F8F8F83737",
+"w. c #F9F9F9F93C3C",
+"e. c #F9F9F9F93D3D",
+"r. c #F6F6F6F64444",
+"t. c #F7F7F7F74949",
+"y. c #F7F7F7F74E4E",
+"u. c #FAFAFAFA4242",
+"i. c #FBFBFBFB4747",
+"p. c #FCFCFCFC4B4B",
+"a. c #FCFCFCFC4C4C",
+"s. c #F8F8F8F85353",
+"d. c #F9F9F9F95757",
+"f. c #FDFDFDFD5151",
+"g. c #FDFDFDFD5454",
+"h. c #FAFAFAFA5C5C",
+"j. c #FEFEFEFE5959",
+"k. c #FEFEFEFE5C5C",
+"l. c #FBFBFBFB6060",
+"z. c #FCFCFCFC6565",
+"x. c #FCFCFCFC6969",
+"c. c #FDFDFDFD6D6D",
+"v. c #FDFDFDFD7171",
+"b. c #FEFEFEFE7474",
+"n. c #FEFEFEFE7777",
+"m. c #FEFEFEFE7979",
+"M. c #FCFCFCFC7C7C",
+"N. c #83838484DEDE",
+"B. c #95959595E3E3",
+"V. c #9C9C9C9CE6E6",
+"C. c #A5A5A5A5EAEA",
+"Z. c #ACACD2D28989",
+"A. c #DFDFE0E0F0F0",
+"S. c #E3E3E3E3F2F2",
+"D. c #E6E6E6E6F4F4",
+"F. c #E9E9E9E9F7F7",
+"G. c #F1F1F1F1F8F8",
+"H. c #F2F2F2F2F9F9",
+"J. c None",
+/* pixels */
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"5.o.O.4.4.4.1.1.,.,.:.:.=.=.*.&.",
+"d $.M.Z.n.n.v.c.x.z.l.k.d.s.y.%.",
+"d N.i +.j.f.f.a.i.u.e.q.9.8.t.#.",
+"<.m.k.j.g.f.p.i.u.e.0.8.7.6.r. at .",
+"& s u y r w F.H.H.D.< , > - 0 # ",
+"% a t r w F.C.8 5 V.S.> ; - 6 @ ",
+"$ p e w F.C.8 5 1 , B.A.- * 2 + ",
+". X... .} } { ] ' ` g O o X [ ",
+"Z _ ! E T Y K J F D S A C V H j ",
+"Z ) ( ^ ^ ~ Q W E U I P L H H j ",
+"N M M b b b v v x x k k j j h h ",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.",
+"J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J."
+};
diff --git a/src/images/flags/VG.xpm b/src/images/flags/VG.xpm
new file mode 100644
index 0000000..0071622
--- /dev/null
+++ b/src/images/flags/VG.xpm
@@ -0,0 +1,188 @@
+/* XPM */
+static const char *VG_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 166 2",
+" c black",
+". c #000000001D1D",
+"X c #000000001F1F",
+"o c #000000002121",
+"O c #000000002323",
+"+ c #000000002525",
+"@ c #000000002727",
+"# c #000000002B2B",
+"$ c #000000002F2F",
+"% c #000000003131",
+"& c #000000003535",
+"* c #000000003737",
+"= c #000000003B3B",
+"- c #000000004141",
+"; c #000000004545",
+": c #000000004747",
+"> c #000000004B4B",
+", c #000000004D4D",
+"< c #000000005151",
+"1 c #000000005353",
+"2 c #000000005757",
+"3 c #000000005959",
+"4 c #000000005D5D",
+"5 c #000000006363",
+"6 c #000000006565",
+"7 c #000000006969",
+"8 c #000000006D6D",
+"9 c #000000006F6F",
+"0 c #000000007373",
+"q c #000000007777",
+"w c #5D5D0F0F6161",
+"e c #5B5B1F1F7575",
+"r c #737309094B4B",
+"t c #7D7D17175151",
+"y c #474779794141",
+"u c #48487A7A4747",
+"i c #4F4F7F7F4B4B",
+"p c #000000008F8F",
+"a c #000000009D9D",
+"s c #1D1D07078989",
+"d c #1E1E1E1E9E9E",
+"f c #23232323A0A0",
+"g c #24242424A3A3",
+"h c #29292929A2A2",
+"j c #2A2A2A2AA3A3",
+"k c #2A2A2A2AA7A7",
+"l c #2C2C2C2CA0A0",
+"z c #2F2F2F2FA3A3",
+"x c #2D2D2D2DA4A4",
+"c c #2F2F2F2FA4A4",
+"v c #2E2E2E2EA6A6",
+"b c #2F2F2F2FA6A6",
+"n c #2F2F2F2FA7A7",
+"m c #31313535A5A5",
+"M c #35353434A7A7",
+"N c #30303030ABAB",
+"B c #32323232AAAA",
+"V c #34343434A9A9",
+"C c #35353535A8A8",
+"Z c #35353535A9A9",
+"A c #36363636ABAB",
+"S c #36363636AEAE",
+"D c #37373A3AA8A8",
+"F c #3B3B3737A3A3",
+"G c #39393939A9A9",
+"H c #3A3A3A3AABAB",
+"J c #3B3B3B3BAAAA",
+"K c #3B3B3B3BAEAE",
+"L c #3D3D3D3DAAAA",
+"P c #3D3D3E3EACAC",
+"I c #3F3F3F3FADAD",
+"U c #3F3F3F3FAFAF",
+"Y c #3C3C3C3CB0B0",
+"T c #40403F3FAEAE",
+"R c #40404040AEAE",
+"E c #42424242ADAD",
+"W c #46464646AEAE",
+"Q c #48484343ACAC",
+"! c #42424242B1B1",
+"~ c #44444444B0B0",
+"^ c #45454545B0B0",
+"/ c #45454545B3B3",
+"( c #46464646B3B3",
+") c #49494949B0B0",
+"_ c #49494949B3B3",
+"` c #4B4B4B4BB1B1",
+"' c #49494A4AB5B5",
+"] c #4E4E4E4EB3B3",
+"[ c #4F4F4F4FB5B5",
+"{ c #52524949ACAC",
+"} c #50505050B3B3",
+"| c #53535353B5B5",
+" . c #54545454B6B6",
+".. c #53535353BEBE",
+"X. c #58585757B9B9",
+"o. c #58585858B8B8",
+"O. c #5C5C5C5CBABA",
+"+. c #5D5D5D5DBABA",
+"@. c #61615555AFAF",
+"#. c #77775D5DA7A7",
+"$. c #7E7E5F5FA5A5",
+"%. c #61616060BCBC",
+"&. c #61616161BDBD",
+"*. c #62626363BDBD",
+"=. c #65656565BEBE",
+"-. c #66666666BFBF",
+";. c #6A6A6A6AC1C1",
+":. c #6A6A6B6BC1C1",
+">. c #6F6F6F6FC4C4",
+",. c #535381815050",
+"<. c #545482825353",
+"1. c #545484845555",
+"2. c #5C5C89895A5A",
+"3. c #5C5C91914949",
+"4. c #565683836565",
+"5. c #555585856868",
+"6. c #61618C8C6161",
+"7. c #7E7EA6A66F6F",
+"8. c #838311114545",
+"9. c #ADAD57577777",
+"0. c #BFBF67677D7D",
+"q. c #CDCD15151717",
+"w. c #D5D56A6A7171",
+"e. c #DFDF75757878",
+"r. c #DEDE7B7B7D7D",
+"t. c #E2E268686767",
+"y. c #E5E573737171",
+"u. c #E8E87B7B7676",
+"i. c #80805C5C9F9F",
+"p. c #8A8A7A7ABDBD",
+"a. c #91917272A9A9",
+"s. c #93937373A9A9",
+"d. c #A7A76D6D9595",
+"f. c #BBBB7C7C9999",
+"g. c #C3C37E7E9595",
+"h. c #D1D17E7E8B8B",
+"j. c #81819E9E4F4F",
+"k. c #81819D9D5050",
+"l. c #9C9C96966666",
+"z. c #A2A29D9D6F6F",
+"x. c #ABABABAB5858",
+"c. c #ADADADAD5C5C",
+"v. c #C6C6BFBF5D5D",
+"b. c #EAEA83837E7E",
+"n. c #C8C8C2C26767",
+"m. c #97978383BDBD",
+"M. c #9F9FBEBE9E9E",
+"N. c #95959898D4D4",
+"B. c #93939B9BDADA",
+"V. c #ACACC2C29C9C",
+"C. c #A7A7C3C3A2A2",
+"Z. c #ABABC3C3A3A3",
+"A. c #D7D79A9AA9A9",
+"S. c #D6D6A7A7B7B7",
+"D. c #D4D4AAAAB7B7",
+"F. c #DFDFAFAFBBBB",
+"G. c #E0E081818484",
+"H. c #E5E591919494",
+"J. c #EFEFA0A09C9C",
+"K. c #EEEEA2A29E9E",
+"L. c #D4D4B3B3C5C5",
+"P. c #DDDDB6B6C3C3",
+"I. c #DDDDCECEDFDF",
+"U. c #E2E2C0C0CBCB",
+"Y. c #E1E1C8C8D4D4",
+"T. c None",
+/* pixels */
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"0.#.a r 8.p w 9.0 9 7 5 4 3 1 , ",
+"s P.I.S.A.L.Y.N.:.=.&.O.o.| ] : ",
+"q.H.b.y.t.u.e.w.{ ! P D m x ) - ",
+"t F.J.r.G.J.h.d.Q U 6.5.4.<.~ = ",
+"@.U.m.f.g.B.D.s.P S 2.7.V.i U & ",
+"e p...$.$./ &.a.F N 1.M.Z.u K $ ",
+"q >.[ _ ~ E L A n k ,.3.C.y S # ",
+"0 :._ ~ T G A x j g n.k.k.v.M O ",
+"9 ;.~ T G Z x j f d z.c.x.l.z o ",
+"7 &.O.o. .} ) W E L G A B x z . ",
+"6 4 2 1 > : - = & $ $ O o o . . ",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.",
+"T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T."
+};
diff --git a/src/images/flags/VI.xpm b/src/images/flags/VI.xpm
new file mode 100644
index 0000000..1c6ffba
--- /dev/null
+++ b/src/images/flags/VI.xpm
@@ -0,0 +1,167 @@
+/* XPM */
+static const char *VI_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 145 2",
+" c black",
+". c #5A5A4343D5D5",
+"X c #5E5E4949DDDD",
+"o c #64645050DDDD",
+"O c #79796868CBCB",
+"+ c #78786C6CDEDE",
+"@ c #75757575CFCF",
+"# c #77777575CFCF",
+"$ c #494992925050",
+"% c #D6D66B6B5353",
+"& c #D8D860605E5E",
+"* c #D9D971716C6C",
+"= c #DCDC71717373",
+"- c #8B8B7F7FE0E0",
+"; c #9292B3B34D4D",
+": c #BBBB9A9A4242",
+"> c #BFBFBFBF6D6D",
+", c #C9C9BFBF5252",
+"< c #CECECECE2B2B",
+"1 c #EBEBD5D51E1E",
+"2 c #E1E1D7D72525",
+"3 c #E4E4DEDE2B2B",
+"4 c #E3E3D7D73A3A",
+"5 c #E9E9D9D93E3E",
+"6 c #EEEEE8E83131",
+"7 c #DDDDDDDD5A5A",
+"8 c #D0D0CDCD6262",
+"9 c #DCDCD5D56D6D",
+"0 c #DFDFD9D96262",
+"q c #E3E3D4D44242",
+"w c #E0E0D9D94242",
+"e c #E7E7DBDB4242",
+"r c #EBEBDDDD4343",
+"t c #E6E6DDDD5A5A",
+"y c #EBEBDFDF5555",
+"u c #EBEBDFDF5858",
+"i c #ECECE0E04848",
+"p c #ECECE5E55454",
+"a c #E8E8E1E15F5F",
+"s c #F3F3E7E74C4C",
+"d c #F5F5EFEF4949",
+"f c #F5F5EBEB5656",
+"g c #EDEDE8E86767",
+"h c #E6E6E3E37E7E",
+"j c #EDEDE7E77979",
+"k c #F1F1E7E76C6C",
+"l c #F2F2E9E96E6E",
+"z c #F2F2ECEC7373",
+"x c #88888383ADAD",
+"c c #91918C8CBFBF",
+"v c #BCBCBCBCBABA",
+"b c #89898989CDCD",
+"n c #95959595D7D7",
+"m c #9B9B9B9BD9D9",
+"M c #9C9C9C9CE1E1",
+"N c #A9A9A8A8DEDE",
+"B c #BBBBBBBBCBCB",
+"V c #BDBDBDBDCDCD",
+"C c #BFBFBFBFCFCF",
+"Z c #AAAAA9A9E0E0",
+"A c #AEAEAEAEE2E2",
+"S c #B8B8B7B7EAEA",
+"D c #B9B9B9B9E5E5",
+"F c #BEBEBEBEE6E6",
+"G c #B5B5B6B6F1F1",
+"H c #BCBCCECEA6A6",
+"J c #DDDDD5D58181",
+"K c #DDDDDFDF8282",
+"L c #D9D9D1D19595",
+"P c #D4D4CECEBDBD",
+"I c #D3D3D5D5A3A3",
+"U c #E4E4E5E59696",
+"Y c #F3F3E9E98585",
+"T c #F2F2E8E88D8D",
+"R c #F4F4EEEE8F8F",
+"E c #FBFBEFEF8E8E",
+"W c #F7F7EFEF9898",
+"Q c #F7F7EEEE9E9E",
+"! c #ECECE5E5A3A3",
+"~ c #F4F4F0F0A3A3",
+"^ c #F6F6F1F1A2A2",
+"/ c #F8F8F0F0A4A4",
+"( c #F9F9F2F2A9A9",
+") c #FCFCF6F6BEBE",
+"_ c #CBCBCBCBCBCB",
+"` c #CFCFCDCDCDCD",
+"' c #CFCFCFCFCDCD",
+"] c gray81",
+"[ c gray82",
+"{ c LightGray",
+"} c #D3D3D3D3D7D7",
+"| c #D7D7D7D7D7D7",
+" . c gray85",
+".. c #DDDDDDDDDDDD",
+"X. c #DFDFDFDFDFDF",
+"o. c #C2C2C2C2E8E8",
+"O. c #C2C2C1C1EDED",
+"+. c #C9C9C8C8EFEF",
+"@. c #D8D8D8D8E7E7",
+"#. c #DCDCDCDCEAEA",
+"$. c #D6D6D5D5F2F2",
+"%. c #EDEDCFCFCFCF",
+"&. c #EBEBCBCBD0D0",
+"*. c #E7E7E7E7CDCD",
+"=. c #EEEEEEEED6D6",
+"-. c #F8F8F2F2C0C0",
+";. c #F7F7F3F3D0D0",
+":. c #F9F9F6F6D5D5",
+">. c #FCFCF9F9DCDC",
+",. c #E1E1E1E1E1E1",
+"<. c gray89",
+"1. c gray90",
+"2. c #E7E7E7E7E7E7",
+"3. c #E1E1E1E1EAEA",
+"4. c #E6E6EAEAE3E3",
+"5. c #E9E9E9E9E9E9",
+"6. c gray92",
+"7. c gray93",
+"8. c #EDEDEDEDEFEF",
+"9. c #EFEFEFEFEFEF",
+"0. c #EFEFEFEFF1F1",
+"q. c #F7F7F7F7E4E4",
+"w. c #F0F0F1F1E9E9",
+"e. c #F1F1F1F1EFEF",
+"r. c #FDFDFBFBE1E1",
+"t. c #F1F1F1F1F0F0",
+"y. c #F1F1F1F1F1F1",
+"u. c gray95",
+"i. c #F2F2F2F2F3F3",
+"p. c #F5F5F5F5F0F0",
+"a. c gray97",
+"s. c #F7F7F7F7F8F8",
+"d. c #F7F7F7F7FCFC",
+"f. c #F9F9F7F7F0F0",
+"g. c #F8F8F6F6F2F2",
+"h. c #FAFAFAFAF2F2",
+"j. c #FDFDFDFDF5F5",
+"k. c #F9F9F9F9F9F9",
+"l. c gray98",
+"z. c #FBFBFBFBFBFB",
+"x. c #FBFBFBFBFCFC",
+"c. c #FBFBFCFCFBFB",
+"v. c gray99",
+"b. c #FDFDFDFDFEFE",
+"n. c None",
+/* pixels */
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"y.y.y.y.y.0.e.8.8.6.6.1.1.,.,.X.",
+"e.( >.r.) E b.Q W v./ -.:.;.T L ",
+"y.~ g j R ~ j.z d h.q.k p q 7 > ",
+"8.x.Y a p f - c x + J 6 < 4 *.} ",
+"@ d.P h t s O o X . q 3 0 ! A C ",
+"@ $.S b.b.k p.= &.& 5 I m #.Z C ",
+"n O.+.z.$ u h.* &.% i G b 3.N B ",
+"8.c.k.b.r ; U , : 8 K 1 @.u.u.' ",
+"6.c.x.k.w.H 4.e 2 9 M v y.y.u._ ",
+"6.z.z.h.k.a.a.p.=.o.D F u.y.y._ ",
+"1.1.<.,.X.X. .| | { [ ] ' _ _ _ ",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n."
+};
diff --git a/src/images/flags/VN.xpm b/src/images/flags/VN.xpm
new file mode 100644
index 0000000..3efc913
--- /dev/null
+++ b/src/images/flags/VN.xpm
@@ -0,0 +1,150 @@
+/* XPM */
+static const char *VN_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 128 2",
+" c black",
+". c #DDDD00000000",
+"X c #DFDF00000000",
+"o c #E1E100000000",
+"O c #E3E300000000",
+"+ c #E5E500000000",
+"@ c #E7E700000000",
+"# c #E9E900000000",
+"$ c #EBEB00000000",
+"% c #EDED00000000",
+"& c #EFEF00000000",
+"* c #F1F100000000",
+"= c #F3F300000000",
+"- c #F5F500000000",
+"; c #F7F700000000",
+": c #F1F10B0B0B0B",
+"> c #F1F10F0F0E0E",
+", c #F9F900000000",
+"< c #FBFB00000000",
+"1 c #FDFD00000000",
+"2 c red",
+"3 c #F2F210101010",
+"4 c #F2F213131313",
+"5 c #F2F214141414",
+"6 c #F3F319191919",
+"7 c #F3F31A1A1A1A",
+"8 c #F4F41F1F1F1F",
+"9 c #F3F327271919",
+"0 c #F4F430301E1E",
+"q c #F4F420202020",
+"w c #F5F523232323",
+"e c #F5F524242424",
+"r c #F5F525252525",
+"t c #F5F526262626",
+"y c #F2F22C2C2C2C",
+"u c #F2F22F2F2F2F",
+"i c #F6F629292929",
+"p c #F6F62B2B2B2B",
+"a c #F6F62C2C2C2C",
+"s c #F6F633332B2B",
+"d c #F2F232323232",
+"f c #F3F332323232",
+"g c #F3F335353535",
+"h c #F7F731313131",
+"j c #F4F436363636",
+"k c #F4F439393939",
+"l c #F4F43B3B3B3B",
+"z c #F5F53D3D3D3D",
+"x c #F5F53F3F3F3F",
+"c c #F8F837373636",
+"v c #F8F837373737",
+"b c #F8F83E3E3434",
+"n c #F9F93A3A3A3A",
+"m c #F9F93C3C3C3C",
+"M c #F9F93C3C3D3D",
+"N c #FAFA3F3F3F3F",
+"B c #F6F642422B2B",
+"V c #F7F743432E2E",
+"C c #F6F64E4E2A2A",
+"Z c #F7F760602F2F",
+"A c #F6F677772A2A",
+"S c #F9F973733A3A",
+"D c #F6F642424242",
+"F c #F6F644444444",
+"G c #F7F746464646",
+"H c #F7F749494949",
+"J c #F7F74B4B4B4B",
+"K c #F7F74E4E4E4E",
+"L c #FAFA40404040",
+"P c #FAFA42424242",
+"I c #FAFA44444444",
+"U c #FBFB45454545",
+"Y c #FBFB49494949",
+"T c #FBFB4A4A4949",
+"R c #FCFC4A4A4B4B",
+"E c #FCFC4B4B4B4B",
+"W c #FCFC4F4F4F4F",
+"Q c #FBFB54544646",
+"! c #F8F850505050",
+"~ c #F8F853535353",
+"^ c #F9F954545555",
+"/ c #F9F957575757",
+"( c #FDFD51515050",
+") c #FDFD51515151",
+"_ c #FDFD53535353",
+"` c #FDFD54545454",
+"' c #F9F958585858",
+"] c #FAFA5C5C5C5C",
+"[ c #FAFA5D5D5D5D",
+"{ c #FEFE58585858",
+"} c #FEFE59595959",
+"| c #FEFE5C5C5C5C",
+" . c #FEFE5F5F5F5F",
+".. c #FBFB76764747",
+"X. c #FCFC78784C4C",
+"o. c #FBFB60606060",
+"O. c #FBFB61616262",
+"+. c #FCFC65656565",
+"@. c #FCFC66666666",
+"#. c #FCFC69696969",
+"$. c #FCFC6A6A6A6A",
+"%. c #FDFD6D6D6D6D",
+"&. c #FDFD6F6F6F6F",
+"*. c #FDFD70707171",
+"=. c #FEFE72727373",
+"-. c #FEFE74747474",
+";. c #FEFE76767676",
+":. c #FEFE77777777",
+">. c #FEFE79797979",
+",. c #FFFF7B7B7A7A",
+"<. c #FFFF7B7B7B7B",
+"1. c #FBFBBFBF4747",
+"2. c #F8F8C1C13636",
+"3. c #F7F7D2D23030",
+"4. c #F5F5F5F52424",
+"5. c #F7F7F7F72F2F",
+"6. c #F7F7F7F73030",
+"7. c #F8F8F8F83434",
+"8. c #F8F8F8F83535",
+"9. c #F8F8F8F83636",
+"0. c #F9F9F9F93B3B",
+"q. c #F9F9F9F93C3C",
+"w. c #FBFBCBCB4646",
+"e. c #FAFACCCC4242",
+"r. c #FCFCD5D54B4B",
+"t. c #FAFAFAFA4040",
+"y. c #FAFAFAFA4141",
+"u. c None",
+/* pixels */
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"2 2 2 2 < 2 2 2 < < ; ; = = % % ",
+"2 <.<.<.;.-.&.%.#.+.o.] / ~ K $ ",
+"2 <.| | | _ _ X...P M c h a H $ ",
+"2 <.| | _ _ T 1.e.M c h p t F + ",
+"2 ;./ _ W r.w.t.0.2.3.s t q x + ",
+"2 =._ W T Q t.0.9.6.B t 8 6 l + ",
+"2 &.W T U L S 8.5.A t 8 6 4 j + ",
+"< $.T I L n 8.Z C 4.q 6 5 3 h . ",
+"; @.I L n b V p q 0 9 5 > : u . ",
+"; O.[ ' / K T F D x l g f u u . ",
+"; = = % % % $ $ + + O O . . . . ",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.",
+"u.u.u.u.u.u.u.u.u.u.u.u.u.u.u.u."
+};
diff --git a/src/images/flags/VU.xpm b/src/images/flags/VU.xpm
new file mode 100644
index 0000000..f40952c
--- /dev/null
+++ b/src/images/flags/VU.xpm
@@ -0,0 +1,178 @@
+/* XPM */
+static const char *VU_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 156 2",
+" c black",
+". c #010100000000",
+"X c #090900000000",
+"o c #191917171414",
+"O c #1E1E1C1C1919",
+"+ c #00003D3D0000",
+"@ c #2D2D1B1B0000",
+"# c #232322221F1F",
+"$ c #242423232020",
+"% c #292927272424",
+"& c #2A2A28282525",
+"* c #2E2E2D2D2A2A",
+"= c #2F2F2E2E2B2B",
+"- c #343432322F2F",
+"; c #353533333030",
+": c #383837373535",
+"> c #3A3A38383636",
+", c #3B3B39393636",
+"< c #3E3E3D3D3A3A",
+"1 c #3F3F3E3E3C3C",
+"2 c #3C3C5A5A3A3A",
+"3 c #3D3D5A5A3A3A",
+"4 c #434341413F3F",
+"5 c #454543434141",
+"6 c #494949494646",
+"7 c #4D4D4B4B4949",
+"8 c #4E4E4C4C4B4B",
+"9 c #5F5F5D5D5C5C",
+"0 c #5B5B74745858",
+"q c #757552525151",
+"w c #7C7C5A5A5959",
+"e c #74746F6F5353",
+"r c #6A6A68686666",
+"t c #6E6E6D6D6A6A",
+"y c #7B7B7A7A7979",
+"u c #7D7D7D7D7A7A",
+"i c #000081810000",
+"p c #000083830000",
+"a c #000087870000",
+"s c #000089890000",
+"d c #00008B8B0000",
+"f c #00008F8F0000",
+"g c #000091910000",
+"h c #000093930000",
+"j c #000099990000",
+"k c #00009D9D0000",
+"l c #00009F9F0000",
+"z c #0000A3A30000",
+"x c #363691913434",
+"c c #36369A9A3434",
+"v c #0B0BC2C20B0B",
+"b c #0F0FC4C40E0E",
+"n c #1313C6C61313",
+"m c #1010CACA1010",
+"M c #1414CBCB1414",
+"N c #1818C7C71919",
+"B c #1919CCCC1919",
+"V c #1E1EC9C91E1E",
+"C c #1F1FCFCF1F1F",
+"Z c #2323CBCB2323",
+"A c #2929CDCD2929",
+"S c #2C2CCACA2C2C",
+"D c #2F2FCACA2F2F",
+"F c #2F2FCBCB2F2F",
+"G c #2424D0D02424",
+"H c #2A2AD2D22A2A",
+"J c #2E2ED3D32E2E",
+"K c #2F2FD5D52F2F",
+"L c #3232CCCC3232",
+"P c #3535CDCD3535",
+"I c #3939CFCF3939",
+"U c #3333D1D13232",
+"Y c #3D3DD0D03D3D",
+"T c #5555ADAD5555",
+"R c #4242D2D24242",
+"E c #4646D3D34646",
+"W c #4B4BD5D54B4B",
+"Q c #5050D8D85050",
+"! c #959500000000",
+"~ c #B3B375750000",
+"^ c #808076764444",
+"/ c #818177774545",
+"( c #818177774646",
+") c #89897F7F5050",
+"_ c #96967A7A7979",
+"` c #B3B34C4C4B4B",
+"' c #E7E700000000",
+"] c #E9E900000000",
+"[ c #EBEB00000000",
+"{ c #EDED00000000",
+"} c #EFEF00000000",
+"| c #F1F100000000",
+" . c #F3F300000000",
+".. c #F5F500000000",
+"X. c #F7F700000000",
+"o. c #F9F900000000",
+"O. c #FBFB00000000",
+"+. c #FDFD00000000",
+"@. c #F5F526262626",
+"#. c #F6F62B2B2B2B",
+"$. c #F6F62C2C2C2C",
+"%. c #F7F731313131",
+"&. c #F8F837373636",
+"*. c #F8F837373737",
+"=. c #F9F93C3C3C3C",
+"-. c #F9F93C3C3D3D",
+";. c #C2C255555454",
+":. c #D0D077777777",
+">. c #F6F644444444",
+",. c #F7F749494949",
+"<. c #F7F74E4E4E4E",
+"1. c #FAFA41414242",
+"2. c #FAFA42424242",
+"3. c #FBFB47474747",
+"4. c #FCFC4C4C4C4C",
+"5. c #F8F853535353",
+"6. c #F9F957575757",
+"7. c #FDFD51515151",
+"8. c #FAFA5C5C5C5C",
+"9. c #FBFB60606060",
+"0. c #FCFC65656565",
+"q. c #FCFC69696969",
+"w. c #FDFD6D6D6D6D",
+"e. c #FDFD70707171",
+"r. c #FEFE74747474",
+"t. c #8E8E85855959",
+"y. c #94948B8B5F5F",
+"u. c #94948C8C6262",
+"i. c #A7A79F9F7B7B",
+"p. c #BFBFAFAF4F4F",
+"a. c #B0B0A6A66F6F",
+"s. c #C7C795950000",
+"d. c #D5D5ABAB0000",
+"f. c #DBDBBDBD2222",
+"g. c #CDCDBFBF7373",
+"h. c #DDDDC0C02828",
+"j. c #DEDEC2C22C2C",
+"k. c #E0E0C4C43232",
+"l. c #E2E2C6C63737",
+"z. c #E3E3C8C83C3C",
+"x. c #D7D7C2C24949",
+"c. c #DADAC6C65454",
+"v. c #D5D5C7C77676",
+"b. c #E0E0C7C74242",
+"n. c #E1E1C8C84545",
+"m. c #E1E1C8C84646",
+"M. c #E5E5CACA4242",
+"N. c #E8E8CFCF4242",
+"B. c #E4E4CDCD5050",
+"V. c #E9E9D3D34F4F",
+"C. c #E7E7D0D05A5A",
+"Z. c #ECECD6D65858",
+"A. c #E6E6D1D16262",
+"S. c #E9E9D3D36161",
+"D. c #EDEDDCDC7F7F",
+"F. c None",
+/* pixels */
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"@ d.X ! +.+.+.+.O.O.X.X. . .{ { ",
+" i.D._ :.r.e.w.q.0.9.8.6.5.<.[ ",
+" u y.S.w ;.7.4.3.2.-.&.%.$.,.[ ",
+" y 9 t.C.q ` 3.2.-.&.%.#. at .>.' ",
+" v.Z.c.) B.6 5 1 > ; = & $ 4 ",
+" v.e V.8 ( N.M.z.l.k.j.f.f.n.~ ",
+" a.p.x.( n.< > - = % # O o > ",
+" t 8 ^ n.2 x J H Z C B M M U h ",
+" r ^ n.2 c J A Z V N M b v F a ",
+" u.A.0 T Q W E R Y Y P L D S i ",
+" s. + z l k j h g g a a a a a ",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.",
+"F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F."
+};
diff --git a/src/images/flags/WF.xpm b/src/images/flags/WF.xpm
new file mode 100644
index 0000000..b77f8c9
--- /dev/null
+++ b/src/images/flags/WF.xpm
@@ -0,0 +1,161 @@
+/* XPM */
+static const char *WF_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 139 2",
+" c black",
+". c #676700000000",
+"X c #6D6D00000000",
+"o c #6F6F00000000",
+"O c #737300000000",
+"+ c #757500000000",
+"@ c #777700000000",
+"# c #7B7B00000000",
+"$ c #7F7F00000000",
+"% c #000000009393",
+"& c #000000009595",
+"* c #76767676D1D1",
+"= c #79797979D3D3",
+"- c #7B7B7B7BD3D3",
+"; c #818100000000",
+": c #858500000000",
+"> c #898900000000",
+", c #8D8D00000000",
+"< c #8F8F00000000",
+"1 c #939300000000",
+"2 c #959500000000",
+"3 c #979700000000",
+"4 c #9B9B00000000",
+"5 c #9F9F00000000",
+"6 c #A1A100000000",
+"7 c #A3A300000000",
+"8 c #A5A500000000",
+"9 c #A7A700000000",
+"0 c #ABAB00000000",
+"q c #ADAD00000000",
+"w c #AFAF00000000",
+"e c #B7B70B0B0B0B",
+"r c #B7B70F0F0E0E",
+"t c #B8B813131313",
+"y c #BABA19191919",
+"u c #BEBE1E1E1E1E",
+"i c #BDBD25252525",
+"p c #C0C023232323",
+"a c #C2C227272727",
+"s c #C3C329292929",
+"d c #C3C32A2A2A2A",
+"f c #C0C02C2C2C2C",
+"g c #C1C12F2F2F2F",
+"h c #C2C22E2E2E2E",
+"j c #C3C32F2F2F2F",
+"k c #C4C42C2C2C2C",
+"l c #C5C52E2E2E2E",
+"z c #C5C52F2F2F2F",
+"x c #C2C232323232",
+"c c #C3C332323232",
+"v c #C3C335353535",
+"b c #C3C336363636",
+"n c #C5C531313131",
+"m c #C5C536363636",
+"M c #C5C537373737",
+"N c #C7C734343434",
+"B c #C7C735353535",
+"V c #C3C33B3B3B3B",
+"C c #C5C539393939",
+"Z c #C7C73A3A3A3A",
+"A c #C7C73B3B3B3B",
+"S c #C7C73D3D3C3C",
+"D c #C7C73D3D3D3D",
+"F c #C7C73F3F3F3F",
+"G c #C9C93A3A3A3A",
+"H c #C9C93B3B3A3A",
+"J c #C9C93B3B3B3B",
+"K c #C8C83B3B3C3C",
+"L c #C9C93C3C3D3D",
+"P c #CBCB3F3F3F3F",
+"I c #C8C842424242",
+"U c #CBCB40404040",
+"Y c #CACA43434343",
+"T c #CACA44444444",
+"R c #CACA46464646",
+"E c #CCCC41414141",
+"W c #CCCC41414242",
+"Q c #CCCC42424242",
+"! c #CDCD44444444",
+"~ c #CDCD45454545",
+"^ c #CECE47474747",
+"/ c #CCCC49494949",
+"( c #CCCC4B4B4B4B",
+") c #CFCF49494949",
+"_ c #CFCF4A4A4949",
+"` c #CDCD4E4E4E4E",
+"' c #CECE4E4E4E4E",
+"] c #CECE50505050",
+"[ c #CECE51515151",
+"{ c #CFCF53535353",
+"} c #D1D143434141",
+"| c #D1D14E4E4E4E",
+" . c #D1D14F4F4F4F",
+".. c #D1D14F4F5050",
+"X. c #D0D053535353",
+"o. c #D0D054545454",
+"O. c #D0D054545555",
+"+. c #D3D354545454",
+"@. c #D2D257575757",
+"#. c #D2D258585858",
+"$. c #D3D35C5C5C5C",
+"%. c #D3D35D5D5D5D",
+"&. c #D4D459595959",
+"*. c #D4D460606060",
+"=. c #D5D561616262",
+"-. c #D6D665656565",
+";. c #D7D766666666",
+":. c #D8D869696969",
+">. c #D8D86A6A6A6A",
+",. c #D9D96F6F6E6E",
+"<. c #DADA6F6F6F6F",
+"1. c #D9D974747474",
+"2. c #DDDD77777777",
+"3. c #DADA8C8C8C8C",
+"4. c #DADA8E8E8E8E",
+"5. c #DDDD89898989",
+"6. c #DFDF8D8D8E8E",
+"7. c #E0E090909090",
+"8. c #E2E292929393",
+"9. c #E1E194949494",
+"0. c #E2E295959595",
+"q. c #E3E396969696",
+"w. c #E4E498989898",
+"e. c #E2E2AEAEAEAE",
+"r. c #E3E3AFAFAFAF",
+"t. c #E4E4AEAEAEAE",
+"y. c #E9E9A9A9A9A9",
+"u. c #E9E9ABABABAB",
+"i. c #E5E5B1B1B1B1",
+"p. c #E5E5BEBEBEBE",
+"a. c #EDEDCBCBCBCB",
+"s. c #EEEECDCDCDCD",
+"d. c #EFEFD8D8D8D8",
+"f. c #F3F3F3F3F3F3",
+"g. c gray97",
+"h. c #FDFDFDFDFDFD",
+"j. c #FEFEFEFEFEFE",
+"k. c gray100",
+"l. c None",
+/* pixels */
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"& & k.k.w q ) w q 9 7 5 5 2 1 2 ",
+"& - k.k.1.1.u.,.>.;.%.$. at .{ ` : ",
+"& - h.k.&.{ w.| ^ Q L m n k / : ",
+"& - k.k.+.{ 9.) Q ` s.g.d.F T $ ",
+"% * k.h...{ 9.U K a.Y i.Z r.F $ ",
+"} y.q.8.6.6.5.J m g.t.a 3.f.V # ",
+"w <. .) ~ Q J N j d.Z 3.k p.b + ",
+"q >.) ~ P J N j d Z r.f.p.i c O ",
+"0 ;.! P J N j d p u y t r e c o ",
+"7 =.%.#. at .` ( T Y F Z V c k i . ",
+"9 4 2 1 , , > : $ # + + O o X O ",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.",
+"l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l."
+};
diff --git a/src/images/flags/WS.xpm b/src/images/flags/WS.xpm
new file mode 100644
index 0000000..a092e06
--- /dev/null
+++ b/src/images/flags/WS.xpm
@@ -0,0 +1,156 @@
+/* XPM */
+static const char *WS_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 134 2",
+" c black",
+". c #000000002323",
+"X c #000000002B2B",
+"o c #000000003131",
+"O c #000000003333",
+"+ c #000000003737",
+"@ c #000000003939",
+"# c #000000003B3B",
+"$ c #414136367F7F",
+"% c #46463B3B8282",
+"& c #47473B3B8383",
+"* c #4B4B40408686",
+"= c #4C4C41418686",
+"- c #4C4C41418888",
+"; c #464646469494",
+": c #4B4B4B4B9393",
+"> c #4B4B4B4B9494",
+", c #505046468A8A",
+"< c #515147478A8A",
+"1 c #525247478B8B",
+"2 c #55554A4A8D8D",
+"3 c #57574C4C8E8E",
+"4 c #515151519595",
+"5 c #5E5E53539393",
+"6 c #585858589B9B",
+"7 c #5A5A5A5A9C9C",
+"8 c #63636363A1A1",
+"9 c #69696969A4A4",
+"0 c #72726969A1A1",
+"q c #75756D6DA3A3",
+"w c #78786F6FA5A5",
+"e c #71717171A9A9",
+"r c #7A7A7272A8A8",
+"t c #79797979AEAE",
+"y c #7A7A7A7AAFAF",
+"u c #7B7B7B7BAEAE",
+"i c #7B7B7B7BAFAF",
+"p c #76767676B0B0",
+"a c #DDDD00000000",
+"s c #DFDF00000000",
+"d c #E1E100000000",
+"f c #E3E300000000",
+"g c #E5E500000000",
+"h c #E7E700000000",
+"j c #E9E900000000",
+"k c #EBEB00000000",
+"l c #EDED00000000",
+"z c #EFEF00000000",
+"x c #F1F100000000",
+"c c #F3F300000000",
+"v c #F5F500000000",
+"b c #F7F700000000",
+"n c #F1F10B0B0B0B",
+"m c #F1F10F0F0E0E",
+"M c #F9F900000000",
+"N c #FBFB00000000",
+"B c #FDFD00000000",
+"V c #F2F210101010",
+"C c #F2F213131313",
+"Z c #F2F214141414",
+"A c #F3F319191919",
+"S c #F3F31A1A1A1A",
+"D c #F4F41E1E1E1E",
+"F c #F4F41F1F1F1F",
+"G c #F4F420202020",
+"H c #F5F523232323",
+"J c #F5F524242424",
+"K c #F5F525252525",
+"L c #F5F526262626",
+"P c #F2F22C2C2C2C",
+"I c #F2F22F2F2F2F",
+"U c #F6F629292929",
+"Y c #F6F62A2A2A2A",
+"T c #F6F62B2B2B2B",
+"R c #F6F62C2C2C2C",
+"E c #F7F72E2E2E2E",
+"W c #F7F72F2F2F2F",
+"Q c #F2F232323232",
+"! c #F3F332323232",
+"~ c #F3F335353535",
+"^ c #F7F730303030",
+"/ c #F7F731313131",
+"( c #F4F436363636",
+") c #F4F439393939",
+"_ c #F4F43B3B3B3B",
+"` c #F5F53D3D3D3D",
+"' c #F5F53F3F3F3F",
+"] c #F8F834343434",
+"[ c #F8F835353535",
+"{ c #F8F836363636",
+"} c #F8F837373636",
+"| c #F8F837373737",
+" . c #F9F93A3A3A3A",
+".. c #F9F93B3B3A3A",
+"X. c #F9F93C3C3C3C",
+"o. c #F9F93C3C3D3D",
+"O. c #FAFA3F3F3F3F",
+"+. c #F6F642424242",
+"@. c #F6F644444444",
+"#. c #F7F746464646",
+"$. c #F7F749494949",
+"%. c #F7F74B4B4B4B",
+"&. c #F7F74E4E4E4E",
+"*. c #FAFA40404040",
+"=. c #FAFA42424242",
+"-. c #FAFA44444444",
+";. c #FBFB45454545",
+":. c #FBFB49494949",
+">. c #FBFB4A4A4949",
+",. c #FCFC4F4F4F4F",
+"<. c #F8F850505050",
+"1. c #F8F853535353",
+"2. c #F9F954545555",
+"3. c #F9F957575757",
+"4. c #F9F958585858",
+"5. c #FAFA5C5C5C5C",
+"6. c #FAFA5D5D5D5D",
+"7. c #FBFB60606060",
+"8. c #FBFB61616262",
+"9. c #FCFC65656565",
+"0. c #FCFC66666666",
+"q. c #FCFC6A6A6A6A",
+"w. c #FDFD6F6F6F6F",
+"e. c #8B8B8B8BB9B9",
+"r. c #8C8C8C8CB9B9",
+"t. c #9C9C9C9CC3C3",
+"y. c #9C9C9D9DC3C3",
+"u. c #9B9BA3A3CACA",
+"i. c #ABABABABCBCB",
+"p. c #AEAEB5B5D4D4",
+"a. c #BBBBBBBBD6D6",
+"s. c #BEBEBEBED6D6",
+"d. c #D0D0D1D1E2E2",
+"f. c None",
+/* pixels */
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"# # # # # o o X . M b b c c l l ",
+"# i t.d.e.s.e.q 0 9.7.5.3.1.&.k ",
+"# i a.9 8 t.4 3 < =.o.} / R $.k ",
+"# t i 6 i.e > < - o.} / T L @.g ",
+"+ t 6 p.u.: ; * & } ^ T L G ' g ",
+"o r 5 w 2 < & % $ ^ T J G A ` g ",
+"B w.,.:.;.=.o.} E T J F A Z ( g ",
+"B q.:.;.O. .} W T J F A Z V / a ",
+"M 9.;.*. ./ R T G F A C m n I a ",
+"b 8.6.4.3.&.>. at .+.' ) ~ ! I I a ",
+"b c c l l l k k g g f f a a a a ",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.",
+"f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f."
+};
diff --git a/src/images/flags/YE.xpm b/src/images/flags/YE.xpm
new file mode 100644
index 0000000..8bbabc3
--- /dev/null
+++ b/src/images/flags/YE.xpm
@@ -0,0 +1,142 @@
+/* XPM */
+static const char *YE_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 120 2",
+" c black",
+". c #161616161616",
+"X c gray10",
+"o c #1E1E1E1E1E1E",
+"O c #222223232323",
+"+ c #282828282828",
+"@ c #2D2D2D2D2D2D",
+"# c #333332323232",
+"$ c gray21",
+"% c #373737373737",
+"& c gray22",
+"* c gray23",
+"= c gray24",
+"- c #3F3F3F3F3F3F",
+"; c #424241414141",
+": c #434343434343",
+"> c #464646464646",
+", c #484848484848",
+"< c gray29",
+"1 c gray30",
+"2 c gray31",
+"3 c #535353535353",
+"4 c #585857575858",
+"5 c gray36",
+"6 c #606060606060",
+"7 c #656565656565",
+"8 c #696969696A6A",
+"9 c gray43",
+"0 c #D5D500000000",
+"q c #D7D700000000",
+"w c #D9D900000000",
+"e c #DBDB00000000",
+"r c #DFDF00000000",
+"t c #E1E100000000",
+"y c #E3E300000000",
+"u c #E5E500000000",
+"i c #E7E700000000",
+"p c #E9E900000000",
+"a c #EBEB00000000",
+"s c #EDED00000000",
+"d c #EFEF00000000",
+"f c #ECEC3C3C2C2C",
+"g c #EDED41413131",
+"h c #EFEF46463737",
+"j c #F0F04C4C3D3D",
+"k c #E7E74D4D4D4D",
+"l c #EEEE57574949",
+"z c #EFEF5C5C4E4E",
+"x c #F1F150504242",
+"c c #F2F255554747",
+"v c #F3F359594C4C",
+"b c #F4F45D5D5151",
+"n c #F0F060605353",
+"m c #F2F265655757",
+"M c #F4F462625454",
+"N c #F5F566665959",
+"B c #F2F269695C5C",
+"V c #F6F669695C5C",
+"C c #F6F66C6C5F5F",
+"Z c #F3F36D6D6060",
+"A c #F4F471716565",
+"S c #F5F575756969",
+"D c #F6F678786D6D",
+"F c #F6F67B7B7171",
+"G c #F7F77F7F7474",
+"H c #818181817F7F",
+"J c #F7F781817777",
+"K c #F7F784847979",
+"L c #F8F885857A7A",
+"P c #F8F885857B7B",
+"I c gray61",
+"U c gray62",
+"Y c gray63",
+"T c #A2A2A2A2A2A2",
+"R c #A5A5A5A5A5A5",
+"E c gray66",
+"W c #A9A9A9A9A9A9",
+"Q c gray67",
+"! c #AEAEAEAEAEAE",
+"~ c gray69",
+"^ c gray70",
+"/ c gray71",
+"( c gray72",
+") c #FFFF8D8D8D8D",
+"_ c #F5F5A7A7A7A7",
+"` c #F6F6A9A9A9A9",
+"' c #F7F7ADADACAC",
+"] c #F8F8AFAFAFAF",
+"[ c #F6F6B3B3B3B3",
+"{ c #F9F9B2B2B2B2",
+"} c #FAFAB3B3B4B4",
+"| c #FBFBB6B6B6B6",
+" . c #FCFCB9B9B9B9",
+".. c #FDFDBBBBBBBB",
+"X. c #FDFDBDBDBDBD",
+"o. c #FEFEBFBFBFBF",
+"O. c #C5C5C5C5C5C5",
+"+. c LightGray",
+"@. c #D5D5D5D5D5D5",
+"#. c #D7D7D7D7D7D7",
+"$. c #FEFEC0C0C0C0",
+"%. c #FEFECCCCCCCC",
+"&. c #F1F1F1F1F1F1",
+"*. c gray95",
+"=. c #F3F3F3F3F3F3",
+"-. c #F4F4F4F4F4F4",
+";. c #F4F4F5F5F5F5",
+":. c gray96",
+">. c #F6F6F6F6F6F6",
+",. c gray97",
+"<. c #F8F8F8F8F8F8",
+"1. c #F9F9F9F9F9F9",
+"2. c gray98",
+"3. c #FBFBFBFBFBFB",
+"4. c #FBFBFCFCFBFB",
+"5. c gray99",
+"6. c #FDFDFCFCFDFD",
+"7. c #FDFDFDFDFDFD",
+"8. c #FEFEFEFEFEFE",
+"9. c None",
+/* pixels */
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"d d d d p d d p p i i t t t w w ",
+"d P P K J G F D S A Z B m n z q ",
+"d P C V N M b v c x j h g f l q ",
+") %.$.o.o.....| | ' ' ' ` _ [ k ",
+":.8.8.8.3.3.2.2.2.2.,.:.:.-.:.#.",
+"*.8.8.3.2.2.2.2.,.,.;.;.:.*.;.#.",
+"*.8.3.8.2.2.2.2.,.,.;.-.-.*.-.+.",
+"H O./ / ^ ~ ! Q W R T Y U I W % ",
+" 9 1 < : = & # @ + O o X . % ",
+" 8 7 6 5 4 3 2 < > ; - * % % ",
+" ",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.",
+"9.9.9.9.9.9.9.9.9.9.9.9.9.9.9.9."
+};
diff --git a/src/images/flags/YT.xpm b/src/images/flags/YT.xpm
new file mode 100644
index 0000000..0f2b347
--- /dev/null
+++ b/src/images/flags/YT.xpm
@@ -0,0 +1,157 @@
+/* XPM */
+static const char *YT_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 135 2",
+" c black",
+". c #4C4C4242A9A9",
+"X c #47474747B1B1",
+"o c #4B4B4D4DB6B6",
+"O c #4B4B4F4FB5B5",
+"+ c #62625A5AB3B3",
+"@ c #62626464BEBE",
+"# c #D8D83B3B2929",
+"$ c #D9D93E3E2A2A",
+"% c #D5D53E3E3434",
+"& c #DADA42422F2F",
+"* c #D5D541413737",
+"= c #D6D642423939",
+"- c #DEDE4D4D3D3D",
+"; c #DBDB53534747",
+": c #AEAEACACADAD",
+"> c #B5B5B2B2B2B2",
+", c #B5B5B4B4B5B5",
+"< c #B6B6B5B5B6B6",
+"1 c #BBBBB8B8B8B8",
+"2 c #BBBBBABABBBB",
+"3 c #B5B5B7B7D6D6",
+"4 c #B2B2B5B5DADA",
+"5 c #B4B4B6B6DBDB",
+"6 c #C0C0BDBDBABA",
+"7 c #E2E292929595",
+"8 c #E0E098989999",
+"9 c #E5E598989A9A",
+"0 c #E6E6ADADAEAE",
+"q c #FAFAB1B1B1B1",
+"w c #FEFEB3B3B3B3",
+"e c #FDFDBFBFBFBF",
+"r c #FEFEBEBEBEBE",
+"t c #C6C6C5C5C5C5",
+"y c #C7C7C5C5C4C4",
+"u c #C7C7C7C7C6C6",
+"i c #C9C9C7C7C8C8",
+"p c #CBCBC9C9C9C9",
+"a c #CDCDCACAC9C9",
+"s c #CCCCCACACACA",
+"d c #CECECDCDCDCD",
+"f c #CFCFCDCDCDCD",
+"g c gray81",
+"h c gray82",
+"j c #D2D2D1D1D1D1",
+"k c #D3D3D1D1D1D1",
+"l c LightGray",
+"z c #D5D5D5D5D5D5",
+"x c #D7D7D5D5D5D5",
+"c c #D7D7D7D7D7D7",
+"v c #D9D9D7D7D7D7",
+"b c gray86",
+"n c gainsboro",
+"m c #DDDDDDDDDDDD",
+"M c #DFDFDFDFDFDF",
+"N c #C4C4C7C7E1E1",
+"B c #DBDBD8D8EAEA",
+"V c #DBDBD9D9EAEA",
+"C c #FBFBC1C1C1C1",
+"Z c #FCFCC3C3C3C3",
+"A c #FDFDC6C6C6C6",
+"S c #E1E1E1E1DFDF",
+"D c #E1E1E2E2E2E2",
+"F c #E1E1E3E3E3E3",
+"G c #E6E6E0E0E1E1",
+"H c #E6E6E3E3E2E2",
+"J c #E4E4E4E4E4E4",
+"K c gray90",
+"L c #E7E7E6E6E7E7",
+"P c #E7E7E7E7E7E7",
+"I c #E6E6EAEAEAEA",
+"U c #E8E8E7E7E7E7",
+"Y c #EBEBE7E7E7E7",
+"T c #EDEDE3E3E3E3",
+"R c #EFEFE5E5E5E5",
+"E c #E9E9E8E8E6E6",
+"W c gray91",
+"Q c #E9E9E9E9E9E9",
+"! c #E9E9E9E9EBEB",
+"~ c #E9E9EBEBE9E9",
+"^ c #EAEAE9E9E9E9",
+"/ c gray92",
+"( c #EBEBEBEBEDED",
+") c #ECECE8E8E9E9",
+"_ c #EDEDEBEBEBEB",
+"` c #EEEEEAEAEAEA",
+"' c #EFEFEBEBEBEB",
+"] c gray93",
+"[ c #EEEEEEEEEEEE",
+"{ c #EFEFEFEFEFEF",
+"} c #EFEFEFEFF0F0",
+"| c #EBEBF0F0F0F0",
+" . c #EEEEF0F0F0F0",
+".. c #EFEFF0F0F0F0",
+"X. c #EFEFF1F1F1F1",
+"o. c #F1F1E9E9E9E9",
+"O. c #F1F1EFEFEFEF",
+"+. c #F3F3EFEFEFEF",
+"@. c #F9F9EEEEEEEE",
+"#. c #FEFEE8E8E8E8",
+"$. c #F3F3EFEFF1F1",
+"%. c gray94",
+"&. c #F1F1F1F1F1F1",
+"*. c #F2F2F1F1F2F2",
+"=. c gray95",
+"-. c #F2F2F3F3F3F3",
+";. c #F3F3F3F3F3F3",
+":. c #F5F5F1F1F1F1",
+">. c #F5F5F3F3F3F3",
+",. c #F4F4F4F4F4F4",
+"<. c #F4F4F4F4F5F5",
+"1. c gray96",
+"2. c #F6F6F6F6F6F6",
+"3. c #F7F7F6F6F6F6",
+"4. c #F7F7F7F7F6F6",
+"5. c gray97",
+"6. c #F8F8F0F0F0F0",
+"7. c #F9F9F6F6F6F6",
+"8. c #FBFBF6F6F6F6",
+"9. c #FDFDF7F7F7F7",
+"0. c #FEFEF7F7F7F7",
+"q. c #FDFDF8F8F7F7",
+"w. c #F8F8F8F8F8F8",
+"e. c #F8F8FBFBFBFB",
+"r. c #FAFAF9F9F8F8",
+"t. c gray98",
+"y. c #FBFBFBFBFBFB",
+"u. c #FCFCF9F9F8F8",
+"i. c gray99",
+"p. c #FDFDFDFDFDFD",
+"a. c #FEFEFCFCFCFC",
+"s. c #FEFEFDFDFDFD",
+"d. c #FEFEFEFEFEFE",
+"f. c gray100",
+"g. c None",
+/* pixels */
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"1.1.1.>.>.$.+.` ` R T Y U U K F ",
+"1.f.f.#.q r r A A e e q @.e.7.m ",
+"1.f.f.f.0.0.q.u.0.e.7.+.e.1.7.m ",
+"1.f.f.{ ] e.N 5 4 3 >.I J 1.1.m ",
+"1.f.b p s &.@ o o X { 2 1 u 1.c ",
+"&.f.g O.7.} + V V . ] E E 2 <.c ",
+"} f.f u 1.&.; * % * Y U > < &.h ",
+"&.a.u.u &.{ - & $ # S J : ..<.l ",
+"{ a.1.i e.Y 0 9 7 8 H U < U &.g ",
+"{ i.t.U P 7.<.......&.m m &.&.g ",
+"U U I K S m c c h h s f h g g g ",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.",
+"g.g.g.g.g.g.g.g.g.g.g.g.g.g.g.g."
+};
diff --git a/src/images/flags/ZA.xpm b/src/images/flags/ZA.xpm
new file mode 100644
index 0000000..6c12a1f
--- /dev/null
+++ b/src/images/flags/ZA.xpm
@@ -0,0 +1,191 @@
+/* XPM */
+static const char *ZA_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 169 2",
+" c black",
+". c #00002D2D0000",
+"X c #000039390000",
+"o c #000045450000",
+"O c #000065650000",
+"+ c #000069690000",
+"@ c #535353535353",
+"# c #6F6F6F6F6F6F",
+"$ c #727272727373",
+"% c #767676767676",
+"& c #000000008181",
+"* c #000000008383",
+"= c #000000008787",
+"- c #000000008989",
+"; c #000000008B8B",
+": c #000000008F8F",
+"> c #000000009191",
+", c #000000009393",
+"< c #000000009999",
+"1 c #000000009B9B",
+"2 c #000000009D9D",
+"3 c #00000000B5B5",
+"4 c #0B0B0B0BC0C0",
+"5 c #0F0F0F0FC2C2",
+"6 c #13131313C4C4",
+"7 c #18181919C6C6",
+"8 c #1E1E1E1EC7C7",
+"9 c #23232323C9C9",
+"0 c #2C2C2C2CCACA",
+"q c #2F2F2F2FC9C9",
+"w c #2F2F2F2FCACA",
+"e c #32323232CCCC",
+"r c #35353535CDCD",
+"t c #39393939CFCF",
+"y c #3B3B3838D2D2",
+"u c #3D3D3D3DD0D0",
+"i c #42424242D2D2",
+"p c #46464646D2D2",
+"a c #51514F4FD8D8",
+"s c #63635F5FCBCB",
+"d c #000085850F0F",
+"f c #000085851313",
+"g c #17179D9D3B3B",
+"h c #1A1A95953434",
+"j c #1F1F98983838",
+"k c #25259A9A3D3D",
+"l c #2A2A9D9D4242",
+"z c #2929A1A14C4C",
+"x c #2E2EA3A35050",
+"c c #3030A0A04848",
+"v c #3636A3A34D4D",
+"b c #3232A5A55555",
+"n c #3434A7A75858",
+"m c #3737A8A85959",
+"M c #3737AAAA5A5A",
+"N c #3B3BA4A45151",
+"B c #3A3AA8A85959",
+"V c #3939A8A85C5C",
+"C c #3B3BABAB5C5C",
+"Z c #3B3BABAB5D5D",
+"A c #3C3CABAB5E5E",
+"S c #3F3FAFAF5F5F",
+"D c #3E3EABAB6161",
+"F c #3F3FAAAA6060",
+"G c #4040AEAE6060",
+"H c #4040AEAE6464",
+"J c #4343AEAE6565",
+"K c #4343AFAF6767",
+"L c #4747AEAE6565",
+"P c #4343B0B06565",
+"I c #4646B1B16565",
+"U c #4848B1B16969",
+"Y c #4B4BB3B36D6D",
+"T c #4B4BBFBF7777",
+"R c #5252B3B36262",
+"E c #5353B5B56464",
+"W c #5050B3B36F6F",
+"Q c #5151B4B46D6D",
+"! c #5858B7B76C6C",
+"~ c #5454B7B77676",
+"^ c #5D5DB7B77777",
+"/ c #5C5CB9B97979",
+"( c #7272BABA5D5D",
+") c #6E6EBCBC6060",
+"_ c #6161BDBD7F7F",
+"` c #6666BEBE7B7B",
+"' c #6D6DBFBF7272",
+"] c #7373BBBB6767",
+"[ c #5C5CC0C07E7E",
+"{ c #7777C9C98C8C",
+"} c #7B7BC6C69090",
+"| c #7B7BC8C89494",
+" . c #E9E900000000",
+".. c #EBEB00000000",
+"X. c #EDED00000000",
+"o. c #EFEF00000000",
+"O. c #F1F100000000",
+"+. c #F3F300000000",
+"@. c #F5F500000000",
+"#. c #F7F700000000",
+"$. c #F9F900000000",
+"%. c #FBFB00000000",
+"&. c #FDFD00000000",
+"*. c #F3F327272727",
+"=. c #F6F62C2C2C2C",
+"-. c #F7F731313131",
+";. c #F8F837373737",
+":. c #F9F93C3C3D3D",
+">. c #F7F749494949",
+",. c #F7F74E4E4E4E",
+"<. c #FAFA42424242",
+"1. c #FBFB47474747",
+"2. c #F8F853535353",
+"3. c #F9F957575757",
+"4. c #FAFA5C5C5C5C",
+"5. c #E7E769696B6B",
+"6. c #FBFB60606060",
+"7. c #FCFC65656565",
+"8. c #FCFC67676B6B",
+"9. c #FCFC69696969",
+"0. c #FDFD6D6D6D6D",
+"q. c #FDFD70707272",
+"w. c #9F9F83830000",
+"e. c #B3B39B9B0000",
+"r. c #8D8D8D8D5656",
+"t. c #999995955555",
+"y. c #8484BBBB5A5A",
+"u. c #A2A29E9E5E5E",
+"i. c #BEBEB6B67070",
+"p. c #8181C3C30000",
+"a. c #9D9DCDCD0000",
+"s. c #DCDCD4D45454",
+"d. c #C9C9C1C17E7E",
+"f. c #E2E2DBDB5E5E",
+"g. c #E9E9DBDB5555",
+"h. c #E6E6E3E35656",
+"j. c #EAEAE8E86868",
+"k. c #E5E5ECEC7474",
+"l. c #88888B8BDDDD",
+"z. c #85858181E4E4",
+"x. c #9595ADADCBCB",
+"c. c #B0B0AEAEE6E6",
+"v. c #B3B3B0B0E8E8",
+"b. c #B5B5B2B2E9E9",
+"n. c #B7B7B4B4EAEA",
+"m. c #BABAB7B7EBEB",
+"M. c #BCBCB9B9EAEA",
+"N. c #9292D8D8ABAB",
+"B. c #ADADDCDCB9B9",
+"V. c #F8F8A1A1A0A0",
+"C. c #F9F9ABABACAC",
+"Z. c #F5F5B5B5B6B6",
+"A. c #F6F6B7B7B8B8",
+"S. c #F7F7BABABABA",
+"D. c #F8F8BCBCBDBD",
+"F. c #F9F9BEBEBFBF",
+"G. c #F6F6BEBEC0C0",
+"H. c #E9E9F2F28787",
+"J. c #D9D9D1D1CBCB",
+"K. c #C4C4C3C3EEEE",
+"L. c #C4C4E5E5D5D5",
+"P. c #CDCDE3E3DBDB",
+"I. c #CDCDE4E4D8D8",
+"U. c #D3D3EBEBDFDF",
+"Y. c #D8D8E6E6E3E3",
+"T. c #FAFAC9C9CACA",
+"R. c #E4E4EEEEE8E8",
+"E. c #E8E8EBEBE4E4",
+"W. c None",
+/* pixels */
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"f d T J.*.&.&.&.%.%.#.#.+.+.X.X.",
+"p.| } N.R.C.q.0.9.7.4.4.3.2.,...",
+"e.H.` / [ U.V.8.1.<.:.;.-.=.>...",
+" d.j.' ~ Q L.E.T.G.D.S.A.Z.G.5.",
+" % u.f.] ! I P Y Y J H V n Y o ",
+" $ @ r.g.( P Z v c l k j h N . ",
+" # t.s.y.E V M G A B b z z L X ",
+" i.h.) H B I.Y.K.m.n.b.b.c.M.s ",
+"w.k.E H S B.l.y 9 8 7 6 5 4 w * ",
+"a._ ^ { P.z.a p p t y r e w 0 * ",
+"+ O g x.3 2 2 < > > : - * - * - ",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.",
+"W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W."
+};
diff --git a/src/images/flags/ZM.xpm b/src/images/flags/ZM.xpm
new file mode 100644
index 0000000..e5b2b70
--- /dev/null
+++ b/src/images/flags/ZM.xpm
@@ -0,0 +1,167 @@
+/* XPM */
+static const char *ZM_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 145 2",
+" c black",
+". c #10100F0F0B0B",
+"X c #151514141010",
+"o c #1A1A19191414",
+"O c #1F1F1D1D1A1A",
+"+ c #000033330000",
+"@ c #000039390000",
+"# c #00003B3B0000",
+"$ c #00003D3D0000",
+"% c #111127270000",
+"& c #24240F0F0E0E",
+"* c #292914141414",
+"= c #2E2E19191919",
+"- c #33331F1F1F1F",
+"; c #232323232020",
+": c #373725252525",
+"> c #343433332F2F",
+", c #3E3E34343232",
+"< c #000041410000",
+"1 c #000047470000",
+"2 c #00004D4D0000",
+"3 c #000053530000",
+"4 c #000059590000",
+"5 c #00005D5D0000",
+"6 c #000063630000",
+"7 c #000069690000",
+"8 c #00006D6D0000",
+"9 c #00006F6F0000",
+"0 c #000073730000",
+"q c #000075750000",
+"w c #000077770000",
+"e c #000079790000",
+"r c #00007B7B0000",
+"t c #00007D7D0000",
+"y c #00007F7F0000",
+"u c #03037F7F0303",
+"i c #030381810303",
+"p c #49499F9F4949",
+"a c #4D4DA1A14D4D",
+"s c #4E4EA2A24E4E",
+"d c #5050A2A25050",
+"f c #5252A4A45252",
+"g c #5353A5A55353",
+"h c #5454A5A55454",
+"j c #5656A6A65656",
+"k c #5757A7A75757",
+"l c #5757A8A85757",
+"z c #5858A8A85858",
+"x c #5959A8A85959",
+"c c #5B5BA9A95B5B",
+"v c #5B5BAAAA5B5B",
+"b c #5C5CAAAA5C5C",
+"n c #5D5DABAB5D5D",
+"m c #5E5EABAB5D5D",
+"M c #5E5EABAB5E5E",
+"N c #5E5EAEAE5D5D",
+"B c #5959B4B46666",
+"V c #6060ACAC6060",
+"C c #6060ADAD6060",
+"Z c #6161ADAD6161",
+"A c #6262ACAC6262",
+"S c #6262AEAE6262",
+"D c #6464AFAF6464",
+"F c #6565AEAE6565",
+"G c #6565AFAF6464",
+"H c #6868AFAF6868",
+"J c #6565B0B06565",
+"K c #6666B0B06565",
+"L c #6767B0B06767",
+"P c #6767B1B16767",
+"I c #6969B0B06969",
+"U c #6969B1B16969",
+"Y c #6969B2B26969",
+"T c #6A6AB2B26A6A",
+"R c #6A6AB3B36A6A",
+"E c #6B6BB3B36C6C",
+"W c #6D6DB2B26D6D",
+"Q c #6D6DB4B46D6D",
+"! c #6D6DB5B56D6D",
+"~ c #6E6EB5B56E6E",
+"^ c #6E6EB6B66E6E",
+"/ c #6F6FB6B66F6F",
+"( c #7878AEAE6868",
+") c #7171B4B47171",
+"_ c #7171B7B77171",
+"` c #7272B7B77272",
+"' c #7373B7B77272",
+"] c #7575B7B77575",
+"[ c #7676B9B97676",
+"{ c #7676BABA7676",
+"} c #7979B9B97979",
+"| c #7979BCBC7979",
+" . c #7979BCBC7A7A",
+".. c #7A7ABCBC7A7A",
+"X. c #7C7CBDBD7C7C",
+"o. c #7D7DBCBC7D7D",
+"O. c #7C7CBEBE7C7C",
+"+. c #7F7FBFBF7F7F",
+"@. c #C5C500000000",
+"#. c #CFCF00000000",
+"$. c #D7D700000000",
+"%. c #DDDD00000000",
+"&. c #DFDF00000000",
+"*. c #E3E300000000",
+"=. c #E5E500000000",
+"-. c #E7E700000000",
+";. c #EDED13131313",
+":. c #EEEE19191919",
+">. c #EFEF1F1F1F1F",
+",. c #E4E424241C1C",
+"<. c #E6E629292222",
+"1. c #E7E72F2F2828",
+"2. c #E9E934342E2E",
+"3. c #EFEF35353535",
+"4. c #EBEB3A3A3333",
+"5. c #F1F125252525",
+"6. c #F5F52B2B2B2B",
+"7. c #E8E842423C3C",
+"8. c #EBEB7E7E3535",
+"9. c #EDED7F7F3737",
+"0. c #9C9CB0B07575",
+"q. c #E7E78C8C3F3F",
+"w. c #EDED83833B3B",
+"e. c #EDED85853F3F",
+"r. c #E8E888883939",
+"t. c #DDDD9F9F5B5B",
+"y. c #EEEE88884343",
+"u. c #E8E899995757",
+"i. c #F1F18A8A4747",
+"p. c #E3E3A2A25F5F",
+"a. c #E8E8A4A46565",
+"s. c #8080BEBE8080",
+"d. c #8484C0C08484",
+"f. c #8787C2C28787",
+"g. c #8888C3C38888",
+"h. c #8A8AC3C38A8A",
+"j. c #8B8BC4C48B8B",
+"k. c #8D8DC5C58D8D",
+"l. c #8E8EC6C68F8F",
+"z. c #8F8FC7C78F8F",
+"x. c #9191C8C89191",
+"c. c #9494C8C89494",
+"v. c #9494C9C99494",
+"b. c #9595CACA9595",
+"n. c None",
+/* pixels */
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"i i i i u u e w 0 8 7 6 5 4 3 2 ",
+"i b.b.b.x.z.z.g.g.d.0.a.p.t.u.% ",
+"i b.+.O...] ' / E J B N q.r.( < ",
+"u b.....] ' / R J S M x h d H # ",
+"u z.| ] ' / R J S M 4.6.: ; i.-.",
+"u z.] ) / I J S M x 2.5.- O y.-.",
+"w g.' / I F N M l g 1.>.= o e.*.",
+"0 g./ I J S x x g a <.:.* X w.&.",
+"8 d.I S S x h g a p ,.;.& . 9.&.",
+"7 +.O.| ] ) W I F S 7.3., > 8.&.",
+"6 5 4 3 2 1 < $ # + @.$. #.&.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.",
+"n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n."
+};
diff --git a/src/images/flags/ZW.xpm b/src/images/flags/ZW.xpm
new file mode 100644
index 0000000..d541085
--- /dev/null
+++ b/src/images/flags/ZW.xpm
@@ -0,0 +1,189 @@
+/* XPM */
+static const char *ZW_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 167 2",
+" c black",
+". c #000001010000",
+"X c #00001F1F0000",
+"o c gray10",
+"O c gray12",
+"+ c #000021210000",
+"@ c #000025250000",
+"# c #000029290000",
+"$ c #00002B2B0000",
+"% c #00002D2D0000",
+"& c #000033330000",
+"* c #000037370000",
+"= c #000039390000",
+"- c #00003D3D0000",
+"; c #252525252525",
+": c #2A2A2B2B2B2B",
+"> c gray19",
+", c gray21",
+"< c gray23",
+"1 c #000041410000",
+"2 c #000047470000",
+"3 c #00004D4D0000",
+"4 c #000053530000",
+"5 c #000059590000",
+"6 c #00005D5D0000",
+"7 c #00005F5F0000",
+"8 c #000063630000",
+"9 c #000069690000",
+"0 c #00006D6D0000",
+"q c #00006F6F0000",
+"w c #000073730000",
+"e c #000075750000",
+"r c #000079790000",
+"t c #00007D7D0000",
+"y c #00007F7F0000",
+"u c #5F5F00000000",
+"i c #404042424242",
+"p c #000081810000",
+"a c #000085850000",
+"s c #050593930000",
+"d c #898900000000",
+"f c #ADAD00000000",
+"g c #B9B900000000",
+"h c #B0B02F2F2020",
+"j c #B3B334342525",
+"k c #B5B539392B2B",
+"l c #B8B83F3F3030",
+"z c #BBBB44443636",
+"x c #BBBB4C4C3F3F",
+"c c #BCBC49493C3C",
+"v c #9C9C5C5C5656",
+"b c #969663634E4E",
+"n c #A1A157574646",
+"m c #BEBE4E4E4141",
+"M c #A4A477775D5D",
+"N c #C5C536361414",
+"B c #C7C73A3A1919",
+"V c #C9C93F3F1F1F",
+"C c #D7D73C3C1010",
+"Z c #D8D840401414",
+"A c #D9D944441919",
+"S c #DBDB49491F1F",
+"D c #CACA43432424",
+"F c #CCCC48482A2A",
+"G c #CECE4D4D2F2F",
+"H c #CDCD52523636",
+"J c #DDDD4E4E2424",
+"K c #DEDE52522A2A",
+"L c #DEDE58582626",
+"P c #D0D052523535",
+"I c #D3D357573A3A",
+"U c #DDDD58583232",
+"Y c #DDDD5A5A3A3A",
+"T c #E0E055552F2F",
+"R c #E0E05C5C2B2B",
+"E c #E1E15B5B3434",
+"W c #E1E161613131",
+"Q c #E3E365653636",
+"! c #E4E469693C3C",
+"~ c #C1C153534646",
+"^ c #E2E26F6F4444",
+"/ c #E5E56D6D4242",
+"( c #E7E772724747",
+") c #E8E876764B4B",
+"_ c #E6E675755151",
+"` c #8A8AA9A96262",
+"' c #9595B3B37E7E",
+"] c #A7A7A5A54B4B",
+"[ c #B9B9B7B76262",
+"{ c #8686C3C33131",
+"} c #8787C4C43434",
+"| c #8A8AC6C63737",
+" . c #8C8CC7C73B3B",
+".. c #8E8EC8C83F3F",
+"X. c #9090CBCB4242",
+"o. c #9494CDCD4646",
+"O. c #9797CECE4B4B",
+"+. c #9494D2D24E4E",
+"@. c #9999D0D05050",
+"#. c #9898D3D35353",
+"$. c #9B9BD5D55757",
+"%. c #9C9CD1D15454",
+"&. c #9F9FD3D35959",
+"*. c #9E9ED7D75C5C",
+"=. c #A2A2D4D45D5D",
+"-. c #A1A1D8D86060",
+";. c #A4A4DADA6565",
+":. c #A7A7DCDC6969",
+">. c #A9A9DDDD6D6D",
+",. c #ABABDEDE7171",
+"<. c #ADADDFDF7474",
+"1. c #AFAFE0E07777",
+"2. c #B2B2E1E17979",
+"3. c #E7E787876F6F",
+"4. c #EDED93937979",
+"5. c #EEEE97977D7D",
+"6. c #EEEE97977E7E",
+"7. c #F2F2BDBD5E5E",
+"8. c #DFDFDDDD0000",
+"9. c #E9E9E9E90000",
+"0. c #F1F1F0F00B0B",
+"q. c #F1F1F1F10E0E",
+"w. c #F2F2F1F11313",
+"e. c #F3F3F2F21919",
+"r. c #F4F4F3F31E1E",
+"t. c #F5F5F4F42323",
+"y. c #F2F2F1F12F2F",
+"u. c #F6F6F5F52929",
+"i. c #F6F6F6F62C2C",
+"p. c #F7F7F7F72E2E",
+"a. c #F7F7F7F73131",
+"s. c #F9F9F4F43A3A",
+"d. c #F8F8F8F83434",
+"f. c #F8F8F8F83737",
+"g. c #F9F9F9F93D3D",
+"h. c #F7F7F7F74949",
+"j. c #FAFAFAFA4242",
+"k. c #FBFBFBFB4747",
+"l. c #FCFCFBFB4F4F",
+"z. c #FCFCFCFC4C4C",
+"x. c #FDFDFDFD5151",
+"c. c #FDFDFCFC5353",
+"v. c #FDFDFDFD5454",
+"b. c #FEFEFCFC5959",
+"n. c #FEFEFDFD5858",
+"m. c #F1F1A2A28C8C",
+"M. c #F1F1A6A69090",
+"N. c #F2F2B9B9A9A9",
+"B. c #F7F7D6D68F8F",
+"V. c #EDEDC5C5BDBD",
+"C. c #FEFEFDFD8484",
+"Z. c #D7D7E1E1D7D7",
+"A. c #E1E1E7E7E1E1",
+"S. c #EFEFEFEFEFEF",
+"D. c #EFEFF2F2F0F0",
+"F. c #F1F1ECECE8E8",
+"G. c #F1F1EFEFF1F1",
+"H. c #F4F4F3F3F4F4",
+"J. c #F5F5F3F3F5F5",
+"K. c #F5F5F4F4F0F0",
+"L. c gray96",
+"P. c gray97",
+"I. c #FAFAFAFAF9F9",
+"U. c #FFFFFAFAFCFC",
+"Y. c #FCFCFCFCFBFB",
+"T. c gray99",
+"R. c None",
+/* pixels */
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"Z.* a p t t r e e 0 9 8 6 5 4 5 ",
+"J.T.' 2.1.<.,.>.:.;.-.*.$.#.+.s ",
+"L.U.Y.[ n.v.x.z.k.j.g.f.a.i.h.9.",
+"L.C.M.Y.M _ ) ( / ! Q W R L ^ g ",
+"3.B.n.6.4.v ~ m c z l k j h x u ",
+"V.m.x.l.N.P.i < , > : ; O o < ",
+"G.6.l.7.L.n I P G F D V B N H d ",
+"S.Y.I.F.b Y E T K J S A Z C U f ",
+"S.U.K.] s.d.p.u.t.r.e.w.q.0.y.8.",
+"L.D.` =.&.%.#.O.o.X... .| } { 0 ",
+"A. 8 4 3 2 - - = & % # @ + X % ",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.",
+"R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R."
+};
diff --git a/src/images/floppy_icon.png.h b/src/images/floppy_icon.png.h
new file mode 100644
index 0000000..665850b
--- /dev/null
+++ b/src/images/floppy_icon.png.h
@@ -0,0 +1,115 @@
+/* floppy_icon.png - 890 bytes */
+ static const unsigned char floppy_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x04, 0x73, 0x42, 0x49,
+ 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
+ 0x88, 0x00, 0x00, 0x03, 0x31, 0x49, 0x44, 0x41,
+ 0x54, 0x58, 0x85, 0xe5, 0x97, 0x3f, 0x6c, 0x1c,
+ 0x45, 0x14, 0x87, 0xbf, 0xf5, 0x2e, 0xf6, 0x71,
+ 0x71, 0x2e, 0x98, 0x9c, 0xe5, 0x58, 0x8e, 0xa5,
+ 0xb8, 0x40, 0xa4, 0xb0, 0x85, 0x43, 0x99, 0x82,
+ 0x3f, 0x12, 0x25, 0x12, 0x0e, 0x71, 0x88, 0x68,
+ 0x50, 0x0a, 0x0a, 0x28, 0x68, 0x88, 0x84, 0x52,
+ 0x45, 0x14, 0xd0, 0x41, 0x49, 0x81, 0x21, 0x15,
+ 0x16, 0x34, 0x14, 0x6e, 0x40, 0x02, 0x04, 0x42,
+ 0xb2, 0x44, 0x01, 0x34, 0x28, 0x12, 0x15, 0xc8,
+ 0x8a, 0x1d, 0xdb, 0x42, 0x36, 0x45, 0x74, 0x9c,
+ 0x8f, 0xbb, 0x9d, 0x79, 0x8f, 0x62, 0x77, 0xf6,
+ 0x66, 0x7d, 0x77, 0x7b, 0x8e, 0xbc, 0xae, 0x78,
+ 0x92, 0xe5, 0xd9, 0xd9, 0x99, 0x79, 0xbf, 0xf9,
+ 0xe6, 0x37, 0x3b, 0x37, 0xf0, 0x7f, 0x8f, 0xc0,
+ 0x15, 0xe6, 0x9f, 0x7d, 0xe3, 0xa3, 0x76, 0xbb,
+ 0xf5, 0x26, 0xda, 0xad, 0x3b, 0xa9, 0x78, 0x64,
+ 0xb4, 0xf2, 0xe5, 0xef, 0xeb, 0x1f, 0x5f, 0x03,
+ 0x88, 0x5c, 0xa5, 0xe9, 0xc4, 0x37, 0x56, 0x56,
+ 0x3e, 0x08, 0x46, 0xa2, 0x08, 0x51, 0x65, 0x7e,
+ 0xfd, 0x0e, 0xa8, 0xa2, 0x22, 0xa0, 0xea, 0xfd,
+ 0x09, 0xea, 0xca, 0xde, 0x3b, 0x4d, 0xdf, 0x65,
+ 0xcf, 0x7e, 0x3f, 0x60, 0xfd, 0x99, 0xb7, 0x50,
+ 0x14, 0x11, 0xe5, 0xf6, 0xad, 0x77, 0x97, 0x5d,
+ 0xde, 0x4c, 0x80, 0x06, 0x12, 0x88, 0xc2, 0x8d,
+ 0x57, 0x5e, 0xe4, 0xe5, 0x9b, 0x9f, 0x52, 0x7f,
+ 0xff, 0x9d, 0xac, 0xf3, 0xb1, 0x23, 0x08, 0xf8,
+ 0xee, 0xd4, 0x55, 0x54, 0x95, 0xe7, 0x16, 0xa7,
+ 0x72, 0xaf, 0x22, 0xff, 0xc1, 0x8a, 0x70, 0xe5,
+ 0xed, 0x4f, 0x10, 0x11, 0xe6, 0x37, 0xa5, 0x9c,
+ 0xe4, 0x69, 0xc8, 0x87, 0x3f, 0x81, 0x2a, 0x62,
+ 0xf3, 0xe3, 0xe6, 0x04, 0x88, 0x28, 0xe2, 0xd0,
+ 0x95, 0x1c, 0x2a, 0xc9, 0xd2, 0x59, 0xc9, 0x8f,
+ 0xdd, 0x43, 0x40, 0xad, 0xa0, 0x74, 0x1b, 0x6d,
+ 0x6c, 0x6c, 0x1c, 0x2b, 0xf1, 0xdc, 0xdc, 0x1c,
+ 0x40, 0x36, 0x31, 0x5b, 0x48, 0xc0, 0xa6, 0x04,
+ 0x3c, 0x01, 0x6e, 0x80, 0xe3, 0x46, 0x46, 0xc0,
+ 0xda, 0xc1, 0x02, 0xac, 0x48, 0xd2, 0x90, 0xf2,
+ 0x97, 0xe0, 0x48, 0x04, 0xac, 0x95, 0x1e, 0x02,
+ 0x65, 0x2d, 0x41, 0x97, 0xc0, 0x10, 0x13, 0xba,
+ 0x86, 0x87, 0x07, 0x38, 0x6e, 0x88, 0x13, 0x60,
+ 0x06, 0x08, 0x50, 0x3c, 0x02, 0x27, 0xb8, 0x0b,
+ 0x8c, 0x0c, 0x22, 0xa0, 0x9e, 0x07, 0xf4, 0x64,
+ 0x76, 0x81, 0xaa, 0x22, 0x85, 0x26, 0xec, 0x43,
+ 0xa0, 0xec, 0x5d, 0x60, 0x0a, 0x4d, 0xd8, 0xc7,
+ 0x03, 0x65, 0x45, 0xd7, 0x03, 0x85, 0x04, 0xec,
+ 0xc9, 0x7b, 0x60, 0xd8, 0x36, 0x74, 0x0d, 0x5f,
+ 0x7b, 0xef, 0x7b, 0x14, 0xb2, 0x93, 0x2f, 0xfb,
+ 0x0f, 0xd9, 0xb3, 0x23, 0xe5, 0xb7, 0x49, 0xaa,
+ 0xf4, 0x50, 0x3f, 0xd0, 0xb4, 0xae, 0xd0, 0x03,
+ 0xe2, 0x79, 0xc0, 0x0d, 0x2e, 0xfb, 0xbf, 0xd1,
+ 0xd9, 0xfd, 0x19, 0x95, 0x7c, 0xc7, 0x61, 0x31,
+ 0x32, 0x12, 0x12, 0x9c, 0x5d, 0xc4, 0x8c, 0x3f,
+ 0x99, 0x9c, 0xca, 0x24, 0x82, 0x0a, 0x09, 0x18,
+ 0x8f, 0x80, 0x9b, 0x6d, 0x67, 0xf7, 0x17, 0xae,
+ 0x2c, 0xbd, 0x44, 0xb5, 0x5a, 0x25, 0x0c, 0x43,
+ 0xa2, 0x28, 0x22, 0x0c, 0xc3, 0xbe, 0x65, 0x6b,
+ 0x2d, 0x71, 0x1c, 0x63, 0x8c, 0xa1, 0xd1, 0x68,
+ 0xf0, 0xd9, 0xea, 0xe7, 0x48, 0xf5, 0x89, 0x1c,
+ 0x01, 0x33, 0xd8, 0x03, 0x9a, 0xdb, 0x05, 0x19,
+ 0x3a, 0x31, 0xd4, 0x6a, 0x35, 0xa2, 0x28, 0xe2,
+ 0xab, 0xaf, 0xbf, 0x61, 0x77, 0x67, 0x0b, 0x80,
+ 0x99, 0xd9, 0x0b, 0xbc, 0x7a, 0x7d, 0x99, 0x30,
+ 0x0c, 0x31, 0xc6, 0xd0, 0x6a, 0xb5, 0xb2, 0xe4,
+ 0x71, 0x1c, 0x27, 0xa6, 0x13, 0x93, 0x4e, 0xa8,
+ 0x4b, 0x60, 0xc8, 0x59, 0x60, 0xf3, 0x04, 0x52,
+ 0x2f, 0x56, 0x2a, 0x15, 0xc2, 0x30, 0x64, 0x77,
+ 0x67, 0x8b, 0xd6, 0xe4, 0x12, 0x00, 0xdb, 0x5b,
+ 0x6b, 0x58, 0x6b, 0x69, 0xb7, 0xdb, 0xb9, 0xc4,
+ 0x7e, 0x19, 0xdc, 0x19, 0x90, 0xf8, 0x44, 0x29,
+ 0xf8, 0x12, 0x02, 0x3d, 0x04, 0x9c, 0x80, 0xb1,
+ 0xb1, 0x31, 0xa2, 0x28, 0xd7, 0x14, 0x80, 0x83,
+ 0x83, 0x83, 0x81, 0xc9, 0x8d, 0x31, 0x09, 0x57,
+ 0x47, 0x40, 0x15, 0x50, 0xe2, 0xa2, 0x6d, 0x68,
+ 0xcc, 0x60, 0x02, 0x87, 0xd1, 0x01, 0x34, 0x9b,
+ 0xcd, 0x5c, 0xc2, 0x23, 0x11, 0x28, 0xfe, 0x12,
+ 0x6a, 0x0f, 0x81, 0x00, 0xb2, 0xf5, 0x2d, 0x83,
+ 0xc0, 0x10, 0x01, 0x36, 0xf9, 0xdd, 0x96, 0x89,
+ 0x48, 0x04, 0xb8, 0x99, 0x0e, 0x12, 0xf0, 0x70,
+ 0x1e, 0xe8, 0x2f, 0x20, 0x52, 0xd1, 0x47, 0xef,
+ 0x6f, 0x6e, 0x33, 0x3b, 0x55, 0xe7, 0xde, 0xce,
+ 0x83, 0xf4, 0xd3, 0x09, 0x23, 0x5e, 0xa2, 0xb3,
+ 0xf5, 0x73, 0xfc, 0xbd, 0xb7, 0x06, 0xc0, 0x63,
+ 0x13, 0x75, 0x9a, 0xcd, 0x66, 0xcf, 0xac, 0x7d,
+ 0x11, 0x3d, 0x04, 0x34, 0xe7, 0x81, 0xd3, 0x40,
+ 0xc3, 0x09, 0x38, 0xf3, 0xcf, 0xde, 0xc6, 0xd5,
+ 0xf5, 0x1f, 0xbe, 0x5d, 0xbd, 0xfc, 0xfc, 0x0b,
+ 0x95, 0x8b, 0x17, 0xa6, 0x03, 0x15, 0x41, 0x14,
+ 0xfe, 0xd8, 0xec, 0x12, 0x78, 0xfa, 0xd2, 0x02,
+ 0x71, 0x7c, 0x31, 0x4b, 0x34, 0x88, 0x80, 0x78,
+ 0x47, 0xee, 0xf4, 0x64, 0x2d, 0xf3, 0x95, 0x88,
+ 0xf8, 0x24, 0x27, 0x00, 0x09, 0x80, 0x10, 0xa8,
+ 0x03, 0xf5, 0xfa, 0xf9, 0xc5, 0xcb, 0x13, 0x33,
+ 0x4f, 0xad, 0xf8, 0x88, 0x16, 0x66, 0x1a, 0x3d,
+ 0xe8, 0x1f, 0x26, 0xee, 0x6e, 0x9f, 0xee, 0xa9,
+ 0x13, 0xdb, 0xf9, 0xf1, 0xcf, 0x5f, 0xbf, 0x78,
+ 0x1d, 0xf8, 0xcb, 0x5d, 0xc3, 0x6a, 0xc0, 0xe3,
+ 0xc0, 0x19, 0x60, 0x1c, 0x18, 0x25, 0xa1, 0x5f,
+ 0x66, 0x74, 0xd2, 0x31, 0xff, 0x05, 0x1a, 0xc0,
+ 0x3e, 0xb0, 0xe7, 0xdf, 0x03, 0x47, 0x49, 0xd6,
+ 0xa5, 0x9a, 0x96, 0xcb, 0x0e, 0xc7, 0xbe, 0x05,
+ 0x3c, 0x00, 0xda, 0x40, 0xe1, 0x45, 0xb4, 0xec,
+ 0x4b, 0x6a, 0xdf, 0x33, 0xfe, 0x3f, 0xc8, 0xb0,
+ 0x73, 0x9a, 0xcf, 0x8f, 0xe1, 0xe6, 0x00, 0x00,
+ 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+ 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/host.xpm b/src/images/host.xpm
new file mode 100644
index 0000000..df1f4e4
--- /dev/null
+++ b/src/images/host.xpm
@@ -0,0 +1,62 @@
+/* XPM */
+static const char * host_xpm[] = {
+"16 16 43 1",
+" c None",
+". c #FF6B00",
+"+ c #FFE684",
+"@ c #FFD42A",
+"# c #FF7D00",
+"$ c #FFAE00",
+"% c #FFDB4D",
+"& c #FFFF98",
+"* c #FFF46B",
+"= c #FFE16B",
+"- c #FFEDA9",
+"; c #FFFFA9",
+"> c #FFC64D",
+", c #FF8900",
+"' c #FFEA98",
+") c #FF4D00",
+"! c #FF8B00",
+"~ c #FFFF6B",
+"{ c #FF9E00",
+"] c #D54000",
+"^ c #FFF24D",
+"/ c #FF7400",
+"( c #FFCB00",
+"_ c #B24A00",
+": c #FFED00",
+"< c #671F00",
+"[ c #FFF16B",
+"} c #943E00",
+"| c #7B2500",
+"1 c #944900",
+"2 c #FFF384",
+"3 c #943A00",
+"4 c #B24600",
+"5 c #FFE384",
+"6 c #FFDE6B",
+"7 c #FFA42A",
+"8 c #D55900",
+"9 c #B70000",
+"0 c #A30000",
+"a c #C30000",
+"b c #D55400",
+"c c #FFA600",
+"d c #FFC100",
+" .. ",
+" .+ at . ",
+" #. .+$$%. .. ",
+".&*..=$%%$=..-=.",
+".;>=%$%$$,$%'$%)",
+".;$$$$$!!$$$$$%)",
+".&$$!!!!!!!!$$%)",
+".~${]]]]]]).!$@]",
+".^!] ./(]",
+".^] _(]",
+"]:<[ .}(]",
+"](|12 .$_(]",
+" ]334555667(((8 ",
+" 90abccccd]]8 ",
+" 88]]]] ",
+" "};
diff --git a/src/images/host_spectator.xpm b/src/images/host_spectator.xpm
new file mode 100644
index 0000000..87120e4
--- /dev/null
+++ b/src/images/host_spectator.xpm
@@ -0,0 +1,88 @@
+/* XPM */
+static const char * host_spectator_xpm[] = {
+"16 16 69 1",
+" c None",
+". c #FF6B00",
+"+ c #FFE684",
+"@ c #FFD42A",
+"# c #FF7D00",
+"$ c #FFAE00",
+"% c #FFDB4D",
+"& c #FFFF98",
+"* c #FFF46B",
+"= c #FFE16B",
+"- c #FFEDA9",
+"; c #FFFFA9",
+"> c #FFC64D",
+", c #FF8900",
+"' c #FFEA98",
+") c #FF4D00",
+"! c #FF8B00",
+"~ c #FFFF6B",
+"{ c #FF9E00",
+"] c #D54000",
+"^ c #FFF24D",
+"/ c #B4B4B4",
+"( c #A6A6A6",
+"_ c #9E9E9E",
+": c #959595",
+"< c #8B8B8B",
+"[ c #FF7400",
+"} c #FFCB00",
+"| c #ADADAD",
+"1 c #E6E6E6",
+"2 c #E7E7E7",
+"3 c #D5D5D5",
+"4 c #B24A00",
+"5 c #FFED00",
+"6 c #A0A0A0",
+"7 c #EAEAEA",
+"8 c #0049B8",
+"9 c #003D9B",
+"0 c #002F77",
+"a c #002764",
+"b c #797979",
+"c c #B5B5B5",
+"d c #FFFFFF",
+"e c #0043A9",
+"f c #C7DCF0",
+"g c #000070",
+"h c #00007D",
+"i c #000092",
+"j c #00245C",
+"k c #C5C5C5",
+"l c #848484",
+"m c #6D6D6D",
+"n c #002154",
+"o c #00007C",
+"p c #000087",
+"q c #0012A3",
+"r c #0026AB",
+"s c #606060",
+"t c #00183C",
+"u c #1549B8",
+"v c #5495D5",
+"w c #458BD1",
+"x c #D7D7D7",
+"y c #313131",
+"z c #424242",
+"A c #001A41",
+"B c #0058BE",
+"C c #6FA6DB",
+"D c #1E1E1E",
+" .. ",
+" .+ at . ",
+" #. .+$$%. .. ",
+".&*..=$%%$=..-=.",
+".;>=%$%$$,$%'$%)",
+".;$$$$$!!$$$$$%)",
+".&$$!!!!!!!!$$%)",
+".~${]]]]]]).!$@]",
+".^!]///(_(:<.[}]",
+".^]|11111223<4}]",
+"]56377890a777b}]",
+"]bc7defghijddkl]",
+"m(7dnoppqread7cm",
+" sk7tqqruvwj7xy ",
+" zzxABwCCAxzD ",
+" yyyyyyyz "};
diff --git a/src/images/ingame.png.h b/src/images/ingame.png.h
new file mode 100644
index 0000000..7e67a70
--- /dev/null
+++ b/src/images/ingame.png.h
@@ -0,0 +1,111 @@
+/* ingame.png - 858 bytes */
+ static const unsigned char ingame_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xa6,
+ 0x00, 0xb0, 0x00, 0xb5, 0x78, 0x71, 0x68, 0x5a,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x12, 0x1b, 0x28, 0xf4, 0xde, 0xa6, 0xf0,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x02,
+ 0xb5, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x85,
+ 0x93, 0x5b, 0x48, 0xd3, 0x51, 0x1c, 0x80, 0xbf,
+ 0xbf, 0x5b, 0x4d, 0xa8, 0x07, 0x83, 0x2c, 0x4a,
+ 0x70, 0x4d, 0x2b, 0xd0, 0x39, 0x5d, 0x17, 0x29,
+ 0x64, 0xb0, 0xfd, 0xd3, 0x40, 0x71, 0x4a, 0x6d,
+ 0xec, 0xa5, 0x0b, 0x49, 0x18, 0x0a, 0x46, 0xc8,
+ 0x9a, 0x68, 0x65, 0x20, 0x56, 0x52, 0x19, 0x62,
+ 0x94, 0x60, 0x0f, 0x96, 0x0c, 0xbb, 0xc0, 0x88,
+ 0x5e, 0x84, 0x85, 0x84, 0x9b, 0x14, 0x1a, 0x45,
+ 0x90, 0x0e, 0x37, 0xd0, 0xca, 0x30, 0xe7, 0xd6,
+ 0x45, 0xd9, 0x34, 0x41, 0x6b, 0x72, 0x7a, 0xd0,
+ 0x45, 0x56, 0xd4, 0xef, 0xe9, 0x3c, 0x7c, 0xdf,
+ 0x77, 0x0e, 0xe7, 0x70, 0xa4, 0x23, 0xc7, 0xcb,
+ 0x45, 0xf2, 0xa6, 0x14, 0x54, 0x89, 0x2a, 0x00,
+ 0xf9, 0xf2, 0xf9, 0xb3, 0x5e, 0xfe, 0x31, 0x75,
+ 0x17, 0x9a, 0x4c, 0x80, 0x67, 0x61, 0x7e, 0x81,
+ 0xcf, 0xa1, 0x20, 0x09, 0x91, 0x68, 0x14, 0x47,
+ 0x4d, 0x0d, 0xa5, 0xa5, 0x25, 0x00, 0x9e, 0x65,
+ 0xe0, 0x9f, 0x72, 0x69, 0x69, 0x09, 0x8e, 0x9a,
+ 0x1a, 0x22, 0xd1, 0x28, 0x09, 0x00, 0xa1, 0x50,
+ 0x18, 0xb5, 0x5a, 0x83, 0xd9, 0x5c, 0x8c, 0x10,
+ 0xc2, 0x53, 0xdb, 0x78, 0xa9, 0xe2, 0x77, 0xb9,
+ 0xb6, 0xf1, 0x52, 0x85, 0x10, 0xc2, 0x63, 0x36,
+ 0x17, 0xa3, 0x56, 0x6b, 0x08, 0x85, 0xc2, 0x00,
+ 0x24, 0x00, 0x72, 0x43, 0xfd, 0x19, 0x26, 0x82,
+ 0x41, 0x34, 0x9a, 0x74, 0x8e, 0x1e, 0x3a, 0x8c,
+ 0x24, 0x49, 0xed, 0xbf, 0x9e, 0xa4, 0xee, 0x42,
+ 0x93, 0x49, 0x92, 0xa4, 0xf6, 0xa3, 0x87, 0x0e,
+ 0xa3, 0xd1, 0xa4, 0x33, 0x11, 0x0c, 0xd2, 0x50,
+ 0x7f, 0x06, 0x40, 0x96, 0x00, 0xcc, 0x56, 0x5b,
+ 0x05, 0xd0, 0x7e, 0xd2, 0xee, 0x40, 0xa7, 0xd5,
+ 0xd2, 0xe7, 0xe9, 0x65, 0xd0, 0xe7, 0x03, 0x90,
+ 0x97, 0x1b, 0x9e, 0x1c, 0x9d, 0x0e, 0xa3, 0xbc,
+ 0x0f, 0xdf, 0xf0, 0x30, 0x37, 0x5b, 0xae, 0x01,
+ 0x54, 0x76, 0x3f, 0x74, 0xdd, 0x92, 0xe2, 0xbb,
+ 0x98, 0xad, 0x36, 0x13, 0xe0, 0x89, 0x47, 0xbc,
+ 0xde, 0x5e, 0x86, 0x86, 0x7c, 0x00, 0x64, 0x67,
+ 0xeb, 0x30, 0x99, 0x56, 0xc8, 0x72, 0xf7, 0x43,
+ 0x97, 0x17, 0x40, 0x11, 0x0f, 0x8c, 0x04, 0xfc,
+ 0xef, 0xb7, 0x67, 0x6a, 0xfb, 0x5e, 0x0c, 0xf4,
+ 0x97, 0x6d, 0xd9, 0xba, 0x8d, 0x94, 0xcd, 0x29,
+ 0x04, 0x02, 0x01, 0xb2, 0xb2, 0xb4, 0xc8, 0x72,
+ 0xfe, 0x5f, 0xe5, 0x15, 0x81, 0x12, 0xab, 0xad,
+ 0x7a, 0xf5, 0x47, 0xd7, 0x7d, 0xc5, 0x9c, 0x9f,
+ 0x37, 0x1f, 0x13, 0xf9, 0x10, 0x9c, 0x40, 0xab,
+ 0xcd, 0x24, 0x3f, 0x7f, 0xff, 0x4f, 0x59, 0x39,
+ 0xed, 0x45, 0x39, 0xf3, 0xb2, 0x6c, 0x6b, 0xae,
+ 0x2d, 0x3a, 0x12, 0xf0, 0x3f, 0x5f, 0x71, 0xcb,
+ 0x16, 0x03, 0x62, 0xa4, 0x17, 0x11, 0x0d, 0x20,
+ 0x4e, 0xd5, 0xd5, 0x8b, 0x47, 0xee, 0x27, 0x22,
+ 0x18, 0xf9, 0x2a, 0x1e, 0x74, 0x3f, 0x16, 0x66,
+ 0xab, 0x4d, 0x9c, 0x38, 0x65, 0x17, 0xd1, 0xc0,
+ 0x12, 0x63, 0x31, 0x20, 0xe2, 0x5e, 0x42, 0x7c,
+ 0x11, 0x5b, 0x04, 0x21, 0xa0, 0xb2, 0xb9, 0x1c,
+ 0x93, 0xd1, 0xb8, 0xb0, 0x31, 0x79, 0x3d, 0x4f,
+ 0x9f, 0x3d, 0xa3, 0xeb, 0x4e, 0x07, 0x7a, 0xfd,
+ 0x0e, 0x8a, 0x8a, 0x8a, 0x16, 0x2a, 0x9b, 0xcb,
+ 0x11, 0x62, 0x89, 0xfd, 0x23, 0xa0, 0x54, 0xd0,
+ 0xe6, 0x38, 0x07, 0xad, 0x76, 0x27, 0x48, 0x92,
+ 0xaa, 0xf3, 0xee, 0x3d, 0xba, 0xee, 0x74, 0x00,
+ 0xf0, 0x69, 0x3a, 0x02, 0x92, 0xa4, 0x6a, 0xb5,
+ 0x3b, 0x71, 0x9c, 0x5b, 0x62, 0x57, 0x04, 0x2c,
+ 0x06, 0xaa, 0x63, 0x8b, 0x54, 0x39, 0x3b, 0x60,
+ 0x7e, 0xee, 0x1b, 0x1b, 0x66, 0x0a, 0x98, 0x1c,
+ 0x1f, 0xe3, 0x58, 0x9e, 0x8b, 0xb0, 0xcf, 0xc5,
+ 0xe4, 0xf8, 0x18, 0x1b, 0x66, 0x0a, 0x98, 0x9f,
+ 0xfb, 0x86, 0xb3, 0x03, 0x62, 0x8b, 0x54, 0x59,
+ 0x0c, 0x54, 0x03, 0x28, 0x2c, 0x06, 0x9a, 0x81,
+ 0xc6, 0xab, 0x17, 0x61, 0xd5, 0x9a, 0x44, 0xda,
+ 0x5a, 0x62, 0xdc, 0xe8, 0x84, 0x03, 0x7b, 0xfc,
+ 0x4c, 0x7d, 0x81, 0xc1, 0x51, 0x38, 0xb8, 0xc7,
+ 0xcf, 0x95, 0x36, 0x88, 0x4e, 0x42, 0xae, 0x21,
+ 0x11, 0xe3, 0xde, 0x18, 0x4f, 0x3c, 0x14, 0x66,
+ 0xa4, 0xb2, 0x56, 0x91, 0x91, 0x4a, 0x8f, 0x7e,
+ 0x1b, 0x64, 0xee, 0x80, 0x5b, 0xd7, 0x63, 0xb8,
+ 0x07, 0x20, 0x79, 0x1d, 0xce, 0xfe, 0x41, 0x72,
+ 0x86, 0xdf, 0x42, 0xd2, 0x1a, 0x78, 0xee, 0x83,
+ 0xe4, 0x24, 0x9c, 0xaf, 0x47, 0xc9, 0x99, 0x7a,
+ 0x1f, 0x23, 0x67, 0x37, 0x4c, 0x7d, 0x80, 0xf0,
+ 0x34, 0x79, 0xca, 0xc8, 0x2c, 0xbc, 0x1e, 0x85,
+ 0xef, 0xb7, 0xc1, 0x3d, 0x00, 0xeb, 0x93, 0x68,
+ 0xe9, 0x79, 0xc5, 0x69, 0xe0, 0xd8, 0xef, 0xff,
+ 0xa1, 0x60, 0x27, 0x5f, 0xdc, 0x03, 0xd8, 0x95,
+ 0x0a, 0x18, 0x7e, 0x07, 0x91, 0xd9, 0xe5, 0xf7,
+ 0xd7, 0xa7, 0x21, 0xf4, 0x69, 0x88, 0xc2, 0x5d,
+ 0x74, 0xf1, 0x9f, 0x29, 0xdc, 0x45, 0x57, 0x9c,
+ 0x2f, 0xb1, 0xda, 0xaa, 0x7f, 0x00, 0x0b, 0x50,
+ 0x2a, 0xbb, 0x60, 0x32, 0xa8, 0x9d, 0x00, 0x00,
+ 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+ 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/join_icon.png.h b/src/images/join_icon.png.h
new file mode 100644
index 0000000..0a83605
--- /dev/null
+++ b/src/images/join_icon.png.h
@@ -0,0 +1,319 @@
+/* join_icon.png - 2526 bytes */
+ static const unsigned char join_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x0a,
+ 0x06, 0x16, 0x03, 0x1b, 0xe4, 0x81, 0x36, 0x72,
+ 0x00, 0x00, 0x09, 0x5e, 0x49, 0x44, 0x41, 0x54,
+ 0x58, 0x47, 0xe5, 0x56, 0x5b, 0x6c, 0x1b, 0x59,
+ 0x19, 0xfe, 0x66, 0x6c, 0x8f, 0xc7, 0xe3, 0x6b,
+ 0x9c, 0x8b, 0xd3, 0x34, 0x69, 0x2e, 0x6d, 0xda,
+ 0x6d, 0xd3, 0xa6, 0xb7, 0x6c, 0x9b, 0x55, 0x5b,
+ 0x16, 0x44, 0x45, 0x25, 0xb6, 0x12, 0x17, 0xad,
+ 0x10, 0x08, 0xa9, 0xe2, 0x01, 0x10, 0x12, 0x97,
+ 0x95, 0xa0, 0x12, 0x3c, 0xf1, 0xc0, 0x22, 0x1e,
+ 0x60, 0xc5, 0xae, 0x56, 0x74, 0xe1, 0x91, 0x8b,
+ 0x04, 0x5a, 0x60, 0x41, 0x0b, 0xd2, 0xa2, 0x96,
+ 0xb2, 0x4d, 0x68, 0xb7, 0x69, 0x9b, 0xb6, 0x49,
+ 0xda, 0xdc, 0xdd, 0xb4, 0x49, 0xec, 0x38, 0xb6,
+ 0x13, 0xdf, 0xc7, 0x63, 0xcf, 0xd5, 0xfc, 0x67,
+ 0x9a, 0x54, 0x4d, 0x9b, 0x2e, 0xcb, 0x33, 0xc7,
+ 0x3a, 0x1a, 0xcf, 0x9c, 0x99, 0xf3, 0x7d, 0xe7,
+ 0xfb, 0xaf, 0xc0, 0xff, 0xfb, 0xe0, 0xfe, 0x57,
+ 0x01, 0x8e, 0x1d, 0x7b, 0x45, 0xaa, 0xd5, 0xac,
+ 0x63, 0xe0, 0xb8, 0x03, 0x35, 0xcb, 0xda, 0x42,
+ 0xdf, 0x7b, 0x68, 0x96, 0x78, 0x07, 0xbf, 0x48,
+ 0xf7, 0xd7, 0x05, 0xc1, 0xba, 0x3d, 0x30, 0xf0,
+ 0x96, 0xf9, 0x51, 0xf7, 0xfd, 0xc8, 0x04, 0x8e,
+ 0x1d, 0xfb, 0x56, 0xbf, 0x4b, 0x10, 0xbe, 0xb3,
+ 0xed, 0xb9, 0xae, 0xcf, 0xf7, 0xec, 0xeb, 0x76,
+ 0x79, 0xeb, 0xeb, 0xf8, 0x8a, 0x61, 0xc1, 0xb0,
+ 0x6a, 0x08, 0xfa, 0x24, 0x28, 0xa5, 0x32, 0x96,
+ 0xe7, 0x97, 0xac, 0x85, 0xe8, 0x42, 0x26, 0x31,
+ 0xb7, 0xf8, 0xfb, 0x5a, 0xcd, 0xfc, 0xf9, 0xd0,
+ 0xd0, 0xb9, 0xc5, 0xff, 0x46, 0xe4, 0x99, 0x04,
+ 0x6a, 0xb5, 0x1a, 0x4f, 0x1f, 0x4b, 0xaf, 0xbf,
+ 0xfe, 0x4e, 0xf3, 0xc0, 0xc0, 0xd8, 0x4f, 0x0e,
+ 0x9f, 0x38, 0xf4, 0x72, 0xd7, 0xfe, 0xdd, 0x9c,
+ 0x20, 0x49, 0x18, 0xbc, 0x3e, 0x8d, 0x6c, 0xae,
+ 0x00, 0xc9, 0xed, 0x02, 0x68, 0x87, 0xb6, 0xd6,
+ 0x08, 0x1a, 0x1a, 0xeb, 0xa1, 0xa8, 0x3a, 0x78,
+ 0xd4, 0x50, 0x2d, 0x16, 0x31, 0x71, 0xe5, 0xa6,
+ 0xba, 0x30, 0x19, 0x7d, 0x8d, 0x83, 0xfe, 0xa3,
+ 0xab, 0x57, 0x7f, 0xa5, 0x3d, 0x8b, 0x88, 0x63,
+ 0xb3, 0x05, 0x02, 0x67, 0xb2, 0xee, 0x38, 0x7f,
+ 0x7e, 0xf8, 0xa5, 0xe5, 0x95, 0xe2, 0x1f, 0x4e,
+ 0xbd, 0x7c, 0xf2, 0x79, 0xd5, 0x2d, 0x71, 0xd1,
+ 0x78, 0x16, 0x8d, 0x0d, 0x21, 0x1c, 0xe9, 0xed,
+ 0x44, 0xa9, 0x50, 0xc4, 0xd6, 0x46, 0x3f, 0xba,
+ 0x3b, 0x9a, 0xd0, 0xd3, 0xdd, 0x0a, 0xb7, 0xe0,
+ 0x84, 0x46, 0x8a, 0x94, 0x14, 0x1d, 0x86, 0x69,
+ 0xe0, 0x60, 0xdf, 0x4e, 0xe7, 0xde, 0xbd, 0x5d,
+ 0x27, 0x2c, 0xd5, 0x38, 0xe5, 0xf3, 0xf6, 0xfc,
+ 0x6d, 0x61, 0x61, 0xa8, 0xbc, 0x19, 0xd6, 0x53,
+ 0x0a, 0x10, 0xb8, 0x93, 0x5e, 0xdc, 0x7d, 0xfd,
+ 0xfa, 0xd4, 0xe9, 0x85, 0xa5, 0xec, 0x0f, 0x23,
+ 0x9d, 0xad, 0xa2, 0xc5, 0x39, 0xe1, 0xf6, 0x88,
+ 0x58, 0xce, 0x94, 0xe1, 0xf3, 0x4a, 0x08, 0x78,
+ 0x1c, 0x98, 0x5f, 0x48, 0xa0, 0x6f, 0x5f, 0x27,
+ 0x9c, 0x0e, 0x1e, 0xb1, 0x64, 0x0e, 0xa2, 0x28,
+ 0x92, 0x22, 0x3c, 0x0a, 0x45, 0x19, 0xf7, 0x97,
+ 0x72, 0x98, 0x5f, 0xce, 0x23, 0x5f, 0xaa, 0xa0,
+ 0x25, 0xec, 0x85, 0x9e, 0x4a, 0xce, 0x2b, 0xf9,
+ 0xd2, 0x89, 0x57, 0x5f, 0xfd, 0x4a, 0xfc, 0x49,
+ 0x12, 0x1b, 0x08, 0x10, 0x38, 0x5b, 0xef, 0x88,
+ 0x46, 0xe3, 0x1f, 0xbb, 0x33, 0xb9, 0xf8, 0x8b,
+ 0x43, 0xcf, 0xef, 0xf1, 0x37, 0xd5, 0xfb, 0xa1,
+ 0x59, 0x1c, 0x2e, 0x0e, 0xcd, 0x00, 0x0e, 0x17,
+ 0xfa, 0x7a, 0xb7, 0xc3, 0x4d, 0x14, 0x79, 0xcb,
+ 0x40, 0xbd, 0xcf, 0x09, 0xc2, 0x27, 0xe9, 0x2d,
+ 0xc8, 0x55, 0x03, 0xc3, 0x33, 0x69, 0x0c, 0xde,
+ 0x9e, 0x47, 0x2a, 0x2b, 0xa3, 0x20, 0x93, 0x4f,
+ 0x24, 0x33, 0x36, 0x5e, 0x67, 0x73, 0x10, 0xe5,
+ 0xd9, 0xd9, 0x6b, 0xc5, 0x74, 0xf2, 0xc4, 0x95,
+ 0x2b, 0xbf, 0x34, 0x1e, 0x27, 0xc1, 0xec, 0xfc,
+ 0xf8, 0x38, 0x40, 0x24, 0x1a, 0x2e, 0xbe, 0x3f,
+ 0xf6, 0x4a, 0xdb, 0x8e, 0x76, 0x7f, 0x6b, 0x93,
+ 0x1f, 0x5e, 0xb7, 0x03, 0x3e, 0x57, 0x0d, 0x07,
+ 0x77, 0x45, 0xb0, 0xb3, 0xc5, 0x0f, 0x11, 0x1a,
+ 0x02, 0x6e, 0x0e, 0x61, 0x9f, 0x0b, 0x2e, 0x07,
+ 0x07, 0x9e, 0xe3, 0x20, 0x0a, 0x64, 0x79, 0xcb,
+ 0x42, 0x58, 0x72, 0x20, 0x44, 0xb3, 0x48, 0x2a,
+ 0xac, 0xac, 0xe4, 0x98, 0x7b, 0xc0, 0x34, 0x2d,
+ 0xdc, 0x27, 0x35, 0xd0, 0xdc, 0x72, 0xd4, 0xb0,
+ 0x9c, 0x3f, 0x78, 0x02, 0x0f, 0x8f, 0x7c, 0x80,
+ 0x80, 0x25, 0x5a, 0x3c, 0xfa, 0xd3, 0x9f, 0xbd,
+ 0xdd, 0xba, 0x73, 0x5f, 0xf7, 0x37, 0x04, 0xc9,
+ 0xcd, 0x49, 0xa2, 0x0b, 0x5e, 0x8f, 0x80, 0xa5,
+ 0x74, 0x09, 0x93, 0x0b, 0x59, 0x04, 0xc2, 0x61,
+ 0x54, 0x88, 0xbf, 0xcb, 0xe9, 0x02, 0x2d, 0x51,
+ 0x24, 0xda, 0x3e, 0x88, 0xbc, 0x62, 0x22, 0x55,
+ 0xd4, 0x30, 0x36, 0xbb, 0x04, 0xaf, 0x8b, 0xc7,
+ 0x89, 0xfd, 0x6d, 0xe8, 0xdd, 0x11, 0x21, 0x15,
+ 0xaa, 0x58, 0xcd, 0x97, 0x61, 0x90, 0x6f, 0x58,
+ 0xbc, 0x93, 0x73, 0xbb, 0x1c, 0x2f, 0x44, 0xfc,
+ 0x7b, 0x7e, 0xb3, 0xb4, 0x74, 0xa3, 0xb8, 0x4e,
+ 0x84, 0xd9, 0x7b, 0x7d, 0xd4, 0xd3, 0x1f, 0x2b,
+ 0x9e, 0x2c, 0x7c, 0x4f, 0x5c, 0x51, 0x38, 0x3e,
+ 0x53, 0x41, 0x2a, 0x23, 0xc3, 0x27, 0x09, 0xb0,
+ 0x6a, 0x1c, 0xba, 0xda, 0x5b, 0x20, 0x88, 0x1e,
+ 0x38, 0x49, 0x33, 0xbf, 0x1b, 0x28, 0x54, 0x19,
+ 0x78, 0xcd, 0xde, 0x5c, 0x51, 0x0d, 0xdc, 0x99,
+ 0x8e, 0x63, 0x66, 0x61, 0x15, 0x1e, 0x7f, 0x10,
+ 0xff, 0x1c, 0x99, 0x86, 0xae, 0x56, 0x71, 0xbc,
+ 0xb7, 0x0d, 0x5f, 0xf8, 0x64, 0x0f, 0xfe, 0x7c,
+ 0x69, 0x0a, 0xb7, 0xa6, 0x12, 0x68, 0x69, 0x6a,
+ 0xf4, 0xa8, 0xc9, 0xe4, 0x77, 0x09, 0x87, 0x4d,
+ 0x7b, 0x3c, 0x6e, 0x02, 0x79, 0x78, 0x78, 0xe6,
+ 0xe3, 0x9a, 0xc3, 0xbd, 0x67, 0x74, 0x76, 0x19,
+ 0x8b, 0xc9, 0x3c, 0x66, 0x63, 0x59, 0x72, 0xa6,
+ 0x22, 0x9e, 0xdb, 0xd5, 0x09, 0xc1, 0xf3, 0x10,
+ 0x3c, 0x40, 0xe0, 0x49, 0x19, 0xb6, 0x12, 0x8a,
+ 0x56, 0x43, 0xa9, 0x6a, 0xa2, 0x58, 0x31, 0xa1,
+ 0xe8, 0x35, 0xf8, 0xfc, 0x01, 0xe8, 0x86, 0x89,
+ 0x5d, 0xdd, 0x6d, 0xd8, 0xd6, 0xde, 0x8a, 0x5b,
+ 0x0f, 0x0a, 0x78, 0xe3, 0x8f, 0xc3, 0xd8, 0xb7,
+ 0xbd, 0x09, 0xdf, 0x3f, 0x73, 0x1c, 0x16, 0xc1,
+ 0x39, 0xeb, 0xc2, 0x67, 0x0e, 0x1f, 0xfe, 0x3a,
+ 0xe9, 0xf7, 0x70, 0x3c, 0x52, 0x80, 0xe3, 0xb8,
+ 0xdc, 0xad, 0x5b, 0xb3, 0xbb, 0x03, 0x2d, 0x11,
+ 0x7e, 0xec, 0xc1, 0x2a, 0x39, 0x95, 0x8e, 0x52,
+ 0x45, 0xc7, 0xd1, 0xbe, 0x3d, 0x28, 0x13, 0x90,
+ 0xc7, 0xc5, 0x91, 0xed, 0x81, 0x44, 0x89, 0x3e,
+ 0x24, 0xdd, 0x79, 0x93, 0x9d, 0xde, 0x44, 0x85,
+ 0x4e, 0xcf, 0x42, 0xef, 0x6e, 0x34, 0x81, 0x89,
+ 0xe8, 0x92, 0x6d, 0xf3, 0x40, 0xc0, 0x07, 0xa7,
+ 0x93, 0x79, 0x2a, 0x6f, 0x27, 0xaa, 0xdf, 0xbd,
+ 0x37, 0x8a, 0xd6, 0x48, 0x08, 0x67, 0x3e, 0x7d,
+ 0x00, 0x7f, 0xfa, 0x6b, 0x39, 0x6c, 0xac, 0xa6,
+ 0x8f, 0xd2, 0x2e, 0x57, 0x18, 0x85, 0xc7, 0x4d,
+ 0x80, 0xcb, 0x97, 0xc7, 0xcb, 0x1d, 0x6d, 0x5b,
+ 0x61, 0x08, 0x12, 0x79, 0x7b, 0x17, 0x4c, 0xc3,
+ 0x80, 0xc3, 0x29, 0x40, 0xd7, 0x0d, 0x34, 0x93,
+ 0xd3, 0xc5, 0xd7, 0x2c, 0x67, 0x11, 0xb8, 0x46,
+ 0xe0, 0x55, 0x4a, 0x3c, 0x2c, 0xf9, 0x7c, 0x70,
+ 0x73, 0x06, 0x53, 0xf7, 0x96, 0xc1, 0x82, 0x88,
+ 0xc5, 0x51, 0x26, 0x57, 0xb4, 0x89, 0x98, 0xe4,
+ 0x98, 0x6e, 0x0a, 0x4f, 0x8e, 0x88, 0x2c, 0xa6,
+ 0x8b, 0x78, 0xfb, 0xd2, 0x34, 0x5e, 0x3c, 0xb6,
+ 0x87, 0x7b, 0x77, 0x6a, 0xb6, 0x7f, 0x9d, 0xc0,
+ 0x86, 0x28, 0xb8, 0xf8, 0xc1, 0x54, 0x47, 0x4f,
+ 0x57, 0x13, 0xfa, 0x0f, 0x74, 0xc1, 0x4b, 0x9e,
+ 0xbd, 0xbd, 0x35, 0x0c, 0x89, 0xc4, 0x6a, 0x0d,
+ 0x39, 0x30, 0xb7, 0xa2, 0x42, 0xae, 0x68, 0x28,
+ 0x57, 0x35, 0x52, 0x47, 0x83, 0xc2, 0x26, 0x81,
+ 0x57, 0x48, 0xa9, 0xb1, 0xc9, 0x79, 0x02, 0xb7,
+ 0x1e, 0x4e, 0x3a, 0x31, 0x63, 0x62, 0x93, 0xb1,
+ 0x00, 0xb5, 0xaa, 0xc2, 0xeb, 0xf7, 0xc1, 0xa4,
+ 0x43, 0x3c, 0x58, 0x4c, 0x23, 0xb1, 0x5a, 0x44,
+ 0x63, 0x63, 0xb0, 0x7d, 0xcd, 0x02, 0x1b, 0x7c,
+ 0x00, 0x92, 0xc7, 0x1d, 0xba, 0x1d, 0x5d, 0xc1,
+ 0xce, 0x46, 0x72, 0xbc, 0xaa, 0x82, 0x80, 0xc8,
+ 0xa3, 0xa3, 0x41, 0x40, 0xba, 0xa0, 0xda, 0x6a,
+ 0x54, 0x18, 0xb8, 0x42, 0x24, 0x14, 0x15, 0x65,
+ 0x22, 0xc3, 0x48, 0x64, 0xf2, 0x32, 0xaa, 0x74,
+ 0xb5, 0x08, 0x91, 0x0e, 0xfc, 0xf0, 0xca, 0xfe,
+ 0x33, 0x42, 0xf4, 0xd3, 0x08, 0x98, 0x91, 0xe1,
+ 0x78, 0x0e, 0x6e, 0x4a, 0x20, 0xcb, 0x2b, 0x05,
+ 0x54, 0x2a, 0x9a, 0x7f, 0x9d, 0xc0, 0x06, 0x13,
+ 0xd0, 0x3b, 0x4a, 0xfb, 0xb6, 0x08, 0x64, 0x1d,
+ 0xe8, 0xdf, 0xbb, 0x85, 0x8a, 0x8c, 0xc7, 0x96,
+ 0x39, 0x5f, 0x90, 0x6d, 0x3f, 0x30, 0x38, 0x17,
+ 0x2a, 0xba, 0x69, 0x6f, 0x68, 0x90, 0xc4, 0xcc,
+ 0xe1, 0x58, 0x2c, 0x32, 0x7b, 0x57, 0x35, 0xc3,
+ 0x06, 0x5d, 0x27, 0xc2, 0xde, 0xb1, 0x48, 0x0d,
+ 0x96, 0xdc, 0xe4, 0x92, 0x4c, 0x09, 0x8b, 0x83,
+ 0x24, 0x3a, 0xe9, 0xc4, 0x14, 0x35, 0x8a, 0xaa,
+ 0x6e, 0xaa, 0x80, 0x5a, 0x2e, 0xc7, 0x98, 0x4d,
+ 0x98, 0x1d, 0xbd, 0xa2, 0xdb, 0x4e, 0x42, 0x61,
+ 0x8a, 0xb9, 0x1c, 0x15, 0x9e, 0xf1, 0xe9, 0x79,
+ 0x64, 0x0b, 0x25, 0x5b, 0x01, 0x99, 0x29, 0xb0,
+ 0xa6, 0x02, 0x73, 0xc2, 0x03, 0xbd, 0x3b, 0x88,
+ 0x04, 0x25, 0x2c, 0x9f, 0x17, 0x1e, 0xfa, 0xce,
+ 0x26, 0x42, 0x72, 0xac, 0x93, 0xd1, 0x75, 0xaa,
+ 0x0f, 0x34, 0x99, 0x23, 0x8b, 0x9c, 0x49, 0xbe,
+ 0x61, 0x26, 0x36, 0x55, 0x40, 0x55, 0xaa, 0x13,
+ 0x8a, 0x5c, 0xfe, 0x94, 0x44, 0xc0, 0x0a, 0x9d,
+ 0x28, 0xe0, 0x75, 0xd9, 0x27, 0x65, 0xf9, 0xbe,
+ 0x54, 0xae, 0x62, 0xe4, 0xfd, 0x11, 0xec, 0xd9,
+ 0xbb, 0xdd, 0xae, 0x07, 0xec, 0x74, 0x86, 0x69,
+ 0xda, 0x05, 0x88, 0xd5, 0x81, 0x23, 0x7d, 0x3d,
+ 0xa4, 0x88, 0x05, 0x55, 0xd3, 0x31, 0x7e, 0x77,
+ 0x86, 0x84, 0xe1, 0xec, 0x77, 0x98, 0x99, 0x2a,
+ 0x14, 0xaa, 0x1e, 0xb7, 0x40, 0x29, 0x39, 0x80,
+ 0xf4, 0xfd, 0x45, 0x7a, 0xca, 0xdd, 0x59, 0x27,
+ 0xb0, 0xa1, 0x1a, 0xb6, 0xb6, 0x1d, 0x71, 0x86,
+ 0x9b, 0x1b, 0xbf, 0x24, 0x04, 0x02, 0x5c, 0x67,
+ 0xb3, 0x1f, 0x43, 0x77, 0xe3, 0x18, 0x99, 0x49,
+ 0xa0, 0x21, 0x28, 0x91, 0x7c, 0x02, 0xae, 0x8d,
+ 0xc7, 0x30, 0x3e, 0x13, 0x43, 0xbe, 0x58, 0x86,
+ 0x87, 0x8a, 0x93, 0x41, 0xd1, 0xa0, 0x12, 0xd1,
+ 0x2a, 0x81, 0xaa, 0xb6, 0xad, 0x2d, 0x48, 0x82,
+ 0x83, 0x26, 0x8f, 0x3a, 0x9f, 0x80, 0x3a, 0xbf,
+ 0x08, 0x3f, 0x25, 0x32, 0x91, 0x0e, 0xd4, 0xb7,
+ 0x6b, 0x0b, 0xd5, 0x86, 0x34, 0xe4, 0xc4, 0x8a,
+ 0xa9, 0x2b, 0x95, 0x6f, 0xc6, 0xe3, 0xc3, 0x94,
+ 0xca, 0x9e, 0x08, 0xc3, 0xb2, 0xac, 0x5e, 0x18,
+ 0x1f, 0x9e, 0x4c, 0xb7, 0xec, 0x68, 0x8f, 0xa4,
+ 0x72, 0x15, 0x4c, 0x2d, 0x66, 0xb1, 0x9a, 0x29,
+ 0xe0, 0xdf, 0x23, 0x0b, 0x94, 0x7e, 0x1d, 0xf8,
+ 0xf2, 0xa9, 0x5e, 0x0c, 0x8e, 0xcc, 0x63, 0x2c,
+ 0x9a, 0x82, 0x97, 0xe4, 0xae, 0xaf, 0x0f, 0xda,
+ 0x7e, 0x60, 0xfb, 0x02, 0xd9, 0x2d, 0x40, 0x21,
+ 0xe3, 0x17, 0x1d, 0x08, 0x0a, 0x61, 0xd4, 0x0c,
+ 0xdd, 0x26, 0x54, 0x26, 0x93, 0x85, 0x03, 0x5b,
+ 0x90, 0xcd, 0xe6, 0xe0, 0xb0, 0x28, 0x6a, 0xf2,
+ 0xa5, 0xbf, 0x53, 0xa3, 0x92, 0xdb, 0xd4, 0x04,
+ 0x37, 0x6e, 0x9c, 0xd3, 0x1d, 0xce, 0x6f, 0xbf,
+ 0x59, 0xce, 0xe4, 0x7e, 0x7c, 0x8d, 0x4a, 0x60,
+ 0xb2, 0x64, 0x80, 0x1a, 0x1c, 0xdb, 0xd3, 0x59,
+ 0xba, 0xbd, 0x3e, 0x11, 0xc3, 0xf1, 0xfd, 0xdb,
+ 0xf0, 0xd5, 0xcf, 0x1c, 0x46, 0xde, 0x70, 0x52,
+ 0x91, 0x29, 0x42, 0x27, 0x13, 0x31, 0x33, 0x05,
+ 0x3c, 0x2e, 0xfb, 0xe4, 0x21, 0x3a, 0xb9, 0x97,
+ 0x72, 0x87, 0xc0, 0x93, 0xd0, 0xc4, 0x4a, 0xa4,
+ 0x3e, 0x41, 0x56, 0x2a, 0x48, 0x27, 0x93, 0xf0,
+ 0x92, 0x4d, 0xe8, 0x20, 0x6f, 0xac, 0x83, 0xb3,
+ 0xeb, 0x93, 0xd5, 0x90, 0xe2, 0xb6, 0xf0, 0x66,
+ 0x62, 0x6a, 0x36, 0x96, 0xa4, 0x92, 0xba, 0x98,
+ 0x96, 0xe1, 0xa2, 0xdc, 0xae, 0xa8, 0xa6, 0x9d,
+ 0xf3, 0x75, 0xdd, 0xc2, 0xa5, 0x9b, 0xf3, 0xf8,
+ 0xf5, 0x7b, 0x63, 0x14, 0x5e, 0x26, 0xfa, 0xba,
+ 0x1b, 0xb0, 0x6b, 0x6b, 0x90, 0x0a, 0x13, 0x4f,
+ 0x36, 0xaf, 0x41, 0xa0, 0x42, 0xe1, 0xa3, 0x2a,
+ 0xd5, 0xdd, 0x5a, 0x87, 0xcf, 0xbe, 0xb8, 0x1b,
+ 0x9f, 0xfb, 0x44, 0x0f, 0x76, 0xb5, 0x37, 0xd0,
+ 0x9e, 0x55, 0x34, 0x85, 0x3c, 0xf0, 0x3b, 0xf9,
+ 0x81, 0xb7, 0xce, 0x7d, 0xed, 0xd6, 0xe3, 0x04,
+ 0x9e, 0xea, 0x88, 0x96, 0x97, 0xc7, 0xdc, 0x7d,
+ 0x07, 0xfb, 0xf3, 0x4a, 0x15, 0x2f, 0xa9, 0x82,
+ 0xc4, 0x55, 0x35, 0xaa, 0xf5, 0xb2, 0x02, 0x8d,
+ 0xec, 0xcc, 0xbc, 0xda, 0x25, 0xb8, 0x50, 0x4f,
+ 0xed, 0xd7, 0x6a, 0x49, 0xc3, 0x74, 0x2c, 0x87,
+ 0x95, 0xbc, 0x82, 0x48, 0x9d, 0x88, 0x8e, 0x26,
+ 0x1f, 0x1a, 0x83, 0x22, 0x1a, 0xfc, 0x02, 0x7a,
+ 0x29, 0xf7, 0xfb, 0xa8, 0x8a, 0xf2, 0x14, 0x7a,
+ 0x0e, 0x72, 0xe0, 0xf4, 0x6a, 0x0e, 0x85, 0xe5,
+ 0xac, 0xdc, 0xb1, 0xcd, 0xf3, 0xda, 0xe0, 0xe0,
+ 0xc5, 0xf8, 0xe5, 0xcb, 0x97, 0xa9, 0x9a, 0x3c,
+ 0x1c, 0x4f, 0x12, 0x60, 0x79, 0x21, 0x78, 0xef,
+ 0xde, 0x68, 0xc6, 0x6d, 0xfa, 0x3d, 0x0e, 0x97,
+ 0x74, 0x90, 0xf3, 0xf9, 0x51, 0xa0, 0x86, 0x53,
+ 0xad, 0xa8, 0x76, 0x4c, 0xfb, 0x28, 0xcf, 0x0b,
+ 0x1e, 0x89, 0xbc, 0xdf, 0x20, 0xc7, 0x33, 0xa9,
+ 0x0e, 0x68, 0x48, 0xe5, 0xca, 0x94, 0x8c, 0x54,
+ 0x70, 0x35, 0x13, 0x41, 0x8a, 0xf5, 0x1d, 0x94,
+ 0x41, 0x59, 0x8b, 0xc6, 0x46, 0xa1, 0xa4, 0xe0,
+ 0x41, 0x34, 0x6e, 0x8a, 0x2e, 0xfd, 0x1d, 0xc3,
+ 0xc8, 0x4f, 0x0e, 0x0d, 0x0d, 0xa5, 0xa6, 0xa6,
+ 0xa6, 0x18, 0x01, 0xbb, 0x73, 0xde, 0x8c, 0x80,
+ 0x4f, 0x51, 0x14, 0x69, 0x6e, 0x6e, 0x38, 0x0a,
+ 0x99, 0x77, 0xd5, 0x05, 0xea, 0xf6, 0x09, 0x7e,
+ 0x2f, 0x57, 0x28, 0x2a, 0xe0, 0x1c, 0xe4, 0xe1,
+ 0x94, 0x56, 0xed, 0x24, 0x44, 0x5e, 0xaf, 0x6b,
+ 0x1a, 0xa5, 0x58, 0x22, 0xa6, 0xa9, 0xf0, 0xf0,
+ 0x16, 0x7a, 0xda, 0xc3, 0xd4, 0x07, 0x34, 0x61,
+ 0x7a, 0x6e, 0x99, 0x4c, 0x66, 0x50, 0x7b, 0xa6,
+ 0x50, 0x48, 0xde, 0x37, 0x6b, 0x46, 0x71, 0xc0,
+ 0x34, 0x8b, 0xa3, 0x4b, 0x34, 0x06, 0x07, 0x07,
+ 0x93, 0xa9, 0x54, 0x4a, 0x21, 0x6c, 0x4a, 0x77,
+ 0x4f, 0x13, 0x60, 0xfd, 0x05, 0xd5, 0xbc, 0x87,
+ 0x73, 0x65, 0x65, 0xfa, 0xbe, 0xa7, 0x86, 0x4c,
+ 0x73, 0xb0, 0x7e, 0x9f, 0xe8, 0x93, 0x9c, 0x75,
+ 0xf5, 0x41, 0xce, 0xd0, 0x29, 0xed, 0x12, 0x60,
+ 0x8d, 0x80, 0x2d, 0x83, 0x5d, 0xab, 0x68, 0xab,
+ 0x97, 0xf0, 0xc5, 0x93, 0x7b, 0x51, 0x51, 0x14,
+ 0x0c, 0xdf, 0x99, 0xb3, 0xd3, 0x76, 0x26, 0x9d,
+ 0x43, 0xec, 0x7e, 0xbc, 0x68, 0x99, 0xf9, 0x81,
+ 0x6a, 0xb5, 0x30, 0x91, 0x4e, 0xa7, 0xe3, 0x93,
+ 0x93, 0x93, 0xf3, 0xe7, 0xcf, 0x9f, 0x4f, 0xd2,
+ 0xfe, 0xac, 0x41, 0xb5, 0x15, 0xd8, 0x90, 0x8a,
+ 0xe9, 0x9e, 0xf5, 0x6b, 0x4c, 0x1e, 0x81, 0x26,
+ 0xab, 0xd9, 0x8e, 0xd1, 0xd1, 0x7f, 0xfc, 0xeb,
+ 0xf4, 0xe9, 0xa3, 0x56, 0x2a, 0xa5, 0x9d, 0x9c,
+ 0x8f, 0x2e, 0x6d, 0x0f, 0x35, 0x36, 0xb8, 0x39,
+ 0x9f, 0x97, 0xf3, 0x7a, 0x45, 0x72, 0xb0, 0x46,
+ 0x1c, 0xd8, 0xd9, 0x82, 0x4c, 0xb6, 0x80, 0xdf,
+ 0xfe, 0x65, 0x00, 0x92, 0x93, 0x43, 0x48, 0x70,
+ 0xd5, 0xca, 0xf1, 0x65, 0xd9, 0x27, 0x99, 0x77,
+ 0x42, 0x21, 0x6b, 0x82, 0xcc, 0x96, 0x91, 0x65,
+ 0x79, 0x29, 0x16, 0x8b, 0xcd, 0x5d, 0xb8, 0x70,
+ 0x21, 0xb6, 0xb6, 0xff, 0xa3, 0x36, 0xfd, 0xa9,
+ 0xae, 0x98, 0xb1, 0xa2, 0xc1, 0xda, 0xf2, 0xd0,
+ 0xda, 0x0c, 0xb8, 0xdd, 0xee, 0xd0, 0xd9, 0xb3,
+ 0x67, 0x0f, 0xf6, 0xf7, 0xbf, 0x70, 0x88, 0xe3,
+ 0x3c, 0x9d, 0x3c, 0xef, 0x0c, 0x66, 0xb3, 0xb2,
+ 0x38, 0x3c, 0xf2, 0xc0, 0x3f, 0x36, 0xfe, 0xc0,
+ 0x69, 0x68, 0x9a, 0x5a, 0x29, 0x15, 0x57, 0xd4,
+ 0x6a, 0x71, 0xd1, 0xe3, 0xa9, 0x46, 0x9b, 0x9b,
+ 0x9d, 0xf1, 0x48, 0x24, 0xa2, 0x79, 0xbd, 0x5e,
+ 0xc5, 0x34, 0xcd, 0x4c, 0x32, 0x99, 0x5c, 0xba,
+ 0x7a, 0xf5, 0x6a, 0x3c, 0x91, 0x48, 0xb0, 0x2e,
+ 0x95, 0xc9, 0xcf, 0xb2, 0xbd, 0x3d, 0x9e, 0x45,
+ 0x80, 0xad, 0x31, 0xff, 0x60, 0x7d, 0x62, 0x80,
+ 0xa6, 0x8f, 0xa6, 0x77, 0xed, 0x9e, 0x3d, 0x5b,
+ 0x57, 0x88, 0x29, 0xc8, 0xf6, 0x60, 0x1b, 0x32,
+ 0x49, 0x99, 0x5d, 0x55, 0x22, 0xac, 0x36, 0x34,
+ 0x34, 0xa8, 0x82, 0x20, 0x28, 0xd9, 0x6c, 0x36,
+ 0x5f, 0xa0, 0x41, 0xcf, 0x99, 0xec, 0x1b, 0x3a,
+ 0x62, 0xba, 0xff, 0x50, 0x02, 0x6c, 0x7d, 0xfd,
+ 0x1d, 0x06, 0x28, 0xd2, 0x64, 0xca, 0x30, 0x1f,
+ 0x61, 0xf7, 0x0c, 0xfc, 0x71, 0x27, 0xa6, 0x62,
+ 0x6c, 0x03, 0x30, 0x79, 0x59, 0x9a, 0x5d, 0x9f,
+ 0xec, 0x9e, 0xad, 0x6d, 0x3a, 0x3e, 0x4c, 0x81,
+ 0x4d, 0x3f, 0x58, 0x7b, 0xc8, 0x80, 0x59, 0x12,
+ 0x63, 0xdf, 0xaf, 0x2b, 0xc0, 0x96, 0x98, 0x0a,
+ 0x0c, 0xec, 0x91, 0xc4, 0x6b, 0xef, 0x3f, 0xf3,
+ 0xf2, 0x1f, 0xbd, 0x3d, 0xcb, 0x55, 0x1c, 0xe5,
+ 0x74, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+ 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/join_icon_text.png.h b/src/images/join_icon_text.png.h
new file mode 100644
index 0000000..7864ce3
--- /dev/null
+++ b/src/images/join_icon_text.png.h
@@ -0,0 +1,193 @@
+/* join_icon_text.png - 1519 bytes */
+ static const unsigned char join_icon_text_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x69, 0x71,
+ 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x03,
+ 0x16, 0x14, 0x2c, 0x30, 0x04, 0xac, 0x16, 0xdf,
+ 0x00, 0x00, 0x05, 0x6f, 0x49, 0x44, 0x41, 0x54,
+ 0x78, 0xda, 0xed, 0x98, 0x5f, 0x68, 0x53, 0x57,
+ 0x1c, 0xc7, 0xbf, 0xf9, 0x63, 0x6e, 0xda, 0xd2,
+ 0xe6, 0x52, 0xc6, 0xa6, 0x38, 0x8a, 0xb8, 0xe4,
+ 0x25, 0x5a, 0xd6, 0xb2, 0xb5, 0x94, 0x89, 0xd2,
+ 0xb1, 0x87, 0x09, 0xed, 0xcb, 0x10, 0x1f, 0x2a,
+ 0xb4, 0x14, 0xf7, 0xa2, 0xac, 0xd0, 0xf8, 0x8f,
+ 0x46, 0xb7, 0x87, 0x29, 0x32, 0x99, 0x79, 0x98,
+ 0xc8, 0x46, 0x87, 0xf8, 0x07, 0x2a, 0x68, 0x51,
+ 0x1c, 0xad, 0x60, 0xa1, 0x5b, 0x06, 0xc6, 0xb2,
+ 0x87, 0xda, 0xa2, 0xb9, 0xf8, 0xa0, 0x09, 0x63,
+ 0xd6, 0x87, 0xae, 0xcc, 0xda, 0xd6, 0x55, 0x93,
+ 0xdb, 0xe4, 0x26, 0xf7, 0xbb, 0x97, 0x9b, 0x92,
+ 0x86, 0xa4, 0xde, 0xb8, 0x6a, 0xe3, 0x76, 0x3e,
+ 0xf0, 0x7b, 0x39, 0xe7, 0xdc, 0xdf, 0xbd, 0xe7,
+ 0x7b, 0xce, 0xef, 0x77, 0x7e, 0xe7, 0x02, 0x02,
+ 0x81, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x81,
+ 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40,
+ 0x20, 0xf8, 0xff, 0x60, 0x79, 0x8d, 0xef, 0xe2,
+ 0x2a, 0xbe, 0xbb, 0x20, 0xd6, 0x15, 0x98, 0x54,
+ 0x3e, 0x8b, 0x01, 0x18, 0x06, 0xf0, 0xc1, 0x92,
+ 0xc1, 0x24, 0x48, 0xfe, 0xa7, 0x76, 0x10, 0x73,
+ 0x49, 0x26, 0x93, 0x8c, 0x44, 0x22, 0xdc, 0xbf,
+ 0x7f, 0x3f, 0x2d, 0x16, 0x0b, 0x01, 0x34, 0xe5,
+ 0x8e, 0xcd, 0xb3, 0x1b, 0xde, 0x7c, 0x01, 0x32,
+ 0xab, 0xbf, 0x6e, 0xdd, 0x3a, 0x0e, 0x0d, 0x0d,
+ 0x91, 0x24, 0xfd, 0x7e, 0x3f, 0x01, 0xfc, 0xf6,
+ 0x02, 0x01, 0xea, 0x73, 0x76, 0x8f, 0x06, 0x40,
+ 0x01, 0xd0, 0x6e, 0x84, 0x49, 0x5f, 0x4e, 0xff,
+ 0xbb, 0xc6, 0x73, 0x6f, 0xe5, 0xb4, 0x5f, 0x2d,
+ 0x05, 0x01, 0xac, 0x00, 0x8e, 0xb9, 0xdd, 0x6e,
+ 0x92, 0xe4, 0xc4, 0xc4, 0x44, 0x26, 0x1c, 0x96,
+ 0x13, 0xe0, 0x23, 0x9f, 0xcf, 0x47, 0x92, 0x4c,
+ 0xa7, 0xd3, 0x9c, 0x9a, 0x9a, 0xe2, 0x99, 0x33,
+ 0x67, 0x58, 0x55, 0x55, 0x45, 0x00, 0x9f, 0x03,
+ 0xe8, 0x1b, 0x1b, 0x1b, 0x23, 0x49, 0xee, 0xdc,
+ 0xb9, 0x93, 0x00, 0xbe, 0x34, 0x9e, 0x6b, 0xdb,
+ 0xbe, 0x7d, 0x3b, 0x49, 0x52, 0x51, 0x94, 0x92,
+ 0x11, 0x00, 0x00, 0xd6, 0xd8, 0xed, 0xf6, 0xc5,
+ 0x70, 0x30, 0x23, 0xc0, 0x91, 0x23, 0x47, 0xe8,
+ 0xf5, 0x7a, 0xe9, 0x74, 0x3a, 0xb9, 0x7b, 0xf7,
+ 0x6e, 0x92, 0xe4, 0x85, 0x0b, 0x17, 0x08, 0x20,
+ 0x02, 0xa0, 0xaf, 0xb3, 0xb3, 0x93, 0x24, 0x39,
+ 0x38, 0x38, 0x98, 0xf1, 0x67, 0x01, 0x70, 0xa7,
+ 0xb7, 0xb7, 0x97, 0x24, 0x79, 0xe8, 0xd0, 0xa1,
+ 0xd2, 0xda, 0x01, 0x1e, 0x8f, 0xc7, 0xec, 0x0e,
+ 0x58, 0x03, 0xe0, 0x2b, 0x00, 0x7f, 0x00, 0x48,
+ 0x03, 0xa0, 0xcd, 0x66, 0x23, 0x49, 0x4e, 0x4f,
+ 0x4f, 0xd3, 0x68, 0x73, 0x3b, 0x9d, 0x4e, 0xce,
+ 0xcc, 0xcc, 0x30, 0x99, 0x4c, 0xb2, 0xba, 0xba,
+ 0x9a, 0x00, 0xbc, 0x16, 0x8b, 0x85, 0x93, 0x93,
+ 0x93, 0x4c, 0xa7, 0xd3, 0x5c, 0xbf, 0x7e, 0x3d,
+ 0x01, 0x34, 0x96, 0x44, 0x0e, 0x58, 0xbb, 0x76,
+ 0x6d, 0x31, 0x39, 0xa0, 0xcf, 0xe3, 0xf1, 0xf0,
+ 0xfa, 0xf5, 0xeb, 0x9c, 0x9d, 0x9d, 0xa5, 0xae,
+ 0xeb, 0x8b, 0x63, 0x74, 0x5d, 0xcf, 0x1e, 0xf7,
+ 0x7b, 0x20, 0x10, 0x20, 0x49, 0xee, 0xd9, 0xb3,
+ 0x87, 0x00, 0x7e, 0x68, 0x68, 0x68, 0x20, 0x49,
+ 0x06, 0x83, 0xc1, 0x4c, 0xde, 0xb0, 0x95, 0xc4,
+ 0x29, 0xa0, 0x69, 0x1a, 0xa3, 0xd1, 0x28, 0x0f,
+ 0x1c, 0x38, 0x60, 0xe6, 0x14, 0x88, 0x65, 0xe2,
+ 0xbb, 0xab, 0xab, 0x8b, 0x92, 0x24, 0xd1, 0x6a,
+ 0xb5, 0xe6, 0x1b, 0xd7, 0xba, 0x71, 0xe3, 0x46,
+ 0xea, 0xba, 0xce, 0x91, 0x91, 0x11, 0x02, 0x48,
+ 0x1f, 0x3f, 0x7e, 0x9c, 0x24, 0xd9, 0xd9, 0xd9,
+ 0x49, 0x00, 0x81, 0x92, 0x39, 0x05, 0x0c, 0x53,
+ 0x01, 0xfc, 0x0c, 0xe0, 0xc3, 0x17, 0xe4, 0x8b,
+ 0x58, 0x32, 0x99, 0x24, 0x49, 0x96, 0x95, 0x95,
+ 0x11, 0xc0, 0xd7, 0x5e, 0xaf, 0xb7, 0x50, 0xa8,
+ 0xa4, 0x87, 0x86, 0x86, 0xa8, 0xeb, 0x3a, 0x37,
+ 0x6c, 0xd8, 0xc0, 0x7b, 0xf7, 0xee, 0x31, 0x1e,
+ 0x8f, 0xb3, 0xb2, 0xb2, 0x92, 0x00, 0xdc, 0xa5,
+ 0x22, 0x40, 0xb1, 0x63, 0x63, 0x77, 0xef, 0xde,
+ 0x25, 0x49, 0xee, 0xda, 0xb5, 0x8b, 0xb2, 0x2c,
+ 0x2f, 0xdc, 0xb8, 0x71, 0xa3, 0x90, 0xcf, 0x63,
+ 0xad, 0xad, 0xad, 0x24, 0xc9, 0x73, 0xe7, 0xce,
+ 0x91, 0x24, 0xfb, 0xfb, 0xfb, 0x09, 0x60, 0x66,
+ 0x35, 0xab, 0xca, 0x7f, 0x2b, 0x40, 0x7f, 0x6d,
+ 0x6d, 0x2d, 0xc7, 0xc7, 0xc7, 0xa9, 0x69, 0x1a,
+ 0x1f, 0x3d, 0x7a, 0xa4, 0xef, 0xdd, 0xbb, 0xb7,
+ 0x90, 0xcf, 0x77, 0xac, 0x56, 0x2b, 0x1f, 0x3e,
+ 0x7c, 0xb8, 0xd8, 0xdf, 0xd2, 0xd2, 0x42, 0x00,
+ 0xdd, 0xab, 0x5a, 0x08, 0xe5, 0x58, 0xb1, 0x63,
+ 0x9d, 0x00, 0x2e, 0x1a, 0x21, 0x93, 0xb1, 0xe5,
+ 0x7c, 0x8e, 0x1c, 0x3e, 0x7c, 0x98, 0x24, 0xf9,
+ 0xf8, 0xf1, 0x63, 0xda, 0xed, 0x76, 0x02, 0x78,
+ 0xfb, 0xff, 0x70, 0x69, 0x0b, 0x00, 0x60, 0x79,
+ 0x79, 0x39, 0xaf, 0x5d, 0xbb, 0x46, 0x92, 0x3c,
+ 0x7a, 0xf4, 0x28, 0x01, 0xdc, 0x7f, 0x63, 0x4b,
+ 0xe8, 0x3c, 0xab, 0xbc, 0xdc, 0xca, 0x07, 0x82,
+ 0xc1, 0xe0, 0xe2, 0xca, 0x9f, 0x3a, 0x75, 0x2a,
+ 0xb3, 0xfa, 0x1f, 0xbf, 0xea, 0x0f, 0x6d, 0x02,
+ 0x70, 0xc5, 0x48, 0x34, 0xd9, 0x76, 0x25, 0xeb,
+ 0x78, 0x5b, 0xa9, 0xdc, 0xb1, 0x5c, 0x3e, 0x09,
+ 0xe4, 0x88, 0x73, 0x1f, 0xc0, 0x67, 0xaf, 0x7a,
+ 0xf2, 0xa7, 0x1d, 0x0e, 0x87, 0xea, 0xf7, 0xfb,
+ 0xb5, 0x70, 0x38, 0xac, 0xc7, 0xe3, 0x71, 0x3d,
+ 0x1e, 0x8f, 0xeb, 0xe1, 0x70, 0x58, 0xf7, 0xfb,
+ 0xfd, 0x29, 0x87, 0xc3, 0x91, 0x00, 0x70, 0xfa,
+ 0x35, 0x09, 0xf0, 0xda, 0x69, 0x92, 0x24, 0x89,
+ 0xa1, 0x50, 0x88, 0x9a, 0xa6, 0xd1, 0xe7, 0xf3,
+ 0x25, 0x65, 0x59, 0x9e, 0x95, 0x65, 0x79, 0x76,
+ 0xdf, 0xbe, 0x7d, 0xa9, 0x54, 0x2a, 0xc5, 0x50,
+ 0x28, 0x44, 0x87, 0xc3, 0xb1, 0xa4, 0xd0, 0xc9,
+ 0xb1, 0xb9, 0x2c, 0xfb, 0x0b, 0xc0, 0x37, 0xc6,
+ 0x79, 0x5e, 0x50, 0x00, 0x13, 0x61, 0xb1, 0x9c,
+ 0x4f, 0x00, 0xa8, 0x02, 0xf0, 0x2d, 0x80, 0x3f,
+ 0x01, 0xfc, 0x9d, 0x65, 0x17, 0xb3, 0x6e, 0x91,
+ 0xa6, 0xb8, 0xda, 0xd3, 0xd3, 0x43, 0x92, 0x3c,
+ 0x71, 0xe2, 0x44, 0xa6, 0xb0, 0x79, 0xdf, 0xb8,
+ 0xba, 0x26, 0x4e, 0x9e, 0x3c, 0x49, 0x92, 0xec,
+ 0xe9, 0xe9, 0xa1, 0x11, 0x0e, 0x4b, 0x26, 0xb5,
+ 0x63, 0xc7, 0x0e, 0x8e, 0x8e, 0x8e, 0x6a, 0xaa,
+ 0xaa, 0xea, 0xcf, 0x9f, 0x3f, 0xe7, 0xf0, 0xf0,
+ 0x30, 0x3d, 0x1e, 0x0f, 0x01, 0x9c, 0x2f, 0x72,
+ 0x07, 0x14, 0xe3, 0x53, 0x06, 0xa0, 0x6e, 0xdd,
+ 0xba, 0x35, 0x11, 0x0c, 0x06, 0xd3, 0xf3, 0xf3,
+ 0xf3, 0xfa, 0xc2, 0xc2, 0x02, 0xc7, 0xc7, 0xc7,
+ 0x33, 0xb7, 0x48, 0x02, 0x78, 0xcf, 0xac, 0x00,
+ 0x73, 0x8a, 0xa2, 0x90, 0x24, 0xbd, 0x5e, 0x2f,
+ 0x01, 0x7c, 0x9a, 0xd5, 0xd7, 0xb2, 0x79, 0xf3,
+ 0x66, 0x92, 0x64, 0x38, 0x1c, 0xce, 0x14, 0x22,
+ 0x4b, 0x3e, 0x76, 0x6c, 0x6c, 0x8c, 0x9b, 0x36,
+ 0x6d, 0x9a, 0x97, 0x24, 0x69, 0xee, 0xe0, 0xc1,
+ 0x83, 0x24, 0xc9, 0xd1, 0xd1, 0x51, 0x02, 0x48,
+ 0xbc, 0xac, 0x00, 0x26, 0x7c, 0x9e, 0x6e, 0x6e,
+ 0x6e, 0xa6, 0xa6, 0x69, 0xbc, 0x79, 0xf3, 0x26,
+ 0x6b, 0x6a, 0x6a, 0x9e, 0x55, 0x56, 0x56, 0xce,
+ 0x9f, 0x3d, 0x7b, 0x96, 0x24, 0xd9, 0xd1, 0xd1,
+ 0x41, 0xe3, 0x2f, 0x95, 0x39, 0x01, 0x54, 0x55,
+ 0x25, 0xc9, 0xcc, 0x36, 0x97, 0xb2, 0xfa, 0x9c,
+ 0x92, 0x24, 0x91, 0x24, 0xe3, 0xf1, 0x78, 0x5e,
+ 0x01, 0xea, 0xeb, 0xeb, 0x69, 0xfc, 0xc8, 0x68,
+ 0xa8, 0xa8, 0xa8, 0x20, 0x49, 0xa6, 0x52, 0x29,
+ 0xd3, 0x93, 0xcd, 0xd7, 0x66, 0xc2, 0xe7, 0x74,
+ 0x28, 0x14, 0x22, 0x49, 0xd6, 0xd6, 0xd6, 0x2e,
+ 0x86, 0x4d, 0x75, 0x75, 0x35, 0x49, 0x32, 0x12,
+ 0x89, 0x64, 0x8b, 0xf5, 0x6a, 0x05, 0xb0, 0xd9,
+ 0x6c, 0x04, 0x50, 0xf6, 0xb2, 0x93, 0xcd, 0xd7,
+ 0x66, 0xc2, 0xe7, 0x74, 0x2c, 0x16, 0x63, 0x21,
+ 0x0c, 0xb1, 0x12, 0xa6, 0x7f, 0x8a, 0x46, 0xa3,
+ 0x51, 0x00, 0x80, 0xdb, 0xed, 0x06, 0x80, 0xe6,
+ 0xac, 0xae, 0x4f, 0x3c, 0x1e, 0xcf, 0x92, 0x31,
+ 0xb9, 0xa4, 0xd3, 0x69, 0x18, 0x79, 0x63, 0xc5,
+ 0x28, 0xc6, 0xa7, 0x2c, 0xcb, 0xb0, 0x58, 0x2c,
+ 0x4b, 0xcc, 0x6e, 0xb7, 0x17, 0xf5, 0x57, 0x38,
+ 0x78, 0xe9, 0xd2, 0x25, 0x00, 0x40, 0x7b, 0x7b,
+ 0x3b, 0x00, 0x0c, 0x18, 0x49, 0xb0, 0x0e, 0xc0,
+ 0x4f, 0x1d, 0x1d, 0x1d, 0x00, 0x80, 0xcb, 0x97,
+ 0x2f, 0x03, 0xc0, 0xaf, 0xa5, 0x52, 0x5d, 0xdd,
+ 0xbe, 0x7d, 0x1b, 0x00, 0xb0, 0x6d, 0xdb, 0x36,
+ 0x00, 0xf8, 0x05, 0x40, 0xb9, 0x71, 0x53, 0xfc,
+ 0xd1, 0xb0, 0xf3, 0x45, 0x1d, 0x83, 0xb7, 0x6e,
+ 0xdd, 0xa2, 0xa6, 0x69, 0xec, 0xee, 0xee, 0x4e,
+ 0xba, 0x5c, 0xae, 0xa7, 0x2e, 0x97, 0xeb, 0xa9,
+ 0xcf, 0xe7, 0x2b, 0x78, 0x0c, 0x16, 0x38, 0xc7,
+ 0x57, 0x24, 0x04, 0x4c, 0xf8, 0xfc, 0x6e, 0xcb,
+ 0x96, 0x2d, 0x4c, 0x24, 0x12, 0x8c, 0x46, 0xa3,
+ 0xac, 0xab, 0xab, 0x5b, 0xb0, 0xdb, 0xed, 0x6a,
+ 0x4d, 0x4d, 0xcd, 0x42, 0x57, 0x57, 0xd7, 0xc4,
+ 0x83, 0x07, 0x0f, 0xa6, 0x00, 0xf4, 0x16, 0x23,
+ 0xe8, 0xf7, 0x92, 0x24, 0xa9, 0x7e, 0xbf, 0x5f,
+ 0x53, 0x14, 0x45, 0x57, 0x55, 0x55, 0x57, 0x55,
+ 0x55, 0x57, 0x14, 0xa5, 0x50, 0x21, 0xb4, 0xda,
+ 0x02, 0x54, 0x01, 0x78, 0xd6, 0xd8, 0xd8, 0x18,
+ 0x1b, 0x1c, 0x1c, 0xd4, 0x9e, 0x3c, 0x79, 0xa2,
+ 0x6b, 0x9a, 0xc6, 0xc9, 0xc9, 0x49, 0x7d, 0x60,
+ 0x60, 0x60, 0xb6, 0xad, 0xad, 0x6d, 0xa0, 0x58,
+ 0x01, 0x32, 0xa5, 0xf0, 0xd5, 0x9c, 0x02, 0x64,
+ 0xce, 0x68, 0x6b, 0x32, 0x79, 0x33, 0x34, 0x5b,
+ 0xf7, 0x17, 0x73, 0x3f, 0x28, 0xd4, 0x5e, 0x01,
+ 0xc0, 0x0f, 0x20, 0x9a, 0x73, 0xc3, 0xbc, 0x03,
+ 0xe0, 0x0b, 0x00, 0x2e, 0x08, 0x04, 0x02, 0x81,
+ 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40,
+ 0x20, 0xf8, 0x07, 0x2a, 0xf1, 0x10, 0xf2, 0x07,
+ 0x08, 0xeb, 0x83, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/map_select_1.png.h b/src/images/map_select_1.png.h
new file mode 100644
index 0000000..7b5500a
--- /dev/null
+++ b/src/images/map_select_1.png.h
@@ -0,0 +1,88 @@
+/* map_select_1.png - 674 bytes */
+ static const unsigned char map_select_1_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x62,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xab, 0xa5, 0x06,
+ 0x0e, 0x00, 0x00, 0x00, 0x04, 0x73, 0x42, 0x49,
+ 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
+ 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59,
+ 0x73, 0x00, 0x00, 0x0e, 0x35, 0x00, 0x00, 0x0e,
+ 0x35, 0x01, 0x46, 0x42, 0x14, 0x5b, 0x00, 0x00,
+ 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f,
+ 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77,
+ 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63,
+ 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b,
+ 0xee, 0x3c, 0x1a, 0x00, 0x00, 0x02, 0x1f, 0x49,
+ 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0xdd, 0x31,
+ 0x4e, 0x5b, 0x41, 0x14, 0x46, 0xe1, 0x33, 0x0f,
+ 0x5a, 0xb3, 0x04, 0x56, 0x00, 0x48, 0x09, 0x54,
+ 0xd0, 0x21, 0x6f, 0x84, 0x15, 0xa5, 0x76, 0xc1,
+ 0x72, 0xa0, 0xc2, 0x29, 0x40, 0x50, 0x5b, 0x2c,
+ 0x81, 0x1a, 0x73, 0x53, 0x3c, 0x27, 0x0a, 0x60,
+ 0x44, 0x93, 0x78, 0x7e, 0x99, 0xf3, 0x49, 0xb7,
+ 0xb0, 0x35, 0xc5, 0xd5, 0x1c, 0x3d, 0xc9, 0xaf,
+ 0x72, 0xab, 0x2a, 0xd6, 0x69, 0xad, 0x1d, 0x01,
+ 0x67, 0xc0, 0xf1, 0x6a, 0x0e, 0x80, 0xdd, 0xb5,
+ 0x87, 0xf5, 0x91, 0x67, 0xe0, 0x1e, 0xb8, 0x01,
+ 0xe6, 0xc0, 0x55, 0x55, 0xdd, 0xae, 0x3d, 0x59,
+ 0x55, 0xaf, 0x06, 0x98, 0x00, 0x33, 0xa0, 0x9c,
+ 0xff, 0x32, 0x33, 0x60, 0xf2, 0xee, 0xde, 0xdf,
+ 0x44, 0x98, 0x02, 0x8b, 0x80, 0x65, 0xb7, 0x7d,
+ 0x16, 0xc0, 0x74, 0x6d, 0x08, 0xe0, 0x1c, 0x78,
+ 0x09, 0x58, 0xf2, 0xab, 0xcc, 0x0b, 0x70, 0xfe,
+ 0xfb, 0xfe, 0x5b, 0x55, 0xd1, 0x5a, 0xdb, 0x03,
+ 0xee, 0x80, 0x7d, 0xb4, 0x49, 0x8f, 0xc0, 0x61,
+ 0x55, 0x3d, 0x0d, 0xab, 0x2f, 0x7e, 0x60, 0x84,
+ 0x1e, 0xf6, 0x19, 0xef, 0x9e, 0x06, 0x7c, 0x03,
+ 0x7e, 0x76, 0x5d, 0x47, 0xdf, 0x07, 0xe0, 0xb4,
+ 0xf7, 0x16, 0xe2, 0x74, 0x00, 0x4e, 0x7a, 0x6f,
+ 0x21, 0x4e, 0x06, 0xc6, 0x97, 0x35, 0xf5, 0x75,
+ 0xdc, 0x18, 0xdf, 0xfe, 0x76, 0x7a, 0x6f, 0xf2,
+ 0xc5, 0x2d, 0x1b, 0xe3, 0x6f, 0x5a, 0x75, 0x36,
+ 0x7c, 0x7e, 0x44, 0x9b, 0x60, 0x88, 0x10, 0x86,
+ 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88,
+ 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08,
+ 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10,
+ 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61,
+ 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86,
+ 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88,
+ 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08,
+ 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10,
+ 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61,
+ 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86,
+ 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88,
+ 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08,
+ 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10,
+ 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61,
+ 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86,
+ 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88,
+ 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08,
+ 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10,
+ 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61,
+ 0x88, 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86,
+ 0x08, 0x61, 0x88, 0x10, 0x86, 0x08, 0x61, 0x88,
+ 0x10, 0x86, 0x08, 0x61, 0x88, 0x10, 0x86, 0x08,
+ 0x61, 0x88, 0x10, 0x86, 0x08, 0x31, 0x00, 0xcb,
+ 0xde, 0x4b, 0x88, 0xe5, 0x00, 0x3c, 0xf4, 0xde,
+ 0x42, 0x3c, 0x0c, 0xc0, 0xbc, 0xf7, 0x16, 0x62,
+ 0x3e, 0x00, 0x37, 0xbd, 0xb7, 0x10, 0x37, 0x03,
+ 0x70, 0xdd, 0x7b, 0x0b, 0x71, 0x4d, 0x55, 0x01,
+ 0x5c, 0x32, 0xfe, 0xc1, 0xb8, 0xb3, 0xf9, 0xb9,
+ 0xac, 0x2a, 0x5a, 0x55, 0xd1, 0x5a, 0xdb, 0x03,
+ 0xee, 0x80, 0xfd, 0x4f, 0xca, 0xe9, 0xdf, 0x7a,
+ 0x04, 0x0e, 0xab, 0xea, 0x69, 0x00, 0xa8, 0xaa,
+ 0x27, 0xe0, 0x82, 0xb1, 0x90, 0x36, 0xa3, 0x80,
+ 0x8b, 0xd5, 0xdd, 0x43, 0x55, 0xfd, 0x19, 0x60,
+ 0x0a, 0x2c, 0xe8, 0xff, 0xb8, 0x6e, 0xfb, 0x2c,
+ 0x80, 0xe9, 0xab, 0xbb, 0xff, 0xfb, 0xc3, 0x2a,
+ 0xc6, 0x04, 0x98, 0x05, 0x2c, 0xbb, 0xad, 0x33,
+ 0x03, 0x26, 0x6f, 0xef, 0xbd, 0xad, 0x2e, 0xff,
+ 0x9d, 0xd6, 0xda, 0x11, 0x70, 0x06, 0x1c, 0xaf,
+ 0xe6, 0x00, 0xd8, 0x5d, 0x7b, 0x58, 0x1f, 0x79,
+ 0x06, 0xee, 0x19, 0x5f, 0x11, 0xe6, 0xc0, 0x55,
+ 0x55, 0xdd, 0xae, 0x3b, 0xf8, 0x0b, 0xa1, 0x12,
+ 0xc6, 0xf6, 0x5f, 0xd5, 0x11, 0xe7, 0x00, 0x00,
+ 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+ 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/map_select_2.png.h b/src/images/map_select_2.png.h
new file mode 100644
index 0000000..cd38646
--- /dev/null
+++ b/src/images/map_select_2.png.h
@@ -0,0 +1,113 @@
+/* map_select_2.png - 876 bytes */
+ static const unsigned char map_select_2_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x62,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xab, 0xa5, 0x06,
+ 0x0e, 0x00, 0x00, 0x00, 0x04, 0x73, 0x42, 0x49,
+ 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64,
+ 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59,
+ 0x73, 0x00, 0x00, 0x0e, 0x21, 0x00, 0x00, 0x0e,
+ 0x21, 0x01, 0xf0, 0xab, 0x83, 0x83, 0x00, 0x00,
+ 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f,
+ 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77,
+ 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63,
+ 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b,
+ 0xee, 0x3c, 0x1a, 0x00, 0x00, 0x02, 0xe9, 0x49,
+ 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0xd7, 0xb1,
+ 0x4b, 0x55, 0x71, 0x18, 0xc6, 0xf1, 0xef, 0x7b,
+ 0x13, 0x2a, 0x42, 0xc4, 0x29, 0x70, 0x0a, 0x0a,
+ 0x07, 0x17, 0xe1, 0x7a, 0x11, 0x52, 0x10, 0x5b,
+ 0x6a, 0xed, 0x5f, 0xa8, 0xd6, 0x8b, 0x44, 0xd0,
+ 0x2c, 0x3a, 0x37, 0x84, 0x38, 0xdb, 0xbf, 0xd0,
+ 0x5a, 0x4b, 0xa0, 0x68, 0x20, 0x57, 0xc5, 0xa5,
+ 0x41, 0x0a, 0x9a, 0x84, 0x26, 0x07, 0x8d, 0x1a,
+ 0x8a, 0xb7, 0xe1, 0xfe, 0x6e, 0x98, 0x1a, 0x2d,
+ 0x79, 0xcf, 0xc3, 0x3d, 0xcf, 0x07, 0x0e, 0x67,
+ 0x38, 0x47, 0x79, 0x79, 0xbf, 0xf7, 0x5e, 0xce,
+ 0x89, 0xcc, 0xe4, 0x22, 0x11, 0x31, 0x06, 0xcc,
+ 0x01, 0xad, 0x72, 0x34, 0x81, 0xe1, 0x0b, 0x6f,
+ 0xb6, 0xbf, 0x39, 0x06, 0x76, 0x81, 0x4e, 0x39,
+ 0xd6, 0x33, 0xf3, 0xf0, 0xa2, 0x1b, 0xe3, 0x6c,
+ 0x88, 0x88, 0x08, 0xa0, 0x0d, 0x2c, 0x01, 0xeb,
+ 0xe5, 0x1f, 0xed, 0x94, 0xf3, 0xd1, 0xe5, 0xcd,
+ 0x3c, 0x90, 0x46, 0xe9, 0x7e, 0x80, 0xa7, 0xca,
+ 0x79, 0x0e, 0x58, 0x04, 0x56, 0xf3, 0xcc, 0xe2,
+ 0xff, 0x08, 0x11, 0x11, 0xb7, 0x80, 0x35, 0xe0,
+ 0x06, 0xf0, 0x28, 0x33, 0x3f, 0xf4, 0x67, 0xde,
+ 0x7a, 0x88, 0x88, 0x09, 0xe0, 0x15, 0xf0, 0x15,
+ 0x78, 0x9c, 0x99, 0x9f, 0x7b, 0xd7, 0x1a, 0xa7,
+ 0x6e, 0xba, 0x0d, 0x6c, 0x03, 0x6f, 0x80, 0x19,
+ 0x47, 0xf8, 0xff, 0xca, 0x4e, 0x67, 0x80, 0xb7,
+ 0xc0, 0x76, 0xd9, 0x39, 0x50, 0xbe, 0x11, 0xe5,
+ 0xe7, 0xe8, 0x1d, 0xf0, 0x3a, 0x33, 0x5f, 0x56,
+ 0x34, 0x67, 0xad, 0x44, 0xc4, 0x53, 0xe0, 0x21,
+ 0x70, 0x2f, 0x33, 0xb3, 0xf7, 0x8d, 0x68, 0x03,
+ 0x43, 0xc0, 0x4a, 0x65, 0x93, 0xd5, 0xcf, 0x0a,
+ 0xdd, 0x9d, 0xb7, 0x01, 0x02, 0x18, 0x03, 0xf6,
+ 0x81, 0xd9, 0xcc, 0x3c, 0xa8, 0x70, 0xb0, 0xda,
+ 0x89, 0x88, 0x71, 0x60, 0x13, 0x98, 0x6c, 0x00,
+ 0xf3, 0xc0, 0x86, 0x23, 0xf4, 0x5f, 0xd9, 0xf9,
+ 0x06, 0x30, 0xdf, 0xa0, 0xfb, 0x8e, 0xb0, 0x53,
+ 0xed, 0x48, 0xb5, 0xb6, 0x03, 0xb4, 0x7a, 0x21,
+ 0x76, 0x2b, 0x1e, 0xa6, 0xce, 0x76, 0x81, 0x56,
+ 0xd0, 0x7d, 0xfb, 0xbb, 0x93, 0x99, 0x5f, 0x2a,
+ 0x1e, 0xa8, 0x96, 0x22, 0xe2, 0x26, 0xf0, 0x31,
+ 0x80, 0x04, 0xae, 0x67, 0xe6, 0xf7, 0x8a, 0x67,
+ 0xaa, 0xa5, 0x88, 0xb8, 0x06, 0x7c, 0x6b, 0xfc,
+ 0xf3, 0x4e, 0xeb, 0x0b, 0x87, 0x10, 0xe1, 0x10,
+ 0x22, 0x1c, 0x42, 0x84, 0x43, 0x88, 0x70, 0x08,
+ 0x11, 0x0e, 0x21, 0xc2, 0x21, 0x44, 0x38, 0x84,
+ 0x08, 0x87, 0x10, 0xe1, 0x10, 0x22, 0x1c, 0x42,
+ 0x84, 0x43, 0x88, 0x70, 0x08, 0x11, 0x0e, 0x21,
+ 0xc2, 0x21, 0x44, 0x38, 0x84, 0x08, 0x87, 0x10,
+ 0xe1, 0x10, 0x22, 0x1c, 0x42, 0x84, 0x43, 0x88,
+ 0x70, 0x08, 0x11, 0x0e, 0x21, 0xc2, 0x21, 0x44,
+ 0x38, 0x84, 0x08, 0x87, 0x10, 0xe1, 0x10, 0x22,
+ 0x1c, 0x42, 0x84, 0x43, 0x88, 0x70, 0x08, 0x11,
+ 0x0e, 0x21, 0xc2, 0x21, 0x44, 0x38, 0x84, 0x08,
+ 0x87, 0x10, 0xe1, 0x10, 0x22, 0x1c, 0x42, 0x84,
+ 0x43, 0x88, 0x70, 0x08, 0x11, 0x0e, 0x21, 0xc2,
+ 0x21, 0x44, 0x38, 0x84, 0x08, 0x87, 0x10, 0xe1,
+ 0x10, 0x22, 0x1c, 0x42, 0x84, 0x43, 0x88, 0x70,
+ 0x08, 0x11, 0x0e, 0x21, 0xc2, 0x21, 0x44, 0x38,
+ 0x84, 0x08, 0x87, 0x10, 0xe1, 0x10, 0x22, 0x1c,
+ 0x42, 0x84, 0x43, 0x88, 0x70, 0x08, 0x11, 0x0e,
+ 0x21, 0xc2, 0x21, 0x44, 0x38, 0x84, 0x08, 0x87,
+ 0x10, 0xe1, 0x10, 0x22, 0x1c, 0x42, 0x84, 0x43,
+ 0x88, 0x70, 0x08, 0x11, 0x0e, 0x21, 0xc2, 0x21,
+ 0x44, 0x38, 0x84, 0x08, 0x87, 0x10, 0xe1, 0x10,
+ 0x22, 0x1c, 0x42, 0x84, 0x43, 0x88, 0x70, 0x08,
+ 0x11, 0x0e, 0x21, 0xc2, 0x21, 0x44, 0x38, 0x84,
+ 0x08, 0x87, 0x10, 0xe1, 0x10, 0x22, 0x1a, 0xc0,
+ 0x09, 0x30, 0x52, 0xf5, 0x20, 0x35, 0x36, 0x02,
+ 0x9c, 0x34, 0x80, 0x3d, 0xa0, 0x59, 0xf1, 0x30,
+ 0x75, 0xd6, 0x04, 0xf6, 0x1a, 0x40, 0x07, 0x87,
+ 0xa8, 0x52, 0x13, 0xe8, 0xf4, 0x42, 0x4c, 0x55,
+ 0x3c, 0x4c, 0x9d, 0x4d, 0x01, 0x9d, 0x00, 0xc6,
+ 0x80, 0x7d, 0x60, 0x36, 0x33, 0x0f, 0xaa, 0x9d,
+ 0xa9, 0x5e, 0x22, 0x62, 0x1c, 0xd8, 0x04, 0x26,
+ 0x1b, 0x99, 0x79, 0x08, 0x2c, 0x03, 0x6b, 0x11,
+ 0xe1, 0xa7, 0xa8, 0x3e, 0x29, 0xbb, 0x5e, 0x03,
+ 0x96, 0x33, 0xf3, 0xb0, 0xb7, 0xf8, 0x55, 0xe0,
+ 0x07, 0xb0, 0x50, 0xd9, 0x64, 0xf5, 0xb3, 0x40,
+ 0x77, 0xe7, 0xab, 0x00, 0x43, 0x00, 0x99, 0x99,
+ 0x11, 0xf1, 0x04, 0x78, 0x1f, 0x11, 0x57, 0x81,
+ 0x17, 0x99, 0xf9, 0xb3, 0xba, 0x19, 0x07, 0x57,
+ 0x44, 0x5c, 0x01, 0x9e, 0x03, 0xcf, 0x80, 0xbb,
+ 0x99, 0x99, 0x70, 0xea, 0x85, 0x2e, 0x33, 0x3f,
+ 0x01, 0xd3, 0xc0, 0x03, 0x60, 0x2b, 0x22, 0x26,
+ 0xaa, 0x18, 0x74, 0x90, 0x95, 0x9d, 0x6e, 0x01,
+ 0xf7, 0x81, 0xe9, 0xb2, 0xf3, 0xee, 0xb5, 0x12,
+ 0xe4, 0xf4, 0xcd, 0x01, 0xb4, 0x81, 0x25, 0x60,
+ 0x1d, 0xd8, 0x05, 0x76, 0xca, 0xf9, 0xa8, 0x4f,
+ 0x33, 0x0f, 0x8a, 0x51, 0xba, 0x8f, 0xa7, 0x53,
+ 0xe5, 0x3c, 0x07, 0x2c, 0x02, 0xab, 0x79, 0x66,
+ 0xf1, 0xe7, 0x42, 0xfc, 0xbe, 0x10, 0x31, 0x56,
+ 0xfe, 0xb0, 0x55, 0x8e, 0x26, 0x30, 0x7c, 0x79,
+ 0x33, 0x0f, 0xa4, 0x63, 0xba, 0x1f, 0xe0, 0x4e,
+ 0x39, 0xd6, 0xcb, 0xc3, 0xd1, 0x39, 0xbf, 0x00,
+ 0x08, 0xf8, 0xb2, 0x78, 0x76, 0xa5, 0x72, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+ 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/nexists.xpm b/src/images/nexists.xpm
new file mode 100644
index 0000000..4a2cfce
--- /dev/null
+++ b/src/images/nexists.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static const char * nexists_xpm[] = {
+"16 16 3 1",
+" c None",
+". c #000000",
+"+ c #C8C8C8",
+" ",
+" ",
+" ",
+" ",
+" ",
+" . . ",
+" . . ",
+" +.. + ",
+" .. + ",
+" . +. ",
+" . ++. ",
+" + + ",
+" + + ",
+" ",
+" ",
+" "};
diff --git a/src/images/no1_icon.png.h b/src/images/no1_icon.png.h
new file mode 100644
index 0000000..afd8485
--- /dev/null
+++ b/src/images/no1_icon.png.h
@@ -0,0 +1,56 @@
+/* no1_icon.png - 417 bytes */
+ static const unsigned char no1_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x14, 0x25, 0x1e, 0x7e, 0x2c, 0x54, 0xa6,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x00,
+ 0xfc, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0xa5,
+ 0x53, 0xcb, 0x6e, 0xc2, 0x30, 0x10, 0x9c, 0x75,
+ 0x12, 0xe1, 0x14, 0x24, 0x1f, 0x7a, 0x28, 0x87,
+ 0xfe, 0x41, 0x3f, 0xa0, 0x3f, 0xda, 0xff, 0xe8,
+ 0x7f, 0x70, 0xe7, 0xce, 0x01, 0x09, 0x22, 0x25,
+ 0x52, 0x23, 0x81, 0x10, 0x50, 0x67, 0x7b, 0x70,
+ 0xe2, 0xc4, 0x76, 0x6c, 0x90, 0x3a, 0x17, 0x3f,
+ 0x66, 0x35, 0x3b, 0xbb, 0x5e, 0xd3, 0x6f, 0xf3,
+ 0xfd, 0x85, 0x10, 0x1d, 0x00, 0x81, 0x38, 0x2c,
+ 0x9f, 0x03, 0x00, 0x15, 0x6f, 0xef, 0x61, 0x0c,
+ 0x11, 0xc0, 0x3c, 0xae, 0x21, 0xf8, 0x5e, 0xed,
+ 0x73, 0x7b, 0xca, 0xd4, 0x1a, 0x00, 0x01, 0xe0,
+ 0x6c, 0xf9, 0xf1, 0xe9, 0x07, 0xeb, 0xf3, 0x76,
+ 0x03, 0x80, 0x87, 0x18, 0xe8, 0xf6, 0x68, 0x1d,
+ 0x98, 0x2c, 0x00, 0x65, 0xab, 0xd7, 0x98, 0xe7,
+ 0x29, 0xc7, 0xfa, 0x54, 0x0f, 0xfb, 0xbe, 0xce,
+ 0x89, 0x45, 0x21, 0x55, 0x77, 0xab, 0x9a, 0xee,
+ 0x56, 0xd5, 0x8e, 0x82, 0x90, 0x0a, 0x42, 0x2a,
+ 0xf6, 0xaa, 0x71, 0x1a, 0x65, 0x49, 0x92, 0x2f,
+ 0x20, 0xb9, 0x74, 0x2d, 0x98, 0x33, 0x19, 0xb3,
+ 0xb3, 0x02, 0xe4, 0x90, 0x62, 0xb1, 0x98, 0x6d,
+ 0x5c, 0xc2, 0xc1, 0xc0, 0x50, 0xe2, 0xf9, 0x02,
+ 0x4e, 0xa4, 0xd4, 0x9f, 0x81, 0xc0, 0x3f, 0x11,
+ 0x17, 0xe8, 0xae, 0xd7, 0xd9, 0x1a, 0xbc, 0x26,
+ 0xe6, 0x33, 0x4d, 0x64, 0x51, 0xa8, 0x32, 0xc8,
+ 0x64, 0xee, 0x4a, 0x7d, 0xd9, 0xfd, 0x24, 0x7b,
+ 0xc0, 0xfa, 0xd2, 0xa6, 0x2c, 0x8f, 0x0e, 0xcc,
+ 0x26, 0x77, 0x6d, 0x9f, 0xeb, 0x7e, 0x6c, 0x6b,
+ 0x3b, 0xb2, 0xde, 0xca, 0xfa, 0x84, 0xe9, 0xf0,
+ 0x8d, 0x02, 0xba, 0x3d, 0xc4, 0x72, 0x8e, 0x9f,
+ 0xca, 0x9b, 0xda, 0x41, 0x80, 0xef, 0xd5, 0xfe,
+ 0xd1, 0xb7, 0x8d, 0xe1, 0x0f, 0xa4, 0x08, 0x5b,
+ 0xac, 0xe6, 0x58, 0x78, 0x5e, 0x00, 0x00, 0x00,
+ 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
+ 0x82};
+/* End Of File */
diff --git a/src/images/no2_icon.png.h b/src/images/no2_icon.png.h
new file mode 100644
index 0000000..616bd16
--- /dev/null
+++ b/src/images/no2_icon.png.h
@@ -0,0 +1,57 @@
+/* no2_icon.png - 427 bytes */
+ static const unsigned char no2_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x14, 0x25, 0x2c, 0xb6, 0xfb, 0x05, 0x26,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x01,
+ 0x06, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x8d,
+ 0x53, 0xdd, 0x6a, 0xc2, 0x30, 0x18, 0x3d, 0x5f,
+ 0xcc, 0x4c, 0xa5, 0xa0, 0x17, 0xce, 0x9f, 0x0b,
+ 0x11, 0x61, 0xaf, 0xbc, 0xe7, 0x10, 0x06, 0x7b,
+ 0x85, 0x5d, 0xec, 0x21, 0x04, 0x11, 0x51, 0x53,
+ 0x2b, 0xd8, 0x62, 0xb1, 0xb5, 0xcc, 0xec, 0xa2,
+ 0x4b, 0x9a, 0xd9, 0xc6, 0xf6, 0xdc, 0x84, 0x24,
+ 0x27, 0xe7, 0x3b, 0xe7, 0x4b, 0x42, 0x9f, 0xbb,
+ 0xe5, 0x3b, 0x1e, 0xa0, 0x80, 0x3b, 0x01, 0x0c,
+ 0x0e, 0xd8, 0xfb, 0x1c, 0x00, 0x46, 0x62, 0x32,
+ 0xab, 0xd2, 0x88, 0x00, 0xa5, 0xca, 0xb1, 0x8a,
+ 0x63, 0x26, 0xb7, 0x5c, 0x4f, 0xfa, 0x2f, 0x83,
+ 0xa9, 0x9b, 0x4c, 0xf4, 0x57, 0xdb, 0x08, 0xc6,
+ 0x79, 0x74, 0x30, 0x0e, 0x34, 0xc1, 0xef, 0xf8,
+ 0xc3, 0xb9, 0xbf, 0x78, 0x73, 0x59, 0xdf, 0x24,
+ 0xeb, 0x15, 0x00, 0x24, 0x3f, 0x97, 0x50, 0xaf,
+ 0xb1, 0x52, 0xb9, 0x19, 0x75, 0xe2, 0xbc, 0x8e,
+ 0x18, 0xdd, 0xce, 0x57, 0x00, 0x20, 0x14, 0xce,
+ 0xfb, 0xdd, 0x41, 0xcf, 0x25, 0xca, 0x1f, 0x73,
+ 0x06, 0xa9, 0x0c, 0x09, 0xe4, 0x77, 0x99, 0x10,
+ 0x6d, 0x5c, 0x59, 0x02, 0x26, 0x06, 0xe9, 0x15,
+ 0xd1, 0x11, 0xac, 0x49, 0x80, 0xd5, 0xdf, 0xb3,
+ 0xb2, 0x7c, 0x19, 0x3d, 0x04, 0xa9, 0x3c, 0xb5,
+ 0x12, 0xa8, 0x3b, 0xac, 0xfb, 0xd2, 0x4a, 0x80,
+ 0x40, 0xf0, 0xb8, 0xc7, 0xec, 0xc3, 0x54, 0x26,
+ 0x7b, 0xde, 0x44, 0x00, 0xca, 0xee, 0x7a, 0x90,
+ 0xca, 0x30, 0xbb, 0x67, 0x6d, 0x9a, 0x58, 0x60,
+ 0xec, 0x4d, 0x5e, 0x9f, 0xcd, 0x37, 0xc9, 0x3a,
+ 0xb2, 0x0b, 0xfe, 0x8b, 0x60, 0xbf, 0x30, 0x17,
+ 0x4a, 0x4e, 0x71, 0x6b, 0xc6, 0x41, 0x9c, 0x9f,
+ 0xf7, 0x00, 0xf0, 0x7d, 0xfa, 0xfa, 0x70, 0x7f,
+ 0x2a, 0x20, 0xce, 0x23, 0x55, 0x89, 0x70, 0xcc,
+ 0xe4, 0xb6, 0xe9, 0xdb, 0xba, 0xf0, 0x0b, 0x5b,
+ 0xbd, 0x63, 0x14, 0x40, 0x01, 0xdf, 0xa1, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/not_found_icon.xpm b/src/images/not_found_icon.xpm
new file mode 100644
index 0000000..64a4801
--- /dev/null
+++ b/src/images/not_found_icon.xpm
@@ -0,0 +1,321 @@
+/* XPM */
+static const char * not_found_icon_xpm[] = {
+"64 64 254 2",
+" c None",
+". c #E8DEDE",
+"+ c #E1CACA",
+"@ c #E1C9C9",
+"# c #E4D1D1",
+"$ c #CE9898",
+"% c #CE9595",
+"& c #CE9696",
+"* c #E4D2D2",
+"= c #CF9999",
+"- c #D6A5A5",
+"; c #E4C2C2",
+"> c #E6CACA",
+", c #E6C9C9",
+"' c #E5D3D3",
+") c #CF9A9A",
+"! c #D6A4A4",
+"~ c #ECD6D6",
+"{ c #ECD3D3",
+"] c #EACBCB",
+"^ c #EACACA",
+"/ c #E9CACA",
+"( c #E9C9C9",
+"_ c #EBD2D2",
+": c #ECD5D5",
+"< c #D7A6A6",
+"[ c #EACDCD",
+"} c #E5BABA",
+"| c #E5B9B9",
+"1 c #E5B8B8",
+"2 c #E5B7B7",
+"3 c #EBD5D5",
+"4 c #D8A9A9",
+"5 c #E4B7B7",
+"6 c #E4B6B6",
+"7 c #EACCCC",
+"8 c #EBD3D3",
+"9 c #D8A8A8",
+"0 c #E5D6D6",
+"a c #EAD2D2",
+"b c #E6D7D7",
+"c c #D09B9B",
+"d c #D7A7A7",
+"e c #EBD4D4",
+"f c #E4B5B5",
+"g c #D7A5A5",
+"h c #D09A9A",
+"i c #E5D5D5",
+"j c #CE9999",
+"k c #E4B4B4",
+"l c #D8A7A7",
+"m c #E6D9D9",
+"n c #E7DADA",
+"o c #D09C9C",
+"p c #E4B3B3",
+"q c #EAD1D1",
+"r c #E3B2B2",
+"s c #E9C8C8",
+"t c #E7DBDB",
+"u c #E8DCDC",
+"v c #E7C2C2",
+"w c #E7C1C1",
+"x c #E3B1B1",
+"y c #EAD0D0",
+"z c #E8DDDD",
+"A c #D19E9E",
+"B c #F3EFEF",
+"C c #EDD6D6",
+"D c #E3B3B3",
+"E c #E9C7C7",
+"F c #F3F0F0",
+"G c #F5F5F5",
+"H c #F5F4F4",
+"I c #ECD4D4",
+"J c #E3B0B0",
+"K c #F4F2F2",
+"L c #EDD7D7",
+"M c #E8C6C6",
+"N c #DEC2C2",
+"O c #D39F9F",
+"P c #F4F3F3",
+"Q c #EDD8D8",
+"R c #E2AFAF",
+"S c #E8C7C7",
+"T c #E9CDCD",
+"U c #D39E9E",
+"V c #DCBDBD",
+"W c #F3F1F1",
+"X c #ECD2D2",
+"Y c #D8AAAA",
+"Z c #E2B0B0",
+"` c #E2AEAE",
+" . c #F4F4F4",
+".. c #EDD5D5",
+"+. c #E4B2B2",
+"@. c #E3AEAE",
+"#. c #E3ADAD",
+"$. c #E2ADAD",
+"%. c #ECD1D1",
+"&. c #F1E5E5",
+"*. c #E4AFAF",
+"=. c #E4B1B1",
+"-. c #E3ACAC",
+";. c #E3AFAF",
+">. c #E2ACAC",
+",. c #E4B0B0",
+"'. c #E3ABAB",
+"). c #E4AEAE",
+"!. c #EDD4D4",
+"~. c #ECD0D0",
+"{. c #E4ADAD",
+"]. c #E2AAAA",
+"^. c #E2A9A9",
+"/. c #E2A8A8",
+"(. c #E2A7A7",
+"_. c #E2A6A6",
+":. c #E2A5A5",
+"<. c #E2A4A4",
+"[. c #E1A4A4",
+"}. c #E1A3A3",
+"|. c #EBCBCB",
+"1. c #D8A6A6",
+"2. c #EDD3D3",
+"3. c #DF9E9E",
+"4. c #DF9C9C",
+"5. c #DF9A9A",
+"6. c #DE9898",
+"7. c #DE9696",
+"8. c #DE9595",
+"9. c #DF9898",
+"0. c #EAC5C5",
+"a. c #D7A4A4",
+"b. c #EBCCCC",
+"c. c #DF9999",
+"d. c #DF9595",
+"e. c #EAC7C7",
+"f. c #E09898",
+"g. c #E1A1A1",
+"h. c #EBCDCD",
+"i. c #EBCACA",
+"j. c #E19898",
+"k. c #D8A4A4",
+"l. c #E3AAAA",
+"m. c #E09999",
+"n. c #E09595",
+"o. c #F0E0E0",
+"p. c #ECCDCD",
+"q. c #EBC5C5",
+"r. c #E09F9F",
+"s. c #EAC9C9",
+"t. c #E19C9C",
+"u. c #EBC9C9",
+"v. c #E19A9A",
+"w. c #E19595",
+"x. c #E29898",
+"y. c #E4ACAC",
+"z. c #E09C9C",
+"A. c #E19999",
+"B. c #E09E9E",
+"C. c #DF9696",
+"D. c #EBC7C7",
+"E. c #ECCBCB",
+"F. c #E19696",
+"G. c #E1A2A2",
+"H. c #E7B8B8",
+"I. c #F3EEEE",
+"J. c #EAC6C6",
+"K. c #EBC6C6",
+"L. c #E8B8B8",
+"M. c #E29595",
+"N. c #E4ABAB",
+"O. c #E09B9B",
+"P. c #E29696",
+"Q. c #E49B9B",
+"R. c #ECC6C6",
+"S. c #D8A3A3",
+"T. c #D39D9D",
+"U. c #E6B6B6",
+"V. c #E09696",
+"W. c #E7B7B7",
+"X. c #F4F1F1",
+"Y. c #E8B7B7",
+"Z. c #E39696",
+"`. c #E9B5B5",
+" + c #E9C2C2",
+".+ c #D39A9A",
+"++ c #D6A0A0",
+"@+ c #E6B4B4",
+"#+ c #E8B9B9",
+"$+ c #ECC9C9",
+"%+ c #F4F0F0",
+"&+ c #E9B9B9",
+"*+ c #E39595",
+"=+ c #E9B4B4",
+"-+ c #EBC8C8",
+";+ c #D7A0A0",
+">+ c #D19D9D",
+",+ c #D59E9E",
+"'+ c #EAC8C8",
+")+ c #E7B5B5",
+"!+ c #E09797",
+"~+ c #E39898",
+"{+ c #E9B8B8",
+"]+ c #E49797",
+"^+ c #D69E9E",
+"/+ c #E9C6C6",
+"(+ c #E19797",
+"_+ c #F3EBEB",
+":+ c #E29999",
+"<+ c #E39999",
+"[+ c #ECC8C8",
+"}+ c #E49595",
+"|+ c #D7A1A1",
+"1+ c #E9C5C5",
+"2+ c #E6A9A9",
+"3+ c #E49898",
+"4+ c #E7A9A9",
+"5+ c #E49696",
+"6+ c #EAB5B5",
+"7+ c #D8A1A1",
+"8+ c #E8B5B5",
+"9+ c #D69F9F",
+"0+ c #E59696",
+"a+ c #E29797",
+"b+ c #E59595",
+"c+ c #E59797",
+"d+ c #E39797",
+"e+ c #E69696",
+"f+ c #EBB5B5",
+"g+ c #E69595",
+"h+ c #ECC7C7",
+"i+ c #D8A0A0",
+"j+ c #E79797",
+"k+ c #EAB6B6",
+"l+ c #E59898",
+"m+ c #E79595",
+"n+ c #E79898",
+"o+ c #EBB6B6",
+"p+ c #ECC5C5",
+"q+ c #D79F9F",
+"r+ c #EAC4C4",
+"s+ c #ECB6B6",
+"t+ c #EBC4C4",
+"u+ c #E89595",
+"v+ c #E89696",
+"w+ c #ECB5B5",
+"x+ c #EDC8C8",
+"y+ c #D69D9D",
+"z+ c #ECBEBE",
+"A+ c #EBB1B1",
+"B+ c #EAB1B1",
+"C+ c #EDBEBE",
+"D+ c #EDC7C7",
+"E+ c #E7BCBC",
+" . + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + . ",
+" # $ % & & & & & & & & & & & & & & & & & & & & & & & % $ # ",
+" * = - ; > > > > > > , , , , , , , , , , , , , , , , , ; - = * ",
+" ' ) ! ~ { ] ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ / / / / / / ( ( ( ( ( _ : ! ) ' ",
+" # = < ~ [ } | | | | | | 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 ] 3 - = # ",
+" * $ 4 3 [ | | | | | 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 5 6 6 6 5 7 8 9 $ * ",
+" 0 = 4 8 [ } | 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 5 5 6 6 6 6 6 6 6 6 2 ] a 9 = 0 ",
+" b c d e [ } 1 1 1 1 1 1 1 1 2 2 2 2 2 2 5 5 6 6 6 6 6 6 6 6 6 6 f f f 2 ] 8 g c b ",
+" b h - ~ [ | 1 1 1 1 1 2 2 2 2 2 2 5 6 6 6 6 6 6 6 6 6 6 6 f f f f f f f f 6 ] 3 ! h b ",
+" i j 9 ~ 7 1 1 1 1 2 2 2 2 2 2 5 6 6 6 6 6 6 6 6 6 6 6 f f f f f f f f f f f k f ^ e l j i ",
+" m j 4 8 7 1 2 2 2 2 2 5 5 6 6 6 6 6 6 6 6 6 6 6 f f f f f f f f f f f k k k k k k f / a 9 j m ",
+" n o 9 8 7 | 2 2 5 5 6 6 6 6 6 6 6 6 6 6 6 f f f f f f f f f f k k k k k k k k p p p p f ( q l o n ",
+" n o - : 7 1 6 6 6 6 6 6 6 6 6 6 6 f f f f f f f f f f f k k k k k k k p p p p p p p p p p f ( e ! o n ",
+" n o < ~ ] 1 6 6 6 6 6 6 6 6 f f f f f f f f f f f k k k k k k k p p p p p p p p p p p p p r r p s e - o n ",
+" t = 9 e ] 6 6 6 6 6 6 6 f f f f f f f f f f f k k k k k k k p p p p p p p p p p p p p r r r r r r r s _ 9 = t ",
+" u h 4 _ ] 2 6 6 f f f f f f f f f 6 v 2 k k k k k k k p p p p p p p p p p f w k r r r r r r r r r r x p s y 9 h u ",
+" z A d 8 ] 2 f f f f f f f f f f k f 7 B C 6 k p p p p p p p p p p p p p r f C B ] p r r r r r x x x x x x D E q g A z ",
+" . A - 3 ^ 5 f f f f f f f k k k k k ] F G H : 6 p p p p p p p p p r r r r f I H G F ^ r x x x x x x x J J J J r E 8 ! A . ",
+" o l 3 / f f f f f k k k k k k k k [ K G G G H L f p p p p p r r r r r r k C H G G G K ] x x x x J J J J J J J J J M 8 < o ",
+"N O y ^ f f k k k k k k k p p p f ] K G G G G G P Q f r r r r r r r r r k Q P G G G G G K ^ r J J J J J J J J R R R J S T U N ",
+"V 4 : | k k k k k p p p p p p f 7 W G G G G G G G P Q k r r r r r x x p L P G G G G G G G F ^ x J J J R R R R R R R R p X 9 V ",
+"V Y : 6 k p p p p p p p p p p ] F G G G G G G G G G H I f x x x x x k I H G G G G G G G G G F ( Z R R R R R R R R R ` x X 4 V ",
+"V Y : 6 p p p p p p p p p r p Q H G G G G G G G G G G H : p x J J p : H G G G G G G G G G G H C J R R R R ` ` ` ` ` ` x X 4 V ",
+"V Y : 6 p p p p p p r r r r r f C H G G G G G G G G G G .L p J p L .G G G G G G G G G G H I x R R ` ` ` ` ` ` ` ` ` J X 4 V ",
+"V Y I f p p r r r r r r r r r r f ..H G G G G G G G G G G P Q f Q P G G G G G G G G G G H I +.` ` ` ` ` ` @. at .#.#.$.$.J %.4 V ",
+"V Y I f r r r r r r r r x x x x x p Q P G G G G G G G G G G P &.P G G G G G G G G G G P L J ` @. at .@. at .#.$.$.$.$.$.$.#.*.%.4 V ",
+"V Y I f r r r r x x x x x x x J J J p Q P G G G G G G G G G G G G G G G G G G G G G P L =. at .#.#.$.$.$.#.#.#.#.#.#.-.-.;.%.4 V ",
+"V Y I k r x x x x x x x J J J J J J J +.C H G G G G G G G G G G G G G G G G G G G H ..J #.#.$.$.#.#.#.#.#.#.-.-.-.>.-.*.%.4 V ",
+"V Y { p x x x x J J J J J J J J J J J ;.+.{ H G G G G G G G G G G G G G G G G G H { ,.#.#.#.#.#.#.#.-.-.-.-.-.-.-.'.'.).%.4 V ",
+"V Y { p J J J J J J J J J J J ;.;.;.;.;.;.+...P G G G G G G G G G G G G G G G P !.,.#.#.#.-.-.-.-.-.-.-.'.'.'.'.'.'.'.).~.9 V ",
+"V Y { p J J J J J J ;.;.;.;.;.;.;.;.;.;.;. at .=.L P G G G G G G G G G G G G G P C *.-.-.-.-.-.-.-.'.'.'.'.'.'.'.'.'.'.'.{.~.9 V ",
+"V Y { +.J J ;.;.;.;.;.;.;.;.;.;.;. at .@. at .@. at .@.=.C H G G G G G G G G G G G H C *.-.-.-.-.'.'.].^.^./.(.(._.:.:.<.[.}.}.:.|.1.V ",
+"V 4 { +.;.;.;.;.;.;.;.;.;.;. at .@. at .@. at .@. at .@. at .,.C H G G G G G G G G G G G H 2.[.3.4.5.6.7.8.8.8.8.8.8.8.8.8.8.8.8.8.8.9.0.a.V ",
+"V 4 X +.;.;.;.;.;. at .@. at .@. at .@. at .@. at .#.#.#.#.,.C P G G G G G G G G G G G G G K b.6.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.9.0.a.V ",
+"V 4 X =.;. at .@. at .@. at .@. at .@. at .#.#.#.#.#.#.#.,...P G G G G G G G G G G G G G G G P ^ c.8.8.8.8.8.8.8.8.8.8.8.8.8.d.d.d.d.9.0.a.V ",
+"V 4 X =. at .@. at .@. at .@.#.#.#.#.#.#.#.#.#.-.*.X H G G G G G G G G G G G G G G G G G .e.c.8.8.8.8.8.8.d.d.d.d.d.d.d.d.d.d.f.0.a.V ",
+"V 4 X ,. at .#.#.#.#.#.#.#.#.#.#.#.-.'.[.g.h. .G G G G G G G G G G G G G G G G G G G .i.9.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.j.0.k.V ",
+"V 4 X ,.#.#.#.#.#.#.#.#.#.-.l.[.4.7.c.h.P G G G G G G G G G G G G G G G G G G G G G P h.m.d.d.d.d.d.d.d.d.d.d.n.n.n.n.j.0.k.V ",
+"V 4 X ,.#.#.#.#.#.-.-.-.^.g.c.8.8.9.h.K G G G G G G G G G G P o.P G G G G G G G G G G K p.f.d.d.d.n.n.n.n.n.n.n.n.n.n.j.q.k.V ",
+"V 4 %.*.-.-.-.-.-.'.(.r.9.8.8.8.5.s.H G G G G G G G G G G K b.t.b.K G G G G G G G G G G H u.v.n.n.n.n.n.n.n.w.w.w.w.w.x.q.k.V ",
+"V 4 %.*.-.y.-.'.(.z.7.8.8.8.8.c.s.H G G G G G G G G G G P |.f.d.f.|.P G G G G G G G G G G H u.A.w.w.w.w.w.w.w.w.w.w.w.x.q.k.V ",
+"V 4 %.*.'.'./.B.8.8.8.8.8.8.C.|.H G G G G G G G G G G H e.f.d.d.d.f.D.H G G G G G G G G G G H E.F.w.w.w.w.w.w.w.w.w.w.x.q.k.V ",
+"V 4 %.).l.G.9.8.8.8.8.d.d.d.d.H.I.G G G G G G G G G H J.A.n.n.n.n.n.A.K.H G G G G G G G G G I.L.w.w.w.w.w.w.M.M.M.M.M.x.q.k.V ",
+"V l ~.N.O.d.d.d.d.d.d.d.d.d.d.C.H.B G G G G G G G K E.j.n.n.n.n.w.w.w.j.E.K G G G G G G G B L.P.M.M.M.M.M.M.M.M.M.M.M.Q.R.S.V ",
+"N T.S U.C.d.d.d.d.d.d.d.d.d.d.n.V.W.X.G G G G G K E.j.w.w.w.w.w.w.w.w.w.x.E.K G G G G G X.Y.P.M.M.M.M.M.M.M.M.M.M.M.Z.`. +.+N ",
+" o ++s @+C.d.d.d.n.n.n.n.n.n.n.n.n.#+F G G G H u.x.w.w.w.w.w.w.w.w.w.w.M.x.$+H G G G %+&+M.M.M.M.M.M.M.*+*+*+*+*+Z.=+-+;+o ",
+" . >+,+'+)+!+n.n.n.n.n.n.n.n.n.w.w.w.L.I.G H q.x.w.w.w.w.w.w.w.M.M.M.M.M.M.~+q.H G I.{+M.M.M.M.*+*+*+*+*+*+*+*+]+`.-+^+>+. ",
+" z >+++/+)+(+n.n.w.w.w.w.w.w.w.w.w.F.L._+-+:+w.w.M.M.M.M.M.M.M.M.M.M.M.M.M.<+[+_+{+Z.*+*+*+*+*+*+*+*+*+}+}+]+`.K.;+>+z ",
+" u h |+1+)+(+w.w.w.w.w.w.w.w.w.w.w.P.2+x.M.M.M.M.M.M.M.M.M.M.M.M.M.*+*+*+*+3+4+5+*+*+*+*+}+}+}+}+}+}+}+]+6+0.7+h u ",
+" t = |+e.8+w.w.w.w.w.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.*+*+*+*+*+*+*+*+*+*+*+}+}+}+}+}+}+}+}+}+}+}+}+}+6+D.7+= t ",
+" n o 9+'+8+P.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.*+*+*+*+*+*+*+*+*+*+}+}+}+}+}+}+}+}+}+}+}+}+}+}+}+0+6+[+9+o n ",
+" n o ,+e.8+a+M.M.M.M.M.M.M.M.M.*+*+*+*+*+*+*+*+*+*+}+}+}+}+}+}+}+}+}+}+}+}+}+}+}+}+b+b+b+b+c+6+D.^+o n ",
+" n o |+0.8+d+M.M.*+*+*+*+*+*+*+*+*+*+}+}+}+}+}+}+}+}+}+}+}+}+}+}+}+}+b+b+b+b+b+b+b+b+b+c+6+q.7+o n ",
+" m j 7+0.`.Z.*+*+*+*+*+}+}+}+}+}+}+}+}+}+}+}+}+}+}+}+}+b+b+b+b+b+b+b+b+b+b+b+b+b+b+e+f+q.7+j m ",
+" i j ;+D.`.5+}+}+}+}+}+}+}+}+}+}+}+}+}+}+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+g+g+g+e+f+h+i+j i ",
+" b h ^+-+6+]+}+}+}+}+}+}+}+}+}+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+g+g+g+g+g+g+j+f+[+^+h b ",
+" b h 9+q.k+l+}+}+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+g+g+g+g+g+g+g+g+g+m+m+n+o+p+q+h b ",
+" 0 = 7+r+k+c+b+b+b+b+b+b+b+b+b+b+b+g+g+g+g+g+g+g+g+g+m+m+m+m+m+m+m+j+s+t+7+= 0 ",
+" * $ 7+K.k+b+b+b+b+b+g+g+g+g+g+g+g+g+g+m+m+m+m+m+m+m+m+m+m+m+m+m+s+R.7+$ * ",
+" # = 9+[+f+e+g+g+g+g+g+g+g+g+m+m+m+m+m+m+m+m+m+m+m+m+m+m+u+v+w+x+q+= # ",
+" ' h y+h+z+A+B+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+C+D+y+h ' ",
+" * = ^+f E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+E+f ^+= * ",
+" # $ % % % % % % % % % % % % % % % % % % % % % % % % % $ # ",
+" . + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + . "};
diff --git a/src/images/nready_q.xpm b/src/images/nready_q.xpm
new file mode 100644
index 0000000..31c5c4a
--- /dev/null
+++ b/src/images/nready_q.xpm
@@ -0,0 +1,55 @@
+/* XPM */
+static const char * nready_q_xpm[] = {
+"16 16 36 1",
+" c None",
+". c #595959",
+"+ c #000000",
+"@ c #A60111",
+"# c #FE0018",
+"$ c #FC0018",
+"% c #A4000F",
+"& c #FF1929",
+"* c #FF0F20",
+"= c #FFA197",
+"- c #EC0016",
+"; c #FF2F39",
+"> c #FF333D",
+", c #E00015",
+"' c #D40014",
+") c #A62127",
+"! c #FF2D37",
+"~ c #FFB0A5",
+"{ c #FF0920",
+"] c #EA0016",
+"^ c #E20015",
+"/ c #8A000D",
+"( c #FF1526",
+"_ c #FF9893",
+": c #FFA89F",
+"< c #FF8885",
+"[ c #FF4956",
+"} c #FF031B",
+"| c #FF6367",
+"1 c #C7EFFF",
+"2 c #FF293D",
+"3 c #00B4FF",
+"4 c #018EC9",
+"5 c #FA0018",
+"6 c #E60016",
+"7 c #E40015",
+" ",
+" .++++. ",
+" +@#$$$%+ ",
+" +&*====$-+ ",
+" +;>======,'+ ",
+" .)!=~=={]^^,/. ",
+" +(=_:<[+++++++ ",
+" +}===|+111111+ ",
+" +#==2+113++334+",
+" +$==5+13+33+34+",
+" .%]=6+13333+34+",
+" +67^+133++334+",
+" +^^+13333334+",
+" +/+133++344+",
+" .++444444+ ",
+" ++++++ "};
diff --git a/src/images/nready_unsync.xpm b/src/images/nready_unsync.xpm
new file mode 100644
index 0000000..6a1f0fb
--- /dev/null
+++ b/src/images/nready_unsync.xpm
@@ -0,0 +1,62 @@
+/* XPM */
+static const char * nready_unsync_xpm[] = {
+"16 16 43 1",
+" c None",
+". c #595959",
+"+ c #000000",
+"@ c #A60111",
+"# c #FE0018",
+"$ c #FC0018",
+"% c #A4000F",
+"& c #FF1929",
+"* c #FF0F20",
+"= c #FFA197",
+"- c #EC0016",
+"; c #FF2F39",
+"> c #FF333D",
+", c #E00015",
+"' c #D40014",
+") c #A62127",
+"! c #FF2D37",
+"~ c #FFB0A5",
+"{ c #FF0920",
+"] c #EA0016",
+"^ c #E20015",
+"/ c #8A000D",
+"( c #FF1526",
+"_ c #FF9893",
+": c #FFA89F",
+"< c #FF8885",
+"[ c #FF4956",
+"} c #FF172D",
+"| c #FFE57C",
+"1 c #FF031B",
+"2 c #FF6367",
+"3 c #FF3F4D",
+"4 c #FF1329",
+"5 c #B40011",
+"6 c #FF293D",
+"7 c #FF2B3F",
+"8 c #FF1D32",
+"9 c #FFCC00",
+"0 c #B38F00",
+"a c #FA0018",
+"b c #F20017",
+"c c #E60016",
+"d c #E40015",
+" ",
+" .++++. ",
+" +@#$$$%+ ",
+" +&*====$-+ ",
+" +;>======,'+ ",
+" .)!=~=={]+^,/. ",
+" +(=_:<[}+|+''+ ",
+" +1===234+|+'5+ ",
+" +#==678+|90+5+ ",
+" +$==aab+|+0+5+ ",
+" .%]=cc+|9+90+. ",
+" +cd^^+|9+90+ ",
+" +^^+|999990+ ",
+" +/+|99+990+ ",
+" +|00000000+",
+" +++++++++++"};
diff --git a/src/images/open_full_game.png.h b/src/images/open_full_game.png.h
new file mode 100644
index 0000000..9fb91eb
--- /dev/null
+++ b/src/images/open_full_game.png.h
@@ -0,0 +1,109 @@
+/* open_full_game.png - 842 bytes */
+ static const unsigned char open_full_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1b, 0x15, 0x3b, 0x39, 0x39, 0x7b, 0x44, 0x17,
+ 0x00, 0x00, 0x02, 0xca, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x8d, 0x93, 0xcd, 0x6b, 0x5c, 0x65,
+ 0x14, 0xc6, 0x7f, 0xef, 0x7b, 0xbf, 0x9c, 0xa4,
+ 0x99, 0x7c, 0xcc, 0x34, 0xb1, 0x93, 0xde, 0x86,
+ 0x08, 0xca, 0x58, 0xdb, 0x6a, 0x11, 0x94, 0xb6,
+ 0x54, 0x6d, 0xdd, 0xb9, 0x75, 0xe1, 0x42, 0xfc,
+ 0x13, 0x4a, 0xa1, 0xd0, 0xda, 0x81, 0xfa, 0x81,
+ 0x8b, 0x04, 0x04, 0x0b, 0x22, 0xba, 0x10, 0xff,
+ 0x01, 0x29, 0xae, 0x44, 0xa1, 0x2b, 0x41, 0x82,
+ 0x5f, 0xe8, 0xa2, 0xd9, 0x34, 0x76, 0x6a, 0x40,
+ 0x93, 0x76, 0x92, 0xf1, 0xd6, 0x3b, 0x73, 0x67,
+ 0x72, 0x33, 0x73, 0xef, 0x7d, 0xdf, 0xe3, 0x22,
+ 0x49, 0x41, 0xb1, 0xc5, 0x07, 0x9e, 0xdd, 0x79,
+ 0x7e, 0xe7, 0x1c, 0x38, 0x47, 0xf1, 0x00, 0x35,
+ 0x7f, 0xbb, 0xf5, 0x82, 0x32, 0xe9, 0x3b, 0xa5,
+ 0x34, 0x3a, 0xab, 0x6c, 0x01, 0xa6, 0x40, 0x09,
+ 0x43, 0x46, 0x2b, 0x3f, 0xdb, 0x89, 0x43, 0x97,
+ 0x67, 0x67, 0x67, 0x97, 0x00, 0xdc, 0x7f, 0x07,
+ 0xeb, 0x8d, 0xf0, 0xf9, 0x0f, 0x5e, 0xfd, 0xf8,
+ 0xf3, 0xa0, 0x88, 0xe7, 0xfc, 0xac, 0x8b, 0x92,
+ 0x82, 0x4e, 0x27, 0xa6, 0xc8, 0x32, 0x0e, 0x4e,
+ 0x8c, 0x06, 0xe6, 0xaf, 0xf8, 0x54, 0x11, 0x35,
+ 0xbf, 0x05, 0xf4, 0x3f, 0x00, 0xf5, 0x46, 0xa8,
+ 0x2a, 0x23, 0xd5, 0x85, 0xda, 0xc9, 0xe9, 0x4b,
+ 0xc7, 0x83, 0xb2, 0xf6, 0xb3, 0x84, 0xf5, 0xbb,
+ 0x2d, 0x9a, 0x1b, 0x19, 0x79, 0xf0, 0x28, 0xb9,
+ 0x51, 0xdc, 0xb8, 0xd3, 0xa2, 0xc6, 0x5d, 0x8e,
+ 0x84, 0x15, 0x15, 0x2d, 0x7f, 0xb3, 0x5c, 0x3d,
+ 0x76, 0xe6, 0xd8, 0x7d, 0xc0, 0x64, 0x50, 0x59,
+ 0x98, 0x3b, 0x5b, 0xbb, 0xfc, 0xf6, 0xf4, 0x15,
+ 0x3a, 0x71, 0xca, 0xe3, 0xc7, 0x5f, 0xe2, 0xbb,
+ 0x34, 0xa5, 0xa3, 0x0c, 0x17, 0x5f, 0x7f, 0x1a,
+ 0x11, 0xcb, 0xb9, 0x0f, 0x7f, 0x61, 0xd5, 0x53,
+ 0x9c, 0x3a, 0x33, 0x45, 0xfb, 0xda, 0xbb, 0x47,
+ 0x6f, 0x7c, 0xfa, 0x66, 0xae, 0xf7, 0xc6, 0xae,
+ 0x3c, 0x3b, 0x7e, 0xc9, 0x8e, 0x19, 0xfc, 0x78,
+ 0x93, 0xf9, 0xa3, 0x27, 0x01, 0x18, 0xe6, 0x42,
+ 0x9a, 0x59, 0xc4, 0xee, 0x78, 0x7b, 0x60, 0x18,
+ 0x66, 0x16, 0x80, 0xe0, 0xb9, 0xd7, 0xc8, 0xb7,
+ 0xba, 0xae, 0x0b, 0x50, 0x29, 0x57, 0x2f, 0xea,
+ 0x69, 0xab, 0x93, 0x20, 0xc6, 0x2d, 0x1f, 0xc6,
+ 0x18, 0x83, 0xd6, 0x9a, 0xca, 0x18, 0x34, 0x5b,
+ 0x39, 0xe7, 0x3f, 0xfa, 0x89, 0x61, 0x26, 0x74,
+ 0xd3, 0x82, 0xa7, 0x0e, 0x8d, 0x60, 0xad, 0x45,
+ 0x4f, 0x1d, 0x64, 0xf2, 0xb1, 0x23, 0xe2, 0xd4,
+ 0x1b, 0xa1, 0x33, 0xbe, 0xbf, 0xfc, 0x59, 0x1e,
+ 0x6e, 0xfb, 0xe9, 0x58, 0x9f, 0x09, 0xc6, 0x99,
+ 0x6f, 0x0b, 0x05, 0x2e, 0xb5, 0x6a, 0x40, 0x2b,
+ 0x4a, 0xd9, 0xb8, 0xb7, 0x4d, 0x96, 0x65, 0xbc,
+ 0x71, 0x7a, 0x94, 0xd3, 0x4f, 0x06, 0x64, 0x5b,
+ 0x09, 0xfd, 0x6b, 0x57, 0x68, 0x0d, 0xdc, 0x1f,
+ 0x54, 0xbd, 0x11, 0xd6, 0x66, 0xe6, 0x66, 0xee,
+ 0x98, 0x67, 0x52, 0x06, 0x33, 0x3d, 0xb4, 0xaf,
+ 0xf9, 0xe2, 0xe6, 0x5b, 0x94, 0x5c, 0x45, 0x6f,
+ 0x6a, 0x9a, 0xb4, 0x7a, 0x00, 0x71, 0x3d, 0x04,
+ 0x41, 0x44, 0xf0, 0xa2, 0x4d, 0x26, 0x56, 0x7f,
+ 0xe5, 0xfb, 0xe6, 0x2d, 0x16, 0xda, 0x5f, 0xef,
+ 0x73, 0x01, 0xe9, 0xb7, 0xfb, 0x38, 0x6d, 0x8b,
+ 0xd9, 0x27, 0x18, 0xc9, 0xb9, 0x3e, 0x7e, 0x8f,
+ 0x27, 0x56, 0x4b, 0xcc, 0xb6, 0x97, 0xa9, 0x4e,
+ 0x6e, 0x60, 0xbd, 0x11, 0x44, 0xc0, 0x24, 0x7f,
+ 0xc2, 0xe6, 0x6d, 0x9a, 0x51, 0x8f, 0x85, 0xfc,
+ 0x47, 0xfa, 0xaa, 0xb0, 0xaa, 0xde, 0x08, 0xb5,
+ 0xf2, 0x54, 0xec, 0x4d, 0x3a, 0xe5, 0x62, 0x7e,
+ 0x1b, 0xf6, 0x1b, 0xf4, 0x23, 0x1a, 0xe5, 0x83,
+ 0x52, 0x0a, 0x00, 0x11, 0x41, 0x32, 0xb0, 0x03,
+ 0x0b, 0x9b, 0x0e, 0xee, 0xef, 0x25, 0xf2, 0xd8,
+ 0xac, 0xdf, 0x7c, 0xef, 0x8f, 0x50, 0xaf, 0x2c,
+ 0xae, 0x59, 0xc9, 0xe5, 0x2b, 0x9b, 0x0b, 0xaa,
+ 0xe7, 0x60, 0x3b, 0x60, 0x12, 0x4b, 0xd1, 0xb1,
+ 0x14, 0x5d, 0xb3, 0xe3, 0x8e, 0xc5, 0x24, 0x16,
+ 0xdb, 0x01, 0x9d, 0xb8, 0xd8, 0xa1, 0x20, 0xb9,
+ 0x7c, 0xc9, 0xde, 0x35, 0x01, 0xef, 0x9b, 0xd4,
+ 0x1a, 0x27, 0xf2, 0xd1, 0x89, 0x8b, 0xa4, 0xec,
+ 0x76, 0xdc, 0xb1, 0x64, 0x20, 0x29, 0xe8, 0xae,
+ 0x87, 0x8e, 0x3d, 0xcc, 0xc0, 0x0e, 0x81, 0xab,
+ 0x00, 0x0e, 0x40, 0xb4, 0x94, 0x6c, 0x54, 0x4f,
+ 0x94, 0x73, 0x0c, 0x2f, 0xbb, 0xb9, 0x07, 0x02,
+ 0xca, 0x80, 0x58, 0x20, 0x57, 0xa8, 0x9e, 0x83,
+ 0xdb, 0xf5, 0x71, 0x22, 0x9f, 0xa2, 0x6b, 0x90,
+ 0xa1, 0x9c, 0x5f, 0x59, 0x5c, 0xbb, 0x7e, 0x1f,
+ 0xb0, 0x0b, 0x59, 0xaa, 0x9c, 0x28, 0x0f, 0x6c,
+ 0x21, 0x2f, 0xea, 0x81, 0xeb, 0x38, 0x5b, 0x1e,
+ 0x4e, 0xea, 0xe1, 0x24, 0x1e, 0x4e, 0xec, 0x21,
+ 0x5d, 0x4d, 0xb1, 0x65, 0x87, 0xbb, 0xe1, 0x4f,
+ 0xf6, 0x72, 0xea, 0x3f, 0x9e, 0xe9, 0x30, 0x70,
+ 0x41, 0x79, 0xea, 0x15, 0x34, 0x07, 0x00, 0xb0,
+ 0xac, 0xef, 0xee, 0x7c, 0x75, 0x65, 0x71, 0xed,
+ 0x36, 0xff, 0x57, 0xf5, 0x46, 0x38, 0x52, 0x6f,
+ 0x84, 0xa5, 0x87, 0xd5, 0xfc, 0x0d, 0xf2, 0x83,
+ 0x6a, 0xde, 0xf4, 0x0d, 0x38, 0xb9, 0x00, 0x00,
+ 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
+ 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/open_full_pw_game.png.h b/src/images/open_full_pw_game.png.h
new file mode 100644
index 0000000..0791ffa
--- /dev/null
+++ b/src/images/open_full_pw_game.png.h
@@ -0,0 +1,114 @@
+/* open_full_pw_game.png - 883 bytes */
+ static const unsigned char open_full_pw_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1b, 0x11, 0x29, 0x01, 0x6e, 0x84, 0x24, 0x86,
+ 0x00, 0x00, 0x02, 0xf3, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x75, 0x93, 0x4b, 0x68, 0x5c, 0x65,
+ 0x18, 0x86, 0x9f, 0xff, 0x9f, 0x73, 0xe6, 0x74,
+ 0x66, 0x32, 0x93, 0x99, 0xcc, 0x74, 0xd2, 0x4e,
+ 0x32, 0x0d, 0x11, 0x85, 0x68, 0xd3, 0xd4, 0x2a,
+ 0x55, 0x68, 0xa9, 0xb4, 0x85, 0x52, 0xf7, 0x2e,
+ 0x5c, 0x88, 0x6b, 0x57, 0x52, 0x10, 0x5a, 0x1b,
+ 0x88, 0x17, 0x14, 0xe3, 0xaa, 0x05, 0x11, 0x5d,
+ 0x88, 0x2b, 0xc1, 0x85, 0x14, 0x45, 0x14, 0xdc,
+ 0x88, 0x08, 0x2a, 0xf5, 0xda, 0x45, 0xd2, 0x45,
+ 0x9b, 0x4c, 0x4d, 0xb1, 0x26, 0x73, 0x73, 0x9a,
+ 0x33, 0x97, 0xe4, 0xcc, 0x9c, 0xcb, 0xff, 0xff,
+ 0x2e, 0xd2, 0x8c, 0x54, 0xe8, 0x07, 0xdf, 0xf2,
+ 0x7d, 0xbe, 0xf7, 0x83, 0xf7, 0x15, 0x3c, 0x60,
+ 0x2a, 0x7f, 0xae, 0x3e, 0x23, 0x94, 0xf7, 0x46,
+ 0xc2, 0x6b, 0x9d, 0x16, 0x3a, 0x02, 0x15, 0x21,
+ 0x0c, 0x3e, 0xa9, 0xfc, 0x1f, 0x3a, 0x7b, 0xe0,
+ 0xe2, 0xc4, 0xc4, 0xc4, 0x4f, 0x00, 0xd6, 0xff,
+ 0x85, 0x33, 0xf3, 0xe5, 0xa7, 0x2f, 0x3d, 0xf7,
+ 0xc1, 0x67, 0x4e, 0xe4, 0x4e, 0xc5, 0x83, 0x0e,
+ 0xc2, 0x44, 0xb4, 0xdb, 0x2e, 0x51, 0x10, 0x30,
+ 0x99, 0x4d, 0x39, 0x6a, 0xd3, 0x3d, 0x1e, 0xb5,
+ 0x2a, 0x3f, 0x00, 0xf2, 0x3e, 0xc0, 0xcc, 0x7c,
+ 0x59, 0xe4, 0x93, 0x85, 0xc5, 0xd2, 0xb1, 0xe2,
+ 0x85, 0x23, 0x4e, 0x46, 0xc6, 0x83, 0x2e, 0xeb,
+ 0xd5, 0x1a, 0x95, 0x7a, 0x40, 0xe8, 0xec, 0x23,
+ 0x54, 0x82, 0xa5, 0x8d, 0x1a, 0x25, 0xaa, 0xcc,
+ 0x96, 0xf3, 0xa2, 0xb5, 0xfc, 0xfd, 0x72, 0x61,
+ 0xee, 0xd4, 0xdc, 0x10, 0x90, 0x73, 0xf2, 0x8b,
+ 0x53, 0xa7, 0x4b, 0x17, 0x5f, 0x2f, 0x2e, 0xd0,
+ 0x76, 0x3d, 0x1e, 0x39, 0x72, 0x92, 0xab, 0x9e,
+ 0x47, 0x5b, 0x28, 0xce, 0xbf, 0x70, 0x18, 0x63,
+ 0x34, 0x2f, 0xbf, 0x77, 0x8d, 0x35, 0x5b, 0x70,
+ 0xfc, 0xd4, 0x18, 0xcd, 0x2b, 0x6f, 0x1e, 0x5a,
+ 0xfa, 0xe8, 0xd5, 0x50, 0xee, 0xda, 0xce, 0x3f,
+ 0x39, 0x7a, 0x41, 0xa7, 0x15, 0x71, 0xb7, 0xc1,
+ 0xf4, 0xa1, 0x63, 0x00, 0xf8, 0xa1, 0xc1, 0x0b,
+ 0x34, 0x46, 0xef, 0x6c, 0x7f, 0xa0, 0xf0, 0x03,
+ 0x0d, 0x80, 0xf3, 0xd4, 0xf3, 0x84, 0xdb, 0x1d,
+ 0xcb, 0x02, 0xc8, 0x67, 0x0a, 0xe7, 0x65, 0x51,
+ 0xcb, 0xae, 0xe3, 0x62, 0x65, 0x1e, 0x43, 0x29,
+ 0x85, 0x94, 0x92, 0x7c, 0x1a, 0x2a, 0xb5, 0x90,
+ 0x73, 0xef, 0xff, 0x86, 0x1f, 0x18, 0x3a, 0x5e,
+ 0xc4, 0xc1, 0x03, 0x49, 0xb4, 0xd6, 0xc8, 0xb1,
+ 0x49, 0x72, 0x0f, 0xcd, 0x9a, 0xd8, 0xcc, 0x7c,
+ 0x39, 0x36, 0xba, 0x37, 0xf3, 0x71, 0x58, 0xee,
+ 0xc7, 0xbd, 0xf4, 0x16, 0x59, 0x46, 0x99, 0x6e,
+ 0x1a, 0x22, 0x2c, 0x4a, 0x05, 0x87, 0x5a, 0xcb,
+ 0xa3, 0x7e, 0xb7, 0x4f, 0x10, 0x04, 0xbc, 0x78,
+ 0x22, 0xc5, 0x89, 0x47, 0x1d, 0x82, 0xed, 0x2e,
+ 0x5b, 0x57, 0x16, 0xa8, 0x0d, 0xac, 0x5f, 0xc4,
+ 0xcc, 0x7c, 0xb9, 0x34, 0x3e, 0x35, 0xbe, 0xa1,
+ 0x1e, 0xf7, 0x18, 0x8c, 0xf7, 0x90, 0x71, 0xc9,
+ 0xe7, 0x37, 0x5e, 0x23, 0x61, 0x09, 0x7a, 0x63,
+ 0x45, 0xbc, 0xc2, 0x7e, 0x8c, 0x65, 0x63, 0x30,
+ 0x18, 0x63, 0xb0, 0x5b, 0x0d, 0xb2, 0x6b, 0x2b,
+ 0xfc, 0x5c, 0x59, 0x65, 0xb1, 0xf9, 0xcd, 0x88,
+ 0xf5, 0xd2, 0x9e, 0xde, 0xe4, 0xed, 0x4d, 0xc9,
+ 0xbe, 0x55, 0x41, 0xb6, 0x26, 0xc8, 0x85, 0x82,
+ 0x3b, 0x69, 0x17, 0xd3, 0x72, 0xd8, 0xdf, 0x5c,
+ 0xa6, 0x90, 0xab, 0xa3, 0xed, 0x24, 0xc6, 0x80,
+ 0xea, 0xfe, 0x03, 0x8d, 0x5b, 0x54, 0x5a, 0x3d,
+ 0x16, 0xc3, 0x5f, 0xd9, 0x12, 0x91, 0x16, 0xfe,
+ 0x97, 0x47, 0x83, 0xbe, 0xb6, 0xec, 0x4f, 0xbe,
+ 0x6d, 0x72, 0xf6, 0x68, 0x8e, 0xb1, 0x11, 0x9b,
+ 0x50, 0x69, 0x7a, 0x9e, 0x62, 0xa5, 0xde, 0xe6,
+ 0xed, 0xb3, 0x5d, 0x06, 0x8e, 0xc0, 0x04, 0xa0,
+ 0x07, 0x1a, 0x1a, 0x31, 0xac, 0xbf, 0x12, 0x84,
+ 0xae, 0x5a, 0xbf, 0xf1, 0xd6, 0x9d, 0xb2, 0x8c,
+ 0x27, 0x12, 0xf6, 0xca, 0x7a, 0x9f, 0xcb, 0x5f,
+ 0x6c, 0xf0, 0xe9, 0x77, 0xcd, 0x61, 0xa0, 0x84,
+ 0x00, 0x63, 0x20, 0xea, 0x2a, 0xa2, 0xb6, 0x46,
+ 0x75, 0x35, 0xba, 0x0d, 0xb2, 0x6b, 0xa1, 0x7d,
+ 0x83, 0x09, 0xcd, 0xd7, 0xc3, 0x20, 0x95, 0xf7,
+ 0x3a, 0xe4, 0xd2, 0x16, 0x27, 0x0f, 0x67, 0xef,
+ 0x4b, 0xa5, 0x10, 0xa0, 0xfd, 0x1d, 0x10, 0x03,
+ 0x90, 0x1d, 0x1b, 0xe9, 0xda, 0x84, 0x03, 0xe5,
+ 0x03, 0x97, 0x87, 0x80, 0x42, 0xc6, 0xe6, 0xe0,
+ 0x54, 0x92, 0x27, 0x1e, 0x1e, 0x21, 0x8c, 0xcc,
+ 0x3d, 0xb1, 0x40, 0x00, 0x6c, 0x0b, 0x44, 0x2f,
+ 0x46, 0xcc, 0xb3, 0x90, 0xae, 0x4d, 0xd4, 0x51,
+ 0x18, 0xdf, 0xbc, 0x72, 0xf3, 0xdd, 0xbf, 0x6f,
+ 0x0d, 0x01, 0x9e, 0xaf, 0xa9, 0x6c, 0xf4, 0xa9,
+ 0xdd, 0x0d, 0x28, 0x8c, 0xda, 0x3b, 0x00, 0x00,
+ 0x03, 0xf1, 0x6a, 0x02, 0xa3, 0x76, 0x6c, 0x87,
+ 0x03, 0xe5, 0xdf, 0x13, 0x7f, 0xb8, 0xeb, 0xd2,
+ 0x52, 0x51, 0xa8, 0x95, 0x46, 0xce, 0x4d, 0xa7,
+ 0xa8, 0x6e, 0xfa, 0xff, 0x01, 0x04, 0xa0, 0x0d,
+ 0xfd, 0xb5, 0x88, 0x20, 0x6e, 0xaa, 0x02, 0xbe,
+ 0x12, 0x31, 0x71, 0x69, 0xf7, 0xf2, 0xf0, 0xcd,
+ 0xab, 0x0b, 0xa9, 0x67, 0x93, 0xe9, 0xcc, 0x19,
+ 0x67, 0x8f, 0x33, 0x6b, 0xa4, 0x55, 0xd4, 0x46,
+ 0xa4, 0x0d, 0xa4, 0xbd, 0xbe, 0x72, 0x6f, 0x37,
+ 0xb6, 0x97, 0xde, 0xf9, 0xbd, 0x7b, 0xee, 0xfa,
+ 0x8f, 0xfd, 0xfa, 0x83, 0x6a, 0xff, 0x2f, 0xbe,
+ 0x25, 0x70, 0x25, 0x0c, 0xa8, 0x3e, 0xac, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/open_game.png.h b/src/images/open_game.png.h
new file mode 100644
index 0000000..1aa1214
--- /dev/null
+++ b/src/images/open_game.png.h
@@ -0,0 +1,94 @@
+/* open_game.png - 721 bytes */
+ static const unsigned char open_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x14, 0x10, 0x18, 0x2c, 0xb4, 0xa7, 0x05, 0x20,
+ 0x00, 0x00, 0x02, 0x51, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x8d, 0x93, 0xbf, 0x6b, 0x53, 0x51,
+ 0x1c, 0xc5, 0x3f, 0xf7, 0xc7, 0x7b, 0xa9, 0x69,
+ 0x1a, 0x84, 0xb6, 0x29, 0xad, 0x46, 0x44, 0x10,
+ 0x82, 0xff, 0x40, 0xd1, 0xa5, 0x83, 0x82, 0xe0,
+ 0x3f, 0x23, 0x08, 0x15, 0x33, 0x74, 0x35, 0xd0,
+ 0xc1, 0xd1, 0xd1, 0xff, 0xc0, 0x49, 0x1c, 0x9c,
+ 0x5c, 0xa2, 0x9b, 0xe0, 0x98, 0x41, 0x07, 0x49,
+ 0x45, 0x9b, 0x06, 0x9a, 0xbc, 0x24, 0x2f, 0x2f,
+ 0xef, 0xfe, 0xf8, 0x3a, 0x34, 0x2d, 0x0a, 0x55,
+ 0x3c, 0x97, 0x03, 0x77, 0xf8, 0x9e, 0x73, 0x39,
+ 0xf7, 0x9e, 0xab, 0xf8, 0x0b, 0x5a, 0xed, 0xa6,
+ 0x01, 0xb6, 0x00, 0x01, 0x8e, 0x7b, 0x9d, 0x7e,
+ 0xbc, 0x6c, 0x4e, 0x5d, 0x22, 0xdc, 0xdd, 0xd9,
+ 0xd9, 0xd9, 0xaf, 0xdd, 0xa8, 0x3e, 0xac, 0xd5,
+ 0x6a, 0x35, 0x80, 0xc9, 0x6c, 0x92, 0xe5, 0x47,
+ 0xc5, 0xdb, 0xef, 0xfd, 0xef, 0x87, 0xbd, 0x4e,
+ 0xff, 0xf3, 0xa5, 0x06, 0xad, 0x76, 0x53, 0xad,
+ 0x57, 0x37, 0x9e, 0xef, 0xdc, 0x6b, 0x3c, 0xdd,
+ 0x6e, 0x34, 0xb4, 0x4f, 0x23, 0xca, 0x04, 0x00,
+ 0xa2, 0x33, 0x24, 0x5e, 0xf3, 0x63, 0x30, 0x08,
+ 0x3f, 0x3e, 0x0e, 0x0f, 0xba, 0x07, 0x9f, 0x3a,
+ 0xe7, 0x3a, 0x73, 0xbe, 0xb9, 0xfd, 0xe0, 0x56,
+ 0xe7, 0xe6, 0x83, 0x6b, 0xcf, 0xae, 0x6c, 0x56,
+ 0xd4, 0x6c, 0x6d, 0x46, 0x99, 0x16, 0xe4, 0x2b,
+ 0x39, 0x45, 0x5a, 0xe0, 0x6d, 0x49, 0x61, 0xe7,
+ 0x54, 0x2a, 0x2b, 0x7a, 0x6d, 0x6b, 0xf5, 0x7e,
+ 0xfd, 0xd6, 0x6a, 0xd1, 0x7f, 0xff, 0xf3, 0xc3,
+ 0x85, 0x41, 0xab, 0xdd, 0xdc, 0xbd, 0xbe, 0xbb,
+ 0xfd, 0x2a, 0x69, 0x18, 0x95, 0xaf, 0x4d, 0xf0,
+ 0x69, 0x89, 0xd3, 0x67, 0xf4, 0xca, 0xe1, 0x95,
+ 0xc3, 0xd9, 0x92, 0x85, 0x99, 0xa3, 0xd1, 0xd8,
+ 0x15, 0xbb, 0xa7, 0x6f, 0x86, 0xd7, 0xc3, 0x6e,
+ 0x76, 0xa2, 0x01, 0xd6, 0xeb, 0x1b, 0xfb, 0xba,
+ 0x11, 0x75, 0x56, 0x39, 0x65, 0x5a, 0x19, 0x53,
+ 0xc8, 0x9c, 0x42, 0xe6, 0xf8, 0xe0, 0xf0, 0xc1,
+ 0x51, 0xc8, 0x9c, 0xb9, 0x9a, 0x31, 0xad, 0x8c,
+ 0x19, 0x55, 0x87, 0xe8, 0x46, 0x4c, 0x36, 0xaf,
+ 0x36, 0x9e, 0x00, 0xd8, 0x56, 0xbb, 0x69, 0x92,
+ 0xba, 0x7d, 0x38, 0x35, 0x13, 0xca, 0x74, 0x8e,
+ 0x16, 0x70, 0xca, 0xa1, 0xd4, 0x9f, 0xf7, 0x2b,
+ 0x22, 0x04, 0x3c, 0xd1, 0x80, 0x33, 0x01, 0xbb,
+ 0x96, 0x3c, 0x02, 0xb0, 0xc0, 0x96, 0x18, 0xa9,
+ 0x95, 0xbe, 0xa4, 0x20, 0x47, 0x47, 0xcd, 0xf9,
+ 0xfa, 0x1d, 0x91, 0xb8, 0x34, 0x09, 0x28, 0x67,
+ 0x30, 0xda, 0x6c, 0xb7, 0xda, 0xcd, 0xaa, 0x05,
+ 0x64, 0x3a, 0x98, 0x62, 0x06, 0x91, 0x50, 0x13,
+ 0x82, 0x38, 0x94, 0xbd, 0xbc, 0x1b, 0xe2, 0x81,
+ 0x5c, 0xe3, 0x4e, 0x02, 0xf9, 0x60, 0x0a, 0x20,
+ 0x16, 0x38, 0xce, 0x7d, 0x9e, 0x25, 0x5f, 0x4d,
+ 0xdd, 0x47, 0x0f, 0x9b, 0x01, 0xbd, 0xa2, 0x51,
+ 0x29, 0x17, 0x31, 0x44, 0x04, 0x29, 0x21, 0x16,
+ 0x11, 0x8e, 0x0d, 0xe1, 0x5b, 0x89, 0xf3, 0xe1,
+ 0xa8, 0xd7, 0xe9, 0xcf, 0x75, 0xaf, 0xd3, 0x8f,
+ 0xe2, 0xe4, 0x6d, 0x74, 0x82, 0x9a, 0x18, 0xe2,
+ 0x08, 0x42, 0x16, 0xf1, 0xa3, 0x88, 0x1f, 0x87,
+ 0x33, 0x8e, 0x22, 0x21, 0x8b, 0xc4, 0x11, 0xe8,
+ 0xcc, 0x12, 0x17, 0x82, 0x38, 0x79, 0x03, 0x5c,
+ 0x04, 0x3d, 0x0c, 0x79, 0x0c, 0x66, 0x98, 0xa2,
+ 0x33, 0x8b, 0xe4, 0x2c, 0x4f, 0x3c, 0xa3, 0x94,
+ 0x20, 0x39, 0xe8, 0x71, 0x82, 0x3e, 0x4d, 0x08,
+ 0x45, 0x5c, 0x00, 0x2f, 0x2e, 0x7a, 0x30, 0xec,
+ 0x66, 0x3f, 0x37, 0xee, 0xd6, 0x1d, 0x81, 0xfb,
+ 0xd6, 0x25, 0x20, 0xa0, 0x02, 0x48, 0x04, 0x9c,
+ 0x42, 0x4d, 0x0c, 0x76, 0x9c, 0x62, 0x86, 0x29,
+ 0x7e, 0x1c, 0x90, 0x85, 0x3c, 0xee, 0x75, 0xfa,
+ 0xef, 0xfe, 0x68, 0xe2, 0xb0, 0x9b, 0x75, 0xd7,
+ 0xef, 0xd6, 0x8b, 0xe8, 0x65, 0x4f, 0x17, 0xd6,
+ 0x98, 0x59, 0x82, 0xc9, 0x13, 0x4c, 0x96, 0x60,
+ 0x4e, 0x13, 0x64, 0xac, 0xf1, 0xb3, 0xb8, 0x58,
+ 0x8a, 0x5f, 0xfe, 0xeb, 0x33, 0xdd, 0x01, 0x9e,
+ 0xa8, 0x44, 0x3d, 0x42, 0xb3, 0xbd, 0x7c, 0xc3,
+ 0xa3, 0x65, 0xe6, 0x17, 0xbd, 0x4e, 0xff, 0x0b,
+ 0xff, 0x8b, 0x56, 0xbb, 0x59, 0x6d, 0xb5, 0x9b,
+ 0x57, 0xfe, 0x35, 0xf3, 0x0b, 0xf4, 0x62, 0x3e,
+ 0xf6, 0x24, 0xe2, 0x18, 0x9b, 0x00, 0x00, 0x00,
+ 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
+ 0x82};
+/* End Of File */
diff --git a/src/images/open_pw_game.png.h b/src/images/open_pw_game.png.h
new file mode 100644
index 0000000..5110e70
--- /dev/null
+++ b/src/images/open_pw_game.png.h
@@ -0,0 +1,104 @@
+/* open_pw_game.png - 800 bytes */
+ static const unsigned char open_pw_game_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1b, 0x11, 0x28, 0x26, 0xd2, 0x95, 0xa0, 0xac,
+ 0x00, 0x00, 0x02, 0xa0, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0xcb, 0x75, 0x93, 0xcd, 0x6b, 0x5c, 0x55,
+ 0x18, 0xc6, 0x7f, 0xe7, 0xe3, 0xce, 0x9d, 0x4c,
+ 0x66, 0xc6, 0xc4, 0x4e, 0x26, 0x26, 0x76, 0xb4,
+ 0x16, 0x0b, 0x03, 0x15, 0x0b, 0x82, 0x04, 0xdc,
+ 0x28, 0xb4, 0xd2, 0xe2, 0x3f, 0x22, 0xb8, 0x11,
+ 0x0a, 0x15, 0x07, 0xec, 0x52, 0x07, 0x04, 0xbb,
+ 0x74, 0xe9, 0x42, 0x70, 0x23, 0xd8, 0x45, 0x8b,
+ 0x2b, 0x11, 0x17, 0xc6, 0x6e, 0x44, 0x50, 0xdc,
+ 0x44, 0x2d, 0x16, 0x99, 0x7c, 0x34, 0xd3, 0xd8,
+ 0x49, 0x66, 0x32, 0xf7, 0xdc, 0xb9, 0xe7, 0xcb,
+ 0xc5, 0x64, 0x12, 0x0b, 0xe9, 0x7b, 0x38, 0x70,
+ 0x16, 0xe7, 0xf9, 0xbd, 0xcf, 0x79, 0x79, 0x8e,
+ 0xe0, 0x29, 0xd5, 0xee, 0xb4, 0x14, 0xb0, 0x0c,
+ 0x44, 0x60, 0x77, 0xa3, 0xdb, 0x0b, 0xa7, 0xdd,
+ 0x13, 0xa7, 0x08, 0xd7, 0x56, 0x57, 0x57, 0x6f,
+ 0x54, 0x5f, 0xa8, 0x5c, 0xad, 0x56, 0xab, 0x55,
+ 0x80, 0xd1, 0x78, 0x34, 0xcc, 0x36, 0xf3, 0x6f,
+ 0xb7, 0x7a, 0x5b, 0x9f, 0x6e, 0x74, 0x7b, 0xbf,
+ 0x9e, 0x0a, 0x68, 0x77, 0x5a, 0xe2, 0x4c, 0xa5,
+ 0xf1, 0xc9, 0xea, 0x1b, 0xcd, 0x0f, 0x56, 0x9a,
+ 0x4d, 0xe9, 0x4a, 0x01, 0xa1, 0x3c, 0x00, 0xc1,
+ 0x2a, 0x12, 0x27, 0xd9, 0xe9, 0xf7, 0xfd, 0xce,
+ 0xbd, 0xbd, 0x9b, 0xeb, 0x37, 0x7f, 0xe9, 0xce,
+ 0x74, 0x6a, 0x76, 0xb8, 0x70, 0xe5, 0x7c, 0xf7,
+ 0xdc, 0x95, 0xe7, 0x3f, 0x9c, 0x5b, 0x4a, 0xc5,
+ 0xb8, 0x36, 0xa6, 0x28, 0xe5, 0x64, 0xe5, 0x8c,
+ 0xbc, 0x94, 0xe3, 0x74, 0x41, 0xae, 0x0d, 0x69,
+ 0x5a, 0x96, 0xb5, 0xe5, 0xf9, 0xcb, 0xf5, 0xf3,
+ 0xf3, 0x79, 0xef, 0x87, 0x87, 0x3f, 0x1d, 0x03,
+ 0xda, 0x9d, 0xd6, 0xda, 0xd9, 0xb5, 0x95, 0x2f,
+ 0x92, 0xa6, 0x12, 0x59, 0x6d, 0x84, 0x2b, 0x15,
+ 0x58, 0x39, 0xdd, 0x4e, 0x58, 0x9c, 0xb0, 0x58,
+ 0x5d, 0x30, 0x51, 0x06, 0x89, 0x44, 0x97, 0xf5,
+ 0x9b, 0xf2, 0x9c, 0xff, 0x66, 0x6f, 0x7d, 0xf8,
+ 0x48, 0x02, 0x9c, 0xa9, 0x37, 0x6e, 0xc8, 0x66,
+ 0x90, 0xc3, 0x74, 0xc0, 0x61, 0x7a, 0x40, 0x1e,
+ 0x0d, 0x79, 0x34, 0x38, 0x6f, 0x71, 0xde, 0x92,
+ 0x47, 0x83, 0x11, 0x63, 0x0e, 0xd3, 0x03, 0xf6,
+ 0x2b, 0x7b, 0xc8, 0x66, 0x48, 0x96, 0x16, 0x9a,
+ 0xd7, 0x01, 0x74, 0xbb, 0xd3, 0x52, 0x49, 0x5d,
+ 0x5f, 0x3d, 0x54, 0x23, 0x8a, 0x92, 0x41, 0x46,
+ 0xb0, 0xc2, 0x22, 0xc4, 0x93, 0xf3, 0x8d, 0x31,
+ 0xe2, 0x71, 0x04, 0x05, 0x56, 0x79, 0x74, 0x2d,
+ 0x79, 0x07, 0x40, 0x03, 0xcb, 0x51, 0xc5, 0x6a,
+ 0xe1, 0x0a, 0x72, 0x32, 0x64, 0x90, 0xcc, 0xd6,
+ 0xff, 0x2b, 0x10, 0x8e, 0x20, 0x1e, 0x61, 0x15,
+ 0x4a, 0xaa, 0x95, 0x76, 0xa7, 0x55, 0xd1, 0xef,
+ 0x96, 0x47, 0x67, 0x1f, 0x3c, 0x96, 0x3c, 0xf7,
+ 0xa7, 0x60, 0x61, 0x47, 0xb0, 0x68, 0x05, 0x8b,
+ 0xb9, 0xc4, 0x98, 0xc0, 0x7d, 0x67, 0xf8, 0xfa,
+ 0x9a, 0xc0, 0x27, 0x53, 0x37, 0xd1, 0x01, 0x99,
+ 0xc4, 0x3e, 0xf2, 0x64, 0xfd, 0x43, 0x80, 0xa8,
+ 0xdf, 0xbb, 0x74, 0x61, 0xdd, 0x04, 0xcd, 0x97,
+ 0xdf, 0xf5, 0xb9, 0xfc, 0x7a, 0x83, 0x67, 0xab,
+ 0x09, 0x36, 0x09, 0x8c, 0xac, 0x47, 0xed, 0xed,
+ 0xc3, 0x60, 0x88, 0x4d, 0x05, 0xb1, 0x80, 0x90,
+ 0x07, 0xd8, 0x55, 0xf8, 0x7f, 0x0a, 0xac, 0xf3,
+ 0x9b, 0x1b, 0xdd, 0x9e, 0x91, 0xa5, 0xb9, 0xb9,
+ 0xe4, 0x8f, 0x4d, 0xc3, 0xad, 0xdb, 0x5b, 0x7c,
+ 0xf5, 0x7d, 0xff, 0x24, 0x20, 0x02, 0x62, 0x04,
+ 0x37, 0xf4, 0xb8, 0xfd, 0x80, 0x1f, 0x06, 0xc2,
+ 0x3e, 0xc8, 0xa1, 0x26, 0x4c, 0x22, 0xd1, 0xc6,
+ 0xbb, 0xb3, 0x19, 0xd0, 0x5a, 0x4a, 0x59, 0xac,
+ 0x69, 0xde, 0xba, 0xb4, 0xf0, 0x64, 0x4c, 0x05,
+ 0x84, 0xc9, 0x14, 0x44, 0x0e, 0xf2, 0x20, 0x41,
+ 0x0e, 0x12, 0x6c, 0xee, 0x27, 0xc0, 0xad, 0x63,
+ 0x40, 0xa3, 0x9e, 0x70, 0xf1, 0xc5, 0x0a, 0xaf,
+ 0xbd, 0x5c, 0xc5, 0xba, 0x78, 0x24, 0x16, 0xd3,
+ 0x98, 0x8e, 0x05, 0x62, 0xa4, 0x50, 0x99, 0x46,
+ 0x0e, 0x12, 0xdc, 0x81, 0x27, 0x4e, 0xe2, 0xf5,
+ 0x8d, 0x6e, 0xef, 0xfe, 0x31, 0x20, 0x9b, 0x04,
+ 0xfe, 0xda, 0x32, 0xec, 0xfc, 0x5b, 0xd0, 0x78,
+ 0x26, 0x39, 0xc9, 0x78, 0x84, 0xd2, 0xf6, 0x1c,
+ 0xd1, 0x4f, 0x6d, 0xdb, 0xdc, 0x4f, 0x8e, 0xc4,
+ 0x9f, 0xcf, 0x5c, 0x6a, 0xef, 0x6c, 0xf0, 0x01,
+ 0xf9, 0xea, 0x4b, 0xf3, 0x6c, 0x3f, 0x9e, 0x9c,
+ 0x00, 0x04, 0x10, 0x22, 0xe6, 0x6f, 0x47, 0x51,
+ 0x8a, 0xdb, 0x02, 0xee, 0x08, 0x25, 0x3e, 0x9b,
+ 0x75, 0x3e, 0x7e, 0xe6, 0xbd, 0x8f, 0xe6, 0xaf,
+ 0x55, 0x6a, 0xf5, 0xb7, 0xd3, 0x72, 0xfa, 0x4a,
+ 0x94, 0xba, 0x19, 0xa2, 0xa8, 0x45, 0xa8, 0x65,
+ 0xc6, 0x0f, 0x1e, 0xec, 0x8e, 0x7f, 0xfb, 0xf8,
+ 0xe7, 0xe1, 0xfb, 0xbf, 0xff, 0x68, 0x1e, 0x3e,
+ 0xed, 0xdb, 0xff, 0x07, 0x11, 0x97, 0x44, 0x34,
+ 0x15, 0x45, 0xa6, 0x90, 0x00, 0x00, 0x00, 0x00,
+ 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+/* End Of File */
diff --git a/src/images/options_icon.png.h b/src/images/options_icon.png.h
new file mode 100644
index 0000000..e3ee34c
--- /dev/null
+++ b/src/images/options_icon.png.h
@@ -0,0 +1,266 @@
+/* options_icon.png - 2100 bytes */
+ static const unsigned char options_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x0a,
+ 0x06, 0x16, 0x03, 0x0c, 0x67, 0x52, 0xb3, 0xb5,
+ 0x00, 0x00, 0x07, 0xb4, 0x49, 0x44, 0x41, 0x54,
+ 0x58, 0x47, 0xed, 0x56, 0x69, 0x50, 0x5b, 0xd7,
+ 0x15, 0x3e, 0x4f, 0xef, 0x69, 0x97, 0x10, 0x12,
+ 0x92, 0xd8, 0x24, 0x10, 0x3b, 0x66, 0x17, 0xc8,
+ 0x36, 0x6e, 0xe3, 0x26, 0x80, 0x29, 0x2e, 0x74,
+ 0xa6, 0x0d, 0x75, 0x9c, 0xe2, 0x24, 0x93, 0xd6,
+ 0xf6, 0xbf, 0x76, 0xa6, 0xf6, 0xd4, 0x09, 0x98,
+ 0x4c, 0xff, 0xd9, 0x20, 0xbb, 0x71, 0xa8, 0xa7,
+ 0xd3, 0xce, 0x24, 0x21, 0x4e, 0x3a, 0xe3, 0x4e,
+ 0x67, 0x9a, 0x76, 0x52, 0x7b, 0x8a, 0x6d, 0x90,
+ 0x84, 0x9d, 0x26, 0x76, 0xbd, 0x15, 0x1b, 0x9c,
+ 0x50, 0x17, 0xb3, 0x9a, 0x45, 0x42, 0x68, 0xdf,
+ 0xd1, 0xf2, 0xd4, 0x7b, 0x95, 0x88, 0x11, 0x02,
+ 0x6c, 0x77, 0xfa, 0xb3, 0x7d, 0x33, 0x77, 0x9e,
+ 0xee, 0xd5, 0x39, 0xdf, 0xf7, 0xbd, 0x73, 0xcf,
+ 0x39, 0xf7, 0x02, 0xfc, 0xaf, 0x3f, 0xc4, 0xb3,
+ 0x04, 0xe0, 0xd4, 0x2f, 0x7b, 0xea, 0x01, 0x88,
+ 0xfd, 0x0c, 0x06, 0x41, 0xa3, 0x67, 0x29, 0x1a,
+ 0x85, 0xfe, 0xae, 0x37, 0xbb, 0x5d, 0xcf, 0xe2,
+ 0x1b, 0xb7, 0xe9, 0xe9, 0xeb, 0xe7, 0x74, 0x1f,
+ 0x3d, 0x1c, 0x48, 0xf6, 0x79, 0xaa, 0x80, 0xde,
+ 0x53, 0xbd, 0xac, 0x94, 0x14, 0x81, 0xef, 0x07,
+ 0x2f, 0xbe, 0x44, 0x46, 0x22, 0x11, 0x70, 0xb9,
+ 0x9c, 0x30, 0xfa, 0xe0, 0xbe, 0x6b, 0x6e, 0x6e,
+ 0xf6, 0xe5, 0xce, 0x37, 0xba, 0xaf, 0x24, 0x03,
+ 0x6e, 0x36, 0xef, 0xed, 0xfb, 0xe0, 0xb0, 0x50,
+ 0x98, 0xf2, 0x9e, 0xc7, 0xe3, 0x6e, 0xed, 0x3a,
+ 0x72, 0x70, 0x9d, 0x0f, 0xb9, 0x99, 0x43, 0xe2,
+ 0x9a, 0x41, 0x6f, 0x88, 0x3c, 0xdf, 0xb0, 0xfb,
+ 0x8a, 0xdb, 0xed, 0x7e, 0x51, 0x91, 0xad, 0xe4,
+ 0xe1, 0xff, 0x0a, 0xf2, 0x0b, 0xd9, 0xe1, 0x70,
+ 0xf8, 0x65, 0x75, 0x5d, 0xcd, 0x5f, 0x74, 0x43,
+ 0x7a, 0xf3, 0x56, 0x18, 0xda, 0xb3, 0xef, 0x12,
+ 0xdf, 0x6e, 0xdb, 0x77, 0xa6, 0xb8, 0xb4, 0xb4,
+ 0x27, 0xbf, 0xb8, 0x08, 0x7f, 0xec, 0x2b, 0xdb,
+ 0x77, 0x7c, 0x6b, 0xd6, 0x30, 0x78, 0x71, 0x34,
+ 0xee, 0xc3, 0xd8, 0xca, 0x39, 0x71, 0xbd, 0xf3,
+ 0x58, 0xf7, 0xed, 0x99, 0x99, 0xa9, 0xa6, 0xbf,
+ 0x7d, 0x76, 0x6d, 0x91, 0xcd, 0x66, 0x83, 0xcf,
+ 0xe7, 0x03, 0x75, 0x4d, 0x1d, 0x53, 0x28, 0x10,
+ 0xbe, 0xb5, 0x95, 0xbf, 0xf6, 0x9d, 0x73, 0x2c,
+ 0x36, 0x5b, 0x70, 0xb1, 0xba, 0xb6, 0xe6, 0x67,
+ 0xf2, 0x8c, 0x8c, 0x58, 0xa4, 0x73, 0x54, 0x2a,
+ 0x22, 0x3d, 0x3b, 0xeb, 0x23, 0x6d, 0xdf, 0x07,
+ 0x4d, 0xff, 0x91, 0x00, 0x6c, 0xfc, 0xe6, 0xb1,
+ 0xe3, 0x63, 0x8f, 0xe7, 0xe7, 0xde, 0x0b, 0xac,
+ 0x06, 0x80, 0xc1, 0x60, 0x40, 0x14, 0x25, 0x42,
+ 0x46, 0x46, 0xc6, 0xfe, 0x9e, 0x53, 0x3d, 0x54,
+ 0xb2, 0x88, 0x13, 0x67, 0xce, 0x11, 0x7c, 0x21,
+ 0xef, 0xba, 0x66, 0x7b, 0x5d, 0x1b, 0x8f, 0x2f,
+ 0x88, 0x6d, 0x1d, 0x1e, 0xc1, 0x40, 0x00, 0x1c,
+ 0x36, 0xbb, 0xae, 0xeb, 0xe8, 0x21, 0x43, 0xdc,
+ 0x67, 0x83, 0x33, 0x4a, 0xb8, 0x46, 0x44, 0xf0,
+ 0x3a, 0x1d, 0x0e, 0xfd, 0xb8, 0xb3, 0xf3, 0x17,
+ 0x74, 0x22, 0x38, 0x83, 0x41, 0x5a, 0x10, 0x33,
+ 0x70, 0x79, 0xbc, 0x98, 0x08, 0x3e, 0x4f, 0x40,
+ 0x10, 0x04, 0xcd, 0x45, 0x36, 0xee, 0x44, 0x3b,
+ 0x8a, 0x0a, 0x11, 0x69, 0x69, 0x62, 0x4d, 0x30,
+ 0x14, 0x86, 0x90, 0x1f, 0xe5, 0x1d, 0xf2, 0x41,
+ 0x09, 0x0c, 0x33, 0x53, 0x33, 0xa6, 0xd5, 0x55,
+ 0xff, 0x81, 0x75, 0x98, 0xc9, 0xea, 0xb3, 0xb2,
+ 0xb2, 0x2f, 0xed, 0xdf, 0xd7, 0xf1, 0x9a, 0x48,
+ 0x2c, 0xb9, 0xa0, 0x7d, 0xfb, 0xc4, 0x9a, 0xc0,
+ 0xde, 0xd3, 0x27, 0x79, 0x62, 0x71, 0xea, 0x81,
+ 0xd4, 0x54, 0x31, 0x70, 0x38, 0x9c, 0xd8, 0xc0,
+ 0x5f, 0x45, 0xd0, 0xe0, 0x4f, 0xc6, 0xa0, 0x69,
+ 0x4a, 0x80, 0xaa, 0x05, 0xfc, 0x3e, 0x0f, 0xf8,
+ 0x3c, 0x1e, 0x08, 0xf8, 0x7d, 0xb0, 0xb2, 0xbc,
+ 0x1c, 0xb5, 0xd9, 0xec, 0x3f, 0x3a, 0x7e, 0xe4,
+ 0xb0, 0x65, 0x9d, 0xd8, 0x64, 0x67, 0x0e, 0x9b,
+ 0x63, 0x23, 0x49, 0x32, 0xb3, 0xb1, 0xa1, 0xb9,
+ 0x6d, 0xf8, 0xaa, 0xfe, 0x33, 0xed, 0xe9, 0x93,
+ 0x83, 0x04, 0x10, 0x3e, 0xa9, 0x54, 0xf6, 0xc3,
+ 0xa6, 0xc6, 0x3d, 0x6a, 0x94, 0x8c, 0xb1, 0xf0,
+ 0xb3, 0x58, 0x2c, 0x70, 0x3a, 0xed, 0xce, 0x68,
+ 0x94, 0x8c, 0x24, 0x62, 0xf4, 0xf4, 0xbd, 0xcf,
+ 0x12, 0x0a, 0x78, 0x97, 0xe5, 0x32, 0x09, 0x60,
+ 0x11, 0x21, 0x3a, 0x0c, 0x81, 0xc0, 0x2a, 0x2c,
+ 0x2d, 0x18, 0xcf, 0x1e, 0x3f, 0x72, 0x70, 0x30,
+ 0x99, 0x6f, 0xc3, 0x16, 0x18, 0x4d, 0xc6, 0x3f,
+ 0x53, 0x14, 0xf5, 0x53, 0x1e, 0x97, 0x47, 0xb4,
+ 0x7f, 0x7f, 0x5f, 0x3d, 0xda, 0xf3, 0xfa, 0x80,
+ 0xdf, 0x0f, 0xa8, 0x8c, 0x20, 0x14, 0x0a, 0xc5,
+ 0xc8, 0xf1, 0xc0, 0xe0, 0x6a, 0xb5, 0x26, 0xc5,
+ 0x62, 0xb1, 0xf4, 0x23, 0xd0, 0x43, 0x18, 0xf8,
+ 0xe4, 0xd9, 0x7e, 0x4a, 0xc0, 0xe5, 0x0d, 0x96,
+ 0x16, 0xa9, 0x76, 0x45, 0x22, 0x61, 0x98, 0x9e,
+ 0x59, 0xb8, 0xed, 0x74, 0xfb, 0x7e, 0x8d, 0xac,
+ 0xa7, 0x19, 0x04, 0x71, 0x2b, 0x99, 0x1c, 0xcf,
+ 0x37, 0xf4, 0x81, 0xb7, 0xcf, 0x68, 0x0b, 0x77,
+ 0xec, 0xd8, 0xf5, 0xcf, 0xca, 0x8a, 0x2a, 0x0a,
+ 0x87, 0x38, 0xf9, 0xc1, 0xe4, 0x38, 0x0a, 0x2e,
+ 0x97, 0x0b, 0xe4, 0x72, 0x39, 0xb8, 0x3d, 0x6e,
+ 0xfa, 0xf2, 0x95, 0x81, 0xbe, 0xd5, 0x70, 0x4a,
+ 0x27, 0x97, 0xcf, 0xbd, 0x54, 0x51, 0x56, 0xd8,
+ 0x8c, 0x6c, 0x88, 0x47, 0x53, 0xf3, 0x77, 0x6d,
+ 0x4e, 0x77, 0x43, 0xf7, 0x91, 0x83, 0x9e, 0x64,
+ 0x8c, 0xc4, 0xf9, 0x86, 0x3e, 0x30, 0x34, 0xa4,
+ 0xb7, 0x6d, 0x2b, 0x2f, 0x9e, 0x49, 0x49, 0x11,
+ 0xb5, 0x2b, 0x14, 0xca, 0x58, 0xa8, 0x99, 0x4c,
+ 0x66, 0x6c, 0x30, 0x48, 0x06, 0xe0, 0x32, 0xf4,
+ 0xa0, 0x7d, 0x4d, 0x4b, 0x4b, 0x8b, 0xbd, 0xe5,
+ 0x32, 0x39, 0x21, 0x93, 0xa5, 0xd7, 0xcf, 0xce,
+ 0x1b, 0x5f, 0xab, 0xae, 0x2c, 0xad, 0x63, 0x32,
+ 0x29, 0x4c, 0x7e, 0xcf, 0x6a, 0x77, 0x35, 0x76,
+ 0x1f, 0x3d, 0xb8, 0x2e, 0x39, 0x37, 0x13, 0xb2,
+ 0x41, 0x00, 0x36, 0xd2, 0x0d, 0x19, 0xc6, 0x0a,
+ 0x4b, 0x0a, 0xae, 0x2f, 0x2c, 0x3c, 0x2e, 0x40,
+ 0x9d, 0x4f, 0x69, 0xb5, 0x5a, 0x83, 0x13, 0x8f,
+ 0xfe, 0x45, 0x7f, 0x7a, 0x6d, 0xf8, 0x23, 0xe3,
+ 0xb2, 0x31, 0x53, 0x5d, 0x53, 0x2b, 0x74, 0x38,
+ 0x1c, 0x20, 0x91, 0x48, 0xc0, 0x6e, 0x77, 0xc0,
+ 0xfd, 0x2f, 0xa7, 0x89, 0xfc, 0x3c, 0xa5, 0x98,
+ 0xc5, 0x64, 0x12, 0x8f, 0x26, 0x1f, 0x8f, 0xae,
+ 0x58, 0xec, 0x0d, 0xdd, 0x47, 0x0f, 0x39, 0x37,
+ 0x23, 0x4c, 0x5e, 0xdb, 0xb0, 0x05, 0xc9, 0x06,
+ 0xbd, 0xa7, 0x4f, 0xb0, 0x50, 0x12, 0x52, 0x44,
+ 0x94, 0x0e, 0xe0, 0xb2, 0x3c, 0x7d, 0x46, 0x5b,
+ 0x55, 0x52, 0x54, 0x32, 0xd4, 0xbc, 0xa7, 0x25,
+ 0x7d, 0x79, 0x79, 0x19, 0xee, 0x8c, 0x4e, 0x40,
+ 0x9a, 0x44, 0x84, 0xaa, 0x82, 0x0d, 0xd3, 0xd3,
+ 0xf3, 0xb0, 0xb4, 0x38, 0xf1, 0x93, 0xce, 0x9f,
+ 0x1f, 0xfb, 0x6d, 0x32, 0xce, 0x56, 0xf3, 0x4d,
+ 0x23, 0x90, 0x68, 0x6c, 0xd0, 0x0d, 0x47, 0xf4,
+ 0xba, 0xe1, 0x90, 0x5e, 0x7f, 0x35, 0x8a, 0xd7,
+ 0x27, 0xa9, 0x26, 0xff, 0x92, 0xd9, 0xe6, 0x0f,
+ 0x78, 0xed, 0xbb, 0x5d, 0x2e, 0x1f, 0x33, 0x35,
+ 0x55, 0x08, 0x3c, 0x2e, 0x17, 0x66, 0x66, 0x17,
+ 0xa1, 0xe1, 0x39, 0x0d, 0x88, 0x45, 0xc2, 0xd6,
+ 0xe2, 0x92, 0x82, 0x5b, 0x7a, 0x9d, 0x61, 0x72,
+ 0x2b, 0xd2, 0xc4, 0xf5, 0xa7, 0x0a, 0x48, 0x34,
+ 0xce, 0xff, 0xee, 0xa9, 0x03, 0x35, 0xe5, 0x79,
+ 0x37, 0x2a, 0x2b, 0xca, 0xf7, 0xea, 0x47, 0xcc,
+ 0x14, 0xd0, 0x61, 0xa2, 0xb2, 0x28, 0x1d, 0xa6,
+ 0x11, 0xf9, 0x37, 0xb6, 0x57, 0x02, 0x45, 0x12,
+ 0xa0, 0x54, 0xe6, 0x10, 0x24, 0x49, 0xbd, 0x54,
+ 0x56, 0x5e, 0xfc, 0x29, 0xda, 0xca, 0xc7, 0x4f,
+ 0x13, 0xf1, 0xcc, 0x02, 0x54, 0x6d, 0xbd, 0x0d,
+ 0x3b, 0xd5, 0x25, 0x17, 0xb6, 0x95, 0xa8, 0xc8,
+ 0xf2, 0x3c, 0x29, 0xb1, 0xe2, 0xa1, 0x89, 0x89,
+ 0x79, 0x3b, 0x18, 0x97, 0x4c, 0xd1, 0xfd, 0xad,
+ 0xf5, 0x04, 0xca, 0xcf, 0x58, 0x82, 0xe2, 0x73,
+ 0x42, 0xa9, 0x50, 0x52, 0xa8, 0x4c, 0xdb, 0xab,
+ 0x6a, 0xca, 0x75, 0x48, 0x84, 0xf1, 0x49, 0x22,
+ 0x9e, 0x49, 0x00, 0x22, 0xaf, 0x2d, 0x2b, 0xca,
+ 0xb9, 0xa4, 0xc8, 0x51, 0x70, 0x17, 0xcc, 0x6e,
+ 0x78, 0x30, 0x65, 0x06, 0xa7, 0xc7, 0x8f, 0xc2,
+ 0xcd, 0x87, 0xfb, 0x0f, 0x8d, 0xce, 0xca, 0xec,
+ 0x50, 0x24, 0x37, 0x47, 0xc5, 0xf2, 0x7a, 0xbd,
+ 0x80, 0x7a, 0x08, 0x6a, 0x3c, 0x01, 0x1c, 0x09,
+ 0x0e, 0x7a, 0x7f, 0x4f, 0xad, 0xae, 0xba, 0xa4,
+ 0xd3, 0x19, 0x56, 0xb6, 0x12, 0xf1, 0x54, 0x01,
+ 0xaa, 0x36, 0xed, 0x4e, 0x4c, 0x5e, 0x58, 0x94,
+ 0x97, 0xe6, 0xf2, 0x04, 0x80, 0x4b, 0xd1, 0x30,
+ 0x37, 0x35, 0x0e, 0x61, 0x9a, 0x44, 0x89, 0xc7,
+ 0x84, 0xf9, 0x25, 0xcb, 0x1f, 0xb2, 0x39, 0xc6,
+ 0x37, 0x68, 0x3a, 0x72, 0x20, 0x3b, 0x4b, 0x41,
+ 0xad, 0xae, 0xae, 0xc6, 0xce, 0x89, 0x60, 0x30,
+ 0x08, 0x39, 0xca, 0x5c, 0x81, 0xd7, 0xe7, 0x6d,
+ 0xab, 0xd5, 0xd4, 0x7c, 0x82, 0xf2, 0x68, 0xd3,
+ 0xaa, 0x78, 0xa2, 0x80, 0xbc, 0xb6, 0xde, 0x76,
+ 0x75, 0x79, 0xc1, 0xc5, 0x82, 0x82, 0x5c, 0x11,
+ 0xde, 0x5f, 0x09, 0x9f, 0x01, 0x23, 0x23, 0x23,
+ 0x10, 0x65, 0x0a, 0x50, 0x1f, 0x90, 0x80, 0xd1,
+ 0x64, 0x71, 0x3a, 0x9d, 0xbe, 0xd7, 0x3f, 0xfe,
+ 0x4d, 0xd7, 0x48, 0x55, 0x4d, 0xc5, 0x75, 0x44,
+ 0xdc, 0x21, 0x97, 0xa7, 0x93, 0x98, 0x1c, 0x77,
+ 0x4a, 0xdc, 0xc8, 0x94, 0x8a, 0x9c, 0x54, 0xd4,
+ 0xac, 0x5a, 0x34, 0x9a, 0xba, 0x3f, 0xea, 0xf5,
+ 0x06, 0x5f, 0x72, 0x24, 0x36, 0x15, 0x90, 0xd7,
+ 0xaa, 0x65, 0xcb, 0xca, 0x5a, 0xde, 0xdd, 0x5d,
+ 0x5f, 0xd9, 0x9b, 0x9f, 0x97, 0xcd, 0x54, 0x4a,
+ 0xf9, 0xc0, 0x63, 0x46, 0x41, 0x77, 0xf5, 0x73,
+ 0xa0, 0x49, 0x1e, 0xc8, 0xe4, 0x19, 0x60, 0x36,
+ 0x5b, 0xac, 0x4b, 0x26, 0xcb, 0x77, 0x66, 0x07,
+ 0xba, 0xc6, 0x30, 0x28, 0xda, 0xeb, 0xd9, 0xca,
+ 0xea, 0xf2, 0x5b, 0x14, 0x93, 0xd9, 0x21, 0x11,
+ 0xa7, 0x31, 0xb0, 0x00, 0x74, 0x69, 0x89, 0xb5,
+ 0x6d, 0x74, 0x91, 0x91, 0x39, 0x9c, 0xb6, 0xe6,
+ 0xfa, 0x9d, 0x9a, 0xf3, 0x7a, 0xfd, 0x70, 0xe8,
+ 0x89, 0x55, 0xa0, 0x6a, 0xd5, 0xbe, 0x2a, 0x4e,
+ 0x15, 0x5c, 0x68, 0x7e, 0x41, 0xf3, 0x7c, 0x91,
+ 0x2a, 0x9d, 0xa8, 0xce, 0x13, 0x83, 0xd5, 0xe1,
+ 0x85, 0x4f, 0x2e, 0x5f, 0x83, 0x08, 0xc1, 0x01,
+ 0x59, 0x7a, 0x26, 0x22, 0xb7, 0x5a, 0x8d, 0x26,
+ 0xeb, 0x9e, 0xd9, 0x81, 0xe3, 0xff, 0x48, 0x04,
+ 0x43, 0x22, 0xa6, 0x2b, 0x2a, 0xcb, 0xee, 0x70,
+ 0xb9, 0xbc, 0x0e, 0xd4, 0x49, 0x19, 0x98, 0x1c,
+ 0x47, 0x01, 0x6f, 0x4b, 0x4e, 0x4e, 0x6e, 0xa6,
+ 0xd5, 0x6e, 0x6b, 0xd8, 0xf5, 0xdc, 0x8e, 0xdf,
+ 0xe9, 0x87, 0x86, 0xd7, 0x8e, 0xf9, 0x75, 0x11,
+ 0xc8, 0x6d, 0xd5, 0xb6, 0x17, 0xe6, 0x2b, 0x7e,
+ 0xbf, 0xf7, 0x05, 0x75, 0x6a, 0x75, 0x91, 0x9c,
+ 0x50, 0xe7, 0x4b, 0xe0, 0xc6, 0x17, 0x8b, 0x30,
+ 0xa0, 0xbf, 0x01, 0x11, 0x9a, 0x01, 0x62, 0x59,
+ 0x26, 0xb8, 0x9c, 0x6e, 0xff, 0xc2, 0x92, 0xb9,
+ 0x05, 0x91, 0xdf, 0x4d, 0x0e, 0x27, 0x9e, 0xe3,
+ 0xfa, 0xaf, 0xa8, 0x2a, 0x1b, 0xe1, 0xf3, 0xf9,
+ 0x1d, 0xf8, 0x40, 0xc3, 0xdb, 0x61, 0x32, 0x99,
+ 0x00, 0x1d, 0x5a, 0x50, 0x5a, 0x52, 0xaa, 0x40,
+ 0x77, 0x49, 0xef, 0xd0, 0xa0, 0xee, 0x7a, 0xdc,
+ 0x77, 0xdd, 0x95, 0x0c, 0xb5, 0xf1, 0x6f, 0xee,
+ 0xde, 0x5e, 0x4a, 0xb6, 0x68, 0x94, 0x90, 0x25,
+ 0xe1, 0xc0, 0x87, 0x97, 0xc7, 0x61, 0xf8, 0xef,
+ 0x63, 0x10, 0x44, 0xa1, 0xe4, 0xa5, 0xca, 0x21,
+ 0x12, 0x8e, 0x44, 0xe7, 0xe6, 0x4d, 0xaf, 0x20,
+ 0xf2, 0x9b, 0x9b, 0x91, 0xc7, 0xd7, 0xd0, 0xed,
+ 0xe9, 0xaf, 0x23, 0xf7, 0xee, 0xb6, 0x2f, 0x9b,
+ 0x4d, 0x28, 0x08, 0xb1, 0xfe, 0x05, 0x52, 0xa9,
+ 0x14, 0x45, 0x22, 0x88, 0x2e, 0x2a, 0x52, 0x4d,
+ 0xa2, 0xef, 0x3a, 0x01, 0x88, 0xc0, 0xeb, 0x40,
+ 0x99, 0x7e, 0x5e, 0x3f, 0x01, 0xbf, 0xfa, 0xf8,
+ 0x3e, 0x4c, 0x2f, 0x98, 0xc1, 0xe7, 0x76, 0x01,
+ 0x53, 0x20, 0x87, 0x14, 0x21, 0x1f, 0x26, 0x27,
+ 0xe7, 0xce, 0xcd, 0x0e, 0xbc, 0x75, 0x01, 0x01,
+ 0x3c, 0xa9, 0x85, 0xe3, 0xff, 0x18, 0x48, 0xc4,
+ 0xc5, 0xdb, 0x77, 0x6e, 0xbe, 0x6a, 0x77, 0xd8,
+ 0x40, 0x20, 0x10, 0x00, 0x2e, 0x51, 0x94, 0xa4,
+ 0x51, 0x8b, 0x65, 0xe5, 0x61, 0xa2, 0x80, 0xf8,
+ 0x16, 0x60, 0x27, 0x92, 0x27, 0xdf, 0x36, 0x19,
+ 0x8a, 0xb2, 0x0e, 0x8b, 0x44, 0x42, 0xb6, 0xc3,
+ 0xed, 0x03, 0x8f, 0xc3, 0x02, 0x04, 0x4b, 0x04,
+ 0x62, 0x89, 0x18, 0x16, 0xe6, 0x16, 0x57, 0x4c,
+ 0xe3, 0xc3, 0xfb, 0xfc, 0x2b, 0x0f, 0x83, 0x5f,
+ 0x0b, 0xc0, 0x3e, 0xf1, 0x81, 0x31, 0x63, 0xc4,
+ 0x5f, 0x0f, 0x8c, 0x4b, 0x1a, 0xf4, 0x57, 0xc7,
+ 0xf3, 0x0b, 0x55, 0x88, 0x90, 0xa8, 0x45, 0x57,
+ 0x31, 0xe1, 0x97, 0xe3, 0x0f, 0xce, 0x8f, 0xdc,
+ 0xbb, 0xd7, 0xf9, 0x60, 0xf4, 0x8b, 0xb5, 0x73,
+ 0x3e, 0x11, 0x24, 0xe6, 0xac, 0x6c, 0xea, 0xda,
+ 0x5b, 0x54, 0xb2, 0xed, 0x4f, 0x72, 0x79, 0x1a,
+ 0x13, 0x55, 0x19, 0x90, 0x6c, 0x3e, 0x70, 0x49,
+ 0xa0, 0x47, 0xef, 0xde, 0x3c, 0x36, 0x3f, 0xac,
+ 0x7d, 0x1f, 0xd9, 0x84, 0xd1, 0xc0, 0x49, 0x14,
+ 0x1f, 0xe8, 0x67, 0xec, 0xc1, 0xb1, 0x8e, 0xe3,
+ 0x61, 0xac, 0xe4, 0x28, 0x61, 0x7b, 0x6c, 0x93,
+ 0x38, 0x60, 0x43, 0x19, 0xba, 0x66, 0x3e, 0x9f,
+ 0x8c, 0x88, 0x2a, 0xc6, 0xfc, 0x81, 0x70, 0x23,
+ 0x9f, 0xc7, 0xa5, 0x42, 0x01, 0x3f, 0x31, 0x33,
+ 0x35, 0xdd, 0x3f, 0x7f, 0xed, 0x9d, 0x9e, 0x68,
+ 0x24, 0x18, 0x27, 0xc7, 0x20, 0xc9, 0x80, 0x71,
+ 0x11, 0xf1, 0x77, 0xa2, 0xc8, 0xb8, 0x6d, 0xfc,
+ 0x8d, 0x6d, 0x62, 0x4f, 0xb2, 0xca, 0xb5, 0x35,
+ 0x51, 0x7e, 0x03, 0x25, 0xc8, 0xae, 0x96, 0x46,
+ 0x02, 0x4e, 0xaf, 0xe9, 0xce, 0x87, 0xf1, 0x5b,
+ 0xcd, 0x57, 0x19, 0xf5, 0xd5, 0x57, 0xac, 0x81,
+ 0xfc, 0xff, 0xc7, 0x7f, 0x13, 0x81, 0x7f, 0x03,
+ 0x92, 0xbf, 0x61, 0xe0, 0x63, 0xbd, 0x16, 0xad,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
+ 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/options_icon_text.png.h b/src/images/options_icon_text.png.h
new file mode 100644
index 0000000..6104210
--- /dev/null
+++ b/src/images/options_icon_text.png.h
@@ -0,0 +1,160 @@
+/* options_icon_text.png - 1253 bytes */
+ static const unsigned char options_icon_text_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x69, 0x71,
+ 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x03,
+ 0x16, 0x14, 0x20, 0x11, 0xe4, 0x70, 0x49, 0x8d,
+ 0x00, 0x00, 0x04, 0x65, 0x49, 0x44, 0x41, 0x54,
+ 0x78, 0xda, 0xed, 0x97, 0x5f, 0x68, 0x53, 0x77,
+ 0x14, 0xc7, 0xbf, 0x5d, 0xd7, 0xdc, 0x8d, 0x82,
+ 0x09, 0x38, 0x35, 0xa9, 0x7d, 0xc8, 0x18, 0x7d,
+ 0xb0, 0xad, 0x76, 0x05, 0x03, 0x7d, 0xe8, 0xf3,
+ 0x2d, 0x32, 0x29, 0x42, 0x5f, 0x0c, 0xa4, 0x11,
+ 0x1f, 0x0a, 0xc2, 0x06, 0xa6, 0x4c, 0x48, 0x5e,
+ 0xc7, 0x60, 0x42, 0x37, 0x36, 0x27, 0x0e, 0x7d,
+ 0x1a, 0x43, 0xda, 0x6a, 0x15, 0xa4, 0x0f, 0x7d,
+ 0x11, 0x96, 0xb4, 0x69, 0x92, 0x87, 0x18, 0x34,
+ 0xc9, 0x46, 0xfd, 0x03, 0x45, 0x1c, 0xdb, 0xa8,
+ 0x8d, 0xd4, 0x88, 0x6b, 0xee, 0x25, 0xb9, 0x37,
+ 0xf7, 0xbb, 0x97, 0x7b, 0xb3, 0x78, 0x9b, 0x2c,
+ 0x76, 0x2b, 0xd4, 0x8d, 0xdf, 0x07, 0x0e, 0x24,
+ 0xbf, 0x73, 0xef, 0xf9, 0xdd, 0xdf, 0xf7, 0x9e,
+ 0xfb, 0x3b, 0xe7, 0x07, 0x08, 0x04, 0x02, 0x81,
+ 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40,
+ 0x20, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40, 0x20,
+ 0x10, 0x08, 0x04, 0x02, 0x81, 0x40, 0x20, 0xf8,
+ 0xbf, 0xd3, 0xb6, 0x4b, 0xf3, 0xf2, 0x0d, 0x79,
+ 0x0e, 0xbc, 0x65, 0xfb, 0x3f, 0x04, 0xe0, 0x06,
+ 0x80, 0x0d, 0x9b, 0xdd, 0x30, 0x7d, 0xff, 0x64,
+ 0xa1, 0xf5, 0xf6, 0x97, 0x83, 0x04, 0xc9, 0x37,
+ 0x2a, 0x1b, 0x2e, 0x3a, 0x1c, 0x0e, 0x35, 0x12,
+ 0x89, 0x68, 0xb9, 0x5c, 0xce, 0x50, 0x14, 0xc5,
+ 0x50, 0x14, 0xc5, 0xc8, 0xe5, 0x72, 0x46, 0x24,
+ 0x12, 0xd1, 0x1d, 0x0e, 0x47, 0x19, 0xc0, 0xc5,
+ 0xed, 0x0a, 0x60, 0x61, 0x13, 0xa0, 0xd9, 0xf8,
+ 0xae, 0x31, 0x24, 0x49, 0x12, 0xe3, 0xf1, 0x38,
+ 0x35, 0x4d, 0x63, 0x28, 0x14, 0xaa, 0xb8, 0x5c,
+ 0xae, 0xe7, 0x2e, 0x97, 0xeb, 0xf9, 0xe4, 0xe4,
+ 0xa4, 0xae, 0xeb, 0x3a, 0xe3, 0xf1, 0x38, 0x1d,
+ 0x0e, 0x07, 0xcd, 0x4c, 0xb0, 0xbf, 0xd9, 0x3f,
+ 0xea, 0x2c, 0x06, 0xe0, 0x7d, 0xcb, 0x67, 0x5b,
+ 0x68, 0x33, 0x03, 0x80, 0xbd, 0x00, 0xbe, 0x03,
+ 0xf0, 0xcc, 0x96, 0x7d, 0x97, 0x4d, 0x5f, 0xa3,
+ 0x8c, 0x2a, 0xd6, 0xd9, 0x3a, 0x80, 0x2f, 0x00,
+ 0x74, 0x00, 0x78, 0x1b, 0x40, 0x08, 0xc0, 0x0a,
+ 0x80, 0x72, 0x9d, 0xfd, 0x0c, 0xe0, 0x13, 0x00,
+ 0x4e, 0xbb, 0x00, 0x37, 0xc3, 0xe1, 0x30, 0x49,
+ 0xf2, 0xfc, 0xf9, 0xf3, 0x04, 0xa0, 0x02, 0x18,
+ 0x00, 0x30, 0x08, 0xa0, 0x3c, 0x35, 0x35, 0x45,
+ 0x92, 0x0c, 0x87, 0xc3, 0x34, 0x3f, 0x87, 0xda,
+ 0xc2, 0x82, 0xc1, 0x20, 0xef, 0xdf, 0xbf, 0x5f,
+ 0x2d, 0x97, 0xcb, 0x5c, 0x5d, 0x5d, 0x65, 0x20,
+ 0x10, 0xa0, 0x7d, 0xf1, 0xf5, 0x34, 0x11, 0x66,
+ 0x2f, 0x00, 0x4d, 0x96, 0x65, 0x3d, 0x91, 0x48,
+ 0x18, 0xa5, 0x52, 0xc9, 0x50, 0x14, 0xc5, 0x48,
+ 0x26, 0x93, 0x86, 0x2c, 0xcb, 0x3a, 0x00, 0xcd,
+ 0xbc, 0xa6, 0x76, 0xdf, 0xd8, 0xd8, 0x18, 0xd3,
+ 0xe9, 0xb4, 0xa6, 0xaa, 0xaa, 0xb1, 0xb9, 0xb9,
+ 0xc9, 0xdb, 0xb7, 0x6f, 0xb3, 0xa7, 0xa7, 0x87,
+ 0x00, 0xbe, 0x07, 0xf0, 0x83, 0xd7, 0xeb, 0xe5,
+ 0xdc, 0xdc, 0x1c, 0xd7, 0xd7, 0xd7, 0xa9, 0xeb,
+ 0x3a, 0x9f, 0x3e, 0x7d, 0x6a, 0xcc, 0xcf, 0xcf,
+ 0xbf, 0xf0, 0xfb, 0xfd, 0xb7, 0x00, 0x5c, 0xb2,
+ 0x0b, 0x50, 0xcc, 0xe7, 0xf3, 0x24, 0xc9, 0xde,
+ 0xde, 0x5e, 0x02, 0x18, 0xa9, 0xf3, 0x7d, 0xd4,
+ 0xdf, 0xdf, 0x4f, 0x92, 0xcc, 0xe5, 0x72, 0x34,
+ 0xdf, 0x4a, 0xed, 0x41, 0x96, 0x96, 0x96, 0xd8,
+ 0xd5, 0xd5, 0xb5, 0xe9, 0x76, 0xbb, 0x37, 0x63,
+ 0xb1, 0x18, 0x49, 0xf2, 0xf8, 0xf1, 0xe3, 0x6c,
+ 0x95, 0x01, 0xb6, 0xf1, 0xcb, 0xb2, 0x2c, 0xb3,
+ 0x5a, 0xad, 0x5a, 0xf1, 0x8a, 0x6e, 0xb7, 0xbb,
+ 0xb8, 0xb8, 0xb8, 0xc8, 0x6a, 0xb5, 0x4a, 0x59,
+ 0x96, 0x69, 0x66, 0x47, 0xed, 0xbe, 0x4c, 0x26,
+ 0xc3, 0xbe, 0xbe, 0xbe, 0x97, 0x92, 0x24, 0x15,
+ 0xcf, 0x9d, 0x3b, 0x47, 0x92, 0x4c, 0xa7, 0xd3,
+ 0x34, 0xdf, 0xb4, 0x7a, 0xe7, 0xce, 0x1d, 0x92,
+ 0xe4, 0x89, 0x13, 0x27, 0x28, 0x49, 0x52, 0xd9,
+ 0xe3, 0xf1, 0x54, 0x26, 0x26, 0x26, 0x7e, 0x7d,
+ 0xf8, 0xf0, 0xe1, 0xef, 0x0d, 0x05, 0x50, 0x55,
+ 0x95, 0x24, 0xad, 0x34, 0x97, 0xea, 0x7c, 0xef,
+ 0x48, 0x92, 0x44, 0x92, 0x54, 0x14, 0x65, 0x8b,
+ 0x00, 0x3e, 0x9f, 0x8f, 0x00, 0xbe, 0x05, 0xf0,
+ 0xf5, 0xd1, 0xa3, 0x47, 0x49, 0x92, 0xc9, 0x64,
+ 0x92, 0x66, 0x2a, 0xbf, 0xee, 0x1e, 0xb0, 0x91,
+ 0x4c, 0x26, 0xed, 0xf1, 0xbe, 0xf1, 0xf9, 0x7c,
+ 0x24, 0xc9, 0x44, 0x22, 0xb1, 0x65, 0xde, 0xc1,
+ 0xc1, 0x41, 0x02, 0xb8, 0x0a, 0xc0, 0xd7, 0xd9,
+ 0xd9, 0x49, 0x92, 0xd4, 0x75, 0xdd, 0x8a, 0xa7,
+ 0x6a, 0x9a, 0x46, 0x92, 0x1c, 0x1e, 0x1e, 0xb6,
+ 0xc6, 0x9e, 0x01, 0xb8, 0x6e, 0x2e, 0x7e, 0xe7,
+ 0x04, 0x90, 0x24, 0x89, 0x00, 0x3a, 0x01, 0x74,
+ 0x5a, 0xd7, 0x95, 0x4a, 0xa5, 0x6d, 0x0b, 0xa0,
+ 0x28, 0x4a, 0xd3, 0x78, 0x8d, 0xe6, 0x6d, 0x6f,
+ 0x6f, 0x27, 0x80, 0x77, 0x9b, 0xc4, 0x53, 0x33,
+ 0x99, 0x4c, 0x6d, 0xac, 0x54, 0x2a, 0x31, 0x9b,
+ 0xcd, 0xf2, 0xc2, 0x85, 0x0b, 0x3c, 0x78, 0xf0,
+ 0xa0, 0x25, 0xdc, 0xce, 0x7c, 0x02, 0xbb, 0x25,
+ 0x40, 0x8b, 0x78, 0x57, 0xbd, 0x5e, 0x2f, 0xa7,
+ 0xa7, 0xa7, 0xb9, 0xb6, 0xb6, 0xf6, 0xca, 0x1e,
+ 0x94, 0xc9, 0x64, 0x08, 0xa0, 0x64, 0xef, 0x03,
+ 0x7e, 0x9c, 0x9d, 0x9d, 0x05, 0x00, 0x8c, 0x8f,
+ 0x8f, 0x03, 0xc0, 0xbc, 0xb9, 0x09, 0x7e, 0x08,
+ 0xe0, 0x56, 0x30, 0x18, 0x04, 0x00, 0x5c, 0xbb,
+ 0x76, 0x0d, 0x00, 0xa2, 0xf5, 0xca, 0x1d, 0x3e,
+ 0x7c, 0x18, 0x00, 0x3e, 0x07, 0xf0, 0x99, 0xf9,
+ 0x1b, 0xd9, 0x6c, 0xb6, 0x59, 0xb5, 0x91, 0x9a,
+ 0x39, 0xee, 0xdd, 0xbb, 0xb7, 0x25, 0xde, 0x91,
+ 0x23, 0x47, 0x00, 0x00, 0x77, 0xef, 0xde, 0xdd,
+ 0x6e, 0x55, 0x5b, 0x7f, 0xf2, 0xe4, 0xc9, 0x57,
+ 0x81, 0x40, 0xe0, 0x27, 0x8f, 0xc7, 0x83, 0x3d,
+ 0x7b, 0xf6, 0xe0, 0xe4, 0xc9, 0x93, 0x00, 0x80,
+ 0x81, 0x81, 0x81, 0xe6, 0x65, 0x70, 0x79, 0x79,
+ 0x99, 0x9a, 0xa6, 0xf1, 0xec, 0xd9, 0xb3, 0x15,
+ 0xa7, 0xd3, 0xf9, 0xc2, 0xe9, 0x74, 0xbe, 0x08,
+ 0x85, 0x42, 0x0d, 0xcb, 0xa0, 0x45, 0x2c, 0x16,
+ 0xa3, 0xdb, 0xed, 0x56, 0xf6, 0xef, 0xdf, 0xaf,
+ 0x44, 0xa3, 0x51, 0x92, 0xe4, 0xe8, 0xe8, 0x28,
+ 0xcd, 0xf2, 0xc5, 0x42, 0xa1, 0x40, 0x92, 0x3c,
+ 0x74, 0xe8, 0xd0, 0x6b, 0x6d, 0x82, 0xb1, 0x58,
+ 0x8c, 0x1e, 0x8f, 0xa7, 0x78, 0xe0, 0xc0, 0x81,
+ 0x62, 0x34, 0x1a, 0x6d, 0xba, 0x09, 0xb6, 0xc8,
+ 0x80, 0x2f, 0x57, 0x56, 0x56, 0x7e, 0xf1, 0xfb,
+ 0xfd, 0xbf, 0xed, 0xdb, 0xb7, 0xaf, 0xdc, 0xd1,
+ 0xd1, 0x51, 0x3e, 0x76, 0xec, 0x18, 0x49, 0x32,
+ 0x95, 0x4a, 0xbd, 0x92, 0x01, 0xf5, 0x5c, 0x92,
+ 0x24, 0x49, 0x8d, 0x44, 0x22, 0x5a, 0x3e, 0x9f,
+ 0x37, 0x54, 0x55, 0x35, 0x54, 0x55, 0x35, 0xf2,
+ 0xf9, 0x7c, 0xa3, 0x46, 0xa8, 0x36, 0xe1, 0xa9,
+ 0x53, 0xa7, 0xf8, 0xe8, 0xd1, 0xa3, 0x6a, 0xa5,
+ 0x52, 0xe1, 0xe3, 0xc7, 0x8f, 0x19, 0x0c, 0x06,
+ 0xad, 0x87, 0x70, 0x03, 0x78, 0x70, 0xe6, 0xcc,
+ 0x19, 0x6e, 0x6c, 0x6c, 0x6c, 0xab, 0x0c, 0x5a,
+ 0x4d, 0x58, 0x2a, 0x95, 0x32, 0x46, 0x46, 0x46,
+ 0x1a, 0x96, 0xc1, 0x56, 0x02, 0x9c, 0x3e, 0x7d,
+ 0xfa, 0xfa, 0xc2, 0xc2, 0xc2, 0xcb, 0x42, 0xa1,
+ 0x60, 0x95, 0x41, 0xce, 0xcc, 0xcc, 0xb0, 0xbb,
+ 0xbb, 0x9b, 0x00, 0xae, 0x34, 0x6d, 0x88, 0x00,
+ 0xdc, 0xb4, 0x35, 0x18, 0x45, 0x73, 0x6c, 0xe8,
+ 0x6f, 0x26, 0x2c, 0xd5, 0x59, 0x1c, 0xc0, 0x07,
+ 0xe6, 0x75, 0xbd, 0x00, 0x56, 0x5b, 0x34, 0x41,
+ 0xf6, 0x46, 0xc8, 0xde, 0x86, 0x5f, 0x01, 0xf0,
+ 0x5e, 0x8b, 0xd6, 0xda, 0x3e, 0xee, 0x02, 0xf0,
+ 0x29, 0x80, 0x07, 0x0d, 0x1a, 0xa1, 0x8f, 0x01,
+ 0xb4, 0xff, 0xdb, 0x43, 0x08, 0xad, 0x3e, 0xbe,
+ 0xad, 0xad, 0x6d, 0x57, 0x0f, 0x33, 0x3b, 0x7d,
+ 0x18, 0x12, 0xc7, 0xe1, 0xff, 0xda, 0x71, 0x56,
+ 0x20, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40, 0x20,
+ 0x10, 0x08, 0x04, 0x02, 0x81, 0x60, 0xbb, 0xfc,
+ 0x09, 0x0a, 0x27, 0x5e, 0xd5, 0x75, 0xbd, 0x87,
+ 0xd3, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
+ 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/player.xpm b/src/images/player.xpm
new file mode 100644
index 0000000..ca7b498
--- /dev/null
+++ b/src/images/player.xpm
@@ -0,0 +1,83 @@
+/* XPM */
+static const char * player_xpm[] = {
+"16 16 64 1",
+" c None",
+". c #3C2D00",
+"+ c #FDB19C",
+"@ c #FDB19B",
+"# c #FDB4A2",
+"$ c #FDAC91",
+"% c #FDA691",
+"& c #FDAD93",
+"* c #FDB49A",
+"= c #FDBBA5",
+"- c #FDB099",
+"; c #FDC7AC",
+"> c #FDC6A9",
+", c #3A2B00",
+"' c #362700",
+") c #FFFFC5",
+"! c #FFFEAD",
+"~ c #FFFC00",
+"{ c #FFFD00",
+"] c #3F3100",
+"^ c #403200",
+"/ c #3F3300",
+"( c #3D2E00",
+"_ c #FFFFBE",
+": c #FFFF73",
+"< c #FFF800",
+"[ c #FFEF8F",
+"} c #3F3000",
+"| c #483800",
+"1 c #FEBDA8",
+"2 c #403100",
+"3 c #FFE76B",
+"4 c #FFE74D",
+"5 c #3E2F00",
+"6 c #FFEB00",
+"7 c #433300",
+"8 c #FEC6A0",
+"9 c #4A3A00",
+"0 c #FEBDA7",
+"a c #413100",
+"b c #FFFE00",
+"c c #FFFE6B",
+"d c #FFEB73",
+"e c #FFE200",
+"f c #FFD500",
+"g c #FFB700",
+"h c #FEB15F",
+"i c #4B3B00",
+"j c #FFE24D",
+"k c #FFCD00",
+"l c #FFA900",
+"m c #FFC300",
+"n c #4F3F00",
+"o c #463700",
+"p c #584800",
+"q c #FF9800",
+"r c #564600",
+"s c #4C3C00",
+"t c #534300",
+"u c #554600",
+"v c #524200",
+"w c #FF8300",
+"x c #504000",
+"y c #4E3E00",
+" ",
+" .. ",
+" .. .+ at . .. ",
+" .#..$%&*..=. ",
+" .-&......;>. ",
+" .,')!~{]^/ ",
+" .(_:~<[<<<}| ",
+" .12~<234566789 ",
+".0abcdaee5ffg9hi",
+" 29<jeeffffklii ",
+" 9j6effffkmln ",
+" 9meoffkkpgqr ",
+" sgftuppfqr ",
+" vqmkkmglwx ",
+" ynqqqwys ",
+" i999 "};
diff --git a/src/images/rank0.xpm b/src/images/rank0.xpm
new file mode 100644
index 0000000..bb1082d
--- /dev/null
+++ b/src/images/rank0.xpm
@@ -0,0 +1,42 @@
+/* XPM */
+static const char * rank0_xpm[] = {
+"16 16 23 1",
+" c None",
+". c #CC7D00",
+"+ c #CC8B00",
+"@ c #FEE662",
+"# c #FEE038",
+"$ c #CC7300",
+"% c #CC8600",
+"& c #FFDF0B",
+"* c #CCA800",
+"= c #CCAD00",
+"- c #FEE538",
+"; c #CC6500",
+"> c #CC9000",
+", c #940000",
+"' c #B20000",
+") c #CCB200",
+"! c #FF6D01",
+"~ c #FEE74A",
+"{ c #CC9E00",
+"] c #FF4F01",
+"^ c #F82900",
+"/ c #FF2B01",
+"( c #D60000",
+" ",
+" ",
+" ",
+" .. ",
+" +@#$ ",
+" %&*=-; ",
+" $->,,=-; ",
+" $-*, '))! ",
+" ;~*, '){] ",
+" ^*, '{/ ",
+" (' '' ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/src/images/rank1.xpm b/src/images/rank1.xpm
new file mode 100644
index 0000000..02ad884
--- /dev/null
+++ b/src/images/rank1.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static const char * rank1_xpm[] = {
+"16 16 22 1",
+" c None",
+". c #CC7300",
+"+ c #CC6500",
+"@ c #FCFE38",
+"# c #EBEE00",
+"$ c #CACC00",
+"% c #CCB200",
+"& c #FF6D01",
+"* c #FCFE24",
+"= c #B20000",
+"- c #EECF00",
+"; c #FEEB6A",
+"> c #F7FA00",
+", c #CCBB00",
+"' c #FCFE4A",
+") c #D62300",
+"! c #FF4F01",
+"~ c #940000",
+"{ c #D60000",
+"] c #EEDA00",
+"^ c #941800",
+"/ c #7C0000",
+" ",
+" ",
+" ",
+" .+ ",
+" .@#+ ",
+" .@$%$& ",
+" .*%==%$& ",
+" +$-=;>=%$& ",
+" +#,='%%$=,$) ",
+" !,=#%~~%$=,{ ",
+" {=#%~ ~%$== ",
+" =#]~ ~,$~ ",
+" ~,~ ~,^ ",
+" ~/ ~/ ",
+" ",
+" "};
diff --git a/src/images/rank2.xpm b/src/images/rank2.xpm
new file mode 100644
index 0000000..18e83de
--- /dev/null
+++ b/src/images/rank2.xpm
@@ -0,0 +1,51 @@
+/* XPM */
+static const char * rank2_xpm[] = {
+"16 16 32 1",
+" c None",
+". c #EE8600",
+"+ c #CC6500",
+"@ c #FCFE38",
+"# c #FCFE4A",
+"$ c #EE9D00",
+"% c #CACC00",
+"& c #CCBB00",
+"* c #FCFE56",
+"= c #CC7300",
+"- c #E76B6B",
+"; c #E24E4E",
+"> c #CCB200",
+", c #B20000",
+"' c #FF950B",
+") c #DA8484",
+"! c #EEDA00",
+"~ c #940000",
+"{ c #FCFE24",
+"] c #D36B6B",
+"^ c #C02A2A",
+"/ c #FCFF0B",
+"( c #C16B6B",
+"_ c #7C0000",
+": c #B26C6C",
+"< c #680000",
+"[ c #AE0000",
+"} c #BC2A2A",
+"| c #A34D4D",
+"1 c #CCB600",
+"2 c #6E0000",
+"3 c #922A2A",
+" .+ ",
+" .@#+ ",
+" $#%&*+ ",
+" =@&-;&@+ ",
+" =#>;##,&@+ ",
+" '#%,#&&#,&@, ",
+" )!,@&~,&{~&~ ",
+" ]^{&~#{~&/~~ ",
+" (*&~#%%{~&@_ ",
+" :!~*%<<%@[&_ ",
+" :}@%_ ~&#~_ ",
+" |@12 _%#_ ",
+" 3&_ _&< ",
+" _< _< ",
+" ",
+" "};
diff --git a/src/images/rank3.xpm b/src/images/rank3.xpm
new file mode 100644
index 0000000..2bfb657
--- /dev/null
+++ b/src/images/rank3.xpm
@@ -0,0 +1,55 @@
+/* XPM */
+static const char * rank3_xpm[] = {
+"16 16 36 1",
+" c None",
+". c #A46C00",
+"+ c #FBE633",
+"@ c #FDE629",
+"# c #A49600",
+"$ c #A45D00",
+"% c #FAFD23",
+"& c #D62300",
+"* c #FDE623",
+"= c #FF6D01",
+"- c #D60000",
+"; c #FDE909",
+"> c #FDE51D",
+", c #FAFD13",
+"' c #D4C200",
+") c #FF4F01",
+"! c #FF2B01",
+"~ c #FDEA13",
+"{ c #B20000",
+"] c #F6E202",
+"^ c #B21D00",
+"/ c #681100",
+"( c #7C1400",
+"_ c #BEAE00",
+": c #940000",
+"< c #7C0000",
+"[ c #941800",
+"} c #B23F00",
+"| c #FF7901",
+"1 c #D62800",
+"2 c #FAFD09",
+"3 c #FAFD25",
+"4 c #A46800",
+"5 c #A47B00",
+"6 c #682000",
+"7 c #680000",
+" .. ",
+" .++. ",
+" .@##@$ ",
+" $%#&&#*= ",
+" $%#-;;-#>= ",
+" =,#-;##;-#'= ",
+" )#-;#&&#;-#) ",
+" !-;#->~{#;-) ",
+" &;#{]##]{#]& ",
+" -#^]#/(_;{#& ",
+" {:;#< :#~:^ ",
+" :;#[ }#~( ",
+" :#:{ |1_/ ",
+" :#234445>]'/ ",
+" ::##]]]#/6 ",
+" 777777 "};
diff --git a/src/images/rank4.xpm b/src/images/rank4.xpm
new file mode 100644
index 0000000..0e035eb
--- /dev/null
+++ b/src/images/rank4.xpm
@@ -0,0 +1,47 @@
+/* XPM */
+static const char * rank4_xpm[] = {
+"16 16 28 1",
+" c None",
+". c #694AB2",
+"+ c #8C8C8C",
+"@ c #EFAAFF",
+"# c #CD92FF",
+"$ c #B07DFF",
+"% c #EAEAEA",
+"& c #976BFF",
+"* c #C9C9C9",
+"= c #D0D0D0",
+"- c #F3F3F3",
+"; c #FFFFFF",
+"> c #999999",
+", c #4C4C4C",
+"' c #B2B2B2",
+") c #949494",
+"! c #F7F7F7",
+"~ c #5B5B5B",
+"{ c #989797",
+"] c #D1D0D0",
+"^ c #B9B8B8",
+"/ c #8B8A8A",
+"( c #D8D8D8",
+"_ c #3F3F3F",
+": c #6D6D6D",
+"< c #353535",
+"[ c #C2C1C1",
+"} c #E5E4E4",
+" ....+++.... ",
+" .@#$%%%$#@. ",
+" .#&&***&&#. ",
+" .$&&***&&$. ",
+" .$&*%*&$. ",
+" .$%+%$. ",
+" .+=+. ",
+" -;> ",
+" =;, ",
+" ');%;'' ",
+" ==;!--!-;>~ ",
+" ~,{];^/,, ",
+" ,;(-_ ",
+" :;^<[}: ",
+" ~[< >], ",
+" ,_ ~, "};
diff --git a/src/images/rank5.xpm b/src/images/rank5.xpm
new file mode 100644
index 0000000..ff13db0
--- /dev/null
+++ b/src/images/rank5.xpm
@@ -0,0 +1,69 @@
+/* XPM */
+static const char * rank5_xpm[] = {
+"16 16 50 1",
+" c None",
+". c #706D34",
+"+ c #565656",
+"@ c #2D5C91",
+"# c #FFFFFF",
+"$ c #FCFE72",
+"% c #6CD7FE",
+"& c #FCFE36",
+"* c #ACAAAA",
+"= c #FCFE5A",
+"- c #E8E8E8",
+"; c #EEE330",
+"> c #50A0FA",
+", c #939393",
+"' c #C7C7C7",
+") c #FCFE48",
+"! c #676767",
+"~ c #87833F",
+"{ c #CC9E00",
+"] c #FAD300",
+"^ c #FCFE4A",
+"/ c #FF7901",
+"( c #F4A600",
+"_ c #FCFF0B",
+": c #D62300",
+"< c #CC8600",
+"[ c #FEEC24",
+"} c #FEEF4A",
+"| c #EBEE00",
+"1 c #CCBB00",
+"2 c #FEEE38",
+"3 c #FFEB0B",
+"4 c #CC6500",
+"5 c #D64100",
+"6 c #B20000",
+"7 c #CC7800",
+"8 c #CC9000",
+"9 c #FEF056",
+"0 c #941800",
+"a c #B21D00",
+"b c #CCA800",
+"c c #7C1400",
+"d c #800000",
+"e c #CCB200",
+"f c #FF6D01",
+"g c #680000",
+"h c #D65B00",
+"i c #CCA300",
+"j c #D60000",
+"k c #940000",
+" .+. at .+.@.+. ",
+" .#$%&*&%=-. ",
+" .#;>;,;>;-. ",
+" .-;>;,;>;-. ",
+" .';>;';>;-. ",
+" +)>)!&>=+ ",
+" .%~{~%. ",
+" @]^/@ ",
+" (_: ",
+" {<^[}{{ ",
+" {{^|1213245 ",
+" :67898<0a ",
+" a2bbc ",
+" <[7d<e: ",
+" f8g hi6 ",
+" jk 66 "};
diff --git a/src/images/rank6.xpm b/src/images/rank6.xpm
new file mode 100644
index 0000000..9a43eec
--- /dev/null
+++ b/src/images/rank6.xpm
@@ -0,0 +1,72 @@
+/* XPM */
+static const char * rank6_xpm[] = {
+"16 16 53 1",
+" c None",
+". c #C9C9C9",
+"+ c #CBCBCB",
+"@ c #FDFDFD",
+"# c #ADADAD",
+"$ c #FBFBFB",
+"% c #838383",
+"& c #B4B4B4",
+"* c #F9F9F9",
+"= c #E2E2E2",
+"- c #909090",
+"; c #8A8A8A",
+"> c #D1D1D1",
+", c #D0D0D0",
+"' c #EEEEEE",
+") c #F8F8F8",
+"! c #F6F6F6",
+"~ c #E6E6E6",
+"{ c #C2C2C2",
+"] c #D6D6D6",
+"^ c #CCCCCC",
+"/ c #B7B7B7",
+"( c #FCFCFC",
+"_ c #F3F3F3",
+": c #F5F5F5",
+"< c #F2F2F2",
+"[ c #9C9C9C",
+"} c #757575",
+"| c #8D8D8D",
+"1 c #A5A5A5",
+"2 c #C3C3C3",
+"3 c #F7F7F7",
+"4 c #AEAEAE",
+"5 c #B0B0B0",
+"6 c #999999",
+"7 c #595959",
+"8 c #303030",
+"9 c #727272",
+"0 c #3D3D3D",
+"a c #4B4B4B",
+"b c #373737",
+"c c #E9E9E9",
+"d c #E0E0E0",
+"e c #AAAAAA",
+"f c #BABABA",
+"g c #646464",
+"h c #F0F0F0",
+"i c #EBEBEB",
+"j c #808080",
+"k c #A2A2A2",
+"l c #565656",
+"m c #ECECEC",
+"n c #242424",
+" . ",
+" +@# ",
+" .$% ",
+" &$*=- ",
+" &$*=; ",
+" >>,>')!=~{]]^ ",
+"/!*!(*_*:($*$<[ ",
+" }|1|23*_45167 ",
+" 8891+*,150a ",
+" b<$c<d0 ",
+" e<*fgchi- ",
+" &<3|g1ch% ",
+" .<3jg891c<% ",
+" k3jl8 a61m% ",
+" %68n 8a6a ",
+" 8 0 "};
diff --git a/src/images/rank_unknown.xpm b/src/images/rank_unknown.xpm
new file mode 100644
index 0000000..6ce6cf4
--- /dev/null
+++ b/src/images/rank_unknown.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static const char * rank_unknown_xpm[] = {
+"16 16 5 1",
+" c None",
+". c #000000",
+"+ c #C7EFFF",
+"@ c #00B4FF",
+"# c #018EC9",
+" ",
+" ",
+" ",
+" ....... ",
+" .++++++. ",
+" .++ at ..@@#. ",
+" .+ at .@@.@#. ",
+" .+@@@@.@#. ",
+" .+@@..@@#. ",
+" .+@@@@@@#. ",
+" .+@@..@##. ",
+" ..######. ",
+" ...... ",
+" ",
+" ",
+" "};
diff --git a/src/images/ready_q.xpm b/src/images/ready_q.xpm
new file mode 100644
index 0000000..fb0508f
--- /dev/null
+++ b/src/images/ready_q.xpm
@@ -0,0 +1,59 @@
+/* XPM */
+static const char * ready_q_xpm[] = {
+"16 16 40 1",
+" c None",
+". c #595959",
+"+ c #000000",
+"@ c #04A618",
+"# c #02FF20",
+"$ c #00FF1E",
+"% c #00A613",
+"& c #1DFF3D",
+"* c #12FF33",
+"= c #9CFFBA",
+"- c #00EF1C",
+"; c #32FF53",
+"> c #36FF57",
+", c #DAFFE6",
+"' c #00E31A",
+") c #00D819",
+"! c #23A638",
+"~ c #30FF51",
+"{ c #12F92D",
+"] c #04EA1F",
+"^ c #00E61B",
+"/ c #008C10",
+"( c #19FF3A",
+"_ c #A5FFC0",
+": c #8AFFA5",
+"< c #4DFF68",
+"[ c #06FF25",
+"} c #69FF84",
+"| c #C7EFFF",
+"1 c #02FF21",
+"2 c #2DFF48",
+"3 c #00B4FF",
+"4 c #018EC9",
+"5 c #00FF1F",
+"6 c #0CF227",
+"7 c #00A614",
+"8 c #01EC1D",
+"9 c #02E81D",
+"0 c #00EA1B",
+"a c #00E71B",
+" ",
+" .++++. ",
+" +@#$$$%+ ",
+" +&*====$-+ ",
+" +;>=,====')+ ",
+" .!~,,,={]^^'/. ",
+" +(=,_:<+++++++ ",
+" +[===}+||||||+ ",
+" +1==2+||3++334+",
+" +5==6+|3+33+34+",
+" .78=9+|3333+34+",
+" +0a^+|33++334+",
+" +^^+|3333334+",
+" +/+|33++344+",
+" .++444444+ ",
+" ++++++ "};
diff --git a/src/images/ready_unsync.xpm b/src/images/ready_unsync.xpm
new file mode 100644
index 0000000..7da0048
--- /dev/null
+++ b/src/images/ready_unsync.xpm
@@ -0,0 +1,66 @@
+/* XPM */
+static const char * ready_unsync_xpm[] = {
+"16 16 47 1",
+" c None",
+". c #595959",
+"+ c #000000",
+"@ c #04A618",
+"# c #02FF20",
+"$ c #00FF1E",
+"% c #00A613",
+"& c #1DFF3D",
+"* c #12FF33",
+"= c #9CFFBA",
+"- c #00EF1C",
+"; c #32FF53",
+"> c #36FF57",
+", c #DAFFE6",
+"' c #00E31A",
+") c #00D819",
+"! c #23A638",
+"~ c #30FF51",
+"{ c #12F92D",
+"] c #04EA1F",
+"^ c #00E61B",
+"/ c #008C10",
+"( c #19FF3A",
+"_ c #A5FFC0",
+": c #8AFFA5",
+"< c #4DFF68",
+"[ c #1AFF35",
+"} c #FFE57C",
+"| c #06FF25",
+"1 c #69FF84",
+"2 c #43FF5E",
+"3 c #18FE33",
+"4 c #00B816",
+"5 c #02FF21",
+"6 c #2DFF48",
+"7 c #2EFF49",
+"8 c #20FF3B",
+"9 c #FFCC00",
+"0 c #B38F00",
+"a c #00FF1F",
+"b c #0CF227",
+"c c #08EE23",
+"d c #00A614",
+"e c #01EC1D",
+"f c #02E81D",
+"g c #00EA1B",
+"h c #00E71B",
+" ",
+" .++++. ",
+" +@#$$$%+ ",
+" +&*====$-+ ",
+" +;>=,====')+ ",
+" .!~,,,={]+^'/. ",
+" +(=,_:<[+}+))+ ",
+" +|===123+}+)4+ ",
+" +5==678+}90+4+ ",
+" +a==bbc+}+0+4+ ",
+" .de=ff+}9+90+. ",
+" +gh^^+}9+90+ ",
+" +^^+}999990+ ",
+" +/+}99+990+ ",
+" +}00000000+",
+" +++++++++++"};
diff --git a/src/images/reload_map.xpm b/src/images/reload_map.xpm
new file mode 100644
index 0000000..520e2ad
--- /dev/null
+++ b/src/images/reload_map.xpm
@@ -0,0 +1,203 @@
+/* XPM */
+static const char * reload_map_xpm[] = {
+"22 22 178 2",
+" c None",
+". c #AFBDCA",
+"+ c #7C97AF",
+"@ c #ADBAC9",
+"# c #699EBF",
+"$ c #89A2B8",
+"% c #6EAECE",
+"& c #6AA9CA",
+"* c #8EA6BB",
+"= c #A4B4C4",
+"- c #8EA3B8",
+"; c #869FB6",
+"> c #85A0B7",
+", c #6385A4",
+"' c #6FB4D4",
+") c #73C0DF",
+"! c #69A8C9",
+"~ c #94AABE",
+"{ c #ABBAC8",
+"] c #5C84A5",
+"^ c #407DA7",
+"/ c #4F97BE",
+"( c #58A6CC",
+"_ c #5AADD3",
+": c #5FB4D8",
+"< c #66BBDD",
+"[ c #6CC1E1",
+"} c #70C3E3",
+"| c #73C4E3",
+"1 c #79C5E3",
+"2 c #66A5C6",
+"3 c #99AEC1",
+"4 c #7A96B0",
+"5 c #437EA8",
+"6 c #3986B4",
+"7 c #3A8DBB",
+"8 c #4298C3",
+"9 c #49A2CB",
+"0 c #51ACD3",
+"a c #58B5DA",
+"b c #5FBCE0",
+"c c #66C3E4",
+"d c #6DC7E7",
+"e c #72C9E7",
+"f c #78C8E6",
+"g c #7EC7E4",
+"h c #61A0C1",
+"i c #A1B3C4",
+"j c #94A9BD",
+"k c #3E7DA9",
+"l c #2A78AA",
+"m c #3182B2",
+"n c #398EBC",
+"o c #4199C5",
+"p c #48A4CD",
+"q c #50AED5",
+"r c #57B7DC",
+"s c #57BDE1",
+"t c #54C0E6",
+"u c #55C4E9",
+"v c #5CC5E9",
+"w c #67C5E7",
+"x c #79C8E5",
+"y c #83C8E3",
+"z c #5C98BB",
+"A c #A8B9C8",
+"B c #43759D",
+"C c #2574A7",
+"D c #2877A9",
+"E c #3082B2",
+"F c #388EBC",
+"G c #3F99C5",
+"H c #3FA0CC",
+"I c #30A1CF",
+"J c #22A2D3",
+"K c #1DA9DA",
+"L c #1FB2E2",
+"M c #20B9E8",
+"N c #20B6E6",
+"O c #1EADDE",
+"P c #1EA5D6",
+"Q c #2EA3D2",
+"R c #4EABD3",
+"S c #407FA7",
+"T c #BBC6D1",
+"U c #3274A2",
+"V c #2071A5",
+"W c #2776A9",
+"X c #2E82B2",
+"Y c #358DBB",
+"Z c #278CBE",
+"` c #198DC1",
+" . c #1A96C9",
+".. c #1CA0D2",
+"+. c #20B9E9",
+"@. c #1CA4D6",
+"#. c #1B9BCE",
+"$. c #3397C4",
+"%. c #698DAB",
+"&. c #99ABBD",
+"*. c #337AAA",
+"=. c #1F70A5",
+"-. c #2575A8",
+";. c #297EB0",
+">. c #1A7CB1",
+",. c #1682B8",
+"'. c #188CC0",
+"). c #1995C8",
+"!. c #1B9DD0",
+"~. c #1DA6D7",
+"{. c #1FB0E1",
+"]. c #1EAADB",
+"^. c #1CA2D4",
+"/. c #329FCC",
+"(. c #5F88A8",
+"_. c #97ABBD",
+":. c #3179A9",
+"<. c #1D6FA4",
+"[. c #2272A6",
+"}. c #1570A7",
+"|. c #1477AD",
+"1. c #1580B5",
+"2. c #1789BD",
+"3. c #1991C5",
+"4. c #1A99CC",
+"5. c #1CA1D3",
+"6. c #1DA6D8",
+"7. c #1DA8D9",
+"8. c #1CA4D5",
+"9. c #31A2D0",
+"0. c #5785A7",
+"a. c #AFBCCA",
+"b. c #3076A5",
+"c. c #1B6EA3",
+"d. c #1469A0",
+"e. c #116BA3",
+"f. c #1374AB",
+"g. c #157DB3",
+"h. c #248CBD",
+"i. c #3190BD",
+"j. c #2E85B2",
+"k. c #3084AF",
+"l. c #3384AF",
+"m. c #33A6D3",
+"n. c #2EA2D0",
+"o. c #5284A7",
+"p. c #326F9C",
+"q. c #11679F",
+"r. c #1169A1",
+"s. c #1371A8",
+"t. c #327CA9",
+"u. c #6F92AE",
+"v. c #A8B7C7",
+"w. c #3298C5",
+"x. c #2B9FCE",
+"y. c #4B81A6",
+"z. c #5F87A8",
+"A. c #2B76A6",
+"B. c #93A8BC",
+"C. c #4098C2",
+"D. c #457FA5",
+"E. c #2771A4",
+"F. c #316B98",
+"G. c #41749B",
+"H. c #4F7EA3",
+"I. c #12679F",
+"J. c #336C98",
+"K. c #2D71A1",
+"L. c #2D6B99",
+"M. c #8BA3BA",
+"N. c #206DA1",
+"O. c #2C72A3",
+"P. c #ACBAC8",
+"Q. c #7494AF",
+"R. c #347AA9",
+"S. c #7895AF",
+"T. c #809BB4",
+"U. c #446F96",
+" ",
+" . + ",
+" @ # $ ",
+" @ % & * ",
+" = - ; > > , ' ) ! ~ ",
+" { ] ^ / ( _ : < [ } | 1 2 3 ",
+" 4 5 6 7 8 9 0 a b c d e f g h i ",
+" j k l m n o p q r s t u v w x y z A ",
+" B C D E F G H I J K L M N O P Q R S ",
+" T U V W X Y Z ` ...K L +.N O @.#.$.%. ",
+" &.*.=.-.;.>.,.'.).!.~.O L {.].^./.(. ",
+" _.:.<.[.}.|.1.2.3.4.5.6.K 7.8.9.0. ",
+" a.b.c.d.e.f.g.h.i.j.k.l.m...n.o. ",
+" p.d.q.r.s.t.u.v. = w.x.y. ",
+" z.q.q.q.A.B. { C.D. ",
+" = E.q.q.F. { G. ",
+" H.I.q.J. ",
+" K.q.L. ",
+" M.N.O.P. ",
+" Q.R.S. ",
+" T.U. ",
+" "};
diff --git a/src/images/replay_icon.png.h b/src/images/replay_icon.png.h
new file mode 100644
index 0000000..312567e
--- /dev/null
+++ b/src/images/replay_icon.png.h
@@ -0,0 +1,537 @@
+/* replay_icon.png - 4267 bytes */
+ static const unsigned char replay_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x0a,
+ 0x07, 0x16, 0x05, 0x3a, 0x46, 0x0e, 0xe6, 0xcf,
+ 0x00, 0x00, 0x10, 0x2b, 0x49, 0x44, 0x41, 0x54,
+ 0x58, 0x09, 0x01, 0x20, 0x10, 0xdf, 0xef, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e, 0x2e, 0x23,
+ 0x03, 0x03, 0x03, 0x3d, 0xfe, 0xfe, 0xfe, 0x38,
+ 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, 0x1a,
+ 0xe2, 0xe2, 0xe2, 0x48, 0xcd, 0xcd, 0xcd, 0xca,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x31, 0x31, 0x31, 0x05, 0xfd, 0xfd, 0xfd,
+ 0x32, 0x03, 0x03, 0x03, 0x3c, 0x04, 0x04, 0x04,
+ 0x39, 0x2f, 0x2f, 0x2f, 0x3c, 0x27, 0x27, 0x27,
+ 0x16, 0x30, 0x30, 0x30, 0x00, 0xe8, 0xe8, 0xe8,
+ 0x01, 0xaa, 0xaa, 0xaa, 0x00, 0x2b, 0x2b, 0x2b,
+ 0x00, 0xde, 0xde, 0xde, 0x5b, 0x00, 0x00, 0x00,
+ 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x2f, 0x2f, 0x2f, 0x12, 0x00, 0x00,
+ 0x00, 0x39, 0x01, 0x01, 0x01, 0x3b, 0x19, 0x19,
+ 0x19, 0x38, 0x2d, 0x2d, 0x2d, 0x39, 0xfd, 0xfd,
+ 0xfd, 0x07, 0x02, 0x02, 0x02, 0x01, 0xed, 0xed,
+ 0xed, 0x00, 0x5a, 0x5a, 0x5a, 0x00, 0x1c, 0x1c,
+ 0x1c, 0x00, 0xfa, 0xfa, 0xfa, 0x00, 0x72, 0x72,
+ 0x72, 0x00, 0xd3, 0xd3, 0xd3, 0x00, 0xfe, 0xfe,
+ 0xfe, 0x00, 0x1b, 0x1b, 0x1b, 0x3a, 0xd1, 0xd1,
+ 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x2e, 0x2e, 0x2e, 0x23, 0x03,
+ 0x03, 0x03, 0x3d, 0xfd, 0xfd, 0xfd, 0x38, 0x18,
+ 0x18, 0x18, 0x3c, 0x0f, 0x0f, 0x0f, 0x2a, 0x21,
+ 0x21, 0x21, 0x00, 0x5e, 0x5e, 0x5e, 0x01, 0x0f,
+ 0x0f, 0x0f, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0x48,
+ 0x48, 0x48, 0x00, 0xe5, 0xe5, 0xe5, 0x00, 0x1a,
+ 0x1a, 0x1a, 0x00, 0x71, 0x71, 0x71, 0x00, 0xfa,
+ 0xfa, 0xfa, 0x00, 0xe3, 0xe3, 0xe3, 0x00, 0xd3,
+ 0xd3, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea,
+ 0xea, 0xea, 0x00, 0x44, 0x44, 0x44, 0x31, 0xe5,
+ 0xe5, 0xe5, 0x0b, 0xd1, 0xd1, 0xd1, 0xf5, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x31, 0x31, 0x31, 0x05, 0xfd, 0xfd, 0xfd, 0x32,
+ 0x04, 0x04, 0x04, 0x3c, 0x07, 0x07, 0x07, 0x38,
+ 0x2a, 0x2a, 0x2a, 0x3d, 0x2b, 0x2b, 0x2b, 0x16,
+ 0x33, 0x33, 0x33, 0x00, 0xf7, 0xf7, 0xf7, 0x01,
+ 0x95, 0x95, 0x95, 0x00, 0xd6, 0xd6, 0xd6, 0x00,
+ 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf1, 0xf1, 0xf1, 0x00, 0xb4, 0xb4, 0xb4, 0x00,
+ 0xe5, 0xe5, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x4c, 0x4c, 0x00, 0x01, 0x01, 0x01, 0x00,
+ 0x03, 0x03, 0x03, 0x00, 0xd9, 0xd9, 0xd9, 0x00,
+ 0x54, 0x54, 0x54, 0x00, 0x16, 0x16, 0x16, 0x00,
+ 0x1c, 0x1c, 0x1c, 0xff, 0xd8, 0xd8, 0xd8, 0xf7,
+ 0xfd, 0xfd, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30,
+ 0x41, 0x00, 0x00, 0x00, 0x45, 0x1c, 0x1c, 0x1c,
+ 0x39, 0x30, 0x30, 0x30, 0x38, 0x10, 0x10, 0x10,
+ 0x07, 0xf2, 0xf2, 0xf2, 0x01, 0xe8, 0xe8, 0xe8,
+ 0x00, 0x24, 0x24, 0x24, 0x00, 0x58, 0x58, 0x58,
+ 0x00, 0xfa, 0xfa, 0xfa, 0x00, 0x6a, 0x6a, 0x6a,
+ 0x00, 0xb6, 0xb6, 0xb6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xb5, 0xb5,
+ 0x00, 0x1b, 0x1b, 0x1b, 0x00, 0x22, 0x22, 0x22,
+ 0x00, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd0, 0xd0, 0xd0, 0xfe, 0xcd, 0xcd, 0xcd,
+ 0x01, 0xef, 0xef, 0xef, 0xd8, 0xd9, 0xd9, 0xd9,
+ 0xc4, 0x05, 0x05, 0x05, 0xc7, 0xfe, 0xfe, 0xfe,
+ 0xba, 0xd4, 0xd4, 0xd4, 0xf4, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x2e, 0x2e, 0x2e, 0x30, 0x57, 0x57,
+ 0x57, 0xcd, 0x60, 0x60, 0x60, 0x02, 0xa3, 0xa3,
+ 0xa3, 0x00, 0xda, 0xda, 0xda, 0x00, 0xd6, 0xd6,
+ 0xd6, 0x00, 0xc8, 0xc8, 0xc8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xaf, 0xaf, 0xaf, 0x00, 0x33, 0x33,
+ 0x33, 0x00, 0xed, 0xed, 0xed, 0x00, 0x37, 0x37,
+ 0x37, 0x00, 0xfa, 0xfa, 0xfa, 0x00, 0x2a, 0x2a,
+ 0x2a, 0x00, 0xb1, 0xb1, 0xb1, 0x00, 0x05, 0x05,
+ 0x05, 0x00, 0xf7, 0xf7, 0xf7, 0x00, 0x91, 0x91,
+ 0x91, 0x00, 0xef, 0xef, 0xef, 0xff, 0xef, 0xef,
+ 0xef, 0xfa, 0xff, 0xff, 0xff, 0xc8, 0xeb, 0xeb,
+ 0xeb, 0xc8, 0x00, 0x00, 0x00, 0xc4, 0xff, 0xff,
+ 0xff, 0xc6, 0xd1, 0xd1, 0xd1, 0xee, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x10,
+ 0x10, 0x10, 0x01, 0x10, 0x10, 0x10, 0x00, 0xd5,
+ 0xd5, 0xd5, 0x00, 0x7a, 0x7a, 0x7a, 0x00, 0x9d,
+ 0x9d, 0x9d, 0x00, 0xd3, 0xd3, 0xd3, 0x00, 0x19,
+ 0x19, 0x19, 0x00, 0x34, 0x34, 0x34, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xd2, 0xd2, 0xd2, 0x00, 0x4e,
+ 0x4e, 0x4e, 0x00, 0x16, 0x16, 0x16, 0x00, 0x2a,
+ 0x2a, 0x2a, 0xff, 0xae, 0xae, 0xae, 0x00, 0xdf,
+ 0xdf, 0xdf, 0xec, 0xca, 0xca, 0xca, 0xc2, 0xfc,
+ 0xfc, 0xfc, 0xc9, 0x01, 0x01, 0x01, 0xc3, 0xfc,
+ 0xfc, 0xfc, 0xce, 0xd5, 0xd5, 0xd5, 0xfa, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x27, 0x27, 0x27, 0xda,
+ 0xdf, 0xdf, 0xdf, 0xee, 0x00, 0x00, 0x00, 0x13,
+ 0xfd, 0xfd, 0xfd, 0x00, 0xfb, 0xfb, 0xfb, 0x00,
+ 0x46, 0x46, 0x46, 0x00, 0xdc, 0xdc, 0xdc, 0x00,
+ 0x32, 0x32, 0x32, 0x00, 0xf7, 0xf7, 0xf7, 0x00,
+ 0xd0, 0xd0, 0xd0, 0xfe, 0xbf, 0xbf, 0xbf, 0x01,
+ 0xf0, 0xf0, 0xf0, 0xd7, 0xd9, 0xd9, 0xd9, 0xc5,
+ 0xc8, 0xc8, 0xc8, 0xc7, 0xfb, 0xfb, 0xfb, 0xc3,
+ 0xd3, 0xd3, 0xd3, 0xdc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab,
+ 0xff, 0x3d, 0x3d, 0x3d, 0xc3, 0x00, 0x00, 0x00,
+ 0x50, 0xfb, 0xfb, 0xfb, 0x00, 0xe2, 0xe2, 0xe2,
+ 0x00, 0xf6, 0xf6, 0xf6, 0x00, 0x4e, 0x4e, 0x4e,
+ 0x00, 0x9c, 0x9c, 0x9c, 0xff, 0xa9, 0xa9, 0xa9,
+ 0xa9, 0x05, 0x05, 0x05, 0xa5, 0xff, 0xff, 0xff,
+ 0xc6, 0xd1, 0xd1, 0xd1, 0xee, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x30, 0x5e, 0x27, 0x27,
+ 0x27, 0xa0, 0xf5, 0xf5, 0xf5, 0x01, 0x58, 0x58,
+ 0x58, 0x00, 0xf6, 0xf6, 0xf6, 0x00, 0xfa, 0xfa,
+ 0xfa, 0x00, 0xf6, 0xf6, 0xf6, 0x00, 0xa5, 0xa5,
+ 0xa5, 0xf7, 0x23, 0x23, 0x23, 0xea, 0x06, 0x06,
+ 0x06, 0x04, 0xfe, 0xfe, 0xfe, 0x05, 0x12, 0x12,
+ 0x12, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfa, 0xfa, 0xfa, 0x08, 0xf2, 0xf2,
+ 0xf2, 0x01, 0x01, 0x01, 0x01, 0x00, 0x05, 0x05,
+ 0x05, 0x00, 0x16, 0x16, 0x16, 0x03, 0x00, 0x00,
+ 0x00, 0x04, 0xfd, 0xfd, 0xfd, 0x00, 0xe9, 0xe9,
+ 0xe9, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0xfd, 0xfd,
+ 0xfd, 0x06, 0x22, 0x22, 0x22, 0x00, 0x04, 0x04,
+ 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xb4, 0xb4,
+ 0xb4, 0x81, 0xcf, 0xcf, 0xcf, 0x81, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x0e, 0x70,
+ 0x70, 0x70, 0x01, 0x83, 0x83, 0x83, 0x00, 0x11,
+ 0x11, 0x11, 0x00, 0xef, 0xef, 0xef, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x63,
+ 0x63, 0x63, 0x09, 0xa7, 0xa7, 0xa7, 0x1f, 0x07,
+ 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b,
+ 0x1b, 0x1b, 0x00, 0x6d, 0x6d, 0x6d, 0x00, 0x02,
+ 0x02, 0x02, 0x00, 0xf4, 0xf4, 0xf4, 0x00, 0x74,
+ 0x74, 0x74, 0x00, 0xef, 0xef, 0xef, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0x59, 0x59, 0x59, 0x00, 0x30,
+ 0x30, 0x30, 0x00, 0x01, 0x01, 0x01, 0x00, 0x81,
+ 0x81, 0x81, 0x00, 0xc5, 0xc5, 0xc5, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x2e, 0x2e, 0x2e, 0x00, 0x6e,
+ 0x6e, 0x6e, 0x00, 0x04, 0x04, 0x04, 0x01, 0xdb,
+ 0xdb, 0xdb, 0x47, 0xcf, 0xcf, 0xcf, 0x81, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0xf8, 0x00,
+ 0xbe, 0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x00,
+ 0xd4, 0xd4, 0xd4, 0x00, 0xea, 0xea, 0xea, 0x00,
+ 0xc0, 0xc0, 0xc0, 0x00, 0x27, 0x27, 0x27, 0x00,
+ 0x3c, 0x3c, 0x3c, 0x00, 0x02, 0x02, 0x02, 0x00,
+ 0x3c, 0x3c, 0x3c, 0x00, 0x7c, 0x7c, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xb7, 0xb7, 0xb7, 0x00, 0x08, 0x08, 0x08, 0x00,
+ 0x62, 0x62, 0x62, 0x00, 0xa4, 0xa4, 0xa4, 0x00,
+ 0xf0, 0xf0, 0xf0, 0x00, 0xd3, 0xd3, 0xd3, 0x00,
+ 0x39, 0x39, 0x39, 0x00, 0x37, 0x37, 0x37, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, 0x19,
+ 0x37, 0x48, 0x48, 0x48, 0x49, 0x2b, 0x2b, 0x2b,
+ 0x00, 0xac, 0xac, 0xac, 0x00, 0xc9, 0xc9, 0xc9,
+ 0x00, 0xd7, 0xd7, 0xd7, 0x00, 0x12, 0x12, 0x12,
+ 0x00, 0x26, 0x26, 0x26, 0x00, 0x3f, 0x3f, 0x3f,
+ 0x00, 0x3c, 0x3c, 0x3c, 0x00, 0xcb, 0xcb, 0xcb,
+ 0x00, 0x0c, 0x0c, 0x0c, 0x00, 0xdc, 0xdc, 0xdc,
+ 0x00, 0x4d, 0x4d, 0x4d, 0x00, 0x07, 0x07, 0x07,
+ 0x00, 0x2c, 0x2c, 0x2c, 0x00, 0xdf, 0xdf, 0xdf,
+ 0x00, 0xfc, 0xfc, 0xfc, 0x00, 0xfe, 0xfe, 0xfe,
+ 0x00, 0x0a, 0x0a, 0x0a, 0x00, 0x30, 0x30, 0x30,
+ 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x24, 0x24, 0x24,
+ 0x00, 0xd7, 0xd7, 0xd7, 0x00, 0x12, 0x12, 0x12,
+ 0x00, 0xdd, 0xdd, 0xdd, 0x00, 0x4f, 0x4f, 0x4f,
+ 0x00, 0xb3, 0xb3, 0xb3, 0xe6, 0xd4, 0xd4, 0xd4,
+ 0x9b, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e,
+ 0x2e, 0x40, 0x44, 0x44, 0x44, 0xbe, 0x22, 0x22,
+ 0x22, 0x01, 0xec, 0xec, 0xec, 0x00, 0xdf, 0xdf,
+ 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07,
+ 0x07, 0x00, 0x27, 0x27, 0x27, 0x00, 0xfd, 0xfd,
+ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0xdb,
+ 0xdb, 0x00, 0xf7, 0xf7, 0xf7, 0x00, 0xfd, 0xfd,
+ 0xfd, 0x00, 0x19, 0x19, 0x19, 0x00, 0x14, 0x14,
+ 0x14, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0xf5, 0xf5,
+ 0xf5, 0x00, 0xd9, 0xd9, 0xd9, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x2c, 0x2c,
+ 0x2c, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xdc, 0xdc, 0xdc, 0x00, 0xf7, 0xf7,
+ 0xf7, 0x00, 0xfc, 0xfc, 0xfc, 0x00, 0x19, 0x19,
+ 0x19, 0x00, 0xc6, 0xc6, 0xc6, 0x95, 0xd1, 0xd1,
+ 0xd1, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0xb6, 0x40,
+ 0x40, 0x40, 0x49, 0xee, 0xee, 0xee, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 0xfe,
+ 0xfe, 0xfe, 0x00, 0xcf, 0xcf, 0xcf, 0x66, 0xe3,
+ 0xe3, 0xe3, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfa,
+ 0x0b, 0x0b, 0x0b, 0x00, 0xf6, 0xf6, 0xf6, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a,
+ 0x0a, 0x00, 0x20, 0x20, 0x20, 0x00, 0x42, 0x42,
+ 0x42, 0x00, 0xff, 0xff, 0xff, 0x00, 0x06, 0x06,
+ 0x06, 0x00, 0x42, 0x42, 0x42, 0x00, 0x3c, 0x3c,
+ 0x3c, 0x00, 0x67, 0x67, 0x67, 0x00, 0x04, 0x04,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0a,
+ 0x0a, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x20, 0x20, 0x00, 0x3b, 0x3b, 0x3b, 0x00, 0x2c,
+ 0x2c, 0x2c, 0x00, 0x2c, 0x2c, 0x2c, 0x00, 0x27,
+ 0x27, 0x27, 0x00, 0xec, 0xec, 0xec, 0x00, 0xf4,
+ 0xf4, 0xf4, 0x00, 0x05, 0x05, 0x05, 0x00, 0x24,
+ 0x24, 0x24, 0x00, 0xd7, 0xd7, 0xd7, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
+ 0x14, 0x14, 0x00, 0xf5, 0xf5, 0xf5, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xd3, 0xd3, 0xd3, 0x00, 0xb4, 0xb4, 0xb4, 0x00,
+ 0xe5, 0xe5, 0xe5, 0x00, 0x9b, 0x9b, 0x9b, 0x00,
+ 0xec, 0xec, 0xec, 0x00, 0xa4, 0xa4, 0xa4, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x00, 0xe0, 0xe0, 0xe0, 0x00,
+ 0x02, 0x02, 0x02, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x09, 0x09, 0x09,
+ 0x00, 0x16, 0x16, 0x16, 0x00, 0x09, 0x09, 0x09,
+ 0x00, 0x1b, 0x1b, 0x1b, 0x00, 0x16, 0x16, 0x16,
+ 0x00, 0xb9, 0xb9, 0xb9, 0x00, 0xf5, 0xf5, 0xf5,
+ 0x00, 0xd9, 0xd9, 0xd9, 0x00, 0xdb, 0xdb, 0xdb,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x08, 0x08, 0x08, 0x00, 0x1d, 0x1d, 0x1d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xea, 0xea, 0xea, 0x00, 0xf6, 0xf6, 0xf6,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe,
+ 0xfe, 0x00, 0xff, 0xff, 0xff, 0x00, 0xf6, 0xf6,
+ 0xf6, 0x00, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xa1, 0xa1, 0xa1, 0x00, 0xdc, 0xdc,
+ 0xdc, 0x00, 0xdc, 0xdc, 0xdc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x0b, 0x0b,
+ 0x0b, 0x00, 0xec, 0xec, 0xec, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x51, 0x51,
+ 0x51, 0x00, 0x02, 0x02, 0x02, 0x00, 0xd8, 0xd8,
+ 0xd8, 0x00, 0xd3, 0xd3, 0xd3, 0x00, 0x0c, 0x0c,
+ 0x0c, 0x00, 0xf6, 0xf6, 0xf6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0xfe, 0xfe, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc9, 0xc9, 0xc9, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x5b, 0x5b, 0x5b, 0x00, 0xe7,
+ 0xe7, 0xe7, 0x00, 0x27, 0x27, 0x27, 0x00, 0xfd,
+ 0xfd, 0xfd, 0x00, 0xf4, 0xf4, 0xf4, 0x00, 0x27,
+ 0x27, 0x27, 0x00, 0x9d, 0x9d, 0x9d, 0x00, 0x04,
+ 0x04, 0x04, 0x00, 0x54, 0x54, 0x54, 0x00, 0xfa,
+ 0xfa, 0xfa, 0x00, 0x90, 0x90, 0x90, 0x00, 0xf1,
+ 0xf1, 0xf1, 0x00, 0xd9, 0xd9, 0xd9, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xfe, 0xfe, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x0e, 0x0e, 0x0e, 0x00, 0x17, 0x17, 0x17, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd4, 0xd4, 0xd4, 0x00,
+ 0xf0, 0xf0, 0xf0, 0x00, 0xe6, 0xe6, 0xe6, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0xe3, 0xe3, 0xe3, 0x00,
+ 0xc0, 0xc0, 0xc0, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x05, 0x05, 0x05, 0x00, 0xea, 0xea, 0xea, 0x00,
+ 0xae, 0xae, 0xae, 0x00, 0xf1, 0xf1, 0xf1, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x0e, 0x0e, 0x0e, 0x00,
+ 0xf1, 0xf1, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xf1, 0xf1, 0xf1, 0x00, 0xf1, 0xf1, 0xf1,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xea, 0xea, 0xea, 0x00, 0xb9, 0xb9, 0xb9,
+ 0x00, 0xea, 0xea, 0xea, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x02, 0xfe, 0xfe, 0xfe, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x07, 0x07, 0x07, 0x00, 0x06, 0x06,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0xf7,
+ 0xf7, 0x00, 0xfb, 0xfb, 0xfb, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xef, 0xef, 0xef, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0xff, 0xff,
+ 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0xfe,
+ 0xfe, 0xfe, 0x08, 0xfe, 0xfe, 0xfe, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd,
+ 0xfd, 0xfd, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00,
+ 0x00, 0x00, 0xf3, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0f,
+ 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x04, 0x04, 0x00, 0xfb, 0xfb, 0xfb, 0x00,
+ 0xfb, 0xfb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x01, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xfe, 0xfe, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0xfa, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0xf9, 0xf9, 0xf9, 0xd3, 0xd7, 0xd7, 0xd7,
+ 0x40, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xfa, 0xfa, 0xfa,
+ 0xf8, 0xf7, 0xf7, 0xf7, 0xd4, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x03, 0x03,
+ 0x03, 0x12, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfd, 0xfe, 0xfe,
+ 0xfe, 0xf4, 0xfe, 0xfe, 0xfe, 0xf0, 0x00, 0x00,
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00,
+ 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xf7, 0x00,
+ 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xfe, 0x66,
+ 0xed, 0x2e, 0xac, 0x43, 0x0b, 0x33, 0x50, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/replay_icon_text.png.h b/src/images/replay_icon_text.png.h
new file mode 100644
index 0000000..ed8f70d
--- /dev/null
+++ b/src/images/replay_icon_text.png.h
@@ -0,0 +1,192 @@
+/* replay_icon_text.png - 1507 bytes */
+ static const unsigned char replay_icon_text_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x69, 0x71,
+ 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x03,
+ 0x17, 0x02, 0x27, 0x24, 0x5d, 0x95, 0xa3, 0xce,
+ 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d,
+ 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, 0x05,
+ 0x3e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed,
+ 0x98, 0x7f, 0x48, 0xd4, 0x67, 0x1c, 0xc7, 0xdf,
+ 0x5e, 0x17, 0xa7, 0xc9, 0xa9, 0xc8, 0xb4, 0xab,
+ 0x44, 0x6e, 0xb5, 0xfe, 0x11, 0xa4, 0x06, 0xda,
+ 0x1f, 0xab, 0xa0, 0xfd, 0x57, 0x64, 0x3f, 0x46,
+ 0x84, 0xbb, 0x68, 0x65, 0x41, 0x50, 0x24, 0x2c,
+ 0x18, 0xb1, 0x6a, 0xfb, 0x63, 0x8d, 0xfe, 0x19,
+ 0x8e, 0x70, 0x23, 0x73, 0x48, 0x11, 0xb8, 0x02,
+ 0x23, 0x2a, 0x8d, 0x0a, 0x36, 0x2e, 0x33, 0x2a,
+ 0x07, 0x29, 0x49, 0x44, 0xa5, 0x61, 0xb6, 0xd8,
+ 0x9c, 0xa5, 0x19, 0x9b, 0x76, 0xea, 0xdd, 0x79,
+ 0xdf, 0xd7, 0xfe, 0xf9, 0x7e, 0xe5, 0xba, 0xee,
+ 0xca, 0xb1, 0x5a, 0x31, 0x9e, 0x17, 0x7c, 0xfe,
+ 0xb9, 0xe7, 0xf3, 0x7d, 0x3e, 0x9f, 0xe7, 0xfd,
+ 0x3c, 0x9f, 0xe7, 0xf9, 0x70, 0x92, 0xc1, 0x60,
+ 0x30, 0x18, 0x0c, 0x06, 0x83, 0xc1, 0x60, 0x30,
+ 0x18, 0x0c, 0x06, 0x83, 0xc1, 0x60, 0x30, 0x18,
+ 0x0c, 0x06, 0x83, 0xc1, 0x60, 0x30, 0x18, 0x0c,
+ 0x06, 0x83, 0xc1, 0x60, 0x30, 0x18, 0x0c, 0x06,
+ 0x83, 0xc1, 0x60, 0x30, 0xfc, 0x0f, 0x49, 0x7b,
+ 0x0b, 0x72, 0xe0, 0x4d, 0xe6, 0xe4, 0x4a, 0x48,
+ 0x24, 0x99, 0x8d, 0x4a, 0xfa, 0x45, 0x52, 0xf9,
+ 0xeb, 0x4a, 0x0e, 0x10, 0xf0, 0xe6, 0x77, 0x22,
+ 0x91, 0x68, 0x34, 0xca, 0x83, 0x07, 0x0f, 0xa8,
+ 0xa9, 0xa9, 0x21, 0x27, 0x27, 0x07, 0x49, 0xbb,
+ 0x5e, 0x67, 0xdc, 0x24, 0xa7, 0xe1, 0xcd, 0x08,
+ 0xe0, 0xec, 0x7e, 0x5e, 0x5e, 0x1e, 0x35, 0x35,
+ 0x35, 0x00, 0x9c, 0x3e, 0x7d, 0x1a, 0x49, 0x83,
+ 0xb6, 0x6f, 0x96, 0xa4, 0x6f, 0x24, 0xfd, 0x21,
+ 0xe9, 0xaf, 0x38, 0xfb, 0x51, 0x52, 0x41, 0x8a,
+ 0x13, 0x35, 0x1c, 0x67, 0xcd, 0x92, 0xde, 0x7d,
+ 0x81, 0x00, 0xef, 0x27, 0x7c, 0x1b, 0x95, 0x74,
+ 0x43, 0xd2, 0x27, 0x92, 0xea, 0x13, 0xc6, 0x9c,
+ 0x78, 0xef, 0x24, 0xfc, 0x7e, 0x42, 0xd2, 0x0e,
+ 0x49, 0xb7, 0x24, 0x85, 0xe3, 0xec, 0xa6, 0xa4,
+ 0x4a, 0x49, 0xd9, 0x2f, 0x13, 0xc0, 0x25, 0xa9,
+ 0x3c, 0x2b, 0x2b, 0x0b, 0x80, 0x91, 0x91, 0x11,
+ 0x47, 0x80, 0x1c, 0x49, 0xa3, 0x8b, 0x17, 0x2f,
+ 0x0e, 0x07, 0x83, 0xc1, 0xd8, 0xd0, 0xd0, 0x90,
+ 0x35, 0x36, 0x36, 0x46, 0x7b, 0x7b, 0x3b, 0x6b,
+ 0xd7, 0xae, 0x75, 0xbe, 0x9d, 0x13, 0x3f, 0xdf,
+ 0x86, 0x0d, 0x1b, 0xb8, 0x7d, 0xfb, 0x76, 0x2c,
+ 0x1c, 0x0e, 0xd3, 0xdd, 0xdd, 0xcd, 0xfa, 0xf5,
+ 0xeb, 0x1d, 0xbf, 0xe9, 0x29, 0x04, 0xf8, 0x60,
+ 0xc7, 0x8e, 0x1d, 0x00, 0xc4, 0x62, 0x31, 0xfa,
+ 0xfa, 0xfa, 0xa8, 0xab, 0xab, 0x23, 0x2b, 0x2b,
+ 0x0b, 0x49, 0xf5, 0x6d, 0x6d, 0x6d, 0x00, 0x4e,
+ 0xbc, 0x2f, 0xec, 0x6f, 0x02, 0x4b, 0x97, 0x2e,
+ 0x05, 0xe0, 0xc6, 0x8d, 0x1b, 0x48, 0x3a, 0xe1,
+ 0xf7, 0xfb, 0x39, 0x7e, 0xfc, 0x38, 0x8f, 0x1e,
+ 0x3d, 0x62, 0x7c, 0x7c, 0x9c, 0x87, 0x0f, 0x1f,
+ 0x5a, 0x8d, 0x8d, 0x8d, 0x7f, 0x06, 0x02, 0x81,
+ 0x53, 0x92, 0x0e, 0x4c, 0x4a, 0x80, 0xec, 0xec,
+ 0x6c, 0x00, 0x06, 0x07, 0x07, 0x1d, 0x01, 0xbe,
+ 0x5f, 0xb2, 0x64, 0x09, 0xd1, 0x68, 0x94, 0x96,
+ 0x96, 0x16, 0x0a, 0x0b, 0x0b, 0x87, 0xbd, 0x5e,
+ 0xef, 0xd0, 0xa1, 0x43, 0x87, 0x26, 0x16, 0x2b,
+ 0xe9, 0xa7, 0xf8, 0xf9, 0x5a, 0x5a, 0x5a, 0x98,
+ 0x39, 0x73, 0xe6, 0x53, 0x9f, 0xcf, 0xf7, 0xb4,
+ 0xb9, 0xb9, 0x19, 0x80, 0xb2, 0xb2, 0x32, 0x24,
+ 0xd5, 0xa6, 0x12, 0x60, 0xcf, 0x9e, 0x3d, 0x14,
+ 0x15, 0x15, 0x91, 0x9e, 0x9e, 0xce, 0xe6, 0xcd,
+ 0x9b, 0x01, 0x38, 0x72, 0xe4, 0x08, 0x92, 0xba,
+ 0x2a, 0x2a, 0x2a, 0x00, 0x68, 0x6a, 0x6a, 0x42,
+ 0x52, 0xc8, 0xbe, 0x9b, 0xae, 0xd7, 0xd6, 0xd6,
+ 0x02, 0xb0, 0x73, 0xe7, 0x4e, 0x24, 0x8d, 0x5e,
+ 0xbb, 0x76, 0x0d, 0x80, 0xd5, 0xab, 0x57, 0xe3,
+ 0xf1, 0x78, 0xc2, 0x33, 0x66, 0xcc, 0x88, 0x6c,
+ 0xd9, 0xb2, 0xe5, 0xb7, 0xce, 0xce, 0xce, 0xde,
+ 0xc9, 0x08, 0xf0, 0x4c, 0x09, 0x1c, 0x3c, 0x78,
+ 0x10, 0x49, 0xdd, 0x92, 0x06, 0x2e, 0x5d, 0xba,
+ 0x04, 0x40, 0x71, 0x71, 0xf1, 0x84, 0x6f, 0x6e,
+ 0x6e, 0x2e, 0x00, 0x5d, 0x5d, 0x5d, 0xd8, 0x47,
+ 0x6d, 0x62, 0xbe, 0xd2, 0xd2, 0x52, 0x24, 0x7d,
+ 0x27, 0x69, 0x7f, 0x49, 0x49, 0x09, 0x00, 0x57,
+ 0xae, 0x5c, 0x41, 0xd2, 0x40, 0x92, 0xb8, 0x53,
+ 0x25, 0x7d, 0x29, 0xa9, 0x47, 0x52, 0x4c, 0x12,
+ 0x53, 0xa6, 0x4c, 0x01, 0x60, 0x60, 0x60, 0x00,
+ 0x49, 0xb1, 0xf4, 0xf4, 0x74, 0x06, 0x07, 0x07,
+ 0x89, 0x44, 0x22, 0xe4, 0xe6, 0xe6, 0x22, 0xa9,
+ 0x28, 0x2d, 0x2d, 0x8d, 0xde, 0xde, 0x5e, 0x62,
+ 0xb1, 0x18, 0xb3, 0x66, 0xcd, 0x42, 0xd2, 0x68,
+ 0x34, 0x1a, 0x05, 0x60, 0xd1, 0xa2, 0x45, 0xce,
+ 0xdc, 0x03, 0x92, 0x1a, 0xec, 0xc5, 0x1f, 0x78,
+ 0xe9, 0x25, 0xe8, 0xd0, 0xd3, 0xd3, 0x43, 0x66,
+ 0x66, 0x26, 0x92, 0x3e, 0x96, 0x34, 0x10, 0x0a,
+ 0x85, 0x52, 0xfa, 0x8e, 0x8f, 0x8f, 0x3f, 0x27,
+ 0x80, 0xc7, 0xe3, 0x41, 0x52, 0xa6, 0xa4, 0x4c,
+ 0x8f, 0xc7, 0x03, 0x40, 0x28, 0x14, 0x4a, 0x25,
+ 0x40, 0xfd, 0xdc, 0xb9, 0x73, 0x39, 0x73, 0xe6,
+ 0x0c, 0x4f, 0x9e, 0x3c, 0xc1, 0xb2, 0xac, 0x89,
+ 0x71, 0xcb, 0xb2, 0x1c, 0x9f, 0xee, 0xaa, 0xaa,
+ 0x2a, 0x00, 0xb6, 0x6e, 0xdd, 0x8a, 0xa4, 0x9a,
+ 0xd2, 0xd2, 0x52, 0x00, 0x82, 0xc1, 0xa0, 0x73,
+ 0x67, 0x8c, 0x3a, 0xa5, 0xe2, 0xc4, 0xeb, 0xe8,
+ 0xe8, 0xa0, 0xba, 0xba, 0xda, 0x11, 0xa8, 0xfe,
+ 0x85, 0x27, 0xc0, 0xed, 0x76, 0x33, 0x6f, 0xde,
+ 0x3c, 0x5a, 0x5b, 0x5b, 0xe3, 0x03, 0xb5, 0xc4,
+ 0x0b, 0x90, 0x9d, 0x9d, 0x9d, 0xea, 0xe9, 0xfc,
+ 0x37, 0x02, 0x84, 0x9c, 0xc4, 0x2b, 0x2b, 0x2b,
+ 0xf1, 0x78, 0x3c, 0xb8, 0x5c, 0xae, 0x44, 0x9f,
+ 0xb2, 0xd9, 0xb3, 0x67, 0x63, 0x59, 0x16, 0x97,
+ 0x2f, 0x5f, 0x46, 0x52, 0x6c, 0xdf, 0xbe, 0x7d,
+ 0x00, 0x54, 0x54, 0x54, 0x20, 0xa9, 0x4a, 0x52,
+ 0xbd, 0xdf, 0xef, 0xe7, 0xe8, 0xd1, 0xa3, 0xf4,
+ 0xf5, 0xf5, 0x3d, 0xb3, 0x49, 0x6d, 0x6d, 0x6d,
+ 0x4e, 0xe9, 0xbc, 0xb0, 0x04, 0x32, 0x24, 0xd5,
+ 0xf9, 0x7c, 0x3e, 0xc2, 0xe1, 0x30, 0xf7, 0xee,
+ 0xdd, 0xc3, 0xe5, 0x72, 0x21, 0x69, 0xe0, 0xe2,
+ 0xc5, 0x8b, 0x00, 0xac, 0x58, 0xb1, 0x02, 0x49,
+ 0x3f, 0xdb, 0xbe, 0x73, 0xec, 0x9a, 0xae, 0x4d,
+ 0xac, 0xed, 0x92, 0x92, 0x12, 0x24, 0xed, 0x97,
+ 0xf4, 0xed, 0x24, 0x4a, 0x20, 0x14, 0x89, 0x44,
+ 0x00, 0xc8, 0xc8, 0xc8, 0x40, 0xd2, 0x57, 0x45,
+ 0x45, 0x45, 0xc9, 0xca, 0x24, 0x76, 0xfe, 0xfc,
+ 0x79, 0x2c, 0xcb, 0xc2, 0xef, 0xf7, 0x73, 0xf3,
+ 0xe6, 0x4d, 0x46, 0x46, 0x46, 0xf0, 0x7a, 0xbd,
+ 0x48, 0x7a, 0xcf, 0x16, 0xa1, 0xca, 0x7e, 0x3d,
+ 0xf0, 0x7a, 0xbd, 0x94, 0x97, 0x97, 0x03, 0x10,
+ 0x89, 0x44, 0x26, 0x25, 0x80, 0xd3, 0x28, 0x0d,
+ 0x9f, 0x3a, 0x75, 0x0a, 0x80, 0x35, 0x6b, 0xd6,
+ 0x20, 0xa9, 0x6e, 0xe1, 0xc2, 0x85, 0x84, 0xc3,
+ 0x61, 0xee, 0xde, 0xbd, 0xcb, 0xfc, 0xf9, 0xf3,
+ 0xc7, 0xdc, 0x6e, 0xf7, 0x68, 0x61, 0x61, 0xe1,
+ 0x58, 0x65, 0x65, 0xe5, 0xaf, 0x9d, 0x9d, 0x9d,
+ 0x7d, 0x89, 0x02, 0x34, 0x37, 0x37, 0xe3, 0xf3,
+ 0xf9, 0x46, 0xf2, 0xf3, 0xf3, 0x47, 0x2e, 0x5c,
+ 0xb8, 0x00, 0xc0, 0xca, 0x95, 0x2b, 0x53, 0x5d,
+ 0x82, 0xa1, 0x8e, 0x8e, 0x0e, 0x00, 0xd6, 0xad,
+ 0x5b, 0x47, 0x4e, 0x4e, 0xce, 0xd8, 0xb9, 0x73,
+ 0xe7, 0x92, 0xe5, 0xf6, 0x75, 0x59, 0x59, 0x19,
+ 0x00, 0x87, 0x0f, 0x1f, 0x06, 0xa0, 0xa1, 0xa1,
+ 0xc1, 0xb9, 0xa8, 0xd3, 0x24, 0x55, 0xdd, 0xba,
+ 0x75, 0xeb, 0x41, 0x20, 0x10, 0xf8, 0x3d, 0x2f,
+ 0x2f, 0x2f, 0x3c, 0x75, 0xea, 0xd4, 0xf0, 0xb2,
+ 0x65, 0xcb, 0x00, 0xb8, 0x7a, 0xf5, 0xea, 0xa4,
+ 0x05, 0x90, 0xa4, 0xcf, 0x57, 0xad, 0x5a, 0x05,
+ 0x40, 0x6b, 0x6b, 0x2b, 0x92, 0xea, 0x24, 0x0d,
+ 0x2f, 0x58, 0xb0, 0x20, 0xd4, 0xd4, 0xd4, 0x14,
+ 0x7d, 0xfc, 0xf8, 0xb1, 0x15, 0x8d, 0x46, 0xe9,
+ 0xed, 0xed, 0xb5, 0x1a, 0x1b, 0x1b, 0x9f, 0x04,
+ 0x02, 0x81, 0xc6, 0xc4, 0x85, 0x6d, 0xdc, 0xb8,
+ 0x91, 0xae, 0xae, 0xae, 0x58, 0x24, 0x12, 0xa1,
+ 0xa7, 0xa7, 0xc7, 0x79, 0x29, 0x90, 0xe4, 0x4b,
+ 0x12, 0xb7, 0xa1, 0xb8, 0xb8, 0x98, 0xf6, 0xf6,
+ 0x76, 0xa7, 0x11, 0xb3, 0xb6, 0x6d, 0xdb, 0x96,
+ 0x2c, 0xb7, 0xe9, 0x2e, 0x97, 0x8b, 0xfb, 0xf7,
+ 0xef, 0x4f, 0x8c, 0x2d, 0x5f, 0xbe, 0x1c, 0x49,
+ 0x9f, 0xda, 0xe3, 0x55, 0x9b, 0x36, 0x6d, 0x6a,
+ 0x38, 0x7b, 0xf6, 0xec, 0x50, 0x7f, 0x7f, 0xbf,
+ 0xf3, 0x0c, 0x72, 0xec, 0xd8, 0x31, 0x0a, 0x0a,
+ 0x0a, 0x90, 0xf4, 0x43, 0xb2, 0x9e, 0x3c, 0xde,
+ 0x1c, 0x7c, 0x09, 0xbf, 0xd7, 0xd9, 0xf5, 0xbc,
+ 0x4b, 0xd2, 0x5d, 0xbb, 0x55, 0x76, 0xec, 0xba,
+ 0xa4, 0xed, 0x76, 0x93, 0xf1, 0xdc, 0xce, 0xc6,
+ 0xd9, 0x25, 0xbb, 0x64, 0x92, 0xc5, 0x4d, 0xb7,
+ 0x1b, 0xaa, 0xf8, 0x79, 0x53, 0xe5, 0x76, 0x79,
+ 0xf7, 0xee, 0xdd, 0x00, 0xf4, 0xf7, 0xf7, 0xe3,
+ 0x76, 0xbb, 0x91, 0x94, 0x6f, 0x8f, 0xe5, 0x48,
+ 0xfa, 0x4c, 0xd2, 0x9d, 0x24, 0x8d, 0xd0, 0x76,
+ 0x49, 0x53, 0xfe, 0xeb, 0xce, 0xf2, 0x55, 0x52,
+ 0x25, 0x89, 0x69, 0xd3, 0xa6, 0x71, 0xf2, 0xe4,
+ 0x49, 0x00, 0xf6, 0xee, 0xdd, 0x8b, 0xbd, 0xd8,
+ 0xb7, 0x86, 0xd7, 0x2a, 0x40, 0x30, 0x18, 0x9c,
+ 0xd8, 0xf9, 0xea, 0xea, 0x6a, 0x67, 0xf7, 0x3f,
+ 0x7c, 0xab, 0x04, 0x48, 0x71, 0x6c, 0x5f, 0xd9,
+ 0x09, 0x88, 0xb3, 0x3b, 0x92, 0x3e, 0x32, 0xff,
+ 0x6e, 0x18, 0x0c, 0xff, 0x98, 0xbf, 0x01, 0xe7,
+ 0x07, 0x1b, 0x95, 0xa2, 0xe8, 0xe2, 0x76, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/select_icon.xpm b/src/images/select_icon.xpm
new file mode 100644
index 0000000..24ae58b
--- /dev/null
+++ b/src/images/select_icon.xpm
@@ -0,0 +1,73 @@
+/* XPM */
+static const char * select_icon_xpm[] = {
+"64 64 6 1",
+" c #FEFFFF",
+". c #000000",
+"+ c #8BE7FF",
+"@ c #008BAE",
+"# c #00CCFF",
+"$ c #FFFFFF",
+" ",
+" ",
+" ........ ............. ............. ............ ........ ",
+" .+++++ at . .++++++++++ at . .++++++++++ at . .+++++++++ at . .+++++ at . ",
+" .+####@. .+#########@. .+#########@. .+########@. .+####@. ",
+" .+####@. .+#########@. .+#########@. .+########@. .+####@. ",
+" .+####@. .+#########@. .+#########@. .+########@. .+####@. ",
+" .+####@. .+#########@. .+#########@. .+########@. .+####@. ",
+" .+####@. .@@@@@@@@@@@. .@@@@@@@@@@@. .@@@@@@@@@@. .+####@. ",
+" .+####@. ............. ............. ............ .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .@@@@@@. .@@@@@@. ",
+" ........ ........ ",
+"$$$$$$$$$ ",
+"$$$$$$$$$ $$$$$$$$ ",
+" ........ ........ ",
+" .+++++ at . $ .+++++ at . ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .+####@. .+####@. ",
+" .@@@@@@. .+####@. ",
+" ........ .@@@@@@. ",
+"$$$$$$$$$$$$ ........ ",
+"$$$$$$$$$$ $$$$$$$$$$",
+" $$$$$$$$$ $$$$$$$$$$",
+" ........ $........ ",
+" .+++++ at . $.+++++ at . ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .+####@. $.+####@. ",
+" .@@@@@@. $.@@@@@@. ",
+" ........ $........ ",
+"$$$$$$$$$$$$ $$$$$$$$$$$$",
+" $ ",
+" ........ $........ ",
+" .+++++ at . $$ $.+++++ at . ",
+"$.+####@. .+####@. ",
+"$.+####@. $$.+####@. ",
+" .+####@. .+####@. ",
+" .+####@. $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$.+####@. ",
+" .+####@. ............. ............. ............$.+####@. ",
+" .+####@. .++++++++++ at . .++++++++++ at . .+++++++++ at .$.+####@. ",
+" .+####@. .+#########@. .+#########@. .+########@.$.+####@. ",
+" .+####@. .+#########@. .+#########@. .+########@.$.+####@. ",
+" .+####@. .+#########@. .+#########@. .+########@.$.+####@. ",
+" .+####@. .+#########@. .+#########@. .+########@.$.+####@. ",
+" .@@@@@@. .@@@@@@@@@@@. .@@@@@@@@@@@. .@@@@@@@@@@.$.@@@@@@. ",
+" ........ ............. ............. ............$........ ",
+" $$$$$$$$$ $$$$$$$$$$"};
diff --git a/src/images/server.xpm b/src/images/server.xpm
new file mode 100644
index 0000000..26d44bf
--- /dev/null
+++ b/src/images/server.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static const char * server_xpm[] = {
+"12 12 7 1",
+" c None",
+". c #000000",
+"+ c #F9F9F9",
+"@ c #A0A0A0",
+"# c #D3D3D3",
+"$ c #00B4FF",
+"% c #00FF2A",
+"...... ",
+".+++ at . ",
+".+##@. ",
+".+##@. ",
+".+.. at .......",
+".+##@.@@@@@.",
+".+##@.@$$$@.",
+".+##@.@$$$@.",
+".+%%@.@$$$@.",
+".+%%@.@$$$@.",
+".@@@@.+ at +@+.",
+"............"};
diff --git a/src/images/single_player_icon.png.h b/src/images/single_player_icon.png.h
new file mode 100644
index 0000000..ef6e016
--- /dev/null
+++ b/src/images/single_player_icon.png.h
@@ -0,0 +1,225 @@
+/* single_player_icon.png - 1771 bytes */
+ static const unsigned char single_player_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a,
+ 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x0a,
+ 0x06, 0x16, 0x02, 0x34, 0x56, 0x4b, 0x3a, 0x6a,
+ 0x00, 0x00, 0x06, 0x6b, 0x49, 0x44, 0x41, 0x54,
+ 0x58, 0x47, 0xed, 0x56, 0x4b, 0x6c, 0x5c, 0x57,
+ 0x19, 0xfe, 0xcf, 0x7d, 0xdf, 0x99, 0x3b, 0x9e,
+ 0x19, 0xc7, 0x1e, 0xbf, 0xe2, 0xc4, 0x49, 0x95,
+ 0x3a, 0xb5, 0x1a, 0xea, 0x0a, 0x2b, 0x0a, 0x0f,
+ 0x15, 0x8a, 0x1c, 0x94, 0x80, 0x5a, 0x04, 0x09,
+ 0x6c, 0x2a, 0xa5, 0xca, 0xa6, 0x8b, 0x2c, 0xba,
+ 0xa3, 0x6d, 0xaa, 0xae, 0x50, 0x0a, 0x2a, 0x2b,
+ 0xd2, 0x6e, 0x80, 0x2e, 0x53, 0x81, 0xba, 0x20,
+ 0xa0, 0x0a, 0x89, 0x54, 0x42, 0x54, 0x48, 0x50,
+ 0xa8, 0x12, 0x43, 0x71, 0x94, 0x17, 0x6d, 0x2d,
+ 0x3b, 0x71, 0xdc, 0xf8, 0x31, 0xef, 0x7b, 0xe7,
+ 0x3e, 0xcf, 0x39, 0x7c, 0x67, 0xd2, 0x48, 0x86,
+ 0x0c, 0xa9, 0xd2, 0xb0, 0x23, 0xc7, 0xfe, 0x7d,
+ 0xee, 0x9c, 0x99, 0x39, 0xdf, 0xf7, 0x7f, 0xff,
+ 0xcb, 0x44, 0xf7, 0xd7, 0x7d, 0x05, 0xee, 0x2b,
+ 0xf0, 0xff, 0xae, 0x00, 0xbb, 0x57, 0x01, 0x4e,
+ 0x9f, 0xfe, 0xd5, 0x33, 0x23, 0xa3, 0xc3, 0x47,
+ 0xa4, 0x24, 0x89, 0xbb, 0x24, 0x56, 0x0b, 0x16,
+ 0x09, 0x29, 0x48, 0x08, 0x41, 0x9c, 0xf3, 0x58,
+ 0x0a, 0x69, 0xe2, 0xcc, 0x48, 0x92, 0x84, 0xe6,
+ 0xe7, 0xcf, 0xff, 0xe0, 0xf8, 0x0b, 0xc7, 0xdf,
+ 0xbf, 0x85, 0x6b, 0xdc, 0x2b, 0x81, 0xc1, 0xca,
+ 0xe0, 0xc1, 0x8f, 0x16, 0x3a, 0x0f, 0x2f, 0x7c,
+ 0xb4, 0xd2, 0xe4, 0x5c, 0x72, 0x80, 0x56, 0x61,
+ 0x45, 0x70, 0x51, 0x77, 0x67, 0xe0, 0xb5, 0x96,
+ 0xa5, 0xd2, 0x1d, 0x1a, 0x2e, 0x97, 0x0f, 0x1c,
+ 0xdc, 0x4d, 0x17, 0x2f, 0x5e, 0x9a, 0xc6, 0xf9,
+ 0xff, 0x8e, 0x80, 0x61, 0x18, 0xf6, 0xfa, 0xda,
+ 0x8d, 0x5a, 0xb3, 0xb1, 0x06, 0x6f, 0xa5, 0xf2,
+ 0x18, 0x24, 0x64, 0x1d, 0x24, 0x06, 0xb1, 0xc7,
+ 0x8a, 0x94, 0x94, 0x42, 0x87, 0x91, 0xe0, 0x42,
+ 0xf9, 0x6b, 0x6d, 0x76, 0xfa, 0x9e, 0x15, 0x20,
+ 0x46, 0x76, 0xb3, 0xd5, 0x09, 0x7c, 0x3f, 0x81,
+ 0x02, 0x02, 0x60, 0x92, 0xa9, 0x38, 0x00, 0x5c,
+ 0xe0, 0x75, 0xd8, 0x6a, 0x05, 0x7e, 0xbd, 0xde,
+ 0x72, 0x77, 0x64, 0x76, 0x14, 0x86, 0x91, 0x9d,
+ 0xcf, 0xe5, 0x72, 0x9f, 0x99, 0xc0, 0xf1, 0x27,
+ 0x73, 0x06, 0x2e, 0xd6, 0xbe, 0xf9, 0x88, 0xa5,
+ 0xa5, 0x22, 0x29, 0x33, 0xd2, 0x52, 0xc9, 0xb3,
+ 0x2d, 0xb5, 0xaa, 0x5f, 0x8b, 0xa2, 0x4c, 0x25,
+ 0x00, 0xe2, 0xae, 0xe0, 0xa5, 0xe3, 0xfb, 0x61,
+ 0x72, 0xe3, 0x46, 0x2d, 0x8b, 0xa2, 0x24, 0x06,
+ 0xe0, 0x42, 0xb3, 0x15, 0x95, 0x18, 0x63, 0x03,
+ 0xa6, 0x65, 0x96, 0x3f, 0x13, 0x81, 0x53, 0x2f,
+ 0x7e, 0xd1, 0x70, 0xb2, 0xd5, 0xcf, 0xf7, 0x5b,
+ 0x8d, 0xef, 0x7a, 0x5b, 0x86, 0x1f, 0xb3, 0x9c,
+ 0xfc, 0xb8, 0xc8, 0x92, 0xa8, 0xf3, 0xfe, 0xcb,
+ 0x95, 0x11, 0x3e, 0xf0, 0xf1, 0x46, 0x32, 0xf1,
+ 0x31, 0x17, 0x3a, 0x94, 0x97, 0x5a, 0xab, 0xd5,
+ 0x61, 0xf5, 0x7a, 0xdb, 0x92, 0x52, 0x93, 0xb6,
+ 0x9d, 0x53, 0xc0, 0x51, 0xa7, 0x93, 0x09, 0x80,
+ 0xe7, 0x0c, 0x43, 0x1f, 0xbc, 0x6b, 0x02, 0xaf,
+ 0x1f, 0x1b, 0x37, 0xec, 0xe0, 0x83, 0xef, 0x6d,
+ 0x1d, 0x1b, 0xfc, 0xf1, 0xe8, 0xce, 0xfd, 0xa3,
+ 0xb6, 0xeb, 0x31, 0x99, 0x45, 0x24, 0xd2, 0x0e,
+ 0x95, 0x13, 0x9f, 0x9e, 0x98, 0xfa, 0x60, 0x67,
+ 0xff, 0x95, 0xab, 0xe5, 0xb7, 0x97, 0xbe, 0xb4,
+ 0xd2, 0x0e, 0x32, 0x3b, 0x0c, 0xd3, 0xd8, 0xb2,
+ 0x1c, 0x62, 0x4c, 0xcb, 0x00, 0xae, 0xc3, 0xf2,
+ 0x82, 0x6b, 0x2a, 0x3f, 0x1c, 0x22, 0xd6, 0x77,
+ 0xd7, 0x04, 0xf2, 0x5a, 0x30, 0x3e, 0x52, 0x29,
+ 0x9d, 0xd8, 0xb6, 0x7b, 0xdf, 0x98, 0x61, 0xe5,
+ 0x48, 0x33, 0x1c, 0x92, 0x66, 0x86, 0xbb, 0x6a,
+ 0x24, 0x41, 0xa0, 0xcf, 0xd5, 0xd8, 0x63, 0x53,
+ 0x71, 0xff, 0xf5, 0xc6, 0x3f, 0xe4, 0x9f, 0xdb,
+ 0x7b, 0x5a, 0xf0, 0x7a, 0x0b, 0x40, 0x1b, 0x30,
+ 0x1b, 0x86, 0x10, 0xa8, 0x6a, 0xb7, 0x5c, 0xc8,
+ 0xa3, 0xe1, 0xe1, 0xee, 0x14, 0xf8, 0xe9, 0x33,
+ 0x15, 0xcb, 0x34, 0xe4, 0x8f, 0x46, 0xb6, 0x4f,
+ 0x4d, 0x18, 0x86, 0x45, 0xba, 0x3b, 0x00, 0xdb,
+ 0x42, 0x92, 0xab, 0x7b, 0x35, 0x92, 0x50, 0x81,
+ 0x47, 0x75, 0xca, 0xdb, 0x8c, 0x1e, 0xdf, 0xb5,
+ 0x5c, 0xbe, 0x50, 0x9f, 0x2e, 0xc4, 0xc2, 0x45,
+ 0xa6, 0x6b, 0x16, 0xc0, 0xa1, 0x02, 0x5b, 0x87,
+ 0x69, 0x71, 0xac, 0x0d, 0x41, 0x81, 0xb2, 0x10,
+ 0xbc, 0x74, 0x57, 0x0a, 0x0c, 0x15, 0x0d, 0x51,
+ 0x70, 0xd8, 0x94, 0xe3, 0xe6, 0x99, 0xea, 0x35,
+ 0xcc, 0xb0, 0x49, 0xb3, 0x8b, 0x00, 0xf6, 0x89,
+ 0xe9, 0x26, 0x48, 0x18, 0xe0, 0xa1, 0x93, 0x88,
+ 0x9b, 0x34, 0x3c, 0x50, 0xd4, 0xbe, 0xfd, 0xf5,
+ 0x92, 0xd5, 0xd0, 0x1e, 0xa0, 0x24, 0x49, 0xbd,
+ 0x5c, 0xce, 0xf5, 0xd0, 0x9d, 0x76, 0xe0, 0x6b,
+ 0xa8, 0x08, 0xc9, 0x38, 0xcf, 0x34, 0xa6, 0x31,
+ 0xf3, 0xc0, 0x81, 0x03, 0xc6, 0x99, 0x33, 0x67,
+ 0x20, 0x21, 0xd1, 0xa7, 0x96, 0x61, 0xde, 0x94,
+ 0x64, 0x99, 0x1a, 0xae, 0x48, 0xd0, 0x56, 0x42,
+ 0x6c, 0x2d, 0xe2, 0x81, 0x0e, 0x05, 0x22, 0xc8,
+ 0x1f, 0xdc, 0xdc, 0x79, 0x8a, 0xbe, 0xc3, 0xc9,
+ 0xb4, 0x74, 0x72, 0xe4, 0x2a, 0x95, 0xfa, 0x86,
+ 0x89, 0x0b, 0x55, 0x11, 0x21, 0x65, 0x69, 0x0a,
+ 0x60, 0xc1, 0xa1, 0x62, 0xed, 0xca, 0xa5, 0x6a,
+ 0x78, 0xed, 0xea, 0xb5, 0xbf, 0x5a, 0x96, 0xc5,
+ 0x6f, 0xa9, 0xf0, 0xa9, 0x04, 0xde, 0x85, 0x8a,
+ 0x33, 0x0c, 0xd1, 0x8b, 0x03, 0xca, 0x14, 0x10,
+ 0xe2, 0xc9, 0xa3, 0x26, 0x00, 0x33, 0x12, 0xd8,
+ 0x95, 0xfc, 0x32, 0xeb, 0xe0, 0x5c, 0xa7, 0x38,
+ 0x4e, 0x68, 0x79, 0xb5, 0x41, 0x61, 0x6b, 0xb9,
+ 0x5b, 0x92, 0xaa, 0x37, 0x87, 0x61, 0x48, 0x7e,
+ 0x3b, 0x08, 0xf3, 0x6e, 0xfe, 0x6c, 0xa5, 0x52,
+ 0x79, 0x6f, 0x72, 0xf2, 0xa1, 0xb9, 0x3d, 0x7b,
+ 0x1e, 0x19, 0x3a, 0x7c, 0xf8, 0xf0, 0xc6, 0x91,
+ 0x23, 0x47, 0x32, 0x7d, 0x73, 0x3c, 0x36, 0x3f,
+ 0x1f, 0xfb, 0xbe, 0xcb, 0x26, 0x1f, 0xd6, 0xb5,
+ 0x57, 0x7f, 0xd2, 0xe0, 0xb3, 0x5f, 0xd0, 0x87,
+ 0x87, 0xf2, 0xde, 0x57, 0x4d, 0x8a, 0x49, 0x40,
+ 0x05, 0x95, 0x78, 0x02, 0xc0, 0x3c, 0xaa, 0x76,
+ 0x77, 0x29, 0x52, 0xd2, 0x9d, 0x22, 0xad, 0xac,
+ 0xb7, 0xd2, 0x7f, 0x66, 0xd3, 0xd2, 0x44, 0x95,
+ 0x58, 0x96, 0x49, 0x69, 0x9a, 0x52, 0xa3, 0xd1,
+ 0x4c, 0xce, 0xcf, 0x9f, 0x3f, 0x7b, 0xf9, 0xca,
+ 0xe5, 0x73, 0x6a, 0x36, 0x14, 0x8b, 0xa5, 0x56,
+ 0x5f, 0x5f, 0xdf, 0x5e, 0xf4, 0xa3, 0x27, 0x0f,
+ 0x1d, 0x3a, 0x74, 0x81, 0x3d, 0xfb, 0xa2, 0xcb,
+ 0x5e, 0xfd, 0x61, 0xa8, 0xc8, 0xf6, 0x5c, 0xc7,
+ 0x9e, 0xcb, 0x69, 0xd4, 0x2e, 0xed, 0xfb, 0xda,
+ 0x80, 0xf7, 0xf6, 0xcc, 0x03, 0x15, 0x8f, 0x52,
+ 0xe5, 0x7d, 0x77, 0xee, 0x00, 0x18, 0x61, 0x44,
+ 0x8b, 0x65, 0x66, 0x9e, 0x22, 0x61, 0xd3, 0x7c,
+ 0xe7, 0x73, 0x24, 0xc7, 0x66, 0x55, 0xe2, 0x75,
+ 0xdf, 0xbf, 0xb5, 0x4a, 0xa5, 0x22, 0x75, 0x3a,
+ 0x08, 0x1f, 0xc2, 0x32, 0x37, 0x77, 0xee, 0x8d,
+ 0x7a, 0xb5, 0x71, 0x62, 0x76, 0x76, 0xf6, 0x09,
+ 0xb4, 0xf1, 0xb3, 0xfa, 0x97, 0x1f, 0x37, 0xb5,
+ 0xe9, 0xbd, 0x06, 0x9d, 0x7b, 0xb7, 0x9b, 0x13,
+ 0xb7, 0xaf, 0xad, 0x4f, 0x7b, 0x8b, 0xd1, 0xe1,
+ 0xe7, 0xd6, 0xcd, 0x3d, 0x33, 0x95, 0xec, 0x82,
+ 0x3e, 0x50, 0x74, 0xc8, 0xd0, 0x55, 0xe4, 0x00,
+ 0xac, 0x5b, 0x48, 0xc8, 0x12, 0xf9, 0xb1, 0xa4,
+ 0x3f, 0x2c, 0x8f, 0xd1, 0xa9, 0x0f, 0x67, 0xa8,
+ 0x52, 0xd0, 0xc9, 0xb3, 0x35, 0x64, 0x1d, 0x08,
+ 0xe0, 0xd7, 0x40, 0xa2, 0x2a, 0x42, 0x86, 0xa9,
+ 0x53, 0x1a, 0x67, 0xe4, 0xb8, 0xce, 0xae, 0x76,
+ 0xcb, 0x4f, 0xe3, 0x38, 0xfe, 0xad, 0x6d, 0xdb,
+ 0xef, 0xdd, 0x71, 0x1c, 0x4f, 0x1c, 0x7c, 0xd9,
+ 0x29, 0x16, 0x0b, 0xaf, 0x6d, 0xdb, 0x39, 0x71,
+ 0xb4, 0xda, 0x4e, 0xf4, 0xed, 0xf9, 0x2a, 0x3d,
+ 0xaa, 0xbd, 0x43, 0xfb, 0x06, 0xae, 0x52, 0x5e,
+ 0x0f, 0x41, 0x42, 0xa3, 0x6b, 0x41, 0x81, 0xce,
+ 0x45, 0x33, 0xf4, 0xb7, 0xce, 0xa3, 0x00, 0x32,
+ 0x29, 0x6a, 0xd5, 0xe8, 0xe8, 0xfe, 0x51, 0x1a,
+ 0x1d, 0x00, 0x51, 0x13, 0x61, 0x48, 0x52, 0x54,
+ 0x09, 0xa3, 0xbe, 0xbe, 0x02, 0xb5, 0xdb, 0xa8,
+ 0x1c, 0xa6, 0xc9, 0x5f, 0xbc, 0xf1, 0xcb, 0x43,
+ 0x3f, 0xff, 0xd9, 0xeb, 0xbf, 0xc1, 0x05, 0xdd,
+ 0x91, 0xd9, 0x73, 0x8d, 0xcd, 0xbe, 0xc4, 0x6c,
+ 0x47, 0x7f, 0x6a, 0x7c, 0xdb, 0xd6, 0xa3, 0x55,
+ 0x9f, 0xeb, 0x19, 0x99, 0xd4, 0xd0, 0xc6, 0xe9,
+ 0x9d, 0xec, 0x3b, 0x44, 0x9e, 0x41, 0x7b, 0x77,
+ 0xe8, 0xa4, 0x69, 0x26, 0xbd, 0xf9, 0xfb, 0x0d,
+ 0x12, 0x6e, 0x3f, 0x35, 0x22, 0x9f, 0x92, 0x38,
+ 0xa2, 0x4a, 0xb1, 0x44, 0xaf, 0xfd, 0xfa, 0xf2,
+ 0x87, 0x5f, 0xd9, 0xde, 0x7c, 0xcb, 0x36, 0x48,
+ 0x65, 0x2d, 0xd6, 0x26, 0x3f, 0x19, 0x72, 0x36,
+ 0xe3, 0x2b, 0x38, 0xec, 0xc6, 0xe8, 0xbf, 0x12,
+ 0x18, 0x2c, 0x6c, 0x0c, 0xb9, 0xfd, 0xe3, 0xcf,
+ 0x07, 0xc8, 0x2f, 0x7c, 0xa1, 0xeb, 0x45, 0x23,
+ 0xe0, 0x00, 0xcd, 0xd3, 0x82, 0xef, 0xd2, 0x53,
+ 0x53, 0xbb, 0x69, 0xbd, 0x19, 0xd1, 0xf5, 0x60,
+ 0x8e, 0x84, 0x1f, 0xa1, 0x02, 0x30, 0x8c, 0x30,
+ 0x6e, 0xeb, 0xed, 0x88, 0x6c, 0xaf, 0x7f, 0xc7,
+ 0x9b, 0x7f, 0x17, 0x7f, 0x5c, 0xfa, 0xdd, 0x0b,
+ 0x6f, 0xf5, 0xf4, 0x6e, 0xd3, 0xa1, 0x6a, 0x8d,
+ 0x3d, 0x97, 0x9f, 0xf4, 0x4f, 0x17, 0x3c, 0x6f,
+ 0x57, 0x10, 0x22, 0xf3, 0x91, 0x6c, 0x2a, 0xe1,
+ 0x78, 0x96, 0xaa, 0xba, 0xa6, 0xf9, 0xc5, 0x36,
+ 0xf9, 0x98, 0x7e, 0x0b, 0xab, 0x1d, 0x8a, 0xf0,
+ 0x2f, 0x47, 0x88, 0xf2, 0x53, 0xf3, 0x5e, 0x59,
+ 0x18, 0x25, 0xe4, 0x3a, 0x96, 0xee, 0xba, 0xc6,
+ 0xb7, 0x7a, 0x5e, 0xfc, 0x1f, 0x87, 0x3d, 0x09,
+ 0xbc, 0x72, 0xc2, 0x65, 0x96, 0xed, 0xb9, 0xba,
+ 0x8e, 0x01, 0x02, 0x50, 0x91, 0x60, 0xf0, 0xa0,
+ 0x07, 0x74, 0x2d, 0x4b, 0xd0, 0xe5, 0x22, 0xfa,
+ 0xcb, 0x85, 0x15, 0xba, 0xb4, 0xb8, 0x4e, 0x1c,
+ 0x84, 0x14, 0xb9, 0x9b, 0xc6, 0xf1, 0x99, 0x84,
+ 0xd2, 0x2c, 0xa3, 0x9c, 0x63, 0x4d, 0x8e, 0x7f,
+ 0xe3, 0x95, 0x7f, 0x9b, 0xfd, 0xbd, 0x08, 0xf5,
+ 0x0c, 0xc1, 0xf3, 0x2f, 0x85, 0x72, 0xfb, 0xfe,
+ 0x8e, 0x21, 0x39, 0x2e, 0xcc, 0xe2, 0x9b, 0xc1,
+ 0xc2, 0x34, 0xeb, 0xc6, 0x52, 0x95, 0x18, 0xa2,
+ 0x77, 0x71, 0x71, 0x83, 0xd6, 0x1a, 0x49, 0x97,
+ 0x14, 0xfe, 0xc0, 0x7b, 0x18, 0xf6, 0x2c, 0x6c,
+ 0x93, 0xf0, 0x54, 0x8b, 0x26, 0x07, 0xfd, 0x0b,
+ 0x0f, 0x77, 0x5e, 0xbd, 0x08, 0xa8, 0xe6, 0x64,
+ 0x06, 0xd5, 0xa5, 0xa6, 0x1f, 0x6c, 0x4b, 0x91,
+ 0xc7, 0x66, 0x22, 0x8c, 0xae, 0xe7, 0x0a, 0x5c,
+ 0xfd, 0xa8, 0xb5, 0xb4, 0xea, 0xd3, 0x4a, 0x0d,
+ 0xed, 0x18, 0x1e, 0x2b, 0xe9, 0x11, 0xa7, 0x2e,
+ 0x09, 0x9e, 0x46, 0xc4, 0xd0, 0xac, 0xc2, 0x4e,
+ 0x7a, 0x95, 0x45, 0xb5, 0xf6, 0x9d, 0xe1, 0x55,
+ 0xff, 0xbc, 0x7d, 0x75, 0xb3, 0x33, 0x6b, 0xaf,
+ 0x76, 0xf4, 0xf2, 0xe4, 0xe4, 0xc8, 0x50, 0xf9,
+ 0xc1, 0x98, 0x0b, 0x38, 0x83, 0xf6, 0xad, 0x80,
+ 0x00, 0xa2, 0xac, 0x19, 0xc4, 0x14, 0xa9, 0xd8,
+ 0x2b, 0xef, 0x3f, 0x79, 0x4f, 0x83, 0x48, 0x65,
+ 0xcf, 0x42, 0xb9, 0x45, 0xc9, 0xc6, 0xca, 0xd2,
+ 0xc9, 0xe5, 0x3f, 0x9d, 0xbc, 0x84, 0xab, 0x3e,
+ 0xa9, 0x84, 0xdb, 0x81, 0xd4, 0x49, 0x2f, 0x02,
+ 0xdd, 0x4f, 0xf2, 0x24, 0x30, 0x23, 0xbf, 0x76,
+ 0x99, 0xbb, 0x63, 0x13, 0xa5, 0x42, 0x7e, 0xa4,
+ 0xe4, 0xd9, 0x66, 0x01, 0x53, 0xd6, 0x73, 0x0c,
+ 0xf2, 0x5c, 0x83, 0x72, 0x16, 0x76, 0xc7, 0x24,
+ 0x75, 0x56, 0xc8, 0xe1, 0x1c, 0xbb, 0xa9, 0x6b,
+ 0xb2, 0xd9, 0x0c, 0xd7, 0x56, 0xaf, 0x2f, 0x9e,
+ 0x5c, 0x9d, 0x3b, 0x75, 0x1a, 0xea, 0xb4, 0xd4,
+ 0x55, 0xbd, 0xa1, 0x6f, 0x9e, 0xfe, 0x0b, 0x35,
+ 0x69, 0x71, 0xb4, 0xbf, 0x6f, 0xa5, 0x2c, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/single_player_icon_text.png.h b/src/images/single_player_icon_text.png.h
new file mode 100644
index 0000000..a89ec30
--- /dev/null
+++ b/src/images/single_player_icon_text.png.h
@@ -0,0 +1,226 @@
+/* single_player_icon_text.png - 1782 bytes */
+ static const unsigned char single_player_icon_text_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x69, 0x71,
+ 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0d, 0xd7, 0x00, 0x00, 0x0d, 0xd7,
+ 0x01, 0x42, 0x28, 0x9b, 0x78, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x03,
+ 0x16, 0x14, 0x28, 0x05, 0x36, 0x73, 0x17, 0xf8,
+ 0x00, 0x00, 0x06, 0x76, 0x49, 0x44, 0x41, 0x54,
+ 0x78, 0xda, 0xed, 0x98, 0x5d, 0x68, 0x14, 0x57,
+ 0x14, 0xc7, 0xff, 0xbb, 0xd9, 0xcd, 0x6e, 0x4c,
+ 0x13, 0x4d, 0x5a, 0x62, 0x16, 0x4b, 0x08, 0xa9,
+ 0xeb, 0x43, 0xd6, 0x50, 0xa5, 0x46, 0x4b, 0x45,
+ 0xb0, 0x2f, 0xd6, 0xe2, 0x07, 0x56, 0x51, 0xd0,
+ 0xd0, 0x10, 0x7c, 0x89, 0xd2, 0x48, 0xc5, 0x18,
+ 0x88, 0x5a, 0xa1, 0x8a, 0xa8, 0x25, 0x82, 0x69,
+ 0xad, 0x04, 0x44, 0x2b, 0x58, 0x0b, 0x82, 0x04,
+ 0x8c, 0xd4, 0xe8, 0x96, 0xa5, 0x49, 0x4c, 0xb4,
+ 0x2c, 0x89, 0x8a, 0x84, 0xe6, 0xcb, 0x50, 0x0d,
+ 0x18, 0x25, 0x9a, 0x8d, 0xe6, 0x63, 0x3f, 0x27,
+ 0x33, 0xff, 0xbe, 0xcc, 0x2c, 0xd3, 0x75, 0xd7,
+ 0xac, 0x64, 0x57, 0x2d, 0xde, 0x1f, 0x9c, 0x87,
+ 0x99, 0xb9, 0x73, 0x66, 0xe6, 0x7f, 0xef, 0x39,
+ 0xf7, 0x9c, 0x31, 0x20, 0x71, 0x30, 0xe2, 0xd8,
+ 0x80, 0xc4, 0x92, 0x14, 0xff, 0xc6, 0x38, 0xc7,
+ 0x7d, 0x01, 0xe0, 0x2f, 0x00, 0x41, 0x9d, 0x8d,
+ 0x03, 0xf8, 0x1b, 0xc0, 0x6f, 0xe1, 0x37, 0x24,
+ 0x41, 0x12, 0xc9, 0x22, 0xd9, 0xfe, 0x63, 0xb1,
+ 0xd1, 0x62, 0xb1, 0xf0, 0xc8, 0x91, 0x23, 0x1c,
+ 0x18, 0x18, 0xe0, 0xe4, 0xe4, 0x24, 0x83, 0xc1,
+ 0x20, 0x87, 0x86, 0x86, 0x94, 0xce, 0xce, 0x4e,
+ 0xbf, 0x4e, 0x00, 0x6a, 0x44, 0x99, 0xad, 0x04,
+ 0x7d, 0x7f, 0x52, 0xfd, 0xc7, 0xa4, 0xff, 0xc4,
+ 0x89, 0x13, 0x24, 0xc9, 0xf2, 0xf2, 0x72, 0xa6,
+ 0xa5, 0xa5, 0x05, 0xb3, 0xb2, 0xb2, 0x82, 0xeb,
+ 0xd7, 0xaf, 0xf7, 0xdf, 0xb8, 0x71, 0x63, 0x42,
+ 0x2f, 0xc0, 0x14, 0xf6, 0x4c, 0x67, 0x43, 0x00,
+ 0x0e, 0x03, 0x30, 0xab, 0xf7, 0xe6, 0x03, 0xf8,
+ 0x13, 0x80, 0x57, 0x67, 0x2f, 0xf8, 0x88, 0x22,
+ 0x40, 0x26, 0x80, 0x1f, 0x00, 0x3c, 0x02, 0x30,
+ 0xaa, 0xb3, 0x5f, 0x01, 0x7c, 0x98, 0x28, 0x01,
+ 0x1e, 0x79, 0x3c, 0x1e, 0x92, 0x64, 0x76, 0x76,
+ 0x36, 0x01, 0x5c, 0x04, 0xf0, 0x25, 0x80, 0x63,
+ 0x3a, 0x8b, 0x36, 0x43, 0xe1, 0xe3, 0x0d, 0x1b,
+ 0x36, 0xd0, 0xed, 0x76, 0x4b, 0x7e, 0xbf, 0x5f,
+ 0x99, 0x98, 0x98, 0xa0, 0xd3, 0xe9, 0xa4, 0xdd,
+ 0x6e, 0x27, 0x80, 0x5f, 0x00, 0xcc, 0x06, 0xc0,
+ 0x92, 0x92, 0x12, 0xf6, 0xf7, 0xf7, 0x33, 0x14,
+ 0x0a, 0xb1, 0xab, 0xab, 0x4b, 0x2e, 0x2d, 0x2d,
+ 0x8d, 0xe9, 0x4f, 0x3d, 0x9e, 0x05, 0xc0, 0xbf,
+ 0x6c, 0xd9, 0xb2, 0xa0, 0xcb, 0xe5, 0x92, 0xc7,
+ 0xc6, 0xc6, 0x94, 0x40, 0x20, 0xc0, 0x8e, 0x8e,
+ 0x0e, 0x6e, 0xdc, 0xb8, 0x51, 0x1b, 0xf3, 0x51,
+ 0x42, 0x04, 0x18, 0x1b, 0x1b, 0x23, 0x49, 0xde,
+ 0xbd, 0x7b, 0x97, 0x47, 0x8f, 0x1e, 0xe5, 0xda,
+ 0xb5, 0x6b, 0x99, 0x99, 0x99, 0x49, 0x00, 0x7e,
+ 0x00, 0x55, 0x6a, 0x2e, 0x89, 0xf9, 0xc2, 0xed,
+ 0xed, 0xed, 0x74, 0x38, 0x1c, 0x63, 0x16, 0x8b,
+ 0xe5, 0xd9, 0xee, 0xdd, 0xbb, 0x49, 0x92, 0x6e,
+ 0xb7, 0x9b, 0x6a, 0x2e, 0xa9, 0x5b, 0xbd, 0x7a,
+ 0x35, 0x49, 0xb2, 0xb9, 0xb9, 0x99, 0x36, 0x9b,
+ 0xcd, 0x67, 0xb3, 0xd9, 0x7c, 0xad, 0xad, 0xad,
+ 0x53, 0x09, 0xf0, 0xd3, 0xf2, 0xe5, 0xcb, 0x29,
+ 0x49, 0x12, 0x9b, 0x9b, 0x9b, 0x99, 0x97, 0x97,
+ 0x37, 0x9e, 0x91, 0x91, 0x31, 0x76, 0xfa, 0xf4,
+ 0x69, 0x92, 0x64, 0x69, 0x69, 0x29, 0x01, 0x38,
+ 0x13, 0x22, 0x40, 0x49, 0x49, 0x09, 0x87, 0x87,
+ 0x87, 0xa9, 0x47, 0x92, 0x24, 0xd6, 0xd7, 0xd7,
+ 0xd3, 0x66, 0xb3, 0x51, 0x5d, 0xce, 0x31, 0x5f,
+ 0x78, 0xe1, 0xc2, 0x85, 0x04, 0x70, 0x0e, 0x40,
+ 0x71, 0x7a, 0x7a, 0x3a, 0x49, 0x72, 0x72, 0x72,
+ 0x52, 0x1b, 0xe7, 0x69, 0x6b, 0x6b, 0x23, 0x49,
+ 0x16, 0x17, 0x17, 0x13, 0xc0, 0x8f, 0x00, 0x4e,
+ 0x2e, 0x59, 0xb2, 0x64, 0x2a, 0x01, 0x9e, 0xb6,
+ 0xb4, 0xb4, 0x90, 0x24, 0x8b, 0x8a, 0x8a, 0xc2,
+ 0x63, 0xb2, 0xb3, 0xb3, 0x49, 0x92, 0xbd, 0xbd,
+ 0xbd, 0x9a, 0xc0, 0xd3, 0x26, 0x1f, 0x40, 0x5f,
+ 0x6a, 0x6a, 0x2a, 0x57, 0xac, 0x58, 0xc1, 0xf3,
+ 0xe7, 0xcf, 0x53, 0x0b, 0x09, 0x92, 0x74, 0x3a,
+ 0x9d, 0x54, 0xe3, 0x2e, 0xe6, 0x0b, 0xa7, 0xa4,
+ 0xa4, 0x10, 0x40, 0x5a, 0x8c, 0x50, 0xf1, 0xf8,
+ 0x7c, 0x3e, 0x92, 0xa4, 0xc5, 0x62, 0x21, 0x80,
+ 0x74, 0x00, 0xef, 0x59, 0xad, 0xd6, 0x29, 0x05,
+ 0xf0, 0x7a, 0xbd, 0x8c, 0x85, 0x2a, 0x70, 0x30,
+ 0x91, 0xc9, 0xf0, 0x7d, 0x00, 0xdb, 0x01, 0xf4,
+ 0x1b, 0x8d, 0x46, 0x1e, 0x3b, 0x76, 0x8c, 0x24,
+ 0x19, 0x08, 0x04, 0xa6, 0x14, 0x20, 0x22, 0x6b,
+ 0xc7, 0x14, 0x20, 0x35, 0x35, 0x55, 0x13, 0xea,
+ 0x95, 0x04, 0x98, 0x39, 0x73, 0x66, 0xac, 0xc4,
+ 0x9b, 0x10, 0x01, 0xce, 0xe9, 0xec, 0x63, 0x00,
+ 0x16, 0x00, 0x6b, 0xb2, 0xb2, 0xb2, 0x48, 0x92,
+ 0x4f, 0x9f, 0x3e, 0x9d, 0xb6, 0x00, 0x5a, 0x08,
+ 0xa8, 0xa1, 0x72, 0x18, 0xc0, 0xcf, 0xf1, 0x84,
+ 0x40, 0x53, 0x53, 0x13, 0x49, 0x72, 0xcd, 0x9a,
+ 0x35, 0x04, 0xf0, 0x87, 0x2a, 0xde, 0x47, 0x00,
+ 0xea, 0x74, 0x36, 0x7d, 0x01, 0xba, 0xbb, 0xbb,
+ 0x9f, 0x57, 0x56, 0x56, 0x3e, 0x77, 0x38, 0x1c,
+ 0x93, 0x56, 0xab, 0x55, 0x4a, 0x4f, 0x4f, 0x97,
+ 0xca, 0xcb, 0xcb, 0x49, 0x92, 0xb5, 0xb5, 0xb5,
+ 0x04, 0xd0, 0x3b, 0x0d, 0x01, 0xc2, 0x49, 0xd0,
+ 0xe9, 0x74, 0x32, 0x27, 0x27, 0xc7, 0x97, 0x9b,
+ 0x9b, 0xeb, 0xbb, 0x7e, 0xfd, 0xfa, 0x54, 0xfe,
+ 0x8e, 0x2f, 0x5d, 0xba, 0x94, 0xc1, 0x60, 0x90,
+ 0x7d, 0x7d, 0x7d, 0x5c, 0xb0, 0x60, 0x41, 0xc0,
+ 0x64, 0x32, 0xf9, 0xf3, 0xf2, 0xf2, 0x02, 0x15,
+ 0x15, 0x15, 0x0f, 0x7a, 0x7a, 0x7a, 0x1e, 0x27,
+ 0x4c, 0x80, 0x96, 0x96, 0x96, 0xa1, 0x7b, 0xf7,
+ 0xee, 0x49, 0xa3, 0xa3, 0xa3, 0x94, 0x65, 0x99,
+ 0xc1, 0x60, 0x90, 0x5d, 0x5d, 0x5d, 0xdc, 0xbf,
+ 0x7f, 0x3f, 0xcd, 0x66, 0x33, 0x01, 0x7c, 0x35,
+ 0x0d, 0x01, 0x5e, 0xd8, 0x06, 0x7b, 0x7b, 0x7b,
+ 0xe5, 0xad, 0x5b, 0xb7, 0x46, 0x26, 0xcb, 0xc8,
+ 0xfb, 0x32, 0x01, 0x8c, 0x2f, 0x5e, 0xbc, 0xd8,
+ 0xdb, 0xd0, 0xd0, 0x20, 0x0d, 0x0f, 0x0f, 0x2b,
+ 0x92, 0x24, 0x71, 0x70, 0x70, 0x50, 0xb9, 0x74,
+ 0xe9, 0xd2, 0xc8, 0xe6, 0xcd, 0x9b, 0x2f, 0x25,
+ 0x4a, 0x80, 0x7d, 0x00, 0xae, 0x02, 0x78, 0x08,
+ 0x40, 0xd2, 0xd9, 0x38, 0x80, 0xdf, 0x01, 0x2c,
+ 0x8b, 0xb3, 0x10, 0x42, 0x8c, 0x71, 0x50, 0xb7,
+ 0xd2, 0xff, 0x14, 0x42, 0xf3, 0xe6, 0xcd, 0x23,
+ 0x49, 0xf6, 0xf4, 0xf4, 0x68, 0xb1, 0x1c, 0xed,
+ 0xbe, 0x74, 0x00, 0xd5, 0x00, 0xfa, 0xd4, 0x2d,
+ 0x59, 0xb3, 0xdb, 0x00, 0xbe, 0x01, 0x30, 0x13,
+ 0xff, 0x13, 0xaa, 0xda, 0xda, 0xda, 0x06, 0x16,
+ 0x2d, 0x5a, 0xe4, 0x37, 0x9b, 0xcd, 0xde, 0x82,
+ 0x82, 0x02, 0xdf, 0xb5, 0x6b, 0xd7, 0xf4, 0xfb,
+ 0xf9, 0xd5, 0xb7, 0xfd, 0x03, 0x62, 0xcd, 0x76,
+ 0xdc, 0x02, 0xec, 0xd8, 0xb1, 0xa3, 0xe5, 0xd6,
+ 0xad, 0x5b, 0x72, 0x28, 0x14, 0xe2, 0xe8, 0xe8,
+ 0xa8, 0xd2, 0xd4, 0xd4, 0xc4, 0x75, 0xeb, 0xd6,
+ 0x25, 0xb4, 0xa2, 0x4b, 0xc4, 0x87, 0x69, 0xe6,
+ 0x55, 0xab, 0xac, 0x4f, 0x12, 0xd4, 0xa8, 0xcc,
+ 0x51, 0xeb, 0x77, 0x7d, 0x2f, 0xf0, 0x10, 0xc0,
+ 0x71, 0x00, 0xb6, 0x37, 0x3a, 0xb3, 0x91, 0xa8,
+ 0x49, 0x8a, 0xbb, 0x76, 0xed, 0xa2, 0xc1, 0x60,
+ 0x20, 0x80, 0x4f, 0xdf, 0x64, 0xa7, 0xf6, 0xda,
+ 0x04, 0xd0, 0x66, 0xdf, 0x66, 0xb3, 0xb1, 0xb1,
+ 0xb1, 0x91, 0x24, 0x59, 0x5d, 0x5d, 0x4d, 0x00,
+ 0x37, 0x62, 0x08, 0xb0, 0x30, 0x62, 0xd5, 0x48,
+ 0x00, 0xee, 0x02, 0xf8, 0x5a, 0xad, 0x29, 0xf4,
+ 0xd7, 0xb4, 0xce, 0xed, 0x83, 0x88, 0xf3, 0x17,
+ 0xe3, 0xec, 0xf8, 0x22, 0x57, 0xe8, 0xd0, 0x34,
+ 0x43, 0x32, 0xa6, 0x00, 0x46, 0x00, 0x07, 0xe7,
+ 0xce, 0x9d, 0x4b, 0x92, 0x7c, 0xf0, 0xe0, 0x81,
+ 0x16, 0x0e, 0xd1, 0x04, 0xf8, 0x6c, 0xe7, 0xce,
+ 0x9d, 0x24, 0x49, 0x59, 0x96, 0xf9, 0xf8, 0xf1,
+ 0x63, 0x9e, 0x3a, 0x75, 0x4a, 0x6b, 0xa2, 0xce,
+ 0xb5, 0xb7, 0xb7, 0x93, 0xa4, 0xd6, 0xb9, 0xed,
+ 0x53, 0xef, 0xd9, 0xbc, 0x72, 0xe5, 0xca, 0x70,
+ 0xe3, 0xa5, 0x0a, 0x10, 0x4f, 0xc7, 0x17, 0x7e,
+ 0xfe, 0xa6, 0x4d, 0x9b, 0xe8, 0x76, 0xbb, 0x43,
+ 0x13, 0x13, 0x13, 0x09, 0x59, 0x91, 0xd1, 0x3e,
+ 0xcc, 0x6c, 0x32, 0x99, 0xc2, 0xe1, 0xf0, 0x32,
+ 0x01, 0xf6, 0xee, 0xdd, 0xcb, 0xc2, 0xc2, 0x42,
+ 0x5a, 0xad, 0x56, 0x6a, 0xfb, 0xfa, 0xd9, 0xb3,
+ 0x67, 0x09, 0xa0, 0xb7, 0xac, 0xac, 0x8c, 0x24,
+ 0xd9, 0xd0, 0xd0, 0xa0, 0xf9, 0x30, 0x00, 0xb8,
+ 0x5d, 0x57, 0x57, 0x47, 0x92, 0xac, 0xaa, 0xaa,
+ 0x22, 0x80, 0x8b, 0x71, 0x76, 0x7c, 0xe1, 0xe7,
+ 0xdf, 0xbc, 0x79, 0x93, 0x0e, 0x87, 0x63, 0x58,
+ 0x0d, 0xcf, 0xe4, 0xac, 0x00, 0xbb, 0xdd, 0x3e,
+ 0xd5, 0x0a, 0x30, 0x03, 0xf8, 0x0e, 0xc0, 0x3f,
+ 0x00, 0x64, 0x00, 0x4c, 0x49, 0x49, 0xd1, 0x97,
+ 0xce, 0xb2, 0xd5, 0x6a, 0xa5, 0xc7, 0xe3, 0x61,
+ 0x28, 0x14, 0xd2, 0xfe, 0x33, 0x14, 0x1a, 0x0c,
+ 0x06, 0x0e, 0x0e, 0x0e, 0x52, 0x96, 0x65, 0xce,
+ 0x99, 0x33, 0xe7, 0x55, 0x3a, 0xbe, 0xf0, 0xf3,
+ 0xe7, 0xcf, 0x9f, 0x4f, 0x00, 0xa7, 0x00, 0xa4,
+ 0x26, 0x25, 0x07, 0xe4, 0xe6, 0xe6, 0xc6, 0x93,
+ 0x03, 0xce, 0xd9, 0xed, 0x76, 0x5e, 0xbe, 0x7c,
+ 0x99, 0x23, 0x23, 0x23, 0x54, 0x14, 0x25, 0x7c,
+ 0x5d, 0x51, 0x14, 0x6d, 0x4c, 0x7f, 0x4d, 0x4d,
+ 0x0d, 0x49, 0x72, 0xdb, 0xb6, 0x6d, 0x04, 0x70,
+ 0xb2, 0xb8, 0xb8, 0x98, 0x24, 0xe9, 0x72, 0xb9,
+ 0xb4, 0x9c, 0x11, 0x6f, 0xc7, 0x17, 0x3e, 0x67,
+ 0x34, 0x1a, 0x09, 0xc0, 0x9a, 0xb4, 0x5d, 0x40,
+ 0x92, 0x24, 0xf6, 0xf5, 0xf5, 0xb1, 0xb2, 0xb2,
+ 0xf2, 0x65, 0xbb, 0x80, 0x57, 0x8b, 0xf1, 0x8a,
+ 0x8a, 0x0a, 0x5a, 0x2c, 0x16, 0x1a, 0x8d, 0xc6,
+ 0xc8, 0x31, 0xab, 0x0b, 0x0a, 0x0a, 0xa8, 0x28,
+ 0x0a, 0x5b, 0x5b, 0x5b, 0x09, 0x40, 0x3e, 0x74,
+ 0xe8, 0x10, 0x49, 0xb2, 0xac, 0xac, 0x8c, 0x00,
+ 0x6a, 0x5e, 0xa1, 0xe3, 0x4b, 0xda, 0x2e, 0xf4,
+ 0xc2, 0x0a, 0x50, 0xcd, 0xaf, 0x76, 0x5f, 0x8b,
+ 0x62, 0x8c, 0xf3, 0x86, 0x42, 0x21, 0x92, 0x64,
+ 0x5a, 0x5a, 0x1a, 0x01, 0x7c, 0x5f, 0x58, 0x58,
+ 0x18, 0x2d, 0x4c, 0xe4, 0xc6, 0xc6, 0x46, 0x2a,
+ 0x8a, 0xc2, 0xfc, 0xfc, 0x7c, 0x76, 0x76, 0x76,
+ 0xd2, 0xe7, 0xf3, 0x31, 0x23, 0x23, 0x83, 0x00,
+ 0xe6, 0xbe, 0x42, 0xc7, 0xf7, 0xda, 0x04, 0x88,
+ 0x77, 0x9c, 0xf7, 0xce, 0x9d, 0x3b, 0x24, 0xc9,
+ 0x2d, 0x5b, 0xb6, 0x70, 0xd6, 0xac, 0x59, 0x81,
+ 0x2b, 0x57, 0xae, 0x44, 0xf3, 0x75, 0x50, 0xeb,
+ 0x04, 0xcf, 0x9c, 0x39, 0x43, 0x92, 0xbc, 0x70,
+ 0xe1, 0x02, 0x01, 0x78, 0xd4, 0xa4, 0x18, 0x6f,
+ 0xc7, 0xf7, 0xd6, 0x09, 0x70, 0xa1, 0xa8, 0xa8,
+ 0x88, 0x1d, 0x1d, 0x1d, 0x94, 0x24, 0x89, 0x03,
+ 0x03, 0x03, 0xca, 0xf6, 0xed, 0xdb, 0xa3, 0xf9,
+ 0x9a, 0x6d, 0x34, 0x1a, 0x79, 0xff, 0xfe, 0xfd,
+ 0xf0, 0xb5, 0x55, 0xab, 0x56, 0x11, 0xc0, 0xb7,
+ 0xba, 0xbf, 0xbe, 0xf1, 0x74, 0x7c, 0xc9, 0x13,
+ 0x20, 0xce, 0x82, 0x22, 0x72, 0x9c, 0x55, 0x2d,
+ 0x54, 0xf4, 0x1d, 0x5a, 0x2c, 0x5f, 0xad, 0x7b,
+ 0xf6, 0xec, 0x21, 0x49, 0x3e, 0x79, 0xf2, 0x84,
+ 0x26, 0x93, 0x89, 0x00, 0x72, 0x74, 0xd7, 0xe3,
+ 0xe9, 0xf8, 0x98, 0xa8, 0xc2, 0xe7, 0x75, 0x52,
+ 0x03, 0x80, 0x33, 0x66, 0xcc, 0x60, 0x7d, 0x7d,
+ 0x3d, 0x49, 0xf2, 0xc0, 0x81, 0x03, 0x04, 0xd0,
+ 0x8d, 0x77, 0x84, 0x1a, 0x97, 0xcb, 0x15, 0x9e,
+ 0xf9, 0xda, 0xda, 0x5a, 0x6d, 0xf6, 0x3f, 0x7f,
+ 0x67, 0x04, 0x88, 0x58, 0xb6, 0xdd, 0xea, 0x9f,
+ 0x25, 0x81, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02,
+ 0x81, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x81,
+ 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40,
+ 0x20, 0x10, 0x08, 0x04, 0x02, 0x81, 0x20, 0x81,
+ 0xfc, 0x0b, 0x31, 0xdb, 0xf0, 0xca, 0x63, 0xe2,
+ 0x06, 0x91, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+ 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/spectator.png.h b/src/images/spectator.png.h
new file mode 100644
index 0000000..b7e0e90
--- /dev/null
+++ b/src/images/spectator.png.h
@@ -0,0 +1,95 @@
+/* spectator.png - 731 bytes */
+ static const unsigned char spectator_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x08,
+ 0x16, 0x00, 0x36, 0x1e, 0x04, 0xa8, 0xdb, 0x76,
+ 0x00, 0x00, 0x02, 0x5b, 0x49, 0x44, 0x41, 0x54,
+ 0x38, 0x4f, 0xc5, 0x53, 0xcb, 0x4e, 0x14, 0x41,
+ 0x14, 0x3d, 0x55, 0xd3, 0xd3, 0x03, 0x3d, 0x0d,
+ 0x32, 0x34, 0x28, 0xef, 0x97, 0xb0, 0x30, 0x20,
+ 0x84, 0x68, 0x62, 0xdc, 0x68, 0xdc, 0xb8, 0x30,
+ 0x31, 0x46, 0xb7, 0x2e, 0xdc, 0xbb, 0x31, 0x31,
+ 0x21, 0xee, 0xe4, 0x03, 0x4c, 0xdc, 0x98, 0x90,
+ 0xf8, 0x0f, 0x26, 0xc6, 0x18, 0x43, 0x74, 0xe7,
+ 0xc2, 0xe0, 0x23, 0xca, 0x02, 0x19, 0x85, 0x00,
+ 0xd3, 0xda, 0xbc, 0x06, 0x19, 0x66, 0x98, 0x47,
+ 0x4f, 0x77, 0xd7, 0xcb, 0x9a, 0x5e, 0x10, 0x23,
+ 0x1f, 0x40, 0x25, 0x77, 0x51, 0x95, 0x73, 0x4e,
+ 0x9d, 0xba, 0xf7, 0x14, 0x70, 0xd2, 0x8b, 0xfc,
+ 0x6f, 0x60, 0x33, 0xf7, 0x53, 0x91, 0xfa, 0x41,
+ 0x16, 0x91, 0x2f, 0x89, 0xe4, 0x26, 0x04, 0x2f,
+ 0x42, 0x0a, 0x10, 0x92, 0x00, 0xd2, 0xce, 0xdb,
+ 0xee, 0xf1, 0xcb, 0xb3, 0xff, 0x72, 0x8e, 0x04,
+ 0x3c, 0xcf, 0x53, 0x89, 0xfa, 0x1e, 0x68, 0x58,
+ 0x80, 0x49, 0x0d, 0xb0, 0x28, 0x40, 0xa9, 0x58,
+ 0x04, 0x8f, 0x22, 0xa4, 0x34, 0xb7, 0xb3, 0x25,
+ 0x0d, 0xc1, 0x42, 0xc1, 0xa5, 0xca, 0xaa, 0xde,
+ 0xe9, 0x5f, 0x67, 0x46, 0xcf, 0xdf, 0x6c, 0x08,
+ 0xc5, 0x02, 0x31, 0xb9, 0xb4, 0x0e, 0x13, 0x0c,
+ 0x9b, 0xdb, 0xdb, 0xf0, 0x76, 0x0e, 0x10, 0x10,
+ 0x1b, 0x2c, 0xd5, 0x05, 0x26, 0x08, 0x22, 0x2e,
+ 0x91, 0xe6, 0x79, 0xf4, 0x60, 0x1b, 0x13, 0xfd,
+ 0x0e, 0xa8, 0x76, 0x24, 0x7b, 0x26, 0xd1, 0x31,
+ 0x79, 0x8d, 0x18, 0xae, 0xeb, 0x3e, 0x4f, 0x54,
+ 0x7e, 0xc3, 0x94, 0x75, 0x2c, 0xad, 0xba, 0x30,
+ 0x07, 0xaf, 0xc2, 0x4f, 0x77, 0x83, 0x71, 0x20,
+ 0x64, 0x0a, 0x81, 0xae, 0x90, 0x49, 0xec, 0x45,
+ 0x5a, 0xa4, 0xcf, 0x44, 0xa1, 0xf2, 0x06, 0xe9,
+ 0x6a, 0x0e, 0x76, 0x6e, 0x01, 0xde, 0xd2, 0x82,
+ 0x22, 0x9b, 0x6b, 0x4b, 0x8a, 0x14, 0x57, 0x71,
+ 0xa8, 0xda, 0x30, 0x36, 0x7d, 0x05, 0xf3, 0xdf,
+ 0x7c, 0x94, 0x7c, 0x19, 0x93, 0x67, 0xee, 0x4e,
+ 0x41, 0x29, 0x89, 0x99, 0xb9, 0x45, 0x2d, 0x24,
+ 0xd1, 0x94, 0x24, 0x78, 0x74, 0xbb, 0x1d, 0xfb,
+ 0x3f, 0x3e, 0x41, 0x7e, 0x9f, 0xc7, 0x7e, 0x95,
+ 0xc3, 0x60, 0x07, 0x1b, 0x68, 0xee, 0x9a, 0xc2,
+ 0x70, 0x67, 0x6f, 0xdc, 0x9b, 0x06, 0xd1, 0x0f,
+ 0x05, 0x42, 0xed, 0x40, 0x49, 0x19, 0x0b, 0xf8,
+ 0x91, 0xde, 0x87, 0x12, 0x44, 0xd1, 0x18, 0xd3,
+ 0x36, 0x76, 0x01, 0x35, 0xab, 0x15, 0xec, 0xf5,
+ 0x1c, 0x8c, 0xe4, 0xe9, 0x09, 0x98, 0x76, 0x06,
+ 0x42, 0x08, 0x50, 0x4a, 0xe1, 0xb4, 0xe8, 0x9e,
+ 0x14, 0x04, 0x02, 0x6d, 0xf9, 0xc1, 0xb3, 0xcf,
+ 0x08, 0x23, 0x2d, 0x58, 0xe7, 0xb1, 0x83, 0xf1,
+ 0x01, 0x0b, 0x52, 0x8b, 0xc6, 0xd8, 0xf6, 0x3e,
+ 0x64, 0x46, 0x26, 0xca, 0x54, 0x95, 0xb7, 0xc0,
+ 0xca, 0x79, 0x70, 0xce, 0xc1, 0x18, 0xc3, 0x80,
+ 0x43, 0x61, 0x9b, 0x12, 0x35, 0x9f, 0xa1, 0xa6,
+ 0x89, 0xb5, 0x80, 0xa1, 0xaa, 0xab, 0xc3, 0x26,
+ 0x98, 0x1e, 0xd2, 0xd3, 0xd1, 0x98, 0x06, 0x36,
+ 0xdc, 0x59, 0x07, 0x2d, 0x6d, 0xb9, 0x86, 0x6c,
+ 0x76, 0xa0, 0x76, 0xf5, 0xd8, 0x2b, 0x79, 0x08,
+ 0x67, 0x08, 0x4e, 0xfa, 0x14, 0x2e, 0x9d, 0xa5,
+ 0x48, 0x51, 0x85, 0xac, 0x17, 0x42, 0x3f, 0x02,
+ 0xe7, 0xfa, 0x4d, 0x5c, 0x1c, 0x35, 0xf5, 0x33,
+ 0xf5, 0x44, 0x6a, 0x65, 0x30, 0x77, 0x11, 0xec,
+ 0xeb, 0x2b, 0xec, 0x24, 0x7b, 0xd7, 0xe3, 0x31,
+ 0xae, 0x2c, 0x2e, 0x08, 0xab, 0xb0, 0x4c, 0x9b,
+ 0x0d, 0x02, 0x95, 0x19, 0xd6, 0x81, 0xe9, 0xd4,
+ 0x95, 0x01, 0x8c, 0xd4, 0x51, 0x66, 0x94, 0x52,
+ 0x50, 0x7f, 0x72, 0x90, 0x1b, 0x1f, 0x11, 0x79,
+ 0xcb, 0x58, 0x09, 0x6c, 0x5c, 0x7f, 0xf8, 0x94,
+ 0x1c, 0x05, 0xe9, 0xcb, 0xfb, 0x77, 0xd9, 0x68,
+ 0x77, 0xd5, 0xea, 0x22, 0x87, 0x83, 0xb6, 0xd5,
+ 0x04, 0xa4, 0x5a, 0x21, 0x93, 0x96, 0x6e, 0xa2,
+ 0x0e, 0x8b, 0xe4, 0xe0, 0xd5, 0x22, 0x90, 0x5f,
+ 0xf3, 0xdd, 0xfd, 0xaa, 0x55, 0x69, 0x1b, 0xc1,
+ 0x8d, 0xfb, 0x8f, 0x63, 0xee, 0xb1, 0x28, 0x37,
+ 0x0e, 0x5f, 0xcc, 0xde, 0xfb, 0xa0, 0xcd, 0x14,
+ 0x4c, 0x02, 0x23, 0x01, 0xd1, 0x23, 0xb9, 0x48,
+ 0xd4, 0x83, 0x60, 0xe3, 0xce, 0x93, 0x97, 0xb7,
+ 0x4e, 0xfa, 0xef, 0x1d, 0xbf, 0xff, 0x2f, 0x00,
+ 0x30, 0x39, 0x31, 0x2b, 0xc7, 0x20, 0xa9, 0x00,
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
+ 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/spectator.xpm b/src/images/spectator.xpm
new file mode 100644
index 0000000..9afeb01
--- /dev/null
+++ b/src/images/spectator.xpm
@@ -0,0 +1,168 @@
+/* XPM */
+static const char * spectator_xpm[] = {
+"16 16 149 2",
+" c None",
+". c #E4DFD8",
+"+ c #E5D6C6",
+"@ c #E5D0BC",
+"# c #E6CEB8",
+"$ c #E6CBB4",
+"% c #E6C9B1",
+"& c #E7CAB4",
+"* c #E7D5C7",
+"= c #E3E3E3",
+"- c #E6DACD",
+"; c #E8D3BA",
+"> c #EED5BE",
+", c #E9CFB6",
+"' c #D9BEA5",
+") c #D5B89F",
+"! c #DCBB9F",
+"~ c #F1C8AA",
+"{ c #EEC3A3",
+"] c #EAC1A2",
+"^ c #E9DCD3",
+"/ c #E6D3C0",
+"( c #ECD3BB",
+"_ c #D0B9A1",
+": c #B3A08F",
+"< c #ABA19B",
+"[ c #A6A8B3",
+"} c #A1A5B4",
+"| c #9BA1B2",
+"1 c #A69D9B",
+"2 c #C09D81",
+"3 c #ECBA94",
+"4 c #EEB891",
+"5 c #ECD2BF",
+"6 c #E0E0E0",
+"7 c #E6D6C5",
+"8 c #ECD1B7",
+"9 c #BFAB97",
+"0 c #C5CAD6",
+"a c #A9C4EF",
+"b c #A4C0EF",
+"c c #9DBBEE",
+"d c #95B6ED",
+"e c #8EB1EB",
+"f c #85ABE9",
+"g c #B1C7EF",
+"h c #D9BAA4",
+"i c #E4AC83",
+"j c #F0B186",
+"k c #E3D3C7",
+"l c #E4DCD3",
+"m c #E5CBAD",
+"n c #D6CABD",
+"o c #FBFBFB",
+"p c #B2C9F1",
+"q c #A2BFEF",
+"r c #9BBAEE",
+"s c #10151D",
+"t c #0F141B",
+"u c #84AAEA",
+"v c #7CA5E8",
+"w c #84AAE9",
+"x c #E7D2C4",
+"y c #E5A67B",
+"z c #D19A77",
+"A c #DFCAB1",
+"B c #E8E2DC",
+"C c #F7F7F7",
+"D c #ABC4F0",
+"E c #98B8EC",
+"F c #91B4EC",
+"G c #0F131B",
+"H c #0E1219",
+"I c #7AA4E7",
+"J c #739DE5",
+"K c #7DA4E7",
+"L c #ECDCD2",
+"M c #CC8F68",
+"N c #E4E0DD",
+"O c #EEEEEE",
+"P c #F4F4F4",
+"Q c #F9F9F9",
+"R c #BED1F0",
+"S c #8EB1E9",
+"T c #86ABE7",
+"U c #7EA6E5",
+"V c #77A0E4",
+"W c #709BE3",
+"X c #6896E1",
+"Y c #9EBBEB",
+"Z c #DDB194",
+"` c #E3D2C2",
+" . c #E9E0D7",
+".. c #F0F0F0",
+"+. c #DCE4F2",
+"@. c #9AB7E7",
+"#. c #7BA1E2",
+"$. c #739DE1",
+"%. c #6C98DF",
+"&. c #6493DE",
+"*. c #7CA2E2",
+"=. c #CFDBEF",
+"-. c #E7D5CB",
+";. c #DFA179",
+">. c #E1DBD5",
+",. c #E8C8AD",
+"'. c #EAD3C0",
+"). c #EDE6E0",
+"!. c #EFEFEF",
+"~. c #D1DAE9",
+"{. c #A1B9E1",
+"]. c #779CDA",
+"^. c #7198D9",
+"/. c #95B0DF",
+"(. c #C9D4E8",
+"_. c #EEE9E6",
+":. c #E9C9B5",
+"<. c #E29666",
+"[. c #C69B81",
+"}. c #D9CFC7",
+"|. c #E3BC9C",
+"1. c #ECC09D",
+"2. c #EBD1BE",
+"3. c #EBDCD3",
+"4. c #EBE7E4",
+"5. c #EBEBEB",
+"6. c #EAEAEA",
+"7. c #E9D5C9",
+"8. c #E7B391",
+"9. c #E19666",
+"0. c #BA8E72",
+"a. c #CBC1BA",
+"b. c #C5A994",
+"c. c #DDAA85",
+"d. c #E9B48D",
+"e. c #E9BB9B",
+"f. c #E7C0A5",
+"g. c #E6BFA5",
+"h. c #E7BDA1",
+"i. c #E3B190",
+"j. c #E39A6C",
+"k. c #C38660",
+"l. c #B69682",
+"m. c #AC7F5F",
+"n. c #B0805F",
+"o. c #B6815F",
+"p. c #B9815C",
+"q. c #B77D59",
+"r. c #AE7551",
+" ",
+" ",
+" . + @ # $ % & * ",
+" = - ; > , ' ) ! ~ { ] ^ ",
+" = / ( _ : < [ } | 1 2 3 4 5 ",
+"6 7 8 9 0 a b c d e f g h i j k ",
+"l m n o p q r s t u v w o x y z ",
+"A B C o D E F G H I J K o C L M ",
+"N O P Q R S T U V W X Y Q P O Z ",
+"` ...P +. at .#.$.%.&.*.=.P ..-.;.",
+">.,.'.).!.~.{.].^./.(..._.:.<.[.",
+" }.|.1.2.3.4.5.5.5.6.7.8.9.0. ",
+" a.b.c.d.e.f.g.h.i.j.k.l. ",
+" m.n.o.p.q.r. ",
+" ",
+" "};
diff --git a/src/images/spring.xpm b/src/images/spring.xpm
new file mode 100644
index 0000000..42d5f36
--- /dev/null
+++ b/src/images/spring.xpm
@@ -0,0 +1,139 @@
+/* XPM */
+static const char * spring_xpm[] = {
+"12 12 124 2",
+" c None",
+". c #EB4E17",
+"+ c #EA4D17",
+"@ c #E64A17",
+"# c #E04716",
+"$ c #DB4416",
+"% c #D44015",
+"& c #CE3C15",
+"* c #C63814",
+"= c #BF3313",
+"- c #B72F13",
+"; c #AF2B12",
+"> c #A72712",
+", c #E94C17",
+"' c #E84C17",
+") c #E44A17",
+"! c #DA4316",
+"~ c #CD3C15",
+"{ c #C63714",
+"] c #BE3313",
+"^ c #AF2A12",
+"/ c #A72612",
+"( c #E44917",
+"_ c #E14816",
+": c #DD4516",
+"< c #D84416",
+"[ c #E16F36",
+"} c #DB6631",
+"| c #C53814",
+"1 c #BD3213",
+"2 c #B52E13",
+"3 c #AE2A12",
+"4 c #A62612",
+"5 c #DF4716",
+"6 c #E5662F",
+"7 c #E87532",
+"8 c #E2651E",
+"9 c #FBE0C3",
+"0 c #F8D4B1",
+"a c #D3581B",
+"b c #D66E37",
+"c c #C14A25",
+"d c #AC2912",
+"e c #A42511",
+"f c #D94316",
+"g c #EB894A",
+"h c #FFFDFB",
+"i c #FAD4A6",
+"j c #F2BB8D",
+"k c #F2BC90",
+"l c #FAD7AD",
+"m c #FFFEFC",
+"n c #CD612D",
+"o c #A92712",
+"p c #A12411",
+"q c #D34015",
+"r c #D74C18",
+"s c #ED8E3C",
+"t c #F9D6B5",
+"u c #D85A1E",
+"v c #C83D15",
+"w c #C33B15",
+"x c #D05C22",
+"y c #F8D9B8",
+"z c #D46C26",
+"A c #AE3214",
+"B c #9F2311",
+"C c #D14718",
+"D c #F5C59E",
+"E c #FFFBF6",
+"F c #E07838",
+"G c #C43714",
+"H c #C03414",
+"I c #BA3113",
+"J c #B63013",
+"K c #DB824B",
+"L c #FEF9F3",
+"M c #EAB997",
+"N c #A32D14",
+"O c #C63B15",
+"P c #E07E42",
+"Q c #FAE4CF",
+"R c #CE4F1A",
+"S c #B93013",
+"T c #B42E13",
+"U c #C3501E",
+"V c #F7E3D1",
+"W c #C76738",
+"X c #9A2312",
+"Y c #BE3614",
+"Z c #C54418",
+"` c #BC3514",
+" . c #B62E13",
+".. c #B22C13",
+"+. c #A92812",
+"@. c #A82C13",
+"#. c #AB3516",
+"$. c #9A2211",
+"%. c #921D11",
+"&. c #B42D13",
+"*. c #B22C12",
+"=. c #AB2912",
+"-. c #A32511",
+";. c #9E2211",
+">. c #992011",
+",. c #931D11",
+"'. c #8D1B10",
+"). c #AD2912",
+"!. c #AA2812",
+"~. c #A42512",
+"{. c #A12311",
+"]. c #9C2111",
+"^. c #981F11",
+"/. c #8E1B10",
+"(. c #881A10",
+"_. c #A52512",
+":. c #A22411",
+"<. c #A02311",
+"[. c #9D2211",
+"}. c #9A2011",
+"|. c #961F11",
+"1. c #911D11",
+"2. c #881910",
+"3. c #851810",
+". + @ # $ % & * = - ; > ",
+", ' ) # ! % ~ { ] - ^ / ",
+") ( _ : < [ } | 1 2 3 4 ",
+"5 5 6 7 8 9 0 a b c d e ",
+"f f g h i j k l m n o p ",
+"q r s t u v w x y z A B ",
+"C D E F G H I J K L M N ",
+"O P Q R 1 S T ; U V W X ",
+"1 Y Z ` ...3 +. at .#.$.%.",
+"2 2 &.*.; =.> -.;.>.,.'.",
+").).d !.> ~.{.].^.,./.(.",
+"_._.~.:.<.[.}.|.1.'.2.3."};
diff --git a/src/images/springlobby.svg b/src/images/springlobby.svg
new file mode 100644
index 0000000..60cff4f
--- /dev/null
+++ b/src/images/springlobby.svg
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ width="128"
+ height="128"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="springlobby.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <metadata
+ id="metadata29">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:window-height="951"
+ inkscape:window-width="1280"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="5.0098609"
+ inkscape:cx="75.34802"
+ inkscape:cy="61.690035"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:current-layer="svg2" />
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective31" />
+ <linearGradient
+ id="linearGradient7128">
+ <stop
+ style="stop-color:#f5a87e;stop-opacity:1"
+ offset="0"
+ id="stop7130" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop7132" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5180">
+ <stop
+ style="stop-color:#ffe300;stop-opacity:1"
+ offset="0"
+ id="stop5182" />
+ <stop
+ style="stop-color:#ffdd00;stop-opacity:0.29896906"
+ offset="1"
+ id="stop5184" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5162">
+ <stop
+ style="stop-color:#ffe300;stop-opacity:0"
+ offset="0"
+ id="stop5164" />
+ <stop
+ style="stop-color:#000000;stop-opacity:1"
+ offset="1"
+ id="stop5166" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5142">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop5144" />
+ <stop
+ style="stop-color:#ffe300;stop-opacity:1"
+ offset="1"
+ id="stop5146" />
+ </linearGradient>
+ <linearGradient
+ x1="227.5757"
+ y1="406.87469"
+ x2="383.85803"
+ y2="569.50922"
+ id="linearGradient5148"
+ xlink:href="#linearGradient5142"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ x1="383.83774"
+ y1="569.48895"
+ x2="676.80225"
+ y2="808.39429"
+ id="linearGradient5172"
+ xlink:href="#linearGradient5162"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ x1="268.57141"
+ y1="418.07648"
+ x2="206.63196"
+ y2="316.78485"
+ id="linearGradient7136"
+ xlink:href="#linearGradient7128"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <g
+ id="layer1"
+ transform="matrix(0.1948277,0,0,0.1948277,-12.454744,-33.319582)">
+ <path
+ d="M 301.02546,353.33662 L 385.42368,194.16767 L 469.34599,346.05509 L 639.53275,275.54066 L 590.84017,434.10284 L 714.31769,462.92134 L 603.88019,584.47053 L 180.81731,583.46037 C 180.81731,583.46037 59.701803,467.97371 71.31127,464.86296 C 82.920737,461.75221 187.54856,442.24267 187.54856,442.24267 L 144.25335,276.3252 L 301.02546,353.33662 z"
+ style="fill:url(#linearGradient7136);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:13.19999981;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path6157" />
+ <path
+ d="M 624.27428,571.52954 C 624.27428,698.72888 521.15884,801.84432 393.95951,801.84432 C 266.76017,801.84432 163.64473,698.72888 163.64473,571.52954 C 163.64473,444.3302 266.76017,341.21476 393.95951,341.21476 C 521.15884,341.21476 624.27428,444.3302 624.27428,571.52954 L 624.27428,571.52954 z"
+ style="fill:url(#linearGradient5148);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:13.10000038;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2221" />
+ <path
+ d="M 624.27428,571.52954 C 624.27428,698.72888 521.15884,801.84432 393.95951,801.84432 C 266.76017,801.84432 163.64473,698.72888 163.64473,571.52954 C 163.64473,444.3302 266.76017,341.21476 393.95951,341.21476 C 521.15884,341.21476 624.27428,444.3302 624.27428,571.52954 L 624.27428,571.52954 z"
+ transform="translate(2.03092e-2,2.03054e-2)"
+ style="fill:url(#linearGradient5172);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:19.20000076;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path5170" />
+ <path
+ d="M 624.27428,571.52954 C 624.27428,698.72888 521.15884,801.84432 393.95951,801.84432 C 266.76017,801.84432 163.64473,698.72888 163.64473,571.52954 C 163.64473,444.3302 266.76017,341.21476 393.95951,341.21476 C 521.15884,341.21476 624.27428,444.3302 624.27428,571.52954 L 624.27428,571.52954 z"
+ transform="matrix(0.8449327,0,0,0.8449327,58.845146,90.074416)"
+ style="fill:#ffe300;fill-opacity:0.1842105;fill-rule:evenodd;stroke:none;stroke-width:13.10000038;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path5174" />
+ <path
+ d="M 353.5534,529.10315 C 353.55708,553.6556 343.60627,573.5632 331.33004,573.5632 C 319.05382,573.5632 309.10301,553.6556 309.10669,529.10315 C 309.10301,504.5507 319.05382,484.6431 331.33004,484.6431 C 343.60627,484.6431 353.55708,504.5507 353.5534,529.10315 L 353.5534,529.10315 z"
+ transform="matrix(1,0,0,0.7045455,0,151.27517)"
+ style="fill:#000000;fill-opacity:0.72368421;stroke-width:5217864335821969031168;stroke-miterlimit:4;stroke-dasharray:none"
+ id="path3194" />
+ <path
+ d="M 353.5534,529.10315 C 353.55708,553.6556 343.60627,573.5632 331.33004,573.5632 C 319.05382,573.5632 309.10301,553.6556 309.10669,529.10315 C 309.10301,504.5507 319.05382,484.6431 331.33004,484.6431 C 343.60627,484.6431 353.55708,504.5507 353.5534,529.10315 L 353.5534,529.10315 z"
+ transform="matrix(9.1424418e-3,-0.6031951,0.7953919,6.9332818e-3,47.867695,705.82639)"
+ style="fill:#000000;fill-opacity:0.72368421;stroke-width:1175966421647293184030221008896;stroke-miterlimit:4;stroke-dasharray:none"
+ id="path3196" />
+ <path
+ d="M 296.98485,660.423 C 296.98485,660.423 325.26912,696.78849 383.85797,698.80879 C 442.44681,700.8291 488.91383,662.4433 488.91383,593.75293"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:36.01582336;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3200" />
+ <path
+ d="M 262.63966,494.75798 C 262.63966,494.75798 270.72088,444.25035 311.12698,432.12852"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:29.21099091;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3202" />
+ </g>
+</svg>
diff --git a/src/images/springlobby.xpm b/src/images/springlobby.xpm
new file mode 100644
index 0000000..52e4ba8
--- /dev/null
+++ b/src/images/springlobby.xpm
@@ -0,0 +1,83 @@
+/* XPM */
+static const char * springlobby_xpm[] = {
+"16 16 64 1",
+" c None",
+". c #3C2D00",
+"+ c #FDB19C",
+"@ c #FDB19B",
+"# c #FDB4A2",
+"$ c #FDAC91",
+"% c #FDA691",
+"& c #FDAD93",
+"* c #FDB49A",
+"= c #FDBBA5",
+"- c #FDB099",
+"; c #FDC7AC",
+"> c #FDC6A9",
+", c #3A2B00",
+"' c #362700",
+") c #FFFFC5",
+"! c #FFFEAD",
+"~ c #FFFC00",
+"{ c #FFFD00",
+"] c #3F3100",
+"^ c #403200",
+"/ c #3F3300",
+"( c #3D2E00",
+"_ c #FFFFBE",
+": c #FFFF73",
+"< c #FFF800",
+"[ c #FFEF8F",
+"} c #3F3000",
+"| c #483800",
+"1 c #FEBDA8",
+"2 c #403100",
+"3 c #FFE76B",
+"4 c #FFE74D",
+"5 c #3E2F00",
+"6 c #FFEB00",
+"7 c #433300",
+"8 c #FEC6A0",
+"9 c #4A3A00",
+"0 c #FEBDA7",
+"a c #413100",
+"b c #FFFE00",
+"c c #FFFE6B",
+"d c #FFEB73",
+"e c #FFE200",
+"f c #FFD500",
+"g c #FFB700",
+"h c #FEB15F",
+"i c #4B3B00",
+"j c #FFE24D",
+"k c #FFCD00",
+"l c #FFA900",
+"m c #FFC300",
+"n c #4F3F00",
+"o c #463700",
+"p c #584800",
+"q c #FF9800",
+"r c #564600",
+"s c #4C3C00",
+"t c #534300",
+"u c #554600",
+"v c #524200",
+"w c #FF8300",
+"x c #504000",
+"y c #4E3E00",
+" ",
+" .. ",
+" .. .+ at . .. ",
+" .#..$%&*..=. ",
+" .-&......;>. ",
+" .,')!~{]^/ ",
+" .(_:~<[<<<}| ",
+" .12~<234566789 ",
+".0abcdaee5ffg9hi",
+" 29<jeeffffklii ",
+" 9j6effffkmln ",
+" 9meoffkkpgqr ",
+" sgftuppfqr ",
+" vqmkkmglwx ",
+" ynqqqwys ",
+" i999 "};
diff --git a/src/images/springsettings.xpm b/src/images/springsettings.xpm
new file mode 100644
index 0000000..1ae4186
--- /dev/null
+++ b/src/images/springsettings.xpm
@@ -0,0 +1,165 @@
+/* XPM */
+static const char * springsettings_xpm[] = {
+"16 16 146 2",
+" c None",
+". c #FFFFFF",
+"+ c #FEFFFF",
+"@ c #B1B1B1",
+"# c #222222",
+"$ c #030303",
+"% c #121213",
+"& c #67696A",
+"* c #F8FEFF",
+"= c #F7FDFF",
+"- c #F8FDFF",
+"; c #FAFEFF",
+"> c #FCFFFF",
+", c #171717",
+"' c #393A3A",
+") c #D4D9DA",
+"! c #BEC4C6",
+"~ c #989FA1",
+"{ c #F0FCFF",
+"] c #F2FCFF",
+"^ c #F5FDFF",
+"/ c #101111",
+"( c #1B1B1C",
+"_ c #93999B",
+": c #D0DBDF",
+"< c #EBFBFF",
+"[ c #E8FBFF",
+"} c #E8FAFF",
+"| c #000000",
+"1 c #303435",
+"2 c #191A1B",
+"3 c #141415",
+"4 c #B5BABB",
+"5 c #FDFFFF",
+"6 c #999C9D",
+"7 c #0D0D0E",
+"8 c #687275",
+"9 c #E1F9FF",
+"0 c #E0F9FF",
+"a c #212526",
+"b c #BECDD1",
+"c c #232526",
+"d c #262829",
+"e c #F9FEFF",
+"f c #FBFFFF",
+"g c #F4FDFF",
+"h c #E8F6F9",
+"i c #AAB8BC",
+"j c #1E2223",
+"k c #08090A",
+"l c #DAF8FF",
+"m c #D9F7FF",
+"n c #505A5D",
+"o c #545B5D",
+"p c #030304",
+"q c #FCFEFF",
+"r c #5E6264",
+"s c #B2BFC3",
+"t c #C2D4D9",
+"u c #2F3537",
+"v c #171B1C",
+"w c #D3F6FF",
+"x c #D1F5FF",
+"y c #202426",
+"z c #B5CBD1",
+"A c #252829",
+"B c #F2FDFF",
+"C c #434748",
+"D c #111213",
+"E c #020203",
+"F c #1D2223",
+"G c #94ADB4",
+"H c #CCF5FF",
+"I c #C9F4FF",
+"J c #30383B",
+"K c #1D2123",
+"L c #121415",
+"M c #AAB7BB",
+"N c #F7FEFF",
+"O c #F3AEB1",
+"P c #FB2122",
+"Q c #FE0203",
+"R c #FC1213",
+"S c #EB656A",
+"T c #C1F3FF",
+"U c #505F63",
+"V c #D8F7FF",
+"W c #DFF9FF",
+"X c #E7FAFF",
+"Y c #EFFCFF",
+"Z c #F6FDFF",
+"` c #FFFEFF",
+" . c #FD1617",
+".. c #F9393A",
+"+. c #E5D4DA",
+"@. c #E1C0C6",
+"#. c #E29BA1",
+"$. c #C8F4FF",
+"%. c #515F63",
+"&. c #FE1011",
+"*. c #FC1B1C",
+"=. c #ED979B",
+"-. c #E1D8DF",
+";. c #D6F7FF",
+">. c #D2F6FF",
+",. c #D8C7D0",
+"'. c #F63133",
+"). c #FE0405",
+"!. c #F82F31",
+"~. c #E8D1D6",
+"{. c #EAFBFF",
+"]. c #F1FCFF",
+"^. c #FBFEFF",
+"/. c #F89B9D",
+"(. c #FE0D0E",
+"_. c #FF0000",
+":. c #EE7175",
+"<. c #F72E30",
+"[. c #F53D3F",
+"}. c #E2D0D6",
+"|. c #F92F31",
+"1. c #F93739",
+"2. c #EEFBFF",
+"3. c #F1F6F9",
+"4. c #F0B9BC",
+"5. c #FB2223",
+"6. c #FD090A",
+"7. c #FE0304",
+"8. c #FD0A0B",
+"9. c #FE6464",
+"0. c #F8C2C3",
+"a. c #F3D6D9",
+"b. c #FB3637",
+"c. c #FA3031",
+"d. c #F93738",
+"e. c #EFB3B7",
+"f. c #F2ABAE",
+"g. c #F87778",
+"h. c #FDFEFF",
+"i. c #FF4848",
+"j. c #FE1213",
+"k. c #FD2223",
+"l. c #F5B1B4",
+"m. c #F0D1D4",
+"n. c #FB393A",
+"o. c #FD4748",
+". . . . . . . . + . . . . . . . ",
+". . @ # $ % & * = - ; > . . . . ",
+". . , ' ) ! ~ { { { ] ^ * + . . ",
+". . / ( _ : < [ } | 1 2 3 4 5 . ",
+". . 6 7 | | 8 9 0 | a b c d e . ",
+". f g h i j k l m | n 9 o p g q ",
+". e r s t u v w x | y z a A B e ",
+". = C D E F G H I | J K L M { - ",
+"+ N O P Q R S I T | U V W X Y Z ",
+"` = ...+. at .#.H $.| %.l 0 [ { = ",
+". e &.*.=.-.;.>.,.'.).!.~.{.].e ",
+". ^./.(._._.:.m <.[.}.|.1.2.g ^.",
+". . * 3.4.5.6.0 7.).8.7.7.B * . ",
+". . 9.0.a.b.*.} c.d.e.f.g.Z h.. ",
+". . i.j.Q k.l.Y m.n.).(.o.5 . . ",
+". . . . + ^.e = Z N * f + . . . "};
diff --git a/src/images/start_ally.xpm b/src/images/start_ally.xpm
new file mode 100644
index 0000000..e3094c8
--- /dev/null
+++ b/src/images/start_ally.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static const char * start_ally_xpm[] = {
+"16 16 7 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #019A1A",
+"# c #BFFFCA",
+"$ c #00FF2A",
+"% c #00D924",
+" ...... ",
+" ..++++++.. ",
+" .+++@@@@+++. ",
+" .++@@@##@@@++. ",
+" .+@@##$$##@@+. ",
+".++@#$$$$$$%@++.",
+".+@@#$$$$$$%@@+.",
+".+@#$$$$$$$$%@+.",
+".+@#$$$$$$$$%@+.",
+".+@@#$$$$$$%@@+.",
+".++@#$$$$$%%@++.",
+" .+@@%%$$%%@@+. ",
+" .++@@@%%@@@++. ",
+" .+++@@@@+++. ",
+" ..++++++.. ",
+" ...... "};
diff --git a/src/images/start_enemy.xpm b/src/images/start_enemy.xpm
new file mode 100644
index 0000000..c92457e
--- /dev/null
+++ b/src/images/start_enemy.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static const char * start_enemy_xpm[] = {
+"16 16 7 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #A20303",
+"# c #FFD6D6",
+"$ c #FF0000",
+"% c #CB0000",
+" ...... ",
+" ..++++++.. ",
+" .+++@@@@+++. ",
+" .++@@@##@@@++. ",
+" .+@@##$$##@@+. ",
+".++@#$$$$$$%@++.",
+".+@@#$$$$$$%@@+.",
+".+@#$$$$$$$$%@+.",
+".+@#$$$$$$$$%@+.",
+".+@@#$$$$$$%@@+.",
+".++@#$$$$$%%@++.",
+" .+@@%%$$%%@@+. ",
+" .++@@@%%@@@++. ",
+" .+++@@@@+++. ",
+" ..++++++.. ",
+" ...... "};
diff --git a/src/images/start_unused.xpm b/src/images/start_unused.xpm
new file mode 100644
index 0000000..b22e1f0
--- /dev/null
+++ b/src/images/start_unused.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static const char * start_unused_xpm[] = {
+"16 16 7 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #425A45",
+"# c #DAE4DB",
+"$ c #6C9472",
+"% c #5C7E61",
+" ...... ",
+" ..++++++.. ",
+" .+++@@@@+++. ",
+" .++@@@##@@@++. ",
+" .+@@##$$##@@+. ",
+".++@#$$$$$$%@++.",
+".+@@#$$$$$$%@@+.",
+".+@#$$$$$$$$%@+.",
+".+@#$$$$$$$$%@+.",
+".+@@#$$$$$$%@@+.",
+".++@#$$$$$%%@++.",
+" .+@@%%$$%%@@+. ",
+" .++@@@%%@@@++. ",
+" .+++@@@@+++. ",
+" ..++++++.. ",
+" ...... "};
diff --git a/src/images/started_game.xpm b/src/images/started_game.xpm
new file mode 100644
index 0000000..cebeb9f
--- /dev/null
+++ b/src/images/started_game.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char * started_game_xpm[] = {
+"16 16 9 1",
+" c None",
+". c #7E7E7E",
+"+ c #000000",
+"@ c #FFFFFF",
+"# c #BCBCBC",
+"$ c #FFEAAC",
+"% c #BC8E00",
+"& c #705400",
+"* c #FFD75F",
+" ",
+" .+++ +++. ",
+" +.@@+ +@@.+ ",
+" +#.#@+ +@#.#+ ",
+" +.#.#@++@#.#.+ ",
+" +.#.#@+#.#.+ ",
+" +.#.#@+#.+ ",
+" ++.#.#@+++ ",
+" +$++.#.#@+$+ ",
+" +%$#+.#.#$%+ ",
+" +%##+.##%+ ",
+" +&&%*++*%&&+ ",
+" +&&&+%**%+&&&+ ",
+" &&&+ ++++ +&&& ",
+" *&+ +&* ",
+" "};
diff --git a/src/images/torrentoptionspanel_icon.png.h b/src/images/torrentoptionspanel_icon.png.h
new file mode 100644
index 0000000..addadea
--- /dev/null
+++ b/src/images/torrentoptionspanel_icon.png.h
@@ -0,0 +1,97 @@
+/* torrentoptionspanel_icon.png - 751 bytes */
+ static const unsigned char torrentoptionspanel_icon_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x56, 0x75, 0x5c,
+ 0xe7, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf9, 0x43, 0xbb, 0x7f,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x04,
+ 0x1e, 0x14, 0x0b, 0x15, 0xe2, 0xf9, 0x84, 0x02,
+ 0x00, 0x00, 0x00, 0x35, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x34,
+ 0x20, 0x4a, 0x61, 0x6b, 0x75, 0x62, 0x20, 0x53,
+ 0x74, 0x65, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x0a,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65,
+ 0x20, 0x47, 0x49, 0x4d, 0x50, 0x90, 0xd9, 0x8b,
+ 0x6f, 0x00, 0x00, 0x02, 0x2e, 0x49, 0x44, 0x41,
+ 0x54, 0x28, 0xcf, 0x2d, 0xc1, 0x4f, 0x48, 0x53,
+ 0x71, 0x00, 0x07, 0xf0, 0xef, 0xef, 0xfd, 0xf6,
+ 0xe6, 0xe6, 0x7b, 0xfa, 0xe6, 0xd4, 0xb5, 0xcd,
+ 0x81, 0xce, 0x37, 0x54, 0xa8, 0x29, 0x45, 0x99,
+ 0x24, 0x19, 0x23, 0x59, 0x7f, 0x90, 0x3a, 0xd4,
+ 0xa1, 0x6e, 0x8a, 0x05, 0xd2, 0xa5, 0x5b, 0x44,
+ 0x97, 0xfe, 0x5d, 0xba, 0x14, 0xd5, 0xc9, 0xa4,
+ 0x43, 0x97, 0xa4, 0x12, 0x3a, 0xd4, 0x21, 0x08,
+ 0x09, 0x8a, 0x84, 0x0e, 0x81, 0x88, 0x25, 0xce,
+ 0xf6, 0x47, 0xe3, 0xb5, 0x99, 0xce, 0xb7, 0x4d,
+ 0x9f, 0x7b, 0x7b, 0xbf, 0xe7, 0xf6, 0xeb, 0xd2,
+ 0xe7, 0x43, 0xfa, 0x4f, 0xdf, 0x1c, 0xe0, 0x9c,
+ 0xcf, 0x70, 0xce, 0x43, 0x9c, 0xa3, 0x5a, 0x36,
+ 0x2d, 0x9a, 0xcf, 0x97, 0xe0, 0xef, 0x68, 0x43,
+ 0x40, 0x6d, 0xff, 0xb6, 0x94, 0xd0, 0xc6, 0xb5,
+ 0xd9, 0x7b, 0x4b, 0x00, 0xe0, 0x3b, 0x71, 0x0b,
+ 0x84, 0x73, 0x8e, 0xc3, 0xf1, 0x1b, 0x97, 0x41,
+ 0x84, 0x69, 0xcb, 0xb2, 0xd1, 0x15, 0x09, 0xe2,
+ 0xe2, 0xc8, 0x00, 0x64, 0x45, 0x81, 0x6e, 0xda,
+ 0xc6, 0xc2, 0xb2, 0xb6, 0xb4, 0x90, 0xd0, 0x1e,
+ 0x7e, 0x9a, 0xba, 0xf6, 0x06, 0x00, 0x1c, 0x84,
+ 0x10, 0x8c, 0xde, 0x79, 0x95, 0x2c, 0x64, 0x37,
+ 0x30, 0x7c, 0x54, 0xc5, 0xc9, 0xd8, 0x41, 0xd8,
+ 0xb6, 0x05, 0x46, 0x1b, 0xe0, 0x35, 0x8a, 0x72,
+ 0x34, 0xdc, 0xdb, 0xdf, 0xea, 0x91, 0x5e, 0x4b,
+ 0xee, 0xe7, 0xc1, 0xf7, 0x4f, 0xae, 0x3c, 0xa6,
+ 0xa7, 0xc6, 0x1e, 0x1d, 0xd8, 0xd0, 0x72, 0x2f,
+ 0xce, 0xc5, 0xa2, 0xfe, 0xb3, 0xb1, 0x9e, 0x1a,
+ 0x95, 0x9a, 0x89, 0xec, 0x6d, 0x45, 0x49, 0x2f,
+ 0x00, 0xa6, 0xce, 0xa3, 0x5d, 0xa1, 0x5a, 0x24,
+ 0x1c, 0x10, 0xd2, 0xda, 0xd6, 0x90, 0x10, 0x8e,
+ 0xbf, 0xa4, 0xdd, 0x87, 0xe2, 0x2b, 0xb2, 0x93,
+ 0x06, 0xc7, 0x2e, 0x0d, 0x51, 0x22, 0xfb, 0x48,
+ 0x9d, 0xab, 0x1e, 0x84, 0x10, 0x54, 0x99, 0x09,
+ 0xcb, 0xdc, 0x25, 0xc9, 0xec, 0xb6, 0xd0, 0x54,
+ 0x4f, 0x20, 0x38, 0xdd, 0x62, 0x76, 0x2d, 0x6d,
+ 0x08, 0x6b, 0x29, 0x4d, 0xe9, 0x52, 0xdb, 0x44,
+ 0xcd, 0x74, 0x83, 0x51, 0x09, 0x10, 0x08, 0x0c,
+ 0xc3, 0x84, 0x57, 0x72, 0x62, 0xf0, 0x48, 0x1f,
+ 0x06, 0x7a, 0x55, 0xd8, 0x8c, 0x41, 0x71, 0x8b,
+ 0x08, 0xea, 0xab, 0x83, 0x02, 0x75, 0xd6, 0xa1,
+ 0xb9, 0xa5, 0x09, 0x0e, 0x5e, 0x41, 0x36, 0x9b,
+ 0xc3, 0xea, 0xa6, 0x05, 0x6d, 0xa3, 0x88, 0x3d,
+ 0x66, 0x02, 0x00, 0x1a, 0x65, 0x37, 0x28, 0x25,
+ 0x60, 0x6c, 0x0f, 0x2e, 0xcb, 0xf0, 0x38, 0x3a,
+ 0xba, 0x3b, 0x2b, 0x36, 0x48, 0xdd, 0xfe, 0xa0,
+ 0x8b, 0x88, 0x0e, 0x27, 0xe6, 0x92, 0xeb, 0xc8,
+ 0xef, 0x02, 0x99, 0x5c, 0x19, 0x0d, 0x09, 0x1d,
+ 0xe7, 0x8f, 0xa9, 0x28, 0x14, 0x8a, 0x58, 0x2f,
+ 0x55, 0xd1, 0xb8, 0xf3, 0x83, 0x0a, 0xcc, 0xac,
+ 0x8c, 0x6f, 0x6e, 0x57, 0xd2, 0x25, 0x8b, 0xa2,
+ 0xb5, 0xc5, 0x5b, 0x1b, 0x54, 0xeb, 0xf1, 0x37,
+ 0x5f, 0xc0, 0x4a, 0xae, 0x8c, 0xcf, 0xcb, 0x45,
+ 0xfc, 0xd1, 0x7e, 0x63, 0xbb, 0x2a, 0x22, 0xb3,
+ 0xf8, 0x0b, 0xde, 0xdd, 0xef, 0x8c, 0x26, 0xe7,
+ 0x3f, 0x2c, 0xee, 0xeb, 0x19, 0x16, 0xf3, 0x3b,
+ 0x66, 0x3c, 0x1c, 0xf4, 0x90, 0x2f, 0xf3, 0x69,
+ 0x7c, 0x4d, 0x14, 0x91, 0x2f, 0x95, 0x61, 0x31,
+ 0x86, 0x9e, 0x90, 0x8c, 0xf9, 0x34, 0x43, 0x6d,
+ 0xf6, 0x69, 0x2e, 0x40, 0x7f, 0xce, 0x10, 0xfc,
+ 0x77, 0xe1, 0xfa, 0xe4, 0x54, 0x77, 0x24, 0x74,
+ 0x55, 0xf1, 0x28, 0xf0, 0x28, 0x12, 0xe0, 0x94,
+ 0xa0, 0x57, 0x84, 0xaa, 0xb1, 0x96, 0xb1, 0x85,
+ 0xb9, 0xc9, 0x2d, 0xb5, 0xf2, 0xf6, 0xd9, 0xe8,
+ 0x3b, 0xdc, 0x27, 0x6a, 0xfc, 0x36, 0x52, 0x1f,
+ 0xef, 0x02, 0x00, 0xce, 0x8c, 0x3d, 0x38, 0xee,
+ 0xf3, 0xfb, 0x27, 0x44, 0xc9, 0x23, 0xca, 0xe5,
+ 0x54, 0x9f, 0xab, 0x94, 0xf1, 0xb5, 0x27, 0xa6,
+ 0x75, 0x45, 0xd2, 0x3b, 0x6b, 0x02, 0xaa, 0x9c,
+ 0x93, 0x89, 0x7f, 0x38, 0xb8, 0xef, 0x80, 0x19,
+ 0x3b, 0x64, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/images/unknown_flag.xpm b/src/images/unknown_flag.xpm
new file mode 100644
index 0000000..f4e4d8a
--- /dev/null
+++ b/src/images/unknown_flag.xpm
@@ -0,0 +1,101 @@
+/* XPM */
+static const char * unknown_flag_xpm[] = {
+"16 16 82 1",
+" c None",
+". c #004381",
+"+ c #003375",
+"@ c #002D73",
+"# c #00276D",
+"$ c #002169",
+"% c #001963",
+"& c #00135D",
+"* c #000D59",
+"= c #000553",
+"- c #00004D",
+"; c #7BB0CA",
+"> c #7BB0C9",
+", c #79AEC9",
+"' c #6DA7C3",
+") c #6AA5C3",
+"! c #65A1C0",
+"~ c #619EBE",
+"{ c #5C9BBB",
+"] c #5899B9",
+"^ c #5396B7",
+"/ c #4E93B4",
+"( c #000047",
+"_ c #5896C3",
+": c #5C9DBE",
+"< c #5093AE",
+"[ c #D9E7ED",
+"} c #FAFCFC",
+"| c #F1F6F9",
+"1 c #95BED3",
+"2 c #3D86AC",
+"3 c #3784AB",
+"4 c #3181A9",
+"5 c #2C7CA6",
+"6 c #498FB1",
+"7 c #000041",
+"8 c #00417F",
+"9 c #9CC2D1",
+"0 c #5E9CBC",
+"a c #CFE1EB",
+"b c #F8FAFC",
+"c c #2B7CA5",
+"d c #267AA2",
+"e c #00003B",
+"f c #629EB6",
+"g c #EAF2F6",
+"h c #CFE1EA",
+"i c #D9E7EF",
+"j c #D7E6EE",
+"k c #4A8EB1",
+"l c #2F7DA4",
+"m c #93BCCD",
+"n c #4991B4",
+"o c #458EB2",
+"p c #458BAD",
+"q c #3381A8",
+"r c #2478A2",
+"s c #1F70A4",
+"t c #196CA2",
+"u c #1469A0",
+"v c #10659D",
+"w c #337BAB",
+"x c #00276F",
+"y c #448CAF",
+"z c #3F8AAF",
+"A c #FFFFFF",
+"B c #79ACC5",
+"C c #1E749F",
+"D c #18709C",
+"E c #136C99",
+"F c #0F6A97",
+"G c #0B6795",
+"H c #000021",
+"I c #619FBE",
+"J c #428AAE",
+"K c #327FA6",
+"L c #2C7BA2",
+"M c #00001F",
+"N c #000039",
+"O c #000033",
+"P c #00002D",
+"Q c #000025",
+" ",
+" ",
+" ",
+"....++++@#$%&*=-",
+".;;>,,,')!~{]^/(",
+".;_:_<[}|1234567",
+"8,:___90ab34cd6e",
+"@,:__<<fgh34cd6e",
+"@,:___<ijk34cd6e",
+"@,:__<lm0234cd6e",
+"@)no__<pqrstuvwe",
+"x!yz_<lABCDEFG5H",
+"$I:]666yJ233KKLM",
+"%&*=eeeeNOPQQHMM",
+" ",
+" "};
diff --git a/src/images/up.xpm b/src/images/up.xpm
new file mode 100644
index 0000000..a7ac162
--- /dev/null
+++ b/src/images/up.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+static const char * up_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" . ",
+" ... ",
+" ..... ",
+"....... ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/src/images/up_down.xpm b/src/images/up_down.xpm
new file mode 100644
index 0000000..b78ab1b
--- /dev/null
+++ b/src/images/up_down.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static const char * up_down_xpm[] = {
+"16 16 5 1",
+" c None",
+". c #000000",
+"+ c #69FFA5",
+"@ c #00FF66",
+"# c #00943B",
+" . ",
+" .+. ",
+" .+@#. ",
+" .+@@@#. ",
+" .+######. ",
+"........... ",
+" ",
+" ",
+"........... ",
+" .+++++++. ",
+" .#@@@#. ",
+" .#@#. ",
+" .#. ",
+" . ",
+" ",
+" "};
diff --git a/src/images/up_downsel.xpm b/src/images/up_downsel.xpm
new file mode 100644
index 0000000..01d2ee7
--- /dev/null
+++ b/src/images/up_downsel.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * up_downsel_xpm[] = {
+"16 16 6 1",
+" c None",
+". c #000000",
+"+ c #69FFA5",
+"@ c #00FF66",
+"# c #00943B",
+"$ c #FFFFFF",
+" . ",
+" .+. ",
+" .+@#. ",
+" .+@@@#. ",
+" .+######. ",
+"........... ",
+" ",
+" ",
+"$$$$$$$$$$$ ",
+" $+++++++$ ",
+" $#@@@#$ ",
+" $#@#$ ",
+" $#$ ",
+" $ ",
+" ",
+" "};
diff --git a/src/images/upsel_down.xpm b/src/images/upsel_down.xpm
new file mode 100644
index 0000000..5a56ac1
--- /dev/null
+++ b/src/images/upsel_down.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * upsel_down_xpm[] = {
+"16 16 6 1",
+" c None",
+". c #FFFFFF",
+"+ c #69FFA5",
+"@ c #00FF66",
+"# c #00943B",
+"$ c #000000",
+" . ",
+" .+. ",
+" .+@#. ",
+" .+@@@#. ",
+" .+######. ",
+"........... ",
+" ",
+" ",
+"$$$$$$$$$$$ ",
+" $+++++++$ ",
+" $#@@@#$ ",
+" $#@#$ ",
+" $#$ ",
+" $ ",
+" ",
+" "};
diff --git a/src/images/userchat.xpm b/src/images/userchat.xpm
new file mode 100644
index 0000000..5121610
--- /dev/null
+++ b/src/images/userchat.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+static const char * userchat_xpm[] = {
+"12 12 6 1",
+" c None",
+". c #000000",
+"+ c #FFFDEA",
+"@ c #FFE400",
+"# c #A49300",
+"$ c #FF0000",
+" .... ",
+" ..++++.. ",
+" .++++@@++. ",
+" .++.@@. at +. ",
+".++ at .@@.@@#.",
+".++@@@@@@##.",
+".+@@@@@@@##.",
+".+ at ......##.",
+" .+ at .$$.##. ",
+" .##@$$###. ",
+" ..####.. ",
+" .... "};
diff --git a/src/images/warning_small.png.h b/src/images/warning_small.png.h
new file mode 100644
index 0000000..a775dfc
--- /dev/null
+++ b/src/images/warning_small.png.h
@@ -0,0 +1,109 @@
+/* warning_small.png - 847 bytes */
+ static const unsigned char warning_small_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
+ 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+ 0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
+ 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+ 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93,
+ 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73,
+ 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13,
+ 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
+ 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd8, 0x08,
+ 0x15, 0x16, 0x28, 0x19, 0x44, 0x93, 0x01, 0x26,
+ 0x00, 0x00, 0x00, 0x35, 0x74, 0x45, 0x58, 0x74,
+ 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00,
+ 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x34,
+ 0x20, 0x4a, 0x61, 0x6b, 0x75, 0x62, 0x20, 0x53,
+ 0x74, 0x65, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x0a,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65,
+ 0x20, 0x47, 0x49, 0x4d, 0x50, 0x90, 0xd9, 0x8b,
+ 0x6f, 0x00, 0x00, 0x02, 0x8e, 0x49, 0x44, 0x41,
+ 0x54, 0x38, 0x4f, 0x7d, 0x52, 0x6d, 0x48, 0x53,
+ 0x61, 0x14, 0x7e, 0xde, 0xdd, 0xe9, 0x66, 0x39,
+ 0x9d, 0x6d, 0x3a, 0x52, 0xa1, 0xe5, 0x27, 0x4d,
+ 0x85, 0xd2, 0x20, 0xc4, 0xfc, 0xa1, 0x59, 0x60,
+ 0xfd, 0x90, 0xa0, 0x85, 0x32, 0x46, 0xfd, 0x0c,
+ 0x13, 0xa2, 0x20, 0x28, 0x05, 0x2b, 0xe8, 0xe3,
+ 0x57, 0x06, 0x6d, 0x48, 0x3f, 0x2a, 0x12, 0xcd,
+ 0x86, 0xd9, 0xaf, 0xa0, 0x2f, 0x7f, 0xc4, 0x8a,
+ 0xcc, 0x51, 0x4e, 0xc4, 0x39, 0x14, 0x2d, 0xa9,
+ 0xa0, 0x08, 0x97, 0x6e, 0xe6, 0xee, 0x74, 0x73,
+ 0x7b, 0x7b, 0xef, 0xdb, 0xae, 0x13, 0xb5, 0x0e,
+ 0xbc, 0xf7, 0x9e, 0x73, 0x9e, 0xe7, 0x3c, 0xf7,
+ 0x9c, 0x73, 0x5f, 0x82, 0x75, 0x76, 0xab, 0x49,
+ 0xb1, 0x3e, 0xc5, 0xe3, 0xb3, 0x8f, 0x62, 0x9b,
+ 0xe6, 0x89, 0x9c, 0x4d, 0x14, 0x12, 0x9c, 0x68,
+ 0x6e, 0x47, 0xba, 0x56, 0xcf, 0xa1, 0x80, 0xdf,
+ 0x87, 0xae, 0xce, 0x2b, 0xff, 0x14, 0x11, 0x24,
+ 0xa4, 0xa3, 0x91, 0x80, 0x10, 0x02, 0xcb, 0xc5,
+ 0x7e, 0xa4, 0x25, 0x47, 0xb0, 0x63, 0x4f, 0x03,
+ 0x48, 0x4a, 0x26, 0xa0, 0xd6, 0x43, 0xb9, 0x45,
+ 0x87, 0xa9, 0x71, 0x17, 0x0e, 0x9f, 0x7e, 0x80,
+ 0x5d, 0x0a, 0x27, 0x6a, 0x0b, 0x16, 0xf1, 0xd2,
+ 0x93, 0x68, 0x86, 0xc8, 0xc5, 0x67, 0x6c, 0x23,
+ 0xc0, 0x9c, 0x07, 0x9f, 0xc7, 0xdf, 0x61, 0x61,
+ 0x89, 0x40, 0x9f, 0x53, 0xcc, 0x59, 0x3f, 0xbe,
+ 0x78, 0xa1, 0xd3, 0x28, 0x91, 0x67, 0xaa, 0x44,
+ 0x54, 0x57, 0x01, 0x7b, 0x8b, 0x09, 0x94, 0x52,
+ 0x9c, 0x73, 0x50, 0x8e, 0x2b, 0xa4, 0x2f, 0xd7,
+ 0xb5, 0x3c, 0x01, 0x7c, 0x4c, 0x20, 0x1c, 0x40,
+ 0x5e, 0x61, 0x29, 0x0a, 0x8c, 0x39, 0x50, 0x88,
+ 0xdf, 0xf8, 0x31, 0x66, 0xeb, 0xa1, 0x5d, 0x4e,
+ 0x55, 0xf5, 0x16, 0x59, 0x46, 0x02, 0xaf, 0x1d,
+ 0xad, 0xd5, 0xa7, 0xfa, 0x79, 0xb7, 0xb2, 0x29,
+ 0x25, 0xa7, 0xd8, 0x68, 0x00, 0x22, 0xcc, 0x5d,
+ 0x14, 0x79, 0x3e, 0x55, 0xa3, 0xe5, 0x27, 0x6e,
+ 0x42, 0xef, 0x81, 0x66, 0x27, 0xf3, 0x77, 0xbf,
+ 0x38, 0x76, 0x79, 0x67, 0xed, 0xe8, 0xd3, 0xeb,
+ 0x6b, 0xb7, 0xc9, 0x57, 0x1e, 0xf9, 0xe9, 0x46,
+ 0x2c, 0x2c, 0x82, 0x66, 0xed, 0x03, 0x32, 0x4a,
+ 0x01, 0x55, 0xc6, 0x5f, 0x8e, 0xa0, 0xc2, 0xcc,
+ 0x73, 0x4f, 0x3f, 0xf3, 0x18, 0xc0, 0x2d, 0x7d,
+ 0xa4, 0xe3, 0x6a, 0xfb, 0x06, 0x01, 0xd0, 0x15,
+ 0x44, 0x87, 0xaf, 0x81, 0xce, 0x4f, 0xb1, 0xa1,
+ 0x92, 0x80, 0xad, 0xb9, 0x58, 0x49, 0x37, 0x21,
+ 0x24, 0x18, 0xf0, 0xfe, 0x7c, 0x67, 0x89, 0x54,
+ 0x60, 0x61, 0x73, 0x4b, 0x36, 0xdf, 0xe5, 0xb2,
+ 0x6e, 0x10, 0x08, 0x8a, 0xcb, 0x6c, 0xeb, 0x3a,
+ 0x20, 0x1a, 0x06, 0xf5, 0x4f, 0x83, 0x7a, 0xec,
+ 0x08, 0x8d, 0xde, 0x21, 0x93, 0xb7, 0x2f, 0xdd,
+ 0x64, 0xe4, 0xc2, 0x9a, 0x81, 0x01, 0x38, 0x9d,
+ 0x4e, 0x54, 0xf5, 0xf5, 0x49, 0xb5, 0x05, 0xaa,
+ 0x19, 0x7a, 0x41, 0x16, 0x51, 0x0c, 0xc6, 0x8e,
+ 0xc2, 0x1b, 0x34, 0x22, 0x2a, 0xa4, 0x01, 0xbf,
+ 0x3f, 0x01, 0x0b, 0x93, 0x0c, 0xa3, 0xa0, 0x4b,
+ 0x73, 0x82, 0xd7, 0x3e, 0x5c, 0x26, 0x11, 0xb3,
+ 0xeb, 0xea, 0x60, 0xb3, 0xd9, 0x60, 0x34, 0x9b,
+ 0x79, 0x5d, 0xda, 0x10, 0x6d, 0x5d, 0x15, 0x90,
+ 0x1c, 0xbf, 0x18, 0xc5, 0xdd, 0xaf, 0x35, 0x18,
+ 0x9b, 0x4d, 0x41, 0x44, 0xfc, 0x85, 0x70, 0x2c,
+ 0x09, 0xd3, 0xce, 0x85, 0x7b, 0x0c, 0x3a, 0x68,
+ 0xb4, 0x58, 0x38, 0xd7, 0xeb, 0xf5, 0xf2, 0x77,
+ 0x3c, 0xd6, 0xf4, 0x00, 0xd5, 0x2c, 0x24, 0x7c,
+ 0x89, 0x31, 0x36, 0x9f, 0x2a, 0x59, 0x85, 0x89,
+ 0xc5, 0x5c, 0x7c, 0x4c, 0x6e, 0xc2, 0x5b, 0xc1,
+ 0x8a, 0x09, 0xdb, 0xd0, 0x5e, 0x09, 0xab, 0xea,
+ 0x61, 0x54, 0x66, 0xdd, 0xdd, 0xdd, 0xfc, 0x2d,
+ 0xc7, 0xcc, 0x7d, 0xc3, 0x8e, 0x86, 0x0b, 0xa8,
+ 0xd5, 0x6a, 0x6c, 0xd3, 0xe9, 0x10, 0x0c, 0x06,
+ 0xe1, 0xf3, 0xf9, 0x20, 0xbe, 0x1a, 0xb8, 0xcf,
+ 0xd2, 0xa6, 0x92, 0xb6, 0x36, 0xb9, 0x53, 0x58,
+ 0xad, 0x89, 0xdd, 0xc9, 0x5d, 0xdd, 0x00, 0x4e,
+ 0x92, 0xf2, 0xf2, 0x32, 0xe4, 0x17, 0x16, 0xa1,
+ 0xd1, 0x7c, 0x1c, 0x99, 0x59, 0x06, 0x84, 0x96,
+ 0x42, 0x98, 0x3d, 0x54, 0xff, 0x8c, 0x55, 0xd6,
+ 0xcb, 0x9b, 0x5f, 0x55, 0x59, 0xe3, 0x3c, 0x8c,
+ 0x5f, 0x26, 0xa5, 0xdb, 0x3d, 0xc6, 0xfe, 0xe2,
+ 0x32, 0x1c, 0x8f, 0x01, 0xad, 0x56, 0x0b, 0x73,
+ 0xc3, 0x11, 0x3e, 0xaa, 0xf4, 0x90, 0x49, 0x9b,
+ 0x09, 0xc8, 0xb9, 0xc4, 0x9d, 0x94, 0xe6, 0xdb,
+ 0x5f, 0xc9, 0xee, 0x3d, 0x41, 0xfe, 0x5c, 0xe4,
+ 0x7b, 0x85, 0xeb, 0xc3, 0xf6, 0xff, 0x15, 0xc6,
+ 0x31, 0xeb, 0x1f, 0x91, 0xb0, 0xd9, 0xec, 0x81,
+ 0x1c, 0x52, 0x84, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+/* End Of File */
diff --git a/src/inetclass.h b/src/inetclass.h
new file mode 100644
index 0000000..f82ed02
--- /dev/null
+++ b/src/inetclass.h
@@ -0,0 +1,49 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_INETCLASS_H
+#define SPRINGLOBBY_HEADERGUARD_INETCLASS_H
+
+class Socket;
+
+//! @brief Abstract baseclass that is used when needed to interface with socket class
+class iNetClass
+{
+ public:
+
+ iNetClass(){}
+ virtual ~iNetClass(){}
+
+ virtual void OnConnected( Socket* sock ) = 0;
+ virtual void OnDisconnected( Socket* sock ) = 0;
+ virtual void OnDataReceived( Socket* sock ) = 0;
+};
+
+class FakeNetClass : public iNetClass
+{
+ public:
+
+ FakeNetClass(){}
+ ~FakeNetClass(){}
+
+ void OnConnected( Socket* /*unused*/ ) {}
+ void OnDisconnected( Socket* /*unused*/ ) {}
+ void OnDataReceived( Socket* /*unused*/ ) {}
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_INETCLASS_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/iunitsync.h b/src/iunitsync.h
new file mode 100644
index 0000000..13c1042
--- /dev/null
+++ b/src/iunitsync.h
@@ -0,0 +1,266 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_IUNITSYNC_H
+#define SPRINGLOBBY_HEADERGUARD_IUNITSYNC_H
+
+#include <wx/string.h>
+#include <wx/arrstr.h>
+#include <wx/event.h>
+#include <map>
+
+#include "mmoptionmodel.h"
+
+class wxImage;
+
+extern const wxEventType UnitSyncAsyncOperationCompletedEvt;
+
+struct UnitSyncMod
+{
+ UnitSyncMod() : name(_T("")),hash(_T("")) { }
+ wxString name;
+ wxString hash;
+};
+
+struct StartPos
+{
+ int x;
+ int y;
+};
+
+struct MapInfo
+{
+ wxString description;
+ int tidalStrength;
+ int gravity;
+ float maxMetal;
+ int extractorRadius;
+ int minWind;
+ int maxWind;
+
+ int width;
+ int height;
+ int posCount;
+ StartPos positions[16];
+
+ wxString author;
+};
+
+struct UnitSyncMap
+{
+ UnitSyncMap() : name(_T("")),hash(_T("")) { }
+ wxString name;
+ wxString hash;
+ MapInfo info;
+};
+
+struct GameOptions;
+
+ /** UnitSync interface definition.
+ */
+class IUnitSync
+{
+ public:
+ IUnitSync() { }
+ virtual ~IUnitSync() { }
+
+ enum GameFeature
+ {
+ USYNC_Sett_Handler,
+ USYNC_GetInfoMap,
+ USYNC_GetDataDir,
+ USYNC_GetSkirmishAI
+ };
+
+ enum MediaType
+ {
+ map,
+ mod
+ };
+
+ typedef std::map<wxString,mmOptionBool> OptionMapBool;
+ typedef std::map<wxString,mmOptionFloat> OptionMapFloat;
+ typedef std::map<wxString,mmOptionString> OptionMapString;
+ typedef std::map<wxString,mmOptionList> OptionMapList;
+ typedef std::map<wxString,mmOptionSection> OptionMapSection;
+
+ typedef std::map<wxString,mmOptionBool>::iterator OptionMapBoolIter;
+ typedef std::map<wxString,mmOptionFloat>::iterator OptionMapFloatIter;
+ typedef std::map<wxString,mmOptionString>::iterator OptionMapStringIter;
+ typedef std::map<wxString,mmOptionList>::iterator OptionMapListIter;
+ typedef std::map<wxString,mmOptionSection>::iterator OptionMapSectionIter;
+
+ typedef std::map<wxString,mmOptionBool>::const_iterator OptionMapBoolConstIter;
+ typedef std::map<wxString,mmOptionFloat>::const_iterator OptionMapFloatConstIter;
+ typedef std::map<wxString,mmOptionString>::const_iterator OptionMapStringConstIter;
+ typedef std::map<wxString,mmOptionList>::const_iterator OptionMapListConstIter;
+ typedef std::map<wxString,mmOptionSection>::const_iterator OptionMapSectionConstIter;
+
+ /** @name Mods
+ *@{
+ */
+ /** Fetch the number of mods available.
+ */
+ virtual int GetNumMods() = 0;
+
+ /** Get a list of the mods available.
+ */
+ virtual wxArrayString GetModList() = 0;
+
+ /** Check by name if a mod exists.
+ */
+ virtual bool ModExists( const wxString& modname ) = 0;
+
+ /** Check by name and hash string if a mod exists.
+ */
+ virtual bool ModExists( const wxString& modname, const wxString& hash ) = 0;
+
+ /** Check by hash string only if a mod exists.
+ */
+ virtual bool ModExistsCheckHash( const wxString& hash ) const = 0;
+
+ /** Get a mod by name.
+ */
+ virtual UnitSyncMod GetMod( const wxString& modname ) = 0;
+
+ /** Get a mod by index.
+ */
+ virtual UnitSyncMod GetMod( int index ) = 0;
+
+ /** Fetch the index of a mod by name.
+ */
+ virtual int GetModIndex( const wxString& name ) = 0;
+
+ /** Fetch the name of a mod archive by the mod index.
+ */
+ virtual wxString GetModArchive( int index ) = 0;
+
+ /** Get the options for a mod by name.
+ */
+ virtual GameOptions GetModOptions( const wxString& name ) = 0;
+ /**@}*/
+
+ virtual wxArrayString GetModDeps( const wxString& name ) = 0;
+
+ virtual int GetNumMaps() = 0;
+ virtual wxArrayString GetMapList() = 0;
+ virtual wxArrayString GetModValidMapList( const wxString& modname ) = 0;
+ virtual bool MapExists( const wxString& mapname ) = 0;
+ virtual bool MapExists( const wxString& mapname, const wxString& hash ) = 0;
+
+ virtual UnitSyncMap GetMap( const wxString& mapname ) = 0;
+ virtual UnitSyncMap GetMap( int index ) = 0;
+ virtual UnitSyncMap GetMapEx( const wxString& mapname ) = 0;
+ virtual UnitSyncMap GetMapEx( int index ) = 0;
+ virtual wxString GetMapArchive( int index ) = 0;
+ virtual GameOptions GetMapOptions( const wxString& name ) = 0;
+ virtual wxArrayString GetMapDeps( const wxString& name ) = 0;
+
+ virtual int GetMapIndex( const wxString& name ) = 0;
+ virtual wxImage GetMinimap( const wxString& mapname ) = 0;
+ virtual wxImage GetMinimap( const wxString& mapname, int width, int height ) = 0;
+ virtual wxImage GetMetalmap( const wxString& mapname ) = 0;
+ virtual wxImage GetMetalmap( const wxString& mapname, int width, int height ) = 0;
+ virtual wxImage GetHeightmap( const wxString& mapname ) = 0;
+ virtual wxImage GetHeightmap( const wxString& mapname, int width, int height ) = 0;
+
+ virtual wxArrayString GetSides( const wxString& modname ) = 0;
+ virtual wxImage GetSidePicture( const wxString& modname, const wxString& SideName ) =0;
+
+ virtual int GetNumUnits( const wxString& modname ) = 0;
+ virtual wxArrayString GetUnitsList( const wxString& modname ) = 0;
+
+ virtual bool LoadUnitSyncLib( const wxString& unitsyncloc ) = 0;
+ virtual void FreeUnitSyncLib() = 0;
+
+ virtual bool IsLoaded() = 0;
+
+ virtual wxString GetDefaultNick() = 0;
+ virtual void SetDefaultNick( const wxString& nick ) = 0;
+
+ virtual wxString GetSpringVersion() = 0;
+ virtual bool VersionSupports( GameFeature feature ) = 0;
+
+ virtual wxArrayString GetAIList( const wxString& modname ) = 0;
+ virtual wxArrayString GetAIInfos( int index ) = 0;
+ virtual GameOptions GetAIOptions( const wxString& modname, int index ) = 0;
+
+ virtual bool ReloadUnitSyncLib() = 0;
+
+ virtual wxArrayString GetPlaybackList( bool ReplayType = true ) = 0; //savegames otherwise
+
+ virtual void SetSpringDataPath( const wxString& path ) = 0;
+
+ virtual bool FileExists( const wxString& name ) = 0;
+
+ virtual wxString GetArchivePath( const wxString& name ) = 0;
+
+ virtual void PrefetchMap( const wxString& mapname ) = 0;
+
+ virtual int RegisterEvtHandler( wxEvtHandler* evtHandler ) = 0;
+ virtual void UnregisterEvtHandler( int evtHandlerId ) = 0;
+
+ virtual void GetMinimapAsync( const wxString& mapname, int evtHandlerId ) = 0;
+ virtual void GetMinimapAsync( const wxString& mapname, int width, int height, int evtHandlerId ) = 0;
+ virtual void GetMetalmapAsync( const wxString& mapname, int evtHandlerId ) = 0;
+ virtual void GetMetalmapAsync( const wxString& mapname, int width, int height, int evtHandlerId ) = 0;
+ virtual void GetHeightmapAsync( const wxString& mapname, int evtHandlerId ) = 0;
+ virtual void GetHeightmapAsync( const wxString& mapname, int width, int height, int evtHandlerId ) = 0;
+ virtual void GetMapExAsync( const wxString& mapname, int evtHandlerId ) = 0;
+
+ virtual wxArrayString GetScreenshotFilenames() = 0;
+
+ private:
+ IUnitSync( const IUnitSync& );
+};
+
+IUnitSync& usync();
+
+struct GameOptions
+{
+ IUnitSync::OptionMapBool bool_map;
+ IUnitSync::OptionMapFloat float_map;
+ IUnitSync::OptionMapString string_map;
+ IUnitSync::OptionMapList list_map;
+ IUnitSync::OptionMapSection section_map;
+};
+
+/// Helper class for managing async operations safely
+class UnitSyncAsyncOps
+{
+ public:
+ UnitSyncAsyncOps( wxEvtHandler* evtHandler ) {
+ m_id = usync().RegisterEvtHandler( evtHandler );
+ }
+ ~UnitSyncAsyncOps() {
+ usync().UnregisterEvtHandler( m_id );
+ }
+
+ void GetMinimap( const wxString& mapname ) { usync().GetMinimapAsync( mapname, m_id ); }
+ void GetMinimap( const wxString& mapname, int w, int h ) { usync().GetMinimapAsync( mapname, w, h, m_id ); }
+ void GetMetalmap( const wxString& mapname ) { usync().GetMetalmapAsync( mapname, m_id ); }
+ void GetMetalmap( const wxString& mapname, int w, int h ) { usync().GetMetalmapAsync( mapname, w, h, m_id ); }
+ void GetHeightmap( const wxString& mapname ) { usync().GetHeightmapAsync( mapname, m_id ); }
+ void GetHeightmap( const wxString& mapname, int w, int h ) { usync().GetHeightmapAsync( mapname, w, h, m_id ); }
+ void GetMapEx( const wxString& mapname ) { usync().GetMapExAsync( mapname, m_id ); }
+
+ private:
+ int m_id;
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_IUNITSYNC_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/libtorrent/asio.hpp b/src/libtorrent/asio.hpp
new file mode 100644
index 0000000..92a0b4b
--- /dev/null
+++ b/src/libtorrent/asio.hpp
@@ -0,0 +1,87 @@
+//
+// asio.hpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_HPP
+#define ASIO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/basic_deadline_timer.hpp"
+#include "asio/basic_io_object.hpp"
+#include "asio/basic_socket_acceptor.hpp"
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/basic_socket_streambuf.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/basic_streambuf.hpp"
+#include "asio/buffer.hpp"
+#include "asio/buffered_read_stream_fwd.hpp"
+#include "asio/buffered_read_stream.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+#include "asio/buffered_stream.hpp"
+#include "asio/buffered_write_stream_fwd.hpp"
+#include "asio/buffered_write_stream.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/datagram_socket_service.hpp"
+#include "asio/deadline_timer_service.hpp"
+#include "asio/deadline_timer.hpp"
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/handler_alloc_hook.hpp"
+#include "asio/handler_invoke_hook.hpp"
+#include "asio/io_service.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v6.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_entry.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/host_name.hpp"
+#include "asio/ip/multicast.hpp"
+#include "asio/ip/resolver_query_base.hpp"
+#include "asio/ip/resolver_service.hpp"
+#include "asio/ip/tcp.hpp"
+#include "asio/ip/udp.hpp"
+#include "asio/ip/unicast.hpp"
+#include "asio/ip/v6_only.hpp"
+#include "asio/is_read_buffered.hpp"
+#include "asio/is_write_buffered.hpp"
+#include "asio/local/basic_endpoint.hpp"
+#include "asio/local/connect_pair.hpp"
+#include "asio/local/datagram_protocol.hpp"
+#include "asio/local/stream_protocol.hpp"
+#include "asio/placeholders.hpp"
+#include "asio/posix/basic_descriptor.hpp"
+#include "asio/posix/basic_stream_descriptor.hpp"
+#include "asio/posix/descriptor_base.hpp"
+#include "asio/posix/stream_descriptor.hpp"
+#include "asio/posix/stream_descriptor_service.hpp"
+#include "asio/read.hpp"
+#include "asio/read_until.hpp"
+#include "asio/socket_acceptor_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/strand.hpp"
+#include "asio/stream_socket_service.hpp"
+#include "asio/streambuf.hpp"
+#include "asio/system_error.hpp"
+#include "asio/thread.hpp"
+#include "asio/time_traits.hpp"
+#include "asio/version.hpp"
+#include "asio/windows/basic_handle.hpp"
+#include "asio/windows/basic_stream_handle.hpp"
+#include "asio/windows/stream_handle.hpp"
+#include "asio/windows/stream_handle_service.hpp"
+#include "asio/write.hpp"
+
+#endif // ASIO_HPP
diff --git a/src/libtorrent/asio/basic_datagram_socket.hpp b/src/libtorrent/asio/basic_datagram_socket.hpp
new file mode 100644
index 0000000..0bfc512
--- /dev/null
+++ b/src/libtorrent/asio/basic_datagram_socket.hpp
@@ -0,0 +1,803 @@
+//
+// basic_datagram_socket.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_DATAGRAM_SOCKET_HPP
+#define ASIO_BASIC_DATAGRAM_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_socket.hpp"
+#include "asio/datagram_socket_service.hpp"
+#include "asio/error.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+/// Provides datagram-oriented socket functionality.
+/**
+ * The basic_datagram_socket class template provides asynchronous and blocking
+ * datagram-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol,
+ typename DatagramSocketService = datagram_socket_service<Protocol> >
+class basic_datagram_socket
+ : public basic_socket<Protocol, DatagramSocketService>
+{
+public:
+ /// The native representation of a socket.
+ typedef typename DatagramSocketService::native_type native_type;
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct a basic_datagram_socket without opening it.
+ /**
+ * This constructor creates a datagram socket without opening it. The open()
+ * function must be called before data can be sent or received on the socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ */
+ explicit basic_datagram_socket(asio::io_service& io_service)
+ : basic_socket<Protocol, DatagramSocketService>(io_service)
+ {
+ }
+
+ /// Construct and open a basic_datagram_socket.
+ /**
+ * This constructor creates and opens a datagram socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_datagram_socket(asio::io_service& io_service,
+ const protocol_type& protocol)
+ : basic_socket<Protocol, DatagramSocketService>(io_service, protocol)
+ {
+ }
+
+ /// Construct a basic_datagram_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a datagram socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the datagram
+ * socket will be bound.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_datagram_socket(asio::io_service& io_service,
+ const endpoint_type& endpoint)
+ : basic_socket<Protocol, DatagramSocketService>(io_service, endpoint)
+ {
+ }
+
+ /// Construct a basic_datagram_socket on an existing native socket.
+ /**
+ * This constructor creates a datagram socket object to hold an existing
+ * native socket.
+ *
+ * @param io_service The io_service object that the datagram socket will use
+ * to dispatch handlers for any asynchronous operations performed on the
+ * socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_datagram_socket(asio::io_service& io_service,
+ const protocol_type& protocol, const native_type& native_socket)
+ : basic_socket<Protocol, DatagramSocketService>(
+ io_service, protocol, native_socket)
+ {
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code socket.send(asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.send(
+ this->implementation, buffers, flags, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return this->service.send(this->implementation, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send(const ConstBufferSequence& buffers, WriteHandler handler)
+ {
+ this->service.async_send(this->implementation, buffers, 0, handler);
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, WriteHandler handler)
+ {
+ this->service.async_send(this->implementation, buffers, flags, handler);
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::ip::udp::endpoint destination(
+ * asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.send_to(asio::buffer(data, size), destination);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.send_to(
+ this->implementation, buffers, destination, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.send_to(
+ this->implementation, buffers, destination, flags, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ asio::error_code& ec)
+ {
+ return this->service.send_to(this->implementation,
+ buffers, destination, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::ip::udp::endpoint destination(
+ * asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.async_send_to(
+ * asio::buffer(data, size), destination, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, WriteHandler handler)
+ {
+ this->service.async_send_to(this->implementation, buffers, destination, 0,
+ handler);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ WriteHandler handler)
+ {
+ this->service.async_send_to(this->implementation, buffers, destination,
+ flags, handler);
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.receive(asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.receive(
+ this->implementation, buffers, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.receive(
+ this->implementation, buffers, flags, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return this->service.receive(this->implementation, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive(const MutableBufferSequence& buffers, ReadHandler handler)
+ {
+ this->service.async_receive(this->implementation, buffers, 0, handler);
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, ReadHandler handler)
+ {
+ this->service.async_receive(this->implementation, buffers, flags, handler);
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * asio::ip::udp::endpoint sender_endpoint;
+ * socket.receive_from(
+ * asio::buffer(data, size), sender_endpoint);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.receive_from(
+ this->implementation, buffers, sender_endpoint, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.receive_from(
+ this->implementation, buffers, sender_endpoint, flags, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ asio::error_code& ec)
+ {
+ return this->service.receive_from(this->implementation, buffers,
+ sender_endpoint, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.async_receive_from(
+ * asio::buffer(data, size), 0, sender_endpoint, handler); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, ReadHandler handler)
+ {
+ this->service.async_receive_from(this->implementation, buffers,
+ sender_endpoint, 0, handler);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ ReadHandler handler)
+ {
+ this->service.async_receive_from(this->implementation, buffers,
+ sender_endpoint, flags, handler);
+ }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP
diff --git a/src/libtorrent/asio/basic_deadline_timer.hpp b/src/libtorrent/asio/basic_deadline_timer.hpp
new file mode 100644
index 0000000..75d33b9
--- /dev/null
+++ b/src/libtorrent/asio/basic_deadline_timer.hpp
@@ -0,0 +1,381 @@
+//
+// basic_deadline_timer.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_DEADLINE_TIMER_HPP
+#define ASIO_BASIC_DEADLINE_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_io_object.hpp"
+#include "asio/deadline_timer_service.hpp"
+#include "asio/error.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+/// Provides waitable timer functionality.
+/**
+ * The basic_deadline_timer class template provides the ability to perform a
+ * blocking or asynchronous wait for a timer to expire.
+ *
+ * Most applications will use the asio::deadline_timer typedef.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Examples
+ * Performing a blocking wait:
+ * @code
+ * // Construct a timer without setting an expiry time.
+ * asio::deadline_timer timer(io_service);
+ *
+ * // Set an expiry time relative to now.
+ * timer.expires_from_now(boost::posix_time::seconds(5));
+ *
+ * // Wait for the timer to expire.
+ * timer.wait();
+ * @endcode
+ *
+ * @par
+ * Performing an asynchronous wait:
+ * @code
+ * void handler(const asio::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Timer expired.
+ * }
+ * }
+ *
+ * ...
+ *
+ * // Construct a timer with an absolute expiry time.
+ * asio::deadline_timer timer(io_service,
+ * boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
+ *
+ * // Start an asynchronous wait.
+ * timer.async_wait(handler);
+ * @endcode
+ *
+ * @par Changing an active deadline_timer's expiry time
+ *
+ * Changing the expiry time of a timer while there are pending asynchronous
+ * waits causes those wait operations to be cancelled. To ensure that the action
+ * associated with the timer is performed only once, use something like this:
+ * used:
+ *
+ * @code
+ * void on_some_event()
+ * {
+ * if (my_timer.expires_from_now(seconds(5)) > 0)
+ * {
+ * // We managed to cancel the timer. Start new asynchronous wait.
+ * my_timer.async_wait(on_timeout);
+ * }
+ * else
+ * {
+ * // Too late, timer has already expired!
+ * }
+ * }
+ *
+ * void on_timeout(const asio::error_code& e)
+ * {
+ * if (e != asio::error::operation_aborted)
+ * {
+ * // Timer was not cancelled, take necessary action.
+ * }
+ * }
+ * @endcode
+ *
+ * @li The asio::basic_deadline_timer::expires_from_now() function
+ * cancels any pending asynchronous waits, and returns the number of
+ * asynchronous waits that were cancelled. If it returns 0 then you were too
+ * late and the wait handler has already been executed, or will soon be
+ * executed. If it returns 1 then the wait handler was successfully cancelled.
+ *
+ * @li If a wait handler is cancelled, the asio::error_code passed to
+ * it contains the value asio::error::operation_aborted.
+ */
+template <typename Time,
+ typename TimeTraits = asio::time_traits<Time>,
+ typename TimerService = deadline_timer_service<Time, TimeTraits> >
+class basic_deadline_timer
+ : public basic_io_object<TimerService>
+{
+public:
+ /// The time traits type.
+ typedef TimeTraits traits_type;
+
+ /// The time type.
+ typedef typename traits_type::time_type time_type;
+
+ /// The duration type.
+ typedef typename traits_type::duration_type duration_type;
+
+ /// Constructor.
+ /**
+ * This constructor creates a timer without setting an expiry time. The
+ * expires_at() or expires_from_now() functions must be called to set an
+ * expiry time before the timer can be waited on.
+ *
+ * @param io_service The io_service object that the timer will use to dispatch
+ * handlers for any asynchronous operations performed on the timer.
+ */
+ explicit basic_deadline_timer(asio::io_service& io_service)
+ : basic_io_object<TimerService>(io_service)
+ {
+ }
+
+ /// Constructor to set a particular expiry time as an absolute time.
+ /**
+ * This constructor creates a timer and sets the expiry time.
+ *
+ * @param io_service The io_service object that the timer will use to dispatch
+ * handlers for any asynchronous operations performed on the timer.
+ *
+ * @param expiry_time The expiry time to be used for the timer, expressed
+ * as an absolute time.
+ */
+ basic_deadline_timer(asio::io_service& io_service,
+ const time_type& expiry_time)
+ : basic_io_object<TimerService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.expires_at(this->implementation, expiry_time, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Constructor to set a particular expiry time relative to now.
+ /**
+ * This constructor creates a timer and sets the expiry time.
+ *
+ * @param io_service The io_service object that the timer will use to dispatch
+ * handlers for any asynchronous operations performed on the timer.
+ *
+ * @param expiry_time The expiry time to be used for the timer, relative to
+ * now.
+ */
+ basic_deadline_timer(asio::io_service& io_service,
+ const duration_type& expiry_time)
+ : basic_io_object<TimerService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.expires_from_now(this->implementation, expiry_time, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Cancel any asynchronous operations that are waiting on the timer.
+ /**
+ * This function forces the completion of any pending asynchronous wait
+ * operations against the timer. The handler for each cancelled operation will
+ * be invoked with the asio::error::operation_aborted error code.
+ *
+ * Cancelling the timer does not change the expiry time.
+ *
+ * @return The number of asynchronous operations that were cancelled.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t cancel()
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.cancel(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Cancel any asynchronous operations that are waiting on the timer.
+ /**
+ * This function forces the completion of any pending asynchronous wait
+ * operations against the timer. The handler for each cancelled operation will
+ * be invoked with the asio::error::operation_aborted error code.
+ *
+ * Cancelling the timer does not change the expiry time.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of asynchronous operations that were cancelled.
+ */
+ std::size_t cancel(asio::error_code& ec)
+ {
+ return this->service.cancel(this->implementation, ec);
+ }
+
+ /// Get the timer's expiry time as an absolute time.
+ /**
+ * This function may be used to obtain the timer's current expiry time.
+ * Whether the timer has expired or not does not affect this value.
+ */
+ time_type expires_at() const
+ {
+ return this->service.expires_at(this->implementation);
+ }
+
+ /// Set the timer's expiry time as an absolute time.
+ /**
+ * This function sets the expiry time. Any pending asynchronous wait
+ * operations will be cancelled. The handler for each cancelled operation will
+ * be invoked with the asio::error::operation_aborted error code.
+ *
+ * @param expiry_time The expiry time to be used for the timer.
+ *
+ * @return The number of asynchronous operations that were cancelled.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t expires_at(const time_type& expiry_time)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.expires_at(
+ this->implementation, expiry_time, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Set the timer's expiry time as an absolute time.
+ /**
+ * This function sets the expiry time. Any pending asynchronous wait
+ * operations will be cancelled. The handler for each cancelled operation will
+ * be invoked with the asio::error::operation_aborted error code.
+ *
+ * @param expiry_time The expiry time to be used for the timer.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of asynchronous operations that were cancelled.
+ */
+ std::size_t expires_at(const time_type& expiry_time,
+ asio::error_code& ec)
+ {
+ return this->service.expires_at(this->implementation, expiry_time, ec);
+ }
+
+ /// Get the timer's expiry time relative to now.
+ /**
+ * This function may be used to obtain the timer's current expiry time.
+ * Whether the timer has expired or not does not affect this value.
+ */
+ duration_type expires_from_now() const
+ {
+ return this->service.expires_from_now(this->implementation);
+ }
+
+ /// Set the timer's expiry time relative to now.
+ /**
+ * This function sets the expiry time. Any pending asynchronous wait
+ * operations will be cancelled. The handler for each cancelled operation will
+ * be invoked with the asio::error::operation_aborted error code.
+ *
+ * @param expiry_time The expiry time to be used for the timer.
+ *
+ * @return The number of asynchronous operations that were cancelled.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t expires_from_now(const duration_type& expiry_time)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.expires_from_now(
+ this->implementation, expiry_time, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Set the timer's expiry time relative to now.
+ /**
+ * This function sets the expiry time. Any pending asynchronous wait
+ * operations will be cancelled. The handler for each cancelled operation will
+ * be invoked with the asio::error::operation_aborted error code.
+ *
+ * @param expiry_time The expiry time to be used for the timer.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of asynchronous operations that were cancelled.
+ */
+ std::size_t expires_from_now(const duration_type& expiry_time,
+ asio::error_code& ec)
+ {
+ return this->service.expires_from_now(
+ this->implementation, expiry_time, ec);
+ }
+
+ /// Perform a blocking wait on the timer.
+ /**
+ * This function is used to wait for the timer to expire. This function
+ * blocks and does not return until the timer has expired.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void wait()
+ {
+ asio::error_code ec;
+ this->service.wait(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Perform a blocking wait on the timer.
+ /**
+ * This function is used to wait for the timer to expire. This function
+ * blocks and does not return until the timer has expired.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ void wait(asio::error_code& ec)
+ {
+ this->service.wait(this->implementation, ec);
+ }
+
+ /// Start an asynchronous wait on the timer.
+ /**
+ * This function may be used to initiate an asynchronous wait against the
+ * timer. It always returns immediately.
+ *
+ * For each call to async_wait(), the supplied handler will be called exactly
+ * once. The handler will be called when:
+ *
+ * @li The timer has expired.
+ *
+ * @li The timer was cancelled, in which case the handler is passed the error
+ * code asio::error::operation_aborted.
+ *
+ * @param handler The handler to be called when the timer expires. Copies
+ * will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error // Result of operation.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ */
+ template <typename WaitHandler>
+ void async_wait(WaitHandler handler)
+ {
+ this->service.async_wait(this->implementation, handler);
+ }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_DEADLINE_TIMER_HPP
diff --git a/src/libtorrent/asio/basic_io_object.hpp b/src/libtorrent/asio/basic_io_object.hpp
new file mode 100644
index 0000000..6e369ab
--- /dev/null
+++ b/src/libtorrent/asio/basic_io_object.hpp
@@ -0,0 +1,97 @@
+//
+// basic_io_object.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_IO_OBJECT_HPP
+#define ASIO_BASIC_IO_OBJECT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+
+/// Base class for all I/O objects.
+template <typename IoObjectService>
+class basic_io_object
+ : private noncopyable
+{
+public:
+ /// The type of the service that will be used to provide I/O operations.
+ typedef IoObjectService service_type;
+
+ /// The underlying implementation type of I/O object.
+ typedef typename service_type::implementation_type implementation_type;
+
+ /// (Deprecated: use get_io_service().) Get the io_service associated with
+ /// the object.
+ /**
+ * This function may be used to obtain the io_service object that the I/O
+ * object uses to dispatch handlers for asynchronous operations.
+ *
+ * @return A reference to the io_service object that the I/O object will use
+ * to dispatch handlers. Ownership is not transferred to the caller.
+ */
+ asio::io_service& io_service()
+ {
+ return service.get_io_service();
+ }
+
+ /// Get the io_service associated with the object.
+ /**
+ * This function may be used to obtain the io_service object that the I/O
+ * object uses to dispatch handlers for asynchronous operations.
+ *
+ * @return A reference to the io_service object that the I/O object will use
+ * to dispatch handlers. Ownership is not transferred to the caller.
+ */
+ asio::io_service& get_io_service()
+ {
+ return service.get_io_service();
+ }
+
+protected:
+ /// Construct a basic_io_object.
+ /**
+ * Performs:
+ * @code service.construct(implementation); @endcode
+ */
+ explicit basic_io_object(asio::io_service& io_service)
+ : service(asio::use_service<IoObjectService>(io_service))
+ {
+ service.construct(implementation);
+ }
+
+ /// Protected destructor to prevent deletion through this type.
+ /**
+ * Performs:
+ * @code service.destroy(implementation); @endcode
+ */
+ ~basic_io_object()
+ {
+ service.destroy(implementation);
+ }
+
+ /// The service associated with the I/O object.
+ service_type& service;
+
+ /// The underlying implementation of the I/O object.
+ implementation_type implementation;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_IO_OBJECT_HPP
diff --git a/src/libtorrent/asio/basic_socket.hpp b/src/libtorrent/asio/basic_socket.hpp
new file mode 100644
index 0000000..5335614
--- /dev/null
+++ b/src/libtorrent/asio/basic_socket.hpp
@@ -0,0 +1,1049 @@
+//
+// basic_socket.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_SOCKET_HPP
+#define ASIO_BASIC_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_io_object.hpp"
+#include "asio/error.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+/// Provides socket functionality.
+/**
+ * The basic_socket class template provides functionality that is common to both
+ * stream-oriented and datagram-oriented sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename SocketService>
+class basic_socket
+ : public basic_io_object<SocketService>,
+ public socket_base
+{
+public:
+ /// The native representation of a socket.
+ typedef typename SocketService::native_type native_type;
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// A basic_socket is always the lowest layer.
+ typedef basic_socket<Protocol, SocketService> lowest_layer_type;
+
+ /// Construct a basic_socket without opening it.
+ /**
+ * This constructor creates a socket without opening it.
+ *
+ * @param io_service The io_service object that the socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ */
+ explicit basic_socket(asio::io_service& io_service)
+ : basic_io_object<SocketService>(io_service)
+ {
+ }
+
+ /// Construct and open a basic_socket.
+ /**
+ * This constructor creates and opens a socket.
+ *
+ * @param io_service The io_service object that the socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_socket(asio::io_service& io_service,
+ const protocol_type& protocol)
+ : basic_io_object<SocketService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.open(this->implementation, protocol, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Construct a basic_socket, opening it and binding it to the given local
+ /// endpoint.
+ /**
+ * This constructor creates a socket and automatically opens it bound to the
+ * specified endpoint on the local machine. The protocol used is the protocol
+ * associated with the given endpoint.
+ *
+ * @param io_service The io_service object that the socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_socket(asio::io_service& io_service,
+ const endpoint_type& endpoint)
+ : basic_io_object<SocketService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.open(this->implementation, endpoint.protocol(), ec);
+ asio::detail::throw_error(ec);
+ this->service.bind(this->implementation, endpoint, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Construct a basic_socket on an existing native socket.
+ /**
+ * This constructor creates a socket object to hold an existing native socket.
+ *
+ * @param io_service The io_service object that the socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_socket(asio::io_service& io_service,
+ const protocol_type& protocol, const native_type& native_socket)
+ : basic_io_object<SocketService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.assign(this->implementation, protocol, native_socket, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Get a reference to the lowest layer.
+ /**
+ * This function returns a reference to the lowest layer in a stack of
+ * layers. Since a basic_socket cannot contain any further layers, it simply
+ * returns a reference to itself.
+ *
+ * @return A reference to the lowest layer in the stack of layers. Ownership
+ * is not transferred to the caller.
+ */
+ lowest_layer_type& lowest_layer()
+ {
+ return *this;
+ }
+
+ /// Open the socket using the specified protocol.
+ /**
+ * This function opens the socket so that it will use the specified protocol.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * socket.open(asio::ip::tcp::v4());
+ * @endcode
+ */
+ void open(const protocol_type& protocol = protocol_type())
+ {
+ asio::error_code ec;
+ this->service.open(this->implementation, protocol, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Open the socket using the specified protocol.
+ /**
+ * This function opens the socket so that it will use the specified protocol.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * asio::error_code ec;
+ * socket.open(asio::ip::tcp::v4(), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code open(const protocol_type& protocol,
+ asio::error_code& ec)
+ {
+ return this->service.open(this->implementation, protocol, ec);
+ }
+
+ /// Assign an existing native socket to the socket.
+ /*
+ * This function opens the socket to hold an existing native socket.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void assign(const protocol_type& protocol, const native_type& native_socket)
+ {
+ asio::error_code ec;
+ this->service.assign(this->implementation, protocol, native_socket, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Assign an existing native socket to the socket.
+ /*
+ * This function opens the socket to hold an existing native socket.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code assign(const protocol_type& protocol,
+ const native_type& native_socket, asio::error_code& ec)
+ {
+ return this->service.assign(this->implementation,
+ protocol, native_socket, ec);
+ }
+
+ /// Determine whether the socket is open.
+ bool is_open() const
+ {
+ return this->service.is_open(this->implementation);
+ }
+
+ /// Close the socket.
+ /**
+ * This function is used to close the socket. Any asynchronous send, receive
+ * or connect operations will be cancelled immediately, and will complete
+ * with the asio::error::operation_aborted error.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note For portable behaviour with respect to graceful closure of a
+ * connected socket, call shutdown() before closing the socket.
+ */
+ void close()
+ {
+ asio::error_code ec;
+ this->service.close(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Close the socket.
+ /**
+ * This function is used to close the socket. Any asynchronous send, receive
+ * or connect operations will be cancelled immediately, and will complete
+ * with the asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::error_code ec;
+ * socket.close(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ *
+ * @note For portable behaviour with respect to graceful closure of a
+ * connected socket, call shutdown() before closing the socket.
+ */
+ asio::error_code close(asio::error_code& ec)
+ {
+ return this->service.close(this->implementation, ec);
+ }
+
+ /// Get the native socket representation.
+ /**
+ * This function may be used to obtain the underlying representation of the
+ * socket. This is intended to allow access to native socket functionality
+ * that is not otherwise provided.
+ */
+ native_type native()
+ {
+ return this->service.native(this->implementation);
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the asio::error::operation_aborted error.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note Calls to cancel() will always fail with
+ * asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
+ void cancel()
+ {
+ asio::error_code ec;
+ this->service.cancel(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note Calls to cancel() will always fail with
+ * asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
+ asio::error_code cancel(asio::error_code& ec)
+ {
+ return this->service.cancel(this->implementation, ec);
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ /**
+ * This function is used to check whether the socket input is currently
+ * positioned at the out-of-band data mark.
+ *
+ * @return A bool indicating whether the socket is at the out-of-band data
+ * mark.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ bool at_mark() const
+ {
+ asio::error_code ec;
+ bool b = this->service.at_mark(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ return b;
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ /**
+ * This function is used to check whether the socket input is currently
+ * positioned at the out-of-band data mark.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return A bool indicating whether the socket is at the out-of-band data
+ * mark.
+ */
+ bool at_mark(asio::error_code& ec) const
+ {
+ return this->service.at_mark(this->implementation, ec);
+ }
+
+ /// Determine the number of bytes available for reading.
+ /**
+ * This function is used to determine the number of bytes that may be read
+ * without blocking.
+ *
+ * @return The number of bytes that may be read without blocking, or 0 if an
+ * error occurs.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t available() const
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.available(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Determine the number of bytes available for reading.
+ /**
+ * This function is used to determine the number of bytes that may be read
+ * without blocking.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of bytes that may be read without blocking, or 0 if an
+ * error occurs.
+ */
+ std::size_t available(asio::error_code& ec) const
+ {
+ return this->service.available(this->implementation, ec);
+ }
+
+ /// Bind the socket to the given local endpoint.
+ /**
+ * This function binds the socket to the specified endpoint on the local
+ * machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * socket.open(asio::ip::tcp::v4());
+ * socket.bind(asio::ip::tcp::endpoint(
+ * asio::ip::tcp::v4(), 12345));
+ * @endcode
+ */
+ void bind(const endpoint_type& endpoint)
+ {
+ asio::error_code ec;
+ this->service.bind(this->implementation, endpoint, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Bind the socket to the given local endpoint.
+ /**
+ * This function binds the socket to the specified endpoint on the local
+ * machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * socket.open(asio::ip::tcp::v4());
+ * asio::error_code ec;
+ * socket.bind(asio::ip::tcp::endpoint(
+ * asio::ip::tcp::v4(), 12345), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code bind(const endpoint_type& endpoint,
+ asio::error_code& ec)
+ {
+ return this->service.bind(this->implementation, endpoint, ec);
+ }
+
+ /// Connect the socket to the specified endpoint.
+ /**
+ * This function is used to connect a socket to the specified remote endpoint.
+ * The function call will block until the connection is successfully made or
+ * an error occurs.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * asio::ip::tcp::endpoint endpoint(
+ * asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.connect(endpoint);
+ * @endcode
+ */
+ void connect(const endpoint_type& peer_endpoint)
+ {
+ asio::error_code ec;
+ if (!is_open())
+ {
+ this->service.open(this->implementation, peer_endpoint.protocol(), ec);
+ asio::detail::throw_error(ec);
+ }
+ this->service.connect(this->implementation, peer_endpoint, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Connect the socket to the specified endpoint.
+ /**
+ * This function is used to connect a socket to the specified remote endpoint.
+ * The function call will block until the connection is successfully made or
+ * an error occurs.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * asio::ip::tcp::endpoint endpoint(
+ * asio::ip::address::from_string("1.2.3.4"), 12345);
+ * asio::error_code ec;
+ * socket.connect(endpoint, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code connect(const endpoint_type& peer_endpoint,
+ asio::error_code& ec)
+ {
+ if (!is_open())
+ {
+ if (this->service.open(this->implementation,
+ peer_endpoint.protocol(), ec))
+ {
+ return ec;
+ }
+ }
+
+ return this->service.connect(this->implementation, peer_endpoint, ec);
+ }
+
+ /// Start an asynchronous connect.
+ /**
+ * This function is used to asynchronously connect a socket to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected. Copies will be made of the endpoint object as required.
+ *
+ * @param handler The handler to be called when the connection operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error // Result of operation
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * @code
+ * void connect_handler(const asio::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Connect succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * asio::ip::tcp::socket socket(io_service);
+ * asio::ip::tcp::endpoint endpoint(
+ * asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.async_connect(endpoint, connect_handler);
+ * @endcode
+ */
+ template <typename ConnectHandler>
+ void async_connect(const endpoint_type& peer_endpoint, ConnectHandler handler)
+ {
+ if (!is_open())
+ {
+ asio::error_code ec;
+ if (this->service.open(this->implementation,
+ peer_endpoint.protocol(), ec))
+ {
+ this->get_io_service().post(
+ asio::detail::bind_handler(handler, ec));
+ return;
+ }
+ }
+
+ this->service.async_connect(this->implementation, peer_endpoint, handler);
+ }
+
+ /// Set an option on the socket.
+ /**
+ * This function is used to set an option on the socket.
+ *
+ * @param option The new option value to be set on the socket.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @sa SettableSocketOption @n
+ * asio::socket_base::broadcast @n
+ * asio::socket_base::do_not_route @n
+ * asio::socket_base::keep_alive @n
+ * asio::socket_base::linger @n
+ * asio::socket_base::receive_buffer_size @n
+ * asio::socket_base::receive_low_watermark @n
+ * asio::socket_base::reuse_address @n
+ * asio::socket_base::send_buffer_size @n
+ * asio::socket_base::send_low_watermark @n
+ * asio::ip::multicast::join_group @n
+ * asio::ip::multicast::leave_group @n
+ * asio::ip::multicast::enable_loopback @n
+ * asio::ip::multicast::outbound_interface @n
+ * asio::ip::multicast::hops @n
+ * asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Setting the IPPROTO_TCP/TCP_NODELAY option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::no_delay option(true);
+ * socket.set_option(option);
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ void set_option(const SettableSocketOption& option)
+ {
+ asio::error_code ec;
+ this->service.set_option(this->implementation, option, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Set an option on the socket.
+ /**
+ * This function is used to set an option on the socket.
+ *
+ * @param option The new option value to be set on the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa SettableSocketOption @n
+ * asio::socket_base::broadcast @n
+ * asio::socket_base::do_not_route @n
+ * asio::socket_base::keep_alive @n
+ * asio::socket_base::linger @n
+ * asio::socket_base::receive_buffer_size @n
+ * asio::socket_base::receive_low_watermark @n
+ * asio::socket_base::reuse_address @n
+ * asio::socket_base::send_buffer_size @n
+ * asio::socket_base::send_low_watermark @n
+ * asio::ip::multicast::join_group @n
+ * asio::ip::multicast::leave_group @n
+ * asio::ip::multicast::enable_loopback @n
+ * asio::ip::multicast::outbound_interface @n
+ * asio::ip::multicast::hops @n
+ * asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Setting the IPPROTO_TCP/TCP_NODELAY option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::no_delay option(true);
+ * asio::error_code ec;
+ * socket.set_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ asio::error_code set_option(const SettableSocketOption& option,
+ asio::error_code& ec)
+ {
+ return this->service.set_option(this->implementation, option, ec);
+ }
+
+ /// Get an option from the socket.
+ /**
+ * This function is used to get the current value of an option on the socket.
+ *
+ * @param option The option value to be obtained from the socket.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @sa GettableSocketOption @n
+ * asio::socket_base::broadcast @n
+ * asio::socket_base::do_not_route @n
+ * asio::socket_base::keep_alive @n
+ * asio::socket_base::linger @n
+ * asio::socket_base::receive_buffer_size @n
+ * asio::socket_base::receive_low_watermark @n
+ * asio::socket_base::reuse_address @n
+ * asio::socket_base::send_buffer_size @n
+ * asio::socket_base::send_low_watermark @n
+ * asio::ip::multicast::join_group @n
+ * asio::ip::multicast::leave_group @n
+ * asio::ip::multicast::enable_loopback @n
+ * asio::ip::multicast::outbound_interface @n
+ * asio::ip::multicast::hops @n
+ * asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::socket::keep_alive option;
+ * socket.get_option(option);
+ * bool is_set = option.get();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ void get_option(GettableSocketOption& option) const
+ {
+ asio::error_code ec;
+ this->service.get_option(this->implementation, option, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Get an option from the socket.
+ /**
+ * This function is used to get the current value of an option on the socket.
+ *
+ * @param option The option value to be obtained from the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa GettableSocketOption @n
+ * asio::socket_base::broadcast @n
+ * asio::socket_base::do_not_route @n
+ * asio::socket_base::keep_alive @n
+ * asio::socket_base::linger @n
+ * asio::socket_base::receive_buffer_size @n
+ * asio::socket_base::receive_low_watermark @n
+ * asio::socket_base::reuse_address @n
+ * asio::socket_base::send_buffer_size @n
+ * asio::socket_base::send_low_watermark @n
+ * asio::ip::multicast::join_group @n
+ * asio::ip::multicast::leave_group @n
+ * asio::ip::multicast::enable_loopback @n
+ * asio::ip::multicast::outbound_interface @n
+ * asio::ip::multicast::hops @n
+ * asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::socket::keep_alive option;
+ * asio::error_code ec;
+ * socket.get_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * bool is_set = option.get();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ asio::error_code get_option(GettableSocketOption& option,
+ asio::error_code& ec) const
+ {
+ return this->service.get_option(this->implementation, option, ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ /**
+ * This function is used to execute an IO control command on the socket.
+ *
+ * @param command The IO control command to be performed on the socket.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @sa IoControlCommand @n
+ * asio::socket_base::bytes_readable @n
+ * asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::socket::bytes_readable command;
+ * socket.io_control(command);
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ void io_control(IoControlCommand& command)
+ {
+ asio::error_code ec;
+ this->service.io_control(this->implementation, command, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ /**
+ * This function is used to execute an IO control command on the socket.
+ *
+ * @param command The IO control command to be performed on the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa IoControlCommand @n
+ * asio::socket_base::bytes_readable @n
+ * asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::socket::bytes_readable command;
+ * asio::error_code ec;
+ * socket.io_control(command, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ asio::error_code io_control(IoControlCommand& command,
+ asio::error_code& ec)
+ {
+ return this->service.io_control(this->implementation, command, ec);
+ }
+
+ /// Get the local endpoint of the socket.
+ /**
+ * This function is used to obtain the locally bound endpoint of the socket.
+ *
+ * @returns An object that represents the local endpoint of the socket.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::endpoint endpoint = socket.local_endpoint();
+ * @endcode
+ */
+ endpoint_type local_endpoint() const
+ {
+ asio::error_code ec;
+ endpoint_type ep = this->service.local_endpoint(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ return ep;
+ }
+
+ /// Get the local endpoint of the socket.
+ /**
+ * This function is used to obtain the locally bound endpoint of the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the local endpoint of the socket.
+ * Returns a default-constructed endpoint object if an error occurred.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::error_code ec;
+ * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type local_endpoint(asio::error_code& ec) const
+ {
+ return this->service.local_endpoint(this->implementation, ec);
+ }
+
+ /// Get the remote endpoint of the socket.
+ /**
+ * This function is used to obtain the remote endpoint of the socket.
+ *
+ * @returns An object that represents the remote endpoint of the socket.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
+ * @endcode
+ */
+ endpoint_type remote_endpoint() const
+ {
+ asio::error_code ec;
+ endpoint_type ep = this->service.remote_endpoint(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ return ep;
+ }
+
+ /// Get the remote endpoint of the socket.
+ /**
+ * This function is used to obtain the remote endpoint of the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the remote endpoint of the socket.
+ * Returns a default-constructed endpoint object if an error occurred.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::error_code ec;
+ * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type remote_endpoint(asio::error_code& ec) const
+ {
+ return this->service.remote_endpoint(this->implementation, ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ /**
+ * This function is used to disable send operations, receive operations, or
+ * both.
+ *
+ * @param what Determines what types of operation will no longer be allowed.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * Shutting down the send side of the socket:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * socket.shutdown(asio::ip::tcp::socket::shutdown_send);
+ * @endcode
+ */
+ void shutdown(shutdown_type what)
+ {
+ asio::error_code ec;
+ this->service.shutdown(this->implementation, what, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ /**
+ * This function is used to disable send operations, receive operations, or
+ * both.
+ *
+ * @param what Determines what types of operation will no longer be allowed.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * Shutting down the send side of the socket:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::error_code ec;
+ * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code shutdown(shutdown_type what,
+ asio::error_code& ec)
+ {
+ return this->service.shutdown(this->implementation, what, ec);
+ }
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ ~basic_socket()
+ {
+ }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_SOCKET_HPP
diff --git a/src/libtorrent/asio/basic_socket_acceptor.hpp b/src/libtorrent/asio/basic_socket_acceptor.hpp
new file mode 100644
index 0000000..43a4fa4
--- /dev/null
+++ b/src/libtorrent/asio/basic_socket_acceptor.hpp
@@ -0,0 +1,824 @@
+//
+// basic_socket_acceptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_SOCKET_ACCEPTOR_HPP
+#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/basic_io_object.hpp"
+#include "asio/basic_socket.hpp"
+#include "asio/error.hpp"
+#include "asio/socket_acceptor_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+/// Provides the ability to accept new connections.
+/**
+ * The basic_socket_acceptor class template is used for accepting new socket
+ * connections.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Example
+ * Opening a socket acceptor with the SO_REUSEADDR option enabled:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
+ * acceptor.open(endpoint.protocol());
+ * acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
+ * acceptor.bind(endpoint);
+ * acceptor.listen();
+ * @endcode
+ */
+template <typename Protocol,
+ typename SocketAcceptorService = socket_acceptor_service<Protocol> >
+class basic_socket_acceptor
+ : public basic_io_object<SocketAcceptorService>,
+ public socket_base
+{
+public:
+ /// The native representation of an acceptor.
+ typedef typename SocketAcceptorService::native_type native_type;
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct an acceptor without opening it.
+ /**
+ * This constructor creates an acceptor without opening it to listen for new
+ * connections. The open() function must be called before the acceptor can
+ * accept new socket connections.
+ *
+ * @param io_service The io_service object that the acceptor will use to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ */
+ explicit basic_socket_acceptor(asio::io_service& io_service)
+ : basic_io_object<SocketAcceptorService>(io_service)
+ {
+ }
+
+ /// Construct an open acceptor.
+ /**
+ * This constructor creates an acceptor and automatically opens it.
+ *
+ * @param io_service The io_service object that the acceptor will use to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_socket_acceptor(asio::io_service& io_service,
+ const protocol_type& protocol)
+ : basic_io_object<SocketAcceptorService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.open(this->implementation, protocol, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Construct an acceptor opened on the given endpoint.
+ /**
+ * This constructor creates an acceptor and automatically opens it to listen
+ * for new connections on the specified endpoint.
+ *
+ * @param io_service The io_service object that the acceptor will use to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ *
+ * @param endpoint An endpoint on the local machine on which the acceptor
+ * will listen for new connections.
+ *
+ * @param reuse_addr Whether the constructor should set the socket option
+ * socket_base::reuse_address.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This constructor is equivalent to the following code:
+ * @code
+ * basic_socket_acceptor<Protocol> acceptor(io_service);
+ * acceptor.open(endpoint.protocol());
+ * if (reuse_addr)
+ * acceptor.set_option(socket_base::reuse_address(true));
+ * acceptor.bind(endpoint);
+ * acceptor.listen(listen_backlog);
+ * @endcode
+ */
+ basic_socket_acceptor(asio::io_service& io_service,
+ const endpoint_type& endpoint, bool reuse_addr = true)
+ : basic_io_object<SocketAcceptorService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.open(this->implementation, endpoint.protocol(), ec);
+ asio::detail::throw_error(ec);
+ if (reuse_addr)
+ {
+ this->service.set_option(this->implementation,
+ socket_base::reuse_address(true), ec);
+ asio::detail::throw_error(ec);
+ }
+ this->service.bind(this->implementation, endpoint, ec);
+ asio::detail::throw_error(ec);
+ this->service.listen(this->implementation,
+ socket_base::max_connections, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Construct a basic_socket_acceptor on an existing native acceptor.
+ /**
+ * This constructor creates an acceptor object to hold an existing native
+ * acceptor.
+ *
+ * @param io_service The io_service object that the acceptor will use to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_acceptor A native acceptor.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_socket_acceptor(asio::io_service& io_service,
+ const protocol_type& protocol, const native_type& native_acceptor)
+ : basic_io_object<SocketAcceptorService>(io_service)
+ {
+ asio::error_code ec;
+ this->service.assign(this->implementation, protocol, native_acceptor, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Open the acceptor using the specified protocol.
+ /**
+ * This function opens the socket acceptor so that it will use the specified
+ * protocol.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * acceptor.open(asio::ip::tcp::v4());
+ * @endcode
+ */
+ void open(const protocol_type& protocol = protocol_type())
+ {
+ asio::error_code ec;
+ this->service.open(this->implementation, protocol, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Open the acceptor using the specified protocol.
+ /**
+ * This function opens the socket acceptor so that it will use the specified
+ * protocol.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * asio::error_code ec;
+ * acceptor.open(asio::ip::tcp::v4(), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code open(const protocol_type& protocol,
+ asio::error_code& ec)
+ {
+ return this->service.open(this->implementation, protocol, ec);
+ }
+
+ /// Assigns an existing native acceptor to the acceptor.
+ /*
+ * This function opens the acceptor to hold an existing native acceptor.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_acceptor A native acceptor.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void assign(const protocol_type& protocol, const native_type& native_acceptor)
+ {
+ asio::error_code ec;
+ this->service.assign(this->implementation, protocol, native_acceptor, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Assigns an existing native acceptor to the acceptor.
+ /*
+ * This function opens the acceptor to hold an existing native acceptor.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_acceptor A native acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code assign(const protocol_type& protocol,
+ const native_type& native_acceptor, asio::error_code& ec)
+ {
+ return this->service.assign(this->implementation,
+ protocol, native_acceptor, ec);
+ }
+
+ /// Determine whether the acceptor is open.
+ bool is_open() const
+ {
+ return this->service.is_open(this->implementation);
+ }
+
+ /// Bind the acceptor to the given local endpoint.
+ /**
+ * This function binds the socket acceptor to the specified endpoint on the
+ * local machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket
+ * acceptor will be bound.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * acceptor.open(asio::ip::tcp::v4());
+ * acceptor.bind(asio::ip::tcp::endpoint(12345));
+ * @endcode
+ */
+ void bind(const endpoint_type& endpoint)
+ {
+ asio::error_code ec;
+ this->service.bind(this->implementation, endpoint, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Bind the acceptor to the given local endpoint.
+ /**
+ * This function binds the socket acceptor to the specified endpoint on the
+ * local machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket
+ * acceptor will be bound.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * acceptor.open(asio::ip::tcp::v4());
+ * asio::error_code ec;
+ * acceptor.bind(asio::ip::tcp::endpoint(12345), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code bind(const endpoint_type& endpoint,
+ asio::error_code& ec)
+ {
+ return this->service.bind(this->implementation, endpoint, ec);
+ }
+
+ /// Place the acceptor into the state where it will listen for new
+ /// connections.
+ /**
+ * This function puts the socket acceptor into the state where it may accept
+ * new connections.
+ *
+ * @param backlog The maximum length of the queue of pending connections.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void listen(int backlog = socket_base::max_connections)
+ {
+ asio::error_code ec;
+ this->service.listen(this->implementation, backlog, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Place the acceptor into the state where it will listen for new
+ /// connections.
+ /**
+ * This function puts the socket acceptor into the state where it may accept
+ * new connections.
+ *
+ * @param backlog The maximum length of the queue of pending connections.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::error_code ec;
+ * acceptor.listen(asio::socket_base::max_connections, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code listen(int backlog, asio::error_code& ec)
+ {
+ return this->service.listen(this->implementation, backlog, ec);
+ }
+
+ /// Close the acceptor.
+ /**
+ * This function is used to close the acceptor. Any asynchronous accept
+ * operations will be cancelled immediately.
+ *
+ * A subsequent call to open() is required before the acceptor can again be
+ * used to again perform socket accept operations.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void close()
+ {
+ asio::error_code ec;
+ this->service.close(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Close the acceptor.
+ /**
+ * This function is used to close the acceptor. Any asynchronous accept
+ * operations will be cancelled immediately.
+ *
+ * A subsequent call to open() is required before the acceptor can again be
+ * used to again perform socket accept operations.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::error_code ec;
+ * acceptor.close(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ asio::error_code close(asio::error_code& ec)
+ {
+ return this->service.close(this->implementation, ec);
+ }
+
+ /// Get the native acceptor representation.
+ /**
+ * This function may be used to obtain the underlying representation of the
+ * acceptor. This is intended to allow access to native acceptor functionality
+ * that is not otherwise provided.
+ */
+ native_type native()
+ {
+ return this->service.native(this->implementation);
+ }
+
+ /// Cancel all asynchronous operations associated with the acceptor.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the asio::error::operation_aborted error.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void cancel()
+ {
+ asio::error_code ec;
+ this->service.cancel(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Cancel all asynchronous operations associated with the acceptor.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code cancel(asio::error_code& ec)
+ {
+ return this->service.cancel(this->implementation, ec);
+ }
+
+ /// Set an option on the acceptor.
+ /**
+ * This function is used to set an option on the acceptor.
+ *
+ * @param option The new option value to be set on the acceptor.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @sa SettableSocketOption @n
+ * asio::socket_base::reuse_address
+ * asio::socket_base::enable_connection_aborted
+ *
+ * @par Example
+ * Setting the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::acceptor::reuse_address option(true);
+ * acceptor.set_option(option);
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ void set_option(const SettableSocketOption& option)
+ {
+ asio::error_code ec;
+ this->service.set_option(this->implementation, option, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Set an option on the acceptor.
+ /**
+ * This function is used to set an option on the acceptor.
+ *
+ * @param option The new option value to be set on the acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa SettableSocketOption @n
+ * asio::socket_base::reuse_address
+ * asio::socket_base::enable_connection_aborted
+ *
+ * @par Example
+ * Setting the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::acceptor::reuse_address option(true);
+ * asio::error_code ec;
+ * acceptor.set_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ asio::error_code set_option(const SettableSocketOption& option,
+ asio::error_code& ec)
+ {
+ return this->service.set_option(this->implementation, option, ec);
+ }
+
+ /// Get an option from the acceptor.
+ /**
+ * This function is used to get the current value of an option on the
+ * acceptor.
+ *
+ * @param option The option value to be obtained from the acceptor.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @sa GettableSocketOption @n
+ * asio::socket_base::reuse_address
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::acceptor::reuse_address option;
+ * acceptor.get_option(option);
+ * bool is_set = option.get();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ void get_option(GettableSocketOption& option)
+ {
+ asio::error_code ec;
+ this->service.get_option(this->implementation, option, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Get an option from the acceptor.
+ /**
+ * This function is used to get the current value of an option on the
+ * acceptor.
+ *
+ * @param option The option value to be obtained from the acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa GettableSocketOption @n
+ * asio::socket_base::reuse_address
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::acceptor::reuse_address option;
+ * asio::error_code ec;
+ * acceptor.get_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * bool is_set = option.get();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ asio::error_code get_option(GettableSocketOption& option,
+ asio::error_code& ec)
+ {
+ return this->service.get_option(this->implementation, option, ec);
+ }
+
+ /// Get the local endpoint of the acceptor.
+ /**
+ * This function is used to obtain the locally bound endpoint of the acceptor.
+ *
+ * @returns An object that represents the local endpoint of the acceptor.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint();
+ * @endcode
+ */
+ endpoint_type local_endpoint() const
+ {
+ asio::error_code ec;
+ endpoint_type ep = this->service.local_endpoint(this->implementation, ec);
+ asio::detail::throw_error(ec);
+ return ep;
+ }
+
+ /// Get the local endpoint of the acceptor.
+ /**
+ * This function is used to obtain the locally bound endpoint of the acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the local endpoint of the acceptor.
+ * Returns a default-constructed endpoint object if an error occurred and the
+ * error handler did not throw an exception.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::error_code ec;
+ * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type local_endpoint(asio::error_code& ec) const
+ {
+ return this->service.local_endpoint(this->implementation, ec);
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket. The function call will block until a new connection has been
+ * accepted successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::socket socket(io_service);
+ * acceptor.accept(socket);
+ * @endcode
+ */
+ template <typename SocketService>
+ void accept(basic_socket<protocol_type, SocketService>& peer)
+ {
+ asio::error_code ec;
+ this->service.accept(this->implementation, peer, 0, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket. The function call will block until a new connection has been
+ * accepted successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::soocket socket(io_service);
+ * asio::error_code ec;
+ * acceptor.accept(socket, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename SocketService>
+ asio::error_code accept(
+ basic_socket<protocol_type, SocketService>& peer,
+ asio::error_code& ec)
+ {
+ return this->service.accept(this->implementation, peer, 0, ec);
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection into a
+ * socket. The function call always returns immediately.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ * Ownership of the peer object is retained by the caller, which must
+ * guarantee that it is valid until the handler is called.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error // Result of operation.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const asio::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::socket socket(io_service);
+ * acceptor.async_accept(socket, accept_handler);
+ * @endcode
+ */
+ template <typename SocketService, typename AcceptHandler>
+ void async_accept(basic_socket<protocol_type, SocketService>& peer,
+ AcceptHandler handler)
+ {
+ this->service.async_accept(this->implementation, peer, 0, handler);
+ }
+
+ /// Accept a new connection and obtain the endpoint of the peer
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket, and additionally provide the endpoint of the remote peer.
+ * The function call will block until a new connection has been accepted
+ * successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @param peer_endpoint An endpoint object which will receive the endpoint of
+ * the remote peer.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::socket socket(io_service);
+ * asio::ip::tcp::endpoint endpoint;
+ * acceptor.accept(socket, endpoint);
+ * @endcode
+ */
+ template <typename SocketService>
+ void accept(basic_socket<protocol_type, SocketService>& peer,
+ endpoint_type& peer_endpoint)
+ {
+ asio::error_code ec;
+ this->service.accept(this->implementation, peer, &peer_endpoint, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Accept a new connection and obtain the endpoint of the peer
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket, and additionally provide the endpoint of the remote peer.
+ * The function call will block until a new connection has been accepted
+ * successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @param peer_endpoint An endpoint object which will receive the endpoint of
+ * the remote peer.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::ip::tcp::socket socket(io_service);
+ * asio::ip::tcp::endpoint endpoint;
+ * asio::error_code ec;
+ * acceptor.accept(socket, endpoint, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename SocketService>
+ asio::error_code accept(
+ basic_socket<protocol_type, SocketService>& peer,
+ endpoint_type& peer_endpoint, asio::error_code& ec)
+ {
+ return this->service.accept(this->implementation, peer, &peer_endpoint, ec);
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection into a
+ * socket, and additionally obtain the endpoint of the remote peer. The
+ * function call always returns immediately.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ * Ownership of the peer object is retained by the caller, which must
+ * guarantee that it is valid until the handler is called.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written. Ownership of the peer_endpoint object is
+ * retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error // Result of operation.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ */
+ template <typename SocketService, typename AcceptHandler>
+ void async_accept(basic_socket<protocol_type, SocketService>& peer,
+ endpoint_type& peer_endpoint, AcceptHandler handler)
+ {
+ this->service.async_accept(this->implementation,
+ peer, &peer_endpoint, handler);
+ }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP
diff --git a/src/libtorrent/asio/basic_socket_iostream.hpp b/src/libtorrent/asio/basic_socket_iostream.hpp
new file mode 100644
index 0000000..1d705ff
--- /dev/null
+++ b/src/libtorrent/asio/basic_socket_iostream.hpp
@@ -0,0 +1,148 @@
+//
+// basic_socket_iostream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_SOCKET_IOSTREAM_HPP
+#define ASIO_BASIC_SOCKET_IOSTREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/preprocessor/arithmetic/inc.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+#include <boost/utility/base_from_member.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_socket_streambuf.hpp"
+#include "asio/stream_socket_service.hpp"
+
+#if !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY)
+#define ASIO_SOCKET_IOSTREAM_MAX_ARITY 5
+#endif // !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY)
+
+// A macro that should expand to:
+// template <typename T1, ..., typename Tn>
+// explicit basic_socket_iostream(T1 x1, ..., Tn xn)
+// : basic_iostream<char>(&this->boost::base_from_member<
+// basic_socket_streambuf<Protocol, StreamSocketService> >::member)
+// {
+// if (rdbuf()->connect(x1, ..., xn) == 0)
+// this->setstate(std::ios_base::failbit);
+// }
+// This macro should only persist within this file.
+
+#define ASIO_PRIVATE_CTR_DEF(z, n, data) \
+ template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
+ explicit basic_socket_iostream(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
+ : std::basic_iostream<char>(&this->boost::base_from_member< \
+ basic_socket_streambuf<Protocol, StreamSocketService> >::member) \
+ { \
+ tie(this); \
+ if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \
+ this->setstate(std::ios_base::failbit); \
+ } \
+ /**/
+
+// A macro that should expand to:
+// template <typename T1, ..., typename Tn>
+// void connect(T1 x1, ..., Tn xn)
+// {
+// if (rdbuf()->connect(x1, ..., xn) == 0)
+// this->setstate(std::ios_base::failbit);
+// }
+// This macro should only persist within this file.
+
+#define ASIO_PRIVATE_CONNECT_DEF(z, n, data) \
+ template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
+ void connect(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
+ { \
+ if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \
+ this->setstate(std::ios_base::failbit); \
+ } \
+ /**/
+
+namespace asio {
+
+/// Iostream interface for a socket.
+template <typename Protocol,
+ typename StreamSocketService = stream_socket_service<Protocol> >
+class basic_socket_iostream
+ : public boost::base_from_member<
+ basic_socket_streambuf<Protocol, StreamSocketService> >,
+ public std::basic_iostream<char>
+{
+public:
+ /// Construct a basic_socket_iostream without establishing a connection.
+ basic_socket_iostream()
+ : std::basic_iostream<char>(&this->boost::base_from_member<
+ basic_socket_streambuf<Protocol, StreamSocketService> >::member)
+ {
+ tie(this);
+ }
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// Establish a connection to an endpoint corresponding to a resolver query.
+ /**
+ * This constructor automatically establishes a connection based on the
+ * supplied resolver query parameters. The arguments are used to construct
+ * a resolver query object.
+ */
+ template <typename T1, ..., typename TN>
+ explicit basic_socket_iostream(T1 t1, ..., TN tn);
+#else
+ BOOST_PP_REPEAT_FROM_TO(
+ 1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY),
+ ASIO_PRIVATE_CTR_DEF, _ )
+#endif
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// Establish a connection to an endpoint corresponding to a resolver query.
+ /**
+ * This function automatically establishes a connection based on the supplied
+ * resolver query parameters. The arguments are used to construct a resolver
+ * query object.
+ */
+ template <typename T1, ..., typename TN>
+ void connect(T1 t1, ..., TN tn);
+#else
+ BOOST_PP_REPEAT_FROM_TO(
+ 1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY),
+ ASIO_PRIVATE_CONNECT_DEF, _ )
+#endif
+
+ /// Close the connection.
+ void close()
+ {
+ if (rdbuf()->close() == 0)
+ this->setstate(std::ios_base::failbit);
+ }
+
+ /// Return a pointer to the underlying streambuf.
+ basic_socket_streambuf<Protocol, StreamSocketService>* rdbuf() const
+ {
+ return const_cast<basic_socket_streambuf<Protocol, StreamSocketService>*>(
+ &this->boost::base_from_member<
+ basic_socket_streambuf<Protocol, StreamSocketService> >::member);
+ }
+};
+
+} // namespace asio
+
+#undef ASIO_PRIVATE_CTR_DEF
+#undef ASIO_PRIVATE_CONNECT_DEF
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP
diff --git a/src/libtorrent/asio/basic_socket_streambuf.hpp b/src/libtorrent/asio/basic_socket_streambuf.hpp
new file mode 100644
index 0000000..0bcd3b7
--- /dev/null
+++ b/src/libtorrent/asio/basic_socket_streambuf.hpp
@@ -0,0 +1,284 @@
+//
+// basic_socket_streambuf.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_SOCKET_STREAMBUF_HPP
+#define ASIO_BASIC_SOCKET_STREAMBUF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <streambuf>
+#include <boost/array.hpp>
+#include <boost/preprocessor/arithmetic/inc.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+#include <boost/utility/base_from_member.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_socket.hpp"
+#include "asio/io_service.hpp"
+#include "asio/stream_socket_service.hpp"
+#include "asio/detail/throw_error.hpp"
+
+#if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
+#define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
+#endif // !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
+
+// A macro that should expand to:
+// template <typename T1, ..., typename Tn>
+// basic_socket_streambuf<Protocol, StreamSocketService>* connect(
+// T1 x1, ..., Tn xn)
+// {
+// init_buffers();
+// asio::error_code ec;
+// this->basic_socket<Protocol, StreamSocketService>::close(ec);
+// typedef typename Protocol::resolver_query resolver_query;
+// resolver_query query(x1, ..., xn);
+// resolve_and_connect(query, ec);
+// return !ec ? this : 0;
+// }
+// This macro should only persist within this file.
+
+#define ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \
+ template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
+ basic_socket_streambuf<Protocol, StreamSocketService>* connect( \
+ BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
+ { \
+ init_buffers(); \
+ asio::error_code ec; \
+ this->basic_socket<Protocol, StreamSocketService>::close(ec); \
+ typedef typename Protocol::resolver_query resolver_query; \
+ resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \
+ resolve_and_connect(query, ec); \
+ return !ec ? this : 0; \
+ } \
+ /**/
+
+namespace asio {
+
+/// Iostream streambuf for a socket.
+template <typename Protocol,
+ typename StreamSocketService = stream_socket_service<Protocol> >
+class basic_socket_streambuf
+ : public std::streambuf,
+ private boost::base_from_member<io_service>,
+ public basic_socket<Protocol, StreamSocketService>
+{
+public:
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct a basic_socket_streambuf without establishing a connection.
+ basic_socket_streambuf()
+ : basic_socket<Protocol, StreamSocketService>(
+ boost::base_from_member<asio::io_service>::member),
+ unbuffered_(false)
+ {
+ init_buffers();
+ }
+
+ /// Destructor flushes buffered data.
+ virtual ~basic_socket_streambuf()
+ {
+ if (pptr() != pbase())
+ overflow(traits_type::eof());
+ }
+
+ /// Establish a connection.
+ /**
+ * This function establishes a connection to the specified endpoint.
+ *
+ * @return \c this if a connection was successfully established, a null
+ * pointer otherwise.
+ */
+ basic_socket_streambuf<Protocol, StreamSocketService>* connect(
+ const endpoint_type& endpoint)
+ {
+ init_buffers();
+ asio::error_code ec;
+ this->basic_socket<Protocol, StreamSocketService>::close(ec);
+ this->basic_socket<Protocol, StreamSocketService>::connect(endpoint, ec);
+ return !ec ? this : 0;
+ }
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// Establish a connection.
+ /**
+ * This function automatically establishes a connection based on the supplied
+ * resolver query parameters. The arguments are used to construct a resolver
+ * query object.
+ *
+ * @return \c this if a connection was successfully established, a null
+ * pointer otherwise.
+ */
+ template <typename T1, ..., typename TN>
+ basic_socket_streambuf<Protocol, StreamSocketService>* connect(
+ T1 t1, ..., TN tn);
+#else
+ BOOST_PP_REPEAT_FROM_TO(
+ 1, BOOST_PP_INC(ASIO_SOCKET_STREAMBUF_MAX_ARITY),
+ ASIO_PRIVATE_CONNECT_DEF, _ )
+#endif
+
+ /// Close the connection.
+ /**
+ * @return \c this if a connection was successfully established, a null
+ * pointer otherwise.
+ */
+ basic_socket_streambuf<Protocol, StreamSocketService>* close()
+ {
+ asio::error_code ec;
+ sync();
+ this->basic_socket<Protocol, StreamSocketService>::close(ec);
+ if (!ec)
+ init_buffers();
+ return !ec ? this : 0;
+ }
+
+protected:
+ int_type underflow()
+ {
+ if (gptr() == egptr())
+ {
+ asio::error_code ec;
+ std::size_t bytes_transferred = this->service.receive(
+ this->implementation,
+ asio::buffer(asio::buffer(get_buffer_) + putback_max),
+ 0, ec);
+ if (ec)
+ return traits_type::eof();
+ setg(get_buffer_.begin(), get_buffer_.begin() + putback_max,
+ get_buffer_.begin() + putback_max + bytes_transferred);
+ return traits_type::to_int_type(*gptr());
+ }
+ else
+ {
+ return traits_type::eof();
+ }
+ }
+
+ int_type overflow(int_type c)
+ {
+ if (unbuffered_)
+ {
+ if (traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ // Nothing to do.
+ return traits_type::not_eof(c);
+ }
+ else
+ {
+ // Send the single character immediately.
+ asio::error_code ec;
+ char_type ch = traits_type::to_char_type(c);
+ this->service.send(this->implementation,
+ asio::buffer(&ch, sizeof(char_type)), 0, ec);
+ if (ec)
+ return traits_type::eof();
+ return c;
+ }
+ }
+ else
+ {
+ // Send all data in the output buffer.
+ asio::const_buffer buffer =
+ asio::buffer(pbase(), pptr() - pbase());
+ while (asio::buffer_size(buffer) > 0)
+ {
+ asio::error_code ec;
+ std::size_t bytes_transferred = this->service.send(
+ this->implementation, asio::buffer(buffer),
+ 0, ec);
+ if (ec)
+ return traits_type::eof();
+ buffer = buffer + bytes_transferred;
+ }
+ setp(put_buffer_.begin(), put_buffer_.end());
+
+ // If the new character is eof then our work here is done.
+ if (traits_type::eq_int_type(c, traits_type::eof()))
+ return traits_type::not_eof(c);
+
+ // Add the new character to the output buffer.
+ *pptr() = traits_type::to_char_type(c);
+ pbump(1);
+ return c;
+ }
+ }
+
+ int sync()
+ {
+ return overflow(traits_type::eof());
+ }
+
+ std::streambuf* setbuf(char_type* s, std::streamsize n)
+ {
+ if (pptr() == pbase() && s == 0 && n == 0)
+ {
+ unbuffered_ = true;
+ setp(0, 0);
+ return this;
+ }
+
+ return 0;
+ }
+
+private:
+ void init_buffers()
+ {
+ setg(get_buffer_.begin(),
+ get_buffer_.begin() + putback_max,
+ get_buffer_.begin() + putback_max);
+ if (unbuffered_)
+ setp(0, 0);
+ else
+ setp(put_buffer_.begin(), put_buffer_.end());
+ }
+
+ void resolve_and_connect(const typename Protocol::resolver_query& query,
+ asio::error_code& ec)
+ {
+ typedef typename Protocol::resolver resolver_type;
+ typedef typename Protocol::resolver_iterator iterator_type;
+ resolver_type resolver(
+ boost::base_from_member<asio::io_service>::member);
+ iterator_type i = resolver.resolve(query, ec);
+ if (!ec)
+ {
+ iterator_type end;
+ ec = asio::error::host_not_found;
+ while (ec && i != end)
+ {
+ this->basic_socket<Protocol, StreamSocketService>::close();
+ this->basic_socket<Protocol, StreamSocketService>::connect(*i, ec);
+ ++i;
+ }
+ }
+ }
+
+ enum { putback_max = 8 };
+ enum { buffer_size = 512 };
+ boost::array<char, buffer_size> get_buffer_;
+ boost::array<char, buffer_size> put_buffer_;
+ bool unbuffered_;
+};
+
+} // namespace asio
+
+#undef ASIO_PRIVATE_CONNECT_DEF
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP
diff --git a/src/libtorrent/asio/basic_stream_socket.hpp b/src/libtorrent/asio/basic_stream_socket.hpp
new file mode 100644
index 0000000..c1e0ef0
--- /dev/null
+++ b/src/libtorrent/asio/basic_stream_socket.hpp
@@ -0,0 +1,718 @@
+//
+// basic_stream_socket.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_STREAM_SOCKET_HPP
+#define ASIO_BASIC_STREAM_SOCKET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_socket.hpp"
+#include "asio/error.hpp"
+#include "asio/stream_socket_service.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+/// Provides stream-oriented socket functionality.
+/**
+ * The basic_stream_socket class template provides asynchronous and blocking
+ * stream-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Protocol,
+ typename StreamSocketService = stream_socket_service<Protocol> >
+class basic_stream_socket
+ : public basic_socket<Protocol, StreamSocketService>
+{
+public:
+ /// The native representation of a socket.
+ typedef typename StreamSocketService::native_type native_type;
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct a basic_stream_socket without opening it.
+ /**
+ * This constructor creates a stream socket without opening it. The socket
+ * needs to be opened and then connected or accepted before data can be sent
+ * or received on it.
+ *
+ * @param io_service The io_service object that the stream socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ */
+ explicit basic_stream_socket(asio::io_service& io_service)
+ : basic_socket<Protocol, StreamSocketService>(io_service)
+ {
+ }
+
+ /// Construct and open a basic_stream_socket.
+ /**
+ * This constructor creates and opens a stream socket. The socket needs to be
+ * connected or accepted before data can be sent or received on it.
+ *
+ * @param io_service The io_service object that the stream socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_stream_socket(asio::io_service& io_service,
+ const protocol_type& protocol)
+ : basic_socket<Protocol, StreamSocketService>(io_service, protocol)
+ {
+ }
+
+ /// Construct a basic_stream_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a stream socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param io_service The io_service object that the stream socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the stream
+ * socket will be bound.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_stream_socket(asio::io_service& io_service,
+ const endpoint_type& endpoint)
+ : basic_socket<Protocol, StreamSocketService>(io_service, endpoint)
+ {
+ }
+
+ /// Construct a basic_stream_socket on an existing native socket.
+ /**
+ * This constructor creates a stream socket object to hold an existing native
+ * socket.
+ *
+ * @param io_service The io_service object that the stream socket will use to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ basic_stream_socket(asio::io_service& io_service,
+ const protocol_type& protocol, const native_type& native_socket)
+ : basic_socket<Protocol, StreamSocketService>(
+ io_service, protocol, native_socket)
+ {
+ }
+
+ /// Send some data on the socket.
+ /**
+ * This function is used to send data on the stream socket. The function
+ * call will block until one or more bytes of the data has been sent
+ * successfully, or an until error occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref write function if you need to ensure that all data
+ * is written before the blocking operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.send(asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.send(
+ this->implementation, buffers, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Send some data on the socket.
+ /**
+ * This function is used to send data on the stream socket. The function
+ * call will block until one or more bytes of the data has been sent
+ * successfully, or an until error occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref write function if you need to ensure that all data
+ * is written before the blocking operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.send(asio::buffer(data, size), 0);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.send(
+ this->implementation, buffers, flags, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Send some data on the socket.
+ /**
+ * This function is used to send data on the stream socket. The function
+ * call will block until one or more bytes of the data has been sent
+ * successfully, or an until error occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent. Returns 0 if an error occurred.
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref write function if you need to ensure that all data
+ * is written before the blocking operation completes.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return this->service.send(this->implementation, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send data on the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref async_write function if you need to ensure that all
+ * data is written before the asynchronous operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send(const ConstBufferSequence& buffers, WriteHandler handler)
+ {
+ this->service.async_send(this->implementation, buffers, 0, handler);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send data on the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref async_write function if you need to ensure that all
+ * data is written before the asynchronous operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(asio::buffer(data, size), 0, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, WriteHandler handler)
+ {
+ this->service.async_send(this->implementation, buffers, flags, handler);
+ }
+
+ /// Receive some data on the socket.
+ /**
+ * This function is used to receive data on the stream socket. The function
+ * call will block until one or more bytes of data has been received
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws asio::system_error Thrown on failure. An error code of
+ * asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.receive(asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Receive some data on the socket.
+ /**
+ * This function is used to receive data on the stream socket. The function
+ * call will block until one or more bytes of data has been received
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws asio::system_error Thrown on failure. An error code of
+ * asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.receive(asio::buffer(data, size), 0);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.receive(
+ this->implementation, buffers, flags, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the stream socket. The function
+ * call will block until one or more bytes of data has been received
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received. Returns 0 if an error occurred.
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return this->service.receive(this->implementation, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive data from the stream
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref async_read function if you need to ensure
+ * that the requested amount of data is received before the asynchronous
+ * operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive(const MutableBufferSequence& buffers, ReadHandler handler)
+ {
+ this->service.async_receive(this->implementation, buffers, 0, handler);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive data from the stream
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref async_read function if you need to ensure
+ * that the requested amount of data is received before the asynchronous
+ * operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(asio::buffer(data, size), 0, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, ReadHandler handler)
+ {
+ this->service.async_receive(this->implementation, buffers, flags, handler);
+ }
+
+ /// Write some data to the socket.
+ /**
+ * This function is used to write data to the stream socket. The function call
+ * will block until one or more bytes of the data has been written
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more data buffers to be written to the socket.
+ *
+ * @returns The number of bytes written.
+ *
+ * @throws asio::system_error Thrown on failure. An error code of
+ * asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The write_some operation may not transmit all of the data to the
+ * peer. Consider using the @ref write function if you need to ensure that
+ * all data is written before the blocking operation completes.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.write_some(asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Write some data to the socket.
+ /**
+ * This function is used to write data to the stream socket. The function call
+ * will block until one or more bytes of the data has been written
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more data buffers to be written to the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. Returns 0 if an error occurred.
+ *
+ * @note The write_some operation may not transmit all of the data to the
+ * peer. Consider using the @ref write function if you need to ensure that
+ * all data is written before the blocking operation completes.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return this->service.send(this->implementation, buffers, 0, ec);
+ }
+
+ /// Start an asynchronous write.
+ /**
+ * This function is used to asynchronously write data to the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be written to the socket.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes written.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The write operation may not transmit all of the data to the peer.
+ * Consider using the @ref async_write function if you need to ensure that all
+ * data is written before the asynchronous operation completes.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_write_some(asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_write_some(const ConstBufferSequence& buffers,
+ WriteHandler handler)
+ {
+ this->service.async_send(this->implementation, buffers, 0, handler);
+ }
+
+ /// Read some data from the socket.
+ /**
+ * This function is used to read data from the stream socket. The function
+ * call will block until one or more bytes of data has been read successfully,
+ * or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be read.
+ *
+ * @returns The number of bytes read.
+ *
+ * @throws asio::system_error Thrown on failure. An error code of
+ * asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The read_some operation may not read all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that
+ * the requested amount of data is read before the blocking operation
+ * completes.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.read_some(asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Read some data from the socket.
+ /**
+ * This function is used to read data from the stream socket. The function
+ * call will block until one or more bytes of data has been read successfully,
+ * or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. Returns 0 if an error occurred.
+ *
+ * @note The read_some operation may not read all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that
+ * the requested amount of data is read before the blocking operation
+ * completes.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return this->service.receive(this->implementation, buffers, 0, ec);
+ }
+
+ /// Start an asynchronous read.
+ /**
+ * This function is used to asynchronously read data from the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes read.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note The read operation may not read all of the requested number of bytes.
+ * Consider using the @ref async_read function if you need to ensure that the
+ * requested amount of data is read before the asynchronous operation
+ * completes.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_read_some(asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_read_some(const MutableBufferSequence& buffers,
+ ReadHandler handler)
+ {
+ this->service.async_receive(this->implementation, buffers, 0, handler);
+ }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_STREAM_SOCKET_HPP
diff --git a/src/libtorrent/asio/basic_streambuf.hpp b/src/libtorrent/asio/basic_streambuf.hpp
new file mode 100644
index 0000000..41649cc
--- /dev/null
+++ b/src/libtorrent/asio/basic_streambuf.hpp
@@ -0,0 +1,198 @@
+//
+// basic_streambuf.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BASIC_STREAMBUF_HPP
+#define ASIO_BASIC_STREAMBUF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <stdexcept>
+#include <streambuf>
+#include <vector>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+
+/// Automatically resizable buffer class based on std::streambuf.
+template <typename Allocator = std::allocator<char> >
+class basic_streambuf
+ : public std::streambuf,
+ private noncopyable
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The type used to represent the get area as a list of buffers.
+ typedef implementation_defined const_buffers_type;
+
+ /// The type used to represent the put area as a list of buffers.
+ typedef implementation_defined mutable_buffers_type;
+#else
+ typedef asio::const_buffers_1 const_buffers_type;
+ typedef asio::mutable_buffers_1 mutable_buffers_type;
+#endif
+
+ /// Construct a buffer with a specified maximum size.
+ explicit basic_streambuf(
+ std::size_t max_size = (std::numeric_limits<std::size_t>::max)(),
+ const Allocator& allocator = Allocator())
+ : max_size_(max_size),
+ buffer_(allocator)
+ {
+ std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);
+ buffer_.resize((std::max<std::size_t>)(pend, 1));
+ setg(&buffer_[0], &buffer_[0], &buffer_[0]);
+ setp(&buffer_[0], &buffer_[0] + pend);
+ }
+
+ /// Return the size of the get area in characters.
+ std::size_t size() const
+ {
+ return pptr() - gptr();
+ }
+
+ /// Return the maximum size of the buffer.
+ std::size_t max_size() const
+ {
+ return max_size_;
+ }
+
+ /// Get a list of buffers that represents the get area.
+ const_buffers_type data() const
+ {
+ return asio::buffer(asio::const_buffer(gptr(),
+ (pptr() - gptr()) * sizeof(char_type)));
+ }
+
+ /// Get a list of buffers that represents the put area, with the given size.
+ mutable_buffers_type prepare(std::size_t size)
+ {
+ reserve(size);
+ return asio::buffer(asio::mutable_buffer(
+ pptr(), size * sizeof(char_type)));
+ }
+
+ /// Move the start of the put area by the specified number of characters.
+ void commit(std::size_t n)
+ {
+ if (pptr() + n > epptr())
+ n = epptr() - pptr();
+ pbump(static_cast<int>(n));
+ }
+
+ /// Move the start of the get area by the specified number of characters.
+ void consume(std::size_t n)
+ {
+ if (gptr() + n > pptr())
+ n = pptr() - gptr();
+ gbump(static_cast<int>(n));
+ }
+
+protected:
+ enum { buffer_delta = 128 };
+
+ int_type underflow()
+ {
+ if (gptr() < pptr())
+ {
+ setg(&buffer_[0], gptr(), pptr());
+ return traits_type::to_int_type(*gptr());
+ }
+ else
+ {
+ return traits_type::eof();
+ }
+ }
+
+ int_type overflow(int_type c)
+ {
+ if (!traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ if (pptr() == epptr())
+ {
+ std::size_t buffer_size = pptr() - gptr();
+ if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)
+ {
+ reserve(max_size_ - buffer_size);
+ }
+ else
+ {
+ reserve(buffer_delta);
+ }
+ }
+
+ *pptr() = traits_type::to_char_type(c);
+ pbump(1);
+ return c;
+ }
+
+ return traits_type::not_eof(c);
+ }
+
+ void reserve(std::size_t n)
+ {
+ // Get current stream positions as offsets.
+ std::size_t gnext = gptr() - &buffer_[0];
+ std::size_t gend = egptr() - &buffer_[0];
+ std::size_t pnext = pptr() - &buffer_[0];
+ std::size_t pend = epptr() - &buffer_[0];
+
+ // Check if there is already enough space in the put area.
+ if (n <= pend - pnext)
+ {
+ return;
+ }
+
+ // Shift existing contents of get area to start of buffer.
+ if (gnext > 0)
+ {
+ std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend);
+ gend -= gnext;
+ pnext -= gnext;
+ }
+
+ // Ensure buffer is large enough to hold at least the specified size.
+ if (n > pend - pnext)
+ {
+ if (n <= max_size_ && pnext <= max_size_ - n)
+ {
+ buffer_.resize((std::max<std::size_t>)(pnext + n, 1));
+ }
+ else
+ {
+ throw std::length_error("asio::streambuf too long");
+ }
+ }
+
+ // Update stream positions.
+ setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend);
+ setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n);
+ }
+
+private:
+ std::size_t max_size_;
+ std::vector<char_type, Allocator> buffer_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BASIC_STREAMBUF_HPP
diff --git a/src/libtorrent/asio/buffer.hpp b/src/libtorrent/asio/buffer.hpp
new file mode 100644
index 0000000..72aa7fe
--- /dev/null
+++ b/src/libtorrent/asio/buffer.hpp
@@ -0,0 +1,830 @@
+//
+// buffer.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BUFFER_HPP
+#define ASIO_BUFFER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/array.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <string>
+#include <vector>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_MSVC)
+# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
+# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# define ASIO_ENABLE_BUFFER_DEBUGGING
+# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# endif // defined(_HAS_ITERATOR_DEBUGGING)
+#endif // defined(BOOST_MSVC)
+
+#if defined(__GNUC__)
+# if defined(_GLIBCXX_DEBUG)
+# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# define ASIO_ENABLE_BUFFER_DEBUGGING
+# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# endif // defined(_GLIBCXX_DEBUG)
+#endif // defined(__GNUC__)
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+# include "asio/detail/push_options.hpp"
+# include <boost/function.hpp>
+# include "asio/detail/pop_options.hpp"
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+namespace asio {
+
+class mutable_buffer;
+class const_buffer;
+
+namespace detail {
+void* buffer_cast_helper(const mutable_buffer&);
+const void* buffer_cast_helper(const const_buffer&);
+std::size_t buffer_size_helper(const mutable_buffer&);
+std::size_t buffer_size_helper(const const_buffer&);
+} // namespace detail
+
+/// Holds a buffer that can be modified.
+/**
+ * The mutable_buffer class provides a safe representation of a buffer that can
+ * be modified. It does not own the underlying data, and so is cheap to copy or
+ * assign.
+ */
+class mutable_buffer
+{
+public:
+ /// Construct an empty buffer.
+ mutable_buffer()
+ : data_(0),
+ size_(0)
+ {
+ }
+
+ /// Construct a buffer to represent a given memory range.
+ mutable_buffer(void* data, std::size_t size)
+ : data_(data),
+ size_(size)
+ {
+ }
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ mutable_buffer(void* data, std::size_t size,
+ boost::function<void()> debug_check)
+ : data_(data),
+ size_(size),
+ debug_check_(debug_check)
+ {
+ }
+
+ const boost::function<void()>& get_debug_check() const
+ {
+ return debug_check_;
+ }
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+private:
+ friend void* asio::detail::buffer_cast_helper(
+ const mutable_buffer& b);
+ friend std::size_t asio::detail::buffer_size_helper(
+ const mutable_buffer& b);
+
+ void* data_;
+ std::size_t size_;
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ boost::function<void()> debug_check_;
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+};
+
+namespace detail {
+
+inline void* buffer_cast_helper(const mutable_buffer& b)
+{
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ if (b.size_ && b.debug_check_)
+ b.debug_check_();
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ return b.data_;
+}
+
+inline std::size_t buffer_size_helper(const mutable_buffer& b)
+{
+ return b.size_;
+}
+
+} // namespace detail
+
+/// Cast a non-modifiable buffer to a specified pointer to POD type.
+/**
+ * @relates mutable_buffer
+ */
+template <typename PointerToPodType>
+inline PointerToPodType buffer_cast(const mutable_buffer& b)
+{
+ return static_cast<PointerToPodType>(detail::buffer_cast_helper(b));
+}
+
+/// Get the number of bytes in a non-modifiable buffer.
+/**
+ * @relates mutable_buffer
+ */
+inline std::size_t buffer_size(const mutable_buffer& b)
+{
+ return detail::buffer_size_helper(b);
+}
+
+/// Create a new modifiable buffer that is offset from the start of another.
+/**
+ * @relates mutable_buffer
+ */
+inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start)
+{
+ if (start > buffer_size(b))
+ return mutable_buffer();
+ char* new_data = buffer_cast<char*>(b) + start;
+ std::size_t new_size = buffer_size(b) - start;
+ return mutable_buffer(new_data, new_size
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ );
+}
+
+/// Create a new modifiable buffer that is offset from the start of another.
+/**
+ * @relates mutable_buffer
+ */
+inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b)
+{
+ if (start > buffer_size(b))
+ return mutable_buffer();
+ char* new_data = buffer_cast<char*>(b) + start;
+ std::size_t new_size = buffer_size(b) - start;
+ return mutable_buffer(new_data, new_size
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ );
+}
+
+/// Adapts a single modifiable buffer so that it meets the requirements of the
+/// MutableBufferSequence concept.
+class mutable_buffers_1
+ : public mutable_buffer
+{
+public:
+ /// The type for each element in the list of buffers.
+ typedef mutable_buffer value_type;
+
+ /// A random-access iterator type that may be used to read elements.
+ typedef const mutable_buffer* const_iterator;
+
+ /// Construct to represent a single modifiable buffer.
+ explicit mutable_buffers_1(const mutable_buffer& b)
+ : mutable_buffer(b)
+ {
+ }
+
+ /// Get a random-access iterator to the first element.
+ const_iterator begin() const
+ {
+ return this;
+ }
+
+ /// Get a random-access iterator for one past the last element.
+ const_iterator end() const
+ {
+ return begin() + 1;
+ }
+};
+
+/// Holds a buffer that cannot be modified.
+/**
+ * The const_buffer class provides a safe representation of a buffer that cannot
+ * be modified. It does not own the underlying data, and so is cheap to copy or
+ * assign.
+ */
+class const_buffer
+{
+public:
+ /// Construct an empty buffer.
+ const_buffer()
+ : data_(0),
+ size_(0)
+ {
+ }
+
+ /// Construct a buffer to represent a given memory range.
+ const_buffer(const void* data, std::size_t size)
+ : data_(data),
+ size_(size)
+ {
+ }
+
+ /// Construct a non-modifiable buffer from a modifiable one.
+ const_buffer(const mutable_buffer& b)
+ : data_(asio::detail::buffer_cast_helper(b)),
+ size_(asio::detail::buffer_size_helper(b))
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , debug_check_(b.get_debug_check())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ {
+ }
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ const_buffer(const void* data, std::size_t size,
+ boost::function<void()> debug_check)
+ : data_(data),
+ size_(size),
+ debug_check_(debug_check)
+ {
+ }
+
+ const boost::function<void()>& get_debug_check() const
+ {
+ return debug_check_;
+ }
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+private:
+ friend const void* asio::detail::buffer_cast_helper(
+ const const_buffer& b);
+ friend std::size_t asio::detail::buffer_size_helper(
+ const const_buffer& b);
+
+ const void* data_;
+ std::size_t size_;
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ boost::function<void()> debug_check_;
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+};
+
+namespace detail {
+
+inline const void* buffer_cast_helper(const const_buffer& b)
+{
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ if (b.size_ && b.debug_check_)
+ b.debug_check_();
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ return b.data_;
+}
+
+inline std::size_t buffer_size_helper(const const_buffer& b)
+{
+ return b.size_;
+}
+
+} // namespace detail
+
+/// Cast a non-modifiable buffer to a specified pointer to POD type.
+/**
+ * @relates const_buffer
+ */
+template <typename PointerToPodType>
+inline PointerToPodType buffer_cast(const const_buffer& b)
+{
+ return static_cast<PointerToPodType>(detail::buffer_cast_helper(b));
+}
+
+/// Get the number of bytes in a non-modifiable buffer.
+/**
+ * @relates const_buffer
+ */
+inline std::size_t buffer_size(const const_buffer& b)
+{
+ return detail::buffer_size_helper(b);
+}
+
+/// Create a new non-modifiable buffer that is offset from the start of another.
+/**
+ * @relates const_buffer
+ */
+inline const_buffer operator+(const const_buffer& b, std::size_t start)
+{
+ if (start > buffer_size(b))
+ return const_buffer();
+ const char* new_data = buffer_cast<const char*>(b) + start;
+ std::size_t new_size = buffer_size(b) - start;
+ return const_buffer(new_data, new_size
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ );
+}
+
+/// Create a new non-modifiable buffer that is offset from the start of another.
+/**
+ * @relates const_buffer
+ */
+inline const_buffer operator+(std::size_t start, const const_buffer& b)
+{
+ if (start > buffer_size(b))
+ return const_buffer();
+ const char* new_data = buffer_cast<const char*>(b) + start;
+ std::size_t new_size = buffer_size(b) - start;
+ return const_buffer(new_data, new_size
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ );
+}
+
+/// Adapts a single non-modifiable buffer so that it meets the requirements of
+/// the ConstBufferSequence concept.
+class const_buffers_1
+ : public const_buffer
+{
+public:
+ /// The type for each element in the list of buffers.
+ typedef const_buffer value_type;
+
+ /// A random-access iterator type that may be used to read elements.
+ typedef const const_buffer* const_iterator;
+
+ /// Construct to represent a single non-modifiable buffer.
+ explicit const_buffers_1(const const_buffer& b)
+ : const_buffer(b)
+ {
+ }
+
+ /// Get a random-access iterator to the first element.
+ const_iterator begin() const
+ {
+ return this;
+ }
+
+ /// Get a random-access iterator for one past the last element.
+ const_iterator end() const
+ {
+ return begin() + 1;
+ }
+};
+
+/// An implementation of both the ConstBufferSequence and MutableBufferSequence
+/// concepts to represent a null buffer sequence.
+class null_buffers
+{
+public:
+ /// The type for each element in the list of buffers.
+ typedef mutable_buffer value_type;
+
+ /// A random-access iterator type that may be used to read elements.
+ typedef const mutable_buffer* const_iterator;
+
+ /// Get a random-access iterator to the first element.
+ const_iterator begin() const
+ {
+ return &buf_;
+ }
+
+ /// Get a random-access iterator for one past the last element.
+ const_iterator end() const
+ {
+ return &buf_;
+ }
+
+private:
+ mutable_buffer buf_;
+};
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+namespace detail {
+
+template <typename Iterator>
+class buffer_debug_check
+{
+public:
+ buffer_debug_check(Iterator iter)
+ : iter_(iter)
+ {
+ }
+
+ ~buffer_debug_check()
+ {
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
+ // MSVC's string iterator checking may crash in a std::string::iterator
+ // object's destructor when the iterator points to an already-destroyed
+ // std::string object, unless the iterator is cleared first.
+ iter_ = Iterator();
+#endif // BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
+ }
+
+ void operator()()
+ {
+ *iter_;
+ }
+
+private:
+ Iterator iter_;
+};
+
+} // namespace detail
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+
+/** @defgroup buffer asio::buffer
+ *
+ * @brief The asio::buffer function is used to create a buffer object to
+ * represent raw memory, an array of POD elements, or a vector of POD elements.
+ *
+ * The simplest use case involves reading or writing a single buffer of a
+ * specified size:
+ *
+ * @code sock.write(asio::buffer(data, size)); @endcode
+ *
+ * In the above example, the return value of asio::buffer meets the
+ * requirements of the ConstBufferSequence concept so that it may be directly
+ * passed to the socket's write function. A buffer created for modifiable
+ * memory also meets the requirements of the MutableBufferSequence concept.
+ *
+ * An individual buffer may be created from a builtin array, std::vector or
+ * boost::array of POD elements. This helps prevent buffer overruns by
+ * automatically determining the size of the buffer:
+ *
+ * @code char d1[128];
+ * size_t bytes_transferred = sock.read(asio::buffer(d1));
+ *
+ * std::vector<char> d2(128);
+ * bytes_transferred = sock.read(asio::buffer(d2));
+ *
+ * boost::array<char, 128> d3;
+ * bytes_transferred = sock.read(asio::buffer(d3)); @endcode
+ *
+ * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple
+ * buffer objects may be assigned into a container that supports the
+ * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts:
+ *
+ * @code
+ * char d1[128];
+ * std::vector<char> d2(128);
+ * boost::array<char, 128> d3;
+ *
+ * boost::array<mutable_buffer, 3> bufs1 = {
+ * asio::buffer(d1),
+ * asio::buffer(d2),
+ * asio::buffer(d3) };
+ * bytes_transferred = sock.read(bufs1);
+ *
+ * std::vector<const_buffer> bufs2;
+ * bufs2.push_back(asio::buffer(d1));
+ * bufs2.push_back(asio::buffer(d2));
+ * bufs2.push_back(asio::buffer(d3));
+ * bytes_transferred = sock.write(bufs2); @endcode
+ */
+/*@{*/
+
+/// Create a new modifiable buffer from an existing buffer.
+inline mutable_buffers_1 buffer(const mutable_buffer& b)
+{
+ return mutable_buffers_1(b);
+}
+
+/// Create a new modifiable buffer from an existing buffer.
+inline mutable_buffers_1 buffer(const mutable_buffer& b,
+ std::size_t max_size_in_bytes)
+{
+ return mutable_buffers_1(
+ mutable_buffer(buffer_cast<void*>(b),
+ buffer_size(b) < max_size_in_bytes
+ ? buffer_size(b) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/// Create a new non-modifiable buffer from an existing buffer.
+inline const_buffers_1 buffer(const const_buffer& b)
+{
+ return const_buffers_1(b);
+}
+
+/// Create a new non-modifiable buffer from an existing buffer.
+inline const_buffers_1 buffer(const const_buffer& b,
+ std::size_t max_size_in_bytes)
+{
+ return const_buffers_1(
+ const_buffer(buffer_cast<const void*>(b),
+ buffer_size(b) < max_size_in_bytes
+ ? buffer_size(b) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , b.get_debug_check()
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/// Create a new modifiable buffer that represents the given memory range.
+inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes)
+{
+ return mutable_buffers_1(mutable_buffer(data, size_in_bytes));
+}
+
+/// Create a new non-modifiable buffer that represents the given memory range.
+inline const_buffers_1 buffer(const void* data,
+ std::size_t size_in_bytes)
+{
+ return const_buffers_1(const_buffer(data, size_in_bytes));
+}
+
+/// Create a new modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline mutable_buffers_1 buffer(PodType (&data)[N])
+{
+ return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType)));
+}
+
+/// Create a new modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline mutable_buffers_1 buffer(PodType (&data)[N],
+ std::size_t max_size_in_bytes)
+{
+ return mutable_buffers_1(
+ mutable_buffer(data,
+ N * sizeof(PodType) < max_size_in_bytes
+ ? N * sizeof(PodType) : max_size_in_bytes));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline const_buffers_1 buffer(const PodType (&data)[N])
+{
+ return const_buffers_1(const_buffer(data, N * sizeof(PodType)));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline const_buffers_1 buffer(const PodType (&data)[N],
+ std::size_t max_size_in_bytes)
+{
+ return const_buffers_1(
+ const_buffer(data,
+ N * sizeof(PodType) < max_size_in_bytes
+ ? N * sizeof(PodType) : max_size_in_bytes));
+}
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \
+ || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+
+// Borland C++ and Sun Studio think the overloads:
+//
+// unspecified buffer(boost::array<PodType, N>& array ...);
+//
+// and
+//
+// unspecified buffer(boost::array<const PodType, N>& array ...);
+//
+// are ambiguous. This will be worked around by using a buffer_types traits
+// class that contains typedefs for the appropriate buffer and container
+// classes, based on whether PodType is const or non-const.
+
+namespace detail {
+
+template <bool IsConst>
+struct buffer_types_base;
+
+template <>
+struct buffer_types_base<false>
+{
+ typedef mutable_buffer buffer_type;
+ typedef mutable_buffers_1 container_type;
+};
+
+template <>
+struct buffer_types_base<true>
+{
+ typedef const_buffer buffer_type;
+ typedef const_buffers_1 container_type;
+};
+
+template <typename PodType>
+struct buffer_types
+ : public buffer_types_base<boost::is_const<PodType>::value>
+{
+};
+
+} // namespace detail
+
+template <typename PodType, std::size_t N>
+inline typename detail::buffer_types<PodType>::container_type
+buffer(boost::array<PodType, N>& data)
+{
+ typedef typename asio::detail::buffer_types<PodType>::buffer_type
+ buffer_type;
+ typedef typename asio::detail::buffer_types<PodType>::container_type
+ container_type;
+ return container_type(
+ buffer_type(data.c_array(), data.size() * sizeof(PodType)));
+}
+
+template <typename PodType, std::size_t N>
+inline typename detail::buffer_types<PodType>::container_type
+buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes)
+{
+ typedef typename asio::detail::buffer_types<PodType>::buffer_type
+ buffer_type;
+ typedef typename asio::detail::buffer_types<PodType>::container_type
+ container_type;
+ return container_type(
+ buffer_type(data.c_array(),
+ data.size() * sizeof(PodType) < max_size_in_bytes
+ ? data.size() * sizeof(PodType) : max_size_in_bytes));
+}
+
+#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+
+/// Create a new modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline mutable_buffers_1 buffer(boost::array<PodType, N>& data)
+{
+ return mutable_buffers_1(
+ mutable_buffer(data.c_array(), data.size() * sizeof(PodType)));
+}
+
+/// Create a new modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline mutable_buffers_1 buffer(boost::array<PodType, N>& data,
+ std::size_t max_size_in_bytes)
+{
+ return mutable_buffers_1(
+ mutable_buffer(data.c_array(),
+ data.size() * sizeof(PodType) < max_size_in_bytes
+ ? data.size() * sizeof(PodType) : max_size_in_bytes));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline const_buffers_1 buffer(boost::array<const PodType, N>& data)
+{
+ return const_buffers_1(
+ const_buffer(data.data(), data.size() * sizeof(PodType)));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline const_buffers_1 buffer(boost::array<const PodType, N>& data,
+ std::size_t max_size_in_bytes)
+{
+ return const_buffers_1(
+ const_buffer(data.data(),
+ data.size() * sizeof(PodType) < max_size_in_bytes
+ ? data.size() * sizeof(PodType) : max_size_in_bytes));
+}
+
+#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline const_buffers_1 buffer(const boost::array<PodType, N>& data)
+{
+ return const_buffers_1(
+ const_buffer(data.data(), data.size() * sizeof(PodType)));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD array.
+template <typename PodType, std::size_t N>
+inline const_buffers_1 buffer(const boost::array<PodType, N>& data,
+ std::size_t max_size_in_bytes)
+{
+ return const_buffers_1(
+ const_buffer(data.data(),
+ data.size() * sizeof(PodType) < max_size_in_bytes
+ ? data.size() * sizeof(PodType) : max_size_in_bytes));
+}
+
+/// Create a new modifiable buffer that represents the given POD vector.
+/**
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data)
+{
+ return mutable_buffers_1(
+ mutable_buffer(&data[0], data.size() * sizeof(PodType)
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , detail::buffer_debug_check<
+ typename std::vector<PodType, Allocator>::iterator
+ >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/// Create a new modifiable buffer that represents the given POD vector.
+/**
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data,
+ std::size_t max_size_in_bytes)
+{
+ return mutable_buffers_1(
+ mutable_buffer(&data[0],
+ data.size() * sizeof(PodType) < max_size_in_bytes
+ ? data.size() * sizeof(PodType) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , detail::buffer_debug_check<
+ typename std::vector<PodType, Allocator>::iterator
+ >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD vector.
+/**
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline const_buffers_1 buffer(
+ const std::vector<PodType, Allocator>& data)
+{
+ return const_buffers_1(
+ const_buffer(&data[0], data.size() * sizeof(PodType)
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , detail::buffer_debug_check<
+ typename std::vector<PodType, Allocator>::const_iterator
+ >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/// Create a new non-modifiable buffer that represents the given POD vector.
+/**
+ * @note The buffer is invalidated by any vector operation that would also
+ * invalidate iterators.
+ */
+template <typename PodType, typename Allocator>
+inline const_buffers_1 buffer(
+ const std::vector<PodType, Allocator>& data, std::size_t max_size_in_bytes)
+{
+ return const_buffers_1(
+ const_buffer(&data[0],
+ data.size() * sizeof(PodType) < max_size_in_bytes
+ ? data.size() * sizeof(PodType) : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , detail::buffer_debug_check<
+ typename std::vector<PodType, Allocator>::const_iterator
+ >(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/// Create a new non-modifiable buffer that represents the given string.
+/**
+ * @note The buffer is invalidated by any non-const operation called on the
+ * given string object.
+ */
+inline const_buffers_1 buffer(const std::string& data)
+{
+ return const_buffers_1(const_buffer(data.data(), data.size()
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , detail::buffer_debug_check<std::string::const_iterator>(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/// Create a new non-modifiable buffer that represents the given string.
+/**
+ * @note The buffer is invalidated by any non-const operation called on the
+ * given string object.
+ */
+inline const_buffers_1 buffer(const std::string& data,
+ std::size_t max_size_in_bytes)
+{
+ return const_buffers_1(
+ const_buffer(data.data(),
+ data.size() < max_size_in_bytes
+ ? data.size() : max_size_in_bytes
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ , detail::buffer_debug_check<std::string::const_iterator>(data.begin())
+#endif // ASIO_ENABLE_BUFFER_DEBUGGING
+ ));
+}
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFER_HPP
diff --git a/src/libtorrent/asio/buffered_read_stream.hpp b/src/libtorrent/asio/buffered_read_stream.hpp
new file mode 100644
index 0000000..673cce3
--- /dev/null
+++ b/src/libtorrent/asio/buffered_read_stream.hpp
@@ -0,0 +1,414 @@
+//
+// buffered_read_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BUFFERED_READ_STREAM_HPP
+#define ASIO_BUFFERED_READ_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <cstring>
+#include <boost/config.hpp>
+#include <boost/type_traits.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffered_read_stream_fwd.hpp"
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_resize_guard.hpp"
+#include "asio/detail/buffered_stream_storage.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+
+/// Adds buffering to the read-related operations of a stream.
+/**
+ * The buffered_read_stream class template can be used to add buffering to the
+ * synchronous and asynchronous read operations of a stream.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, Sync_Read_Stream, SyncWriteStream.
+ */
+template <typename Stream>
+class buffered_read_stream
+ : private noncopyable
+{
+public:
+ /// The type of the next layer.
+ typedef typename boost::remove_reference<Stream>::type next_layer_type;
+
+ /// The type of the lowest layer.
+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// The default buffer size.
+ static const std::size_t default_buffer_size = implementation_defined;
+#else
+ BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
+#endif
+
+ /// Construct, passing the specified argument to initialise the next layer.
+ template <typename Arg>
+ explicit buffered_read_stream(Arg& a)
+ : next_layer_(a),
+ storage_(default_buffer_size)
+ {
+ }
+
+ /// Construct, passing the specified argument to initialise the next layer.
+ template <typename Arg>
+ buffered_read_stream(Arg& a, std::size_t buffer_size)
+ : next_layer_(a),
+ storage_(buffer_size)
+ {
+ }
+
+ /// Get a reference to the next layer.
+ next_layer_type& next_layer()
+ {
+ return next_layer_;
+ }
+
+ /// Get a reference to the lowest layer.
+ lowest_layer_type& lowest_layer()
+ {
+ return next_layer_.lowest_layer();
+ }
+
+ /// (Deprecated: use get_io_service().) Get the io_service associated with
+ /// the object.
+ asio::io_service& io_service()
+ {
+ return next_layer_.get_io_service();
+ }
+
+ /// Get the io_service associated with the object.
+ asio::io_service& get_io_service()
+ {
+ return next_layer_.get_io_service();
+ }
+
+ /// Close the stream.
+ void close()
+ {
+ next_layer_.close();
+ }
+
+ /// Close the stream.
+ asio::error_code close(asio::error_code& ec)
+ {
+ return next_layer_.close(ec);
+ }
+
+ /// Write the given data to the stream. Returns the number of bytes written.
+ /// Throws an exception on failure.
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers)
+ {
+ return next_layer_.write_some(buffers);
+ }
+
+ /// Write the given data to the stream. Returns the number of bytes written,
+ /// or 0 if an error occurred.
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return next_layer_.write_some(buffers, ec);
+ }
+
+ /// Start an asynchronous write. The data being written must be valid for the
+ /// lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_write_some(const ConstBufferSequence& buffers,
+ WriteHandler handler)
+ {
+ next_layer_.async_write_some(buffers, handler);
+ }
+
+ /// Fill the buffer with some data. Returns the number of bytes placed in the
+ /// buffer as a result of the operation. Throws an exception on failure.
+ std::size_t fill()
+ {
+ detail::buffer_resize_guard<detail::buffered_stream_storage>
+ resize_guard(storage_);
+ std::size_t previous_size = storage_.size();
+ storage_.resize(storage_.capacity());
+ storage_.resize(previous_size + next_layer_.read_some(buffer(
+ storage_.data() + previous_size,
+ storage_.size() - previous_size)));
+ resize_guard.commit();
+ return storage_.size() - previous_size;
+ }
+
+ /// Fill the buffer with some data. Returns the number of bytes placed in the
+ /// buffer as a result of the operation, or 0 if an error occurred.
+ std::size_t fill(asio::error_code& ec)
+ {
+ detail::buffer_resize_guard<detail::buffered_stream_storage>
+ resize_guard(storage_);
+ std::size_t previous_size = storage_.size();
+ storage_.resize(storage_.capacity());
+ storage_.resize(previous_size + next_layer_.read_some(buffer(
+ storage_.data() + previous_size,
+ storage_.size() - previous_size),
+ ec));
+ resize_guard.commit();
+ return storage_.size() - previous_size;
+ }
+
+ template <typename ReadHandler>
+ class fill_handler
+ {
+ public:
+ fill_handler(asio::io_service& io_service,
+ detail::buffered_stream_storage& storage,
+ std::size_t previous_size, ReadHandler handler)
+ : io_service_(io_service),
+ storage_(storage),
+ previous_size_(previous_size),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ storage_.resize(previous_size_ + bytes_transferred);
+ io_service_.dispatch(detail::bind_handler(
+ handler_, ec, bytes_transferred));
+ }
+
+ private:
+ asio::io_service& io_service_;
+ detail::buffered_stream_storage& storage_;
+ std::size_t previous_size_;
+ ReadHandler handler_;
+ };
+
+ /// Start an asynchronous fill.
+ template <typename ReadHandler>
+ void async_fill(ReadHandler handler)
+ {
+ std::size_t previous_size = storage_.size();
+ storage_.resize(storage_.capacity());
+ next_layer_.async_read_some(
+ buffer(
+ storage_.data() + previous_size,
+ storage_.size() - previous_size),
+ fill_handler<ReadHandler>(get_io_service(),
+ storage_, previous_size, handler));
+ }
+
+ /// Read some data from the stream. Returns the number of bytes read. Throws
+ /// an exception on failure.
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers)
+ {
+ if (storage_.empty())
+ fill();
+ return copy(buffers);
+ }
+
+ /// Read some data from the stream. Returns the number of bytes read or 0 if
+ /// an error occurred.
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ ec = asio::error_code();
+ if (storage_.empty() && !fill(ec))
+ return 0;
+ return copy(buffers);
+ }
+
+ template <typename MutableBufferSequence, typename ReadHandler>
+ class read_some_handler
+ {
+ public:
+ read_some_handler(asio::io_service& io_service,
+ detail::buffered_stream_storage& storage,
+ const MutableBufferSequence& buffers, ReadHandler handler)
+ : io_service_(io_service),
+ storage_(storage),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec, std::size_t)
+ {
+ if (ec || storage_.empty())
+ {
+ std::size_t length = 0;
+ io_service_.dispatch(detail::bind_handler(handler_, ec, length));
+ }
+ else
+ {
+ using namespace std; // For memcpy.
+
+ std::size_t bytes_avail = storage_.size();
+ std::size_t bytes_copied = 0;
+
+ typename MutableBufferSequence::const_iterator iter = buffers_.begin();
+ typename MutableBufferSequence::const_iterator end = buffers_.end();
+ for (; iter != end && bytes_avail > 0; ++iter)
+ {
+ std::size_t max_length = buffer_size(*iter);
+ std::size_t length = (max_length < bytes_avail)
+ ? max_length : bytes_avail;
+ memcpy(buffer_cast<void*>(*iter),
+ storage_.data() + bytes_copied, length);
+ bytes_copied += length;
+ bytes_avail -= length;
+ }
+
+ storage_.consume(bytes_copied);
+ io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
+ }
+ }
+
+ private:
+ asio::io_service& io_service_;
+ detail::buffered_stream_storage& storage_;
+ MutableBufferSequence buffers_;
+ ReadHandler handler_;
+ };
+
+ /// Start an asynchronous read. The buffer into which the data will be read
+ /// must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_read_some(const MutableBufferSequence& buffers,
+ ReadHandler handler)
+ {
+ if (storage_.empty())
+ {
+ async_fill(read_some_handler<MutableBufferSequence, ReadHandler>(
+ get_io_service(), storage_, buffers, handler));
+ }
+ else
+ {
+ std::size_t length = copy(buffers);
+ get_io_service().post(detail::bind_handler(
+ handler, asio::error_code(), length));
+ }
+ }
+
+ /// Peek at the incoming data on the stream. Returns the number of bytes read.
+ /// Throws an exception on failure.
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers)
+ {
+ if (storage_.empty())
+ fill();
+ return peek_copy(buffers);
+ }
+
+ /// Peek at the incoming data on the stream. Returns the number of bytes read,
+ /// or 0 if an error occurred.
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ ec = asio::error_code();
+ if (storage_.empty() && !fill(ec))
+ return 0;
+ return peek_copy(buffers);
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ std::size_t in_avail()
+ {
+ return storage_.size();
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ std::size_t in_avail(asio::error_code& ec)
+ {
+ ec = asio::error_code();
+ return storage_.size();
+ }
+
+private:
+ /// Copy data out of the internal buffer to the specified target buffer.
+ /// Returns the number of bytes copied.
+ template <typename MutableBufferSequence>
+ std::size_t copy(const MutableBufferSequence& buffers)
+ {
+ using namespace std; // For memcpy.
+
+ std::size_t bytes_avail = storage_.size();
+ std::size_t bytes_copied = 0;
+
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ for (; iter != end && bytes_avail > 0; ++iter)
+ {
+ std::size_t max_length = buffer_size(*iter);
+ std::size_t length = (max_length < bytes_avail)
+ ? max_length : bytes_avail;
+ memcpy(buffer_cast<void*>(*iter), storage_.data() + bytes_copied, length);
+ bytes_copied += length;
+ bytes_avail -= length;
+ }
+
+ storage_.consume(bytes_copied);
+ return bytes_copied;
+ }
+
+ /// Copy data from the internal buffer to the specified target buffer, without
+ /// removing the data from the internal buffer. Returns the number of bytes
+ /// copied.
+ template <typename MutableBufferSequence>
+ std::size_t peek_copy(const MutableBufferSequence& buffers)
+ {
+ using namespace std; // For memcpy.
+
+ std::size_t bytes_avail = storage_.size();
+ std::size_t bytes_copied = 0;
+
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ for (; iter != end && bytes_avail > 0; ++iter)
+ {
+ std::size_t max_length = buffer_size(*iter);
+ std::size_t length = (max_length < bytes_avail)
+ ? max_length : bytes_avail;
+ memcpy(buffer_cast<void*>(*iter), storage_.data() + bytes_copied, length);
+ bytes_copied += length;
+ bytes_avail -= length;
+ }
+
+ return bytes_copied;
+ }
+
+ /// The next layer.
+ Stream next_layer_;
+
+ // The data in the buffer.
+ detail::buffered_stream_storage storage_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERED_READ_STREAM_HPP
diff --git a/src/libtorrent/asio/buffered_read_stream_fwd.hpp b/src/libtorrent/asio/buffered_read_stream_fwd.hpp
new file mode 100644
index 0000000..2f646a6
--- /dev/null
+++ b/src/libtorrent/asio/buffered_read_stream_fwd.hpp
@@ -0,0 +1,29 @@
+//
+// buffered_read_stream_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BUFFERED_READ_STREAM_FWD_HPP
+#define ASIO_BUFFERED_READ_STREAM_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Stream>
+class buffered_read_stream;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP
diff --git a/src/libtorrent/asio/buffered_stream.hpp b/src/libtorrent/asio/buffered_stream.hpp
new file mode 100644
index 0000000..a02dc88
--- /dev/null
+++ b/src/libtorrent/asio/buffered_stream.hpp
@@ -0,0 +1,250 @@
+//
+// buffered_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BUFFERED_STREAM_HPP
+#define ASIO_BUFFERED_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffered_read_stream.hpp"
+#include "asio/buffered_write_stream.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+
+/// Adds buffering to the read- and write-related operations of a stream.
+/**
+ * The buffered_stream class template can be used to add buffering to the
+ * synchronous and asynchronous read and write operations of a stream.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Stream>
+class buffered_stream
+ : private noncopyable
+{
+public:
+ /// The type of the next layer.
+ typedef typename boost::remove_reference<Stream>::type next_layer_type;
+
+ /// The type of the lowest layer.
+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+ /// Construct, passing the specified argument to initialise the next layer.
+ template <typename Arg>
+ explicit buffered_stream(Arg& a)
+ : inner_stream_impl_(a),
+ stream_impl_(inner_stream_impl_)
+ {
+ }
+
+ /// Construct, passing the specified argument to initialise the next layer.
+ template <typename Arg>
+ explicit buffered_stream(Arg& a, std::size_t read_buffer_size,
+ std::size_t write_buffer_size)
+ : inner_stream_impl_(a, write_buffer_size),
+ stream_impl_(inner_stream_impl_, read_buffer_size)
+ {
+ }
+
+ /// Get a reference to the next layer.
+ next_layer_type& next_layer()
+ {
+ return stream_impl_.next_layer().next_layer();
+ }
+
+ /// Get a reference to the lowest layer.
+ lowest_layer_type& lowest_layer()
+ {
+ return stream_impl_.lowest_layer();
+ }
+
+ /// (Deprecated: use get_io_service().) Get the io_service associated with
+ /// the object.
+ asio::io_service& io_service()
+ {
+ return stream_impl_.get_io_service();
+ }
+
+ /// Get the io_service associated with the object.
+ asio::io_service& get_io_service()
+ {
+ return stream_impl_.get_io_service();
+ }
+
+ /// Close the stream.
+ void close()
+ {
+ stream_impl_.close();
+ }
+
+ /// Close the stream.
+ asio::error_code close(asio::error_code& ec)
+ {
+ return stream_impl_.close(ec);
+ }
+
+ /// Flush all data from the buffer to the next layer. Returns the number of
+ /// bytes written to the next layer on the last write operation. Throws an
+ /// exception on failure.
+ std::size_t flush()
+ {
+ return stream_impl_.next_layer().flush();
+ }
+
+ /// Flush all data from the buffer to the next layer. Returns the number of
+ /// bytes written to the next layer on the last write operation, or 0 if an
+ /// error occurred.
+ std::size_t flush(asio::error_code& ec)
+ {
+ return stream_impl_.next_layer().flush(ec);
+ }
+
+ /// Start an asynchronous flush.
+ template <typename WriteHandler>
+ void async_flush(WriteHandler handler)
+ {
+ return stream_impl_.next_layer().async_flush(handler);
+ }
+
+ /// Write the given data to the stream. Returns the number of bytes written.
+ /// Throws an exception on failure.
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers)
+ {
+ return stream_impl_.write_some(buffers);
+ }
+
+ /// Write the given data to the stream. Returns the number of bytes written,
+ /// or 0 if an error occurred.
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return stream_impl_.write_some(buffers, ec);
+ }
+
+ /// Start an asynchronous write. The data being written must be valid for the
+ /// lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_write_some(const ConstBufferSequence& buffers,
+ WriteHandler handler)
+ {
+ stream_impl_.async_write_some(buffers, handler);
+ }
+
+ /// Fill the buffer with some data. Returns the number of bytes placed in the
+ /// buffer as a result of the operation. Throws an exception on failure.
+ std::size_t fill()
+ {
+ return stream_impl_.fill();
+ }
+
+ /// Fill the buffer with some data. Returns the number of bytes placed in the
+ /// buffer as a result of the operation, or 0 if an error occurred.
+ std::size_t fill(asio::error_code& ec)
+ {
+ return stream_impl_.fill(ec);
+ }
+
+ /// Start an asynchronous fill.
+ template <typename ReadHandler>
+ void async_fill(ReadHandler handler)
+ {
+ stream_impl_.async_fill(handler);
+ }
+
+ /// Read some data from the stream. Returns the number of bytes read. Throws
+ /// an exception on failure.
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers)
+ {
+ return stream_impl_.read_some(buffers);
+ }
+
+ /// Read some data from the stream. Returns the number of bytes read or 0 if
+ /// an error occurred.
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return stream_impl_.read_some(buffers, ec);
+ }
+
+ /// Start an asynchronous read. The buffer into which the data will be read
+ /// must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_read_some(const MutableBufferSequence& buffers,
+ ReadHandler handler)
+ {
+ stream_impl_.async_read_some(buffers, handler);
+ }
+
+ /// Peek at the incoming data on the stream. Returns the number of bytes read.
+ /// Throws an exception on failure.
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers)
+ {
+ return stream_impl_.peek(buffers);
+ }
+
+ /// Peek at the incoming data on the stream. Returns the number of bytes read,
+ /// or 0 if an error occurred.
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return stream_impl_.peek(buffers, ec);
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ std::size_t in_avail()
+ {
+ return stream_impl_.in_avail();
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ std::size_t in_avail(asio::error_code& ec)
+ {
+ return stream_impl_.in_avail(ec);
+ }
+
+private:
+ // The buffered write stream.
+ typedef buffered_write_stream<Stream> write_stream_type;
+ write_stream_type inner_stream_impl_;
+
+ // The buffered read stream.
+ typedef buffered_read_stream<write_stream_type&> read_stream_type;
+ read_stream_type stream_impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERED_STREAM_HPP
diff --git a/src/libtorrent/asio/buffered_stream_fwd.hpp b/src/libtorrent/asio/buffered_stream_fwd.hpp
new file mode 100644
index 0000000..987e113
--- /dev/null
+++ b/src/libtorrent/asio/buffered_stream_fwd.hpp
@@ -0,0 +1,29 @@
+//
+// buffered_stream_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BUFFERED_STREAM_FWD_HPP
+#define ASIO_BUFFERED_STREAM_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Stream>
+class buffered_stream;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERED_STREAM_FWD_HPP
diff --git a/src/libtorrent/asio/buffered_write_stream.hpp b/src/libtorrent/asio/buffered_write_stream.hpp
new file mode 100644
index 0000000..0ebd345
--- /dev/null
+++ b/src/libtorrent/asio/buffered_write_stream.hpp
@@ -0,0 +1,368 @@
+//
+// buffered_write_stream.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BUFFERED_WRITE_STREAM_HPP
+#define ASIO_BUFFERED_WRITE_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <cstring>
+#include <boost/config.hpp>
+#include <boost/type_traits.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffered_write_stream_fwd.hpp"
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/write.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffered_stream_storage.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+
+/// Adds buffering to the write-related operations of a stream.
+/**
+ * The buffered_write_stream class template can be used to add buffering to the
+ * synchronous and asynchronous write operations of a stream.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Stream>
+class buffered_write_stream
+ : private noncopyable
+{
+public:
+ /// The type of the next layer.
+ typedef typename boost::remove_reference<Stream>::type next_layer_type;
+
+ /// The type of the lowest layer.
+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// The default buffer size.
+ static const std::size_t default_buffer_size = implementation_defined;
+#else
+ BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
+#endif
+
+ /// Construct, passing the specified argument to initialise the next layer.
+ template <typename Arg>
+ explicit buffered_write_stream(Arg& a)
+ : next_layer_(a),
+ storage_(default_buffer_size)
+ {
+ }
+
+ /// Construct, passing the specified argument to initialise the next layer.
+ template <typename Arg>
+ buffered_write_stream(Arg& a, std::size_t buffer_size)
+ : next_layer_(a),
+ storage_(buffer_size)
+ {
+ }
+
+ /// Get a reference to the next layer.
+ next_layer_type& next_layer()
+ {
+ return next_layer_;
+ }
+
+ /// Get a reference to the lowest layer.
+ lowest_layer_type& lowest_layer()
+ {
+ return next_layer_.lowest_layer();
+ }
+
+ /// (Deprecated: use get_io_service().) Get the io_service associated with
+ /// the object.
+ asio::io_service& io_service()
+ {
+ return next_layer_.get_io_service();
+ }
+
+ /// Get the io_service associated with the object.
+ asio::io_service& get_io_service()
+ {
+ return next_layer_.get_io_service();
+ }
+
+ /// Close the stream.
+ void close()
+ {
+ next_layer_.close();
+ }
+
+ /// Close the stream.
+ asio::error_code close(asio::error_code& ec)
+ {
+ return next_layer_.close(ec);
+ }
+
+ /// Flush all data from the buffer to the next layer. Returns the number of
+ /// bytes written to the next layer on the last write operation. Throws an
+ /// exception on failure.
+ std::size_t flush()
+ {
+ std::size_t bytes_written = write(next_layer_,
+ buffer(storage_.data(), storage_.size()));
+ storage_.consume(bytes_written);
+ return bytes_written;
+ }
+
+ /// Flush all data from the buffer to the next layer. Returns the number of
+ /// bytes written to the next layer on the last write operation, or 0 if an
+ /// error occurred.
+ std::size_t flush(asio::error_code& ec)
+ {
+ std::size_t bytes_written = write(next_layer_,
+ buffer(storage_.data(), storage_.size()),
+ transfer_all(), ec);
+ storage_.consume(bytes_written);
+ return bytes_written;
+ }
+
+ template <typename WriteHandler>
+ class flush_handler
+ {
+ public:
+ flush_handler(asio::io_service& io_service,
+ detail::buffered_stream_storage& storage, WriteHandler handler)
+ : io_service_(io_service),
+ storage_(storage),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_written)
+ {
+ storage_.consume(bytes_written);
+ io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written));
+ }
+
+ private:
+ asio::io_service& io_service_;
+ detail::buffered_stream_storage& storage_;
+ WriteHandler handler_;
+ };
+
+ /// Start an asynchronous flush.
+ template <typename WriteHandler>
+ void async_flush(WriteHandler handler)
+ {
+ async_write(next_layer_, buffer(storage_.data(), storage_.size()),
+ flush_handler<WriteHandler>(get_io_service(), storage_, handler));
+ }
+
+ /// Write the given data to the stream. Returns the number of bytes written.
+ /// Throws an exception on failure.
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers)
+ {
+ if (storage_.size() == storage_.capacity())
+ flush();
+ return copy(buffers);
+ }
+
+ /// Write the given data to the stream. Returns the number of bytes written,
+ /// or 0 if an error occurred and the error handler did not throw.
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ ec = asio::error_code();
+ if (storage_.size() == storage_.capacity() && !flush(ec))
+ return 0;
+ return copy(buffers);
+ }
+
+ template <typename ConstBufferSequence, typename WriteHandler>
+ class write_some_handler
+ {
+ public:
+ write_some_handler(asio::io_service& io_service,
+ detail::buffered_stream_storage& storage,
+ const ConstBufferSequence& buffers, WriteHandler handler)
+ : io_service_(io_service),
+ storage_(storage),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec, std::size_t)
+ {
+ if (ec)
+ {
+ std::size_t length = 0;
+ io_service_.dispatch(detail::bind_handler(handler_, ec, length));
+ }
+ else
+ {
+ using namespace std; // For memcpy.
+
+ std::size_t orig_size = storage_.size();
+ std::size_t space_avail = storage_.capacity() - orig_size;
+ std::size_t bytes_copied = 0;
+
+ typename ConstBufferSequence::const_iterator iter = buffers_.begin();
+ typename ConstBufferSequence::const_iterator end = buffers_.end();
+ for (; iter != end && space_avail > 0; ++iter)
+ {
+ std::size_t bytes_avail = buffer_size(*iter);
+ std::size_t length = (bytes_avail < space_avail)
+ ? bytes_avail : space_avail;
+ storage_.resize(orig_size + bytes_copied + length);
+ memcpy(storage_.data() + orig_size + bytes_copied,
+ buffer_cast<const void*>(*iter), length);
+ bytes_copied += length;
+ space_avail -= length;
+ }
+
+ io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
+ }
+ }
+
+ private:
+ asio::io_service& io_service_;
+ detail::buffered_stream_storage& storage_;
+ ConstBufferSequence buffers_;
+ WriteHandler handler_;
+ };
+
+ /// Start an asynchronous write. The data being written must be valid for the
+ /// lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_write_some(const ConstBufferSequence& buffers,
+ WriteHandler handler)
+ {
+ if (storage_.size() == storage_.capacity())
+ {
+ async_flush(write_some_handler<ConstBufferSequence, WriteHandler>(
+ get_io_service(), storage_, buffers, handler));
+ }
+ else
+ {
+ std::size_t bytes_copied = copy(buffers);
+ get_io_service().post(detail::bind_handler(
+ handler, asio::error_code(), bytes_copied));
+ }
+ }
+
+ /// Read some data from the stream. Returns the number of bytes read. Throws
+ /// an exception on failure.
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers)
+ {
+ return next_layer_.read_some(buffers);
+ }
+
+ /// Read some data from the stream. Returns the number of bytes read or 0 if
+ /// an error occurred.
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return next_layer_.read_some(buffers, ec);
+ }
+
+ /// Start an asynchronous read. The buffer into which the data will be read
+ /// must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_read_some(const MutableBufferSequence& buffers,
+ ReadHandler handler)
+ {
+ next_layer_.async_read_some(buffers, handler);
+ }
+
+ /// Peek at the incoming data on the stream. Returns the number of bytes read.
+ /// Throws an exception on failure.
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers)
+ {
+ return next_layer_.peek(buffers);
+ }
+
+ /// Peek at the incoming data on the stream. Returns the number of bytes read,
+ /// or 0 if an error occurred.
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return next_layer_.peek(buffers, ec);
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ std::size_t in_avail()
+ {
+ return next_layer_.in_avail();
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ std::size_t in_avail(asio::error_code& ec)
+ {
+ return next_layer_.in_avail(ec);
+ }
+
+private:
+ /// Copy data into the internal buffer from the specified source buffer.
+ /// Returns the number of bytes copied.
+ template <typename ConstBufferSequence>
+ std::size_t copy(const ConstBufferSequence& buffers)
+ {
+ using namespace std; // For memcpy.
+
+ std::size_t orig_size = storage_.size();
+ std::size_t space_avail = storage_.capacity() - orig_size;
+ std::size_t bytes_copied = 0;
+
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ for (; iter != end && space_avail > 0; ++iter)
+ {
+ std::size_t bytes_avail = buffer_size(*iter);
+ std::size_t length = (bytes_avail < space_avail)
+ ? bytes_avail : space_avail;
+ storage_.resize(orig_size + bytes_copied + length);
+ memcpy(storage_.data() + orig_size + bytes_copied,
+ buffer_cast<const void*>(*iter), length);
+ bytes_copied += length;
+ space_avail -= length;
+ }
+
+ return bytes_copied;
+ }
+
+ /// The next layer.
+ Stream next_layer_;
+
+ // The data in the buffer.
+ detail::buffered_stream_storage storage_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERED_WRITE_STREAM_HPP
diff --git a/src/libtorrent/asio/buffered_write_stream_fwd.hpp b/src/libtorrent/asio/buffered_write_stream_fwd.hpp
new file mode 100644
index 0000000..4e33c8a
--- /dev/null
+++ b/src/libtorrent/asio/buffered_write_stream_fwd.hpp
@@ -0,0 +1,29 @@
+//
+// buffered_write_stream_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
+#define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+template <typename Stream>
+class buffered_write_stream;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
diff --git a/src/libtorrent/asio/completion_condition.hpp b/src/libtorrent/asio/completion_condition.hpp
new file mode 100644
index 0000000..b4d5908
--- /dev/null
+++ b/src/libtorrent/asio/completion_condition.hpp
@@ -0,0 +1,145 @@
+//
+// completion_condition.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_COMPLETION_CONDITION_HPP
+#define ASIO_COMPLETION_CONDITION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+
+namespace detail {
+
+class transfer_all_t
+{
+public:
+ typedef bool result_type;
+
+ template <typename Error>
+ bool operator()(const Error& err, std::size_t)
+ {
+ return !!err;
+ }
+};
+
+class transfer_at_least_t
+{
+public:
+ typedef bool result_type;
+
+ explicit transfer_at_least_t(std::size_t minimum)
+ : minimum_(minimum)
+ {
+ }
+
+ template <typename Error>
+ bool operator()(const Error& err, std::size_t bytes_transferred)
+ {
+ return !!err || bytes_transferred >= minimum_;
+ }
+
+private:
+ std::size_t minimum_;
+};
+
+} // namespace detail
+
+/**
+ * @defgroup completion_condition Completion Condition Function Objects
+ *
+ * Function objects used for determining when a read or write operation should
+ * complete.
+ */
+/*@{*/
+
+/// Return a completion condition function object that indicates that a read or
+/// write operation should continue until all of the data has been transferred,
+/// or until an error occurs.
+/**
+ * This function is used to create an object, of unspecified type, that meets
+ * CompletionCondition requirements.
+ *
+ * @par Example
+ * Reading until a buffer is full:
+ * @code
+ * boost::array<char, 128> buf;
+ * asio::error_code ec;
+ * std::size_t n = asio::read(
+ * sock, asio::buffer(buf),
+ * asio::transfer_all(), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * else
+ * {
+ * // n == 128
+ * }
+ * @endcode
+ */
+#if defined(GENERATING_DOCUMENTATION)
+unspecified transfer_all();
+#else
+inline detail::transfer_all_t transfer_all()
+{
+ return detail::transfer_all_t();
+}
+#endif
+
+/// Return a completion condition function object that indicates that a read or
+/// write operation should continue until a minimum number of bytes has been
+/// transferred, or until an error occurs.
+/**
+ * This function is used to create an object, of unspecified type, that meets
+ * CompletionCondition requirements.
+ *
+ * @par Example
+ * Reading until a buffer is full or contains at least 64 bytes:
+ * @code
+ * boost::array<char, 128> buf;
+ * asio::error_code ec;
+ * std::size_t n = asio::read(
+ * sock, asio::buffer(buf),
+ * asio::transfer_at_least(64), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * else
+ * {
+ * // n >= 64 && n <= 128
+ * }
+ * @endcode
+ */
+#if defined(GENERATING_DOCUMENTATION)
+unspecified transfer_at_least(std::size_t minimum);
+#else
+inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum)
+{
+ return detail::transfer_at_least_t(minimum);
+}
+#endif
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_COMPLETION_CONDITION_HPP
diff --git a/src/libtorrent/asio/datagram_socket_service.hpp b/src/libtorrent/asio/datagram_socket_service.hpp
new file mode 100644
index 0000000..9328f36
--- /dev/null
+++ b/src/libtorrent/asio/datagram_socket_service.hpp
@@ -0,0 +1,323 @@
+//
+// datagram_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DATAGRAM_SOCKET_SERVICE_HPP
+#define ASIO_DATAGRAM_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/reactive_socket_service.hpp"
+#include "asio/detail/win_iocp_socket_service.hpp"
+
+namespace asio {
+
+/// Default service implementation for a datagram socket.
+template <typename Protocol>
+class datagram_socket_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public asio::io_service::service
+#else
+ : public asio::detail::service_base<datagram_socket_service<Protocol> >
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static asio::io_service::id id;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+private:
+ // The type of the platform-specific implementation.
+#if defined(ASIO_HAS_IOCP)
+ typedef detail::win_iocp_socket_service<Protocol> service_impl_type;
+#elif defined(ASIO_HAS_EPOLL)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::epoll_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_KQUEUE)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::kqueue_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_DEV_POLL)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::dev_poll_reactor<false> > service_impl_type;
+#else
+ typedef detail::reactive_socket_service<
+ Protocol, detail::select_reactor<false> > service_impl_type;
+#endif
+
+public:
+ /// The type of a datagram socket.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef typename service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// The native socket type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_type;
+#else
+ typedef typename service_impl_type::native_type native_type;
+#endif
+
+ /// Construct a new datagram socket service for the specified io_service.
+ explicit datagram_socket_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ datagram_socket_service<Protocol> >(io_service),
+ service_impl_(asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Construct a new datagram socket implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+ /// Destroy a datagram socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ // Open a new datagram socket implementation.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::error_code& ec)
+ {
+ if (protocol.type() == SOCK_DGRAM)
+ service_impl_.open(impl, protocol, ec);
+ else
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ /// Assign an existing native socket to a datagram socket.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_type& native_socket,
+ asio::error_code& ec)
+ {
+ return service_impl_.assign(impl, protocol, native_socket, ec);
+ }
+
+ /// Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return service_impl_.is_open(impl);
+ }
+
+ /// Close a datagram socket implementation.
+ asio::error_code close(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return service_impl_.close(impl, ec);
+ }
+
+ /// Get the native socket implementation.
+ native_type native(implementation_type& impl)
+ {
+ return service_impl_.native(impl);
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return service_impl_.cancel(impl, ec);
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.at_mark(impl, ec);
+ }
+
+ /// Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.available(impl, ec);
+ }
+
+ // Bind the datagram socket to the specified local endpoint.
+ asio::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ return service_impl_.bind(impl, endpoint, ec);
+ }
+
+ /// Connect the datagram socket to the specified endpoint.
+ asio::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, asio::error_code& ec)
+ {
+ return service_impl_.connect(impl, peer_endpoint, ec);
+ }
+
+ /// Start an asynchronous connect.
+ template <typename ConnectHandler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, ConnectHandler handler)
+ {
+ service_impl_.async_connect(impl, peer_endpoint, handler);
+ }
+
+ /// Set a socket option.
+ template <typename SettableSocketOption>
+ asio::error_code set_option(implementation_type& impl,
+ const SettableSocketOption& option, asio::error_code& ec)
+ {
+ return service_impl_.set_option(impl, option, ec);
+ }
+
+ /// Get a socket option.
+ template <typename GettableSocketOption>
+ asio::error_code get_option(const implementation_type& impl,
+ GettableSocketOption& option, asio::error_code& ec) const
+ {
+ return service_impl_.get_option(impl, option, ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ template <typename IoControlCommand>
+ asio::error_code io_control(implementation_type& impl,
+ IoControlCommand& command, asio::error_code& ec)
+ {
+ return service_impl_.io_control(impl, command, ec);
+ }
+
+ /// Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.local_endpoint(impl, ec);
+ }
+
+ /// Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.remote_endpoint(impl, ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ asio::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, asio::error_code& ec)
+ {
+ return service_impl_.shutdown(impl, what, ec);
+ }
+
+ /// Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ std::size_t send(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return service_impl_.send(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, WriteHandler handler)
+ {
+ service_impl_.async_send(impl, buffers, flags, handler);
+ }
+
+ /// Send a datagram to the specified endpoint.
+ template <typename ConstBufferSequence>
+ std::size_t send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return service_impl_.send_to(impl, buffers, destination, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags, WriteHandler handler)
+ {
+ service_impl_.async_send_to(impl, buffers, destination, flags, handler);
+ }
+
+ /// Receive some data from the peer.
+ template <typename MutableBufferSequence>
+ std::size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return service_impl_.receive(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, ReadHandler handler)
+ {
+ service_impl_.async_receive(impl, buffers, flags, handler);
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return service_impl_.receive_from(impl, buffers, sender_endpoint, flags,
+ ec);
+ }
+
+ /// Start an asynchronous receive that will get the endpoint of the sender.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, ReadHandler handler)
+ {
+ service_impl_.async_receive_from(impl, buffers, sender_endpoint, flags,
+ handler);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DATAGRAM_SOCKET_SERVICE_HPP
diff --git a/src/libtorrent/asio/deadline_timer.hpp b/src/libtorrent/asio/deadline_timer.hpp
new file mode 100644
index 0000000..0ea3737
--- /dev/null
+++ b/src/libtorrent/asio/deadline_timer.hpp
@@ -0,0 +1,37 @@
+//
+// deadline_timer.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DEADLINE_TIMER_HPP
+#define ASIO_DEADLINE_TIMER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+
+#include "asio/detail/push_options.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_deadline_timer.hpp"
+
+namespace asio {
+
+/// Typedef for the typical usage of timer.
+typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DEADLINE_TIMER_HPP
diff --git a/src/libtorrent/asio/deadline_timer_service.hpp b/src/libtorrent/asio/deadline_timer_service.hpp
new file mode 100644
index 0000000..2a79b49
--- /dev/null
+++ b/src/libtorrent/asio/deadline_timer_service.hpp
@@ -0,0 +1,168 @@
+//
+// deadline_timer_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DEADLINE_TIMER_SERVICE_HPP
+#define ASIO_DEADLINE_TIMER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/time_traits.hpp"
+#include "asio/detail/deadline_timer_service.hpp"
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/win_iocp_io_service.hpp"
+
+namespace asio {
+
+/// Default service implementation for a timer.
+template <typename TimeType,
+ typename TimeTraits = asio::time_traits<TimeType> >
+class deadline_timer_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public asio::io_service::service
+#else
+ : public asio::detail::service_base<
+ deadline_timer_service<TimeType, TimeTraits> >
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static asio::io_service::id id;
+#endif
+
+ /// The time traits type.
+ typedef TimeTraits traits_type;
+
+ /// The time type.
+ typedef typename traits_type::time_type time_type;
+
+ /// The duration type.
+ typedef typename traits_type::duration_type duration_type;
+
+private:
+ // The type of the platform-specific implementation.
+#if defined(ASIO_HAS_IOCP)
+ typedef detail::deadline_timer_service<
+ traits_type, detail::win_iocp_io_service> service_impl_type;
+#elif defined(ASIO_HAS_EPOLL)
+ typedef detail::deadline_timer_service<
+ traits_type, detail::epoll_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_KQUEUE)
+ typedef detail::deadline_timer_service<
+ traits_type, detail::kqueue_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_DEV_POLL)
+ typedef detail::deadline_timer_service<
+ traits_type, detail::dev_poll_reactor<false> > service_impl_type;
+#else
+ typedef detail::deadline_timer_service<
+ traits_type, detail::select_reactor<false> > service_impl_type;
+#endif
+
+public:
+ /// The implementation type of the deadline timer.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef typename service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// Construct a new timer service for the specified io_service.
+ explicit deadline_timer_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ deadline_timer_service<TimeType, TimeTraits> >(io_service),
+ service_impl_(asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Construct a new timer implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+ /// Destroy a timer implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ /// Cancel any asynchronous wait operations associated with the timer.
+ std::size_t cancel(implementation_type& impl, asio::error_code& ec)
+ {
+ return service_impl_.cancel(impl, ec);
+ }
+
+ /// Get the expiry time for the timer as an absolute time.
+ time_type expires_at(const implementation_type& impl) const
+ {
+ return service_impl_.expires_at(impl);
+ }
+
+ /// Set the expiry time for the timer as an absolute time.
+ std::size_t expires_at(implementation_type& impl,
+ const time_type& expiry_time, asio::error_code& ec)
+ {
+ return service_impl_.expires_at(impl, expiry_time, ec);
+ }
+
+ /// Get the expiry time for the timer relative to now.
+ duration_type expires_from_now(const implementation_type& impl) const
+ {
+ return service_impl_.expires_from_now(impl);
+ }
+
+ /// Set the expiry time for the timer relative to now.
+ std::size_t expires_from_now(implementation_type& impl,
+ const duration_type& expiry_time, asio::error_code& ec)
+ {
+ return service_impl_.expires_from_now(impl, expiry_time, ec);
+ }
+
+ // Perform a blocking wait on the timer.
+ void wait(implementation_type& impl, asio::error_code& ec)
+ {
+ service_impl_.wait(impl, ec);
+ }
+
+ // Start an asynchronous wait on the timer.
+ template <typename WaitHandler>
+ void async_wait(implementation_type& impl, WaitHandler handler)
+ {
+ service_impl_.async_wait(impl, handler);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DEADLINE_TIMER_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/bind_handler.hpp b/src/libtorrent/asio/detail/bind_handler.hpp
new file mode 100644
index 0000000..f6200f2
--- /dev/null
+++ b/src/libtorrent/asio/detail/bind_handler.hpp
@@ -0,0 +1,349 @@
+//
+// bind_handler.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_BIND_HANDLER_HPP
+#define ASIO_DETAIL_BIND_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Arg1>
+class binder1
+{
+public:
+ binder1(const Handler& handler, const Arg1& arg1)
+ : handler_(handler),
+ arg1_(arg1)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_);
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+};
+
+template <typename Handler, typename Arg1>
+inline void* asio_handler_allocate(std::size_t size,
+ binder1<Handler, Arg1>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder1<Handler, Arg1>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline void asio_handler_invoke(const Function& function,
+ binder1<Handler, Arg1>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline binder1<Handler, Arg1> bind_handler(const Handler& handler,
+ const Arg1& arg1)
+{
+ return binder1<Handler, Arg1>(handler, arg1);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+class binder2
+{
+public:
+ binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, arg2_);
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline void* asio_handler_allocate(std::size_t size,
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_invoke(const Function& function,
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline binder2<Handler, Arg1, Arg2> bind_handler(const Handler& handler,
+ const Arg1& arg1, const Arg2& arg2)
+{
+ return binder2<Handler, Arg1, Arg2>(handler, arg1, arg2);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+class binder3
+{
+public:
+ binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, arg2_, arg3_);
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_, arg3_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+ Arg3 arg3_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline void* asio_handler_allocate(std::size_t size,
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2,
+ typename Arg3>
+inline void asio_handler_invoke(const Function& function,
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline binder3<Handler, Arg1, Arg2, Arg3> bind_handler(const Handler& handler,
+ const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
+{
+ return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+class binder4
+{
+public:
+ binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, arg2_, arg3_, arg4_);
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_, arg3_, arg4_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+ Arg3 arg3_;
+ Arg4 arg4_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+inline void* asio_handler_allocate(std::size_t size,
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4>
+inline void asio_handler_invoke(const Function& function,
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+inline binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler(
+ const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4)
+{
+ return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3,
+ arg4);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+class binder5
+{
+public:
+ binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4),
+ arg5_(arg5)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+ Arg3 arg3_;
+ Arg4 arg4_;
+ Arg5 arg5_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+inline void* asio_handler_allocate(std::size_t size,
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
+inline void asio_handler_invoke(const Function& function,
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+inline binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(
+ const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+{
+ return binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2,
+ arg3, arg4, arg5);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BIND_HANDLER_HPP
diff --git a/src/libtorrent/asio/detail/buffer_resize_guard.hpp b/src/libtorrent/asio/detail/buffer_resize_guard.hpp
new file mode 100644
index 0000000..c40d2b2
--- /dev/null
+++ b/src/libtorrent/asio/detail/buffer_resize_guard.hpp
@@ -0,0 +1,70 @@
+//
+// buffer_resize_guard.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <limits>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to manage buffer resizing in an exception safe way.
+template <typename Buffer>
+class buffer_resize_guard
+{
+public:
+ // Constructor.
+ buffer_resize_guard(Buffer& buffer)
+ : buffer_(buffer),
+ old_size_(buffer.size())
+ {
+ }
+
+ // Destructor rolls back the buffer resize unless commit was called.
+ ~buffer_resize_guard()
+ {
+ if (old_size_
+ != std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
+ {
+ buffer_.resize(old_size_);
+ }
+ }
+
+ // Commit the resize transaction.
+ void commit()
+ {
+ old_size_
+ = std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION();
+ }
+
+private:
+ // The buffer being managed.
+ Buffer& buffer_;
+
+ // The size of the buffer at the time the guard was constructed.
+ size_t old_size_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
diff --git a/src/libtorrent/asio/detail/buffered_stream_storage.hpp b/src/libtorrent/asio/detail/buffered_stream_storage.hpp
new file mode 100644
index 0000000..072377a
--- /dev/null
+++ b/src/libtorrent/asio/detail/buffered_stream_storage.hpp
@@ -0,0 +1,127 @@
+//
+// buffered_stream_storage.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <vector>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class buffered_stream_storage
+{
+public:
+ // The type of the bytes stored in the buffer.
+ typedef unsigned char byte_type;
+
+ // The type used for offsets into the buffer.
+ typedef std::size_t size_type;
+
+ // Constructor.
+ explicit buffered_stream_storage(std::size_t capacity)
+ : begin_offset_(0),
+ end_offset_(0),
+ buffer_(capacity)
+ {
+ }
+
+ /// Clear the buffer.
+ void clear()
+ {
+ begin_offset_ = 0;
+ end_offset_ = 0;
+ }
+
+ // Return a pointer to the beginning of the unread data.
+ byte_type* data()
+ {
+ return &buffer_[0] + begin_offset_;
+ }
+
+ // Return a pointer to the beginning of the unread data.
+ const byte_type* data() const
+ {
+ return &buffer_[0] + begin_offset_;
+ }
+
+ // Is there no unread data in the buffer.
+ bool empty() const
+ {
+ return begin_offset_ == end_offset_;
+ }
+
+ // Return the amount of unread data the is in the buffer.
+ size_type size() const
+ {
+ return end_offset_ - begin_offset_;
+ }
+
+ // Resize the buffer to the specified length.
+ void resize(size_type length)
+ {
+ assert(length <= capacity());
+ if (begin_offset_ + length <= capacity())
+ {
+ end_offset_ = begin_offset_ + length;
+ }
+ else
+ {
+ using namespace std; // For memmove.
+ memmove(&buffer_[0], &buffer_[0] + begin_offset_, size());
+ end_offset_ = length;
+ begin_offset_ = 0;
+ }
+ }
+
+ // Return the maximum size for data in the buffer.
+ size_type capacity() const
+ {
+ return buffer_.size();
+ }
+
+ // Consume multiple bytes from the beginning of the buffer.
+ void consume(size_type count)
+ {
+ assert(begin_offset_ + count <= end_offset_);
+ begin_offset_ += count;
+ if (empty())
+ clear();
+ }
+
+private:
+ // The offset to the beginning of the unread data.
+ size_type begin_offset_;
+
+ // The offset to the end of the unread data.
+ size_type end_offset_;
+
+ // The data in the buffer.
+ std::vector<byte_type> buffer_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
diff --git a/src/libtorrent/asio/detail/call_stack.hpp b/src/libtorrent/asio/detail/call_stack.hpp
new file mode 100644
index 0000000..7387699
--- /dev/null
+++ b/src/libtorrent/asio/detail/call_stack.hpp
@@ -0,0 +1,90 @@
+//
+// call_stack.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_CALL_STACK_HPP
+#define ASIO_DETAIL_CALL_STACK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/tss_ptr.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to determine whether or not the current thread is inside an
+// invocation of io_service::run() for a specified io_service object.
+template <typename Owner>
+class call_stack
+{
+public:
+ // Context class automatically pushes an owner on to the stack.
+ class context
+ : private noncopyable
+ {
+ public:
+ // Push the owner on to the stack.
+ explicit context(Owner* d)
+ : owner_(d),
+ next_(call_stack<Owner>::top_)
+ {
+ call_stack<Owner>::top_ = this;
+ }
+
+ // Pop the owner from the stack.
+ ~context()
+ {
+ call_stack<Owner>::top_ = next_;
+ }
+
+ private:
+ friend class call_stack<Owner>;
+
+ // The owner associated with the context.
+ Owner* owner_;
+
+ // The next element in the stack.
+ context* next_;
+ };
+
+ friend class context;
+
+ // Determine whether the specified owner is on the stack.
+ static bool contains(Owner* d)
+ {
+ context* elem = top_;
+ while (elem)
+ {
+ if (elem->owner_ == d)
+ return true;
+ elem = elem->next_;
+ }
+ return false;
+ }
+
+private:
+ // The top of the stack of calls for the current thread.
+ static tss_ptr<context> top_;
+};
+
+template <typename Owner>
+tss_ptr<typename call_stack<Owner>::context>
+call_stack<Owner>::top_;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CALL_STACK_HPP
diff --git a/src/libtorrent/asio/detail/const_buffers_iterator.hpp b/src/libtorrent/asio/detail/const_buffers_iterator.hpp
new file mode 100644
index 0000000..6ac3ac5
--- /dev/null
+++ b/src/libtorrent/asio/detail/const_buffers_iterator.hpp
@@ -0,0 +1,151 @@
+//
+// const_buffers_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP
+#define ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+
+namespace asio {
+namespace detail {
+
+// A proxy iterator for a sub-range in a list of buffers.
+template <typename ConstBufferSequence>
+class const_buffers_iterator
+ : public boost::iterator_facade<const_buffers_iterator<ConstBufferSequence>,
+ const char, boost::bidirectional_traversal_tag>
+{
+public:
+ // Default constructor creates an iterator in an undefined state.
+ const_buffers_iterator()
+ {
+ }
+
+ // Create an iterator for the specified position.
+ const_buffers_iterator(const ConstBufferSequence& buffers,
+ std::size_t position)
+ : begin_(buffers.begin()),
+ current_(buffers.begin()),
+ end_(buffers.end()),
+ position_(0)
+ {
+ while (current_ != end_)
+ {
+ current_buffer_ = *current_;
+ std::size_t buffer_size = asio::buffer_size(current_buffer_);
+ if (position - position_ < buffer_size)
+ {
+ current_buffer_position_ = position - position_;
+ position_ = position;
+ return;
+ }
+ position_ += buffer_size;
+ ++current_;
+ }
+ current_buffer_ = asio::const_buffer();
+ current_buffer_position_ = 0;
+ }
+
+ std::size_t position() const
+ {
+ return position_;
+ }
+
+private:
+ friend class boost::iterator_core_access;
+
+ void increment()
+ {
+ if (current_ == end_)
+ return;
+
+ ++position_;
+
+ ++current_buffer_position_;
+ if (current_buffer_position_ != asio::buffer_size(current_buffer_))
+ return;
+
+ ++current_;
+ current_buffer_position_ = 0;
+ while (current_ != end_)
+ {
+ current_buffer_ = *current_;
+ if (asio::buffer_size(current_buffer_) > 0)
+ return;
+ ++current_;
+ }
+ }
+
+ void decrement()
+ {
+ if (position_ == 0)
+ return;
+
+ --position_;
+
+ if (current_buffer_position_ != 0)
+ {
+ --current_buffer_position_;
+ return;
+ }
+
+ typename ConstBufferSequence::const_iterator iter = current_;
+ while (iter != begin_)
+ {
+ --iter;
+ asio::const_buffer buffer = *iter;
+ std::size_t buffer_size = asio::buffer_size(buffer);
+ if (buffer_size > 0)
+ {
+ current_ = iter;
+ current_buffer_ = buffer;
+ current_buffer_position_ = buffer_size - 1;
+ return;
+ }
+ }
+ }
+
+ bool equal(const const_buffers_iterator& other) const
+ {
+ return position_ == other.position_;
+ }
+
+ const char& dereference() const
+ {
+ return asio::buffer_cast<const char*>(
+ current_buffer_)[current_buffer_position_];
+ }
+
+ asio::const_buffer current_buffer_;
+ std::size_t current_buffer_position_;
+ typename ConstBufferSequence::const_iterator begin_;
+ typename ConstBufferSequence::const_iterator current_;
+ typename ConstBufferSequence::const_iterator end_;
+ std::size_t position_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP
diff --git a/src/libtorrent/asio/detail/consuming_buffers.hpp b/src/libtorrent/asio/detail/consuming_buffers.hpp
new file mode 100644
index 0000000..8e88e36
--- /dev/null
+++ b/src/libtorrent/asio/detail/consuming_buffers.hpp
@@ -0,0 +1,225 @@
+//
+// consuming_buffers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <algorithm>
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+
+namespace asio {
+namespace detail {
+
+// A proxy iterator for a sub-range in a list of buffers.
+template <typename Buffer, typename Buffer_Iterator>
+class consuming_buffers_iterator
+ : public boost::iterator_facade<
+ consuming_buffers_iterator<Buffer, Buffer_Iterator>,
+ const Buffer, boost::forward_traversal_tag>
+{
+public:
+ // Default constructor creates an end iterator.
+ consuming_buffers_iterator()
+ : at_end_(true)
+ {
+ }
+
+ // Construct with a buffer for the first entry and an iterator
+ // range for the remaining entries.
+ consuming_buffers_iterator(bool at_end, const Buffer& first,
+ Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder)
+ : at_end_(at_end),
+ first_(buffer(first, max_size)),
+ begin_remainder_(begin_remainder),
+ end_remainder_(end_remainder),
+ offset_(0)
+ {
+ }
+
+private:
+ friend class boost::iterator_core_access;
+
+ enum { max_size = 65536 };
+
+ void increment()
+ {
+ if (!at_end_)
+ {
+ if (begin_remainder_ == end_remainder_
+ || offset_ + buffer_size(first_) >= max_size)
+ {
+ at_end_ = true;
+ }
+ else
+ {
+ offset_ += buffer_size(first_);
+ first_ = buffer(*begin_remainder_++, max_size - offset_);
+ }
+ }
+ }
+
+ bool equal(const consuming_buffers_iterator& other) const
+ {
+ if (at_end_ && other.at_end_)
+ return true;
+ return !at_end_ && !other.at_end_
+ && buffer_cast<const void*>(first_)
+ == buffer_cast<const void*>(other.first_)
+ && buffer_size(first_) == buffer_size(other.first_)
+ && begin_remainder_ == other.begin_remainder_
+ && end_remainder_ == other.end_remainder_;
+ }
+
+ const Buffer& dereference() const
+ {
+ return first_;
+ }
+
+ bool at_end_;
+ Buffer first_;
+ Buffer_Iterator begin_remainder_;
+ Buffer_Iterator end_remainder_;
+ std::size_t offset_;
+};
+
+// A proxy for a sub-range in a list of buffers.
+template <typename Buffer, typename Buffers>
+class consuming_buffers
+{
+public:
+ // The type for each element in the list of buffers.
+ typedef Buffer value_type;
+
+ // A forward-only iterator type that may be used to read elements.
+ typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
+ const_iterator;
+
+ // Construct to represent the entire list of buffers.
+ consuming_buffers(const Buffers& buffers)
+ : buffers_(buffers),
+ at_end_(buffers_.begin() == buffers_.end()),
+ first_(*buffers_.begin()),
+ begin_remainder_(buffers_.begin())
+ {
+ if (!at_end_)
+ ++begin_remainder_;
+ }
+
+ // Copy constructor.
+ consuming_buffers(const consuming_buffers& other)
+ : buffers_(other.buffers_),
+ at_end_(other.at_end_),
+ first_(other.first_),
+ begin_remainder_(buffers_.begin())
+ {
+ typename Buffers::const_iterator first = other.buffers_.begin();
+ typename Buffers::const_iterator second = other.begin_remainder_;
+ std::advance(begin_remainder_, std::distance(first, second));
+ }
+
+ // Assignment operator.
+ consuming_buffers& operator=(const consuming_buffers& other)
+ {
+ buffers_ = other.buffers_;
+ at_end_ = other.at_end_;
+ first_ = other.first_;
+ begin_remainder_ = buffers_.begin();
+ typename Buffers::const_iterator first = other.buffers_.begin();
+ typename Buffers::const_iterator second = other.begin_remainder_;
+ std::advance(begin_remainder_, std::distance(first, second));
+ return *this;
+ }
+
+ // Get a forward-only iterator to the first element.
+ const_iterator begin() const
+ {
+ return const_iterator(at_end_, first_, begin_remainder_, buffers_.end());
+ }
+
+ // Get a forward-only iterator for one past the last element.
+ const_iterator end() const
+ {
+ return const_iterator();
+ }
+
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
+ {
+ // Remove buffers from the start until the specified size is reached.
+ while (size > 0 && !at_end_)
+ {
+ if (buffer_size(first_) <= size)
+ {
+ size -= buffer_size(first_);
+ if (begin_remainder_ == buffers_.end())
+ at_end_ = true;
+ else
+ first_ = *begin_remainder_++;
+ }
+ else
+ {
+ first_ = first_ + size;
+ size = 0;
+ }
+ }
+
+ // Remove any more empty buffers at the start.
+ while (!at_end_ && buffer_size(first_) == 0)
+ {
+ if (begin_remainder_ == buffers_.end())
+ at_end_ = true;
+ else
+ first_ = *begin_remainder_++;
+ }
+ }
+
+private:
+ Buffers buffers_;
+ bool at_end_;
+ Buffer first_;
+ typename Buffers::const_iterator begin_remainder_;
+};
+
+// Specialisation for null_buffers to ensure that the null_buffers type is
+// always passed through to the underlying read or write operation.
+template <typename Buffer>
+class consuming_buffers<Buffer, asio::null_buffers>
+ : public asio::null_buffers
+{
+public:
+ consuming_buffers(const asio::null_buffers&)
+ {
+ // No-op.
+ }
+
+ void consume(std::size_t)
+ {
+ // No-op.
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP
diff --git a/src/libtorrent/asio/detail/deadline_timer_service.hpp b/src/libtorrent/asio/detail/deadline_timer_service.hpp
new file mode 100644
index 0000000..1acbd15
--- /dev/null
+++ b/src/libtorrent/asio/detail/deadline_timer_service.hpp
@@ -0,0 +1,199 @@
+//
+// deadline_timer_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits, typename Timer_Scheduler>
+class deadline_timer_service
+ : public asio::detail::service_base<
+ deadline_timer_service<Time_Traits, Timer_Scheduler> >
+{
+public:
+ // The time type.
+ typedef typename Time_Traits::time_type time_type;
+
+ // The duration type.
+ typedef typename Time_Traits::duration_type duration_type;
+
+ // The implementation type of the timer. This type is dependent on the
+ // underlying implementation of the timer service.
+ struct implementation_type
+ : private asio::detail::noncopyable
+ {
+ time_type expiry;
+ bool might_have_pending_waits;
+ };
+
+ // Constructor.
+ deadline_timer_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
+ scheduler_(asio::use_service<Timer_Scheduler>(io_service))
+ {
+ scheduler_.add_timer_queue(timer_queue_);
+ }
+
+ // Destructor.
+ ~deadline_timer_service()
+ {
+ scheduler_.remove_timer_queue(timer_queue_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Construct a new timer implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.expiry = time_type();
+ impl.might_have_pending_waits = false;
+ }
+
+ // Destroy a timer implementation.
+ void destroy(implementation_type& impl)
+ {
+ asio::error_code ec;
+ cancel(impl, ec);
+ }
+
+ // Cancel any asynchronous wait operations associated with the timer.
+ std::size_t cancel(implementation_type& impl, asio::error_code& ec)
+ {
+ if (!impl.might_have_pending_waits)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+ std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
+ impl.might_have_pending_waits = false;
+ ec = asio::error_code();
+ return count;
+ }
+
+ // Get the expiry time for the timer as an absolute time.
+ time_type expires_at(const implementation_type& impl) const
+ {
+ return impl.expiry;
+ }
+
+ // Set the expiry time for the timer as an absolute time.
+ std::size_t expires_at(implementation_type& impl,
+ const time_type& expiry_time, asio::error_code& ec)
+ {
+ std::size_t count = cancel(impl, ec);
+ impl.expiry = expiry_time;
+ ec = asio::error_code();
+ return count;
+ }
+
+ // Get the expiry time for the timer relative to now.
+ duration_type expires_from_now(const implementation_type& impl) const
+ {
+ return Time_Traits::subtract(expires_at(impl), Time_Traits::now());
+ }
+
+ // Set the expiry time for the timer relative to now.
+ std::size_t expires_from_now(implementation_type& impl,
+ const duration_type& expiry_time, asio::error_code& ec)
+ {
+ return expires_at(impl,
+ Time_Traits::add(Time_Traits::now(), expiry_time), ec);
+ }
+
+ // Perform a blocking wait on the timer.
+ void wait(implementation_type& impl, asio::error_code& ec)
+ {
+ time_type now = Time_Traits::now();
+ while (Time_Traits::less_than(now, impl.expiry))
+ {
+ boost::posix_time::time_duration timeout =
+ Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now));
+ ::timeval tv;
+ tv.tv_sec = timeout.total_seconds();
+ tv.tv_usec = timeout.total_microseconds() % 1000000;
+ asio::error_code ec;
+ socket_ops::select(0, 0, 0, 0, &tv, ec);
+ now = Time_Traits::now();
+ }
+ ec = asio::error_code();
+ }
+
+ template <typename Handler>
+ class wait_handler
+ {
+ public:
+ wait_handler(asio::io_service& io_service, Handler handler)
+ : io_service_(io_service),
+ work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& result)
+ {
+ io_service_.post(detail::bind_handler(handler_, result));
+ }
+
+ private:
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous wait on the timer.
+ template <typename Handler>
+ void async_wait(implementation_type& impl, Handler handler)
+ {
+ impl.might_have_pending_waits = true;
+ scheduler_.schedule_timer(timer_queue_, impl.expiry,
+ wait_handler<Handler>(this->get_io_service(), handler), &impl);
+ }
+
+private:
+ // The queue of timers.
+ timer_queue<Time_Traits> timer_queue_;
+
+ // The object that schedules and executes timers. Usually a reactor.
+ Timer_Scheduler& scheduler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/dev_poll_reactor.hpp b/src/libtorrent/asio/detail/dev_poll_reactor.hpp
new file mode 100644
index 0000000..45aeb3c
--- /dev/null
+++ b/src/libtorrent/asio/detail/dev_poll_reactor.hpp
@@ -0,0 +1,651 @@
+//
+// dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+#define ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/dev_poll_reactor_fwd.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <vector>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/throw_exception.hpp>
+#include <sys/devpoll.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/task_io_service.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue.hpp"
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class dev_poll_reactor
+ : public asio::detail::service_base<dev_poll_reactor<Own_Thread> >
+{
+public:
+ // Constructor.
+ dev_poll_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<
+ dev_poll_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ dev_poll_fd_(do_dev_poll_create()),
+ wait_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false)
+ {
+ // Start the reactor's internal thread only if needed.
+ if (Own_Thread)
+ {
+ asio::detail::signal_blocker sb;
+ thread_ = new asio::detail::thread(
+ bind_handler(&dev_poll_reactor::call_run_thread, this));
+ }
+
+ // Add the interrupter's descriptor to /dev/poll.
+ ::pollfd ev = { 0 };
+ ev.fd = interrupter_.read_descriptor();
+ ev.events = POLLIN | POLLERR;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+ }
+
+ // Destructor.
+ ~dev_poll_reactor()
+ {
+ shutdown_service();
+ ::close(dev_poll_fd_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type descriptor)
+ {
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor, Handler handler,
+ bool allow_speculative_read = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (allow_speculative_read)
+ if (!read_op_queue_.has_operation(descriptor))
+ if (handler(asio::error_code()))
+ return;
+
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLIN | POLLERR | POLLHUP;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= POLLOUT;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= POLLPRI;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor, Handler handler,
+ bool allow_speculative_write = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (allow_speculative_write)
+ if (!write_op_queue_.has_operation(descriptor))
+ if (handler(asio::error_code()))
+ return;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLOUT | POLLERR | POLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= POLLIN;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= POLLPRI;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLPRI | POLLERR | POLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= POLLIN;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= POLLOUT;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Start new write and exception operations. The handler object will be
+ // invoked when the given descriptor is ready for writing or has exception
+ // information available, or an error has occurred.
+ template <typename Handler>
+ void start_write_and_except_ops(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler);
+ need_mod = except_op_queue_.enqueue_operation(descriptor, handler)
+ && need_mod;
+ if (need_mod)
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= POLLIN;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Enqueue cancellation of all operations associated with the given
+ // descriptor. The handlers associated with the descriptor will be invoked
+ // with the operation_aborted error. This function does not acquire the
+ // dev_poll_reactor's mutex, and so should only be used from within a reactor
+ // handler.
+ void enqueue_cancel_ops_unlocked(socket_type descriptor)
+ {
+ pending_cancellations_.push_back(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from /dev/poll.
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLREMOVE;
+ interrupter_.interrupt();
+
+ // Cancel any outstanding operations associated with the descriptor.
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // Cancel the timer associated with the given token. Returns the number of
+ // handlers that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<dev_poll_reactor<Own_Thread> >;
+
+ // Run /dev/poll once until interrupted or events are ready to be dispatched.
+ void run(bool block)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ except_op_queue_.dispatch_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ // Write the pending event registration changes to the /dev/poll descriptor.
+ std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
+ errno = 0;
+ int result = ::write(dev_poll_fd_,
+ &pending_event_changes_[0], events_size);
+ if (result != static_cast<int>(events_size))
+ {
+ for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
+ {
+ int descriptor = pending_event_changes_[i].fd;
+ asio::error_code ec = asio::error_code(
+ errno, asio::error::get_system_category());
+ read_op_queue_.dispatch_all_operations(descriptor, ec);
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ pending_event_changes_.clear();
+ pending_event_change_index_.clear();
+
+ int timeout = block ? get_timeout() : 0;
+ wait_in_progress_ = true;
+ lock.unlock();
+
+ // Block on the /dev/poll descriptor.
+ ::pollfd events[128] = { { 0 } };
+ ::dvpoll dp = { 0 };
+ dp.dp_fds = events;
+ dp.dp_nfds = 128;
+ dp.dp_timeout = timeout;
+ int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
+
+ lock.lock();
+ wait_in_progress_ = false;
+
+ // Block signals while dispatching operations.
+ asio::detail::signal_blocker sb;
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].fd;
+ if (descriptor == interrupter_.read_descriptor())
+ {
+ interrupter_.reset();
+ }
+ else
+ {
+ bool more_reads = false;
+ bool more_writes = false;
+ bool more_except = false;
+ asio::error_code ec;
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
+ more_except = except_op_queue_.dispatch_operation(descriptor, ec);
+ else
+ more_except = except_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (POLLIN | POLLERR | POLLHUP))
+ more_reads = read_op_queue_.dispatch_operation(descriptor, ec);
+ else
+ more_reads = read_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
+ more_writes = write_op_queue_.dispatch_operation(descriptor, ec);
+ else
+ more_writes = write_op_queue_.has_operation(descriptor);
+
+ if ((events[i].events == POLLHUP)
+ && !more_except && !more_reads && !more_writes)
+ {
+ // If we have only an POLLHUP event and no operations associated
+ // with the descriptor then we need to delete the descriptor from
+ // /dev/poll. The poll operation might produce POLLHUP events even
+ // if they are not specifically requested, so if we do not remove the
+ // descriptor we can end up in a tight polling loop.
+ ::pollfd ev = { 0 };
+ ev.fd = descriptor;
+ ev.events = POLLREMOVE;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+ }
+ else
+ {
+ ::pollfd ev = { 0 };
+ ev.fd = descriptor;
+ ev.events = POLLERR | POLLHUP;
+ if (more_reads)
+ ev.events |= POLLIN;
+ if (more_writes)
+ ev.events |= POLLOUT;
+ if (more_except)
+ ev.events |= POLLPRI;
+ ev.revents = 0;
+ int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
+ if (result != sizeof(ev))
+ {
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+ read_op_queue_.dispatch_all_operations(descriptor, ec);
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+ }
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ except_op_queue_.dispatch_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ cleanup_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(dev_poll_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // Create the /dev/poll file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ static int do_dev_poll_create()
+ {
+ int fd = ::open("/dev/poll", O_RDWR);
+ if (fd == -1)
+ {
+ boost::throw_exception(
+ asio::system_error(
+ asio::error_code(errno,
+ asio::error::get_system_category()),
+ "/dev/poll"));
+ }
+ return fd;
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the /dev/poll DP_POLL operation. The timeout
+ // value is returned as a number of milliseconds. A return value of -1
+ // indicates that the poll should block indefinitely.
+ int get_timeout()
+ {
+ if (all_timer_queues_are_empty())
+ return -1;
+
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ int milliseconds = minimum_wait_duration.total_milliseconds();
+ return milliseconds > 0 ? milliseconds : 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The do_cancel
+ // function of the handler objects will be invoked. This function does not
+ // acquire the dev_poll_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void cleanup_operations_and_timers(
+ asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.cleanup_operations();
+ write_op_queue_.cleanup_operations();
+ except_op_queue_.cleanup_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->cleanup_timers();
+ }
+
+ // Add a pending event entry for the given descriptor.
+ ::pollfd& add_pending_event_change(int descriptor)
+ {
+ hash_map<int, std::size_t>::iterator iter
+ = pending_event_change_index_.find(descriptor);
+ if (iter == pending_event_change_index_.end())
+ {
+ std::size_t index = pending_event_changes_.size();
+ pending_event_changes_.reserve(pending_event_changes_.size() + 1);
+ pending_event_change_index_.insert(std::make_pair(descriptor, index));
+ pending_event_changes_.push_back(::pollfd());
+ pending_event_changes_[index].fd = descriptor;
+ pending_event_changes_[index].revents = 0;
+ return pending_event_changes_[index];
+ }
+ else
+ {
+ return pending_event_changes_[iter->second];
+ }
+ }
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // The /dev/poll file descriptor.
+ int dev_poll_fd_;
+
+ // Vector of /dev/poll events waiting to be written to the descriptor.
+ std::vector< ::pollfd> pending_event_changes_;
+
+ // Hash map to associate a descriptor with a pending event change index.
+ hash_map<int, std::size_t> pending_event_change_index_;
+
+ // Whether the DP_POLL operation is currently in progress
+ bool wait_in_progress_;
+
+ // The interrupter is used to break a blocking DP_POLL operation.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of except operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP
diff --git a/src/libtorrent/asio/detail/dev_poll_reactor_fwd.hpp b/src/libtorrent/asio/detail/dev_poll_reactor_fwd.hpp
new file mode 100644
index 0000000..f3c6da1
--- /dev/null
+++ b/src/libtorrent/asio/detail/dev_poll_reactor_fwd.hpp
@@ -0,0 +1,40 @@
+//
+// dev_poll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
+#define ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#if !defined(ASIO_DISABLE_DEV_POLL)
+#if defined(__sun) // This service is only supported on Solaris.
+
+// Define this to indicate that /dev/poll is supported on the target platform.
+#define ASIO_HAS_DEV_POLL 1
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class dev_poll_reactor;
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(__sun)
+#endif // !defined(ASIO_DISABLE_DEV_POLL)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
diff --git a/src/libtorrent/asio/detail/epoll_reactor.hpp b/src/libtorrent/asio/detail/epoll_reactor.hpp
new file mode 100644
index 0000000..1cf257e
--- /dev/null
+++ b/src/libtorrent/asio/detail/epoll_reactor.hpp
@@ -0,0 +1,660 @@
+//
+// epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_EPOLL_REACTOR_HPP
+#define ASIO_DETAIL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/epoll_reactor_fwd.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <vector>
+#include <sys/epoll.h>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/task_io_service.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue.hpp"
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class epoll_reactor
+ : public asio::detail::service_base<epoll_reactor<Own_Thread> >
+{
+public:
+ // Constructor.
+ epoll_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<epoll_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ epoll_fd_(do_epoll_create()),
+ wait_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false),
+ need_epoll_wait_(true)
+ {
+ // Start the reactor's internal thread only if needed.
+ if (Own_Thread)
+ {
+ asio::detail::signal_blocker sb;
+ thread_ = new asio::detail::thread(
+ bind_handler(&epoll_reactor::call_run_thread, this));
+ }
+
+ // Add the interrupter's descriptor to epoll.
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR;
+ ev.data.fd = interrupter_.read_descriptor();
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+ }
+
+ // Destructor.
+ ~epoll_reactor()
+ {
+ shutdown_service();
+ close(epoll_fd_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type descriptor)
+ {
+ // No need to lock according to epoll documentation.
+
+ epoll_event ev = { 0, { 0 } };
+ ev.events = 0;
+ ev.data.fd = descriptor;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ return errno;
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor, Handler handler,
+ bool allow_speculative_read = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_read)
+ need_epoll_wait_ = true;
+ else if (!read_op_queue_.has_operation(descriptor))
+ if (handler(asio::error_code()))
+ return;
+
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLOUT;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLPRI;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ read_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor, Handler handler,
+ bool allow_speculative_write = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_write)
+ need_epoll_wait_ = true;
+ else if (!write_op_queue_.has_operation(descriptor))
+ if (handler(asio::error_code()))
+ return;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLIN;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLPRI;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLIN;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLOUT;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start new write and exception operations. The handler object will be
+ // invoked when the given descriptor is ready for writing or has exception
+ // information available, or an error has occurred.
+ template <typename Handler>
+ void start_write_and_except_ops(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler);
+ need_mod = except_op_queue_.enqueue_operation(descriptor, handler)
+ && need_mod;
+ if (need_mod)
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLIN;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Enqueue cancellation of all operations associated with the given
+ // descriptor. The handlers associated with the descriptor will be invoked
+ // with the operation_aborted error. This function does not acquire the
+ // epoll_reactor's mutex, and so should only be used from within a reactor
+ // handler.
+ void enqueue_cancel_ops_unlocked(socket_type descriptor)
+ {
+ pending_cancellations_.push_back(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from epoll.
+ epoll_event ev = { 0, { 0 } };
+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+
+ // Cancel any outstanding operations associated with the descriptor.
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // Cancel the timer associated with the given token. Returns the number of
+ // handlers that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<epoll_reactor<Own_Thread> >;
+
+ // Run epoll once until interrupted or events are ready to be dispatched.
+ void run(bool block)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ except_op_queue_.dispatch_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ int timeout = block ? get_timeout() : 0;
+ wait_in_progress_ = true;
+ lock.unlock();
+
+ // Block on the epoll descriptor.
+ epoll_event events[128];
+ int num_events = (block || need_epoll_wait_)
+ ? epoll_wait(epoll_fd_, events, 128, timeout)
+ : 0;
+
+ lock.lock();
+ wait_in_progress_ = false;
+
+ // Block signals while dispatching operations.
+ asio::detail::signal_blocker sb;
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].data.fd;
+ if (descriptor == interrupter_.read_descriptor())
+ {
+ interrupter_.reset();
+ }
+ else
+ {
+ bool more_reads = false;
+ bool more_writes = false;
+ bool more_except = false;
+ asio::error_code ec;
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP))
+ more_except = except_op_queue_.dispatch_operation(descriptor, ec);
+ else
+ more_except = except_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))
+ more_reads = read_op_queue_.dispatch_operation(descriptor, ec);
+ else
+ more_reads = read_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
+ more_writes = write_op_queue_.dispatch_operation(descriptor, ec);
+ else
+ more_writes = write_op_queue_.has_operation(descriptor);
+
+ if ((events[i].events == EPOLLHUP)
+ && !more_except && !more_reads && !more_writes)
+ {
+ // If we have only an EPOLLHUP event and no operations associated
+ // with the descriptor then we need to delete the descriptor from
+ // epoll. The epoll_wait system call will produce EPOLLHUP events
+ // even if they are not specifically requested, so if we do not
+ // remove the descriptor we can end up in a tight loop of repeated
+ // calls to epoll_wait.
+ epoll_event ev = { 0, { 0 } };
+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+ }
+ else
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLERR | EPOLLHUP;
+ if (more_reads)
+ ev.events |= EPOLLIN;
+ if (more_writes)
+ ev.events |= EPOLLOUT;
+ if (more_except)
+ ev.events |= EPOLLPRI;
+ ev.data.fd = descriptor;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+ read_op_queue_.dispatch_all_operations(descriptor, ec);
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+ }
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ except_op_queue_.dispatch_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ // Determine whether epoll_wait should be called when the reactor next runs.
+ need_epoll_wait_ = !read_op_queue_.empty()
+ || !write_op_queue_.empty() || !except_op_queue_.empty();
+
+ cleanup_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(epoll_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // The hint to pass to epoll_create to size its data structures.
+ enum { epoll_size = 20000 };
+
+ // Create the epoll file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ static int do_epoll_create()
+ {
+ int fd = epoll_create(epoll_size);
+ if (fd == -1)
+ {
+ boost::throw_exception(
+ asio::system_error(
+ asio::error_code(errno,
+ asio::error::get_system_category()),
+ "epoll"));
+ }
+ return fd;
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the epoll_wait call. The timeout value is
+ // returned as a number of milliseconds. A return value of -1 indicates
+ // that epoll_wait should block indefinitely.
+ int get_timeout()
+ {
+ if (all_timer_queues_are_empty())
+ return -1;
+
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ int milliseconds = minimum_wait_duration.total_milliseconds();
+ return milliseconds > 0 ? milliseconds : 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The do_cancel
+ // function of the handler objects will be invoked. This function does not
+ // acquire the epoll_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void cleanup_operations_and_timers(
+ asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.cleanup_operations();
+ write_op_queue_.cleanup_operations();
+ except_op_queue_.cleanup_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->cleanup_timers();
+ }
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // The epoll file descriptor.
+ int epoll_fd_;
+
+ // Whether the epoll_wait call is currently in progress
+ bool wait_in_progress_;
+
+ // The interrupter is used to break a blocking epoll_wait call.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of except operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+
+ // Whether we need to call epoll_wait the next time the reactor is run.
+ bool need_epoll_wait_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP
diff --git a/src/libtorrent/asio/detail/epoll_reactor_fwd.hpp b/src/libtorrent/asio/detail/epoll_reactor_fwd.hpp
new file mode 100644
index 0000000..601ce81
--- /dev/null
+++ b/src/libtorrent/asio/detail/epoll_reactor_fwd.hpp
@@ -0,0 +1,47 @@
+//
+// epoll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
+#define ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#if !defined(ASIO_DISABLE_EPOLL)
+#if defined(__linux__) // This service is only supported on Linux.
+
+#include "asio/detail/push_options.hpp"
+#include <linux/version.h>
+#include "asio/detail/pop_options.hpp"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45.
+
+// Define this to indicate that epoll is supported on the target platform.
+#define ASIO_HAS_EPOLL 1
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class epoll_reactor;
+
+} // namespace detail
+} // namespace asio
+
+#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
+#endif // defined(__linux__)
+#endif // !defined(ASIO_DISABLE_EPOLL)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
diff --git a/src/libtorrent/asio/detail/event.hpp b/src/libtorrent/asio/detail/event.hpp
new file mode 100644
index 0000000..1f959d7
--- /dev/null
+++ b/src/libtorrent/asio/detail/event.hpp
@@ -0,0 +1,50 @@
+//
+// event.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_EVENT_HPP
+#define ASIO_DETAIL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+# include "asio/detail/null_event.hpp"
+#elif defined(BOOST_WINDOWS)
+# include "asio/detail/win_event.hpp"
+#elif defined(BOOST_HAS_PTHREADS)
+# include "asio/detail/posix_event.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_event event;
+#elif defined(BOOST_WINDOWS)
+typedef win_event event;
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_event event;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_EVENT_HPP
diff --git a/src/libtorrent/asio/detail/fd_set_adapter.hpp b/src/libtorrent/asio/detail/fd_set_adapter.hpp
new file mode 100644
index 0000000..5ae31b1
--- /dev/null
+++ b/src/libtorrent/asio/detail/fd_set_adapter.hpp
@@ -0,0 +1,41 @@
+//
+// fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/posix_fd_set_adapter.hpp"
+#include "asio/detail/win_fd_set_adapter.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef win_fd_set_adapter fd_set_adapter;
+#else
+typedef posix_fd_set_adapter fd_set_adapter;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP
diff --git a/src/libtorrent/asio/detail/handler_alloc_helpers.hpp b/src/libtorrent/asio/detail/handler_alloc_helpers.hpp
new file mode 100644
index 0000000..22b54e7
--- /dev/null
+++ b/src/libtorrent/asio/detail/handler_alloc_helpers.hpp
@@ -0,0 +1,256 @@
+//
+// handler_alloc_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/handler_alloc_hook.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+// Calls to asio_handler_allocate and asio_handler_deallocate must be made from
+// a namespace that does not contain any overloads of these functions. The
+// asio_handler_alloc_helpers namespace is defined here for that purpose.
+namespace asio_handler_alloc_helpers {
+
+template <typename Handler>
+inline void* allocate(std::size_t s, Handler* h)
+{
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+ return ::operator new(s);
+#else
+ using namespace asio;
+ return asio_handler_allocate(s, h);
+#endif
+}
+
+template <typename Handler>
+inline void deallocate(void* p, std::size_t s, Handler* h)
+{
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+ ::operator delete(p);
+#else
+ using namespace asio;
+ asio_handler_deallocate(p, s, h);
+#endif
+}
+
+} // namespace asio_handler_alloc_helpers
+
+namespace asio {
+namespace detail {
+
+// Traits for handler allocation.
+template <typename Handler, typename Object>
+struct handler_alloc_traits
+{
+ typedef Handler handler_type;
+ typedef Object value_type;
+ typedef Object* pointer_type;
+ BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object));
+};
+
+template <typename Alloc_Traits>
+class handler_ptr;
+
+// Helper class to provide RAII on uninitialised handler memory.
+template <typename Alloc_Traits>
+class raw_handler_ptr
+ : private noncopyable
+{
+public:
+ typedef typename Alloc_Traits::handler_type handler_type;
+ typedef typename Alloc_Traits::value_type value_type;
+ typedef typename Alloc_Traits::pointer_type pointer_type;
+ BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
+
+ // Constructor allocates the memory.
+ raw_handler_ptr(handler_type& handler)
+ : handler_(handler),
+ pointer_(static_cast<pointer_type>(
+ asio_handler_alloc_helpers::allocate(value_size, &handler_)))
+ {
+ }
+
+ // Destructor automatically deallocates memory, unless it has been stolen by
+ // a handler_ptr object.
+ ~raw_handler_ptr()
+ {
+ if (pointer_)
+ asio_handler_alloc_helpers::deallocate(
+ pointer_, value_size, &handler_);
+ }
+
+private:
+ friend class handler_ptr<Alloc_Traits>;
+ handler_type& handler_;
+ pointer_type pointer_;
+};
+
+// Helper class to provide RAII on uninitialised handler memory.
+template <typename Alloc_Traits>
+class handler_ptr
+ : private noncopyable
+{
+public:
+ typedef typename Alloc_Traits::handler_type handler_type;
+ typedef typename Alloc_Traits::value_type value_type;
+ typedef typename Alloc_Traits::pointer_type pointer_type;
+ BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
+ typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
+
+ // Take ownership of existing memory.
+ handler_ptr(handler_type& handler, pointer_type pointer)
+ : handler_(handler),
+ pointer_(pointer)
+ {
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ handler_ptr(raw_ptr_type& raw_ptr)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type)
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5, typename Arg6>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5, Arg6& a6)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5, typename Arg6, typename Arg7>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5, Arg6& a6, Arg7& a7)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5, typename Arg6, typename Arg7, typename Arg8>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(
+ a1, a2, a3, a4, a5, a6, a7, a8))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Destructor automatically deallocates memory, unless it has been released.
+ ~handler_ptr()
+ {
+ reset();
+ }
+
+ // Get the memory.
+ pointer_type get() const
+ {
+ return pointer_;
+ }
+
+ // Release ownership of the memory.
+ pointer_type release()
+ {
+ pointer_type tmp = pointer_;
+ pointer_ = 0;
+ return tmp;
+ }
+
+ // Explicitly destroy and deallocate the memory.
+ void reset()
+ {
+ if (pointer_)
+ {
+ pointer_->value_type::~value_type();
+ asio_handler_alloc_helpers::deallocate(
+ pointer_, value_size, &handler_);
+ pointer_ = 0;
+ }
+ }
+
+private:
+ handler_type& handler_;
+ pointer_type pointer_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
diff --git a/src/libtorrent/asio/detail/handler_invoke_helpers.hpp b/src/libtorrent/asio/detail/handler_invoke_helpers.hpp
new file mode 100644
index 0000000..9bdb049
--- /dev/null
+++ b/src/libtorrent/asio/detail/handler_invoke_helpers.hpp
@@ -0,0 +1,47 @@
+//
+// handler_invoke_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/handler_invoke_hook.hpp"
+
+// Calls to asio_handler_invoke must be made from a namespace that does not
+// contain overloads of this function. The asio_handler_invoke_helpers
+// namespace is defined here for that purpose.
+namespace asio_handler_invoke_helpers {
+
+template <typename Function, typename Context>
+inline void invoke(const Function& function, Context* context)
+{
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+ Function tmp(function);
+ tmp();
+#else
+ using namespace asio;
+ asio_handler_invoke(function, context);
+#endif
+}
+
+} // namespace asio_handler_invoke_helpers
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
diff --git a/src/libtorrent/asio/detail/handler_queue.hpp b/src/libtorrent/asio/detail/handler_queue.hpp
new file mode 100644
index 0000000..63c78a7
--- /dev/null
+++ b/src/libtorrent/asio/detail/handler_queue.hpp
@@ -0,0 +1,219 @@
+//
+// handler_queue.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_HANDLER_QUEUE_HPP
+#define ASIO_DETAIL_HANDLER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class handler_queue
+ : private noncopyable
+{
+public:
+ // Base class for handlers in the queue.
+ class handler
+ : private noncopyable
+ {
+ public:
+ void invoke()
+ {
+ invoke_func_(this);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*invoke_func_type)(handler*);
+ typedef void (*destroy_func_type)(handler*);
+
+ handler(invoke_func_type invoke_func,
+ destroy_func_type destroy_func)
+ : next_(0),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ }
+
+ ~handler()
+ {
+ }
+
+ private:
+ friend class handler_queue;
+ handler* next_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ // Smart point to manager handler lifetimes.
+ class scoped_ptr
+ : private noncopyable
+ {
+ public:
+ explicit scoped_ptr(handler* h)
+ : handler_(h)
+ {
+ }
+
+ ~scoped_ptr()
+ {
+ if (handler_)
+ handler_->destroy();
+ }
+
+ handler* get() const
+ {
+ return handler_;
+ }
+
+ handler* release()
+ {
+ handler* tmp = handler_;
+ handler_ = 0;
+ return tmp;
+ }
+
+ private:
+ handler* handler_;
+ };
+
+ // Constructor.
+ handler_queue()
+ : front_(0),
+ back_(0)
+ {
+ }
+
+ // Wrap a handler to be pushed into the queue.
+ template <typename Handler>
+ static handler* wrap(Handler h)
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(h);
+ handler_ptr<alloc_traits> ptr(raw_ptr, h);
+ return ptr.release();
+ }
+
+ // Get the handler at the front of the queue.
+ handler* front()
+ {
+ return front_;
+ }
+
+ // Pop a handler from the front of the queue.
+ void pop()
+ {
+ if (front_)
+ {
+ handler* tmp = front_;
+ front_ = front_->next_;
+ if (front_ == 0)
+ back_ = 0;
+ tmp->next_= 0;
+ }
+ }
+
+ // Push a handler on to the back of the queue.
+ void push(handler* h)
+ {
+ h->next_ = 0;
+ if (back_)
+ {
+ back_->next_ = h;
+ back_ = h;
+ }
+ else
+ {
+ front_ = back_ = h;
+ }
+ }
+
+ // Whether the queue is empty.
+ bool empty() const
+ {
+ return front_ == 0;
+ }
+
+private:
+ // Template wrapper for handlers.
+ template <typename Handler>
+ class handler_wrapper
+ : public handler
+ {
+ public:
+ handler_wrapper(Handler h)
+ : handler(
+ &handler_wrapper<Handler>::do_call,
+ &handler_wrapper<Handler>::do_destroy),
+ handler_(h)
+ {
+ }
+
+ static void do_call(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(h->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void do_destroy(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // The front of the queue.
+ handler* front_;
+
+ // The back of the queue.
+ handler* back_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_QUEUE_HPP
diff --git a/src/libtorrent/asio/detail/hash_map.hpp b/src/libtorrent/asio/detail/hash_map.hpp
new file mode 100644
index 0000000..8560e58
--- /dev/null
+++ b/src/libtorrent/asio/detail/hash_map.hpp
@@ -0,0 +1,209 @@
+//
+// hash_map.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_HASH_MAP_HPP
+#define ASIO_DETAIL_HASH_MAP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cassert>
+#include <list>
+#include <utility>
+#include <boost/functional/hash.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+inline std::size_t calculate_hash_value(const T& t)
+{
+ return boost::hash_value(t);
+}
+
+#if defined(_WIN64)
+inline std::size_t calculate_hash_value(SOCKET s)
+{
+ return static_cast<std::size_t>(s);
+}
+#endif // defined(_WIN64)
+
+template <typename K, typename V>
+class hash_map
+ : private noncopyable
+{
+public:
+ // The type of a value in the map.
+ typedef std::pair<K, V> value_type;
+
+ // The type of a non-const iterator over the hash map.
+ typedef typename std::list<value_type>::iterator iterator;
+
+ // The type of a const iterator over the hash map.
+ typedef typename std::list<value_type>::const_iterator const_iterator;
+
+ // Constructor.
+ hash_map()
+ {
+ // Initialise all buckets to empty.
+ for (size_t i = 0; i < num_buckets; ++i)
+ buckets_[i].first = buckets_[i].last = values_.end();
+ }
+
+ // Get an iterator for the beginning of the map.
+ iterator begin()
+ {
+ return values_.begin();
+ }
+
+ // Get an iterator for the beginning of the map.
+ const_iterator begin() const
+ {
+ return values_.begin();
+ }
+
+ // Get an iterator for the end of the map.
+ iterator end()
+ {
+ return values_.end();
+ }
+
+ // Get an iterator for the end of the map.
+ const_iterator end() const
+ {
+ return values_.end();
+ }
+
+ // Check whether the map is empty.
+ bool empty() const
+ {
+ return values_.empty();
+ }
+
+ // Find an entry in the map.
+ iterator find(const K& k)
+ {
+ size_t bucket = calculate_hash_value(k) % num_buckets;
+ iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ return values_.end();
+ iterator end = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ if (it->first == k)
+ return it;
+ ++it;
+ }
+ return values_.end();
+ }
+
+ // Find an entry in the map.
+ const_iterator find(const K& k) const
+ {
+ size_t bucket = calculate_hash_value(k) % num_buckets;
+ const_iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ return it;
+ const_iterator end = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ if (it->first == k)
+ return it;
+ ++it;
+ }
+ return values_.end();
+ }
+
+ // Insert a new entry into the map.
+ std::pair<iterator, bool> insert(const value_type& v)
+ {
+ size_t bucket = calculate_hash_value(v.first) % num_buckets;
+ iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ {
+ buckets_[bucket].first = buckets_[bucket].last =
+ values_.insert(values_.end(), v);
+ return std::pair<iterator, bool>(buckets_[bucket].last, true);
+ }
+ iterator end = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ if (it->first == v.first)
+ return std::pair<iterator, bool>(it, false);
+ ++it;
+ }
+ buckets_[bucket].last = values_.insert(end, v);
+ return std::pair<iterator, bool>(buckets_[bucket].last, true);
+ }
+
+ // Erase an entry from the map.
+ void erase(iterator it)
+ {
+ assert(it != values_.end());
+
+ size_t bucket = calculate_hash_value(it->first) % num_buckets;
+ bool is_first = (it == buckets_[bucket].first);
+ bool is_last = (it == buckets_[bucket].last);
+ if (is_first && is_last)
+ buckets_[bucket].first = buckets_[bucket].last = values_.end();
+ else if (is_first)
+ ++buckets_[bucket].first;
+ else if (is_last)
+ --buckets_[bucket].last;
+
+ values_.erase(it);
+ }
+
+ // Remove all entries from the map.
+ void clear()
+ {
+ // Clear the values.
+ values_.clear();
+
+ // Initialise all buckets to empty.
+ for (size_t i = 0; i < num_buckets; ++i)
+ buckets_[i].first = buckets_[i].last = values_.end();
+ }
+
+private:
+ // The list of all values in the hash map.
+ std::list<value_type> values_;
+
+ // The type for a bucket in the hash table.
+ struct bucket_type
+ {
+ iterator first;
+ iterator last;
+ };
+
+ // The number of buckets in the hash.
+ enum { num_buckets = 1021 };
+
+ // The buckets in the hash.
+ bucket_type buckets_[num_buckets];
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HASH_MAP_HPP
diff --git a/src/libtorrent/asio/detail/io_control.hpp b/src/libtorrent/asio/detail/io_control.hpp
new file mode 100644
index 0000000..cc18678
--- /dev/null
+++ b/src/libtorrent/asio/detail/io_control.hpp
@@ -0,0 +1,137 @@
+//
+// io_control.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_IO_CONTROL_HPP
+#define ASIO_DETAIL_IO_CONTROL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+namespace io_control {
+
+// IO control command for non-blocking I/O.
+class non_blocking_io
+{
+public:
+ // Default constructor.
+ non_blocking_io()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific command value.
+ non_blocking_io(bool value)
+ : value_(value ? 1 : 0)
+ {
+ }
+
+ // Get the name of the IO control command.
+ int name() const
+ {
+ return FIONBIO;
+ }
+
+ // Set the value of the I/O control command.
+ void set(bool value)
+ {
+ value_ = value ? 1 : 0;
+ }
+
+ // Get the current value of the I/O control command.
+ bool get() const
+ {
+ return value_ != 0;
+ }
+
+ // Get the address of the command data.
+ detail::ioctl_arg_type* data()
+ {
+ return &value_;
+ }
+
+ // Get the address of the command data.
+ const detail::ioctl_arg_type* data() const
+ {
+ return &value_;
+ }
+
+private:
+ detail::ioctl_arg_type value_;
+};
+
+// I/O control command for getting number of bytes available.
+class bytes_readable
+{
+public:
+ // Default constructor.
+ bytes_readable()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific command value.
+ bytes_readable(std::size_t value)
+ : value_(static_cast<detail::ioctl_arg_type>(value))
+ {
+ }
+
+ // Get the name of the IO control command.
+ int name() const
+ {
+ return FIONREAD;
+ }
+
+ // Set the value of the I/O control command.
+ void set(std::size_t value)
+ {
+ value_ = static_cast<detail::ioctl_arg_type>(value);
+ }
+
+ // Get the current value of the I/O control command.
+ std::size_t get() const
+ {
+ return static_cast<std::size_t>(value_);
+ }
+
+ // Get the address of the command data.
+ detail::ioctl_arg_type* data()
+ {
+ return &value_;
+ }
+
+ // Get the address of the command data.
+ const detail::ioctl_arg_type* data() const
+ {
+ return &value_;
+ }
+
+private:
+ detail::ioctl_arg_type value_;
+};
+
+} // namespace io_control
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IO_CONTROL_HPP
diff --git a/src/libtorrent/asio/detail/kqueue_reactor.hpp b/src/libtorrent/asio/detail/kqueue_reactor.hpp
new file mode 100644
index 0000000..2721b59
--- /dev/null
+++ b/src/libtorrent/asio/detail/kqueue_reactor.hpp
@@ -0,0 +1,658 @@
+//
+// kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_KQUEUE_REACTOR_HPP
+#define ASIO_DETAIL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/kqueue_reactor_fwd.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <vector>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/task_io_service.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue.hpp"
+
+// Older versions of Mac OS X may not define EV_OOBAND.
+#if !defined(EV_OOBAND)
+# define EV_OOBAND EV_FLAG1
+#endif // !defined(EV_OOBAND)
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class kqueue_reactor
+ : public asio::detail::service_base<kqueue_reactor<Own_Thread> >
+{
+public:
+ // Constructor.
+ kqueue_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<
+ kqueue_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ kqueue_fd_(do_kqueue_create()),
+ wait_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false),
+ need_kqueue_wait_(true)
+ {
+ // Start the reactor's internal thread only if needed.
+ if (Own_Thread)
+ {
+ asio::detail::signal_blocker sb;
+ thread_ = new asio::detail::thread(
+ bind_handler(&kqueue_reactor::call_run_thread, this));
+ }
+
+ // Add the interrupter's descriptor to the kqueue.
+ struct kevent event;
+ EV_SET(&event, interrupter_.read_descriptor(),
+ EVFILT_READ, EV_ADD, 0, 0, 0);
+ ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
+ }
+
+ // Destructor.
+ ~kqueue_reactor()
+ {
+ shutdown_service();
+ close(kqueue_fd_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type)
+ {
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor, Handler handler,
+ bool allow_speculative_read = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_read)
+ need_kqueue_wait_ = true;
+ else if (!read_op_queue_.has_operation(descriptor))
+ if (handler(asio::error_code()))
+ return;
+
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ read_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor, Handler handler,
+ bool allow_speculative_write = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_write)
+ need_kqueue_wait_ = true;
+ else if (!write_op_queue_.has_operation(descriptor))
+ if (handler(asio::error_code()))
+ return;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ if (read_op_queue_.has_operation(descriptor))
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ else
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start new write and exception operations. The handler object will be
+ // invoked when the given descriptor is ready for writing or has exception
+ // information available, or an error has occurred.
+ template <typename Handler>
+ void start_write_and_except_ops(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ if (read_op_queue_.has_operation(descriptor))
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ else
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Enqueue cancellation of all operations associated with the given
+ // descriptor. The handlers associated with the descriptor will be invoked
+ // with the operation_aborted error. This function does not acquire the
+ // kqueue_reactor's mutex, and so should only be used from within a reactor
+ // handler.
+ void enqueue_cancel_ops_unlocked(socket_type descriptor)
+ {
+ pending_cancellations_.push_back(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from kqueue.
+ struct kevent event[2];
+ EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
+ EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ ::kevent(kqueue_fd_, event, 2, 0, 0, 0);
+
+ // Cancel any outstanding operations associated with the descriptor.
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // Cancel the timer associated with the given token. Returns the number of
+ // handlers that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<kqueue_reactor<Own_Thread> >;
+
+ // Run the kqueue loop.
+ void run(bool block)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ except_op_queue_.dispatch_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ // Determine how long to block while waiting for events.
+ timespec timeout_buf = { 0, 0 };
+ timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
+
+ wait_in_progress_ = true;
+ lock.unlock();
+
+ // Block on the kqueue descriptor.
+ struct kevent events[128];
+ int num_events = (block || need_kqueue_wait_)
+ ? kevent(kqueue_fd_, 0, 0, events, 128, timeout)
+ : 0;
+
+ lock.lock();
+ wait_in_progress_ = false;
+
+ // Block signals while dispatching operations.
+ asio::detail::signal_blocker sb;
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].ident;
+ if (descriptor == interrupter_.read_descriptor())
+ {
+ interrupter_.reset();
+ }
+ else if (events[i].filter == EVFILT_READ)
+ {
+ // Dispatch operations associated with the descriptor.
+ bool more_reads = false;
+ bool more_except = false;
+ if (events[i].flags & EV_ERROR)
+ {
+ asio::error_code error(
+ events[i].data, asio::error::get_system_category());
+ except_op_queue_.dispatch_all_operations(descriptor, error);
+ read_op_queue_.dispatch_all_operations(descriptor, error);
+ }
+ else if (events[i].flags & EV_OOBAND)
+ {
+ asio::error_code error;
+ more_except = except_op_queue_.dispatch_operation(descriptor, error);
+ if (events[i].data > 0)
+ more_reads = read_op_queue_.dispatch_operation(descriptor, error);
+ else
+ more_reads = read_op_queue_.has_operation(descriptor);
+ }
+ else
+ {
+ asio::error_code error;
+ more_reads = read_op_queue_.dispatch_operation(descriptor, error);
+ more_except = except_op_queue_.has_operation(descriptor);
+ }
+
+ // Update the descriptor in the kqueue.
+ struct kevent event;
+ if (more_reads)
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ else if (more_except)
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
+ else
+ EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code error(errno,
+ asio::error::get_system_category());
+ except_op_queue_.dispatch_all_operations(descriptor, error);
+ read_op_queue_.dispatch_all_operations(descriptor, error);
+ }
+ }
+ else if (events[i].filter == EVFILT_WRITE)
+ {
+ // Dispatch operations associated with the descriptor.
+ bool more_writes = false;
+ if (events[i].flags & EV_ERROR)
+ {
+ asio::error_code error(
+ events[i].data, asio::error::get_system_category());
+ write_op_queue_.dispatch_all_operations(descriptor, error);
+ }
+ else
+ {
+ asio::error_code error;
+ more_writes = write_op_queue_.dispatch_operation(descriptor, error);
+ }
+
+ // Update the descriptor in the kqueue.
+ struct kevent event;
+ if (more_writes)
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+ else
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code error(errno,
+ asio::error::get_system_category());
+ write_op_queue_.dispatch_all_operations(descriptor, error);
+ }
+ }
+ }
+
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ except_op_queue_.dispatch_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (std::size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ // Determine whether kqueue needs to be called next time the reactor is run.
+ need_kqueue_wait_ = !read_op_queue_.empty()
+ || !write_op_queue_.empty() || !except_op_queue_.empty();
+
+ cleanup_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(kqueue_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // Create the kqueue file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ static int do_kqueue_create()
+ {
+ int fd = kqueue();
+ if (fd == -1)
+ {
+ boost::throw_exception(
+ asio::system_error(
+ asio::error_code(errno,
+ asio::error::get_system_category()),
+ "kqueue"));
+ }
+ return fd;
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the kevent call.
+ timespec* get_timeout(timespec& ts)
+ {
+ if (all_timer_queues_are_empty())
+ return 0;
+
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ ts.tv_sec = minimum_wait_duration.total_seconds();
+ ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000;
+ }
+ else
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+
+ return &ts;
+ }
+
+ // Cancel all operations associated with the given descriptor. The do_cancel
+ // function of the handler objects will be invoked. This function does not
+ // acquire the kqueue_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void cleanup_operations_and_timers(
+ asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.cleanup_operations();
+ write_op_queue_.cleanup_operations();
+ except_op_queue_.cleanup_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->cleanup_timers();
+ }
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // The kqueue file descriptor.
+ int kqueue_fd_;
+
+ // Whether the kqueue wait call is currently in progress
+ bool wait_in_progress_;
+
+ // The interrupter is used to break a blocking kevent call.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of except operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+
+ // Whether we need to call kqueue the next time the reactor is run.
+ bool need_kqueue_wait_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP
diff --git a/src/libtorrent/asio/detail/kqueue_reactor_fwd.hpp b/src/libtorrent/asio/detail/kqueue_reactor_fwd.hpp
new file mode 100644
index 0000000..c81858f
--- /dev/null
+++ b/src/libtorrent/asio/detail/kqueue_reactor_fwd.hpp
@@ -0,0 +1,41 @@
+//
+// kqueue_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
+#define ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#if !defined(ASIO_DISABLE_KQUEUE)
+#if defined(__MACH__) && defined(__APPLE__)
+
+// Define this to indicate that epoll is supported on the target platform.
+#define ASIO_HAS_KQUEUE 1
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class kqueue_reactor;
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(__MACH__) && defined(__APPLE__)
+#endif // !defined(ASIO_DISABLE_KQUEUE)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
diff --git a/src/libtorrent/asio/detail/local_free_on_block_exit.hpp b/src/libtorrent/asio/detail/local_free_on_block_exit.hpp
new file mode 100644
index 0000000..e5e7a4d
--- /dev/null
+++ b/src/libtorrent/asio/detail/local_free_on_block_exit.hpp
@@ -0,0 +1,59 @@
+//
+// local_free_on_block_exit.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
+#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+
+class local_free_on_block_exit
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ explicit local_free_on_block_exit(void* p)
+ : p_(p)
+ {
+ }
+
+ // Destructor restores the previous signal mask.
+ ~local_free_on_block_exit()
+ {
+ ::LocalFree(p_);
+ }
+
+private:
+ void* p_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
diff --git a/src/libtorrent/asio/detail/mutex.hpp b/src/libtorrent/asio/detail/mutex.hpp
new file mode 100644
index 0000000..9c083f6
--- /dev/null
+++ b/src/libtorrent/asio/detail/mutex.hpp
@@ -0,0 +1,50 @@
+//
+// mutex.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_MUTEX_HPP
+#define ASIO_DETAIL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+# include "asio/detail/null_mutex.hpp"
+#elif defined(BOOST_WINDOWS)
+# include "asio/detail/win_mutex.hpp"
+#elif defined(BOOST_HAS_PTHREADS)
+# include "asio/detail/posix_mutex.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_mutex mutex;
+#elif defined(BOOST_WINDOWS)
+typedef win_mutex mutex;
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_mutex mutex;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_MUTEX_HPP
diff --git a/src/libtorrent/asio/detail/noncopyable.hpp b/src/libtorrent/asio/detail/noncopyable.hpp
new file mode 100644
index 0000000..5164e07
--- /dev/null
+++ b/src/libtorrent/asio/detail/noncopyable.hpp
@@ -0,0 +1,55 @@
+//
+// noncopyable.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_NONCOPYABLE_HPP
+#define ASIO_DETAIL_NONCOPYABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+// Redefine the noncopyable class for Borland C++ since that compiler does not
+// apply the empty base optimisation unless the base class contains a dummy
+// char data member.
+class noncopyable
+{
+protected:
+ noncopyable() {}
+ ~noncopyable() {}
+private:
+ noncopyable(const noncopyable&);
+ const noncopyable& operator=(const noncopyable&);
+ char dummy_;
+};
+#else
+using boost::noncopyable;
+#endif
+
+} // namespace detail
+
+using asio::detail::noncopyable;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NONCOPYABLE_HPP
diff --git a/src/libtorrent/asio/detail/null_event.hpp b/src/libtorrent/asio/detail/null_event.hpp
new file mode 100644
index 0000000..51529e4
--- /dev/null
+++ b/src/libtorrent/asio/detail/null_event.hpp
@@ -0,0 +1,71 @@
+//
+// null_event.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_NULL_EVENT_HPP
+#define ASIO_DETAIL_NULL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ null_event()
+ {
+ }
+
+ // Destructor.
+ ~null_event()
+ {
+ }
+
+ // Signal the event.
+ template <typename Lock>
+ void signal(Lock&)
+ {
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock&)
+ {
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock&)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_EVENT_HPP
diff --git a/src/libtorrent/asio/detail/null_mutex.hpp b/src/libtorrent/asio/detail/null_mutex.hpp
new file mode 100644
index 0000000..d29aafc
--- /dev/null
+++ b/src/libtorrent/asio/detail/null_mutex.hpp
@@ -0,0 +1,66 @@
+//
+// null_mutex.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_NULL_MUTEX_HPP
+#define ASIO_DETAIL_NULL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<null_mutex> scoped_lock;
+
+ // Constructor.
+ null_mutex()
+ {
+ }
+
+ // Destructor.
+ ~null_mutex()
+ {
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_MUTEX_HPP
diff --git a/src/libtorrent/asio/detail/null_signal_blocker.hpp b/src/libtorrent/asio/detail/null_signal_blocker.hpp
new file mode 100644
index 0000000..33f23ca
--- /dev/null
+++ b/src/libtorrent/asio/detail/null_signal_blocker.hpp
@@ -0,0 +1,63 @@
+//
+// null_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_signal_blocker
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ null_signal_blocker()
+ {
+ }
+
+ // Destructor restores the previous signal mask.
+ ~null_signal_blocker()
+ {
+ }
+
+ // Block all signals for the calling thread.
+ void block()
+ {
+ }
+
+ // Restore the previous signal mask.
+ void unblock()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
diff --git a/src/libtorrent/asio/detail/null_thread.hpp b/src/libtorrent/asio/detail/null_thread.hpp
new file mode 100644
index 0000000..f91ca53
--- /dev/null
+++ b/src/libtorrent/asio/detail/null_thread.hpp
@@ -0,0 +1,68 @@
+//
+// null_thread.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_NULL_THREAD_HPP
+#define ASIO_DETAIL_NULL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ null_thread(Function f)
+ {
+ asio::system_error e(
+ asio::error::operation_not_supported, "thread");
+ boost::throw_exception(e);
+ }
+
+ // Destructor.
+ ~null_thread()
+ {
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_THREAD_HPP
diff --git a/src/libtorrent/asio/detail/null_tss_ptr.hpp b/src/libtorrent/asio/detail/null_tss_ptr.hpp
new file mode 100644
index 0000000..0cbdae6
--- /dev/null
+++ b/src/libtorrent/asio/detail/null_tss_ptr.hpp
@@ -0,0 +1,70 @@
+//
+// null_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_NULL_TSS_PTR_HPP
+#define ASIO_DETAIL_NULL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class null_tss_ptr
+ : private noncopyable
+{
+public:
+ // Constructor.
+ null_tss_ptr()
+ : value_(0)
+ {
+ }
+
+ // Destructor.
+ ~null_tss_ptr()
+ {
+ }
+
+ // Get the value.
+ operator T*() const
+ {
+ return value_;
+ }
+
+ // Set the value.
+ void operator=(T* value)
+ {
+ value_ = value;
+ }
+
+private:
+ T* value_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP
diff --git a/src/libtorrent/asio/detail/old_win_sdk_compat.hpp b/src/libtorrent/asio/detail/old_win_sdk_compat.hpp
new file mode 100644
index 0000000..a935677
--- /dev/null
+++ b/src/libtorrent/asio/detail/old_win_sdk_compat.hpp
@@ -0,0 +1,335 @@
+//
+// old_win_sdk_compat.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Guess whether we are building against on old Platform SDK.
+#if !defined(IN6ADDR_ANY_INIT)
+#define ASIO_HAS_OLD_WIN_SDK 1
+#endif // !defined(IN6ADDR_ANY_INIT)
+
+#if defined(ASIO_HAS_OLD_WIN_SDK)
+
+// Emulation of types that are missing from old Platform SDKs.
+//
+// N.B. this emulation is also used if building for a Windows 2000 target with
+// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support
+// in that case.
+
+namespace asio {
+namespace detail {
+
+enum
+{
+ sockaddr_storage_maxsize = 128, // Maximum size.
+ sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment.
+ sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)),
+ sockaddr_storage_pad2size = (sockaddr_storage_maxsize -
+ (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize))
+};
+
+struct sockaddr_storage_emulation
+{
+ short ss_family;
+ char __ss_pad1[sockaddr_storage_pad1size];
+ __int64 __ss_align;
+ char __ss_pad2[sockaddr_storage_pad2size];
+};
+
+struct in6_addr_emulation
+{
+ union
+ {
+ u_char Byte[16];
+ u_short Word[8];
+ } u;
+};
+
+#if !defined(s6_addr)
+# define _S6_un u
+# define _S6_u8 Byte
+# define s6_addr _S6_un._S6_u8
+#endif // !defined(s6_addr)
+
+struct sockaddr_in6_emulation
+{
+ short sin6_family;
+ u_short sin6_port;
+ u_long sin6_flowinfo;
+ in6_addr_emulation sin6_addr;
+ u_long sin6_scope_id;
+};
+
+struct ipv6_mreq_emulation
+{
+ in6_addr_emulation ipv6mr_multiaddr;
+ unsigned int ipv6mr_interface;
+};
+
+#if !defined(IN6ADDR_ANY_INIT)
+# define IN6ADDR_ANY_INIT { 0 }
+#endif
+
+#if !defined(IN6ADDR_LOOPBACK_INIT)
+# define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
+#endif
+
+struct addrinfo_emulation
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char* ai_canonname;
+ sockaddr* ai_addr;
+ addrinfo_emulation* ai_next;
+};
+
+#if !defined(AI_PASSIVE)
+# define AI_PASSIVE 0x1
+#endif
+
+#if !defined(AI_CANONNAME)
+# define AI_CANONNAME 0x2
+#endif
+
+#if !defined(AI_NUMERICHOST)
+# define AI_NUMERICHOST 0x4
+#endif
+
+#if !defined(EAI_AGAIN)
+# define EAI_AGAIN WSATRY_AGAIN
+#endif
+
+#if !defined(EAI_BADFLAGS)
+# define EAI_BADFLAGS WSAEINVAL
+#endif
+
+#if !defined(EAI_FAIL)
+# define EAI_FAIL WSANO_RECOVERY
+#endif
+
+#if !defined(EAI_FAMILY)
+# define EAI_FAMILY WSAEAFNOSUPPORT
+#endif
+
+#if !defined(EAI_MEMORY)
+# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
+#endif
+
+#if !defined(EAI_NODATA)
+# define EAI_NODATA WSANO_DATA
+#endif
+
+#if !defined(EAI_NONAME)
+# define EAI_NONAME WSAHOST_NOT_FOUND
+#endif
+
+#if !defined(EAI_SERVICE)
+# define EAI_SERVICE WSATYPE_NOT_FOUND
+#endif
+
+#if !defined(EAI_SOCKTYPE)
+# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
+#endif
+
+#if !defined(NI_NOFQDN)
+# define NI_NOFQDN 0x01
+#endif
+
+#if !defined(NI_NUMERICHOST)
+# define NI_NUMERICHOST 0x02
+#endif
+
+#if !defined(NI_NAMEREQD)
+# define NI_NAMEREQD 0x04
+#endif
+
+#if !defined(NI_NUMERICSERV)
+# define NI_NUMERICSERV 0x08
+#endif
+
+#if !defined(NI_DGRAM)
+# define NI_DGRAM 0x10
+#endif
+
+#if !defined(IPPROTO_IPV6)
+# define IPPROTO_IPV6 41
+#endif
+
+#if !defined(IPV6_UNICAST_HOPS)
+# define IPV6_UNICAST_HOPS 4
+#endif
+
+#if !defined(IPV6_MULTICAST_IF)
+# define IPV6_MULTICAST_IF 9
+#endif
+
+#if !defined(IPV6_MULTICAST_HOPS)
+# define IPV6_MULTICAST_HOPS 10
+#endif
+
+#if !defined(IPV6_MULTICAST_LOOP)
+# define IPV6_MULTICAST_LOOP 11
+#endif
+
+#if !defined(IPV6_JOIN_GROUP)
+# define IPV6_JOIN_GROUP 12
+#endif
+
+#if !defined(IPV6_LEAVE_GROUP)
+# define IPV6_LEAVE_GROUP 13
+#endif
+
+inline int IN6_IS_ADDR_UNSPECIFIED(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0)
+ && (a->s6_addr[11] == 0)
+ && (a->s6_addr[12] == 0)
+ && (a->s6_addr[13] == 0)
+ && (a->s6_addr[14] == 0)
+ && (a->s6_addr[15] == 0));
+}
+
+inline int IN6_IS_ADDR_LOOPBACK(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0)
+ && (a->s6_addr[11] == 0)
+ && (a->s6_addr[12] == 0)
+ && (a->s6_addr[13] == 0)
+ && (a->s6_addr[14] == 0)
+ && (a->s6_addr[15] == 1));
+}
+
+inline int IN6_IS_ADDR_MULTICAST(const in6_addr_emulation* a)
+{
+ return (a->s6_addr[0] == 0xff);
+}
+
+inline int IN6_IS_ADDR_LINKLOCAL(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0x80));
+}
+
+inline int IN6_IS_ADDR_SITELOCAL(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0xc0));
+}
+
+inline int IN6_IS_ADDR_V4MAPPED(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0xff)
+ && (a->s6_addr[11] == 0xff));
+}
+
+inline int IN6_IS_ADDR_V4COMPAT(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0xff)
+ && (a->s6_addr[11] == 0xff)
+ && !((a->s6_addr[12] == 0)
+ && (a->s6_addr[13] == 0)
+ && (a->s6_addr[14] == 0)
+ && ((a->s6_addr[15] == 0) || (a->s6_addr[15] == 1))));
+}
+
+inline int IN6_IS_ADDR_MC_NODELOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 1);
+}
+
+inline int IN6_IS_ADDR_MC_LINKLOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 2);
+}
+
+inline int IN6_IS_ADDR_MC_SITELOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 5);
+}
+
+inline int IN6_IS_ADDR_MC_ORGLOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 8);
+}
+
+inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 0xe);
+}
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(ASIO_HAS_OLD_WIN_SDK)
+
+// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY.
+#if !defined(IPV6_V6ONLY)
+# define IPV6_V6ONLY 27
+#endif
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
diff --git a/src/libtorrent/asio/detail/pipe_select_interrupter.hpp b/src/libtorrent/asio/detail/pipe_select_interrupter.hpp
new file mode 100644
index 0000000..e0a224e
--- /dev/null
+++ b/src/libtorrent/asio/detail/pipe_select_interrupter.hpp
@@ -0,0 +1,114 @@
+//
+// pipe_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+#include <fcntl.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+
+class pipe_select_interrupter
+{
+public:
+ // Constructor.
+ pipe_select_interrupter()
+ {
+ int pipe_fds[2];
+ if (pipe(pipe_fds) == 0)
+ {
+ read_descriptor_ = pipe_fds[0];
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ write_descriptor_ = pipe_fds[1];
+ ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+ }
+ else
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::system_error e(ec, "pipe_select_interrupter");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~pipe_select_interrupter()
+ {
+ if (read_descriptor_ != -1)
+ ::close(read_descriptor_);
+ if (write_descriptor_ != -1)
+ ::close(write_descriptor_);
+ }
+
+ // Interrupt the select call.
+ void interrupt()
+ {
+ char byte = 0;
+ ::write(write_descriptor_, &byte, 1);
+ }
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ bool reset()
+ {
+ char data[1024];
+ int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ return was_interrupted;
+ }
+
+ // Get the read descriptor to be passed to select.
+ int read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // The read end of a connection used to interrupt the select call. This file
+ // descriptor is passed to select such that when it is time to stop, a single
+ // byte will be written on the other end of the connection and this
+ // descriptor will become readable.
+ int read_descriptor_;
+
+ // The write end of a connection used to interrupt the select call. A single
+ // byte may be written to this to wake up the select which is waiting for the
+ // other end to become readable.
+ int write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
diff --git a/src/libtorrent/asio/detail/pop_options.hpp b/src/libtorrent/asio/detail/pop_options.hpp
new file mode 100644
index 0000000..7f56662
--- /dev/null
+++ b/src/libtorrent/asio/detail/pop_options.hpp
@@ -0,0 +1,88 @@
+//
+// pop_options.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// No header guard
+
+#if defined(__COMO__)
+
+// Comeau C++
+
+#elif defined(__DMC__)
+
+// Digital Mars C++
+
+#elif defined(__INTEL_COMPILER) || defined(__ICL) \
+ || defined(__ICC) || defined(__ECC)
+
+// Intel C++
+
+#elif defined(__GNUC__)
+
+// GNU C++
+
+# if defined(__MINGW32__) || defined(__CYGWIN__)
+# pragma pack (pop)
+# endif
+
+#elif defined(__KCC)
+
+// Kai C++
+
+#elif defined(__sgi)
+
+// SGI MIPSpro C++
+
+#elif defined(__DECCXX)
+
+// Compaq Tru64 Unix cxx
+
+#elif defined(__ghs)
+
+// Greenhills C++
+
+#elif defined(__BORLANDC__)
+
+// Borland C++
+
+# pragma option pop
+# pragma nopushoptwarn
+# pragma nopackwarning
+
+#elif defined(__MWERKS__)
+
+// Metrowerks CodeWarrior
+
+#elif defined(__SUNPRO_CC)
+
+// Sun Workshop Compiler C++
+
+#elif defined(__HP_aCC)
+
+// HP aCC
+
+#elif defined(__MRC__) || defined(__SC__)
+
+// MPW MrCpp or SCpp
+
+#elif defined(__IBMCPP__)
+
+// IBM Visual Age
+
+#elif defined(_MSC_VER)
+
+// Microsoft Visual C++
+//
+// Must remain the last #elif since some other vendors (Metrowerks, for example)
+// also #define _MSC_VER
+
+# pragma warning (pop)
+# pragma pack (pop)
+
+#endif
diff --git a/src/libtorrent/asio/detail/posix_event.hpp b/src/libtorrent/asio/detail/posix_event.hpp
new file mode 100644
index 0000000..958a5e0
--- /dev/null
+++ b/src/libtorrent/asio/detail/posix_event.hpp
@@ -0,0 +1,104 @@
+//
+// posix_event.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_POSIX_EVENT_HPP
+#define ASIO_DETAIL_POSIX_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/push_options.hpp"
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ posix_event()
+ : signalled_(false)
+ {
+ int error = ::pthread_cond_init(&cond_, 0);
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "event");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~posix_event()
+ {
+ ::pthread_cond_destroy(&cond_);
+ }
+
+ // Signal the event.
+ template <typename Lock>
+ void signal(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ signalled_ = true;
+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ signalled_ = false;
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ while (!signalled_)
+ ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL.
+ }
+
+private:
+ ::pthread_cond_t cond_;
+ bool signalled_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_POSIX_EVENT_HPP
diff --git a/src/libtorrent/asio/detail/posix_fd_set_adapter.hpp b/src/libtorrent/asio/detail/posix_fd_set_adapter.hpp
new file mode 100644
index 0000000..5519b9a
--- /dev/null
+++ b/src/libtorrent/asio/detail/posix_fd_set_adapter.hpp
@@ -0,0 +1,77 @@
+//
+// posix_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_types.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class posix_fd_set_adapter
+{
+public:
+ posix_fd_set_adapter()
+ : max_descriptor_(invalid_socket)
+ {
+ using namespace std; // Needed for memset on Solaris.
+ FD_ZERO(&fd_set_);
+ }
+
+ bool set(socket_type descriptor)
+ {
+ if (descriptor < (socket_type)FD_SETSIZE)
+ {
+ if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)
+ max_descriptor_ = descriptor;
+ FD_SET(descriptor, &fd_set_);
+ return true;
+ }
+ return false;
+ }
+
+ bool is_set(socket_type descriptor) const
+ {
+ return FD_ISSET(descriptor, &fd_set_) != 0;
+ }
+
+ operator fd_set*()
+ {
+ return &fd_set_;
+ }
+
+ socket_type max_descriptor() const
+ {
+ return max_descriptor_;
+ }
+
+private:
+ mutable fd_set fd_set_;
+ socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
diff --git a/src/libtorrent/asio/detail/posix_mutex.hpp b/src/libtorrent/asio/detail/posix_mutex.hpp
new file mode 100644
index 0000000..4f6cbba
--- /dev/null
+++ b/src/libtorrent/asio/detail/posix_mutex.hpp
@@ -0,0 +1,107 @@
+//
+// posix_mutex.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_POSIX_MUTEX_HPP
+#define ASIO_DETAIL_POSIX_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_event;
+
+class posix_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;
+
+ // Constructor.
+ posix_mutex()
+ {
+ int error = ::pthread_mutex_init(&mutex_, 0);
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~posix_mutex()
+ {
+ ::pthread_mutex_destroy(&mutex_);
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ int error = ::pthread_mutex_lock(&mutex_);
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ int error = ::pthread_mutex_unlock(&mutex_);
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+private:
+ friend class posix_event;
+ ::pthread_mutex_t mutex_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_POSIX_MUTEX_HPP
diff --git a/src/libtorrent/asio/detail/posix_signal_blocker.hpp b/src/libtorrent/asio/detail/posix_signal_blocker.hpp
new file mode 100644
index 0000000..5ab6e7a
--- /dev/null
+++ b/src/libtorrent/asio/detail/posix_signal_blocker.hpp
@@ -0,0 +1,90 @@
+//
+// posix_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/push_options.hpp"
+#include <csignal>
+#include <pthread.h>
+#include <signal.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_signal_blocker
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ posix_signal_blocker()
+ : blocked_(false)
+ {
+ sigset_t new_mask;
+ sigfillset(&new_mask);
+ blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
+ }
+
+ // Destructor restores the previous signal mask.
+ ~posix_signal_blocker()
+ {
+ if (blocked_)
+ pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
+ }
+
+ // Block all signals for the calling thread.
+ void block()
+ {
+ if (!blocked_)
+ {
+ sigset_t new_mask;
+ sigfillset(&new_mask);
+ blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
+ }
+ }
+
+ // Restore the previous signal mask.
+ void unblock()
+ {
+ if (blocked_)
+ blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0);
+ }
+
+private:
+ // Have signals been blocked.
+ bool blocked_;
+
+ // The previous signal mask.
+ sigset_t old_mask_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
diff --git a/src/libtorrent/asio/detail/posix_thread.hpp b/src/libtorrent/asio/detail/posix_thread.hpp
new file mode 100644
index 0000000..892ffe0
--- /dev/null
+++ b/src/libtorrent/asio/detail/posix_thread.hpp
@@ -0,0 +1,129 @@
+//
+// posix_thread.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_POSIX_THREAD_HPP
+#define ASIO_DETAIL_POSIX_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/push_options.hpp"
+#include <memory>
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+extern "C" void* asio_detail_posix_thread_function(void* arg);
+
+class posix_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ posix_thread(Function f)
+ : joined_(false)
+ {
+ std::auto_ptr<func_base> arg(new func<Function>(f));
+ int error = ::pthread_create(&thread_, 0,
+ asio_detail_posix_thread_function, arg.get());
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "thread");
+ boost::throw_exception(e);
+ }
+ arg.release();
+ }
+
+ // Destructor.
+ ~posix_thread()
+ {
+ if (!joined_)
+ ::pthread_detach(thread_);
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ if (!joined_)
+ {
+ ::pthread_join(thread_, 0);
+ joined_ = true;
+ }
+ }
+
+private:
+ friend void* asio_detail_posix_thread_function(void* arg);
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ::pthread_t thread_;
+ bool joined_;
+};
+
+inline void* asio_detail_posix_thread_function(void* arg)
+{
+ std::auto_ptr<posix_thread::func_base> f(
+ static_cast<posix_thread::func_base*>(arg));
+ f->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_POSIX_THREAD_HPP
diff --git a/src/libtorrent/asio/detail/posix_tss_ptr.hpp b/src/libtorrent/asio/detail/posix_tss_ptr.hpp
new file mode 100644
index 0000000..0944d3d
--- /dev/null
+++ b/src/libtorrent/asio/detail/posix_tss_ptr.hpp
@@ -0,0 +1,88 @@
+//
+// posix_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_POSIX_TSS_PTR_HPP
+#define ASIO_DETAIL_POSIX_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class posix_tss_ptr
+ : private noncopyable
+{
+public:
+ // Constructor.
+ posix_tss_ptr()
+ {
+ int error = ::pthread_key_create(&tss_key_, 0);
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "tss");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~posix_tss_ptr()
+ {
+ ::pthread_key_delete(tss_key_);
+ }
+
+ // Get the value.
+ operator T*() const
+ {
+ return static_cast<T*>(::pthread_getspecific(tss_key_));
+ }
+
+ // Set the value.
+ void operator=(T* value)
+ {
+ ::pthread_setspecific(tss_key_, value);
+ }
+
+private:
+ // Thread-specific storage to allow unlocked access to determine whether a
+ // thread is a member of the pool.
+ pthread_key_t tss_key_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP
diff --git a/src/libtorrent/asio/detail/push_options.hpp b/src/libtorrent/asio/detail/push_options.hpp
new file mode 100644
index 0000000..47524b2
--- /dev/null
+++ b/src/libtorrent/asio/detail/push_options.hpp
@@ -0,0 +1,114 @@
+//
+// push_options.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// No header guard
+
+#if defined(__COMO__)
+
+// Comeau C++
+
+#elif defined(__DMC__)
+
+// Digital Mars C++
+
+#elif defined(__INTEL_COMPILER) || defined(__ICL) \
+ || defined(__ICC) || defined(__ECC)
+
+// Intel C++
+
+#elif defined(__GNUC__)
+
+// GNU C++
+
+# if defined(__MINGW32__) || defined(__CYGWIN__)
+# pragma pack (push, 8)
+# endif
+
+#elif defined(__KCC)
+
+// Kai C++
+
+#elif defined(__sgi)
+
+// SGI MIPSpro C++
+
+#elif defined(__DECCXX)
+
+// Compaq Tru64 Unix cxx
+
+#elif defined(__ghs)
+
+// Greenhills C++
+
+#elif defined(__BORLANDC__)
+
+// Borland C++
+
+# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi-
+# pragma nopushoptwarn
+# pragma nopackwarning
+# if !defined(__MT__)
+# error Multithreaded RTL must be selected.
+# endif // !defined(__MT__)
+
+#elif defined(__MWERKS__)
+
+// Metrowerks CodeWarrior
+
+#elif defined(__SUNPRO_CC)
+
+// Sun Workshop Compiler C++
+
+#elif defined(__HP_aCC)
+
+// HP aCC
+
+#elif defined(__MRC__) || defined(__SC__)
+
+// MPW MrCpp or SCpp
+
+#elif defined(__IBMCPP__)
+
+// IBM Visual Age
+
+#elif defined(_MSC_VER)
+
+// Microsoft Visual C++
+//
+// Must remain the last #elif since some other vendors (Metrowerks, for example)
+// also #define _MSC_VER
+
+# pragma warning (disable:4103)
+# pragma warning (push)
+# pragma warning (disable:4127)
+# pragma warning (disable:4244)
+# pragma warning (disable:4355)
+# pragma warning (disable:4512)
+# pragma warning (disable:4675)
+# if defined(_M_IX86) && defined(_Wp64)
+// The /Wp64 option is broken. If you want to check 64 bit portability, use a
+// 64 bit compiler!
+# pragma warning (disable:4311)
+# pragma warning (disable:4312)
+# endif // defined(_M_IX86) && defined(_Wp64)
+# pragma pack (push, 8)
+// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler
+// has a tendency to incorrectly optimise away some calls to member template
+// functions, even though those functions contain code that should not be
+// optimised away! Therefore we will always disable this optimisation option
+// for the MSVC6 compiler.
+# if (_MSC_VER < 1300)
+# pragma optimize ("g", off)
+# endif
+# if !defined(_MT)
+# error Multithreaded RTL must be selected.
+# endif // !defined(_MT)
+
+#endif
diff --git a/src/libtorrent/asio/detail/reactive_socket_service.hpp b/src/libtorrent/asio/detail/reactive_socket_service.hpp
new file mode 100644
index 0000000..167b136
--- /dev/null
+++ b/src/libtorrent/asio/detail/reactive_socket_service.hpp
@@ -0,0 +1,1756 @@
+//
+// reactive_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/shared_ptr.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Reactor>
+class reactive_socket_service
+ : public asio::detail::service_base<
+ reactive_socket_service<Protocol, Reactor> >
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ typedef socket_type native_type;
+
+ // The implementation type of the socket.
+ class implementation_type
+ : private asio::detail::noncopyable
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : socket_(invalid_socket),
+ flags_(0),
+ protocol_(endpoint_type().protocol())
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class reactive_socket_service<Protocol, Reactor>;
+
+ // The native socket representation.
+ socket_type socket_;
+
+ enum
+ {
+ user_set_non_blocking = 1, // The user wants a non-blocking socket.
+ internal_non_blocking = 2, // The socket has been set non-blocking.
+ enable_connection_aborted = 4, // User wants connection_aborted errors.
+ user_set_linger = 8 // The user set the linger option.
+ };
+
+ // Flags indicating the current state of the socket.
+ unsigned char flags_;
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+ };
+
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+ // Constructor.
+ reactive_socket_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ reactive_socket_service<Protocol, Reactor> >(io_service),
+ reactor_(asio::use_service<Reactor>(io_service))
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Construct a new socket implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ }
+
+ // Destroy a socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ if (impl.socket_ != invalid_socket)
+ {
+ reactor_.close_descriptor(impl.socket_);
+
+ if (impl.flags_ & implementation_type::internal_non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ asio::error_code ignored_ec;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::internal_non_blocking;
+ }
+
+ if (impl.flags_ & implementation_type::user_set_linger)
+ {
+ ::linger opt;
+ opt.l_onoff = 0;
+ opt.l_linger = 0;
+ asio::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_,
+ SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
+ }
+
+ asio::error_code ignored_ec;
+ socket_ops::close(impl.socket_, ignored_ec);
+
+ impl.socket_ = invalid_socket;
+ }
+ }
+
+ // Open a new socket implementation.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(protocol.family(),
+ protocol.type(), protocol.protocol(), ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ if (int err = reactor_.register_descriptor(sock.get()))
+ {
+ ec = asio::error_code(err,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = sock.release();
+ impl.flags_ = 0;
+ impl.protocol_ = protocol;
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_type& native_socket,
+ asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(native_socket))
+ {
+ ec = asio::error_code(err,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ impl.flags_ = 0;
+ impl.protocol_ = protocol;
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ asio::error_code close(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ reactor_.close_descriptor(impl.socket_);
+
+ if (impl.flags_ & implementation_type::internal_non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ asio::error_code ignored_ec;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::internal_non_blocking;
+ }
+
+ if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
+ return ec;
+
+ impl.socket_ = invalid_socket;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_type native(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ reactor_.cancel_ops(impl.socket_);
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
+#if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = asio::error::not_socket;
+#endif // defined(ENOTTY)
+ return ec ? false : value != 0;
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
+#if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = asio::error::not_socket;
+#endif // defined(ENOTTY)
+ return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
+ }
+
+ // Bind the socket to the specified local endpoint.
+ asio::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ asio::error_code listen(implementation_type& impl, int backlog,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code set_option(implementation_type& impl,
+ const Option& option, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ }
+ else
+ {
+ if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
+ impl.flags_ |= implementation_type::enable_connection_aborted;
+ else
+ impl.flags_ &= ~implementation_type::enable_connection_aborted;
+ ec = asio::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ if (option.level(impl.protocol_) == SOL_SOCKET
+ && option.name(impl.protocol_) == SO_LINGER)
+ {
+ impl.flags_ |= implementation_type::user_set_linger;
+ }
+
+ socket_ops::setsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+
+#if defined(__MACH__) && defined(__APPLE__) \
+|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
+ // need to also set SO_REUSEPORT on BSD-based platforms.
+ if (!ec && impl.protocol_.type() == SOCK_DGRAM
+ && option.level(impl.protocol_) == SOL_SOCKET
+ && option.name(impl.protocol_) == SO_REUSEADDR)
+ {
+ asio::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT,
+ option.data(impl.protocol_), option.size(impl.protocol_),
+ ignored_ec);
+ }
+#endif
+
+ return ec;
+ }
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code get_option(const implementation_type& impl,
+ Option& option, asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ }
+ else
+ {
+ int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ *target = 1;
+ else
+ *target = 0;
+ option.resize(impl.protocol_, sizeof(int));
+ ec = asio::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ asio::error_code io_control(implementation_type& impl,
+ IO_Control_Command& command, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (command.name() == static_cast<int>(FIONBIO))
+ {
+ if (command.get())
+ impl.flags_ |= implementation_type::user_set_non_blocking;
+ else
+ impl.flags_ &= ~implementation_type::user_set_non_blocking;
+ ec = asio::error_code();
+ }
+ else
+ {
+ socket_ops::ioctl(impl.socket_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ }
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ /// Disable sends or receives on the socket.
+ asio::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<const void*>(buffer),
+ asio::buffer_size(buffer));
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Send the data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes_sent >= 0)
+ return bytes_sent;
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_handler
+ {
+ public:
+ send_handler(socket_type socket, asio::io_service& io_service,
+ const ConstBufferSequence& buffers, socket_base::message_flags flags,
+ Handler handler)
+ : socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ flags_(flags),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers_.begin();
+ typename ConstBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<const void*>(buffer),
+ asio::buffer_size(buffer));
+ }
+
+ // Send the data.
+ asio::error_code ec;
+ int bytes = socket_ops::send(socket_, bufs, i, flags_, ec);
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
+ return true;
+ }
+
+ private:
+ socket_type socket_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ socket_base::message_flags flags_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ if (impl.protocol_.type() == SOCK_STREAM)
+ {
+ // Determine total size of buffers.
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error_code(), 0));
+ return;
+ }
+ }
+
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ asio::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_write_op(impl.socket_,
+ send_handler<ConstBufferSequence, Handler>(
+ impl.socket_, this->get_io_service(), buffers, flags, handler));
+ }
+ }
+
+ template <typename Handler>
+ class null_buffers_handler
+ {
+ public:
+ null_buffers_handler(asio::io_service& io_service, Handler handler)
+ : work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ work_.get_io_service().post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ private:
+ asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_write_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<const void*>(buffer),
+ asio::buffer_size(buffer));
+ }
+
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Send the data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_sent = socket_ops::sendto(impl.socket_, bufs, i, flags,
+ destination.data(), destination.size(), ec);
+
+ // Check if operation succeeded.
+ if (bytes_sent >= 0)
+ return bytes_sent;
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_to_handler
+ {
+ public:
+ send_to_handler(socket_type socket, asio::io_service& io_service,
+ const ConstBufferSequence& buffers, const endpoint_type& endpoint,
+ socket_base::message_flags flags, Handler handler)
+ : socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ destination_(endpoint),
+ flags_(flags),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers_.begin();
+ typename ConstBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<const void*>(buffer),
+ asio::buffer_size(buffer));
+ }
+
+ // Send the data.
+ asio::error_code ec;
+ int bytes = socket_ops::sendto(socket_, bufs, i, flags_,
+ destination_.data(), destination_.size(), ec);
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
+ return true;
+ }
+
+ private:
+ socket_type socket_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ endpoint_type destination_;
+ socket_base::message_flags flags_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ asio::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_write_op(impl.socket_,
+ send_to_handler<ConstBufferSequence, Handler>(
+ impl.socket_, this->get_io_service(), buffers,
+ destination, flags, handler));
+ }
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_write_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<void*>(buffer),
+ asio::buffer_size(buffer));
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Receive some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes_recvd > 0)
+ return bytes_recvd;
+
+ // Check for EOF.
+ if (bytes_recvd == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(implementation_type& impl,
+ const null_buffers& buffers,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_handler
+ {
+ public:
+ receive_handler(socket_type socket, asio::io_service& io_service,
+ const MutableBufferSequence& buffers, socket_base::message_flags flags,
+ Handler handler)
+ : socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ flags_(flags),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers_.begin();
+ typename MutableBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<void*>(buffer),
+ asio::buffer_size(buffer));
+ }
+
+ // Receive some data.
+ asio::error_code ec;
+ int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec);
+ if (bytes == 0)
+ ec = asio::error::eof;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
+ return true;
+ }
+
+ private:
+ socket_type socket_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags flags_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ if (impl.protocol_.type() == SOCK_STREAM)
+ {
+ // Determine total size of buffers.
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error_code(), 0));
+ return;
+ }
+ }
+
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ asio::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor_.start_except_op(impl.socket_,
+ receive_handler<MutableBufferSequence, Handler>(
+ impl.socket_, this->get_io_service(), buffers, flags, handler));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.socket_,
+ receive_handler<MutableBufferSequence, Handler>(
+ impl.socket_, this->get_io_service(), buffers, flags, handler));
+ }
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else if (flags & socket_base::message_out_of_band)
+ {
+ reactor_.start_except_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<void*>(buffer),
+ asio::buffer_size(buffer));
+ }
+
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Receive some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ std::size_t addr_len = sender_endpoint.capacity();
+ int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags,
+ sender_endpoint.data(), &addr_len, ec);
+
+ // Check if operation succeeded.
+ if (bytes_recvd > 0)
+ {
+ sender_endpoint.resize(addr_len);
+ return bytes_recvd;
+ }
+
+ // Check for EOF.
+ if (bytes_recvd == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl,
+ const null_buffers& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_from_handler
+ {
+ public:
+ receive_from_handler(socket_type socket,
+ asio::io_service& io_service,
+ const MutableBufferSequence& buffers, endpoint_type& endpoint,
+ socket_base::message_flags flags, Handler handler)
+ : socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ sender_endpoint_(endpoint),
+ flags_(flags),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers_.begin();
+ typename MutableBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ asio::buffer_cast<void*>(buffer),
+ asio::buffer_size(buffer));
+ }
+
+ // Receive some data.
+ std::size_t addr_len = sender_endpoint_.capacity();
+ asio::error_code ec;
+ int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_,
+ sender_endpoint_.data(), &addr_len, ec);
+ if (bytes == 0)
+ ec = asio::error::eof;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ sender_endpoint_.resize(addr_len);
+ io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
+ return true;
+ }
+
+ private:
+ socket_type socket_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ endpoint_type& sender_endpoint_;
+ socket_base::message_flags flags_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous receive. The buffer for the data being received and
+ // the sender_endpoint object must both be valid for the lifetime of the
+ // asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ asio::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_read_op(impl.socket_,
+ receive_from_handler<MutableBufferSequence, Handler>(
+ impl.socket_, this->get_io_service(), buffers,
+ sender_endpoint, flags, handler));
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor_.start_except_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ asio::error_code accept(implementation_type& impl,
+ Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return ec;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Accept a socket.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ asio::error_code ec;
+ socket_holder new_socket;
+ std::size_t addr_len = 0;
+ if (peer_endpoint)
+ {
+ addr_len = peer_endpoint->capacity();
+ new_socket.reset(socket_ops::accept(impl.socket_,
+ peer_endpoint->data(), &addr_len, ec));
+ }
+ else
+ {
+ new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
+ }
+
+ // Check if operation succeeded.
+ if (new_socket.get() >= 0)
+ {
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ return ec;
+ }
+
+ // Operation failed.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ {
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ return ec;
+ // Fall through to retry operation.
+ }
+ else if (ec == asio::error::connection_aborted)
+ {
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ return ec;
+ // Fall through to retry operation.
+ }
+#if defined(EPROTO)
+ else if (ec.value() == EPROTO)
+ {
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ return ec;
+ // Fall through to retry operation.
+ }
+#endif // defined(EPROTO)
+ else
+ return ec;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(impl.socket_, ec) < 0)
+ return ec;
+ }
+ }
+
+ template <typename Socket, typename Handler>
+ class accept_handler
+ {
+ public:
+ accept_handler(socket_type socket, asio::io_service& io_service,
+ Socket& peer, const protocol_type& protocol,
+ endpoint_type* peer_endpoint, bool enable_connection_aborted,
+ Handler handler)
+ : socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ enable_connection_aborted_(enable_connection_aborted),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result));
+ return true;
+ }
+
+ // Accept the waiting connection.
+ asio::error_code ec;
+ socket_holder new_socket;
+ std::size_t addr_len = 0;
+ if (peer_endpoint_)
+ {
+ addr_len = peer_endpoint_->capacity();
+ new_socket.reset(socket_ops::accept(socket_,
+ peer_endpoint_->data(), &addr_len, ec));
+ }
+ else
+ {
+ new_socket.reset(socket_ops::accept(socket_, 0, 0, ec));
+ }
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+ if (ec == asio::error::connection_aborted
+ && !enable_connection_aborted_)
+ return false;
+#if defined(EPROTO)
+ if (ec.value() == EPROTO && !enable_connection_aborted_)
+ return false;
+#endif // defined(EPROTO)
+
+ // Transfer ownership of the new socket to the peer object.
+ if (!ec)
+ {
+ if (peer_endpoint_)
+ peer_endpoint_->resize(addr_len);
+ peer_.assign(protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ }
+
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+
+ private:
+ socket_type socket_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ Socket& peer_;
+ protocol_type protocol_;
+ endpoint_type* peer_endpoint_;
+ bool enable_connection_aborted_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous accept. The peer and peer_endpoint objects
+ // must be valid until the accept's handler is invoked.
+ template <typename Socket, typename Handler>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor));
+ }
+ else if (peer.is_open())
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::already_open));
+ }
+ else
+ {
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ asio::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_read_op(impl.socket_,
+ accept_handler<Socket, Handler>(
+ impl.socket_, this->get_io_service(),
+ peer, impl.protocol_, peer_endpoint,
+ (impl.flags_ & implementation_type::enable_connection_aborted) != 0,
+ handler));
+ }
+ }
+
+ // Connect the socket to the specified endpoint.
+ asio::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (impl.flags_ & implementation_type::internal_non_blocking)
+ {
+ // Mark the socket as blocking while we perform the connect.
+ ioctl_arg_type non_blocking = 0;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return ec;
+ impl.flags_ &= ~implementation_type::internal_non_blocking;
+ }
+
+ // Perform the connect operation.
+ socket_ops::connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ return ec;
+ }
+
+ template <typename Handler>
+ class connect_handler
+ {
+ public:
+ connect_handler(socket_type socket, boost::shared_ptr<bool> completed,
+ asio::io_service& io_service, Reactor& reactor, Handler handler)
+ : socket_(socket),
+ completed_(completed),
+ io_service_(io_service),
+ work_(io_service),
+ reactor_(reactor),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ // Check whether a handler has already been called for the connection.
+ // If it has, then we don't want to do anything in this handler.
+ if (*completed_)
+ return true;
+
+ // Cancel the other reactor operation for the connection.
+ *completed_ = true;
+ reactor_.enqueue_cancel_ops_unlocked(socket_);
+
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result));
+ return true;
+ }
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ asio::error_code ec;
+ if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == socket_error_retval)
+ {
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+
+ // If connection failed then post the handler with the error code.
+ if (connect_error)
+ {
+ ec = asio::error_code(connect_error,
+ asio::error::get_system_category());
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+
+ // Post the result of the successful connection operation.
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+
+ private:
+ socket_type socket_;
+ boost::shared_ptr<bool> completed_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ Reactor& reactor_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor));
+ return;
+ }
+
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ asio::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ // Start the connect operation. The socket is already marked as non-blocking
+ // so the connection will take place asynchronously.
+ asio::error_code ec;
+ if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
+ peer_endpoint.size(), ec) == 0)
+ {
+ // The connect operation has finished successfully so we need to post the
+ // handler immediately.
+ this->get_io_service().post(bind_handler(handler,
+ asio::error_code()));
+ }
+ else if (ec == asio::error::in_progress
+ || ec == asio::error::would_block)
+ {
+ // The connection is happening in the background, and we need to wait
+ // until the socket becomes writeable.
+ boost::shared_ptr<bool> completed(new bool(false));
+ reactor_.start_write_and_except_ops(impl.socket_,
+ connect_handler<Handler>(impl.socket_, completed,
+ this->get_io_service(), reactor_, handler));
+ }
+ else
+ {
+ // The connect operation has failed, so post the handler immediately.
+ this->get_io_service().post(bind_handler(handler, ec));
+ }
+ }
+
+private:
+ // The selector that performs event demultiplexing for the service.
+ Reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/reactor_op_queue.hpp b/src/libtorrent/asio/detail/reactor_op_queue.hpp
new file mode 100644
index 0000000..b419c7c
--- /dev/null
+++ b/src/libtorrent/asio/detail/reactor_op_queue.hpp
@@ -0,0 +1,389 @@
+//
+// reactor_op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <memory>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Descriptor>
+class reactor_op_queue
+ : private noncopyable
+{
+public:
+ // Constructor.
+ reactor_op_queue()
+ : operations_(),
+ cancelled_operations_(0),
+ cleanup_operations_(0)
+ {
+ }
+
+ // Add a new operation to the queue. Returns true if this is the only
+ // operation for the given descriptor, in which case the reactor's event
+ // demultiplexing function call may need to be interrupted and restarted.
+ template <typename Handler>
+ bool enqueue_operation(Descriptor descriptor, Handler handler)
+ {
+ op_base* new_op = new op<Handler>(descriptor, handler);
+
+ typedef typename operation_map::iterator iterator;
+ typedef typename operation_map::value_type value_type;
+ std::pair<iterator, bool> entry =
+ operations_.insert(value_type(descriptor, new_op));
+ if (entry.second)
+ return true;
+
+ op_base* current_op = entry.first->second;
+ while (current_op->next_)
+ current_op = current_op->next_;
+ current_op->next_ = new_op;
+
+ return false;
+ }
+
+ // Cancel all operations associated with the descriptor. Any operations
+ // pending for the descriptor will be notified that they have been cancelled
+ // next time dispatch_cancellations is called. Returns true if any operations
+ // were cancelled, in which case the reactor's event demultiplexing function
+ // may need to be interrupted and restarted.
+ bool cancel_operations(Descriptor descriptor)
+ {
+ typename operation_map::iterator i = operations_.find(descriptor);
+ if (i != operations_.end())
+ {
+ op_base* last_op = i->second;
+ while (last_op->next_)
+ last_op = last_op->next_;
+ last_op->next_ = cancelled_operations_;
+ cancelled_operations_ = i->second;
+ operations_.erase(i);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Whether there are no operations in the queue.
+ bool empty() const
+ {
+ return operations_.empty();
+ }
+
+ // Determine whether there are any operations associated with the descriptor.
+ bool has_operation(Descriptor descriptor) const
+ {
+ return operations_.find(descriptor) != operations_.end();
+ }
+
+ // Dispatch the first operation corresponding to the descriptor. Returns true
+ // if there are more operations queued for the descriptor.
+ bool dispatch_operation(Descriptor descriptor,
+ const asio::error_code& result)
+ {
+ typename operation_map::iterator i = operations_.find(descriptor);
+ if (i != operations_.end())
+ {
+ op_base* this_op = i->second;
+ i->second = this_op->next_;
+ this_op->next_ = cleanup_operations_;
+ cleanup_operations_ = this_op;
+ bool done = this_op->invoke(result);
+ if (done)
+ {
+ // Operation has finished.
+ if (i->second)
+ {
+ return true;
+ }
+ else
+ {
+ operations_.erase(i);
+ return false;
+ }
+ }
+ else
+ {
+ // Operation wants to be called again. Leave it at the front of the
+ // queue for this descriptor, and remove from the cleanup list.
+ cleanup_operations_ = this_op->next_;
+ this_op->next_ = i->second;
+ i->second = this_op;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Dispatch all operations corresponding to the descriptor.
+ void dispatch_all_operations(Descriptor descriptor,
+ const asio::error_code& result)
+ {
+ typename operation_map::iterator i = operations_.find(descriptor);
+ if (i != operations_.end())
+ {
+ while (i->second)
+ {
+ op_base* this_op = i->second;
+ i->second = this_op->next_;
+ this_op->next_ = cleanup_operations_;
+ cleanup_operations_ = this_op;
+ bool done = this_op->invoke(result);
+ if (!done)
+ {
+ // Operation has not finished yet, so leave at front of queue, and
+ // remove from the cleanup list.
+ cleanup_operations_ = this_op->next_;
+ this_op->next_ = i->second;
+ i->second = this_op;
+ return;
+ }
+ }
+ operations_.erase(i);
+ }
+ }
+
+ // Fill a descriptor set with the descriptors corresponding to each active
+ // operation.
+ template <typename Descriptor_Set>
+ void get_descriptors(Descriptor_Set& descriptors)
+ {
+ typename operation_map::iterator i = operations_.begin();
+ while (i != operations_.end())
+ {
+ Descriptor descriptor = i->first;
+ ++i;
+ if (!descriptors.set(descriptor))
+ {
+ asio::error_code ec(error::fd_set_failure);
+ dispatch_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Dispatch the operations corresponding to the ready file descriptors
+ // contained in the given descriptor set.
+ template <typename Descriptor_Set>
+ void dispatch_descriptors(const Descriptor_Set& descriptors,
+ const asio::error_code& result)
+ {
+ typename operation_map::iterator i = operations_.begin();
+ while (i != operations_.end())
+ {
+ typename operation_map::iterator op_iter = i++;
+ if (descriptors.is_set(op_iter->first))
+ {
+ op_base* this_op = op_iter->second;
+ op_iter->second = this_op->next_;
+ this_op->next_ = cleanup_operations_;
+ cleanup_operations_ = this_op;
+ bool done = this_op->invoke(result);
+ if (done)
+ {
+ if (!op_iter->second)
+ operations_.erase(op_iter);
+ }
+ else
+ {
+ // Operation has not finished yet, so leave at front of queue, and
+ // remove from the cleanup list.
+ cleanup_operations_ = this_op->next_;
+ this_op->next_ = op_iter->second;
+ op_iter->second = this_op;
+ }
+ }
+ }
+ }
+
+ // Dispatch any pending cancels for operations.
+ void dispatch_cancellations()
+ {
+ while (cancelled_operations_)
+ {
+ op_base* this_op = cancelled_operations_;
+ cancelled_operations_ = this_op->next_;
+ this_op->next_ = cleanup_operations_;
+ cleanup_operations_ = this_op;
+ this_op->invoke(asio::error::operation_aborted);
+ }
+ }
+
+ // Destroy operations that are waiting to be cleaned up.
+ void cleanup_operations()
+ {
+ while (cleanup_operations_)
+ {
+ op_base* next_op = cleanup_operations_->next_;
+ cleanup_operations_->next_ = 0;
+ cleanup_operations_->destroy();
+ cleanup_operations_ = next_op;
+ }
+ }
+
+ // Destroy all operations owned by the queue.
+ void destroy_operations()
+ {
+ while (cancelled_operations_)
+ {
+ op_base* next_op = cancelled_operations_->next_;
+ cancelled_operations_->next_ = 0;
+ cancelled_operations_->destroy();
+ cancelled_operations_ = next_op;
+ }
+
+ while (cleanup_operations_)
+ {
+ op_base* next_op = cleanup_operations_->next_;
+ cleanup_operations_->next_ = 0;
+ cleanup_operations_->destroy();
+ cleanup_operations_ = next_op;
+ }
+
+ typename operation_map::iterator i = operations_.begin();
+ while (i != operations_.end())
+ {
+ typename operation_map::iterator op_iter = i++;
+ op_base* curr_op = op_iter->second;
+ operations_.erase(op_iter);
+ while (curr_op)
+ {
+ op_base* next_op = curr_op->next_;
+ curr_op->next_ = 0;
+ curr_op->destroy();
+ curr_op = next_op;
+ }
+ }
+ }
+
+private:
+ // Base class for reactor operations. A function pointer is used instead of
+ // virtual functions to avoid the associated overhead.
+ class op_base
+ {
+ public:
+ // Get the descriptor associated with the operation.
+ Descriptor descriptor() const
+ {
+ return descriptor_;
+ }
+
+ // Perform the operation.
+ bool invoke(const asio::error_code& result)
+ {
+ return invoke_func_(this, result);
+ }
+
+ // Destroy the operation.
+ void destroy()
+ {
+ return destroy_func_(this);
+ }
+
+ protected:
+ typedef bool (*invoke_func_type)(op_base*,
+ const asio::error_code&);
+ typedef void (*destroy_func_type)(op_base*);
+
+ // Construct an operation for the given descriptor.
+ op_base(invoke_func_type invoke_func,
+ destroy_func_type destroy_func, Descriptor descriptor)
+ : invoke_func_(invoke_func),
+ destroy_func_(destroy_func),
+ descriptor_(descriptor),
+ next_(0)
+ {
+ }
+
+ // Prevent deletion through this type.
+ ~op_base()
+ {
+ }
+
+ private:
+ friend class reactor_op_queue<Descriptor>;
+
+ // The function to be called to dispatch the handler.
+ invoke_func_type invoke_func_;
+
+ // The function to be called to delete the handler.
+ destroy_func_type destroy_func_;
+
+ // The descriptor associated with the operation.
+ Descriptor descriptor_;
+
+ // The next operation for the same file descriptor.
+ op_base* next_;
+ };
+
+ // Adaptor class template for using handlers in operations.
+ template <typename Handler>
+ class op
+ : public op_base
+ {
+ public:
+ // Constructor.
+ op(Descriptor descriptor, Handler handler)
+ : op_base(&op<Handler>::invoke_handler,
+ &op<Handler>::destroy_handler, descriptor),
+ handler_(handler)
+ {
+ }
+
+ // Invoke the handler.
+ static bool invoke_handler(op_base* base,
+ const asio::error_code& result)
+ {
+ return static_cast<op<Handler>*>(base)->handler_(result);
+ }
+
+ // Delete the handler.
+ static void destroy_handler(op_base* base)
+ {
+ delete static_cast<op<Handler>*>(base);
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // The type for a map of operations.
+ typedef hash_map<Descriptor, op_base*> operation_map;
+
+ // The operations that are currently executing asynchronously.
+ operation_map operations_;
+
+ // The list of operations that have been cancelled.
+ op_base* cancelled_operations_;
+
+ // The list of operations to be destroyed.
+ op_base* cleanup_operations_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
diff --git a/src/libtorrent/asio/detail/resolver_service.hpp b/src/libtorrent/asio/detail/resolver_service.hpp
new file mode 100644
index 0000000..172a8fc
--- /dev/null
+++ b/src/libtorrent/asio/detail/resolver_service.hpp
@@ -0,0 +1,357 @@
+//
+// resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_RESOLVER_SERVICE_HPP
+#define ASIO_DETAIL_RESOLVER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstring>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/thread.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class resolver_service
+ : public asio::detail::service_base<resolver_service<Protocol> >
+{
+private:
+ // Helper class to perform exception-safe cleanup of addrinfo objects.
+ class auto_addrinfo
+ : private asio::detail::noncopyable
+ {
+ public:
+ explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
+ : ai_(ai)
+ {
+ }
+
+ ~auto_addrinfo()
+ {
+ if (ai_)
+ socket_ops::freeaddrinfo(ai_);
+ }
+
+ operator asio::detail::addrinfo_type*()
+ {
+ return ai_;
+ }
+
+ private:
+ asio::detail::addrinfo_type* ai_;
+ };
+
+public:
+ // The implementation type of the resolver. The shared pointer is used as a
+ // cancellation token to indicate to the background thread that the operation
+ // has been cancelled.
+ typedef boost::shared_ptr<void> implementation_type;
+ struct noop_deleter { void operator()(void*) {} };
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The query type.
+ typedef typename Protocol::resolver_query query_type;
+
+ // The iterator type.
+ typedef typename Protocol::resolver_iterator iterator_type;
+
+ // Constructor.
+ resolver_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ resolver_service<Protocol> >(io_service),
+ mutex_(),
+ work_io_service_(new asio::io_service),
+ work_(new asio::io_service::work(*work_io_service_)),
+ work_thread_(0)
+ {
+ }
+
+ // Destructor.
+ ~resolver_service()
+ {
+ shutdown_service();
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ work_.reset();
+ if (work_io_service_)
+ {
+ work_io_service_->stop();
+ if (work_thread_)
+ {
+ work_thread_->join();
+ work_thread_.reset();
+ }
+ work_io_service_.reset();
+ }
+ }
+
+ // Construct a new resolver implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.reset(static_cast<void*>(0), noop_deleter());
+ }
+
+ // Destroy a resolver implementation.
+ void destroy(implementation_type&)
+ {
+ }
+
+ // Cancel pending asynchronous operations.
+ void cancel(implementation_type& impl)
+ {
+ impl.reset(static_cast<void*>(0), noop_deleter());
+ }
+
+ // Resolve a query to a list of entries.
+ iterator_type resolve(implementation_type&, const query_type& query,
+ asio::error_code& ec)
+ {
+ asio::detail::addrinfo_type* address_info = 0;
+ std::string host_name = query.host_name();
+ std::string service_name = query.service_name();
+ asio::detail::addrinfo_type hints = query.hints();
+
+ socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
+ service_name.c_str(), &hints, &address_info, ec);
+ auto_addrinfo auto_address_info(address_info);
+
+ if (ec)
+ return iterator_type();
+
+ return iterator_type::create(address_info, host_name, service_name);
+ }
+
+ template <typename Handler>
+ class resolve_query_handler
+ {
+ public:
+ resolve_query_handler(implementation_type impl, const query_type& query,
+ asio::io_service& io_service, Handler handler)
+ : impl_(impl),
+ query_(query),
+ io_service_(io_service),
+ work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ void operator()()
+ {
+ // Check if the operation has been cancelled.
+ if (impl_.expired())
+ {
+ iterator_type iterator;
+ io_service_.post(asio::detail::bind_handler(handler_,
+ asio::error::operation_aborted, iterator));
+ return;
+ }
+
+ // Perform the blocking host resolution operation.
+ asio::detail::addrinfo_type* address_info = 0;
+ std::string host_name = query_.host_name();
+ std::string service_name = query_.service_name();
+ asio::detail::addrinfo_type hints = query_.hints();
+ asio::error_code ec;
+ socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
+ service_name.c_str(), &hints, &address_info, ec);
+ auto_addrinfo auto_address_info(address_info);
+
+ // Invoke the handler and pass the result.
+ iterator_type iterator;
+ if (!ec)
+ iterator = iterator_type::create(address_info, host_name, service_name);
+ io_service_.post(asio::detail::bind_handler(
+ handler_, ec, iterator));
+ }
+
+ private:
+ boost::weak_ptr<void> impl_;
+ query_type query_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Asynchronously resolve a query to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl, const query_type& query,
+ Handler handler)
+ {
+ if (work_io_service_)
+ {
+ start_work_thread();
+ work_io_service_->post(
+ resolve_query_handler<Handler>(
+ impl, query, this->get_io_service(), handler));
+ }
+ }
+
+ // Resolve an endpoint to a list of entries.
+ iterator_type resolve(implementation_type&,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ // First try resolving with the service name. If that fails try resolving
+ // but allow the service to be returned as a number.
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
+ socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ if (ec)
+ {
+ flags |= NI_NUMERICSERV;
+ socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ }
+
+ if (ec)
+ return iterator_type();
+
+ return iterator_type::create(endpoint, host_name, service_name);
+ }
+
+ template <typename Handler>
+ class resolve_endpoint_handler
+ {
+ public:
+ resolve_endpoint_handler(implementation_type impl,
+ const endpoint_type& endpoint, asio::io_service& io_service,
+ Handler handler)
+ : impl_(impl),
+ endpoint_(endpoint),
+ io_service_(io_service),
+ work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ void operator()()
+ {
+ // Check if the operation has been cancelled.
+ if (impl_.expired())
+ {
+ iterator_type iterator;
+ io_service_.post(asio::detail::bind_handler(handler_,
+ asio::error::operation_aborted, iterator));
+ return;
+ }
+
+
+ // First try resolving with the service name. If that fails try resolving
+ // but allow the service to be returned as a number.
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
+ asio::error_code ec;
+ socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ if (ec)
+ {
+ flags |= NI_NUMERICSERV;
+ socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ }
+
+ // Invoke the handler and pass the result.
+ iterator_type iterator;
+ if (!ec)
+ iterator = iterator_type::create(endpoint_, host_name, service_name);
+ io_service_.post(asio::detail::bind_handler(
+ handler_, ec, iterator));
+ }
+
+ private:
+ boost::weak_ptr<void> impl_;
+ endpoint_type endpoint_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Asynchronously resolve an endpoint to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
+ Handler handler)
+ {
+ if (work_io_service_)
+ {
+ start_work_thread();
+ work_io_service_->post(
+ resolve_endpoint_handler<Handler>(
+ impl, endpoint, this->get_io_service(), handler));
+ }
+ }
+
+private:
+ // Helper class to run the work io_service in a thread.
+ class work_io_service_runner
+ {
+ public:
+ work_io_service_runner(asio::io_service& io_service)
+ : io_service_(io_service) {}
+ void operator()() { io_service_.run(); }
+ private:
+ asio::io_service& io_service_;
+ };
+
+ // Start the work thread if it's not already running.
+ void start_work_thread()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (work_thread_ == 0)
+ {
+ work_thread_.reset(new asio::detail::thread(
+ work_io_service_runner(*work_io_service_)));
+ }
+ }
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // Private io_service used for performing asynchronous host resolution.
+ boost::scoped_ptr<asio::io_service> work_io_service_;
+
+ // Work for the private io_service to perform.
+ boost::scoped_ptr<asio::io_service::work> work_;
+
+ // Thread used for running the work io_service's run loop.
+ boost::scoped_ptr<asio::detail::thread> work_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/scoped_lock.hpp b/src/libtorrent/asio/detail/scoped_lock.hpp
new file mode 100644
index 0000000..70b6729
--- /dev/null
+++ b/src/libtorrent/asio/detail/scoped_lock.hpp
@@ -0,0 +1,91 @@
+//
+// scoped_lock.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SCOPED_LOCK_HPP
+#define ASIO_DETAIL_SCOPED_LOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to lock and unlock a mutex automatically.
+template <typename Mutex>
+class scoped_lock
+ : private noncopyable
+{
+public:
+ // Constructor acquires the lock.
+ scoped_lock(Mutex& m)
+ : mutex_(m)
+ {
+ mutex_.lock();
+ locked_ = true;
+ }
+
+ // Destructor releases the lock.
+ ~scoped_lock()
+ {
+ if (locked_)
+ mutex_.unlock();
+ }
+
+ // Explicitly acquire the lock.
+ void lock()
+ {
+ if (!locked_)
+ {
+ mutex_.lock();
+ locked_ = true;
+ }
+ }
+
+ // Explicitly release the lock.
+ void unlock()
+ {
+ if (locked_)
+ {
+ mutex_.unlock();
+ locked_ = false;
+ }
+ }
+
+ // Test whether the lock is held.
+ bool locked() const
+ {
+ return locked_;
+ }
+
+ // Get the underlying mutex.
+ Mutex& mutex()
+ {
+ return mutex_;
+ }
+
+private:
+ // The underlying mutex.
+ Mutex& mutex_;
+
+ // Whether the mutex is currently locked or unlocked.
+ bool locked_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCOPED_LOCK_HPP
diff --git a/src/libtorrent/asio/detail/select_interrupter.hpp b/src/libtorrent/asio/detail/select_interrupter.hpp
new file mode 100644
index 0000000..4277e47
--- /dev/null
+++ b/src/libtorrent/asio/detail/select_interrupter.hpp
@@ -0,0 +1,41 @@
+//
+// select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/pipe_select_interrupter.hpp"
+#include "asio/detail/socket_select_interrupter.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef socket_select_interrupter select_interrupter;
+#else
+typedef pipe_select_interrupter select_interrupter;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP
diff --git a/src/libtorrent/asio/detail/select_reactor.hpp b/src/libtorrent/asio/detail/select_reactor.hpp
new file mode 100644
index 0000000..8963501
--- /dev/null
+++ b/src/libtorrent/asio/detail/select_reactor.hpp
@@ -0,0 +1,471 @@
+//
+// select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SELECT_REACTOR_HPP
+#define ASIO_DETAIL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <vector>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fd_set_adapter.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/select_reactor_fwd.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/task_io_service.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/timer_queue.hpp"
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class select_reactor
+ : public asio::detail::service_base<select_reactor<Own_Thread> >
+{
+public:
+ // Constructor.
+ select_reactor(asio::io_service& io_service)
+ : asio::detail::service_base<
+ select_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ select_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false)
+ {
+ if (Own_Thread)
+ {
+ asio::detail::signal_blocker sb;
+ thread_ = new asio::detail::thread(
+ bind_handler(&select_reactor::call_run_thread, this));
+ }
+ }
+
+ // Destructor.
+ ~select_reactor()
+ {
+ shutdown_service();
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type descriptor)
+ {
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor, Handler handler,
+ bool /*allow_speculative_read*/ = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ interrupter_.interrupt();
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor, Handler handler,
+ bool /*allow_speculative_write*/ = true)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ interrupter_.interrupt();
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ interrupter_.interrupt();
+ }
+
+ // Start new write and exception operations. The handler object will be
+ // invoked when the given descriptor is ready for writing or has exception
+ // information available, or an error has occurred.
+ template <typename Handler>
+ void start_write_and_except_ops(socket_type descriptor, Handler handler)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ {
+ bool interrupt = write_op_queue_.enqueue_operation(descriptor, handler);
+ interrupt = except_op_queue_.enqueue_operation(descriptor, handler)
+ || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Enqueue cancellation of all operations associated with the given
+ // descriptor. The handlers associated with the descriptor will be invoked
+ // with the operation_aborted error. This function does not acquire the
+ // select_reactor's mutex, and so should only be used from within a reactor
+ // handler.
+ void enqueue_cancel_ops_unlocked(socket_type descriptor)
+ {
+ pending_cancellations_.push_back(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // Cancel the timer associated with the given token. Returns the number of
+ // handlers that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<select_reactor<Own_Thread> >;
+
+ // Run select once until interrupted or events are ready to be dispatched.
+ void run(bool block)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ except_op_queue_.dispatch_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ cleanup_operations_and_timers(lock);
+ return;
+ }
+
+ // Set up the descriptor sets.
+ fd_set_adapter read_fds;
+ read_fds.set(interrupter_.read_descriptor());
+ read_op_queue_.get_descriptors(read_fds);
+ fd_set_adapter write_fds;
+ write_op_queue_.get_descriptors(write_fds);
+ fd_set_adapter except_fds;
+ except_op_queue_.get_descriptors(except_fds);
+ socket_type max_fd = read_fds.max_descriptor();
+ if (write_fds.max_descriptor() > max_fd)
+ max_fd = write_fds.max_descriptor();
+ if (except_fds.max_descriptor() > max_fd)
+ max_fd = except_fds.max_descriptor();
+
+ // Block on the select call without holding the lock so that new
+ // operations can be started while the call is executing.
+ timeval tv_buf = { 0, 0 };
+ timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
+ select_in_progress_ = true;
+ lock.unlock();
+ asio::error_code ec;
+ int retval = socket_ops::select(static_cast<int>(max_fd + 1),
+ read_fds, write_fds, except_fds, tv, ec);
+ lock.lock();
+ select_in_progress_ = false;
+
+ // Block signals while dispatching operations.
+ asio::detail::signal_blocker sb;
+
+ // Reset the interrupter.
+ if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor()))
+ interrupter_.reset();
+
+ // Dispatch all ready operations.
+ if (retval > 0)
+ {
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ except_op_queue_.dispatch_descriptors(except_fds,
+ asio::error_code());
+ read_op_queue_.dispatch_descriptors(read_fds,
+ asio::error_code());
+ write_op_queue_.dispatch_descriptors(write_fds,
+ asio::error_code());
+ except_op_queue_.dispatch_cancellations();
+ read_op_queue_.dispatch_cancellations();
+ write_op_queue_.dispatch_cancellations();
+ }
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ cleanup_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(select_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the select call.
+ timeval* get_timeout(timeval& tv)
+ {
+ if (all_timer_queues_are_empty())
+ return 0;
+
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ tv.tv_sec = minimum_wait_duration.total_seconds();
+ tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000;
+ }
+ else
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+
+ return &tv;
+ }
+
+ // Cancel all operations associated with the given descriptor. The do_cancel
+ // function of the handler objects will be invoked. This function does not
+ // acquire the select_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void cleanup_operations_and_timers(
+ asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.cleanup_operations();
+ write_op_queue_.cleanup_operations();
+ except_op_queue_.cleanup_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->cleanup_timers();
+ }
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // Whether the select loop is currently running or not.
+ bool select_in_progress_;
+
+ // The interrupter is used to break a blocking select call.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of exception operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SELECT_REACTOR_HPP
diff --git a/src/libtorrent/asio/detail/select_reactor_fwd.hpp b/src/libtorrent/asio/detail/select_reactor_fwd.hpp
new file mode 100644
index 0000000..d43bc8a
--- /dev/null
+++ b/src/libtorrent/asio/detail/select_reactor_fwd.hpp
@@ -0,0 +1,31 @@
+//
+// select_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
+#define ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class select_reactor;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
diff --git a/src/libtorrent/asio/detail/service_base.hpp b/src/libtorrent/asio/detail/service_base.hpp
new file mode 100644
index 0000000..906a354
--- /dev/null
+++ b/src/libtorrent/asio/detail/service_base.hpp
@@ -0,0 +1,49 @@
+//
+// service_base.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SERVICE_BASE_HPP
+#define ASIO_DETAIL_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/detail/service_id.hpp"
+
+namespace asio {
+namespace detail {
+
+// Special service base class to keep classes header-file only.
+template <typename Type>
+class service_base
+ : public asio::io_service::service
+{
+public:
+ static asio::detail::service_id<Type> id;
+
+ // Constructor.
+ service_base(asio::io_service& io_service)
+ : asio::io_service::service(io_service)
+ {
+ }
+};
+
+template <typename Type>
+asio::detail::service_id<Type> service_base<Type>::id;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SERVICE_BASE_HPP
diff --git a/src/libtorrent/asio/detail/service_id.hpp b/src/libtorrent/asio/detail/service_id.hpp
new file mode 100644
index 0000000..e604064
--- /dev/null
+++ b/src/libtorrent/asio/detail/service_id.hpp
@@ -0,0 +1,37 @@
+//
+// service_id.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SERVICE_ID_HPP
+#define ASIO_DETAIL_SERVICE_ID_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/io_service.hpp"
+
+namespace asio {
+namespace detail {
+
+// Special derived service id type to keep classes header-file only.
+template <typename Type>
+class service_id
+ : public asio::io_service::id
+{
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SERVICE_ID_HPP
diff --git a/src/libtorrent/asio/detail/service_registry.hpp b/src/libtorrent/asio/detail/service_registry.hpp
new file mode 100644
index 0000000..f517cbb
--- /dev/null
+++ b/src/libtorrent/asio/detail/service_registry.hpp
@@ -0,0 +1,210 @@
+//
+// service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SERVICE_REGISTRY_HPP
+#define ASIO_DETAIL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <memory>
+#include <typeinfo>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/service_id.hpp"
+
+#if defined(BOOST_NO_TYPEID)
+# if !defined(ASIO_NO_TYPEID)
+# define ASIO_NO_TYPEID
+# endif // !defined(ASIO_NO_TYPEID)
+#endif // defined(BOOST_NO_TYPEID)
+
+namespace asio {
+namespace detail {
+
+class service_registry
+ : private noncopyable
+{
+public:
+ // Constructor.
+ service_registry(asio::io_service& o)
+ : owner_(o),
+ first_service_(0)
+ {
+ }
+
+ // Destructor.
+ ~service_registry()
+ {
+ // Shutdown all services. This must be done in a separate loop before the
+ // services are destroyed since the destructors of user-defined handler
+ // objects may try to access other service objects.
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ service->shutdown_service();
+ service = service->next_;
+ }
+
+ // Destroy all services.
+ while (first_service_)
+ {
+ asio::io_service::service* next_service = first_service_->next_;
+ delete first_service_;
+ first_service_ = next_service;
+ }
+ }
+
+ // Get the service object corresponding to the specified service type. Will
+ // create a new service object automatically if no such object already
+ // exists. Ownership of the service object is not transferred to the caller.
+ template <typename Service>
+ Service& use_service()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // First see if there is an existing service object for the given type.
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (service_id_matches(*service, Service::id))
+ return *static_cast<Service*>(service);
+ service = service->next_;
+ }
+
+ // Create a new service object. The service registry's mutex is not locked
+ // at this time to allow for nested calls into this function from the new
+ // service's constructor.
+ lock.unlock();
+ std::auto_ptr<Service> new_service(new Service(owner_));
+ init_service_id(*new_service, Service::id);
+ Service& new_service_ref = *new_service;
+ lock.lock();
+
+ // Check that nobody else created another service object of the same type
+ // while the lock was released.
+ service = first_service_;
+ while (service)
+ {
+ if (service_id_matches(*service, Service::id))
+ return *static_cast<Service*>(service);
+ service = service->next_;
+ }
+
+ // Service was successfully initialised, pass ownership to registry.
+ new_service->next_ = first_service_;
+ first_service_ = new_service.release();
+
+ return new_service_ref;
+ }
+
+ // Add a service object. Returns false on error, in which case ownership of
+ // the object is retained by the caller.
+ template <typename Service>
+ bool add_service(Service* new_service)
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Check if there is an existing service object for the given type.
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (service_id_matches(*service, Service::id))
+ return false;
+ service = service->next_;
+ }
+
+ // Take ownership of the service object.
+ init_service_id(*new_service, Service::id);
+ new_service->next_ = first_service_;
+ first_service_ = new_service;
+
+ return true;
+ }
+
+ // Check whether a service object of the specified type already exists.
+ template <typename Service>
+ bool has_service() const
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (service_id_matches(*service, Service::id))
+ return true;
+ service = service->next_;
+ }
+
+ return false;
+ }
+
+private:
+ // Set a service's id.
+ void init_service_id(asio::io_service::service& service,
+ const asio::io_service::id& id)
+ {
+ service.type_info_ = 0;
+ service.id_ = &id;
+ }
+
+#if !defined(ASIO_NO_TYPEID)
+ // Set a service's id.
+ template <typename Service>
+ void init_service_id(asio::io_service::service& service,
+ const asio::detail::service_id<Service>& /*id*/)
+ {
+ service.type_info_ = &typeid(Service);
+ service.id_ = 0;
+ }
+#endif // !defined(ASIO_NO_TYPEID)
+
+ // Check if a service matches the given id.
+ static bool service_id_matches(
+ const asio::io_service::service& service,
+ const asio::io_service::id& id)
+ {
+ return service.id_ == &id;
+ }
+
+#if !defined(ASIO_NO_TYPEID)
+ // Check if a service matches the given id.
+ template <typename Service>
+ static bool service_id_matches(
+ const asio::io_service::service& service,
+ const asio::detail::service_id<Service>& /*id*/)
+ {
+ return service.type_info_ != 0 && *service.type_info_ == typeid(Service);
+ }
+#endif // !defined(ASIO_NO_TYPEID)
+
+ // Mutex to protect access to internal data.
+ mutable asio::detail::mutex mutex_;
+
+ // The owner of this service registry and the services it contains.
+ asio::io_service& owner_;
+
+ // The first service in the list of contained services.
+ asio::io_service::service* first_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP
diff --git a/src/libtorrent/asio/detail/service_registry_fwd.hpp b/src/libtorrent/asio/detail/service_registry_fwd.hpp
new file mode 100644
index 0000000..136c0e9
--- /dev/null
+++ b/src/libtorrent/asio/detail/service_registry_fwd.hpp
@@ -0,0 +1,30 @@
+//
+// service_registry_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
+#define ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class service_registry;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
diff --git a/src/libtorrent/asio/detail/signal_blocker.hpp b/src/libtorrent/asio/detail/signal_blocker.hpp
new file mode 100644
index 0000000..e2148d7
--- /dev/null
+++ b/src/libtorrent/asio/detail/signal_blocker.hpp
@@ -0,0 +1,50 @@
+//
+// signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+# include "asio/detail/null_signal_blocker.hpp"
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/win_signal_blocker.hpp"
+#elif defined(BOOST_HAS_PTHREADS)
+# include "asio/detail/posix_signal_blocker.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_signal_blocker signal_blocker;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef win_signal_blocker signal_blocker;
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_signal_blocker signal_blocker;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP
diff --git a/src/libtorrent/asio/detail/signal_init.hpp b/src/libtorrent/asio/detail/signal_init.hpp
new file mode 100644
index 0000000..620182b
--- /dev/null
+++ b/src/libtorrent/asio/detail/signal_init.hpp
@@ -0,0 +1,51 @@
+//
+// signal_init.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SIGNAL_INIT_HPP
+#define ASIO_DETAIL_SIGNAL_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+#include <csignal>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <int Signal = SIGPIPE>
+class signal_init
+{
+public:
+ // Constructor.
+ signal_init()
+ {
+ std::signal(Signal, SIG_IGN);
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SIGNAL_INIT_HPP
diff --git a/src/libtorrent/asio/detail/socket_holder.hpp b/src/libtorrent/asio/detail/socket_holder.hpp
new file mode 100644
index 0000000..c60d21e
--- /dev/null
+++ b/src/libtorrent/asio/detail/socket_holder.hpp
@@ -0,0 +1,95 @@
+//
+// socket_holder.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SOCKET_HOLDER_HPP
+#define ASIO_DETAIL_SOCKET_HOLDER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+namespace asio {
+namespace detail {
+
+// Implement the resource acquisition is initialisation idiom for sockets.
+class socket_holder
+ : private noncopyable
+{
+public:
+ // Construct as an uninitialised socket.
+ socket_holder()
+ : socket_(invalid_socket)
+ {
+ }
+
+ // Construct to take ownership of the specified socket.
+ explicit socket_holder(socket_type s)
+ : socket_(s)
+ {
+ }
+
+ // Destructor.
+ ~socket_holder()
+ {
+ if (socket_ != invalid_socket)
+ {
+ asio::error_code ec;
+ socket_ops::close(socket_, ec);
+ }
+ }
+
+ // Get the underlying socket.
+ socket_type get() const
+ {
+ return socket_;
+ }
+
+ // Reset to an uninitialised socket.
+ void reset()
+ {
+ if (socket_ != invalid_socket)
+ {
+ asio::error_code ec;
+ socket_ops::close(socket_, ec);
+ socket_ = invalid_socket;
+ }
+ }
+
+ // Reset to take ownership of the specified socket.
+ void reset(socket_type s)
+ {
+ reset();
+ socket_ = s;
+ }
+
+ // Release ownership of the socket.
+ socket_type release()
+ {
+ socket_type tmp = socket_;
+ socket_ = invalid_socket;
+ return tmp;
+ }
+
+private:
+ // The underlying socket.
+ socket_type socket_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP
diff --git a/src/libtorrent/asio/detail/socket_ops.hpp b/src/libtorrent/asio/detail/socket_ops.hpp
new file mode 100644
index 0000000..231bc61
--- /dev/null
+++ b/src/libtorrent/asio/detail/socket_ops.hpp
@@ -0,0 +1,1893 @@
+//
+// socket_ops.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SOCKET_OPS_HPP
+#define ASIO_DETAIL_SOCKET_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <boost/assert.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <boost/detail/workaround.hpp>
+#include <new>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+struct msghdr { int msg_namelen; };
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux)
+// HP-UX doesn't declare these functions extern "C", so they are declared again
+// here to avoid linker errors about undefined symbols.
+extern "C" char* if_indextoname(unsigned int, char*);
+extern "C" unsigned int if_nametoindex(const char*);
+#endif // defined(__hpux)
+
+inline void clear_error(asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif
+ ec = asio::error_code();
+}
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+ asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error_code(WSAGetLastError(),
+ asio::error::get_system_category());
+#else
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+#endif
+ return return_value;
+}
+
+template <typename SockLenType>
+inline socket_type call_accept(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
+ socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
+ if (addrlen)
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+inline socket_type accept(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ clear_error(ec);
+
+ socket_type new_s = error_wrapper(call_accept(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (new_s == invalid_socket)
+ return new_s;
+
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+ int optval = 1;
+ int result = error_wrapper(::setsockopt(new_s,
+ SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+ if (result != 0)
+ {
+ ::close(new_s);
+ return invalid_socket;
+ }
+#endif
+
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ clear_error(ec);
+#endif
+
+ return new_s;
+}
+
+template <typename SockLenType>
+inline int call_bind(SockLenType msghdr::*,
+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+ return ::bind(s, addr, (SockLenType)addrlen);
+}
+
+inline int bind(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_bind(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+inline int close(socket_type s, asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::closesocket(s), ec);
+# if defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+# endif
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ return error_wrapper(::close(s), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int shutdown(socket_type s, int what, asio::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::shutdown(s, what), ec);
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+template <typename SockLenType>
+inline int call_connect(SockLenType msghdr::*,
+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+ return ::connect(s, addr, (SockLenType)addrlen);
+}
+
+inline int connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_connect(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+inline int socketpair(int af, int type, int protocol,
+ socket_type sv[2], asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(af);
+ (void)(type);
+ (void)(protocol);
+ (void)(sv);
+ ec = asio::error::operation_not_supported;
+ return -1;
+#else
+ clear_error(ec);
+ return error_wrapper(::socketpair(af, type, protocol, sv), ec);
+#endif
+}
+
+inline int listen(socket_type s, int backlog, asio::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::listen(s, backlog), ec);
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+inline void init_buf(buf& b, void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(data);
+ b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.iov_base = data;
+ b.iov_len = size;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline void init_buf(buf& b, const void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(const_cast<void*>(data));
+ b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.iov_base = const_cast<void*>(data);
+ b.iov_len = size;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
+{
+ name = addr;
+}
+
+inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
+{
+ name = const_cast<socket_addr_type*>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
+{
+ name = reinterpret_cast<T>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
+{
+ name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
+}
+
+inline int recv(socket_type s, buf* bufs, size_t count, int flags,
+ asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Receive some data.
+ DWORD recv_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = error_wrapper(::WSARecv(s, bufs,
+ recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
+ if (result != 0)
+ return -1;
+# if defined(UNDER_CE)
+ clear_error(ec);
+# endif
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = count;
+ return error_wrapper(::recvmsg(s, &msg, flags), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Receive some data.
+ DWORD recv_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int tmp_addrlen = (int)*addrlen;
+ int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
+ &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
+ *addrlen = (std::size_t)tmp_addrlen;
+ if (result != 0)
+ return -1;
+# if defined(UNDER_CE)
+ clear_error(ec);
+# endif
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = *addrlen;
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = count;
+ int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ *addrlen = msg.msg_namelen;
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int send(socket_type s, const buf* bufs, size_t count, int flags,
+ asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Send the data.
+ DWORD send_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD send_flags = flags;
+ int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
+ send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
+ if (result != 0)
+ return -1;
+# if defined(UNDER_CE)
+ clear_error(ec);
+# endif
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = const_cast<buf*>(bufs);
+ msg.msg_iovlen = count;
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ return error_wrapper(::sendmsg(s, &msg, flags), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
+ const socket_addr_type* addr, std::size_t addrlen,
+ asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Send the data.
+ DWORD send_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
+ send_buf_count, &bytes_transferred, flags, addr,
+ static_cast<int>(addrlen), 0, 0), ec);
+ if (result != 0)
+ return -1;
+# if defined(UNDER_CE)
+ clear_error(ec);
+# endif
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = addrlen;
+ msg.msg_iov = const_cast<buf*>(bufs);
+ msg.msg_iovlen = count;
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ return error_wrapper(::sendmsg(s, &msg, flags), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline socket_type socket(int af, int type, int protocol,
+ asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
+ WSA_FLAG_OVERLAPPED), ec);
+ if (s == invalid_socket)
+ return s;
+
+ if (af == AF_INET6)
+ {
+ // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
+ // false. This will only succeed on Windows Vista and later versions of
+ // Windows, where a dual-stack IPv4/v6 implementation is available.
+ DWORD optval = 0;
+ ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ reinterpret_cast<const char*>(&optval), sizeof(optval));
+ }
+
+# if defined(UNDER_CE)
+ clear_error(ec);
+# endif
+
+ return s;
+#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+ socket_type s = error_wrapper(::socket(af, type, protocol), ec);
+ if (s == invalid_socket)
+ return s;
+
+ int optval = 1;
+ int result = error_wrapper(::setsockopt(s,
+ SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+ if (result != 0)
+ {
+ ::close(s);
+ return invalid_socket;
+ }
+
+ return s;
+#else
+ return error_wrapper(::socket(af, type, protocol), ec);
+#endif
+}
+
+template <typename SockLenType>
+inline int call_setsockopt(SockLenType msghdr::*,
+ socket_type s, int level, int optname,
+ const void* optval, std::size_t optlen)
+{
+ return ::setsockopt(s, level, optname,
+ (const char*)optval, (SockLenType)optlen);
+}
+
+inline int setsockopt(socket_type s, int level, int optname,
+ const void* optval, std::size_t optlen, asio::error_code& ec)
+{
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
+ if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
+ {
+ clear_error(ec);
+ return error_wrapper(sso(s, level, optname,
+ reinterpret_cast<const char*>(optval),
+ static_cast<int>(optlen)), ec);
+ }
+ }
+ ec = asio::error::fault;
+ return -1;
+#else // defined(__BORLANDC__)
+ clear_error(ec);
+ int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+# if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+# endif
+ return result;
+#endif // defined(__BORLANDC__)
+}
+
+template <typename SockLenType>
+inline int call_getsockopt(SockLenType msghdr::*,
+ socket_type s, int level, int optname,
+ void* optval, std::size_t* optlen)
+{
+ SockLenType tmp_optlen = (SockLenType)*optlen;
+ int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
+ *optlen = (std::size_t)tmp_optlen;
+ return result;
+}
+
+inline int getsockopt(socket_type s, int level, int optname, void* optval,
+ size_t* optlen, asio::error_code& ec)
+{
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
+ if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
+ {
+ clear_error(ec);
+ int tmp_optlen = static_cast<int>(*optlen);
+ int result = error_wrapper(gso(s, level, optname,
+ reinterpret_cast<char*>(optval), &tmp_optlen), ec);
+ *optlen = static_cast<size_t>(tmp_optlen);
+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+ {
+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
+ // only supported on Windows Vista and later. To simplify program logic
+ // we will fake success of getting this option and specify that the
+ // value is non-zero (i.e. true). This corresponds to the behavior of
+ // IPv6 sockets on Windows platforms pre-Vista.
+ *static_cast<DWORD*>(optval) = 1;
+ clear_error(ec);
+ }
+ return result;
+ }
+ }
+ ec = asio::error::fault;
+ return -1;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ clear_error(ec);
+ int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+ {
+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
+ // supported on Windows Vista and later. To simplify program logic we will
+ // fake success of getting this option and specify that the value is
+ // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
+ // on Windows platforms pre-Vista.
+ *static_cast<DWORD*>(optval) = 1;
+ clear_error(ec);
+ }
+# if defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+# endif
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ clear_error(ec);
+ int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+#if defined(__linux__)
+ if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
+ && (optname == SO_SNDBUF || optname == SO_RCVBUF))
+ {
+ // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
+ // to set the buffer size to N*2. Linux puts additional stuff into the
+ // buffers so that only about half is actually available to the application.
+ // The retrieved value is divided by 2 here to make it appear as though the
+ // correct value has been set.
+ *static_cast<int*>(optval) /= 2;
+ }
+#endif // defined(__linux__)
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+template <typename SockLenType>
+inline int call_getpeername(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = (SockLenType)*addrlen;
+ int result = ::getpeername(s, addr, &tmp_addrlen);
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+inline int getpeername(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_getpeername(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+template <typename SockLenType>
+inline int call_getsockname(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = (SockLenType)*addrlen;
+ int result = ::getsockname(s, addr, &tmp_addrlen);
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+inline int getsockname(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_getsockname(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
+ asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
+# if defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+# endif
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ return error_wrapper(::ioctl(s, cmd, arg), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (!readfds && !writefds && !exceptfds && timeout)
+ {
+ DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+ if (milliseconds == 0)
+ milliseconds = 1; // Force context switch.
+ ::Sleep(milliseconds);
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // The select() call allows timeout values measured in microseconds, but the
+ // system clock (as wrapped by boost::posix_time::microsec_clock) typically
+ // has a resolution of 10 milliseconds. This can lead to a spinning select
+ // reactor, meaning increased CPU usage, when waiting for the earliest
+ // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
+ // spin we'll use a minimum timeout of 1 millisecond.
+ if (timeout && timeout->tv_sec == 0
+ && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
+ timeout->tv_usec = 1000;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux) && defined(__HP_aCC)
+ timespec ts;
+ ts.tv_sec = timeout ? timeout->tv_sec : 0;
+ ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
+ return error_wrapper(::pselect(nfds, readfds,
+ writefds, exceptfds, timeout ? &ts : 0, 0), ec);
+#else
+ int result = error_wrapper(::select(nfds, readfds,
+ writefds, exceptfds, timeout), ec);
+# if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result >= 0)
+ clear_error(ec);
+# endif
+ return result;
+#endif
+}
+
+inline int poll_read(socket_type s, asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ FD_SET fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ clear_error(ec);
+ int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
+# if defined(UNDER_CE)
+ if (result >= 0)
+ clear_error(ec);
+# endif
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ clear_error(ec);
+ return error_wrapper(::poll(&fds, 1, -1), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int poll_write(socket_type s, asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ FD_SET fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ clear_error(ec);
+ int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
+# if defined(UNDER_CE)
+ if (result >= 0)
+ clear_error(ec);
+# endif
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_error(ec);
+ return error_wrapper(::poll(&fds, 1, -1), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
+ unsigned long scope_id, asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy.
+
+ if (af != AF_INET && af != AF_INET6)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
+ DWORD address_length;
+ if (af == AF_INET)
+ {
+ address_length = sizeof(sockaddr_in4_type);
+ address.v4.sin_family = AF_INET;
+ address.v4.sin_port = 0;
+ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
+ }
+ else // AF_INET6
+ {
+ address_length = sizeof(sockaddr_in6_type);
+ address.v6.sin6_family = AF_INET6;
+ address.v6.sin6_port = 0;
+ address.v6.sin6_flowinfo = 0;
+ address.v6.sin6_scope_id = scope_id;
+ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
+ }
+
+ DWORD string_length = static_cast<DWORD>(length);
+#if defined(BOOST_NO_ANSI_APIS)
+ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
+ int result = error_wrapper(::WSAAddressToStringW(&address.base,
+ address_length, 0, string_buffer, &string_length), ec);
+ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
+#else
+ int result = error_wrapper(::WSAAddressToStringA(
+ &address.base, address_length, 0, dest, &string_length), ec);
+#endif
+
+ // Windows may set error code on success.
+ if (result != socket_error_retval)
+ clear_error(ec);
+
+ // Windows may not set an error code on failure.
+ else if (result == socket_error_retval && !ec)
+ ec = asio::error::invalid_argument;
+
+ return result == socket_error_retval ? 0 : dest;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec);
+ if (result == 0 && !ec)
+ ec = asio::error::invalid_argument;
+ if (result != 0 && af == AF_INET6 && scope_id != 0)
+ {
+ using namespace std; // For strcat and sprintf.
+ char if_name[IF_NAMESIZE + 1] = "%";
+ const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
+ bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+ if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
+ sprintf(if_name + 1, "%lu", scope_id);
+ strcat(dest, if_name);
+ }
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int inet_pton(int af, const char* src, void* dest,
+ unsigned long* scope_id, asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy and strcmp.
+
+ if (af != AF_INET && af != AF_INET6)
+ {
+ ec = asio::error::address_family_not_supported;
+ return -1;
+ }
+
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
+ int address_length = sizeof(sockaddr_storage_type);
+#if defined(BOOST_NO_ANSI_APIS)
+ int num_wide_chars = strlen(src) + 1;
+ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
+ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
+ int result = error_wrapper(::WSAStringToAddressW(
+ wide_buffer, af, 0, &address.base, &address_length), ec);
+#else
+ int result = error_wrapper(::WSAStringToAddressA(
+ const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
+#endif
+
+ if (af == AF_INET)
+ {
+ if (result != socket_error_retval)
+ {
+ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
+ clear_error(ec);
+ }
+ else if (strcmp(src, "255.255.255.255") == 0)
+ {
+ static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
+ clear_error(ec);
+ }
+ }
+ else // AF_INET6
+ {
+ if (result != socket_error_retval)
+ {
+ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
+ if (scope_id)
+ *scope_id = address.v6.sin6_scope_id;
+ clear_error(ec);
+ }
+ }
+
+ // Windows may not set an error code on failure.
+ if (result == socket_error_retval && !ec)
+ ec = asio::error::invalid_argument;
+
+#if defined(UNDER_CE)
+ if (result != socket_error_retval)
+ clear_error(ec);
+#endif
+
+ return result == socket_error_retval ? -1 : 1;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::inet_pton(af, src, dest), ec);
+ if (result <= 0 && !ec)
+ ec = asio::error::invalid_argument;
+ if (result > 0 && af == AF_INET6 && scope_id)
+ {
+ using namespace std; // For strchr and atoi.
+ *scope_id = 0;
+ if (const char* if_name = strchr(src, '%'))
+ {
+ in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
+ bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+ if (is_link_local)
+ *scope_id = if_nametoindex(if_name + 1);
+ if (*scope_id == 0)
+ *scope_id = atoi(if_name + 1);
+ }
+ }
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int gethostname(char* name, int namelen, asio::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::gethostname(name, namelen), ec);
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
+ || defined(__MACH__) && defined(__APPLE__)
+
+// The following functions are only needed for emulation of getaddrinfo and
+// getnameinfo.
+
+inline asio::error_code translate_netdb_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return asio::error_code();
+ case HOST_NOT_FOUND:
+ return asio::error::host_not_found;
+ case TRY_AGAIN:
+ return asio::error::host_not_found_try_again;
+ case NO_RECOVERY:
+ return asio::error::no_recovery;
+ case NO_DATA:
+ return asio::error::no_data;
+ default:
+ BOOST_ASSERT(false);
+ return asio::error::invalid_argument;
+ }
+}
+
+inline hostent* gethostbyaddr(const char* addr, int length, int af,
+ hostent* result, char* buffer, int buflength, asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
+ if (!retval)
+ return 0;
+# if defined(UNDER_CE)
+ clear_error(ec);
+# endif
+ *result = *retval;
+ return retval;
+#elif defined(__sun) || defined(__QNX__)
+ int error = 0;
+ hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
+ buffer, buflength, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+ (void)(buffer);
+ (void)(buflength);
+ int error = 0;
+ hostent* retval = error_wrapper(::getipnodebyaddr(
+ addr, length, af, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ if (!retval)
+ return 0;
+ *result = *retval;
+ return retval;
+#else
+ hostent* retval = 0;
+ int error = 0;
+ error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
+ buflength, &retval, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#endif
+}
+
+inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
+ char* buffer, int buflength, int ai_flags, asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ hostent* retval = error_wrapper(::gethostbyname(name), ec);
+ if (!retval)
+ return 0;
+# if defined(UNDER_CE)
+ clear_error(ec);
+# endif
+ *result = *retval;
+ return result;
+#elif defined(__sun) || defined(__QNX__)
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ int error = 0;
+ hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
+ buflength, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+ (void)(buffer);
+ (void)(buflength);
+ int error = 0;
+ hostent* retval = error_wrapper(::getipnodebyname(
+ name, af, ai_flags, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ if (!retval)
+ return 0;
+ *result = *retval;
+ return retval;
+#else
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ hostent* retval = 0;
+ int error = 0;
+ error_wrapper(::gethostbyname_r(name, result,
+ buffer, buflength, &retval, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#endif
+}
+
+inline void freehostent(hostent* h)
+{
+#if defined(__MACH__) && defined(__APPLE__)
+ if (h)
+ ::freehostent(h);
+#else
+ (void)(h);
+#endif
+}
+
+// Emulation of getaddrinfo based on implementation in:
+// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
+
+struct gai_search
+{
+ const char* host;
+ int family;
+};
+
+inline int gai_nsearch(const char* host,
+ const addrinfo_type* hints, gai_search (&search)[2])
+{
+ int search_count = 0;
+ if (host == 0 || host[0] == '\0')
+ {
+ if (hints->ai_flags & AI_PASSIVE)
+ {
+ // No host and AI_PASSIVE implies wildcard bind.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = "0::0";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = "0::0";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // No host and not AI_PASSIVE means connect to local host.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Host is specified.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = host;
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ return search_count;
+}
+
+template <typename T>
+inline T* gai_alloc(std::size_t size = sizeof(T))
+{
+ using namespace std;
+ T* p = static_cast<T*>(::operator new(size, std::nothrow));
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+inline void gai_free(void* p)
+{
+ ::operator delete(p);
+}
+
+inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
+{
+ using namespace std;
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ strcpy_s(target, max_size, source);
+#else
+ *target = 0;
+ strncat(target, source, max_size);
+#endif
+}
+
+enum { gai_clone_flag = 1 << 30 };
+
+inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
+ const void* addr, int family)
+{
+ using namespace std;
+
+ addrinfo_type* ai = gai_alloc<addrinfo_type>();
+ if (ai == 0)
+ return EAI_MEMORY;
+
+ ai->ai_next = 0;
+ **next = ai;
+ *next = &ai->ai_next;
+
+ ai->ai_canonname = 0;
+ ai->ai_socktype = hints->ai_socktype;
+ if (ai->ai_socktype == 0)
+ ai->ai_flags |= gai_clone_flag;
+ ai->ai_protocol = hints->ai_protocol;
+ ai->ai_family = family;
+
+ switch (ai->ai_family)
+ {
+ case AF_INET:
+ {
+ sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
+ if (sinptr == 0)
+ return EAI_MEMORY;
+ sinptr->sin_family = AF_INET;
+ memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
+ ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
+ ai->ai_addrlen = sizeof(sockaddr_in4_type);
+ break;
+ }
+ case AF_INET6:
+ {
+ sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
+ if (sin6ptr == 0)
+ return EAI_MEMORY;
+ sin6ptr->sin6_family = AF_INET6;
+ memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
+ ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
+ ai->ai_addrlen = sizeof(sockaddr_in6_type);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+inline addrinfo_type* gai_clone(addrinfo_type* ai)
+{
+ using namespace std;
+
+ addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
+ if (new_ai == 0)
+ return new_ai;
+
+ new_ai->ai_next = ai->ai_next;
+ ai->ai_next = new_ai;
+
+ new_ai->ai_flags = 0;
+ new_ai->ai_family = ai->ai_family;
+ new_ai->ai_socktype = ai->ai_socktype;
+ new_ai->ai_protocol = ai->ai_protocol;
+ new_ai->ai_canonname = 0;
+ new_ai->ai_addrlen = ai->ai_addrlen;
+ new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
+ memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+
+ return new_ai;
+}
+
+inline int gai_port(addrinfo_type* aihead, int port, int socktype)
+{
+ int num_found = 0;
+
+ for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
+ {
+ if (ai->ai_flags & gai_clone_flag)
+ {
+ if (ai->ai_socktype != 0)
+ {
+ ai = gai_clone(ai);
+ if (ai == 0)
+ return -1;
+ // ai now points to newly cloned entry.
+ }
+ }
+ else if (ai->ai_socktype != socktype)
+ {
+ // Ignore if mismatch on socket type.
+ continue;
+ }
+
+ ai->ai_socktype = socktype;
+
+ switch (ai->ai_family)
+ {
+ case AF_INET:
+ {
+ sockaddr_in4_type* sinptr =
+ reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+ sinptr->sin_port = port;
+ ++num_found;
+ break;
+ }
+ case AF_INET6:
+ {
+ sockaddr_in6_type* sin6ptr =
+ reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
+ sin6ptr->sin6_port = port;
+ ++num_found;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return num_found;
+}
+
+inline int gai_serv(addrinfo_type* aihead,
+ const addrinfo_type* hints, const char* serv)
+{
+ using namespace std;
+
+ int num_found = 0;
+
+ if (
+#if defined(AI_NUMERICSERV)
+ (hints->ai_flags & AI_NUMERICSERV) ||
+#endif
+ isdigit(serv[0]))
+ {
+ int port = htons(atoi(serv));
+ if (hints->ai_socktype)
+ {
+ // Caller specifies socket type.
+ int rc = gai_port(aihead, port, hints->ai_socktype);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ else
+ {
+ // Caller does not specify socket type.
+ int rc = gai_port(aihead, port, SOCK_STREAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ rc = gai_port(aihead, port, SOCK_DGRAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ else
+ {
+ // Try service name with TCP first, then UDP.
+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
+ {
+ servent* sptr = getservbyname(serv, "tcp");
+ if (sptr != 0)
+ {
+ int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
+ {
+ servent* sptr = getservbyname(serv, "udp");
+ if (sptr != 0)
+ {
+ int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ }
+
+ if (num_found == 0)
+ {
+ if (hints->ai_socktype == 0)
+ {
+ // All calls to getservbyname() failed.
+ return EAI_NONAME;
+ }
+ else
+ {
+ // Service not supported for socket type.
+ return EAI_SERVICE;
+ }
+ }
+
+ return 0;
+}
+
+inline int gai_echeck(const char* host, const char* service,
+ int flags, int family, int socktype, int protocol)
+{
+ (void)(flags);
+ (void)(protocol);
+
+ // Host or service must be specified.
+ if (host == 0 || host[0] == '\0')
+ if (service == 0 || service[0] == '\0')
+ return EAI_NONAME;
+
+ // Check combination of family and socket type.
+ switch (family)
+ {
+ case AF_UNSPEC:
+ break;
+ case AF_INET:
+ case AF_INET6:
+ if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
+ return EAI_SOCKTYPE;
+ break;
+ default:
+ return EAI_FAMILY;
+ }
+
+ return 0;
+}
+
+inline void freeaddrinfo_emulation(addrinfo_type* aihead)
+{
+ addrinfo_type* ai = aihead;
+ while (ai)
+ {
+ gai_free(ai->ai_addr);
+ gai_free(ai->ai_canonname);
+ addrinfo_type* ainext = ai->ai_next;
+ gai_free(ai);
+ ai = ainext;
+ }
+}
+
+inline int getaddrinfo_emulation(const char* host, const char* service,
+ const addrinfo_type* hintsp, addrinfo_type** result)
+{
+ // Set up linked list of addrinfo structures.
+ addrinfo_type* aihead = 0;
+ addrinfo_type** ainext = &aihead;
+ char* canon = 0;
+
+ // Supply default hints if not specified by caller.
+ addrinfo_type hints = addrinfo_type();
+ hints.ai_family = AF_UNSPEC;
+ if (hintsp)
+ hints = *hintsp;
+
+ // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
+ // and AI_ALL flags.
+#if defined(AI_V4MAPPED)
+ if (hints.ai_family != AF_INET6)
+ hints.ai_flags &= ~AI_V4MAPPED;
+#endif
+#if defined(AI_ALL)
+ if (hints.ai_family != AF_INET6)
+ hints.ai_flags &= ~AI_ALL;
+#endif
+
+ // Basic error checking.
+ int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
+ hints.ai_socktype, hints.ai_protocol);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return rc;
+ }
+
+ gai_search search[2];
+ int search_count = gai_nsearch(host, &hints, search);
+ for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
+ {
+ // Check for IPv4 dotted decimal string.
+ in4_addr_type inaddr;
+ asio::error_code ec;
+ if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == AF_INET)
+ {
+ rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return rc;
+ }
+ }
+ continue;
+ }
+
+ // Check for IPv6 hex string.
+ in6_addr_type in6addr;
+ if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == AF_INET6)
+ {
+ rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return rc;
+ }
+ }
+ continue;
+ }
+
+ // Look up hostname.
+ hostent hent;
+ char hbuf[8192] = "";
+ hostent* hptr = socket_ops::gethostbyname(sptr->host,
+ sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
+ if (hptr == 0)
+ {
+ if (search_count == 2)
+ {
+ // Failure is OK if there are multiple searches.
+ continue;
+ }
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ if (ec == asio::error::host_not_found)
+ return EAI_NONAME;
+ if (ec == asio::error::host_not_found_try_again)
+ return EAI_AGAIN;
+ if (ec == asio::error::no_recovery)
+ return EAI_FAIL;
+ if (ec == asio::error::no_data)
+ return EAI_NONAME;
+ return EAI_NONAME;
+ }
+
+ // Check for address family mismatch if one was specified.
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ socket_ops::freehostent(hptr);
+ return EAI_FAMILY;
+ }
+
+ // Save canonical name first time.
+ if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
+ && (hints.ai_flags & AI_CANONNAME) && canon == 0)
+ {
+ std::size_t canon_len = strlen(hptr->h_name) + 1;
+ canon = gai_alloc<char>(canon_len);
+ if (canon == 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ socket_ops::freehostent(hptr);
+ return EAI_MEMORY;
+ }
+ gai_strcpy(canon, hptr->h_name, canon_len);
+ }
+
+ // Create an addrinfo structure for each returned address.
+ for (char** ap = hptr->h_addr_list; *ap; ++ap)
+ {
+ rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ socket_ops::freehostent(hptr);
+ return EAI_FAMILY;
+ }
+ }
+
+ socket_ops::freehostent(hptr);
+ }
+
+ // Check if we found anything.
+ if (aihead == 0)
+ {
+ gai_free(canon);
+ return EAI_NONAME;
+ }
+
+ // Return canonical name in first entry.
+ if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
+ {
+ if (canon)
+ {
+ aihead->ai_canonname = canon;
+ canon = 0;
+ }
+ else
+ {
+ std::size_t canonname_len = strlen(search[0].host) + 1;
+ aihead->ai_canonname = gai_alloc<char>(canonname_len);
+ if (aihead->ai_canonname == 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return EAI_MEMORY;
+ }
+ gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
+ }
+ }
+ gai_free(canon);
+
+ // Process the service name.
+ if (service != 0 && service[0] != '\0')
+ {
+ rc = gai_serv(aihead, &hints, service);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return rc;
+ }
+ }
+
+ // Return result to caller.
+ *result = aihead;
+ return 0;
+}
+
+inline asio::error_code getnameinfo_emulation(
+ const socket_addr_type* sa, std::size_t salen, char* host,
+ std::size_t hostlen, char* serv, std::size_t servlen, int flags,
+ asio::error_code& ec)
+{
+ using namespace std;
+
+ const char* addr;
+ size_t addr_len;
+ unsigned short port;
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (salen != sizeof(sockaddr_in4_type))
+ {
+ return ec = asio::error::invalid_argument;
+ }
+ addr = reinterpret_cast<const char*>(
+ &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
+ addr_len = sizeof(in4_addr_type);
+ port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
+ break;
+ case AF_INET6:
+ if (salen != sizeof(sockaddr_in6_type))
+ {
+ return ec = asio::error::invalid_argument;
+ }
+ addr = reinterpret_cast<const char*>(
+ &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
+ addr_len = sizeof(in6_addr_type);
+ port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
+ break;
+ default:
+ return ec = asio::error::address_family_not_supported;
+ }
+
+ if (host && hostlen > 0)
+ {
+ if (flags & NI_NUMERICHOST)
+ {
+ if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
+ {
+ return ec;
+ }
+ }
+ else
+ {
+ hostent hent;
+ char hbuf[8192] = "";
+ hostent* hptr = socket_ops::gethostbyaddr(addr,
+ static_cast<int>(addr_len), sa->sa_family,
+ &hent, hbuf, sizeof(hbuf), ec);
+ if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
+ {
+ if (flags & NI_NOFQDN)
+ {
+ char* dot = strchr(hptr->h_name, '.');
+ if (dot)
+ {
+ *dot = 0;
+ }
+ }
+ gai_strcpy(host, hptr->h_name, hostlen);
+ socket_ops::freehostent(hptr);
+ }
+ else
+ {
+ socket_ops::freehostent(hptr);
+ if (flags & NI_NAMEREQD)
+ {
+ return ec = asio::error::host_not_found;
+ }
+ if (socket_ops::inet_ntop(sa->sa_family,
+ addr, host, hostlen, 0, ec) == 0)
+ {
+ return ec;
+ }
+ }
+ }
+ }
+
+ if (serv && servlen > 0)
+ {
+ if (flags & NI_NUMERICSERV)
+ {
+ if (servlen < 6)
+ {
+ return ec = asio::error::no_buffer_space;
+ }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+ sprintf(serv, "%u", ntohs(port));
+#endif
+ }
+ else
+ {
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ ::pthread_mutex_lock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
+ if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
+ {
+ gai_strcpy(serv, sptr->s_name, servlen);
+ }
+ else
+ {
+ if (servlen < 6)
+ {
+ return ec = asio::error::no_buffer_space;
+ }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+ sprintf(serv, "%u", ntohs(port));
+#endif
+ }
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ ::pthread_mutex_unlock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ }
+ }
+
+ clear_error(ec);
+ return ec;
+}
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // || defined(__MACH__) && defined(__APPLE__)
+
+inline asio::error_code translate_addrinfo_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return asio::error_code();
+ case EAI_AGAIN:
+ return asio::error::host_not_found_try_again;
+ case EAI_BADFLAGS:
+ return asio::error::invalid_argument;
+ case EAI_FAIL:
+ return asio::error::no_recovery;
+ case EAI_FAMILY:
+ return asio::error::address_family_not_supported;
+ case EAI_MEMORY:
+ return asio::error::no_memory;
+ case EAI_NONAME:
+#if defined(EAI_ADDRFAMILY)
+ case EAI_ADDRFAMILY:
+#endif
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
+#endif
+ return asio::error::host_not_found;
+ case EAI_SERVICE:
+ return asio::error::service_not_found;
+ case EAI_SOCKTYPE:
+ return asio::error::socket_type_not_supported;
+ default: // Possibly the non-portable EAI_SYSTEM.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ return asio::error_code(
+ WSAGetLastError(), asio::error::get_system_category());
+#else
+ return asio::error_code(
+ errno, asio::error::get_system_category());
+#endif
+ }
+}
+
+inline asio::error_code getaddrinfo(const char* host,
+ const char* service, const addrinfo_type* hints, addrinfo_type** result,
+ asio::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // Building for Windows XP, Windows Server 2003, or later.
+ int error = ::getaddrinfo(host, service, hints, result);
+ return ec = translate_addrinfo_error(error);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *gai_t)(const char*,
+ const char*, const addrinfo_type*, addrinfo_type**);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
+ {
+ int error = gai(host, service, hints, result);
+ return ec = translate_addrinfo_error(error);
+ }
+ }
+ int error = getaddrinfo_emulation(host, service, hints, result);
+ return ec = translate_addrinfo_error(error);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+ int error = getaddrinfo_emulation(host, service, hints, result);
+ return ec = translate_addrinfo_error(error);
+#else
+ int error = ::getaddrinfo(host, service, hints, result);
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+inline void freeaddrinfo(addrinfo_type* ai)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // Building for Windows XP, Windows Server 2003, or later.
+ ::freeaddrinfo(ai);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *fai_t)(addrinfo_type*);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
+ {
+ fai(ai);
+ return;
+ }
+ }
+ freeaddrinfo_emulation(ai);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+ freeaddrinfo_emulation(ai);
+#else
+ ::freeaddrinfo(ai);
+#endif
+}
+
+inline asio::error_code getnameinfo(const socket_addr_type* addr,
+ std::size_t addrlen, char* host, std::size_t hostlen,
+ char* serv, std::size_t servlen, int flags, asio::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // Building for Windows XP, Windows Server 2003, or later.
+ clear_error(ec);
+ int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
+ host, static_cast<DWORD>(hostlen),
+ serv, static_cast<DWORD>(servlen), flags);
+ return ec = translate_addrinfo_error(error);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *gni_t)(const socket_addr_type*,
+ int, char*, DWORD, char*, DWORD, int);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
+ {
+ clear_error(ec);
+ int error = gni(addr, static_cast<int>(addrlen),
+ host, static_cast<DWORD>(hostlen),
+ serv, static_cast<DWORD>(servlen), flags);
+ return ec = translate_addrinfo_error(error);
+ }
+ }
+ clear_error(ec);
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+ using namespace std; // For memcpy.
+ sockaddr_storage_type tmp_addr;
+ memcpy(&tmp_addr, addr, addrlen);
+ tmp_addr.ss_len = addrlen;
+ addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
+ clear_error(ec);
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+#else
+ clear_error(ec);
+ int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+inline u_long_type network_to_host_long(u_long_type value)
+{
+ return ntohl(value);
+}
+
+inline u_long_type host_to_network_long(u_long_type value)
+{
+ return htonl(value);
+}
+
+inline u_short_type network_to_host_short(u_short_type value)
+{
+ return ntohs(value);
+}
+
+inline u_short_type host_to_network_short(u_short_type value)
+{
+ return htons(value);
+}
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/src/libtorrent/asio/detail/socket_option.hpp b/src/libtorrent/asio/detail/socket_option.hpp
new file mode 100644
index 0000000..27c898a
--- /dev/null
+++ b/src/libtorrent/asio/detail/socket_option.hpp
@@ -0,0 +1,309 @@
+//
+// socket_option.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SOCKET_OPTION_HPP
+#define ASIO_DETAIL_SOCKET_OPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <stdexcept>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_option {
+
+// Helper template for implementing boolean-based options.
+template <int Level, int Name>
+class boolean
+{
+public:
+ // Default constructor.
+ boolean()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific option value.
+ explicit boolean(bool v)
+ : value_(v ? 1 : 0)
+ {
+ }
+
+ // Set the current value of the boolean.
+ boolean& operator=(bool v)
+ {
+ value_ = v ? 1 : 0;
+ return *this;
+ }
+
+ // Get the current value of the boolean.
+ bool value() const
+ {
+ return !!value_;
+ }
+
+ // Convert to bool.
+ operator bool() const
+ {
+ return !!value_;
+ }
+
+ // Test for false.
+ bool operator!() const
+ {
+ return !value_;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return Name;
+ }
+
+ // Get the address of the boolean data.
+ template <typename Protocol>
+ int* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the boolean data.
+ template <typename Protocol>
+ const int* data(const Protocol&) const
+ {
+ return &value_;
+ }
+
+ // Get the size of the boolean data.
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return sizeof(value_);
+ }
+
+ // Set the size of the boolean data.
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t s)
+ {
+ // On some platforms (e.g. Windows Vista), the getsockopt function will
+ // return the size of a boolean socket option as one byte, even though a
+ // four byte integer was passed in.
+ switch (s)
+ {
+ case sizeof(char):
+ value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0;
+ break;
+ case sizeof(value_):
+ break;
+ default:
+ throw std::length_error("boolean socket option resize");
+ }
+ }
+
+private:
+ int value_;
+};
+
+// Helper template for implementing integer options.
+template <int Level, int Name>
+class integer
+{
+public:
+ // Default constructor.
+ integer()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific option value.
+ explicit integer(int v)
+ : value_(v)
+ {
+ }
+
+ // Set the value of the int option.
+ integer& operator=(int v)
+ {
+ value_ = v;
+ return *this;
+ }
+
+ // Get the current value of the int option.
+ int value() const
+ {
+ return value_;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return Name;
+ }
+
+ // Get the address of the int data.
+ template <typename Protocol>
+ int* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the int data.
+ template <typename Protocol>
+ const int* data(const Protocol&) const
+ {
+ return &value_;
+ }
+
+ // Get the size of the int data.
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return sizeof(value_);
+ }
+
+ // Set the size of the int data.
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t s)
+ {
+ if (s != sizeof(value_))
+ throw std::length_error("integer socket option resize");
+ }
+
+private:
+ int value_;
+};
+
+// Helper template for implementing linger options.
+template <int Level, int Name>
+class linger
+{
+public:
+ // Default constructor.
+ linger()
+ {
+ value_.l_onoff = 0;
+ value_.l_linger = 0;
+ }
+
+ // Construct with specific option values.
+ linger(bool e, int t)
+ {
+ enabled(e);
+ timeout(t);
+ }
+
+ // Set the value for whether linger is enabled.
+ void enabled(bool value)
+ {
+ value_.l_onoff = value ? 1 : 0;
+ }
+
+ // Get the value for whether linger is enabled.
+ bool enabled() const
+ {
+ return value_.l_onoff != 0;
+ }
+
+ // Set the value for the linger timeout.
+ void timeout(int value)
+ {
+#if defined(WIN32)
+ value_.l_linger = static_cast<u_short>(value);
+#else
+ value_.l_linger = value;
+#endif
+ }
+
+ // Get the value for the linger timeout.
+ int timeout() const
+ {
+ return static_cast<int>(value_.l_linger);
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return Name;
+ }
+
+ // Get the address of the linger data.
+ template <typename Protocol>
+ ::linger* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the linger data.
+ template <typename Protocol>
+ const ::linger* data(const Protocol&) const
+ {
+ return &value_;
+ }
+
+ // Get the size of the linger data.
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return sizeof(value_);
+ }
+
+ // Set the size of the int data.
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t s)
+ {
+ if (s != sizeof(value_))
+ throw std::length_error("linger socket option resize");
+ }
+
+private:
+ ::linger value_;
+};
+
+} // namespace socket_option
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPTION_HPP
diff --git a/src/libtorrent/asio/detail/socket_select_interrupter.hpp b/src/libtorrent/asio/detail/socket_select_interrupter.hpp
new file mode 100644
index 0000000..f978f7c
--- /dev/null
+++ b/src/libtorrent/asio/detail/socket_select_interrupter.hpp
@@ -0,0 +1,187 @@
+//
+// socket_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstdlib>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+
+class socket_select_interrupter
+{
+public:
+ // Constructor.
+ socket_select_interrupter()
+ {
+ asio::error_code ec;
+ socket_holder acceptor(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (acceptor.get() == invalid_socket)
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ int opt = 1;
+ socket_ops::setsockopt(acceptor.get(),
+ SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
+
+ using namespace std; // For memset.
+ sockaddr_in4_type addr;
+ std::size_t addr_len = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = 0;
+ if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
+ &addr_len, ec) == socket_error_retval)
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ if (socket_ops::listen(acceptor.get(),
+ SOMAXCONN, ec) == socket_error_retval)
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ socket_holder client(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (client.get() == invalid_socket)
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
+ if (server.get() == invalid_socket)
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ opt = 1;
+ socket_ops::setsockopt(client.get(),
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ non_blocking = 1;
+ if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
+ {
+ asio::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ opt = 1;
+ socket_ops::setsockopt(server.get(),
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ read_descriptor_ = server.release();
+ write_descriptor_ = client.release();
+ }
+
+ // Destructor.
+ ~socket_select_interrupter()
+ {
+ asio::error_code ec;
+ if (read_descriptor_ != invalid_socket)
+ socket_ops::close(read_descriptor_, ec);
+ if (write_descriptor_ != invalid_socket)
+ socket_ops::close(write_descriptor_, ec);
+ }
+
+ // Interrupt the select call.
+ void interrupt()
+ {
+ char byte = 0;
+ socket_ops::buf b;
+ socket_ops::init_buf(b, &byte, 1);
+ asio::error_code ec;
+ socket_ops::send(write_descriptor_, &b, 1, 0, ec);
+ }
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ bool reset()
+ {
+ char data[1024];
+ socket_ops::buf b;
+ socket_ops::init_buf(b, data, sizeof(data));
+ asio::error_code ec;
+ int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+ return was_interrupted;
+ }
+
+ // Get the read descriptor to be passed to select.
+ socket_type read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // The read end of a connection used to interrupt the select call. This file
+ // descriptor is passed to select such that when it is time to stop, a single
+ // byte will be written on the other end of the connection and this
+ // descriptor will become readable.
+ socket_type read_descriptor_;
+
+ // The write end of a connection used to interrupt the select call. A single
+ // byte may be written to this to wake up the select which is waiting for the
+ // other end to become readable.
+ socket_type write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
diff --git a/src/libtorrent/asio/detail/socket_types.hpp b/src/libtorrent/asio/detail/socket_types.hpp
new file mode 100644
index 0000000..b2acb69
--- /dev/null
+++ b/src/libtorrent/asio/detail/socket_types.hpp
@@ -0,0 +1,201 @@
+//
+// socket_types.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_SOCKET_TYPES_HPP
+#define ASIO_DETAIL_SOCKET_TYPES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+# error WinSock.h has already been included
+# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+# pragma message("Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately")
+# pragma message("Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)")
+# else // defined(_MSC_VER) || defined(__BORLANDC__)
+# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately
+# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+# define _WIN32_WINNT 0x0501
+# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+# if defined(_MSC_VER)
+# if defined(_WIN32) && !defined(WIN32)
+# if !defined(_WINSOCK2API_)
+# define WIN32 // Needed for correct types in winsock2.h
+# else // !defined(_WINSOCK2API_)
+# error Please define the macro WIN32 in your compiler options
+# endif // !defined(_WINSOCK2API_)
+# endif // defined(_WIN32) && !defined(WIN32)
+# endif // defined(_MSC_VER)
+# if defined(__BORLANDC__)
+# include <stdlib.h> // Needed for __errno
+# if defined(__WIN32__) && !defined(WIN32)
+# if !defined(_WINSOCK2API_)
+# define WIN32 // Needed for correct types in winsock2.h
+# else // !defined(_WINSOCK2API_)
+# error Please define the macro WIN32 in your compiler options
+# endif // !defined(_WINSOCK2API_)
+# endif // defined(__WIN32__) && !defined(WIN32)
+# if !defined(_WSPIAPI_H_)
+# define _WSPIAPI_H_
+# define ASIO_WSPIAPI_H_DEFINED
+# endif // !defined(_WSPIAPI_H_)
+# endif // defined(__BORLANDC__)
+# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+# if !defined(WIN32_LEAN_AND_MEAN)
+# define WIN32_LEAN_AND_MEAN
+# endif // !defined(WIN32_LEAN_AND_MEAN)
+# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+# if defined(__CYGWIN__)
+# if !defined(__USE_W32_SOCKETS)
+# error You must add -D__USE_W32_SOCKETS to your compiler options.
+# endif // !defined(__USE_W32_SOCKETS)
+# if !defined(NOMINMAX)
+# define NOMINMAX 1
+# endif // !defined(NOMINMAX)
+# endif // defined(__CYGWIN__)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <mswsock.h>
+# if defined(ASIO_WSPIAPI_H_DEFINED)
+# undef _WSPIAPI_H_
+# undef ASIO_WSPIAPI_H_DEFINED
+# endif // defined(ASIO_WSPIAPI_H_DEFINED)
+# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
+# if defined(UNDER_CE)
+# pragma comment(lib, "ws2.lib")
+# elif defined(_MSC_VER) || defined(__BORLANDC__)
+# pragma comment(lib, "ws2_32.lib")
+# pragma comment(lib, "mswsock.lib")
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
+# include "asio/detail/old_win_sdk_compat.hpp"
+#else
+# include <sys/ioctl.h>
+# include <sys/poll.h>
+# include <sys/types.h>
+# if defined(__hpux) && !defined(__HP_aCC)
+# include <sys/time.h>
+# else
+# include <sys/select.h>
+# endif
+# include <sys/socket.h>
+# include <sys/uio.h>
+# include <sys/un.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <net/if.h>
+# include <limits.h>
+# if defined(__sun)
+# include <sys/filio.h>
+# include <sys/sockio.h>
+# endif
+#endif
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef SOCKET socket_type;
+const SOCKET invalid_socket = INVALID_SOCKET;
+const int socket_error_retval = SOCKET_ERROR;
+const int max_addr_v4_str_len = 256;
+const int max_addr_v6_str_len = 256;
+typedef sockaddr socket_addr_type;
+typedef in_addr in4_addr_type;
+typedef ip_mreq in4_mreq_type;
+typedef sockaddr_in sockaddr_in4_type;
+# if defined(ASIO_HAS_OLD_WIN_SDK)
+typedef in6_addr_emulation in6_addr_type;
+typedef ipv6_mreq_emulation in6_mreq_type;
+typedef sockaddr_in6_emulation sockaddr_in6_type;
+typedef sockaddr_storage_emulation sockaddr_storage_type;
+typedef addrinfo_emulation addrinfo_type;
+# else
+typedef in6_addr in6_addr_type;
+typedef ipv6_mreq in6_mreq_type;
+typedef sockaddr_in6 sockaddr_in6_type;
+typedef sockaddr_storage sockaddr_storage_type;
+typedef addrinfo addrinfo_type;
+# endif
+typedef unsigned long ioctl_arg_type;
+typedef u_long u_long_type;
+typedef u_short u_short_type;
+const int shutdown_receive = SD_RECEIVE;
+const int shutdown_send = SD_SEND;
+const int shutdown_both = SD_BOTH;
+const int message_peek = MSG_PEEK;
+const int message_out_of_band = MSG_OOB;
+const int message_do_not_route = MSG_DONTROUTE;
+# if defined (_WIN32_WINNT)
+const int max_iov_len = 64;
+# else
+const int max_iov_len = 16;
+# endif
+#else
+typedef int socket_type;
+const int invalid_socket = -1;
+const int socket_error_retval = -1;
+const int max_addr_v4_str_len = INET_ADDRSTRLEN;
+const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;
+typedef sockaddr socket_addr_type;
+typedef in_addr in4_addr_type;
+# if defined(__hpux)
+// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined.
+struct in4_mreq_type
+{
+ struct in_addr imr_multiaddr;
+ struct in_addr imr_interface;
+};
+# else
+typedef ip_mreq in4_mreq_type;
+# endif
+typedef sockaddr_in sockaddr_in4_type;
+typedef in6_addr in6_addr_type;
+typedef ipv6_mreq in6_mreq_type;
+typedef sockaddr_in6 sockaddr_in6_type;
+typedef sockaddr_storage sockaddr_storage_type;
+typedef sockaddr_un sockaddr_un_type;
+typedef addrinfo addrinfo_type;
+typedef int ioctl_arg_type;
+typedef uint32_t u_long_type;
+typedef uint16_t u_short_type;
+const int shutdown_receive = SHUT_RD;
+const int shutdown_send = SHUT_WR;
+const int shutdown_both = SHUT_RDWR;
+const int message_peek = MSG_PEEK;
+const int message_out_of_band = MSG_OOB;
+const int message_do_not_route = MSG_DONTROUTE;
+const int max_iov_len = IOV_MAX;
+#endif
+const int custom_socket_option_level = 0xA5100000;
+const int enable_connection_aborted_option = 1;
+const int always_fail_option = 2;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_TYPES_HPP
diff --git a/src/libtorrent/asio/detail/strand_service.hpp b/src/libtorrent/asio/detail/strand_service.hpp
new file mode 100644
index 0000000..42a5752
--- /dev/null
+++ b/src/libtorrent/asio/detail/strand_service.hpp
@@ -0,0 +1,525 @@
+//
+// strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_STRAND_SERVICE_HPP
+#define ASIO_DETAIL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/aligned_storage.hpp>
+#include <boost/assert.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/service_base.hpp"
+
+namespace asio {
+namespace detail {
+
+// Default service implementation for a strand.
+class strand_service
+ : public asio::detail::service_base<strand_service>
+{
+public:
+ class handler_base;
+ class invoke_current_handler;
+ class post_next_waiter_on_exit;
+
+ // The underlying implementation of a strand.
+ class strand_impl
+ {
+#if defined (__BORLANDC__)
+ public:
+#else
+ private:
+#endif
+ void add_ref()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ ++ref_count_;
+ }
+
+ void release()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ --ref_count_;
+ if (ref_count_ == 0)
+ {
+ lock.unlock();
+ delete this;
+ }
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class strand_service;
+ friend class post_next_waiter_on_exit;
+ friend class invoke_current_handler;
+
+ strand_impl(strand_service& owner)
+ : owner_(owner),
+ current_handler_(0),
+ first_waiter_(0),
+ last_waiter_(0),
+ ref_count_(0)
+ {
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(owner_.mutex_);
+ next_ = owner_.impl_list_;
+ prev_ = 0;
+ if (owner_.impl_list_)
+ owner_.impl_list_->prev_ = this;
+ owner_.impl_list_ = this;
+ }
+
+ ~strand_impl()
+ {
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(owner_.mutex_);
+ if (owner_.impl_list_ == this)
+ owner_.impl_list_ = next_;
+ if (prev_)
+ prev_->next_ = next_;
+ if (next_)
+ next_->prev_= prev_;
+ next_ = 0;
+ prev_ = 0;
+ lock.unlock();
+
+ if (current_handler_)
+ {
+ current_handler_->destroy();
+ }
+
+ while (first_waiter_)
+ {
+ handler_base* next = first_waiter_->next_;
+ first_waiter_->destroy();
+ first_waiter_ = next;
+ }
+ }
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // The service that owns this implementation.
+ strand_service& owner_;
+
+ // The handler that is ready to execute. If this pointer is non-null then it
+ // indicates that a handler holds the lock.
+ handler_base* current_handler_;
+
+ // The start of the list of waiting handlers for the strand.
+ handler_base* first_waiter_;
+
+ // The end of the list of waiting handlers for the strand.
+ handler_base* last_waiter_;
+
+ // Storage for posted handlers.
+ typedef boost::aligned_storage<128> handler_storage_type;
+#if defined(__BORLANDC__)
+ boost::aligned_storage<128> handler_storage_;
+#else
+ handler_storage_type handler_storage_;
+#endif
+
+ // Pointers to adjacent socket implementations in linked list.
+ strand_impl* next_;
+ strand_impl* prev_;
+
+ // The reference count on the strand implementation.
+ size_t ref_count_;
+
+#if !defined(__BORLANDC__)
+ friend void intrusive_ptr_add_ref(strand_impl* p)
+ {
+ p->add_ref();
+ }
+
+ friend void intrusive_ptr_release(strand_impl* p)
+ {
+ p->release();
+ }
+#endif
+ };
+
+ friend class strand_impl;
+
+ typedef boost::intrusive_ptr<strand_impl> implementation_type;
+
+ // Base class for all handler types.
+ class handler_base
+ {
+ public:
+ typedef void (*invoke_func_type)(handler_base*,
+ strand_service&, implementation_type&);
+ typedef void (*destroy_func_type)(handler_base*);
+
+ handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func)
+ : next_(0),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ }
+
+ void invoke(strand_service& service_impl, implementation_type& impl)
+ {
+ invoke_func_(this, service_impl, impl);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ ~handler_base()
+ {
+ }
+
+ private:
+ friend class strand_service;
+ friend class strand_impl;
+ friend class post_next_waiter_on_exit;
+ handler_base* next_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ // Helper class to allow handlers to be dispatched.
+ class invoke_current_handler
+ {
+ public:
+ invoke_current_handler(strand_service& service_impl,
+ const implementation_type& impl)
+ : service_impl_(service_impl),
+ impl_(impl)
+ {
+ }
+
+ void operator()()
+ {
+ impl_->current_handler_->invoke(service_impl_, impl_);
+ }
+
+ friend void* asio_handler_allocate(std::size_t size,
+ invoke_current_handler* this_handler)
+ {
+ return this_handler->do_handler_allocate(size);
+ }
+
+ friend void asio_handler_deallocate(void*, std::size_t,
+ invoke_current_handler*)
+ {
+ }
+
+ void* do_handler_allocate(std::size_t size)
+ {
+#if defined(__BORLANDC__)
+ BOOST_ASSERT(size <= boost::aligned_storage<128>::size);
+#else
+ BOOST_ASSERT(size <= strand_impl::handler_storage_type::size);
+#endif
+ (void)size;
+ return impl_->handler_storage_.address();
+ }
+
+ // The asio_handler_invoke hook is not defined here since the default one
+ // provides the correct behaviour, and including it here breaks MSVC 7.1
+ // in some situations.
+
+ private:
+ strand_service& service_impl_;
+ implementation_type impl_;
+ };
+
+ // Helper class to automatically enqueue next waiter on block exit.
+ class post_next_waiter_on_exit
+ {
+ public:
+ post_next_waiter_on_exit(strand_service& service_impl,
+ implementation_type& impl)
+ : service_impl_(service_impl),
+ impl_(impl),
+ cancelled_(false)
+ {
+ }
+
+ ~post_next_waiter_on_exit()
+ {
+ if (!cancelled_)
+ {
+ asio::detail::mutex::scoped_lock lock(impl_->mutex_);
+ impl_->current_handler_ = impl_->first_waiter_;
+ if (impl_->current_handler_)
+ {
+ impl_->first_waiter_ = impl_->first_waiter_->next_;
+ if (impl_->first_waiter_ == 0)
+ impl_->last_waiter_ = 0;
+ lock.unlock();
+ service_impl_.get_io_service().post(
+ invoke_current_handler(service_impl_, impl_));
+ }
+ }
+ }
+
+ void cancel()
+ {
+ cancelled_ = true;
+ }
+
+ private:
+ strand_service& service_impl_;
+ implementation_type& impl_;
+ bool cancelled_;
+ };
+
+ // Class template for a waiter.
+ template <typename Handler>
+ class handler_wrapper
+ : public handler_base
+ {
+ public:
+ handler_wrapper(Handler handler)
+ : handler_base(&handler_wrapper<Handler>::do_invoke,
+ &handler_wrapper<Handler>::do_destroy),
+ handler_(handler)
+ {
+ }
+
+ static void do_invoke(handler_base* base,
+ strand_service& service_impl, implementation_type& impl)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ post_next_waiter_on_exit p1(service_impl, impl);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(h->handler_);
+
+ // A handler object must still be valid when the next waiter is posted
+ // since destroying the last handler might cause the strand object to be
+ // destroyed. Therefore we create a second post_next_waiter_on_exit object
+ // that will be destroyed before the handler object.
+ p1.cancel();
+ post_next_waiter_on_exit p2(service_impl, impl);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl.get());
+
+ // Make the upcall.
+ asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void do_destroy(handler_base* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // Construct a new strand service for the specified io_service.
+ explicit strand_service(asio::io_service& io_service)
+ : asio::detail::service_base<strand_service>(io_service),
+ mutex_(),
+ impl_list_(0)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ // Construct a list of all handlers to be destroyed.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ strand_impl* impl = impl_list_;
+ handler_base* first_handler = 0;
+ while (impl)
+ {
+ if (impl->current_handler_)
+ {
+ impl->current_handler_->next_ = first_handler;
+ first_handler = impl->current_handler_;
+ impl->current_handler_ = 0;
+ }
+ if (impl->first_waiter_)
+ {
+ impl->last_waiter_->next_ = first_handler;
+ first_handler = impl->first_waiter_;
+ impl->first_waiter_ = 0;
+ impl->last_waiter_ = 0;
+ }
+ impl = impl->next_;
+ }
+
+ // Destroy all handlers without holding the lock.
+ lock.unlock();
+ while (first_handler)
+ {
+ handler_base* next = first_handler->next_;
+ first_handler->destroy();
+ first_handler = next;
+ }
+ }
+
+ // Construct a new strand implementation.
+ void construct(implementation_type& impl)
+ {
+ impl = implementation_type(new strand_impl(*this));
+ }
+
+ // Destroy a strand implementation.
+ void destroy(implementation_type& impl)
+ {
+ implementation_type().swap(impl);
+ }
+
+ // Request the io_service to invoke the given handler.
+ template <typename Handler>
+ void dispatch(implementation_type& impl, Handler handler)
+ {
+ if (call_stack<strand_impl>::contains(impl.get()))
+ {
+ asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+ else
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+
+ asio::detail::mutex::scoped_lock lock(impl->mutex_);
+
+ if (impl->current_handler_ == 0)
+ {
+ // This handler now has the lock, so can be dispatched immediately.
+ impl->current_handler_ = ptr.release();
+ lock.unlock();
+ this->get_io_service().dispatch(invoke_current_handler(*this, impl));
+ }
+ else
+ {
+ // Another handler already holds the lock, so this handler must join
+ // the list of waiters. The handler will be posted automatically when
+ // its turn comes.
+ if (impl->last_waiter_)
+ {
+ impl->last_waiter_->next_ = ptr.get();
+ impl->last_waiter_ = impl->last_waiter_->next_;
+ }
+ else
+ {
+ impl->first_waiter_ = ptr.get();
+ impl->last_waiter_ = ptr.get();
+ }
+ ptr.release();
+ }
+ }
+ }
+
+ // Request the io_service to invoke the given handler and return immediately.
+ template <typename Handler>
+ void post(implementation_type& impl, Handler handler)
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+
+ asio::detail::mutex::scoped_lock lock(impl->mutex_);
+
+ if (impl->current_handler_ == 0)
+ {
+ // This handler now has the lock, so can be dispatched immediately.
+ impl->current_handler_ = ptr.release();
+ lock.unlock();
+ this->get_io_service().post(invoke_current_handler(*this, impl));
+ }
+ else
+ {
+ // Another handler already holds the lock, so this handler must join the
+ // list of waiters. The handler will be posted automatically when its turn
+ // comes.
+ if (impl->last_waiter_)
+ {
+ impl->last_waiter_->next_ = ptr.get();
+ impl->last_waiter_ = impl->last_waiter_->next_;
+ }
+ else
+ {
+ impl->first_waiter_ = ptr.get();
+ impl->last_waiter_ = ptr.get();
+ }
+ ptr.release();
+ }
+ }
+
+private:
+ // Mutex to protect access to the linked list of implementations.
+ asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ strand_impl* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#if defined(__BORLANDC__)
+
+namespace boost {
+
+inline void intrusive_ptr_add_ref(
+ asio::detail::strand_service::strand_impl* p)
+{
+ p->add_ref();
+}
+
+inline void intrusive_ptr_release(
+ asio::detail::strand_service::strand_impl* p)
+{
+ p->release();
+}
+
+} // namespace boost
+
+#endif // defined(__BORLANDC__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_STRAND_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/task_io_service.hpp b/src/libtorrent/asio/detail/task_io_service.hpp
new file mode 100644
index 0000000..6889845
--- /dev/null
+++ b/src/libtorrent/asio/detail/task_io_service.hpp
@@ -0,0 +1,419 @@
+//
+// task_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_TASK_IO_SERVICE_HPP
+#define ASIO_DETAIL_TASK_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_queue.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/task_io_service_fwd.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Task>
+class task_io_service
+ : public asio::detail::service_base<task_io_service<Task> >
+{
+public:
+ // Constructor.
+ task_io_service(asio::io_service& io_service)
+ : asio::detail::service_base<task_io_service<Task> >(io_service),
+ mutex_(),
+ task_(use_service<Task>(io_service)),
+ task_interrupted_(true),
+ outstanding_work_(0),
+ stopped_(false),
+ shutdown_(false),
+ first_idle_thread_(0)
+ {
+ handler_queue_.push(&task_handler_);
+ }
+
+ void init(size_t /*concurrency_hint*/)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ // Destroy handler objects.
+ while (!handler_queue_.empty())
+ {
+ handler_queue::handler* h = handler_queue_.front();
+ handler_queue_.pop();
+ if (h != &task_handler_)
+ h->destroy();
+ }
+
+ // Reset handler queue to initial state.
+ handler_queue_.push(&task_handler_);
+ }
+
+ // Run the event loop until interrupted or no more work.
+ size_t run(asio::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ size_t n = 0;
+ while (do_one(lock, &this_idle_thread, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Run until interrupted or one operation is performed.
+ size_t run_one(asio::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ return do_one(lock, &this_idle_thread, ec);
+ }
+
+ // Poll for operations without blocking.
+ size_t poll(asio::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ size_t n = 0;
+ while (do_one(lock, 0, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Poll for one operation without blocking.
+ size_t poll_one(asio::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ return do_one(lock, 0, ec);
+ }
+
+ // Interrupt the event processing loop.
+ void stop()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ stop_all_threads(lock);
+ }
+
+ // Reset in preparation for a subsequent run invocation.
+ void reset()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ stopped_ = false;
+ }
+
+ // Notify that some work has started.
+ void work_started()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ ++outstanding_work_;
+ }
+
+ // Notify that some work has finished.
+ void work_finished()
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (--outstanding_work_ == 0)
+ stop_all_threads(lock);
+ }
+
+ // Request invocation of the given handler.
+ template <typename Handler>
+ void dispatch(Handler handler)
+ {
+ if (call_stack<task_io_service>::contains(this))
+ asio_handler_invoke_helpers::invoke(handler, &handler);
+ else
+ post(handler);
+ }
+
+ // Request invocation of the given handler and return immediately.
+ template <typename Handler>
+ void post(Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // If the service has been shut down we silently discard the handler.
+ if (shutdown_)
+ return;
+
+ // Add the handler to the end of the queue.
+ handler_queue_.push(ptr.get());
+ ptr.release();
+
+ // An undelivered handler is treated as unfinished work.
+ ++outstanding_work_;
+
+ // Wake up a thread to execute the handler.
+ if (!interrupt_one_idle_thread(lock))
+ {
+ if (!task_interrupted_)
+ {
+ task_interrupted_ = true;
+ task_.interrupt();
+ }
+ }
+ }
+
+private:
+ struct idle_thread_info;
+
+ size_t do_one(asio::detail::mutex::scoped_lock& lock,
+ idle_thread_info* this_idle_thread, asio::error_code& ec)
+ {
+ if (outstanding_work_ == 0 && !stopped_)
+ {
+ stop_all_threads(lock);
+ ec = asio::error_code();
+ return 0;
+ }
+
+ bool polling = !this_idle_thread;
+ bool task_has_run = false;
+ while (!stopped_)
+ {
+ if (!handler_queue_.empty())
+ {
+ // Prepare to execute first handler from queue.
+ handler_queue::handler* h = handler_queue_.front();
+ handler_queue_.pop();
+
+ if (h == &task_handler_)
+ {
+ bool more_handlers = (!handler_queue_.empty());
+ task_interrupted_ = more_handlers || polling;
+
+ // If the task has already run and we're polling then we're done.
+ if (task_has_run && polling)
+ {
+ task_interrupted_ = true;
+ handler_queue_.push(&task_handler_);
+ ec = asio::error_code();
+ return 0;
+ }
+ task_has_run = true;
+
+ lock.unlock();
+ task_cleanup c(lock, *this);
+
+ // Run the task. May throw an exception. Only block if the handler
+ // queue is empty and we have an idle_thread_info object, otherwise
+ // we want to return as soon as possible.
+ task_.run(!more_handlers && !polling);
+ }
+ else
+ {
+ lock.unlock();
+ handler_cleanup c(lock, *this);
+
+ // Invoke the handler. May throw an exception.
+ h->invoke(); // invoke() deletes the handler object
+
+ ec = asio::error_code();
+ return 1;
+ }
+ }
+ else if (this_idle_thread)
+ {
+ // Nothing to run right now, so just wait for work to do.
+ this_idle_thread->next = first_idle_thread_;
+ first_idle_thread_ = this_idle_thread;
+ this_idle_thread->wakeup_event.clear(lock);
+ this_idle_thread->wakeup_event.wait(lock);
+ }
+ else
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+ }
+
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Stop the task and all idle threads.
+ void stop_all_threads(
+ asio::detail::mutex::scoped_lock& lock)
+ {
+ stopped_ = true;
+ interrupt_all_idle_threads(lock);
+ if (!task_interrupted_)
+ {
+ task_interrupted_ = true;
+ task_.interrupt();
+ }
+ }
+
+ // Interrupt a single idle thread. Returns true if a thread was interrupted,
+ // false if no running thread could be found to interrupt.
+ bool interrupt_one_idle_thread(
+ asio::detail::mutex::scoped_lock& lock)
+ {
+ if (first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = first_idle_thread_;
+ first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(lock);
+ return true;
+ }
+ return false;
+ }
+
+ // Interrupt all idle threads.
+ void interrupt_all_idle_threads(
+ asio::detail::mutex::scoped_lock& lock)
+ {
+ while (first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = first_idle_thread_;
+ first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(lock);
+ }
+ }
+
+ // Helper class to perform task-related operations on block exit.
+ class task_cleanup;
+ friend class task_cleanup;
+ class task_cleanup
+ {
+ public:
+ task_cleanup(asio::detail::mutex::scoped_lock& lock,
+ task_io_service& task_io_svc)
+ : lock_(lock),
+ task_io_service_(task_io_svc)
+ {
+ }
+
+ ~task_cleanup()
+ {
+ // Reinsert the task at the end of the handler queue.
+ lock_.lock();
+ task_io_service_.task_interrupted_ = true;
+ task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
+ }
+
+ private:
+ asio::detail::mutex::scoped_lock& lock_;
+ task_io_service& task_io_service_;
+ };
+
+ // Helper class to perform handler-related operations on block exit.
+ class handler_cleanup;
+ friend class handler_cleanup;
+ class handler_cleanup
+ {
+ public:
+ handler_cleanup(asio::detail::mutex::scoped_lock& lock,
+ task_io_service& task_io_svc)
+ : lock_(lock),
+ task_io_service_(task_io_svc)
+ {
+ }
+
+ ~handler_cleanup()
+ {
+ lock_.lock();
+ if (--task_io_service_.outstanding_work_ == 0)
+ task_io_service_.stop_all_threads(lock_);
+ }
+
+ private:
+ asio::detail::mutex::scoped_lock& lock_;
+ task_io_service& task_io_service_;
+ };
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // The task to be run by this service.
+ Task& task_;
+
+ // Handler object to represent the position of the task in the queue.
+ class task_handler
+ : public handler_queue::handler
+ {
+ public:
+ task_handler()
+ : handler_queue::handler(0, 0)
+ {
+ }
+ } task_handler_;
+
+ // Whether the task has been interrupted.
+ bool task_interrupted_;
+
+ // The count of unfinished work.
+ int outstanding_work_;
+
+ // The queue of handlers that are ready to be delivered.
+ handler_queue handler_queue_;
+
+ // Flag to indicate that the dispatcher has been stopped.
+ bool stopped_;
+
+ // Flag to indicate that the dispatcher has been shut down.
+ bool shutdown_;
+
+ // Structure containing information about an idle thread.
+ struct idle_thread_info
+ {
+ event wakeup_event;
+ idle_thread_info* next;
+ };
+
+ // The number of threads that are currently idle.
+ idle_thread_info* first_idle_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/task_io_service_fwd.hpp b/src/libtorrent/asio/detail/task_io_service_fwd.hpp
new file mode 100644
index 0000000..02ccdc2
--- /dev/null
+++ b/src/libtorrent/asio/detail/task_io_service_fwd.hpp
@@ -0,0 +1,31 @@
+//
+// task_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
+#define ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Task>
+class task_io_service;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
diff --git a/src/libtorrent/asio/detail/thread.hpp b/src/libtorrent/asio/detail/thread.hpp
new file mode 100644
index 0000000..66b701c
--- /dev/null
+++ b/src/libtorrent/asio/detail/thread.hpp
@@ -0,0 +1,58 @@
+//
+// thread.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_THREAD_HPP
+#define ASIO_DETAIL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+# include "asio/detail/null_thread.hpp"
+#elif defined(BOOST_WINDOWS)
+# if defined(UNDER_CE)
+# include "asio/detail/wince_thread.hpp"
+# else
+# include "asio/detail/win_thread.hpp"
+# endif
+#elif defined(BOOST_HAS_PTHREADS)
+# include "asio/detail/posix_thread.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_thread thread;
+#elif defined(BOOST_WINDOWS)
+# if defined(UNDER_CE)
+typedef wince_thread thread;
+# else
+typedef win_thread thread;
+# endif
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_thread thread;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_THREAD_HPP
diff --git a/src/libtorrent/asio/detail/throw_error.hpp b/src/libtorrent/asio/detail/throw_error.hpp
new file mode 100644
index 0000000..bf2356c
--- /dev/null
+++ b/src/libtorrent/asio/detail/throw_error.hpp
@@ -0,0 +1,44 @@
+//
+// throw_error.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_THROW_ERROR_HPP
+#define ASIO_DETAIL_THROW_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/system_error.hpp"
+
+namespace asio {
+namespace detail {
+
+inline void throw_error(const asio::error_code& err)
+{
+ if (err)
+ {
+ asio::system_error e(err);
+ boost::throw_exception(e);
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_THROW_ERROR_HPP
diff --git a/src/libtorrent/asio/detail/timer_queue.hpp b/src/libtorrent/asio/detail/timer_queue.hpp
new file mode 100644
index 0000000..ed12dda
--- /dev/null
+++ b/src/libtorrent/asio/detail/timer_queue.hpp
@@ -0,0 +1,395 @@
+//
+// timer_queue.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_TIMER_QUEUE_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <vector>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+class timer_queue
+ : public timer_queue_base
+{
+public:
+ // The time type.
+ typedef typename Time_Traits::time_type time_type;
+
+ // The duration type.
+ typedef typename Time_Traits::duration_type duration_type;
+
+ // Constructor.
+ timer_queue()
+ : timers_(),
+ heap_(),
+ cancelled_timers_(0),
+ cleanup_timers_(0)
+ {
+ }
+
+ // Add a new timer to the queue. Returns true if this is the timer that is
+ // earliest in the queue, in which case the reactor's event demultiplexing
+ // function call may need to be interrupted and restarted.
+ template <typename Handler>
+ bool enqueue_timer(const time_type& time, Handler handler, void* token)
+ {
+ // Ensure that there is space for the timer in the heap. We reserve here so
+ // that the push_back below will not throw due to a reallocation failure.
+ heap_.reserve(heap_.size() + 1);
+
+ // Create a new timer object.
+ std::auto_ptr<timer<Handler> > new_timer(
+ new timer<Handler>(time, handler, token));
+
+ // Insert the new timer into the hash.
+ typedef typename hash_map<void*, timer_base*>::iterator iterator;
+ typedef typename hash_map<void*, timer_base*>::value_type value_type;
+ std::pair<iterator, bool> result =
+ timers_.insert(value_type(token, new_timer.get()));
+ if (!result.second)
+ {
+ result.first->second->prev_ = new_timer.get();
+ new_timer->next_ = result.first->second;
+ result.first->second = new_timer.get();
+ }
+
+ // Put the timer at the correct position in the heap.
+ new_timer->heap_index_ = heap_.size();
+ heap_.push_back(new_timer.get());
+ up_heap(heap_.size() - 1);
+ bool is_first = (heap_[0] == new_timer.get());
+
+ // Ownership of the timer is transferred to the timer queue.
+ new_timer.release();
+
+ return is_first;
+ }
+
+ // Whether there are no timers in the queue.
+ virtual bool empty() const
+ {
+ return heap_.empty();
+ }
+
+ // Get the time for the timer that is earliest in the queue.
+ virtual boost::posix_time::time_duration wait_duration() const
+ {
+ return Time_Traits::to_posix_duration(
+ Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
+ }
+
+ // Dispatch the timers that are earlier than the specified time.
+ virtual void dispatch_timers()
+ {
+ const time_type now = Time_Traits::now();
+ while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
+ {
+ timer_base* t = heap_[0];
+ remove_timer(t);
+ t->prev_ = 0;
+ t->next_ = cleanup_timers_;
+ cleanup_timers_ = t;
+ t->invoke(asio::error_code());
+ }
+ }
+
+ // Cancel the timers with the given token. Any timers pending for the token
+ // will be notified that they have been cancelled next time
+ // dispatch_cancellations is called. Returns the number of timers that were
+ // cancelled.
+ std::size_t cancel_timer(void* timer_token)
+ {
+ std::size_t num_cancelled = 0;
+ typedef typename hash_map<void*, timer_base*>::iterator iterator;
+ iterator it = timers_.find(timer_token);
+ if (it != timers_.end())
+ {
+ timer_base* t = it->second;
+ while (t)
+ {
+ timer_base* next = t->next_;
+ remove_timer(t);
+ t->prev_ = 0;
+ t->next_ = cancelled_timers_;
+ cancelled_timers_ = t;
+ t = next;
+ ++num_cancelled;
+ }
+ }
+ return num_cancelled;
+ }
+
+ // Dispatch any pending cancels for timers.
+ virtual void dispatch_cancellations()
+ {
+ while (cancelled_timers_)
+ {
+ timer_base* this_timer = cancelled_timers_;
+ cancelled_timers_ = this_timer->next_;
+ this_timer->next_ = cleanup_timers_;
+ cleanup_timers_ = this_timer;
+ this_timer->invoke(asio::error::operation_aborted);
+ }
+ }
+
+ // Destroy timers that are waiting to be cleaned up.
+ virtual void cleanup_timers()
+ {
+ destroy_timer_list(cleanup_timers_);
+ }
+
+ // Destroy all timers.
+ virtual void destroy_timers()
+ {
+ typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
+ typename hash_map<void*, timer_base*>::iterator end = timers_.end();
+ while (i != end)
+ {
+ timer_base* t = i->second;
+ typename hash_map<void*, timer_base*>::iterator old_i = i++;
+ timers_.erase(old_i);
+ destroy_timer_list(t);
+ }
+ heap_.clear();
+ timers_.clear();
+ destroy_timer_list(cancelled_timers_);
+ destroy_timer_list(cleanup_timers_);
+ }
+
+private:
+ // Base class for timer operations. Function pointers are used instead of
+ // virtual functions to avoid the associated overhead.
+ class timer_base
+ {
+ public:
+ // Perform the timer operation and then destroy.
+ void invoke(const asio::error_code& result)
+ {
+ invoke_func_(this, result);
+ }
+
+ // Destroy the timer operation.
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*invoke_func_type)(timer_base*,
+ const asio::error_code&);
+ typedef void (*destroy_func_type)(timer_base*);
+
+ // Constructor.
+ timer_base(invoke_func_type invoke_func, destroy_func_type destroy_func,
+ const time_type& time, void* token)
+ : invoke_func_(invoke_func),
+ destroy_func_(destroy_func),
+ time_(time),
+ token_(token),
+ next_(0),
+ prev_(0),
+ heap_index_(
+ std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
+ {
+ }
+
+ // Prevent deletion through this type.
+ ~timer_base()
+ {
+ }
+
+ private:
+ friend class timer_queue<Time_Traits>;
+
+ // The function to be called to dispatch the handler.
+ invoke_func_type invoke_func_;
+
+ // The function to be called to destroy the handler.
+ destroy_func_type destroy_func_;
+
+ // The time when the operation should fire.
+ time_type time_;
+
+ // The token associated with the timer.
+ void* token_;
+
+ // The next timer known to the queue.
+ timer_base* next_;
+
+ // The previous timer known to the queue.
+ timer_base* prev_;
+
+ // The index of the timer in the heap.
+ size_t heap_index_;
+ };
+
+ // Adaptor class template for using handlers in timers.
+ template <typename Handler>
+ class timer
+ : public timer_base
+ {
+ public:
+ // Constructor.
+ timer(const time_type& time, Handler handler, void* token)
+ : timer_base(&timer<Handler>::invoke_handler,
+ &timer<Handler>::destroy_handler, time, token),
+ handler_(handler)
+ {
+ }
+
+ // Invoke the handler and then destroy it.
+ static void invoke_handler(timer_base* base,
+ const asio::error_code& result)
+ {
+ static_cast<timer<Handler>*>(base)->handler_(result);
+ }
+
+ // Destroy the handler.
+ static void destroy_handler(timer_base* base)
+ {
+ delete static_cast<timer<Handler>*>(base);
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // Move the item at the given index up the heap to its correct position.
+ void up_heap(size_t index)
+ {
+ size_t parent = (index - 1) / 2;
+ while (index > 0
+ && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
+ {
+ swap_heap(index, parent);
+ index = parent;
+ parent = (index - 1) / 2;
+ }
+ }
+
+ // Move the item at the given index down the heap to its correct position.
+ void down_heap(size_t index)
+ {
+ size_t child = index * 2 + 1;
+ while (child < heap_.size())
+ {
+ size_t min_child = (child + 1 == heap_.size()
+ || Time_Traits::less_than(
+ heap_[child]->time_, heap_[child + 1]->time_))
+ ? child : child + 1;
+ if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
+ break;
+ swap_heap(index, min_child);
+ index = min_child;
+ child = index * 2 + 1;
+ }
+ }
+
+ // Swap two entries in the heap.
+ void swap_heap(size_t index1, size_t index2)
+ {
+ timer_base* tmp = heap_[index1];
+ heap_[index1] = heap_[index2];
+ heap_[index2] = tmp;
+ heap_[index1]->heap_index_ = index1;
+ heap_[index2]->heap_index_ = index2;
+ }
+
+ // Remove a timer from the heap and list of timers.
+ void remove_timer(timer_base* t)
+ {
+ // Remove the timer from the heap.
+ size_t index = t->heap_index_;
+ if (!heap_.empty() && index < heap_.size())
+ {
+ if (index == heap_.size() - 1)
+ {
+ heap_.pop_back();
+ }
+ else
+ {
+ swap_heap(index, heap_.size() - 1);
+ heap_.pop_back();
+ size_t parent = (index - 1) / 2;
+ if (index > 0 && Time_Traits::less_than(
+ heap_[index]->time_, heap_[parent]->time_))
+ up_heap(index);
+ else
+ down_heap(index);
+ }
+ }
+
+ // Remove the timer from the hash.
+ typedef typename hash_map<void*, timer_base*>::iterator iterator;
+ iterator it = timers_.find(t->token_);
+ if (it != timers_.end())
+ {
+ if (it->second == t)
+ it->second = t->next_;
+ if (t->prev_)
+ t->prev_->next_ = t->next_;
+ if (t->next_)
+ t->next_->prev_ = t->prev_;
+ if (it->second == 0)
+ timers_.erase(it);
+ }
+ }
+
+ // Destroy all timers in a linked list.
+ void destroy_timer_list(timer_base*& t)
+ {
+ while (t)
+ {
+ timer_base* next = t->next_;
+ t->next_ = 0;
+ t->destroy();
+ t = next;
+ }
+ }
+
+ // A hash of timer token to linked lists of timers.
+ hash_map<void*, timer_base*> timers_;
+
+ // The heap of timers, with the earliest timer at the front.
+ std::vector<timer_base*> heap_;
+
+ // The list of timers to be cancelled.
+ timer_base* cancelled_timers_;
+
+ // The list of timers to be destroyed.
+ timer_base* cleanup_timers_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_HPP
diff --git a/src/libtorrent/asio/detail/timer_queue_base.hpp b/src/libtorrent/asio/detail/timer_queue_base.hpp
new file mode 100644
index 0000000..30a2a21
--- /dev/null
+++ b/src/libtorrent/asio/detail/timer_queue_base.hpp
@@ -0,0 +1,62 @@
+//
+// timer_queue_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+
+#include "asio/detail/push_options.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class timer_queue_base
+ : private noncopyable
+{
+public:
+ // Destructor.
+ virtual ~timer_queue_base() {}
+
+ // Whether there are no timers in the queue.
+ virtual bool empty() const = 0;
+
+ // Get the time to wait until the next timer.
+ virtual boost::posix_time::time_duration wait_duration() const = 0;
+
+ // Dispatch all ready timers.
+ virtual void dispatch_timers() = 0;
+
+ // Dispatch any pending cancels for timers.
+ virtual void dispatch_cancellations() = 0;
+
+ // Destroy timers that are waiting to be cleaned up.
+ virtual void cleanup_timers() = 0;
+
+ // Destroy all timers.
+ virtual void destroy_timers() = 0;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
diff --git a/src/libtorrent/asio/detail/tss_ptr.hpp b/src/libtorrent/asio/detail/tss_ptr.hpp
new file mode 100644
index 0000000..5e5f8a0
--- /dev/null
+++ b/src/libtorrent/asio/detail/tss_ptr.hpp
@@ -0,0 +1,65 @@
+//
+// tss_ptr.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_TSS_PTR_HPP
+#define ASIO_DETAIL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if !defined(BOOST_HAS_THREADS)
+# include "asio/detail/null_tss_ptr.hpp"
+#elif defined(BOOST_WINDOWS)
+# include "asio/detail/win_tss_ptr.hpp"
+#elif defined(BOOST_HAS_PTHREADS)
+# include "asio/detail/posix_tss_ptr.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class tss_ptr
+#if !defined(BOOST_HAS_THREADS)
+ : public null_tss_ptr<T>
+#elif defined(BOOST_WINDOWS)
+ : public win_tss_ptr<T>
+#elif defined(BOOST_HAS_PTHREADS)
+ : public posix_tss_ptr<T>
+#endif
+{
+public:
+ void operator=(T* value)
+ {
+#if !defined(BOOST_HAS_THREADS)
+ null_tss_ptr<T>::operator=(value);
+#elif defined(BOOST_WINDOWS)
+ win_tss_ptr<T>::operator=(value);
+#elif defined(BOOST_HAS_PTHREADS)
+ posix_tss_ptr<T>::operator=(value);
+#endif
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TSS_PTR_HPP
diff --git a/src/libtorrent/asio/detail/win_event.hpp b/src/libtorrent/asio/detail/win_event.hpp
new file mode 100644
index 0000000..2f057cd
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_event.hpp
@@ -0,0 +1,103 @@
+//
+// win_event.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_EVENT_HPP
+#define ASIO_DETAIL_WIN_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ win_event()
+ : event_(::CreateEvent(0, true, false, 0))
+ {
+ if (!event_)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "event");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~win_event()
+ {
+ ::CloseHandle(event_);
+ }
+
+ // Signal the event.
+ template <typename Lock>
+ void signal(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ ::SetEvent(event_);
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ ::ResetEvent(event_);
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ lock.unlock();
+ ::WaitForSingleObject(event_, INFINITE);
+ lock.lock();
+ }
+
+private:
+ HANDLE event_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_EVENT_HPP
diff --git a/src/libtorrent/asio/detail/win_fd_set_adapter.hpp b/src/libtorrent/asio/detail/win_fd_set_adapter.hpp
new file mode 100644
index 0000000..ea52542
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_fd_set_adapter.hpp
@@ -0,0 +1,88 @@
+//
+// win_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_types.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class win_fd_set_adapter
+{
+public:
+ enum { win_fd_set_size = 1024 };
+
+ win_fd_set_adapter()
+ : max_descriptor_(invalid_socket)
+ {
+ fd_set_.fd_count = 0;
+ }
+
+ bool set(socket_type descriptor)
+ {
+ for (u_int i = 0; i < fd_set_.fd_count; ++i)
+ if (fd_set_.fd_array[i] == descriptor)
+ return true;
+ if (fd_set_.fd_count < win_fd_set_size)
+ {
+ fd_set_.fd_array[fd_set_.fd_count++] = descriptor;
+ return true;
+ }
+ return false;
+ }
+
+ bool is_set(socket_type descriptor) const
+ {
+ return !!__WSAFDIsSet(descriptor,
+ const_cast<fd_set*>(reinterpret_cast<const fd_set*>(&fd_set_)));
+ }
+
+ operator fd_set*()
+ {
+ return reinterpret_cast<fd_set*>(&fd_set_);
+ }
+
+ socket_type max_descriptor() const
+ {
+ return max_descriptor_;
+ }
+
+private:
+ // This structure is defined to be compatible with the Windows API fd_set
+ // structure, but without being dependent on the value of FD_SETSIZE.
+ struct win_fd_set
+ {
+ u_int fd_count;
+ SOCKET fd_array[win_fd_set_size];
+ };
+
+ win_fd_set fd_set_;
+ socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
diff --git a/src/libtorrent/asio/detail/win_iocp_io_service.hpp b/src/libtorrent/asio/detail/win_iocp_io_service.hpp
new file mode 100644
index 0000000..cb1a429
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_iocp_io_service.hpp
@@ -0,0 +1,718 @@
+//
+// win_iocp_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/win_iocp_io_service_fwd.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+#include <limits>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue.hpp"
+#include "asio/detail/mutex.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_io_service
+ : public asio::detail::service_base<win_iocp_io_service>
+{
+public:
+ // Base class for all operations. A function pointer is used instead of
+ // virtual functions to avoid the associated overhead.
+ //
+ // This class inherits from OVERLAPPED so that we can downcast to get back to
+ // the operation pointer from the LPOVERLAPPED out parameter of
+ // GetQueuedCompletionStatus.
+ class operation
+ : public OVERLAPPED
+ {
+ public:
+ typedef void (*invoke_func_type)(operation*, DWORD, size_t);
+ typedef void (*destroy_func_type)(operation*);
+
+ operation(win_iocp_io_service& iocp_service,
+ invoke_func_type invoke_func, destroy_func_type destroy_func)
+ : outstanding_operations_(&iocp_service.outstanding_operations_),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ Internal = 0;
+ InternalHigh = 0;
+ Offset = 0;
+ OffsetHigh = 0;
+ hEvent = 0;
+
+ ::InterlockedIncrement(outstanding_operations_);
+ }
+
+ void do_completion(DWORD last_error, size_t bytes_transferred)
+ {
+ invoke_func_(this, last_error, bytes_transferred);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ // Prevent deletion through this type.
+ ~operation()
+ {
+ ::InterlockedDecrement(outstanding_operations_);
+ }
+
+ private:
+ long* outstanding_operations_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+
+ // Constructor.
+ win_iocp_io_service(asio::io_service& io_service)
+ : asio::detail::service_base<win_iocp_io_service>(io_service),
+ iocp_(),
+ outstanding_work_(0),
+ outstanding_operations_(0),
+ stopped_(0),
+ shutdown_(0),
+ timer_thread_(0),
+ timer_interrupt_issued_(false)
+ {
+ }
+
+ void init(size_t concurrency_hint)
+ {
+ iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
+ static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
+ if (!iocp_.handle)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "iocp");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ ::InterlockedExchange(&shutdown_, 1);
+
+ while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0)
+ {
+ DWORD bytes_transferred = 0;
+#if (WINVER < 0x0500)
+ DWORD completion_key = 0;
+#else
+ DWORD_PTR completion_key = 0;
+#endif
+ LPOVERLAPPED overlapped = 0;
+ ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, INFINITE);
+ if (overlapped)
+ static_cast<operation*>(overlapped)->destroy();
+ }
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Register a handle with the IO completion port.
+ asio::error_code register_handle(
+ HANDLE handle, asio::error_code& ec)
+ {
+ if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ return ec;
+ }
+
+ // Run the event loop until stopped or no more work.
+ size_t run(asio::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ size_t n = 0;
+ while (do_one(true, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Run until stopped or one operation is performed.
+ size_t run_one(asio::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ return do_one(true, ec);
+ }
+
+ // Poll for operations without blocking.
+ size_t poll(asio::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ size_t n = 0;
+ while (do_one(false, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Poll for one operation without blocking.
+ size_t poll_one(asio::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ return do_one(false, ec);
+ }
+
+ // Stop the event processing loop.
+ void stop()
+ {
+ if (::InterlockedExchange(&stopped_, 1) == 0)
+ {
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "pqcs");
+ boost::throw_exception(e);
+ }
+ }
+ }
+
+ // Reset in preparation for a subsequent run invocation.
+ void reset()
+ {
+ ::InterlockedExchange(&stopped_, 0);
+ }
+
+ // Notify that some work has started.
+ void work_started()
+ {
+ ::InterlockedIncrement(&outstanding_work_);
+ }
+
+ // Notify that some work has finished.
+ void work_finished()
+ {
+ if (::InterlockedDecrement(&outstanding_work_) == 0)
+ stop();
+ }
+
+ // Request invocation of the given handler.
+ template <typename Handler>
+ void dispatch(Handler handler)
+ {
+ if (call_stack<win_iocp_io_service>::contains(this))
+ asio_handler_invoke_helpers::invoke(handler, &handler);
+ else
+ post(handler);
+ }
+
+ // Request invocation of the given handler and return immediately.
+ template <typename Handler>
+ void post(Handler handler)
+ {
+ // If the service has been shut down we silently discard the handler.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return;
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef handler_operation<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, *this, handler);
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, ptr.get()))
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "pqcs");
+ boost::throw_exception(e);
+ }
+
+ // Operation has been successfully posted.
+ ptr.release();
+ }
+
+ // Request invocation of the given OVERLAPPED-derived operation.
+ void post_completion(operation* op, DWORD op_last_error,
+ DWORD bytes_transferred)
+ {
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ bytes_transferred, op_last_error, op))
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "pqcs");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Add a new timer queue to the service.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the service.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ // If the service has been shut down we silently discard the timer.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return;
+
+ asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ if (timer_queue.enqueue_timer(time, handler, token))
+ {
+ if (!timer_interrupt_issued_)
+ {
+ timer_interrupt_issued_ = true;
+ lock.unlock();
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, steal_timer_dispatching, 0);
+ }
+ }
+ }
+
+ // Cancel the timer associated with the given token. Returns the number of
+ // handlers that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
+ {
+ // If the service has been shut down we silently ignore the cancellation.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return 0;
+
+ asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0 && !timer_interrupt_issued_)
+ {
+ timer_interrupt_issued_ = true;
+ lock.unlock();
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, steal_timer_dispatching, 0);
+ }
+ return n;
+ }
+
+private:
+ // Dequeues at most one operation from the I/O completion port, and then
+ // executes it. Returns the number of operations that were dequeued (i.e.
+ // either 0 or 1).
+ size_t do_one(bool block, asio::error_code& ec)
+ {
+ long this_thread_id = static_cast<long>(::GetCurrentThreadId());
+
+ for (;;)
+ {
+ // Try to acquire responsibility for dispatching timers.
+ bool dispatching_timers = (::InterlockedCompareExchange(
+ &timer_thread_, this_thread_id, 0) == 0);
+
+ // Calculate timeout for GetQueuedCompletionStatus call.
+ DWORD timeout = max_timeout;
+ if (dispatching_timers)
+ {
+ asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ timer_interrupt_issued_ = false;
+ timeout = get_timeout();
+ }
+
+ // Get the next operation from the queue.
+ DWORD bytes_transferred = 0;
+#if (WINVER < 0x0500)
+ DWORD completion_key = 0;
+#else
+ DWORD_PTR completion_key = 0;
+#endif
+ LPOVERLAPPED overlapped = 0;
+ ::SetLastError(0);
+ BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, block ? timeout : 0);
+ DWORD last_error = ::GetLastError();
+
+ // Dispatch any pending timers.
+ if (dispatching_timers)
+ {
+ try
+ {
+ asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ timer_queues_copy_ = timer_queues_;
+ for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i)
+ {
+ timer_queues_copy_[i]->dispatch_timers();
+ timer_queues_copy_[i]->dispatch_cancellations();
+ timer_queues_copy_[i]->cleanup_timers();
+ }
+ }
+ catch (...)
+ {
+ // Transfer responsibility for dispatching timers to another thread.
+ if (::InterlockedCompareExchange(&timer_thread_,
+ 0, this_thread_id) == this_thread_id)
+ {
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, transfer_timer_dispatching, 0);
+ }
+
+ throw;
+ }
+ }
+
+ if (!ok && overlapped == 0)
+ {
+ if (block && last_error == WAIT_TIMEOUT)
+ {
+ // Relinquish responsibility for dispatching timers.
+ if (dispatching_timers)
+ {
+ ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
+ }
+
+ continue;
+ }
+
+ // Transfer responsibility for dispatching timers to another thread.
+ if (dispatching_timers && ::InterlockedCompareExchange(
+ &timer_thread_, 0, this_thread_id) == this_thread_id)
+ {
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, transfer_timer_dispatching, 0);
+ }
+
+ ec = asio::error_code();
+ return 0;
+ }
+ else if (overlapped)
+ {
+ // We may have been passed a last_error value in the completion_key.
+ if (last_error == 0)
+ {
+ last_error = completion_key;
+ }
+
+ // Transfer responsibility for dispatching timers to another thread.
+ if (dispatching_timers && ::InterlockedCompareExchange(
+ &timer_thread_, 0, this_thread_id) == this_thread_id)
+ {
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, transfer_timer_dispatching, 0);
+ }
+
+ // Ensure that the io_service does not exit due to running out of work
+ // while we make the upcall.
+ auto_work work(*this);
+
+ // Dispatch the operation.
+ operation* op = static_cast<operation*>(overlapped);
+ op->do_completion(last_error, bytes_transferred);
+
+ ec = asio::error_code();
+ return 1;
+ }
+ else if (completion_key == transfer_timer_dispatching)
+ {
+ // Woken up to try to acquire responsibility for dispatching timers.
+ ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
+ }
+ else if (completion_key == steal_timer_dispatching)
+ {
+ // Woken up to steal responsibility for dispatching timers.
+ ::InterlockedExchange(&timer_thread_, 0);
+ }
+ else
+ {
+ // Relinquish responsibility for dispatching timers. If the io_service
+ // is not being stopped then the thread will get an opportunity to
+ // reacquire timer responsibility on the next loop iteration.
+ if (dispatching_timers)
+ {
+ ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
+ }
+
+ // The stopped_ flag is always checked to ensure that any leftover
+ // interrupts from a previous run invocation are ignored.
+ if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
+ {
+ // Wake up next thread that is blocked on GetQueuedCompletionStatus.
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return 0;
+ }
+ }
+ }
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the GetQueuedCompletionStatus call. The timeout
+ // value is returned as a number of milliseconds. We will wait no longer than
+ // 1000 milliseconds.
+ DWORD get_timeout()
+ {
+ if (all_timer_queues_are_empty())
+ return max_timeout;
+
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::milliseconds(max_timeout);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ int milliseconds = minimum_wait_duration.total_milliseconds();
+ return static_cast<DWORD>(milliseconds > 0 ? milliseconds : 1);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ struct auto_work
+ {
+ auto_work(win_iocp_io_service& io_service)
+ : io_service_(io_service)
+ {
+ io_service_.work_started();
+ }
+
+ ~auto_work()
+ {
+ io_service_.work_finished();
+ }
+
+ private:
+ win_iocp_io_service& io_service_;
+ };
+
+ template <typename Handler>
+ struct handler_operation
+ : public operation
+ {
+ handler_operation(win_iocp_io_service& io_service,
+ Handler handler)
+ : operation(io_service, &handler_operation<Handler>::do_completion_impl,
+ &handler_operation<Handler>::destroy_impl),
+ io_service_(io_service),
+ handler_(handler)
+ {
+ io_service_.work_started();
+ }
+
+ ~handler_operation()
+ {
+ io_service_.work_finished();
+ }
+
+ private:
+ // Prevent copying and assignment.
+ handler_operation(const handler_operation&);
+ void operator=(const handler_operation&);
+
+ static void do_completion_impl(operation* op, DWORD, size_t)
+ {
+ // Take ownership of the operation object.
+ typedef handler_operation<Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef handler_operation<Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ }
+
+ win_iocp_io_service& io_service_;
+ Handler handler_;
+ };
+
+ // The IO completion port used for queueing operations.
+ struct iocp_holder
+ {
+ HANDLE handle;
+ iocp_holder() : handle(0) {}
+ ~iocp_holder() { if (handle) ::CloseHandle(handle); }
+ } iocp_;
+
+ // The count of unfinished work.
+ long outstanding_work_;
+
+ // The count of unfinished operations.
+ long outstanding_operations_;
+ friend class operation;
+
+ // Flag to indicate whether the event loop has been stopped.
+ long stopped_;
+
+ // Flag to indicate whether the service has been shut down.
+ long shutdown_;
+
+ enum
+ {
+ // Maximum GetQueuedCompletionStatus timeout, in milliseconds.
+ max_timeout = 500,
+
+ // Completion key value to indicate that responsibility for dispatching
+ // timers is being cooperatively transferred from one thread to another.
+ transfer_timer_dispatching = 1,
+
+ // Completion key value to indicate that responsibility for dispatching
+ // timers should be stolen from another thread.
+ steal_timer_dispatching = 2
+ };
+
+ // The thread that's currently in charge of dispatching timers.
+ long timer_thread_;
+
+ // Mutex for protecting access to the timer queues.
+ mutex timer_mutex_;
+
+ // Whether a thread has been interrupted to process a new timeout.
+ bool timer_interrupt_issued_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when dispatching, cancelling and cleaning
+ // up timers. The copy is stored as a class data member to avoid unnecessary
+ // memory allocation.
+ std::vector<timer_queue_base*> timer_queues_copy_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp b/src/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp
new file mode 100644
index 0000000..a40c6a8
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp
@@ -0,0 +1,50 @@
+//
+// win_iocp_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
+#define ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/socket_types.hpp"
+
+// This service is only supported on Win32 (NT4 and later).
+#if !defined(ASIO_DISABLE_IOCP)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#if !defined(UNDER_CE)
+
+// Define this to indicate that IOCP is supported on the target platform.
+#define ASIO_HAS_IOCP 1
+
+namespace asio {
+namespace detail {
+
+class win_iocp_io_service;
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(UNDER_CE)
+#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#endif // !defined(ASIO_DISABLE_IOCP)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
diff --git a/src/libtorrent/asio/detail/win_iocp_socket_service.hpp b/src/libtorrent/asio/detail/win_iocp_socket_service.hpp
new file mode 100644
index 0000000..33e4c58
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_iocp_socket_service.hpp
@@ -0,0 +1,2363 @@
+//
+// win_iocp_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/win_iocp_io_service_fwd.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+#include <cstring>
+#include <boost/shared_ptr.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/weak_ptr.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/win_iocp_io_service.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class win_iocp_socket_service
+ : public asio::detail::service_base<win_iocp_socket_service<Protocol> >
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // Base class for all operations.
+ typedef win_iocp_io_service::operation operation;
+
+ struct noop_deleter { void operator()(void*) {} };
+ typedef boost::shared_ptr<void> shared_cancel_token_type;
+ typedef boost::weak_ptr<void> weak_cancel_token_type;
+
+ // The native type of a socket.
+ class native_type
+ {
+ public:
+ native_type(socket_type s)
+ : socket_(s),
+ have_remote_endpoint_(false)
+ {
+ }
+
+ native_type(socket_type s, const endpoint_type& ep)
+ : socket_(s),
+ have_remote_endpoint_(true),
+ remote_endpoint_(ep)
+ {
+ }
+
+ void operator=(socket_type s)
+ {
+ socket_ = s;
+ have_remote_endpoint_ = false;
+ remote_endpoint_ = endpoint_type();
+ }
+
+ operator socket_type() const
+ {
+ return socket_;
+ }
+
+ HANDLE as_handle() const
+ {
+ return reinterpret_cast<HANDLE>(socket_);
+ }
+
+ bool have_remote_endpoint() const
+ {
+ return have_remote_endpoint_;
+ }
+
+ endpoint_type remote_endpoint() const
+ {
+ return remote_endpoint_;
+ }
+
+ private:
+ socket_type socket_;
+ bool have_remote_endpoint_;
+ endpoint_type remote_endpoint_;
+ };
+
+ // The implementation type of the socket.
+ class implementation_type
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : socket_(invalid_socket),
+ flags_(0),
+ cancel_token_(),
+ protocol_(endpoint_type().protocol()),
+ next_(0),
+ prev_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class win_iocp_socket_service;
+
+ // The native socket representation.
+ native_type socket_;
+
+ enum
+ {
+ enable_connection_aborted = 1, // User wants connection_aborted errors.
+ close_might_block = 2, // User set linger option for blocking close.
+ user_set_non_blocking = 4 // The user wants a non-blocking socket.
+ };
+
+ // Flags indicating the current state of the socket.
+ unsigned char flags_;
+
+ // We use a shared pointer as a cancellation token here to work around the
+ // broken Windows support for cancellation. MSDN says that when you call
+ // closesocket any outstanding WSARecv or WSASend operations will complete
+ // with the error ERROR_OPERATION_ABORTED. In practice they complete with
+ // ERROR_NETNAME_DELETED, which means you can't tell the difference between
+ // a local cancellation and the socket being hard-closed by the peer.
+ shared_cancel_token_type cancel_token_;
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // The ID of the thread from which it is safe to cancel asynchronous
+ // operations. 0 means no asynchronous operations have been started yet.
+ // ~0 means asynchronous operations have been started from more than one
+ // thread, and cancellation is not supported for the socket.
+ DWORD safe_cancellation_thread_id_;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Pointers to adjacent socket implementations in linked list.
+ implementation_type* next_;
+ implementation_type* prev_;
+ };
+
+ // The type of the reactor used for connect operations.
+ typedef detail::select_reactor<true> reactor_type;
+
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+ // Constructor.
+ win_iocp_socket_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ win_iocp_socket_service<Protocol> >(io_service),
+ iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
+ reactor_(0),
+ mutex_(),
+ impl_list_(0)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ // Close all implementations, causing all operations to complete.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ asio::error_code ignored_ec;
+ close_for_destruction(*impl);
+ impl = impl->next_;
+ }
+ }
+
+ // Construct a new socket implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+ }
+
+ // Destroy a socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ close_for_destruction(impl);
+
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+ }
+
+ // Open a new socket implementation.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(),
+ protocol.protocol(), ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
+ if (iocp_service_.register_handle(sock_as_handle, ec))
+ return ec;
+
+ impl.socket_ = sock.release();
+ impl.flags_ = 0;
+ impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
+ impl.protocol_ = protocol;
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_type& native_socket,
+ asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (iocp_service_.register_handle(native_socket.as_handle(), ec))
+ return ec;
+
+ impl.socket_ = native_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
+ impl.protocol_ = protocol;
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ asio::error_code close(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ // Check if the reactor was created, in which case we need to close the
+ // socket on the reactor as well to cancel any operations that might be
+ // running there.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (reactor)
+ reactor->close_descriptor(impl.socket_);
+
+ if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
+ return ec;
+
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_type native(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ }
+ else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+ ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+ {
+ // The version of Windows supports cancellation from any thread.
+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+ cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+ socket_type sock = impl.socket_;
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+ if (!cancel_io_ex(sock_as_handle, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error == ERROR_NOT_FOUND)
+ {
+ // ERROR_NOT_FOUND means that there were no operations to be
+ // cancelled. We swallow this error to match the behaviour on other
+ // platforms.
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+#if defined(ASIO_ENABLE_CANCELIO)
+ else if (impl.safe_cancellation_thread_id_ == 0)
+ {
+ // No operations have been started, so there's nothing to cancel.
+ ec = asio::error_code();
+ }
+ else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+ {
+ // Asynchronous operations have been started from the current thread only,
+ // so it is safe to try to cancel them using CancelIo.
+ socket_type sock = impl.socket_;
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+ if (!::CancelIo(sock_as_handle))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+ else
+ {
+ // Asynchronous operations have been started from more than one thread,
+ // so cancellation is not safe.
+ ec = asio::error::operation_not_supported;
+ }
+#else // defined(ASIO_ENABLE_CANCELIO)
+ else
+ {
+ // Cancellation is not supported as CancelIo may not be used.
+ ec = asio::error::operation_not_supported;
+ }
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ return ec;
+ }
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
+ return ec ? false : value != 0;
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
+ return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
+ }
+
+ // Bind the socket to the specified local endpoint.
+ asio::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ asio::error_code listen(implementation_type& impl, int backlog,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code set_option(implementation_type& impl,
+ const Option& option, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ }
+ else
+ {
+ if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
+ impl.flags_ |= implementation_type::enable_connection_aborted;
+ else
+ impl.flags_ &= ~implementation_type::enable_connection_aborted;
+ ec = asio::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ if (option.level(impl.protocol_) == SOL_SOCKET
+ && option.name(impl.protocol_) == SO_LINGER)
+ {
+ const ::linger* linger_option =
+ reinterpret_cast<const ::linger*>(option.data(impl.protocol_));
+ if (linger_option->l_onoff != 0 && linger_option->l_linger != 0)
+ impl.flags_ |= implementation_type::close_might_block;
+ else
+ impl.flags_ &= ~implementation_type::close_might_block;
+ }
+
+ socket_ops::setsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
+ }
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code get_option(const implementation_type& impl,
+ Option& option, asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ }
+ else
+ {
+ int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ *target = 1;
+ else
+ *target = 0;
+ option.resize(impl.protocol_, sizeof(int));
+ ec = asio::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ asio::error_code io_control(implementation_type& impl,
+ IO_Control_Command& command, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::ioctl(impl.socket_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+
+ if (!ec && command.name() == static_cast<int>(FIONBIO))
+ {
+ if (command.get())
+ impl.flags_ |= implementation_type::user_set_non_blocking;
+ else
+ impl.flags_ &= ~implementation_type::user_set_non_blocking;
+ }
+
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ if (impl.socket_.have_remote_endpoint())
+ {
+ // Check if socket is still connected.
+ DWORD connect_time = 0;
+ size_t connect_time_len = sizeof(connect_time);
+ if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME,
+ &connect_time, &connect_time_len, ec) == socket_error_retval)
+ {
+ return endpoint_type();
+ }
+ if (connect_time == 0xFFFFFFFF)
+ {
+ ec = asio::error::not_connected;
+ return endpoint_type();
+ }
+
+ ec = asio::error_code();
+ return impl.socket_.remote_endpoint();
+ }
+ else
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+ }
+
+ /// Disable sends or receives on the socket.
+ asio::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer. Returns the number of bytes sent.
+ template <typename ConstBufferSequence>
+ size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ asio::buffer_cast<const char*>(buffer));
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASend(impl.socket_, bufs,
+ i, &bytes_transferred, flags, 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_NETNAME_DELETED)
+ last_error = WSAECONNRESET;
+ else if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_operation
+ : public operation
+ {
+ public:
+ send_operation(win_iocp_io_service& io_service,
+ weak_cancel_token_type cancel_token,
+ const ConstBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &send_operation<ConstBufferSequence, Handler>::do_completion_impl,
+ &send_operation<ConstBufferSequence, Handler>::destroy_impl),
+ work_(io_service.get_io_service()),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef send_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename ConstBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename ConstBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ asio::const_buffer buffer(*iter);
+ asio::buffer_cast<const char*>(buffer);
+ ++iter;
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (handler_op->cancel_token_.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef send_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ }
+
+ asio::io_service::work work_;
+ weak_cancel_token_type cancel_token_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef send_operation<ConstBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_,
+ impl.cancel_token_, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ asio::buffer_cast<const char*>(buffer));
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code error;
+ iocp_service_.post(bind_handler(handler, error, 0));
+ return;
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASend(impl.socket_, bufs, i,
+ &bytes_transferred, flags, ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ template <typename Handler>
+ class null_buffers_handler
+ {
+ public:
+ null_buffers_handler(asio::io_service& io_service, Handler handler)
+ : work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ work_.get_io_service().post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ private:
+ asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ reactor->start_write_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ asio::buffer_cast<const char*>(buffer));
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred,
+ flags, destination.data(), static_cast<int>(destination.size()), 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_to_operation
+ : public operation
+ {
+ public:
+ send_to_operation(win_iocp_io_service& io_service,
+ const ConstBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &send_to_operation<ConstBufferSequence, Handler>::do_completion_impl,
+ &send_to_operation<ConstBufferSequence, Handler>::destroy_impl),
+ work_(io_service.get_io_service()),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef send_to_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename ConstBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename ConstBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ asio::const_buffer buffer(*iter);
+ asio::buffer_cast<const char*>(buffer);
+ ++iter;
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef send_to_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ }
+
+ asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef send_to_operation<ConstBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ asio::buffer_cast<const char*>(buffer));
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred, flags,
+ destination.data(), static_cast<int>(destination.size()), ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ reactor->start_write_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = asio::buffer_cast<char*>(buffer);
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, bufs, i,
+ &bytes_transferred, &recv_flags, 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_NETNAME_DELETED)
+ last_error = WSAECONNRESET;
+ else if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+ if (bytes_transferred == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_operation
+ : public operation
+ {
+ public:
+ receive_operation(win_iocp_io_service& io_service,
+ weak_cancel_token_type cancel_token,
+ const MutableBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &receive_operation<
+ MutableBufferSequence, Handler>::do_completion_impl,
+ &receive_operation<
+ MutableBufferSequence, Handler>::destroy_impl),
+ work_(io_service.get_io_service()),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef receive_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename MutableBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename MutableBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ asio::mutable_buffer buffer(*iter);
+ asio::buffer_cast<char*>(buffer);
+ ++iter;
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (handler_op->cancel_token_.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // Check for connection closed.
+ else if (!ec && bytes_transferred == 0
+ && !boost::is_same<MutableBufferSequence, null_buffers>::value)
+ {
+ ec = asio::error::eof;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef receive_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ }
+
+ asio::io_service::work work_;
+ weak_cancel_token_type cancel_token_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_operation<MutableBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_,
+ impl.cancel_token_, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = asio::buffer_cast<char*>(buffer);
+ total_buffer_size += asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code error;
+ iocp_service_.post(bind_handler(handler, error, 0));
+ return;
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, bufs, i,
+ &bytes_transferred, &recv_flags, ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(implementation_type& impl, const null_buffers& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else if (impl.protocol_.type() == SOCK_STREAM)
+ {
+ // For stream sockets on Windows, we may issue a 0-byte overlapped
+ // WSARecv to wait until there is data available on the socket.
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_operation<null_buffers, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_,
+ impl.cancel_token_, buffers, handler);
+
+ // Issue a receive operation with an empty buffer.
+ ::WSABUF buf = { 0, 0 };
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, &buf, 1,
+ &bytes_transferred, &recv_flags, ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor->start_except_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor->start_read_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = asio::buffer_cast<char*>(buffer);
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int endpoint_size = static_cast<int>(sender_endpoint.capacity());
+ int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred,
+ &recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+ if (bytes_transferred == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ sender_endpoint.resize(static_cast<std::size_t>(endpoint_size));
+
+ ec = asio::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_from_operation
+ : public operation
+ {
+ public:
+ receive_from_operation(win_iocp_io_service& io_service,
+ endpoint_type& endpoint, const MutableBufferSequence& buffers,
+ Handler handler)
+ : operation(io_service,
+ &receive_from_operation<
+ MutableBufferSequence, Handler>::do_completion_impl,
+ &receive_from_operation<
+ MutableBufferSequence, Handler>::destroy_impl),
+ endpoint_(endpoint),
+ endpoint_size_(static_cast<int>(endpoint.capacity())),
+ work_(io_service.get_io_service()),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ int& endpoint_size()
+ {
+ return endpoint_size_;
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef receive_from_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename MutableBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename MutableBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ asio::mutable_buffer buffer(*iter);
+ asio::buffer_cast<char*>(buffer);
+ ++iter;
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // Check for connection closed.
+ if (!ec && bytes_transferred == 0)
+ {
+ ec = asio::error::eof;
+ }
+
+ // Record the size of the endpoint returned by the operation.
+ handler_op->endpoint_.resize(handler_op->endpoint_size_);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef receive_from_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ }
+
+ endpoint_type& endpoint_;
+ int endpoint_size_;
+ asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous receive. The buffer for the data being received and
+ // the sender_endpoint object must both be valid for the lifetime of the
+ // asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endp,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_from_operation<MutableBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_,
+ sender_endp, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer));
+ bufs[i].buf = asio::buffer_cast<char*>(buffer);
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred,
+ &recv_flags, sender_endp.data(), &ptr.get()->endpoint_size(),
+ ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor->start_except_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor->start_read_op(impl.socket_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ asio::error_code accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ for (;;)
+ {
+ socket_holder new_socket;
+ std::size_t addr_len = 0;
+ if (peer_endpoint)
+ {
+ addr_len = peer_endpoint->capacity();
+ new_socket.reset(socket_ops::accept(impl.socket_,
+ peer_endpoint->data(), &addr_len, ec));
+ }
+ else
+ {
+ new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
+ }
+
+ if (ec)
+ {
+ if (ec == asio::error::connection_aborted
+ && !(impl.flags_ & implementation_type::enable_connection_aborted))
+ {
+ // Retry accept operation.
+ continue;
+ }
+ else
+ {
+ return ec;
+ }
+ }
+
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ return ec;
+ }
+ }
+
+ template <typename Socket, typename Handler>
+ class accept_operation
+ : public operation
+ {
+ public:
+ accept_operation(win_iocp_io_service& io_service,
+ socket_type socket, socket_type new_socket, Socket& peer,
+ const protocol_type& protocol, endpoint_type* peer_endpoint,
+ bool enable_connection_aborted, Handler handler)
+ : operation(io_service,
+ &accept_operation<Socket, Handler>::do_completion_impl,
+ &accept_operation<Socket, Handler>::destroy_impl),
+ io_service_(io_service),
+ socket_(socket),
+ new_socket_(new_socket),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ work_(io_service.get_io_service()),
+ enable_connection_aborted_(enable_connection_aborted),
+ handler_(handler)
+ {
+ }
+
+ socket_type new_socket()
+ {
+ return new_socket_.get();
+ }
+
+ void* output_buffer()
+ {
+ return output_buffer_;
+ }
+
+ DWORD address_length()
+ {
+ return sizeof(sockaddr_storage_type) + 16;
+ }
+
+ private:
+ static void do_completion_impl(operation* op, DWORD last_error, size_t)
+ {
+ // Take ownership of the operation object.
+ typedef accept_operation<Socket, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // Map Windows error ERROR_NETNAME_DELETED to connection_aborted.
+ if (last_error == ERROR_NETNAME_DELETED)
+ {
+ last_error = WSAECONNABORTED;
+ }
+
+ // Restart the accept operation if we got the connection_aborted error
+ // and the enable_connection_aborted socket option is not set.
+ if (last_error == WSAECONNABORTED
+ && !ptr.get()->enable_connection_aborted_)
+ {
+ // Reset OVERLAPPED structure.
+ ptr.get()->Internal = 0;
+ ptr.get()->InternalHigh = 0;
+ ptr.get()->Offset = 0;
+ ptr.get()->OffsetHigh = 0;
+ ptr.get()->hEvent = 0;
+
+ // Create a new socket for the next connection, since the AcceptEx call
+ // fails with WSAEINVAL if we try to reuse the same socket.
+ asio::error_code ec;
+ ptr.get()->new_socket_.reset();
+ ptr.get()->new_socket_.reset(socket_ops::socket(
+ ptr.get()->protocol_.family(), ptr.get()->protocol_.type(),
+ ptr.get()->protocol_.protocol(), ec));
+ if (ptr.get()->new_socket() != invalid_socket)
+ {
+ // Accept a connection.
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(ptr.get()->socket_, ptr.get()->new_socket(),
+ ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
+ ptr.get()->address_length(), &bytes_read, ptr.get());
+ last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (!result && last_error != WSA_IO_PENDING)
+ {
+ if (last_error == ERROR_NETNAME_DELETED
+ || last_error == WSAECONNABORTED)
+ {
+ // Post this handler so that operation will be restarted again.
+ ptr.get()->io_service_.post_completion(ptr.get(), last_error, 0);
+ ptr.release();
+ return;
+ }
+ else
+ {
+ // Operation already complete. Continue with rest of this handler.
+ }
+ }
+ else
+ {
+ // Asynchronous operation has been successfully restarted.
+ ptr.release();
+ return;
+ }
+ }
+ }
+
+ // Get the address of the peer.
+ endpoint_type peer_endpoint;
+ if (last_error == 0)
+ {
+ LPSOCKADDR local_addr = 0;
+ int local_addr_length = 0;
+ LPSOCKADDR remote_addr = 0;
+ int remote_addr_length = 0;
+ GetAcceptExSockaddrs(handler_op->output_buffer(), 0,
+ handler_op->address_length(), handler_op->address_length(),
+ &local_addr, &local_addr_length, &remote_addr, &remote_addr_length);
+ if (static_cast<std::size_t>(remote_addr_length)
+ > peer_endpoint.capacity())
+ {
+ last_error = WSAEINVAL;
+ }
+ else
+ {
+ using namespace std; // For memcpy.
+ memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
+ peer_endpoint.resize(static_cast<std::size_t>(remote_addr_length));
+ }
+ }
+
+ // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
+ // and getpeername will work on the accepted socket.
+ if (last_error == 0)
+ {
+ SOCKET update_ctx_param = handler_op->socket_;
+ asio::error_code ec;
+ if (socket_ops::setsockopt(handler_op->new_socket_.get(),
+ SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ &update_ctx_param, sizeof(SOCKET), ec) != 0)
+ {
+ last_error = ec.value();
+ }
+ }
+
+ // If the socket was successfully accepted, transfer ownership of the
+ // socket to the peer object.
+ if (last_error == 0)
+ {
+ asio::error_code ec;
+ handler_op->peer_.assign(handler_op->protocol_,
+ native_type(handler_op->new_socket_.get(), peer_endpoint), ec);
+ if (ec)
+ last_error = ec.value();
+ else
+ handler_op->new_socket_.release();
+ }
+
+ // Pass endpoint back to caller.
+ if (handler_op->peer_endpoint_)
+ *handler_op->peer_endpoint_ = peer_endpoint;
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef accept_operation<Socket, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ }
+
+ win_iocp_io_service& io_service_;
+ socket_type socket_;
+ socket_holder new_socket_;
+ Socket& peer_;
+ protocol_type protocol_;
+ endpoint_type* peer_endpoint_;
+ asio::io_service::work work_;
+ unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+ bool enable_connection_aborted_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous accept. The peer and peer_endpoint objects
+ // must be valid until the accept's handler is invoked.
+ template <typename Socket, typename Handler>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler handler)
+ {
+ // Check whether acceptor has been initialised.
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor));
+ return;
+ }
+
+ // Check that peer socket has not already been opened.
+ if (peer.is_open())
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::already_open));
+ return;
+ }
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Create a new socket for the connection.
+ asio::error_code ec;
+ socket_holder sock(socket_ops::socket(impl.protocol_.family(),
+ impl.protocol_.type(), impl.protocol_.protocol(), ec));
+ if (sock.get() == invalid_socket)
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef accept_operation<Socket, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ socket_type new_socket = sock.get();
+ bool enable_connection_aborted =
+ (impl.flags_ & implementation_type::enable_connection_aborted);
+ handler_ptr<alloc_traits> ptr(raw_ptr,
+ iocp_service_, impl.socket_, new_socket, peer, impl.protocol_,
+ peer_endpoint, enable_connection_aborted, handler);
+ sock.release();
+
+ // Accept a connection.
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(impl.socket_, ptr.get()->new_socket(),
+ ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
+ ptr.get()->address_length(), &bytes_read, ptr.get());
+ DWORD last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (!result && last_error != WSA_IO_PENDING)
+ {
+ if (!enable_connection_aborted
+ && (last_error == ERROR_NETNAME_DELETED
+ || last_error == WSAECONNABORTED))
+ {
+ // Post handler so that operation will be restarted again. We do not
+ // perform the AcceptEx again here to avoid the possibility of starving
+ // other handlers.
+ iocp_service_.post_completion(ptr.get(), last_error, 0);
+ ptr.release();
+ }
+ else
+ {
+ asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec));
+ }
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Connect the socket to the specified endpoint.
+ asio::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, asio::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ // Perform the connect operation.
+ socket_ops::connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ return ec;
+ }
+
+ template <typename Handler>
+ class connect_handler
+ {
+ public:
+ connect_handler(socket_type socket, bool user_set_non_blocking,
+ boost::shared_ptr<bool> completed,
+ asio::io_service& io_service,
+ reactor_type& reactor, Handler handler)
+ : socket_(socket),
+ user_set_non_blocking_(user_set_non_blocking),
+ completed_(completed),
+ io_service_(io_service),
+ reactor_(reactor),
+ work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const asio::error_code& result)
+ {
+ // Check whether a handler has already been called for the connection.
+ // If it has, then we don't want to do anything in this handler.
+ if (*completed_)
+ return true;
+
+ // Cancel the other reactor operation for the connection.
+ *completed_ = true;
+ reactor_.enqueue_cancel_ops_unlocked(socket_);
+
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result));
+ return true;
+ }
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ asio::error_code ec;
+ if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == socket_error_retval)
+ {
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+
+ // If connection failed then post the handler with the error code.
+ if (connect_error)
+ {
+ ec = asio::error_code(connect_error,
+ asio::error::get_system_category());
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!user_set_non_blocking_)
+ {
+ ioctl_arg_type non_blocking = 0;
+ if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec))
+ {
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+ }
+
+ // Post the result of the successful connection operation.
+ ec = asio::error_code();
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
+
+ private:
+ socket_type socket_;
+ bool user_set_non_blocking_;
+ boost::shared_ptr<bool> completed_;
+ asio::io_service& io_service_;
+ reactor_type& reactor_;
+ asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ asio::error::bad_descriptor));
+ return;
+ }
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ // Mark the socket as non-blocking so that the connection will take place
+ // asynchronously.
+ ioctl_arg_type non_blocking = 1;
+ asio::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+
+ // Start the connect operation.
+ if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
+ peer_endpoint.size(), ec) == 0)
+ {
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ {
+ non_blocking = 0;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ }
+
+ // The connect operation has finished successfully so we need to post the
+ // handler immediately.
+ this->get_io_service().post(bind_handler(handler, ec));
+ }
+ else if (ec == asio::error::in_progress
+ || ec == asio::error::would_block)
+ {
+ // The connection is happening in the background, and we need to wait
+ // until the socket becomes writeable.
+ boost::shared_ptr<bool> completed(new bool(false));
+ reactor->start_write_and_except_ops(impl.socket_,
+ connect_handler<Handler>(
+ impl.socket_,
+ (impl.flags_ & implementation_type::user_set_non_blocking) != 0,
+ completed, this->get_io_service(), *reactor, handler));
+ }
+ else
+ {
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ {
+ non_blocking = 0;
+ asio::error_code ignored_ec;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
+ }
+
+ // The connect operation has failed, so post the handler immediately.
+ this->get_io_service().post(bind_handler(handler, ec));
+ }
+ }
+
+private:
+ // Helper function to close a socket when the associated object is being
+ // destroyed.
+ void close_for_destruction(implementation_type& impl)
+ {
+ if (is_open(impl))
+ {
+ // Check if the reactor was created, in which case we need to close the
+ // socket on the reactor as well to cancel any operations that might be
+ // running there.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (reactor)
+ reactor->close_descriptor(impl.socket_);
+
+ // The socket destructor must not block. If the user has changed the
+ // linger option to block in the foreground, we will change it back to the
+ // default so that the closure is performed in the background.
+ if (impl.flags_ & implementation_type::close_might_block)
+ {
+ ::linger opt;
+ opt.l_onoff = 0;
+ opt.l_linger = 0;
+ asio::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_,
+ SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
+ }
+
+ asio::error_code ignored_ec;
+ socket_ops::close(impl.socket_, ignored_ec);
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+ }
+ }
+
+ // Helper function to emulate InterlockedCompareExchangePointer functionality
+ // for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp)
+ {
+#if defined(_M_IX86)
+ return reinterpret_cast<void*>(InterlockedCompareExchange(
+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
+ reinterpret_cast<LONG>(cmp)));
+#else
+ return InterlockedCompareExchangePointer(dest, exch, cmp);
+#endif
+ }
+
+ // Helper function to emulate InterlockedExchangePointer functionality for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ void* interlocked_exchange_pointer(void** dest, void* val)
+ {
+#if defined(_M_IX86)
+ return reinterpret_cast<void*>(InterlockedExchange(
+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
+#else
+ return InterlockedExchangePointer(dest, val);
+#endif
+ }
+
+ // The IOCP service used for running asynchronous operations and dispatching
+ // handlers.
+ win_iocp_io_service& iocp_service_;
+
+ // The reactor used for performing connect operations. This object is created
+ // only if needed.
+ reactor_type* reactor_;
+
+ // Mutex to protect access to the linked list of implementations.
+ asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
diff --git a/src/libtorrent/asio/detail/win_mutex.hpp b/src/libtorrent/asio/detail/win_mutex.hpp
new file mode 100644
index 0000000..4fdb597
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_mutex.hpp
@@ -0,0 +1,149 @@
+//
+// win_mutex.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_MUTEX_HPP
+#define ASIO_DETAIL_WIN_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<win_mutex> scoped_lock;
+
+ // Constructor.
+ win_mutex()
+ {
+ int error = do_init();
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~win_mutex()
+ {
+ ::DeleteCriticalSection(&crit_section_);
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ int error = do_lock();
+ if (error != 0)
+ {
+ asio::system_error e(
+ asio::error_code(error,
+ asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ ::LeaveCriticalSection(&crit_section_);
+ }
+
+private:
+ // Initialisation must be performed in a separate function to the constructor
+ // since the compiler does not support the use of structured exceptions and
+ // C++ exceptions in the same function.
+ int do_init()
+ {
+#if defined(__MINGW32__)
+ // Not sure if MinGW supports structured exception handling, so for now
+ // we'll just call the Windows API and hope.
+ ::InitializeCriticalSection(&crit_section_);
+ return 0;
+#else
+ __try
+ {
+ ::InitializeCriticalSection(&crit_section_);
+ }
+ __except(GetExceptionCode() == STATUS_NO_MEMORY
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ return 0;
+#endif
+ }
+
+ // Locking must be performed in a separate function to lock() since the
+ // compiler does not support the use of structured exceptions and C++
+ // exceptions in the same function.
+ int do_lock()
+ {
+#if defined(__MINGW32__)
+ // Not sure if MinGW supports structured exception handling, so for now
+ // we'll just call the Windows API and hope.
+ ::EnterCriticalSection(&crit_section_);
+ return 0;
+#else
+ __try
+ {
+ ::EnterCriticalSection(&crit_section_);
+ }
+ __except(GetExceptionCode() == STATUS_INVALID_HANDLE
+ || GetExceptionCode() == STATUS_NO_MEMORY
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ if (GetExceptionCode() == STATUS_NO_MEMORY)
+ return ERROR_OUTOFMEMORY;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ return 0;
+#endif
+ }
+
+ ::CRITICAL_SECTION crit_section_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_MUTEX_HPP
diff --git a/src/libtorrent/asio/detail/win_signal_blocker.hpp b/src/libtorrent/asio/detail/win_signal_blocker.hpp
new file mode 100644
index 0000000..5c3c9f4
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_signal_blocker.hpp
@@ -0,0 +1,67 @@
+//
+// win_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/noncopyable.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_signal_blocker
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ win_signal_blocker()
+ {
+ // No-op.
+ }
+
+ // Destructor restores the previous signal mask.
+ ~win_signal_blocker()
+ {
+ // No-op.
+ }
+
+ // Block all signals for the calling thread.
+ void block()
+ {
+ // No-op.
+ }
+
+ // Restore the previous signal mask.
+ void unblock()
+ {
+ // No-op.
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
diff --git a/src/libtorrent/asio/detail/win_thread.hpp b/src/libtorrent/asio/detail/win_thread.hpp
new file mode 100644
index 0000000..acd8b51
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_thread.hpp
@@ -0,0 +1,125 @@
+//
+// win_thread.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_THREAD_HPP
+#define ASIO_DETAIL_WIN_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include <memory>
+#include <process.h>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+unsigned int __stdcall win_thread_function(void* arg);
+
+class win_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ win_thread(Function f)
+ {
+ std::auto_ptr<func_base> arg(new func<Function>(f));
+ unsigned int thread_id = 0;
+ thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0,
+ win_thread_function, arg.get(), 0, &thread_id));
+ if (!thread_)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "thread");
+ boost::throw_exception(e);
+ }
+ arg.release();
+ }
+
+ // Destructor.
+ ~win_thread()
+ {
+ ::CloseHandle(thread_);
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
+
+private:
+ friend unsigned int __stdcall win_thread_function(void* arg);
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ::HANDLE thread_;
+};
+
+inline unsigned int __stdcall win_thread_function(void* arg)
+{
+ std::auto_ptr<win_thread::func_base> func(
+ static_cast<win_thread::func_base*>(arg));
+ func->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_THREAD_HPP
diff --git a/src/libtorrent/asio/detail/win_tss_ptr.hpp b/src/libtorrent/asio/detail/win_tss_ptr.hpp
new file mode 100644
index 0000000..40b4115
--- /dev/null
+++ b/src/libtorrent/asio/detail/win_tss_ptr.hpp
@@ -0,0 +1,95 @@
+//
+// win_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WIN_TSS_PTR_HPP
+#define ASIO_DETAIL_WIN_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class win_tss_ptr
+ : private noncopyable
+{
+public:
+#if defined(UNDER_CE)
+ enum { out_of_indexes = 0xFFFFFFFF };
+#else
+ enum { out_of_indexes = TLS_OUT_OF_INDEXES };
+#endif
+
+ // Constructor.
+ win_tss_ptr()
+ {
+ tss_key_ = ::TlsAlloc();
+ if (tss_key_ == out_of_indexes)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "tss");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~win_tss_ptr()
+ {
+ ::TlsFree(tss_key_);
+ }
+
+ // Get the value.
+ operator T*() const
+ {
+ return static_cast<T*>(::TlsGetValue(tss_key_));
+ }
+
+ // Set the value.
+ void operator=(T* value)
+ {
+ ::TlsSetValue(tss_key_, value);
+ }
+
+private:
+ // Thread-specific storage to allow unlocked access to determine whether a
+ // thread is a member of the pool.
+ DWORD tss_key_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP
diff --git a/src/libtorrent/asio/detail/wince_thread.hpp b/src/libtorrent/asio/detail/wince_thread.hpp
new file mode 100644
index 0000000..d0b4a9f
--- /dev/null
+++ b/src/libtorrent/asio/detail/wince_thread.hpp
@@ -0,0 +1,124 @@
+//
+// wince_thread.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WINCE_THREAD_HPP
+#define ASIO_DETAIL_WINCE_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include <memory>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD WINAPI wince_thread_function(LPVOID arg);
+
+class wince_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ wince_thread(Function f)
+ {
+ std::auto_ptr<func_base> arg(new func<Function>(f));
+ DWORD thread_id = 0;
+ thread_ = ::CreateThread(0, 0, wince_thread_function,
+ arg.get(), 0, &thread_id);
+ if (!thread_)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "thread");
+ boost::throw_exception(e);
+ }
+ arg.release();
+ }
+
+ // Destructor.
+ ~wince_thread()
+ {
+ ::CloseHandle(thread_);
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
+
+private:
+ friend DWORD WINAPI wince_thread_function(LPVOID arg);
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ::HANDLE thread_;
+};
+
+inline DWORD WINAPI wince_thread_function(LPVOID arg)
+{
+ std::auto_ptr<wince_thread::func_base> func(
+ static_cast<wince_thread::func_base*>(arg));
+ func->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WINCE_THREAD_HPP
diff --git a/src/libtorrent/asio/detail/winsock_init.hpp b/src/libtorrent/asio/detail/winsock_init.hpp
new file mode 100644
index 0000000..f5ca1a9
--- /dev/null
+++ b/src/libtorrent/asio/detail/winsock_init.hpp
@@ -0,0 +1,120 @@
+//
+// winsock_init.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WINSOCK_INIT_HPP
+#define ASIO_DETAIL_WINSOCK_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/system_error.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace detail {
+
+template <int Major = 2, int Minor = 0>
+class winsock_init
+ : private noncopyable
+{
+private:
+ // Structure to perform the actual initialisation.
+ struct do_init
+ {
+ do_init()
+ {
+ WSADATA wsa_data;
+ result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data);
+ }
+
+ ~do_init()
+ {
+ ::WSACleanup();
+ }
+
+ int result() const
+ {
+ return result_;
+ }
+
+ // Helper function to manage a do_init singleton. The static instance of the
+ // winsock_init object ensures that this function is always called before
+ // main, and therefore before any other threads can get started. The do_init
+ // instance must be static in this function to ensure that it gets
+ // initialised before any other global objects try to use it.
+ static boost::shared_ptr<do_init> instance()
+ {
+ static boost::shared_ptr<do_init> init(new do_init);
+ return init;
+ }
+
+ private:
+ int result_;
+ };
+
+public:
+ // Constructor.
+ winsock_init()
+ : ref_(do_init::instance())
+ {
+ // Check whether winsock was successfully initialised. This check is not
+ // performed for the global instance since there will be nobody around to
+ // catch the exception.
+ if (this != &instance_ && ref_->result() != 0)
+ {
+ asio::system_error e(
+ asio::error_code(ref_->result(),
+ asio::error::get_system_category()),
+ "winsock");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~winsock_init()
+ {
+ }
+
+private:
+ // Instance to force initialisation of winsock at global scope.
+ static winsock_init instance_;
+
+ // Reference to singleton do_init object to ensure that winsock does not get
+ // cleaned up until the last user has finished with it.
+ boost::shared_ptr<do_init> ref_;
+};
+
+template <int Major, int Minor>
+winsock_init<Major, Minor> winsock_init<Major, Minor>::instance_;
+
+} // namespace detail
+} // namespace asio
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WINSOCK_INIT_HPP
diff --git a/src/libtorrent/asio/detail/wrapped_handler.hpp b/src/libtorrent/asio/detail/wrapped_handler.hpp
new file mode 100644
index 0000000..0d8d035
--- /dev/null
+++ b/src/libtorrent/asio/detail/wrapped_handler.hpp
@@ -0,0 +1,193 @@
+//
+// wrapped_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_DETAIL_WRAPPED_HANDLER_HPP
+#define ASIO_DETAIL_WRAPPED_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/type_traits.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Dispatcher, typename Handler>
+class wrapped_handler
+{
+public:
+ typedef void result_type;
+
+ wrapped_handler(
+ typename boost::add_reference<Dispatcher>::type dispatcher,
+ Handler handler)
+ : dispatcher_(dispatcher),
+ handler_(handler)
+ {
+ }
+
+ void operator()()
+ {
+ dispatcher_.dispatch(handler_);
+ }
+
+ void operator()() const
+ {
+ dispatcher_.dispatch(handler_);
+ }
+
+ template <typename Arg1>
+ void operator()(const Arg1& arg1)
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
+ }
+
+ template <typename Arg1>
+ void operator()(const Arg1& arg1) const
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
+ }
+
+ template <typename Arg1, typename Arg2>
+ void operator()(const Arg1& arg1, const Arg2& arg2)
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
+ }
+
+ template <typename Arg1, typename Arg2>
+ void operator()(const Arg1& arg1, const Arg2& arg2) const
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4)
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4) const
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4, const Arg5& arg5)
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4, const Arg5& arg5) const
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
+ }
+
+//private:
+ Dispatcher dispatcher_;
+ Handler handler_;
+};
+
+template <typename Dispatcher, typename Handler>
+inline void* asio_handler_allocate(std::size_t size,
+ wrapped_handler<Dispatcher, Handler>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Dispatcher, typename Handler>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ wrapped_handler<Dispatcher, Handler>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Handler, typename Context>
+class rewrapped_handler
+{
+public:
+ explicit rewrapped_handler(const Handler& handler, const Context& context)
+ : handler_(handler),
+ context_(context)
+ {
+ }
+
+ void operator()()
+ {
+ handler_();
+ }
+
+ void operator()() const
+ {
+ handler_();
+ }
+
+//private:
+ Handler handler_;
+ Context context_;
+};
+
+template <typename Function, typename Dispatcher, typename Handler>
+inline void asio_handler_invoke(const Function& function,
+ wrapped_handler<Dispatcher, Handler>* this_handler)
+{
+ this_handler->dispatcher_.dispatch(
+ rewrapped_handler<Function, Handler>(
+ function, this_handler->handler_));
+}
+
+template <typename Function, typename Handler, typename Context>
+inline void asio_handler_invoke(const Function& function,
+ rewrapped_handler<Handler, Context>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->context_);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP
diff --git a/src/libtorrent/asio/error.hpp b/src/libtorrent/asio/error.hpp
new file mode 100644
index 0000000..7a82a88
--- /dev/null
+++ b/src/libtorrent/asio/error.hpp
@@ -0,0 +1,260 @@
+//
+// error.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_ERROR_HPP
+#define ASIO_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cerrno>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+/// INTERNAL ONLY.
+# define ASIO_NATIVE_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_SOCKET_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_NETDB_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_GETADDRINFO_ERROR(e) implementation_defined
+/// INTERNAL ONLY.
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# define ASIO_NATIVE_ERROR(e) e
+# define ASIO_SOCKET_ERROR(e) WSA ## e
+# define ASIO_NETDB_ERROR(e) WSA ## e
+# define ASIO_GETADDRINFO_ERROR(e) WSA ## e
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win
+#else
+# define ASIO_NATIVE_ERROR(e) e
+# define ASIO_SOCKET_ERROR(e) e
+# define ASIO_NETDB_ERROR(e) e
+# define ASIO_GETADDRINFO_ERROR(e) e
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix
+#endif
+
+namespace asio {
+namespace error {
+
+enum basic_errors
+{
+ /// Permission denied.
+ access_denied = ASIO_SOCKET_ERROR(EACCES),
+
+ /// Address family not supported by protocol.
+ address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT),
+
+ /// Address already in use.
+ address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE),
+
+ /// Transport endpoint is already connected.
+ already_connected = ASIO_SOCKET_ERROR(EISCONN),
+
+ /// Operation already in progress.
+ already_started = ASIO_SOCKET_ERROR(EALREADY),
+
+ /// Broken pipe.
+ broken_pipe = ASIO_WIN_OR_POSIX(
+ ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE),
+ ASIO_NATIVE_ERROR(EPIPE)),
+
+ /// A connection has been aborted.
+ connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED),
+
+ /// Connection refused.
+ connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED),
+
+ /// Connection reset by peer.
+ connection_reset = ASIO_SOCKET_ERROR(ECONNRESET),
+
+ /// Bad file descriptor.
+ bad_descriptor = ASIO_SOCKET_ERROR(EBADF),
+
+ /// Bad address.
+ fault = ASIO_SOCKET_ERROR(EFAULT),
+
+ /// No route to host.
+ host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH),
+
+ /// Operation now in progress.
+ in_progress = ASIO_SOCKET_ERROR(EINPROGRESS),
+
+ /// Interrupted system call.
+ interrupted = ASIO_SOCKET_ERROR(EINTR),
+
+ /// Invalid argument.
+ invalid_argument = ASIO_SOCKET_ERROR(EINVAL),
+
+ /// Message too long.
+ message_size = ASIO_SOCKET_ERROR(EMSGSIZE),
+
+ /// The name was too long.
+ name_too_long = ASIO_SOCKET_ERROR(ENAMETOOLONG),
+
+ /// Network is down.
+ network_down = ASIO_SOCKET_ERROR(ENETDOWN),
+
+ /// Network dropped connection on reset.
+ network_reset = ASIO_SOCKET_ERROR(ENETRESET),
+
+ /// Network is unreachable.
+ network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH),
+
+ /// Too many open files.
+ no_descriptors = ASIO_SOCKET_ERROR(EMFILE),
+
+ /// No buffer space available.
+ no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS),
+
+ /// Cannot allocate memory.
+ no_memory = ASIO_WIN_OR_POSIX(
+ ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY),
+ ASIO_NATIVE_ERROR(ENOMEM)),
+
+ /// Operation not permitted.
+ no_permission = ASIO_WIN_OR_POSIX(
+ ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED),
+ ASIO_NATIVE_ERROR(EPERM)),
+
+ /// Protocol not available.
+ no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT),
+
+ /// Transport endpoint is not connected.
+ not_connected = ASIO_SOCKET_ERROR(ENOTCONN),
+
+ /// Socket operation on non-socket.
+ not_socket = ASIO_SOCKET_ERROR(ENOTSOCK),
+
+ /// Operation cancelled.
+ operation_aborted = ASIO_WIN_OR_POSIX(
+ ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED),
+ ASIO_NATIVE_ERROR(ECANCELED)),
+
+ /// Operation not supported.
+ operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP),
+
+ /// Cannot send after transport endpoint shutdown.
+ shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN),
+
+ /// Connection timed out.
+ timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT),
+
+ /// Resource temporarily unavailable.
+ try_again = ASIO_WIN_OR_POSIX(
+ ASIO_NATIVE_ERROR(ERROR_RETRY),
+ ASIO_NATIVE_ERROR(EAGAIN)),
+
+ /// The socket is marked non-blocking and the requested operation would block.
+ would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK)
+};
+
+enum netdb_errors
+{
+ /// Host not found (authoritative).
+ host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND),
+
+ /// Host not found (non-authoritative).
+ host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN),
+
+ /// The query is valid but does not have associated address data.
+ no_data = ASIO_NETDB_ERROR(NO_DATA),
+
+ /// A non-recoverable error occurred.
+ no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY)
+};
+
+enum addrinfo_errors
+{
+ /// The service is not supported for the given socket type.
+ service_not_found = ASIO_WIN_OR_POSIX(
+ ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND),
+ ASIO_GETADDRINFO_ERROR(EAI_SERVICE)),
+
+ /// The socket type is not supported.
+ socket_type_not_supported = ASIO_WIN_OR_POSIX(
+ ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT),
+ ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE))
+};
+
+enum misc_errors
+{
+ /// Already open.
+ already_open = 1,
+
+ /// End of file or stream.
+ eof,
+
+ /// Element not found.
+ not_found,
+
+ /// The descriptor cannot fit into the select system call's fd_set.
+ fd_set_failure
+};
+
+enum ssl_errors
+{
+};
+
+// boostify: error category definitions go here.
+
+inline asio::error_code make_error_code(basic_errors e)
+{
+ return asio::error_code(
+ static_cast<int>(e), get_system_category());
+}
+
+inline asio::error_code make_error_code(netdb_errors e)
+{
+ return asio::error_code(
+ static_cast<int>(e), get_netdb_category());
+}
+
+inline asio::error_code make_error_code(addrinfo_errors e)
+{
+ return asio::error_code(
+ static_cast<int>(e), get_addrinfo_category());
+}
+
+inline asio::error_code make_error_code(misc_errors e)
+{
+ return asio::error_code(
+ static_cast<int>(e), get_misc_category());
+}
+
+inline asio::error_code make_error_code(ssl_errors e)
+{
+ return asio::error_code(
+ static_cast<int>(e), get_ssl_category());
+}
+
+} // namespace error
+} // namespace asio
+
+#undef ASIO_NATIVE_ERROR
+#undef ASIO_SOCKET_ERROR
+#undef ASIO_NETDB_ERROR
+#undef ASIO_GETADDRINFO_ERROR
+#undef ASIO_WIN_OR_POSIX
+
+#include "asio/impl/error_code.ipp"
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_ERROR_HPP
diff --git a/src/libtorrent/asio/error_code.hpp b/src/libtorrent/asio/error_code.hpp
new file mode 100644
index 0000000..9e67fca
--- /dev/null
+++ b/src/libtorrent/asio/error_code.hpp
@@ -0,0 +1,164 @@
+//
+// error_code.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_ERROR_CODE_HPP
+#define ASIO_ERROR_CODE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <string>
+#include "asio/detail/pop_options.hpp"
+
+#if defined(GENERATING_DOCUMENTATION)
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win
+#else
+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix
+#endif
+
+namespace asio {
+
+namespace error
+{
+ /// Available error code categories.
+ enum error_category
+ {
+ /// System error codes.
+ system_category = ASIO_WIN_OR_POSIX(0, 0),
+
+ /// Error codes from NetDB functions.
+ netdb_category = ASIO_WIN_OR_POSIX(system_category, 1),
+
+ /// Error codes from getaddrinfo.
+ addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2),
+
+ /// Miscellaneous error codes.
+ misc_category = ASIO_WIN_OR_POSIX(3, 3),
+
+ /// SSL error codes.
+ ssl_category = ASIO_WIN_OR_POSIX(4, 4)
+ };
+
+ // Category getters.
+ inline error_category get_system_category() { return system_category; }
+ inline error_category get_netdb_category() { return netdb_category; }
+ inline error_category get_addrinfo_category() { return addrinfo_category; }
+ inline error_category get_misc_category() { return misc_category; }
+ inline error_category get_ssl_category() { return ssl_category; }
+
+} // namespace error
+
+/// Bring error category type into the asio namespace.
+typedef asio::error::error_category error_category;
+
+/// Class to represent an error code value.
+class error_code
+{
+public:
+ /// The underlying representation of an error code.
+ typedef int value_type;
+
+ /// Default constructor.
+ error_code()
+ : value_(0),
+ category_(error::system_category)
+ {
+ }
+
+ /// Construct with specific error code and category.
+ error_code(value_type v, error_category c)
+ : value_(v),
+ category_(c)
+ {
+ }
+
+ /// Construct from an error code enum.
+ template <typename ErrorEnum>
+ error_code(ErrorEnum e)
+ {
+ *this = make_error_code(e);
+ }
+
+ /// Get the error value.
+ value_type value() const
+ {
+ return value_;
+ }
+
+ /// Get the error category.
+ error_category category() const
+ {
+ return category_;
+ }
+
+ /// Get the message associated with the error.
+ std::string message() const;
+
+ struct unspecified_bool_type_t
+ {
+ };
+
+ typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
+
+ static void unspecified_bool_true(unspecified_bool_type_t)
+ {
+ }
+
+ /// Operator returns non-null if there is a non-success error code.
+ operator unspecified_bool_type() const
+ {
+ if (value_ == 0)
+ return 0;
+ else
+ return &error_code::unspecified_bool_true;
+ }
+
+ /// Operator to test if the error represents success.
+ bool operator!() const
+ {
+ return value_ == 0;
+ }
+
+ /// Equality operator to compare two error objects.
+ friend bool operator==(const error_code& e1, const error_code& e2)
+ {
+ return e1.value_ == e2.value_ && e1.category_ == e2.category_;
+ }
+
+ /// Inequality operator to compare two error objects.
+ friend bool operator!=(const error_code& e1, const error_code& e2)
+ {
+ return e1.value_ != e2.value_ || e1.category_ != e2.category_;
+ }
+
+private:
+ // The value associated with the error code.
+ value_type value_;
+
+ // The category associated with the error code.
+ error_category category_;
+};
+
+} // namespace asio
+
+#undef ASIO_WIN_OR_POSIX
+
+#include "asio/error.hpp"
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_ERROR_CODE_HPP
diff --git a/src/libtorrent/asio/handler_alloc_hook.hpp b/src/libtorrent/asio/handler_alloc_hook.hpp
new file mode 100644
index 0000000..f49a78d
--- /dev/null
+++ b/src/libtorrent/asio/handler_alloc_hook.hpp
@@ -0,0 +1,88 @@
+//
+// handler_alloc_hook.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_HANDLER_ALLOC_HOOK_HPP
+#define ASIO_HANDLER_ALLOC_HOOK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+
+/// Default allocation function for handlers.
+/**
+ * Asynchronous operations may need to allocate temporary objects. Since
+ * asynchronous operations have a handler function object, these temporary
+ * objects can be said to be associated with the handler.
+ *
+ * Implement asio_handler_allocate and asio_handler_deallocate for your own
+ * handlers to provide custom allocation for these temporary objects.
+ *
+ * This default implementation is simply:
+ * @code
+ * return ::operator new(bytes);
+ * @endcode
+ *
+ * @note All temporary objects associated with a handler will be deallocated
+ * before the upcall to the handler is performed. This allows the same memory to
+ * be reused for a subsequent asynchronous operation initiated by the handler.
+ *
+ * @par Example
+ * @code
+ * class my_handler;
+ *
+ * void* asio_handler_allocate(std::size_t size, my_handler* context)
+ * {
+ * return ::operator new(size);
+ * }
+ *
+ * void asio_handler_deallocate(void* pointer, std::size_t size,
+ * my_handler* context)
+ * {
+ * ::operator delete(pointer);
+ * }
+ * @endcode
+ */
+inline void* asio_handler_allocate(std::size_t size, ...)
+{
+ return ::operator new(size);
+}
+
+/// Default deallocation function for handlers.
+/**
+ * Implement asio_handler_allocate and asio_handler_deallocate for your own
+ * handlers to provide custom allocation for the associated temporary objects.
+ *
+ * This default implementation is simply:
+ * @code
+ * ::operator delete(pointer);
+ * @endcode
+ *
+ * @sa asio_handler_allocate.
+ */
+inline void asio_handler_deallocate(void* pointer, std::size_t size, ...)
+{
+ (void)(size);
+ ::operator delete(pointer);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_HANDLER_ALLOC_HOOK_HPP
diff --git a/src/libtorrent/asio/handler_invoke_hook.hpp b/src/libtorrent/asio/handler_invoke_hook.hpp
new file mode 100644
index 0000000..0c6587d
--- /dev/null
+++ b/src/libtorrent/asio/handler_invoke_hook.hpp
@@ -0,0 +1,69 @@
+//
+// handler_invoke_hook.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_HANDLER_INVOKE_HOOK_HPP
+#define ASIO_HANDLER_INVOKE_HOOK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Default invoke function for handlers.
+/**
+ * Completion handlers for asynchronous operations are invoked by the
+ * io_service associated with the corresponding object (e.g. a socket or
+ * deadline_timer). Certain guarantees are made on when the handler may be
+ * invoked, in particular that a handler can only be invoked from a thread that
+ * is currently calling asio::io_service::run() on the corresponding
+ * io_service object. Handlers may subsequently be invoked through other
+ * objects (such as asio::strand objects) that provide additional
+ * guarantees.
+ *
+ * When asynchronous operations are composed from other asynchronous
+ * operations, all intermediate handlers should be invoked using the same
+ * method as the final handler. This is required to ensure that user-defined
+ * objects are not accessed in a way that may violate the guarantees. This
+ * hooking function ensures that the invoked method used for the final handler
+ * is accessible at each intermediate step.
+ *
+ * Implement asio_handler_invoke for your own handlers to specify a custom
+ * invocation strategy.
+ *
+ * This default implementation is simply:
+ * @code
+ * function();
+ * @endcode
+ *
+ * @par Example
+ * @code
+ * class my_handler;
+ *
+ * template <typename Function>
+ * void asio_handler_invoke(Function function, my_handler* context)
+ * {
+ * context->strand_.dispatch(function);
+ * }
+ * @endcode
+ */
+template <typename Function>
+inline void asio_handler_invoke(Function function, ...)
+{
+ function();
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_HANDLER_INVOKE_HOOK_HPP
diff --git a/src/libtorrent/asio/impl/error_code.ipp b/src/libtorrent/asio/impl/error_code.ipp
new file mode 100644
index 0000000..fa0520a
--- /dev/null
+++ b/src/libtorrent/asio/impl/error_code.ipp
@@ -0,0 +1,104 @@
+//
+// error_code.ipp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_ERROR_CODE_IPP
+#define ASIO_ERROR_CODE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <cerrno>
+#include <cstring>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/detail/local_free_on_block_exit.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+
+inline std::string error_code::message() const
+{
+ if (*this == error::already_open)
+ return "Already open.";
+ if (*this == error::not_found)
+ return "Not found.";
+ if (*this == error::fd_set_failure)
+ return "The descriptor does not fit into the select call's fd_set.";
+ if (category_ == error::get_ssl_category())
+ return "SSL error.";
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ value_type value = value_;
+ if (category() != error::get_system_category() && *this != error::eof)
+ return "asio error";
+ if (*this == error::eof)
+ value = ERROR_HANDLE_EOF;
+ char* msg = 0;
+ DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);
+ detail::local_free_on_block_exit local_free_obj(msg);
+ if (length && msg[length - 1] == '\n')
+ msg[--length] = '\0';
+ if (length && msg[length - 1] == '\r')
+ msg[--length] = '\0';
+ if (length)
+ return msg;
+ else
+ return "asio error";
+#else // defined(BOOST_WINDOWS)
+ if (*this == error::eof)
+ return "End of file.";
+ if (*this == error::host_not_found)
+ return "Host not found (authoritative).";
+ if (*this == error::host_not_found_try_again)
+ return "Host not found (non-authoritative), try again later.";
+ if (*this == error::no_recovery)
+ return "A non-recoverable error occurred during database lookup.";
+ if (*this == error::no_data)
+ return "The query is valid, but it does not have associated data.";
+ if (*this == error::not_found)
+ return "Element not found.";
+#if !defined(__sun)
+ if (*this == error::operation_aborted)
+ return "Operation aborted.";
+#endif // !defined(__sun)
+ if (*this == error::service_not_found)
+ return "Service not found.";
+ if (*this == error::socket_type_not_supported)
+ return "Socket type not supported.";
+ if (category() != error::get_system_category())
+ return "asio error";
+#if defined(__sun) || defined(__QNX__)
+ return strerror(value_);
+#elif defined(__MACH__) && defined(__APPLE__) \
+|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
+|| defined(_AIX) || defined(__hpux) || defined(__osf__)
+ char buf[256] = "";
+ strerror_r(value_, buf, sizeof(buf));
+ return buf;
+#else
+ char buf[256] = "";
+ return strerror_r(value_, buf, sizeof(buf));
+#endif
+#endif // defined(BOOST_WINDOWS)
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_ERROR_CODE_IPP
diff --git a/src/libtorrent/asio/impl/io_service.ipp b/src/libtorrent/asio/impl/io_service.ipp
new file mode 100644
index 0000000..e548055
--- /dev/null
+++ b/src/libtorrent/asio/impl/io_service.ipp
@@ -0,0 +1,224 @@
+//
+// io_service.ipp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IO_SERVICE_IPP
+#define ASIO_IO_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <limits>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/dev_poll_reactor.hpp"
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/service_registry.hpp"
+#include "asio/detail/task_io_service.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_iocp_io_service.hpp"
+
+namespace asio {
+
+inline io_service::io_service()
+ : service_registry_(new asio::detail::service_registry(*this)),
+ impl_(service_registry_->use_service<impl_type>())
+{
+ impl_.init((std::numeric_limits<std::size_t>::max)());
+}
+
+inline io_service::io_service(std::size_t concurrency_hint)
+ : service_registry_(new asio::detail::service_registry(*this)),
+ impl_(service_registry_->use_service<impl_type>())
+{
+ impl_.init(concurrency_hint);
+}
+
+inline io_service::~io_service()
+{
+ delete service_registry_;
+}
+
+inline std::size_t io_service::run()
+{
+ asio::error_code ec;
+ std::size_t s = impl_.run(ec);
+ asio::detail::throw_error(ec);
+ return s;
+}
+
+inline std::size_t io_service::run(asio::error_code& ec)
+{
+ return impl_.run(ec);
+}
+
+inline std::size_t io_service::run_one()
+{
+ asio::error_code ec;
+ std::size_t s = impl_.run_one(ec);
+ asio::detail::throw_error(ec);
+ return s;
+}
+
+inline std::size_t io_service::run_one(asio::error_code& ec)
+{
+ return impl_.run_one(ec);
+}
+
+inline std::size_t io_service::poll()
+{
+ asio::error_code ec;
+ std::size_t s = impl_.poll(ec);
+ asio::detail::throw_error(ec);
+ return s;
+}
+
+inline std::size_t io_service::poll(asio::error_code& ec)
+{
+ return impl_.poll(ec);
+}
+
+inline std::size_t io_service::poll_one()
+{
+ asio::error_code ec;
+ std::size_t s = impl_.poll_one(ec);
+ asio::detail::throw_error(ec);
+ return s;
+}
+
+inline std::size_t io_service::poll_one(asio::error_code& ec)
+{
+ return impl_.poll_one(ec);
+}
+
+inline void io_service::stop()
+{
+ impl_.stop();
+}
+
+inline void io_service::reset()
+{
+ impl_.reset();
+}
+
+template <typename Handler>
+inline void io_service::dispatch(Handler handler)
+{
+ impl_.dispatch(handler);
+}
+
+template <typename Handler>
+inline void io_service::post(Handler handler)
+{
+ impl_.post(handler);
+}
+
+template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+unspecified
+#else
+inline detail::wrapped_handler<io_service&, Handler>
+#endif
+io_service::wrap(Handler handler)
+{
+ return detail::wrapped_handler<io_service&, Handler>(*this, handler);
+}
+
+inline io_service::work::work(asio::io_service& io_service)
+ : io_service_(io_service)
+{
+ io_service_.impl_.work_started();
+}
+
+inline io_service::work::work(const work& other)
+ : io_service_(other.io_service_)
+{
+ io_service_.impl_.work_started();
+}
+
+inline io_service::work::~work()
+{
+ io_service_.impl_.work_finished();
+}
+
+inline asio::io_service& io_service::work::io_service()
+{
+ return io_service_;
+}
+
+inline asio::io_service& io_service::work::get_io_service()
+{
+ return io_service_;
+}
+
+inline io_service::service::service(asio::io_service& owner)
+ : owner_(owner),
+ type_info_(0),
+ next_(0)
+{
+}
+
+inline io_service::service::~service()
+{
+}
+
+inline asio::io_service& io_service::service::io_service()
+{
+ return owner_;
+}
+
+inline asio::io_service& io_service::service::get_io_service()
+{
+ return owner_;
+}
+
+template <typename Service>
+inline Service& use_service(io_service& ios)
+{
+ // Check that Service meets the necessary type requirements.
+ (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+ (void)static_cast<const io_service::id*>(&Service::id);
+
+ return ios.service_registry_->template use_service<Service>();
+}
+
+template <typename Service>
+void add_service(io_service& ios, Service* svc)
+{
+ // Check that Service meets the necessary type requirements.
+ (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+ (void)static_cast<const io_service::id*>(&Service::id);
+
+ if (&ios != &svc->io_service())
+ boost::throw_exception(invalid_service_owner());
+ if (!ios.service_registry_->template add_service<Service>(svc))
+ boost::throw_exception(service_already_exists());
+}
+
+template <typename Service>
+bool has_service(io_service& ios)
+{
+ // Check that Service meets the necessary type requirements.
+ (void)static_cast<io_service::service*>(static_cast<Service*>(0));
+ (void)static_cast<const io_service::id*>(&Service::id);
+
+ return ios.service_registry_->template has_service<Service>();
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IO_SERVICE_IPP
diff --git a/src/libtorrent/asio/impl/read.ipp b/src/libtorrent/asio/impl/read.ipp
new file mode 100644
index 0000000..b3d5739
--- /dev/null
+++ b/src/libtorrent/asio/impl/read.ipp
@@ -0,0 +1,314 @@
+//
+// read.ipp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_READ_IPP
+#define ASIO_READ_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <algorithm>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/error.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ asio::detail::consuming_buffers<
+ mutable_buffer, MutableBufferSequence> tmp(buffers);
+ std::size_t total_transferred = 0;
+ while (tmp.begin() != tmp.end())
+ {
+ std::size_t bytes_transferred = s.read_some(tmp, ec);
+ tmp.consume(bytes_transferred);
+ total_transferred += bytes_transferred;
+ if (completion_condition(ec, total_transferred))
+ return total_transferred;
+ }
+ ec = asio::error_code();
+ return total_transferred;
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, buffers, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ std::size_t total_transferred = 0;
+ for (;;)
+ {
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec);
+ b.commit(bytes_transferred);
+ total_transferred += bytes_transferred;
+ if (b.size() == b.max_size()
+ || completion_condition(ec, total_transferred))
+ return total_transferred;
+ }
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, b, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator,
+ typename CompletionCondition>
+inline std::size_t read(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read(s, b, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+ class read_handler
+ {
+ public:
+ typedef asio::detail::consuming_buffers<
+ mutable_buffer, MutableBufferSequence> buffers_type;
+
+ read_handler(AsyncReadStream& stream, const buffers_type& buffers,
+ CompletionCondition completion_condition, ReadHandler handler)
+ : stream_(stream),
+ buffers_(buffers),
+ total_transferred_(0),
+ completion_condition_(completion_condition),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ total_transferred_ += bytes_transferred;
+ buffers_.consume(bytes_transferred);
+ if (completion_condition_(ec, total_transferred_)
+ || buffers_.begin() == buffers_.end())
+ {
+ handler_(ec, total_transferred_);
+ }
+ else
+ {
+ stream_.async_read_some(buffers_, *this);
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ buffers_type buffers_;
+ std::size_t total_transferred_;
+ CompletionCondition completion_condition_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_handler<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_handler<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream,
+ typename MutableBufferSequence, typename CompletionCondition,
+ typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_handler<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, ReadHandler handler)
+{
+ asio::detail::consuming_buffers<
+ mutable_buffer, MutableBufferSequence> tmp(buffers);
+ s.async_read_some(tmp,
+ detail::read_handler<AsyncReadStream, MutableBufferSequence,
+ CompletionCondition, ReadHandler>(
+ s, tmp, completion_condition, handler));
+}
+
+template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename ReadHandler>
+inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+ ReadHandler handler)
+{
+ async_read(s, buffers, transfer_all(), handler);
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ class read_streambuf_handler
+ {
+ public:
+ read_streambuf_handler(AsyncReadStream& stream,
+ basic_streambuf<Allocator>& streambuf,
+ CompletionCondition completion_condition, ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ total_transferred_(0),
+ completion_condition_(completion_condition),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ total_transferred_ += bytes_transferred;
+ streambuf_.commit(bytes_transferred);
+ if (streambuf_.size() == streambuf_.max_size()
+ || completion_condition_(ec, total_transferred_))
+ {
+ handler_(ec, total_transferred_);
+ }
+ else
+ {
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
+ stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
+ }
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ std::size_t total_transferred_;
+ CompletionCondition completion_condition_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_streambuf_handler<AsyncReadStream, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_streambuf_handler<AsyncReadStream, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream,
+ typename Allocator, typename CompletionCondition, typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_streambuf_handler<AsyncReadStream, Allocator,
+ CompletionCondition, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+inline void async_read(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, ReadHandler handler)
+{
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ s.async_read_some(b.prepare(bytes_available),
+ detail::read_streambuf_handler<AsyncReadStream, Allocator,
+ CompletionCondition, ReadHandler>(
+ s, b, completion_condition, handler));
+}
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+inline void async_read(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, ReadHandler handler)
+{
+ async_read(s, b, transfer_all(), handler);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_READ_IPP
diff --git a/src/libtorrent/asio/impl/read_until.ipp b/src/libtorrent/asio/impl/read_until.ipp
new file mode 100644
index 0000000..fa549fe
--- /dev/null
+++ b/src/libtorrent/asio/impl/read_until.ipp
@@ -0,0 +1,756 @@
+//
+// read_until.ipp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_READ_UNTIL_IPP
+#define ASIO_READ_UNTIL_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <utility>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/const_buffers_iterator.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_until(s, b, delim, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim,
+ asio::error_code& ec)
+{
+ std::size_t next_search_start = 0;
+ for (;;)
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin(buffers, next_search_start);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ iterator iter = std::find(begin, end, delim);
+ if (iter != end)
+ {
+ // Found a match. We're done.
+ ec = asio::error_code();
+ return iter.position() + 1;
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ next_search_start = end.position();
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ ec = error::not_found;
+ return 0;
+ }
+
+ // Need more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ b.commit(s.read_some(b.prepare(bytes_available), ec));
+ if (ec)
+ return 0;
+ }
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_until(s, b, delim, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+namespace detail
+{
+ // Algorithm that finds a subsequence of equal values in a sequence. Returns
+ // (iterator,true) if a full match was found, in which case the iterator
+ // points to the beginning of the match. Returns (iterator,false) if a
+ // partial match was found at the end of the first sequence, in which case
+ // the iterator points to the beginning of the partial match. Returns
+ // (last1,false) if no full or partial match was found.
+ template <typename Iterator1, typename Iterator2>
+ std::pair<Iterator1, bool> partial_search(
+ Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
+ {
+ for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
+ {
+ Iterator1 test_iter1 = iter1;
+ Iterator2 test_iter2 = first2;
+ for (;; ++test_iter1, ++test_iter2)
+ {
+ if (test_iter2 == last2)
+ return std::make_pair(iter1, true);
+ if (test_iter1 == last1)
+ {
+ if (test_iter2 != first2)
+ return std::make_pair(iter1, false);
+ else
+ break;
+ }
+ if (*test_iter1 != *test_iter2)
+ break;
+ }
+ }
+ return std::make_pair(last1, false);
+ }
+} // namespace detail
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim,
+ asio::error_code& ec)
+{
+ std::size_t next_search_start = 0;
+ for (;;)
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin(buffers, next_search_start);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ std::pair<iterator, bool> result = asio::detail::partial_search(
+ begin, end, delim.begin(), delim.end());
+ if (result.first != end)
+ {
+ if (result.second)
+ {
+ // Full match. We're done.
+ ec = asio::error_code();
+ return result.first.position() + delim.length();
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start = result.first.position();
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ next_search_start = end.position();
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ ec = error::not_found;
+ return 0;
+ }
+
+ // Need more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ b.commit(s.read_some(b.prepare(bytes_available), ec));
+ if (ec)
+ return 0;
+ }
+}
+
+template <typename SyncReadStream, typename Allocator>
+inline std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = read_until(s, b, expr, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+ asio::error_code& ec)
+{
+ std::size_t next_search_start = 0;
+ for (;;)
+ {
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin(buffers, next_search_start);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ boost::match_results<iterator> match_results;
+ if (boost::regex_search(begin, end, match_results, expr,
+ boost::match_default | boost::match_partial))
+ {
+ if (match_results[0].matched)
+ {
+ // Full match. We're done.
+ ec = asio::error_code();
+ return match_results[0].second.position();
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start = match_results[0].first.position();
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ next_search_start = end.position();
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ ec = error::not_found;
+ return 0;
+ }
+
+ // Need more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ b.commit(s.read_some(b.prepare(bytes_available), ec));
+ if (ec)
+ return 0;
+ }
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ class read_until_delim_handler
+ {
+ public:
+ read_until_delim_handler(AsyncReadStream& stream,
+ asio::basic_streambuf<Allocator>& streambuf, char delim,
+ std::size_t next_search_start, ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ delim_(delim),
+ next_search_start_(next_search_start),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ // Check for errors.
+ if (ec)
+ {
+ std::size_t bytes = 0;
+ handler_(ec, bytes);
+ return;
+ }
+
+ // Commit received data to streambuf's get area.
+ streambuf_.commit(bytes_transferred);
+
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = streambuf_.data();
+ iterator begin(buffers, next_search_start_);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ iterator iter = std::find(begin, end, delim_);
+ if (iter != end)
+ {
+ // Found a match. We're done.
+ std::size_t bytes = iter.position() + 1;
+ handler_(ec, bytes);
+ return;
+ }
+
+ // No match. Check if buffer is full.
+ if (streambuf_.size() == streambuf_.max_size())
+ {
+ std::size_t bytes = 0;
+ asio::error_code ec(error::not_found);
+ handler_(ec, bytes);
+ return;
+ }
+
+ // Next search can start with the new data.
+ next_search_start_ = end.position();
+
+ // Start a new asynchronous read operation to obtain more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
+ stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ char delim_;
+ std::size_t next_search_start_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_until_delim_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_until_delim_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream, typename Allocator,
+ typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_until_delim_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim, ReadHandler handler)
+{
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin(buffers, 0);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ iterator iter = std::find(begin, end, delim);
+ if (iter != end)
+ {
+ // Found a match. We're done.
+ asio::error_code ec;
+ std::size_t bytes = iter.position() + 1;
+ s.io_service().post(detail::bind_handler(handler, ec, bytes));
+ return;
+ }
+
+ // No match. Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ asio::error_code ec(error::not_found);
+ s.io_service().post(detail::bind_handler(handler, ec, 0));
+ return;
+ }
+
+ // Start a new asynchronous read operation to obtain more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ s.async_read_some(b.prepare(bytes_available),
+ detail::read_until_delim_handler<AsyncReadStream, Allocator, ReadHandler>(
+ s, b, delim, end.position(), handler));
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ class read_until_delim_string_handler
+ {
+ public:
+ read_until_delim_string_handler(AsyncReadStream& stream,
+ asio::basic_streambuf<Allocator>& streambuf,
+ const std::string& delim, std::size_t next_search_start,
+ ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ delim_(delim),
+ next_search_start_(next_search_start),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ // Check for errors.
+ if (ec)
+ {
+ std::size_t bytes = 0;
+ handler_(ec, bytes);
+ return;
+ }
+
+ // Commit received data to streambuf's get area.
+ streambuf_.commit(bytes_transferred);
+
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = streambuf_.data();
+ iterator begin(buffers, next_search_start_);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ std::pair<iterator, bool> result = asio::detail::partial_search(
+ begin, end, delim_.begin(), delim_.end());
+ if (result.first != end)
+ {
+ if (result.second)
+ {
+ // Full match. We're done.
+ std::size_t bytes = result.first.position() + delim_.length();
+ handler_(ec, bytes);
+ return;
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start_ = result.first.position();
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ next_search_start_ = end.position();
+ }
+
+ // Check if buffer is full.
+ if (streambuf_.size() == streambuf_.max_size())
+ {
+ std::size_t bytes = 0;
+ asio::error_code ec(error::not_found);
+ handler_(ec, bytes);
+ return;
+ }
+
+ // Start a new asynchronous read operation to obtain more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
+ stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ std::string delim_;
+ std::size_t next_search_start_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_until_delim_string_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_until_delim_string_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream,
+ typename Allocator, typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_until_delim_string_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim,
+ ReadHandler handler)
+{
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin(buffers, 0);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ std::size_t next_search_start;
+ std::pair<iterator, bool> result = asio::detail::partial_search(
+ begin, end, delim.begin(), delim.end());
+ if (result.first != end)
+ {
+ if (result.second)
+ {
+ // Full match. We're done.
+ asio::error_code ec;
+ std::size_t bytes = result.first.position() + delim.length();
+ s.io_service().post(detail::bind_handler(handler, ec, bytes));
+ return;
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start = result.first.position();
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ next_search_start = end.position();
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ asio::error_code ec(error::not_found);
+ s.io_service().post(detail::bind_handler(handler, ec, 0));
+ return;
+ }
+
+ // Start a new asynchronous read operation to obtain more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ s.async_read_some(b.prepare(bytes_available),
+ detail::read_until_delim_string_handler<
+ AsyncReadStream, Allocator, ReadHandler>(
+ s, b, delim, next_search_start, handler));
+}
+
+namespace detail
+{
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ class read_until_expr_handler
+ {
+ public:
+ read_until_expr_handler(AsyncReadStream& stream,
+ asio::basic_streambuf<Allocator>& streambuf,
+ const boost::regex& expr, std::size_t next_search_start,
+ ReadHandler handler)
+ : stream_(stream),
+ streambuf_(streambuf),
+ expr_(expr),
+ next_search_start_(next_search_start),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ // Check for errors.
+ if (ec)
+ {
+ std::size_t bytes = 0;
+ handler_(ec, bytes);
+ return;
+ }
+
+ // Commit received data to streambuf's get area.
+ streambuf_.commit(bytes_transferred);
+
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = streambuf_.data();
+ iterator begin(buffers, next_search_start_);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ boost::match_results<iterator> match_results;
+ if (boost::regex_search(begin, end, match_results, expr_,
+ boost::match_default | boost::match_partial))
+ {
+ if (match_results[0].matched)
+ {
+ // Full match. We're done.
+ std::size_t bytes = match_results[0].second.position();
+ handler_(ec, bytes);
+ return;
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start_ = match_results[0].first.position();
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ next_search_start_ = end.position();
+ }
+
+ // Check if buffer is full.
+ if (streambuf_.size() == streambuf_.max_size())
+ {
+ std::size_t bytes = 0;
+ asio::error_code ec(error::not_found);
+ handler_(ec, bytes);
+ return;
+ }
+
+ // Start a new asynchronous read operation to obtain more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
+ stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
+ }
+
+ //private:
+ AsyncReadStream& stream_;
+ asio::basic_streambuf<Allocator>& streambuf_;
+ boost::regex expr_;
+ std::size_t next_search_start_;
+ ReadHandler handler_;
+ };
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ read_until_expr_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+ }
+
+ template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ read_until_expr_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncReadStream, typename Allocator,
+ typename ReadHandler>
+ inline void asio_handler_invoke(const Function& function,
+ read_until_expr_handler<AsyncReadStream,
+ Allocator, ReadHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+ ReadHandler handler)
+{
+ // Determine the range of the data to be searched.
+ typedef typename asio::basic_streambuf<
+ Allocator>::const_buffers_type const_buffers_type;
+ typedef asio::detail::const_buffers_iterator<
+ const_buffers_type> iterator;
+ const_buffers_type buffers = b.data();
+ iterator begin(buffers, 0);
+ iterator end(buffers, (std::numeric_limits<std::size_t>::max)());
+
+ // Look for a match.
+ std::size_t next_search_start;
+ boost::match_results<iterator> match_results;
+ if (boost::regex_search(begin, end, match_results, expr,
+ boost::match_default | boost::match_partial))
+ {
+ if (match_results[0].matched)
+ {
+ // Full match. We're done.
+ asio::error_code ec;
+ std::size_t bytes = match_results[0].second.position();
+ s.io_service().post(detail::bind_handler(handler, ec, bytes));
+ return;
+ }
+ else
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start = match_results[0].first.position();
+ }
+ }
+ else
+ {
+ // No match. Next search can start with the new data.
+ next_search_start = end.position();
+ }
+
+ // Check if buffer is full.
+ if (b.size() == b.max_size())
+ {
+ asio::error_code ec(error::not_found);
+ s.io_service().post(detail::bind_handler(handler, ec, 0));
+ return;
+ }
+
+ // Start a new asynchronous read operation to obtain more data.
+ std::size_t bytes_available =
+ std::min<std::size_t>(512, b.max_size() - b.size());
+ s.async_read_some(b.prepare(bytes_available),
+ detail::read_until_expr_handler<AsyncReadStream, Allocator, ReadHandler>(
+ s, b, expr, next_search_start, handler));
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_READ_UNTIL_IPP
diff --git a/src/libtorrent/asio/impl/write.ipp b/src/libtorrent/asio/impl/write.ipp
new file mode 100644
index 0000000..43bc297
--- /dev/null
+++ b/src/libtorrent/asio/impl/write.ipp
@@ -0,0 +1,279 @@
+//
+// write.ipp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_WRITE_IPP
+#define ASIO_WRITE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/consuming_buffers.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ asio::detail::consuming_buffers<
+ const_buffer, ConstBufferSequence> tmp(buffers);
+ std::size_t total_transferred = 0;
+ while (tmp.begin() != tmp.end())
+ {
+ std::size_t bytes_transferred = s.write_some(tmp, ec);
+ tmp.consume(bytes_transferred);
+ total_transferred += bytes_transferred;
+ if (completion_condition(ec, total_transferred))
+ return total_transferred;
+ }
+ ec = asio::error_code();
+ return total_transferred;
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, buffers, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec)
+{
+ std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec);
+ b.consume(bytes_transferred);
+ return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename Allocator>
+inline std::size_t write(SyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, b, transfer_all(), ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+template <typename SyncWriteStream, typename Allocator,
+ typename CompletionCondition>
+inline std::size_t write(SyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition)
+{
+ asio::error_code ec;
+ std::size_t bytes_transferred = write(s, b, completion_condition, ec);
+ asio::detail::throw_error(ec);
+ return bytes_transferred;
+}
+
+namespace detail
+{
+ template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ class write_handler
+ {
+ public:
+ typedef asio::detail::consuming_buffers<
+ const_buffer, ConstBufferSequence> buffers_type;
+
+ write_handler(AsyncWriteStream& stream, const buffers_type& buffers,
+ CompletionCondition completion_condition, WriteHandler handler)
+ : stream_(stream),
+ buffers_(buffers),
+ total_transferred_(0),
+ completion_condition_(completion_condition),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ total_transferred_ += bytes_transferred;
+ buffers_.consume(bytes_transferred);
+ if (completion_condition_(ec, total_transferred_)
+ || buffers_.begin() == buffers_.end())
+ {
+ handler_(ec, total_transferred_);
+ }
+ else
+ {
+ stream_.async_write_some(buffers_, *this);
+ }
+ }
+
+ //private:
+ AsyncWriteStream& stream_;
+ buffers_type buffers_;
+ std::size_t total_transferred_;
+ CompletionCondition completion_condition_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ write_handler<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+ }
+
+ template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ write_handler<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncWriteStream,
+ typename ConstBufferSequence, typename CompletionCondition,
+ typename WriteHandler>
+ inline void asio_handler_invoke(const Function& function,
+ write_handler<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, WriteHandler handler)
+{
+ asio::detail::consuming_buffers<
+ const_buffer, ConstBufferSequence> tmp(buffers);
+ s.async_write_some(tmp,
+ detail::write_handler<AsyncWriteStream, ConstBufferSequence,
+ CompletionCondition, WriteHandler>(
+ s, tmp, completion_condition, handler));
+}
+
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename WriteHandler>
+inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+ WriteHandler handler)
+{
+ async_write(s, buffers, transfer_all(), handler);
+}
+
+namespace detail
+{
+ template <typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ class write_streambuf_handler
+ {
+ public:
+ write_streambuf_handler(asio::basic_streambuf<Allocator>& streambuf,
+ WriteHandler handler)
+ : streambuf_(streambuf),
+ handler_(handler)
+ {
+ }
+
+ void operator()(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ streambuf_.consume(bytes_transferred);
+ handler_(ec, bytes_transferred);
+ }
+
+ //private:
+ asio::basic_streambuf<Allocator>& streambuf_;
+ WriteHandler handler_;
+ };
+
+ template <typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ inline void* asio_handler_allocate(std::size_t size,
+ write_streambuf_handler<AsyncWriteStream,
+ Allocator, WriteHandler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+ }
+
+ template <typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ write_streambuf_handler<AsyncWriteStream,
+ Allocator, WriteHandler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+ }
+
+ template <typename Function, typename AsyncWriteStream, typename Allocator,
+ typename WriteHandler>
+ inline void asio_handler_invoke(const Function& function,
+ write_streambuf_handler<AsyncWriteStream,
+ Allocator, WriteHandler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+ }
+} // namespace detail
+
+template <typename AsyncWriteStream, typename Allocator,
+ typename CompletionCondition, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, WriteHandler handler)
+{
+ async_write(s, b.data(), completion_condition,
+ detail::write_streambuf_handler<
+ AsyncWriteStream, Allocator, WriteHandler>(b, handler));
+}
+
+template <typename AsyncWriteStream, typename Allocator, typename WriteHandler>
+inline void async_write(AsyncWriteStream& s,
+ asio::basic_streambuf<Allocator>& b, WriteHandler handler)
+{
+ async_write(s, b, transfer_all(), handler);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_WRITE_IPP
diff --git a/src/libtorrent/asio/io_service.hpp b/src/libtorrent/asio/io_service.hpp
new file mode 100644
index 0000000..451b65a
--- /dev/null
+++ b/src/libtorrent/asio/io_service.hpp
@@ -0,0 +1,519 @@
+//
+// io_service.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IO_SERVICE_HPP
+#define ASIO_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <stdexcept>
+#include <typeinfo>
+#include <boost/config.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/detail/dev_poll_reactor_fwd.hpp"
+#include "asio/detail/epoll_reactor_fwd.hpp"
+#include "asio/detail/kqueue_reactor_fwd.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/select_reactor_fwd.hpp"
+#include "asio/detail/service_registry_fwd.hpp"
+#include "asio/detail/signal_init.hpp"
+#include "asio/detail/task_io_service_fwd.hpp"
+#include "asio/detail/win_iocp_io_service_fwd.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/detail/wrapped_handler.hpp"
+
+namespace asio {
+
+class io_service;
+template <typename Service> Service& use_service(io_service& ios);
+template <typename Service> void add_service(io_service& ios, Service* svc);
+template <typename Service> bool has_service(io_service& ios);
+
+/// Provides core I/O functionality.
+/**
+ * The io_service class provides the core I/O functionality for users of the
+ * asynchronous I/O objects, including:
+ *
+ * @li asio::ip::tcp::socket
+ * @li asio::ip::tcp::acceptor
+ * @li asio::ip::udp::socket
+ * @li asio::deadline_timer.
+ *
+ * The io_service class also includes facilities intended for developers of
+ * custom asynchronous services.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Safe, with the exception that calling reset()
+ * while there are unfinished run() calls results in undefined behaviour.
+ *
+ * @par Concepts:
+ * Dispatcher.
+ *
+ * @par Effect of exceptions thrown from handlers
+ *
+ * If an exception is thrown from a handler, the exception is allowed to
+ * propagate through the throwing thread's invocation of
+ * asio::io_service::run(), asio::io_service::run_one(),
+ * asio::io_service::poll() or asio::io_service::poll_one().
+ * No other threads that are calling any of these functions are affected. It is
+ * then the responsibility of the application to catch the exception.
+ *
+ * After the exception has been caught, the
+ * asio::io_service::run(), asio::io_service::run_one(),
+ * asio::io_service::poll() or asio::io_service::poll_one()
+ * call may be restarted @em without the need for an intervening call to
+ * asio::io_service::reset(). This allows the thread to rejoin the
+ * io_service's thread pool without impacting any other threads in the pool.
+ *
+ * For example:
+ *
+ * @code
+ * asio::io_service io_service;
+ * ...
+ * for (;;)
+ * {
+ * try
+ * {
+ * io_service.run();
+ * break; // run() exited normally
+ * }
+ * catch (my_exception& e)
+ * {
+ * // Deal with exception as appropriate.
+ * }
+ * }
+ * @endcode
+ */
+class io_service
+ : private noncopyable
+{
+private:
+ // The type of the platform-specific implementation.
+#if defined(ASIO_HAS_IOCP)
+ typedef detail::win_iocp_io_service impl_type;
+#elif defined(ASIO_HAS_EPOLL)
+ typedef detail::task_io_service<detail::epoll_reactor<false> > impl_type;
+#elif defined(ASIO_HAS_KQUEUE)
+ typedef detail::task_io_service<detail::kqueue_reactor<false> > impl_type;
+#elif defined(ASIO_HAS_DEV_POLL)
+ typedef detail::task_io_service<detail::dev_poll_reactor<false> > impl_type;
+#else
+ typedef detail::task_io_service<detail::select_reactor<false> > impl_type;
+#endif
+
+public:
+ class work;
+ friend class work;
+
+ class id;
+
+ class service;
+
+ class strand;
+
+ /// Constructor.
+ io_service();
+
+ /// Constructor.
+ /**
+ * Construct with a hint about the required level of concurrency.
+ *
+ * @param concurrency_hint A suggestion to the implementation on how many
+ * threads it should allow to run simultaneously.
+ */
+ explicit io_service(std::size_t concurrency_hint);
+
+ /// Destructor.
+ ~io_service();
+
+ /// Run the io_service's event processing loop.
+ /**
+ * The run() function blocks until all work has finished and there are no
+ * more handlers to be dispatched, or until the io_service has been stopped.
+ *
+ * Multiple threads may call the run() function to set up a pool of threads
+ * from which the io_service may execute handlers. All threads that are
+ * waiting in the pool are equivalent and the io_service may choose any one
+ * of them to invoke a handler.
+ *
+ * The run() function may be safely called again once it has completed only
+ * after a call to reset().
+ *
+ * @return The number of handlers that were executed.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t run();
+
+ /// Run the io_service's event processing loop.
+ /**
+ * The run() function blocks until all work has finished and there are no
+ * more handlers to be dispatched, or until the io_service has been stopped.
+ *
+ * Multiple threads may call the run() function to set up a pool of threads
+ * from which the io_service may execute handlers. All threads that are
+ * waiting in the pool are equivalent and the io_service may choose any one
+ * of them to invoke a handler.
+ *
+ * The run() function may be safely called again once it has completed only
+ * after a call to reset().
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of handlers that were executed.
+ */
+ std::size_t run(asio::error_code& ec);
+
+ /// Run the io_service's event processing loop to execute at most one handler.
+ /**
+ * The run_one() function blocks until one handler has been dispatched, or
+ * until the io_service has been stopped.
+ *
+ * @return The number of handlers that were executed.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t run_one();
+
+ /// Run the io_service's event processing loop to execute at most one handler.
+ /**
+ * The run_one() function blocks until one handler has been dispatched, or
+ * until the io_service has been stopped.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of handlers that were executed.
+ */
+ std::size_t run_one(asio::error_code& ec);
+
+ /// Run the io_service's event processing loop to execute ready handlers.
+ /**
+ * The poll() function runs handlers that are ready to run, without blocking,
+ * until the io_service has been stopped or there are no more ready handlers.
+ *
+ * @return The number of handlers that were executed.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t poll();
+
+ /// Run the io_service's event processing loop to execute ready handlers.
+ /**
+ * The poll() function runs handlers that are ready to run, without blocking,
+ * until the io_service has been stopped or there are no more ready handlers.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of handlers that were executed.
+ */
+ std::size_t poll(asio::error_code& ec);
+
+ /// Run the io_service's event processing loop to execute one ready handler.
+ /**
+ * The poll_one() function runs at most one handler that is ready to run,
+ * without blocking.
+ *
+ * @return The number of handlers that were executed.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t poll_one();
+
+ /// Run the io_service's event processing loop to execute one ready handler.
+ /**
+ * The poll_one() function runs at most one handler that is ready to run,
+ * without blocking.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of handlers that were executed.
+ */
+ std::size_t poll_one(asio::error_code& ec);
+
+ /// Stop the io_service's event processing loop.
+ /**
+ * This function does not block, but instead simply signals the io_service to
+ * stop. All invocations of its run() or run_one() member functions should
+ * return as soon as possible. Subsequent calls to run(), run_one(), poll()
+ * or poll_one() will return immediately until reset() is called.
+ */
+ void stop();
+
+ /// Reset the io_service in preparation for a subsequent run() invocation.
+ /**
+ * This function must be called prior to any second or later set of
+ * invocations of the run(), run_one(), poll() or poll_one() functions when a
+ * previous invocation of these functions returned due to the io_service
+ * being stopped or running out of work. This function allows the io_service
+ * to reset any internal state, such as a "stopped" flag.
+ *
+ * This function must not be called while there are any unfinished calls to
+ * the run(), run_one(), poll() or poll_one() functions.
+ */
+ void reset();
+
+ /// Request the io_service to invoke the given handler.
+ /**
+ * This function is used to ask the io_service to execute the given handler.
+ *
+ * The io_service guarantees that the handler will only be called in a thread
+ * in which the run(), run_one(), poll() or poll_one() member functions is
+ * currently being invoked. The handler may be executed inside this function
+ * if the guarantee can be met.
+ *
+ * @param handler The handler to be called. The io_service will make
+ * a copy of the handler object as required. The function signature of the
+ * handler must be: @code void handler(); @endcode
+ */
+ template <typename CompletionHandler>
+ void dispatch(CompletionHandler handler);
+
+ /// Request the io_service to invoke the given handler and return immediately.
+ /**
+ * This function is used to ask the io_service to execute the given handler,
+ * but without allowing the io_service to call the handler from inside this
+ * function.
+ *
+ * The io_service guarantees that the handler will only be called in a thread
+ * in which the run(), run_one(), poll() or poll_one() member functions is
+ * currently being invoked.
+ *
+ * @param handler The handler to be called. The io_service will make
+ * a copy of the handler object as required. The function signature of the
+ * handler must be: @code void handler(); @endcode
+ */
+ template <typename CompletionHandler>
+ void post(CompletionHandler handler);
+
+ /// Create a new handler that automatically dispatches the wrapped handler
+ /// on the io_service.
+ /**
+ * This function is used to create a new handler function object that, when
+ * invoked, will automatically pass the wrapped handler to the io_service's
+ * dispatch function.
+ *
+ * @param handler The handler to be wrapped. The io_service will make a copy
+ * of the handler object as required. The function signature of the handler
+ * must be: @code void handler(A1 a1, ... An an); @endcode
+ *
+ * @return A function object that, when invoked, passes the wrapped handler to
+ * the io_service's dispatch function. Given a function object with the
+ * signature:
+ * @code R f(A1 a1, ... An an); @endcode
+ * If this function object is passed to the wrap function like so:
+ * @code io_service.wrap(f); @endcode
+ * then the return value is a function object with the signature
+ * @code void g(A1 a1, ... An an); @endcode
+ * that, when invoked, executes code equivalent to:
+ * @code io_service.dispatch(boost::bind(f, a1, ... an)); @endcode
+ */
+ template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+ unspecified
+#else
+ detail::wrapped_handler<io_service&, Handler>
+#endif
+ wrap(Handler handler);
+
+ /// Obtain the service object corresponding to the given type.
+ /**
+ * This function is used to locate a service object that corresponds to
+ * the given service type. If there is no existing implementation of the
+ * service, then the io_service will create a new instance of the service.
+ *
+ * @param ios The io_service object that owns the service.
+ *
+ * @return The service interface implementing the specified service type.
+ * Ownership of the service interface is not transferred to the caller.
+ */
+ template <typename Service>
+ friend Service& use_service(io_service& ios);
+
+ /// Add a service object to the io_service.
+ /**
+ * This function is used to add a service to the io_service.
+ *
+ * @param ios The io_service object that owns the service.
+ *
+ * @param svc The service object. On success, ownership of the service object
+ * is transferred to the io_service. When the io_service object is destroyed,
+ * it will destroy the service object by performing:
+ * @code delete static_cast<io_service::service*>(svc) @endcode
+ *
+ * @throws asio::service_already_exists Thrown if a service of the
+ * given type is already present in the io_service.
+ *
+ * @throws asio::invalid_service_owner Thrown if the service's owning
+ * io_service is not the io_service object specified by the ios parameter.
+ */
+ template <typename Service>
+ friend void add_service(io_service& ios, Service* svc);
+
+ /// Determine if an io_service contains a specified service type.
+ /**
+ * This function is used to determine whether the io_service contains a
+ * service object corresponding to the given service type.
+ *
+ * @param ios The io_service object that owns the service.
+ *
+ * @return A boolean indicating whether the io_service contains the service.
+ */
+ template <typename Service>
+ friend bool has_service(io_service& ios);
+
+private:
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ detail::winsock_init<> init_;
+#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
+ || defined(__osf__)
+ detail::signal_init<> init_;
+#endif
+
+ // The service registry.
+ asio::detail::service_registry* service_registry_;
+
+ // The implementation.
+ impl_type& impl_;
+};
+
+/// Class to inform the io_service when it has work to do.
+/**
+ * The work class is used to inform the io_service when work starts and
+ * finishes. This ensures that the io_service's run() function will not exit
+ * while work is underway, and that it does exit when there is no unfinished
+ * work remaining.
+ *
+ * The work class is copy-constructible so that it may be used as a data member
+ * in a handler class. It is not assignable.
+ */
+class io_service::work
+{
+public:
+ /// Constructor notifies the io_service that work is starting.
+ /**
+ * The constructor is used to inform the io_service that some work has begun.
+ * This ensures that the io_service's run() function will not exit while the
+ * work is underway.
+ */
+ explicit work(asio::io_service& io_service);
+
+ /// Copy constructor notifies the io_service that work is starting.
+ /**
+ * The constructor is used to inform the io_service that some work has begun.
+ * This ensures that the io_service's run() function will not exit while the
+ * work is underway.
+ */
+ work(const work& other);
+
+ /// Destructor notifies the io_service that the work is complete.
+ /**
+ * The destructor is used to inform the io_service that some work has
+ * finished. Once the count of unfinished work reaches zero, the io_service's
+ * run() function is permitted to exit.
+ */
+ ~work();
+
+ /// (Deprecated: use get_io_service().) Get the io_service associated with the
+ /// work.
+ asio::io_service& io_service();
+
+ /// Get the io_service associated with the work.
+ asio::io_service& get_io_service();
+
+private:
+ // Prevent assignment.
+ void operator=(const work& other);
+
+ // The io_service.
+ asio::io_service& io_service_;
+};
+
+/// Class used to uniquely identify a service.
+class io_service::id
+ : private noncopyable
+{
+public:
+ /// Constructor.
+ id() {}
+};
+
+/// Base class for all io_service services.
+class io_service::service
+ : private noncopyable
+{
+public:
+ /// (Deprecated: use get_io_service().) Get the io_service object that owns
+ /// the service.
+ asio::io_service& io_service();
+
+ /// Get the io_service object that owns the service.
+ asio::io_service& get_io_service();
+
+protected:
+ /// Constructor.
+ /**
+ * @param owner The io_service object that owns the service.
+ */
+ service(asio::io_service& owner);
+
+ /// Destructor.
+ virtual ~service();
+
+private:
+ /// Destroy all user-defined handler objects owned by the service.
+ virtual void shutdown_service() = 0;
+
+ friend class asio::detail::service_registry;
+ asio::io_service& owner_;
+ const std::type_info* type_info_;
+ const asio::io_service::id* id_;
+ service* next_;
+};
+
+/// Exception thrown when trying to add a duplicate service to an io_service.
+class service_already_exists
+ : public std::logic_error
+{
+public:
+ service_already_exists()
+ : std::logic_error("Service already exists.")
+ {
+ }
+};
+
+/// Exception thrown when trying to add a service object to an io_service where
+/// the service has a different owner.
+class invalid_service_owner
+ : public std::logic_error
+{
+public:
+ invalid_service_owner()
+ : std::logic_error("Invalid service owner.")
+ {
+ }
+};
+
+} // namespace asio
+
+#include "asio/impl/io_service.ipp"
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IO_SERVICE_HPP
diff --git a/src/libtorrent/asio/ip/address.hpp b/src/libtorrent/asio/ip/address.hpp
new file mode 100644
index 0000000..a96fcc5
--- /dev/null
+++ b/src/libtorrent/asio/ip/address.hpp
@@ -0,0 +1,277 @@
+//
+// address.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_ADDRESS_HPP
+#define ASIO_IP_ADDRESS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <iosfwd>
+#include <string>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v6.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Implements version-independent IP addresses.
+/**
+ * The asio::ip::address class provides the ability to use either IP
+ * version 4 or version 6 addresses.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+class address
+{
+public:
+ /// Default constructor.
+ address()
+ : type_(ipv4),
+ ipv4_address_(),
+ ipv6_address_()
+ {
+ }
+
+ /// Construct an address from an IPv4 address.
+ address(const asio::ip::address_v4& ipv4_address)
+ : type_(ipv4),
+ ipv4_address_(ipv4_address),
+ ipv6_address_()
+ {
+ }
+
+ /// Construct an address from an IPv6 address.
+ address(const asio::ip::address_v6& ipv6_address)
+ : type_(ipv6),
+ ipv4_address_(),
+ ipv6_address_(ipv6_address)
+ {
+ }
+
+ /// Copy constructor.
+ address(const address& other)
+ : type_(other.type_),
+ ipv4_address_(other.ipv4_address_),
+ ipv6_address_(other.ipv6_address_)
+ {
+ }
+
+ /// Assign from another address.
+ address& operator=(const address& other)
+ {
+ type_ = other.type_;
+ ipv4_address_ = other.ipv4_address_;
+ ipv6_address_ = other.ipv6_address_;
+ return *this;
+ }
+
+ /// Assign from an IPv4 address.
+ address& operator=(const asio::ip::address_v4& ipv4_address)
+ {
+ type_ = ipv4;
+ ipv4_address_ = ipv4_address;
+ ipv6_address_ = asio::ip::address_v6();
+ return *this;
+ }
+
+ /// Assign from an IPv6 address.
+ address& operator=(const asio::ip::address_v6& ipv6_address)
+ {
+ type_ = ipv6;
+ ipv4_address_ = asio::ip::address_v4();
+ ipv6_address_ = ipv6_address;
+ return *this;
+ }
+
+ /// Get whether the address is an IP version 4 address.
+ bool is_v4() const
+ {
+ return type_ == ipv4;
+ }
+
+ /// Get whether the address is an IP version 6 address.
+ bool is_v6() const
+ {
+ return type_ == ipv6;
+ }
+
+ /// Get the address as an IP version 4 address.
+ asio::ip::address_v4 to_v4() const
+ {
+ if (type_ != ipv4)
+ {
+ asio::system_error e(
+ asio::error::address_family_not_supported);
+ boost::throw_exception(e);
+ }
+ return ipv4_address_;
+ }
+
+ /// Get the address as an IP version 6 address.
+ asio::ip::address_v6 to_v6() const
+ {
+ if (type_ != ipv6)
+ {
+ asio::system_error e(
+ asio::error::address_family_not_supported);
+ boost::throw_exception(e);
+ }
+ return ipv6_address_;
+ }
+
+ /// Get the address as a string in dotted decimal format.
+ std::string to_string() const
+ {
+ if (type_ == ipv6)
+ return ipv6_address_.to_string();
+ return ipv4_address_.to_string();
+ }
+
+ /// Get the address as a string in dotted decimal format.
+ std::string to_string(asio::error_code& ec) const
+ {
+ if (type_ == ipv6)
+ return ipv6_address_.to_string(ec);
+ return ipv4_address_.to_string(ec);
+ }
+
+ /// Create an address from an IPv4 address string in dotted decimal form,
+ /// or from an IPv6 address in hexadecimal notation.
+ static address from_string(const char* str)
+ {
+ asio::error_code ec;
+ address addr = from_string(str, ec);
+ asio::detail::throw_error(ec);
+ return addr;
+ }
+
+ /// Create an address from an IPv4 address string in dotted decimal form,
+ /// or from an IPv6 address in hexadecimal notation.
+ static address from_string(const char* str, asio::error_code& ec)
+ {
+ asio::ip::address_v6 ipv6_address =
+ asio::ip::address_v6::from_string(str, ec);
+ if (!ec)
+ {
+ address tmp;
+ tmp.type_ = ipv6;
+ tmp.ipv6_address_ = ipv6_address;
+ return tmp;
+ }
+
+ asio::ip::address_v4 ipv4_address =
+ asio::ip::address_v4::from_string(str, ec);
+ if (!ec)
+ {
+ address tmp;
+ tmp.type_ = ipv4;
+ tmp.ipv4_address_ = ipv4_address;
+ return tmp;
+ }
+
+ return address();
+ }
+
+ /// Create an address from an IPv4 address string in dotted decimal form,
+ /// or from an IPv6 address in hexadecimal notation.
+ static address from_string(const std::string& str)
+ {
+ return from_string(str.c_str());
+ }
+
+ /// Create an address from an IPv4 address string in dotted decimal form,
+ /// or from an IPv6 address in hexadecimal notation.
+ static address from_string(const std::string& str,
+ asio::error_code& ec)
+ {
+ return from_string(str.c_str(), ec);
+ }
+
+ /// Compare two addresses for equality.
+ friend bool operator==(const address& a1, const address& a2)
+ {
+ if (a1.type_ != a2.type_)
+ return false;
+ if (a1.type_ == ipv6)
+ return a1.ipv6_address_ == a2.ipv6_address_;
+ return a1.ipv4_address_ == a2.ipv4_address_;
+ }
+
+ /// Compare two addresses for inequality.
+ friend bool operator!=(const address& a1, const address& a2)
+ {
+ if (a1.type_ != a2.type_)
+ return true;
+ if (a1.type_ == ipv6)
+ return a1.ipv6_address_ != a2.ipv6_address_;
+ return a1.ipv4_address_ != a2.ipv4_address_;
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator<(const address& a1, const address& a2)
+ {
+ if (a1.type_ < a2.type_)
+ return true;
+ if (a1.type_ > a2.type_)
+ return false;
+ if (a1.type_ == ipv6)
+ return a1.ipv6_address_ < a2.ipv6_address_;
+ return a1.ipv4_address_ < a2.ipv4_address_;
+ }
+
+private:
+ // The type of the address.
+ enum { ipv4, ipv6 } type_;
+
+ // The underlying IPv4 address.
+ asio::ip::address_v4 ipv4_address_;
+
+ // The underlying IPv6 address.
+ asio::ip::address_v6 ipv6_address_;
+};
+
+/// Output an address as a string.
+/**
+ * Used to output a human-readable string for a specified address.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param addr The address to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::address
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os, const address& addr)
+{
+ os << addr.to_string();
+ return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_HPP
diff --git a/src/libtorrent/asio/ip/address_v4.hpp b/src/libtorrent/asio/ip/address_v4.hpp
new file mode 100644
index 0000000..cda2a11
--- /dev/null
+++ b/src/libtorrent/asio/ip/address_v4.hpp
@@ -0,0 +1,288 @@
+//
+// address_v4.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_ADDRESS_V4_HPP
+#define ASIO_IP_ADDRESS_V4_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <string>
+#include <boost/array.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Implements IP version 4 style addresses.
+/**
+ * The asio::ip::address_v4 class provides the ability to use and
+ * manipulate IP version 4 addresses.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+class address_v4
+{
+public:
+ /// The type used to represent an address as an array of bytes.
+ typedef boost::array<unsigned char, 4> bytes_type;
+
+ /// Default constructor.
+ address_v4()
+ {
+ addr_.s_addr = 0;
+ }
+
+ /// Construct an address from raw bytes.
+ explicit address_v4(const bytes_type& bytes)
+ {
+ using namespace std; // For memcpy.
+ memcpy(&addr_.s_addr, bytes.elems, 4);
+ }
+
+ /// Construct an address from a unsigned long in host byte order.
+ explicit address_v4(unsigned long addr)
+ {
+ addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr);
+ }
+
+ /// Copy constructor.
+ address_v4(const address_v4& other)
+ : addr_(other.addr_)
+ {
+ }
+
+ /// Assign from another address.
+ address_v4& operator=(const address_v4& other)
+ {
+ addr_ = other.addr_;
+ return *this;
+ }
+
+ /// Get the address in bytes.
+ bytes_type to_bytes() const
+ {
+ using namespace std; // For memcpy.
+ bytes_type bytes;
+ memcpy(bytes.elems, &addr_.s_addr, 4);
+ return bytes;
+ }
+
+ /// Get the address as an unsigned long in host byte order
+ unsigned long to_ulong() const
+ {
+ return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);
+ }
+
+ /// Get the address as a string in dotted decimal format.
+ std::string to_string() const
+ {
+ asio::error_code ec;
+ std::string addr = to_string(ec);
+ asio::detail::throw_error(ec);
+ return addr;
+ }
+
+ /// Get the address as a string in dotted decimal format.
+ std::string to_string(asio::error_code& ec) const
+ {
+ char addr_str[asio::detail::max_addr_v4_str_len];
+ const char* addr =
+ asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str,
+ asio::detail::max_addr_v4_str_len, 0, ec);
+ if (addr == 0)
+ return std::string();
+ return addr;
+ }
+
+ /// Create an address from an IP address string in dotted decimal form.
+ static address_v4 from_string(const char* str)
+ {
+ asio::error_code ec;
+ address_v4 addr = from_string(str, ec);
+ asio::detail::throw_error(ec);
+ return addr;
+ }
+
+ /// Create an address from an IP address string in dotted decimal form.
+ static address_v4 from_string(const char* str, asio::error_code& ec)
+ {
+ address_v4 tmp;
+ if (asio::detail::socket_ops::inet_pton(
+ AF_INET, str, &tmp.addr_, 0, ec) <= 0)
+ return address_v4();
+ return tmp;
+ }
+
+ /// Create an address from an IP address string in dotted decimal form.
+ static address_v4 from_string(const std::string& str)
+ {
+ return from_string(str.c_str());
+ }
+
+ /// Create an address from an IP address string in dotted decimal form.
+ static address_v4 from_string(const std::string& str,
+ asio::error_code& ec)
+ {
+ return from_string(str.c_str(), ec);
+ }
+
+ /// Determine whether the address is a class A address.
+ bool is_class_a() const
+ {
+ return IN_CLASSA(to_ulong());
+ }
+
+ /// Determine whether the address is a class B address.
+ bool is_class_b() const
+ {
+ return IN_CLASSB(to_ulong());
+ }
+
+ /// Determine whether the address is a class C address.
+ bool is_class_c() const
+ {
+ return IN_CLASSC(to_ulong());
+ }
+
+ /// Determine whether the address is a multicast address.
+ bool is_multicast() const
+ {
+ return IN_MULTICAST(to_ulong());
+ }
+
+ /// Compare two addresses for equality.
+ friend bool operator==(const address_v4& a1, const address_v4& a2)
+ {
+ return a1.addr_.s_addr == a2.addr_.s_addr;
+ }
+
+ /// Compare two addresses for inequality.
+ friend bool operator!=(const address_v4& a1, const address_v4& a2)
+ {
+ return a1.addr_.s_addr != a2.addr_.s_addr;
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator<(const address_v4& a1, const address_v4& a2)
+ {
+ return a1.to_ulong() < a2.to_ulong();
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator>(const address_v4& a1, const address_v4& a2)
+ {
+ return a1.to_ulong() > a2.to_ulong();
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator<=(const address_v4& a1, const address_v4& a2)
+ {
+ return a1.to_ulong() <= a2.to_ulong();
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator>=(const address_v4& a1, const address_v4& a2)
+ {
+ return a1.to_ulong() >= a2.to_ulong();
+ }
+
+ /// Obtain an address object that represents any address.
+ static address_v4 any()
+ {
+ return address_v4(static_cast<unsigned long>(INADDR_ANY));
+ }
+
+ /// Obtain an address object that represents the loopback address.
+ static address_v4 loopback()
+ {
+ return address_v4(static_cast<unsigned long>(INADDR_LOOPBACK));
+ }
+
+ /// Obtain an address object that represents the broadcast address.
+ static address_v4 broadcast()
+ {
+ return address_v4(static_cast<unsigned long>(INADDR_BROADCAST));
+ }
+
+ /// Obtain an address object that represents the broadcast address that
+ /// corresponds to the specified address and netmask.
+ static address_v4 broadcast(const address_v4& addr, const address_v4& mask)
+ {
+ return address_v4(addr.to_ulong() | ~mask.to_ulong());
+ }
+
+ /// Obtain the netmask that corresponds to the address, based on its address
+ /// class.
+ static address_v4 netmask(const address_v4& addr)
+ {
+ if (addr.is_class_a())
+ return address_v4(0xFF000000);
+ if (addr.is_class_b())
+ return address_v4(0xFFFF0000);
+ if (addr.is_class_c())
+ return address_v4(0xFFFFFF00);
+ return address_v4(0xFFFFFFFF);
+ }
+
+private:
+ // The underlying IPv4 address.
+ asio::detail::in4_addr_type addr_;
+};
+
+/// Output an address as a string.
+/**
+ * Used to output a human-readable string for a specified address.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param addr The address to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::address_v4
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os, const address_v4& addr)
+{
+ asio::error_code ec;
+ std::string s = addr.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::ios::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::ios_base::failbit);
+ }
+ else
+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+ os << os.widen(*i);
+ return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_V4_HPP
diff --git a/src/libtorrent/asio/ip/address_v6.hpp b/src/libtorrent/asio/ip/address_v6.hpp
new file mode 100644
index 0000000..c317fe4
--- /dev/null
+++ b/src/libtorrent/asio/ip/address_v6.hpp
@@ -0,0 +1,406 @@
+//
+// address_v6.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_ADDRESS_V6_HPP
+#define ASIO_IP_ADDRESS_V6_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstring>
+#include <string>
+#include <stdexcept>
+#include <typeinfo>
+#include <boost/array.hpp>
+#include <boost/throw_exception.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/ip/address_v4.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Implements IP version 6 style addresses.
+/**
+ * The asio::ip::address_v6 class provides the ability to use and
+ * manipulate IP version 6 addresses.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+class address_v6
+{
+public:
+ /// The type used to represent an address as an array of bytes.
+ typedef boost::array<unsigned char, 16> bytes_type;
+
+ /// Default constructor.
+ address_v6()
+ : scope_id_(0)
+ {
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+ addr_ = tmp_addr;
+ }
+
+ /// Construct an address from raw bytes and scope ID.
+ explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0)
+ : scope_id_(scope_id)
+ {
+ using namespace std; // For memcpy.
+ memcpy(addr_.s6_addr, bytes.elems, 16);
+ }
+
+ /// Copy constructor.
+ address_v6(const address_v6& other)
+ : addr_(other.addr_),
+ scope_id_(other.scope_id_)
+ {
+ }
+
+ /// Assign from another address.
+ address_v6& operator=(const address_v6& other)
+ {
+ addr_ = other.addr_;
+ scope_id_ = other.scope_id_;
+ return *this;
+ }
+
+ /// The scope ID of the address.
+ /**
+ * Returns the scope ID associated with the IPv6 address.
+ */
+ unsigned long scope_id() const
+ {
+ return scope_id_;
+ }
+
+ /// The scope ID of the address.
+ /**
+ * Modifies the scope ID associated with the IPv6 address.
+ */
+ void scope_id(unsigned long id)
+ {
+ scope_id_ = id;
+ }
+
+ /// Get the address in bytes.
+ bytes_type to_bytes() const
+ {
+ using namespace std; // For memcpy.
+ bytes_type bytes;
+ memcpy(bytes.elems, addr_.s6_addr, 16);
+ return bytes;
+ }
+
+ /// Get the address as a string.
+ std::string to_string() const
+ {
+ asio::error_code ec;
+ std::string addr = to_string(ec);
+ asio::detail::throw_error(ec);
+ return addr;
+ }
+
+ /// Get the address as a string.
+ std::string to_string(asio::error_code& ec) const
+ {
+ char addr_str[asio::detail::max_addr_v6_str_len];
+ const char* addr =
+ asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str,
+ asio::detail::max_addr_v6_str_len, scope_id_, ec);
+ if (addr == 0)
+ return std::string();
+ return addr;
+ }
+
+ /// Create an address from an IP address string.
+ static address_v6 from_string(const char* str)
+ {
+ asio::error_code ec;
+ address_v6 addr = from_string(str, ec);
+ asio::detail::throw_error(ec);
+ return addr;
+ }
+
+ /// Create an address from an IP address string.
+ static address_v6 from_string(const char* str, asio::error_code& ec)
+ {
+ address_v6 tmp;
+ if (asio::detail::socket_ops::inet_pton(
+ AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0)
+ return address_v6();
+ return tmp;
+ }
+
+ /// Create an address from an IP address string.
+ static address_v6 from_string(const std::string& str)
+ {
+ return from_string(str.c_str());
+ }
+
+ /// Create an address from an IP address string.
+ static address_v6 from_string(const std::string& str,
+ asio::error_code& ec)
+ {
+ return from_string(str.c_str(), ec);
+ }
+
+ /// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address.
+ address_v4 to_v4() const
+ {
+ if (!is_v4_mapped() && !is_v4_compatible())
+ throw std::bad_cast();
+ address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
+ addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
+ return address_v4(v4_bytes);
+ }
+
+ /// Determine whether the address is a loopback address.
+ bool is_loopback() const
+ {
+#if defined(__BORLANDC__)
+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+ && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+ && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+ && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));
+#else
+ using namespace asio::detail;
+ return IN6_IS_ADDR_LOOPBACK(&addr_) != 0;
+#endif
+ }
+
+ /// Determine whether the address is unspecified.
+ bool is_unspecified() const
+ {
+#if defined(__BORLANDC__)
+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)
+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)
+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)
+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)
+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)
+ && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)
+ && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)
+ && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));
+#else
+ using namespace asio::detail;
+ return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0;
+#endif
+ }
+
+ /// Determine whether the address is link local.
+ bool is_link_local() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0;
+ }
+
+ /// Determine whether the address is site local.
+ bool is_site_local() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_SITELOCAL(&addr_) != 0;
+ }
+
+ /// Determine whether the address is a mapped IPv4 address.
+ bool is_v4_mapped() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_V4MAPPED(&addr_) != 0;
+ }
+
+ /// Determine whether the address is an IPv4-compatible address.
+ bool is_v4_compatible() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_V4COMPAT(&addr_) != 0;
+ }
+
+ /// Determine whether the address is a multicast address.
+ bool is_multicast() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MULTICAST(&addr_) != 0;
+ }
+
+ /// Determine whether the address is a global multicast address.
+ bool is_multicast_global() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0;
+ }
+
+ /// Determine whether the address is a link-local multicast address.
+ bool is_multicast_link_local() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0;
+ }
+
+ /// Determine whether the address is a node-local multicast address.
+ bool is_multicast_node_local() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0;
+ }
+
+ /// Determine whether the address is a org-local multicast address.
+ bool is_multicast_org_local() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0;
+ }
+
+ /// Determine whether the address is a site-local multicast address.
+ bool is_multicast_site_local() const
+ {
+ using namespace asio::detail;
+ return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0;
+ }
+
+ /// Compare two addresses for equality.
+ friend bool operator==(const address_v6& a1, const address_v6& a2)
+ {
+ using namespace std; // For memcmp.
+ return memcmp(&a1.addr_, &a2.addr_,
+ sizeof(asio::detail::in6_addr_type)) == 0
+ && a1.scope_id_ == a2.scope_id_;
+ }
+
+ /// Compare two addresses for inequality.
+ friend bool operator!=(const address_v6& a1, const address_v6& a2)
+ {
+ using namespace std; // For memcmp.
+ return memcmp(&a1.addr_, &a2.addr_,
+ sizeof(asio::detail::in6_addr_type)) != 0
+ || a1.scope_id_ != a2.scope_id_;
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator<(const address_v6& a1, const address_v6& a2)
+ {
+ using namespace std; // For memcmp.
+ int memcmp_result = memcmp(&a1.addr_, &a2.addr_,
+ sizeof(asio::detail::in6_addr_type));
+ if (memcmp_result < 0)
+ return true;
+ if (memcmp_result > 0)
+ return false;
+ return a1.scope_id_ < a2.scope_id_;
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator>(const address_v6& a1, const address_v6& a2)
+ {
+ return a2 < a1;
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator<=(const address_v6& a1, const address_v6& a2)
+ {
+ return !(a2 < a1);
+ }
+
+ /// Compare addresses for ordering.
+ friend bool operator>=(const address_v6& a1, const address_v6& a2)
+ {
+ return !(a1 < a2);
+ }
+
+ /// Obtain an address object that represents any address.
+ static address_v6 any()
+ {
+ return address_v6();
+ }
+
+ /// Obtain an address object that represents the loopback address.
+ static address_v6 loopback()
+ {
+ address_v6 tmp;
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT;
+ tmp.addr_ = tmp_addr;
+ return tmp;
+ }
+
+ /// Create an IPv4-mapped IPv6 address.
+ static address_v6 v4_mapped(const address_v4& addr)
+ {
+ address_v4::bytes_type v4_bytes = addr.to_bytes();
+ bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
+ v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+ return address_v6(v6_bytes);
+ }
+
+ /// Create an IPv4-compatible IPv6 address.
+ static address_v6 v4_compatible(const address_v4& addr)
+ {
+ address_v4::bytes_type v4_bytes = addr.to_bytes();
+ bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };
+ return address_v6(v6_bytes);
+ }
+
+private:
+ // The underlying IPv6 address.
+ asio::detail::in6_addr_type addr_;
+
+ // The scope ID associated with the address.
+ unsigned long scope_id_;
+};
+
+/// Output an address as a string.
+/**
+ * Used to output a human-readable string for a specified address.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param addr The address to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::address_v6
+ */
+template <typename Elem, typename Traits>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os, const address_v6& addr)
+{
+ asio::error_code ec;
+ std::string s = addr.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::ios::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::ios_base::failbit);
+ }
+ else
+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)
+ os << os.widen(*i);
+ return os;
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_ADDRESS_V6_HPP
diff --git a/src/libtorrent/asio/ip/basic_endpoint.hpp b/src/libtorrent/asio/ip/basic_endpoint.hpp
new file mode 100644
index 0000000..c832285
--- /dev/null
+++ b/src/libtorrent/asio/ip/basic_endpoint.hpp
@@ -0,0 +1,368 @@
+//
+// basic_endpoint.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_BASIC_ENDPOINT_HPP
+#define ASIO_IP_BASIC_ENDPOINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/throw_exception.hpp>
+#include <boost/detail/workaround.hpp>
+#include <cstring>
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+# include <ostream>
+#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Describes an endpoint for a version-independent IP socket.
+/**
+ * The asio::ip::basic_endpoint class template describes an endpoint that
+ * may be associated with a particular socket.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * Endpoint.
+ */
+template <typename InternetProtocol>
+class basic_endpoint
+{
+public:
+ /// The protocol type associated with the endpoint.
+ typedef InternetProtocol protocol_type;
+
+ /// The type of the endpoint structure. This type is dependent on the
+ /// underlying implementation of the socket layer.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined data_type;
+#else
+ typedef asio::detail::socket_addr_type data_type;
+#endif
+
+ /// Default constructor.
+ basic_endpoint()
+ : data_()
+ {
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port = 0;
+ data_.v4.sin_addr.s_addr = INADDR_ANY;
+ }
+
+ /// Construct an endpoint using a port number, specified in the host's byte
+ /// order. The IP address will be the any address (i.e. INADDR_ANY or
+ /// in6addr_any). This constructor would typically be used for accepting new
+ /// connections.
+ /**
+ * @par Examples
+ * To initialise an IPv4 TCP endpoint for port 1234, use:
+ * @code
+ * asio::ip::tcp::endpoint ep(asio::ip::tcp::v4(), 1234);
+ * @endcode
+ *
+ * To specify an IPv6 UDP endpoint for port 9876, use:
+ * @code
+ * asio::ip::udp::endpoint ep(asio::ip::udp::v6(), 9876);
+ * @endcode
+ */
+ basic_endpoint(const InternetProtocol& protocol, unsigned short port_num)
+ : data_()
+ {
+ using namespace std; // For memcpy.
+ if (protocol.family() == PF_INET)
+ {
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v4.sin_addr.s_addr = INADDR_ANY;
+ }
+ else
+ {
+ data_.v6.sin6_family = AF_INET6;
+ data_.v6.sin6_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v6.sin6_flowinfo = 0;
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+ data_.v6.sin6_addr = tmp_addr;
+ data_.v6.sin6_scope_id = 0;
+ }
+ }
+
+ /// Construct an endpoint using a port number and an IP address. This
+ /// constructor may be used for accepting connections on a specific interface
+ /// or for making a connection to a remote endpoint.
+ basic_endpoint(const asio::ip::address& addr, unsigned short port_num)
+ : data_()
+ {
+ using namespace std; // For memcpy.
+ if (addr.is_v4())
+ {
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v4.sin_addr.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ addr.to_v4().to_ulong());
+ }
+ else
+ {
+ data_.v6.sin6_family = AF_INET6;
+ data_.v6.sin6_port =
+ asio::detail::socket_ops::host_to_network_short(port_num);
+ data_.v6.sin6_flowinfo = 0;
+ asio::ip::address_v6 v6_addr = addr.to_v6();
+ asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
+ memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16);
+ data_.v6.sin6_scope_id = v6_addr.scope_id();
+ }
+ }
+
+ /// Copy constructor.
+ basic_endpoint(const basic_endpoint& other)
+ : data_(other.data_)
+ {
+ }
+
+ /// Assign from another endpoint.
+ basic_endpoint& operator=(const basic_endpoint& other)
+ {
+ data_ = other.data_;
+ return *this;
+ }
+
+ /// The protocol associated with the endpoint.
+ protocol_type protocol() const
+ {
+ if (is_v4())
+ return InternetProtocol::v4();
+ return InternetProtocol::v6();
+ }
+
+ /// Get the underlying endpoint in the native type.
+ data_type* data()
+ {
+ return &data_.base;
+ }
+
+ /// Get the underlying endpoint in the native type.
+ const data_type* data() const
+ {
+ return &data_.base;
+ }
+
+ /// Get the underlying size of the endpoint in the native type.
+ std::size_t size() const
+ {
+ if (is_v4())
+ return sizeof(asio::detail::sockaddr_in4_type);
+ else
+ return sizeof(asio::detail::sockaddr_in6_type);
+ }
+
+ /// Set the underlying size of the endpoint in the native type.
+ void resize(std::size_t size)
+ {
+ if (size > sizeof(asio::detail::sockaddr_storage_type))
+ {
+ asio::system_error e(asio::error::invalid_argument);
+ boost::throw_exception(e);
+ }
+ }
+
+ /// Get the capacity of the endpoint in the native type.
+ std::size_t capacity() const
+ {
+ return sizeof(asio::detail::sockaddr_storage_type);
+ }
+
+ /// Get the port associated with the endpoint. The port number is always in
+ /// the host's byte order.
+ unsigned short port() const
+ {
+ if (is_v4())
+ {
+ return asio::detail::socket_ops::network_to_host_short(
+ data_.v4.sin_port);
+ }
+ else
+ {
+ return asio::detail::socket_ops::network_to_host_short(
+ data_.v6.sin6_port);
+ }
+ }
+
+ /// Set the port associated with the endpoint. The port number is always in
+ /// the host's byte order.
+ void port(unsigned short port_num)
+ {
+ if (is_v4())
+ {
+ data_.v4.sin_port
+ = asio::detail::socket_ops::host_to_network_short(port_num);
+ }
+ else
+ {
+ data_.v6.sin6_port
+ = asio::detail::socket_ops::host_to_network_short(port_num);
+ }
+ }
+
+ /// Get the IP address associated with the endpoint.
+ asio::ip::address address() const
+ {
+ using namespace std; // For memcpy.
+ if (is_v4())
+ {
+ return asio::ip::address_v4(
+ asio::detail::socket_ops::network_to_host_long(
+ data_.v4.sin_addr.s_addr));
+ }
+ else
+ {
+ asio::ip::address_v6::bytes_type bytes;
+ memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
+ return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
+ }
+ }
+
+ /// Set the IP address associated with the endpoint.
+ void address(const asio::ip::address& addr)
+ {
+ basic_endpoint<InternetProtocol> tmp_endpoint(addr, port());
+ data_ = tmp_endpoint.data_;
+ }
+
+ /// Compare two endpoints for equality.
+ friend bool operator==(const basic_endpoint<InternetProtocol>& e1,
+ const basic_endpoint<InternetProtocol>& e2)
+ {
+ return e1.address() == e2.address() && e1.port() == e2.port();
+ }
+
+ /// Compare two endpoints for inequality.
+ friend bool operator!=(const basic_endpoint<InternetProtocol>& e1,
+ const basic_endpoint<InternetProtocol>& e2)
+ {
+ return e1.address() != e2.address() || e1.port() != e2.port();
+ }
+
+ /// Compare endpoints for ordering.
+ friend bool operator<(const basic_endpoint<InternetProtocol>& e1,
+ const basic_endpoint<InternetProtocol>& e2)
+ {
+ if (e1.address() < e2.address())
+ return true;
+ if (e1.address() != e2.address())
+ return false;
+ return e1.port() < e2.port();
+ }
+
+private:
+ // Helper function to determine whether the endpoint is IPv4.
+ bool is_v4() const
+ {
+ return data_.base.sa_family == AF_INET;
+ }
+
+ // The underlying IP socket address.
+ union data_union
+ {
+ asio::detail::socket_addr_type base;
+ asio::detail::sockaddr_storage_type storage;
+ asio::detail::sockaddr_in4_type v4;
+ asio::detail::sockaddr_in6_type v6;
+ } data_;
+};
+
+/// Output an endpoint as a string.
+/**
+ * Used to output a human-readable string for a specified endpoint.
+ *
+ * @param os The output stream to which the string will be written.
+ *
+ * @param endpoint The endpoint to be written.
+ *
+ * @return The output stream.
+ *
+ * @relates asio::ip::basic_endpoint
+ */
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+template <typename InternetProtocol>
+std::ostream& operator<<(std::ostream& os,
+ const basic_endpoint<InternetProtocol>& endpoint)
+{
+ const address& addr = endpoint.address();
+ asio::error_code ec;
+ std::string a = addr.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::ios::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ if (addr.is_v4())
+ os << a;
+ else
+ os << '[' << a << ']';
+ os << ':' << endpoint.port();
+ }
+ return os;
+}
+#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+template <typename Elem, typename Traits, typename InternetProtocol>
+std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& os,
+ const basic_endpoint<InternetProtocol>& endpoint)
+{
+ const address& addr = endpoint.address();
+ asio::error_code ec;
+ std::string a = addr.to_string(ec);
+ if (ec)
+ {
+ if (os.exceptions() & std::ios::failbit)
+ asio::detail::throw_error(ec);
+ else
+ os.setstate(std::ios_base::failbit);
+ }
+ else
+ {
+ if (addr.is_v4())
+ os << a;
+ else
+ os << '[' << a << ']';
+ os << ':' << endpoint.port();
+ }
+ return os;
+}
+#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_ENDPOINT_HPP
diff --git a/src/libtorrent/asio/ip/basic_resolver.hpp b/src/libtorrent/asio/ip/basic_resolver.hpp
new file mode 100644
index 0000000..d559377
--- /dev/null
+++ b/src/libtorrent/asio/ip/basic_resolver.hpp
@@ -0,0 +1,245 @@
+//
+// basic_resolver.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_BASIC_RESOLVER_HPP
+#define ASIO_IP_BASIC_RESOLVER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/basic_io_object.hpp"
+#include "asio/error.hpp"
+#include "asio/ip/resolver_service.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Provides endpoint resolution functionality.
+/**
+ * The basic_resolver class template provides the ability to resolve a query
+ * to a list of endpoints.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol,
+ typename ResolverService = resolver_service<InternetProtocol> >
+class basic_resolver
+ : public basic_io_object<ResolverService>
+{
+public:
+ /// The protocol type.
+ typedef InternetProtocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename InternetProtocol::endpoint endpoint_type;
+
+ /// The query type.
+ typedef typename InternetProtocol::resolver_query query;
+
+ /// The iterator type.
+ typedef typename InternetProtocol::resolver_iterator iterator;
+
+ /// Constructor.
+ /**
+ * This constructor creates a basic_resolver.
+ *
+ * @param io_service The io_service object that the resolver will use to
+ * dispatch handlers for any asynchronous operations performed on the timer.
+ */
+ explicit basic_resolver(asio::io_service& io_service)
+ : basic_io_object<ResolverService>(io_service)
+ {
+ }
+
+ /// Cancel any asynchronous operations that are waiting on the resolver.
+ /**
+ * This function forces the completion of any pending asynchronous
+ * operations on the host resolver. The handler for each cancelled operation
+ * will be invoked with the asio::error::operation_aborted error code.
+ */
+ void cancel()
+ {
+ return this->service.cancel(this->implementation);
+ }
+
+ /// Resolve a query to a list of entries.
+ /**
+ * This function is used to resolve a query into a list of endpoint entries.
+ *
+ * @param q A query object that determines what endpoints will be returned.
+ *
+ * @returns A forward-only iterator that can be used to traverse the list
+ * of endpoint entries.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note A default constructed iterator represents the end of the list.
+ *
+ * A successful call to this function is guaranteed to return at least one
+ * entry.
+ */
+ iterator resolve(const query& q)
+ {
+ asio::error_code ec;
+ iterator i = this->service.resolve(this->implementation, q, ec);
+ asio::detail::throw_error(ec);
+ return i;
+ }
+
+ /// Resolve a query to a list of entries.
+ /**
+ * This function is used to resolve a query into a list of endpoint entries.
+ *
+ * @param q A query object that determines what endpoints will be returned.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns A forward-only iterator that can be used to traverse the list
+ * of endpoint entries. Returns a default constructed iterator if an error
+ * occurs.
+ *
+ * @note A default constructed iterator represents the end of the list.
+ *
+ * A successful call to this function is guaranteed to return at least one
+ * entry.
+ */
+ iterator resolve(const query& q, asio::error_code& ec)
+ {
+ return this->service.resolve(this->implementation, q, ec);
+ }
+
+ /// Asynchronously resolve a query to a list of entries.
+ /**
+ * This function is used to asynchronously resolve a query into a list of
+ * endpoint entries.
+ *
+ * @param q A query object that determines what endpoints will be returned.
+ *
+ * @param handler The handler to be called when the resolve operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * resolver::iterator iterator // Forward-only iterator that can
+ * // be used to traverse the list
+ * // of endpoint entries.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note A default constructed iterator represents the end of the list.
+ *
+ * A successful resolve operation is guaranteed to pass at least one entry to
+ * the handler.
+ */
+ template <typename ResolveHandler>
+ void async_resolve(const query& q, ResolveHandler handler)
+ {
+ return this->service.async_resolve(this->implementation, q, handler);
+ }
+
+ /// Resolve an endpoint to a list of entries.
+ /**
+ * This function is used to resolve an endpoint into a list of endpoint
+ * entries.
+ *
+ * @param e An endpoint object that determines what endpoints will be
+ * returned.
+ *
+ * @returns A forward-only iterator that can be used to traverse the list
+ * of endpoint entries.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note A default constructed iterator represents the end of the list.
+ *
+ * A successful call to this function is guaranteed to return at least one
+ * entry.
+ */
+ iterator resolve(const endpoint_type& e)
+ {
+ asio::error_code ec;
+ iterator i = this->service.resolve(this->implementation, e, ec);
+ asio::detail::throw_error(ec);
+ return i;
+ }
+
+ /// Resolve an endpoint to a list of entries.
+ /**
+ * This function is used to resolve an endpoint into a list of endpoint
+ * entries.
+ *
+ * @param e An endpoint object that determines what endpoints will be
+ * returned.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns A forward-only iterator that can be used to traverse the list
+ * of endpoint entries. Returns a default constructed iterator if an error
+ * occurs.
+ *
+ * @note A default constructed iterator represents the end of the list.
+ *
+ * A successful call to this function is guaranteed to return at least one
+ * entry.
+ */
+ iterator resolve(const endpoint_type& e, asio::error_code& ec)
+ {
+ return this->service.resolve(this->implementation, e, ec);
+ }
+
+ /// Asynchronously resolve an endpoint to a list of entries.
+ /**
+ * This function is used to asynchronously resolve an endpoint into a list of
+ * endpoint entries.
+ *
+ * @param e An endpoint object that determines what endpoints will be
+ * returned.
+ *
+ * @param handler The handler to be called when the resolve operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * resolver::iterator iterator // Forward-only iterator that can
+ * // be used to traverse the list
+ * // of endpoint entries.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation
+ * of the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note A default constructed iterator represents the end of the list.
+ *
+ * A successful resolve operation is guaranteed to pass at least one entry to
+ * the handler.
+ */
+ template <typename ResolveHandler>
+ void async_resolve(const endpoint_type& e, ResolveHandler handler)
+ {
+ return this->service.async_resolve(this->implementation, e, handler);
+ }
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_HPP
diff --git a/src/libtorrent/asio/ip/basic_resolver_entry.hpp b/src/libtorrent/asio/ip/basic_resolver_entry.hpp
new file mode 100644
index 0000000..b29f957
--- /dev/null
+++ b/src/libtorrent/asio/ip/basic_resolver_entry.hpp
@@ -0,0 +1,95 @@
+//
+// basic_resolver_entry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_BASIC_RESOLVER_ENTRY_HPP
+#define ASIO_IP_BASIC_RESOLVER_ENTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <string>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace ip {
+
+/// An entry produced by a resolver.
+/**
+ * The asio::ip::basic_resolver_entry class template describes an entry
+ * as returned by a resolver.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol>
+class basic_resolver_entry
+{
+public:
+ /// The protocol type associated with the endpoint entry.
+ typedef InternetProtocol protocol_type;
+
+ /// The endpoint type associated with the endpoint entry.
+ typedef typename InternetProtocol::endpoint endpoint_type;
+
+ /// Default constructor.
+ basic_resolver_entry()
+ {
+ }
+
+ /// Construct with specified endpoint, host name and service name.
+ basic_resolver_entry(const endpoint_type& endpoint,
+ const std::string& host_name, const std::string& service_name)
+ : endpoint_(endpoint),
+ host_name_(host_name),
+ service_name_(service_name)
+ {
+ }
+
+ /// Get the endpoint associated with the entry.
+ endpoint_type endpoint() const
+ {
+ return endpoint_;
+ }
+
+ /// Convert to the endpoint associated with the entry.
+ operator endpoint_type() const
+ {
+ return endpoint_;
+ }
+
+ /// Get the host name associated with the entry.
+ std::string host_name() const
+ {
+ return host_name_;
+ }
+
+ /// Get the service name associated with the entry.
+ std::string service_name() const
+ {
+ return service_name_;
+ }
+
+private:
+ endpoint_type endpoint_;
+ std::string host_name_;
+ std::string service_name_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_ENTRY_HPP
diff --git a/src/libtorrent/asio/ip/basic_resolver_iterator.hpp b/src/libtorrent/asio/ip/basic_resolver_iterator.hpp
new file mode 100644
index 0000000..fe04ffc
--- /dev/null
+++ b/src/libtorrent/asio/ip/basic_resolver_iterator.hpp
@@ -0,0 +1,154 @@
+//
+// basic_resolver_iterator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP
+#define ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <cstring>
+#include <string>
+#include <vector>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/ip/basic_resolver_entry.hpp"
+
+namespace asio {
+namespace ip {
+
+/// An iterator over the entries produced by a resolver.
+/**
+ * The asio::ip::basic_resolver_iterator class template is used to define
+ * iterators over the results returned by a resolver.
+ *
+ * The iterator's value_type, obtained when the iterator is dereferenced, is:
+ * @code const basic_resolver_entry<InternetProtocol> @endcode
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol>
+class basic_resolver_iterator
+ : public boost::iterator_facade<
+ basic_resolver_iterator<InternetProtocol>,
+ const basic_resolver_entry<InternetProtocol>,
+ boost::forward_traversal_tag>
+{
+public:
+ /// Default constructor creates an end iterator.
+ basic_resolver_iterator()
+ {
+ }
+
+ /// Create an iterator from an addrinfo list returned by getaddrinfo.
+ static basic_resolver_iterator create(
+ asio::detail::addrinfo_type* address_info,
+ const std::string& host_name, const std::string& service_name)
+ {
+ basic_resolver_iterator iter;
+ if (!address_info)
+ return iter;
+
+ std::string actual_host_name = host_name;
+ if (address_info->ai_canonname)
+ actual_host_name = address_info->ai_canonname;
+
+ iter.values_.reset(new values_type);
+
+ while (address_info)
+ {
+ if (address_info->ai_family == PF_INET
+ || address_info->ai_family == PF_INET6)
+ {
+ using namespace std; // For memcpy.
+ typename InternetProtocol::endpoint endpoint;
+ endpoint.resize(static_cast<std::size_t>(address_info->ai_addrlen));
+ memcpy(endpoint.data(), address_info->ai_addr,
+ address_info->ai_addrlen);
+ iter.values_->push_back(
+ basic_resolver_entry<InternetProtocol>(endpoint,
+ actual_host_name, service_name));
+ }
+ address_info = address_info->ai_next;
+ }
+
+ if (iter.values_->size())
+ iter.iter_ = iter.values_->begin();
+ else
+ iter.values_.reset();
+
+ return iter;
+ }
+
+ /// Create an iterator from an endpoint, host name and service name.
+ static basic_resolver_iterator create(
+ const typename InternetProtocol::endpoint& endpoint,
+ const std::string& host_name, const std::string& service_name)
+ {
+ basic_resolver_iterator iter;
+ iter.values_.reset(new values_type);
+ iter.values_->push_back(
+ basic_resolver_entry<InternetProtocol>(
+ endpoint, host_name, service_name));
+ iter.iter_ = iter.values_->begin();
+ return iter;
+ }
+
+private:
+ friend class boost::iterator_core_access;
+
+ void increment()
+ {
+ if (++*iter_ == values_->end())
+ {
+ // Reset state to match a default constructed end iterator.
+ values_.reset();
+ typedef typename values_type::const_iterator values_iterator_type;
+ iter_.reset();
+ }
+ }
+
+ bool equal(const basic_resolver_iterator& other) const
+ {
+ if (!values_ && !other.values_)
+ return true;
+ if (values_ != other.values_)
+ return false;
+ return *iter_ == *other.iter_;
+ }
+
+ const basic_resolver_entry<InternetProtocol>& dereference() const
+ {
+ return **iter_;
+ }
+
+ typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
+ typedef typename values_type::const_iterator values_iter_type;
+ boost::shared_ptr<values_type> values_;
+ boost::optional<values_iter_type> iter_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP
diff --git a/src/libtorrent/asio/ip/basic_resolver_query.hpp b/src/libtorrent/asio/ip/basic_resolver_query.hpp
new file mode 100644
index 0000000..bf43a44
--- /dev/null
+++ b/src/libtorrent/asio/ip/basic_resolver_query.hpp
@@ -0,0 +1,149 @@
+//
+// basic_resolver_query.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_BASIC_RESOLVER_QUERY_HPP
+#define ASIO_IP_BASIC_RESOLVER_QUERY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <string>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/socket_ops.hpp"
+#include "asio/ip/resolver_query_base.hpp"
+
+namespace asio {
+namespace ip {
+
+/// An query to be passed to a resolver.
+/**
+ * The asio::ip::basic_resolver_query class template describes a query
+ * that can be passed to a resolver.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename InternetProtocol>
+class basic_resolver_query
+ : public resolver_query_base
+{
+public:
+ /// The protocol type associated with the endpoint query.
+ typedef InternetProtocol protocol_type;
+
+ /// Construct with specified service name for any protocol.
+ basic_resolver_query(const std::string& service_name,
+ int flags = passive | address_configured)
+ : hints_(),
+ host_name_(),
+ service_name_(service_name)
+ {
+ typename InternetProtocol::endpoint endpoint;
+ hints_.ai_flags = flags;
+ hints_.ai_family = PF_UNSPEC;
+ hints_.ai_socktype = endpoint.protocol().type();
+ hints_.ai_protocol = endpoint.protocol().protocol();
+ hints_.ai_addrlen = 0;
+ hints_.ai_canonname = 0;
+ hints_.ai_addr = 0;
+ hints_.ai_next = 0;
+ }
+
+ /// Construct with specified service name for a given protocol.
+ basic_resolver_query(const protocol_type& protocol,
+ const std::string& service_name,
+ int flags = passive | address_configured)
+ : hints_(),
+ host_name_(),
+ service_name_(service_name)
+ {
+ hints_.ai_flags = flags;
+ hints_.ai_family = protocol.family();
+ hints_.ai_socktype = protocol.type();
+ hints_.ai_protocol = protocol.protocol();
+ hints_.ai_addrlen = 0;
+ hints_.ai_canonname = 0;
+ hints_.ai_addr = 0;
+ hints_.ai_next = 0;
+ }
+
+ /// Construct with specified host name and service name for any protocol.
+ basic_resolver_query(const std::string& host_name,
+ const std::string& service_name, int flags = address_configured)
+ : hints_(),
+ host_name_(host_name),
+ service_name_(service_name)
+ {
+ typename InternetProtocol::endpoint endpoint;
+ hints_.ai_flags = flags;
+ hints_.ai_family = PF_UNSPEC;
+ hints_.ai_socktype = endpoint.protocol().type();
+ hints_.ai_protocol = endpoint.protocol().protocol();
+ hints_.ai_addrlen = 0;
+ hints_.ai_canonname = 0;
+ hints_.ai_addr = 0;
+ hints_.ai_next = 0;
+ }
+
+ /// Construct with specified host name and service name for a given protocol.
+ basic_resolver_query(const protocol_type& protocol,
+ const std::string& host_name, const std::string& service_name,
+ int flags = address_configured)
+ : hints_(),
+ host_name_(host_name),
+ service_name_(service_name)
+ {
+ hints_.ai_flags = flags;
+ hints_.ai_family = protocol.family();
+ hints_.ai_socktype = protocol.type();
+ hints_.ai_protocol = protocol.protocol();
+ hints_.ai_addrlen = 0;
+ hints_.ai_canonname = 0;
+ hints_.ai_addr = 0;
+ hints_.ai_next = 0;
+ }
+
+ /// Get the hints associated with the query.
+ const asio::detail::addrinfo_type& hints() const
+ {
+ return hints_;
+ }
+
+ /// Get the host name associated with the query.
+ std::string host_name() const
+ {
+ return host_name_;
+ }
+
+ /// Get the service name associated with the query.
+ std::string service_name() const
+ {
+ return service_name_;
+ }
+
+private:
+ asio::detail::addrinfo_type hints_;
+ std::string host_name_;
+ std::string service_name_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_BASIC_RESOLVER_QUERY_HPP
diff --git a/src/libtorrent/asio/ip/detail/socket_option.hpp b/src/libtorrent/asio/ip/detail/socket_option.hpp
new file mode 100644
index 0000000..a3496fd
--- /dev/null
+++ b/src/libtorrent/asio/ip/detail/socket_option.hpp
@@ -0,0 +1,578 @@
+//
+// socket_option.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_DETAIL_SOCKET_OPTION_HPP
+#define ASIO_IP_DETAIL_SOCKET_OPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <cstring>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/address.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace ip {
+namespace detail {
+namespace socket_option {
+
+// Helper template for implementing multicast enable loopback options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class multicast_enable_loopback
+{
+public:
+#if defined(__sun) || defined(__osf__)
+ typedef unsigned char ipv4_value_type;
+ typedef unsigned char ipv6_value_type;
+#elif defined(_AIX) || defined(__hpux)
+ typedef unsigned char ipv4_value_type;
+ typedef unsigned int ipv6_value_type;
+#else
+ typedef int ipv4_value_type;
+ typedef int ipv6_value_type;
+#endif
+
+ // Default constructor.
+ multicast_enable_loopback()
+ : ipv4_value_(0),
+ ipv6_value_(0)
+ {
+ }
+
+ // Construct with a specific option value.
+ explicit multicast_enable_loopback(bool v)
+ : ipv4_value_(v ? 1 : 0),
+ ipv6_value_(v ? 1 : 0)
+ {
+ }
+
+ // Set the value of the boolean.
+ multicast_enable_loopback& operator=(bool v)
+ {
+ ipv4_value_ = v ? 1 : 0;
+ ipv6_value_ = v ? 1 : 0;
+ return *this;
+ }
+
+ // Get the current value of the boolean.
+ bool value() const
+ {
+ return !!ipv4_value_;
+ }
+
+ // Convert to bool.
+ operator bool() const
+ {
+ return !!ipv4_value_;
+ }
+
+ // Test for false.
+ bool operator!() const
+ {
+ return !ipv4_value_;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Level;
+ return IPv4_Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Name;
+ return IPv4_Name;
+ }
+
+ // Get the address of the boolean data.
+ template <typename Protocol>
+ void* data(const Protocol& protocol)
+ {
+ if (protocol.family() == PF_INET6)
+ return &ipv6_value_;
+ return &ipv4_value_;
+ }
+
+ // Get the address of the boolean data.
+ template <typename Protocol>
+ const void* data(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return &ipv6_value_;
+ return &ipv4_value_;
+ }
+
+ // Get the size of the boolean data.
+ template <typename Protocol>
+ std::size_t size(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return sizeof(ipv6_value_);
+ return sizeof(ipv4_value_);
+ }
+
+ // Set the size of the boolean data.
+ template <typename Protocol>
+ void resize(const Protocol& protocol, std::size_t s)
+ {
+ if (protocol.family() == PF_INET6)
+ {
+ if (s != sizeof(ipv6_value_))
+ {
+ throw std::length_error(
+ "multicast_enable_loopback socket option resize");
+ }
+ ipv4_value_ = ipv6_value_ ? 1 : 0;
+ }
+ else
+ {
+ if (s != sizeof(ipv4_value_))
+ {
+ throw std::length_error(
+ "multicast_enable_loopback socket option resize");
+ }
+ ipv6_value_ = ipv4_value_ ? 1 : 0;
+ }
+ }
+
+private:
+ ipv4_value_type ipv4_value_;
+ ipv6_value_type ipv6_value_;
+};
+
+// Helper template for implementing unicast hops options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class unicast_hops
+{
+public:
+ // Default constructor.
+ unicast_hops()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific option value.
+ explicit unicast_hops(int v)
+ : value_(v)
+ {
+ }
+
+ // Set the value of the option.
+ unicast_hops& operator=(int v)
+ {
+ value_ = v;
+ return *this;
+ }
+
+ // Get the current value of the option.
+ int value() const
+ {
+ return value_;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Level;
+ return IPv4_Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Name;
+ return IPv4_Name;
+ }
+
+ // Get the address of the data.
+ template <typename Protocol>
+ int* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the data.
+ template <typename Protocol>
+ const int* data(const Protocol&) const
+ {
+ return &value_;
+ }
+
+ // Get the size of the data.
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return sizeof(value_);
+ }
+
+ // Set the size of the data.
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t s)
+ {
+ if (s != sizeof(value_))
+ throw std::length_error("unicast hops socket option resize");
+#if defined(__hpux)
+ if (value_ < 0)
+ value_ = value_ & 0xFF;
+#endif
+ }
+
+private:
+ int value_;
+};
+
+// Helper template for implementing multicast hops options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class multicast_hops
+{
+public:
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+ typedef int ipv4_value_type;
+#else
+ typedef unsigned char ipv4_value_type;
+#endif
+ typedef int ipv6_value_type;
+
+ // Default constructor.
+ multicast_hops()
+ : ipv4_value_(0),
+ ipv6_value_(0)
+ {
+ }
+
+ // Construct with a specific option value.
+ explicit multicast_hops(int v)
+ {
+ if (v < 0 || v > 255)
+ throw std::out_of_range("multicast hops value out of range");
+ ipv4_value_ = (ipv4_value_type)v;
+ ipv6_value_ = v;
+ }
+
+ // Set the value of the option.
+ multicast_hops& operator=(int v)
+ {
+ if (v < 0 || v > 255)
+ throw std::out_of_range("multicast hops value out of range");
+ ipv4_value_ = (ipv4_value_type)v;
+ ipv6_value_ = v;
+ return *this;
+ }
+
+ // Get the current value of the option.
+ int value() const
+ {
+ return ipv6_value_;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Level;
+ return IPv4_Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Name;
+ return IPv4_Name;
+ }
+
+ // Get the address of the data.
+ template <typename Protocol>
+ void* data(const Protocol& protocol)
+ {
+ if (protocol.family() == PF_INET6)
+ return &ipv6_value_;
+ return &ipv4_value_;
+ }
+
+ // Get the address of the data.
+ template <typename Protocol>
+ const void* data(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return &ipv6_value_;
+ return &ipv4_value_;
+ }
+
+ // Get the size of the data.
+ template <typename Protocol>
+ std::size_t size(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return sizeof(ipv6_value_);
+ return sizeof(ipv4_value_);
+ }
+
+ // Set the size of the data.
+ template <typename Protocol>
+ void resize(const Protocol& protocol, std::size_t s)
+ {
+ if (protocol.family() == PF_INET6)
+ {
+ if (s != sizeof(ipv6_value_))
+ throw std::length_error("multicast hops socket option resize");
+ if (ipv6_value_ < 0)
+ ipv4_value_ = 0;
+ else if (ipv6_value_ > 255)
+ ipv4_value_ = 255;
+ else
+ ipv4_value_ = (ipv4_value_type)ipv6_value_;
+ }
+ else
+ {
+ if (s != sizeof(ipv4_value_))
+ throw std::length_error("multicast hops socket option resize");
+ ipv6_value_ = ipv4_value_;
+ }
+ }
+
+private:
+ ipv4_value_type ipv4_value_;
+ ipv6_value_type ipv6_value_;
+};
+
+// Helper template for implementing ip_mreq-based options.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class multicast_request
+{
+public:
+ // Default constructor.
+ multicast_request()
+ {
+ ipv4_value_.imr_multiaddr.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+ ipv4_value_.imr_interface.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+ ipv6_value_.ipv6mr_multiaddr = tmp_addr;
+ ipv6_value_.ipv6mr_interface = 0;
+ }
+
+ // Construct with multicast address only.
+ explicit multicast_request(const asio::ip::address& multicast_address)
+ {
+ if (multicast_address.is_v6())
+ {
+ ipv4_value_.imr_multiaddr.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+ ipv4_value_.imr_interface.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+
+ using namespace std; // For memcpy.
+ asio::ip::address_v6 ipv6_address = multicast_address.to_v6();
+ asio::ip::address_v6::bytes_type bytes = ipv6_address.to_bytes();
+ memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16);
+ ipv6_value_.ipv6mr_interface = 0;
+ }
+ else
+ {
+ ipv4_value_.imr_multiaddr.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ multicast_address.to_v4().to_ulong());
+ ipv4_value_.imr_interface.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+ ipv6_value_.ipv6mr_multiaddr = tmp_addr;
+ ipv6_value_.ipv6mr_interface = 0;
+ }
+ }
+
+ // Construct with multicast address and IPv4 address specifying an interface.
+ explicit multicast_request(
+ const asio::ip::address_v4& multicast_address,
+ const asio::ip::address_v4& network_interface
+ = asio::ip::address_v4::any())
+ {
+ ipv4_value_.imr_multiaddr.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ multicast_address.to_ulong());
+ ipv4_value_.imr_interface.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ network_interface.to_ulong());
+
+ asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
+ ipv6_value_.ipv6mr_multiaddr = tmp_addr;
+ ipv6_value_.ipv6mr_interface = 0;
+ }
+
+ // Construct with multicast address and IPv6 network interface index.
+ explicit multicast_request(
+ const asio::ip::address_v6& multicast_address,
+ unsigned long network_interface = 0)
+ {
+ ipv4_value_.imr_multiaddr.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+ ipv4_value_.imr_interface.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+
+ using namespace std; // For memcpy.
+ asio::ip::address_v6::bytes_type bytes =
+ multicast_address.to_bytes();
+ memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16);
+ ipv6_value_.ipv6mr_interface = network_interface;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Level;
+ return IPv4_Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Name;
+ return IPv4_Name;
+ }
+
+ // Get the address of the option data.
+ template <typename Protocol>
+ const void* data(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return &ipv6_value_;
+ return &ipv4_value_;
+ }
+
+ // Get the size of the option data.
+ template <typename Protocol>
+ std::size_t size(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return sizeof(ipv6_value_);
+ return sizeof(ipv4_value_);
+ }
+
+private:
+ asio::detail::in4_mreq_type ipv4_value_;
+ asio::detail::in6_mreq_type ipv6_value_;
+};
+
+// Helper template for implementing options that specify a network interface.
+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
+class network_interface
+{
+public:
+ // Default constructor.
+ network_interface()
+ {
+ ipv4_value_.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+ ipv6_value_ = 0;
+ }
+
+ // Construct with IPv4 interface.
+ explicit network_interface(const asio::ip::address_v4& ipv4_interface)
+ {
+ ipv4_value_.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ ipv4_interface.to_ulong());
+ ipv6_value_ = 0;
+ }
+
+ // Construct with IPv6 interface.
+ explicit network_interface(unsigned int ipv6_interface)
+ {
+ ipv4_value_.s_addr =
+ asio::detail::socket_ops::host_to_network_long(
+ asio::ip::address_v4::any().to_ulong());
+ ipv6_value_ = ipv6_interface;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Level;
+ return IPv4_Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return IPv6_Name;
+ return IPv4_Name;
+ }
+
+ // Get the address of the option data.
+ template <typename Protocol>
+ const void* data(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return &ipv6_value_;
+ return &ipv4_value_;
+ }
+
+ // Get the size of the option data.
+ template <typename Protocol>
+ std::size_t size(const Protocol& protocol) const
+ {
+ if (protocol.family() == PF_INET6)
+ return sizeof(ipv6_value_);
+ return sizeof(ipv4_value_);
+ }
+
+private:
+ asio::detail::in4_addr_type ipv4_value_;
+ unsigned int ipv6_value_;
+};
+
+} // namespace socket_option
+} // namespace detail
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_DETAIL_SOCKET_OPTION_HPP
diff --git a/src/libtorrent/asio/ip/host_name.hpp b/src/libtorrent/asio/ip/host_name.hpp
new file mode 100644
index 0000000..8528013
--- /dev/null
+++ b/src/libtorrent/asio/ip/host_name.hpp
@@ -0,0 +1,62 @@
+//
+// host_name.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_HOST_NAME_HPP
+#define ASIO_IP_HOST_NAME_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <string>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Get the current host name.
+std::string host_name();
+
+/// Get the current host name.
+std::string host_name(asio::error_code& ec);
+
+inline std::string host_name()
+{
+ char name[1024];
+ asio::error_code ec;
+ if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+ {
+ asio::detail::throw_error(ec);
+ return std::string();
+ }
+ return std::string(name);
+}
+
+inline std::string host_name(asio::error_code& ec)
+{
+ char name[1024];
+ if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)
+ return std::string();
+ return std::string(name);
+}
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_HOST_NAME_HPP
diff --git a/src/libtorrent/asio/ip/multicast.hpp b/src/libtorrent/asio/ip/multicast.hpp
new file mode 100644
index 0000000..c8b84f5
--- /dev/null
+++ b/src/libtorrent/asio/ip/multicast.hpp
@@ -0,0 +1,181 @@
+//
+// multicast.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_MULTICAST_HPP
+#define ASIO_IP_MULTICAST_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/detail/socket_option.hpp"
+
+namespace asio {
+namespace ip {
+namespace multicast {
+
+/// Socket option to join a multicast group on a specified interface.
+/**
+ * Implements the IPPROTO_IP/IP_ADD_MEMBERSHIP socket option.
+ *
+ * @par Examples
+ * Setting the option to join a multicast group:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::address multicast_address =
+ * asio::ip::address::from_string("225.0.0.1");
+ * asio::ip::multicast::join_group option(multicast_address);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par Concepts:
+ * SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined join_group;
+#else
+typedef asio::ip::detail::socket_option::multicast_request<
+ IPPROTO_IP, IP_ADD_MEMBERSHIP, IPPROTO_IPV6, IPV6_JOIN_GROUP> join_group;
+#endif
+
+/// Socket option to leave a multicast group on a specified interface.
+/**
+ * Implements the IPPROTO_IP/IP_DROP_MEMBERSHIP socket option.
+ *
+ * @par Examples
+ * Setting the option to leave a multicast group:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::address multicast_address =
+ * asio::ip::address::from_string("225.0.0.1");
+ * asio::ip::multicast::leave_group option(multicast_address);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par Concepts:
+ * SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined leave_group;
+#else
+typedef asio::ip::detail::socket_option::multicast_request<
+ IPPROTO_IP, IP_DROP_MEMBERSHIP, IPPROTO_IPV6, IPV6_LEAVE_GROUP> leave_group;
+#endif
+
+/// Socket option for local interface to use for outgoing multicast packets.
+/**
+ * Implements the IPPROTO_IP/IP_MULTICAST_IF socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::address_v4 local_interface =
+ * asio::ip::address_v4::from_string("1.2.3.4");
+ * asio::ip::multicast::outbound_interface option(local_interface);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par Concepts:
+ * SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined outbound_interface;
+#else
+typedef asio::ip::detail::socket_option::network_interface<
+ IPPROTO_IP, IP_MULTICAST_IF, IPPROTO_IPV6, IPV6_MULTICAST_IF>
+ outbound_interface;
+#endif
+
+/// Socket option for time-to-live associated with outgoing multicast packets.
+/**
+ * Implements the IPPROTO_IP/IP_MULTICAST_TTL socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::multicast::hops option(4);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::multicast::hops option;
+ * socket.get_option(option);
+ * int ttl = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined hops;
+#else
+typedef asio::ip::detail::socket_option::multicast_hops<
+ IPPROTO_IP, IP_MULTICAST_TTL, IPPROTO_IPV6, IPV6_MULTICAST_HOPS> hops;
+#endif
+
+/// Socket option determining whether outgoing multicast packets will be
+/// received on the same socket if it is a member of the multicast group.
+/**
+ * Implements the IPPROTO_IP/IP_MULTICAST_LOOP socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::multicast::enable_loopback option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::multicast::enable_loopback option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined enable_loopback;
+#else
+typedef asio::ip::detail::socket_option::multicast_enable_loopback<
+ IPPROTO_IP, IP_MULTICAST_LOOP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP>
+ enable_loopback;
+#endif
+
+} // namespace multicast
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_MULTICAST_HPP
diff --git a/src/libtorrent/asio/ip/resolver_query_base.hpp b/src/libtorrent/asio/ip/resolver_query_base.hpp
new file mode 100644
index 0000000..16f8466
--- /dev/null
+++ b/src/libtorrent/asio/ip/resolver_query_base.hpp
@@ -0,0 +1,107 @@
+//
+// resolver_query_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_RESOLVER_QUERY_BASE_HPP
+#define ASIO_IP_RESOLVER_QUERY_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace ip {
+
+/// The resolver_query_base class is used as a base for the
+/// basic_resolver_query class templates to provide a common place to define
+/// the flag constants.
+class resolver_query_base
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// Determine the canonical name of the host specified in the query.
+ static const int canonical_name = implementation_defined;
+
+ /// Indicate that returned endpoint is intended for use as a locally bound
+ /// socket endpoint.
+ static const int passive = implementation_defined;
+
+ /// Host name should be treated as a numeric string defining an IPv4 or IPv6
+ /// address and no name resolution should be attempted.
+ static const int numeric_host = implementation_defined;
+
+ /// Service name should be treated as a numeric string defining a port number
+ /// and no name resolution should be attempted.
+ static const int numeric_service = implementation_defined;
+
+ /// If the query protocol family is specified as IPv6, return IPv4-mapped
+ /// IPv6 addresses on finding no IPv6 addresses.
+ static const int v4_mapped = implementation_defined;
+
+ /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses.
+ static const int all_matching = implementation_defined;
+
+ /// Only return IPv4 addresses if a non-loopback IPv4 address is configured
+ /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address
+ /// is configured for the system.
+ static const int address_configured = implementation_defined;
+#else
+ BOOST_STATIC_CONSTANT(int, canonical_name = AI_CANONNAME);
+ BOOST_STATIC_CONSTANT(int, passive = AI_PASSIVE);
+ BOOST_STATIC_CONSTANT(int, numeric_host = AI_NUMERICHOST);
+# if defined(AI_NUMERICSERV)
+ BOOST_STATIC_CONSTANT(int, numeric_service = AI_NUMERICSERV);
+# else
+ BOOST_STATIC_CONSTANT(int, numeric_service = 0);
+# endif
+# if defined(AI_V4MAPPED)
+ BOOST_STATIC_CONSTANT(int, v4_mapped = AI_V4MAPPED);
+# else
+ BOOST_STATIC_CONSTANT(int, v4_mapped = 0);
+# endif
+# if defined(AI_ALL)
+ BOOST_STATIC_CONSTANT(int, all_matching = AI_ALL);
+# else
+ BOOST_STATIC_CONSTANT(int, all_matching = 0);
+# endif
+# if defined(AI_ADDRCONFIG)
+ BOOST_STATIC_CONSTANT(int, address_configured = AI_ADDRCONFIG);
+# else
+ BOOST_STATIC_CONSTANT(int, address_configured = 0);
+# endif
+#endif
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ ~resolver_query_base()
+ {
+ }
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+private:
+ // Workaround to enable the empty base optimisation with Borland C++.
+ char dummy_;
+#endif
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_RESOLVER_QUERY_BASE_HPP
diff --git a/src/libtorrent/asio/ip/resolver_service.hpp b/src/libtorrent/asio/ip/resolver_service.hpp
new file mode 100644
index 0000000..01b0a8e
--- /dev/null
+++ b/src/libtorrent/asio/ip/resolver_service.hpp
@@ -0,0 +1,140 @@
+//
+// resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_RESOLVER_SERVICE_HPP
+#define ASIO_IP_RESOLVER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/resolver_service.hpp"
+#include "asio/detail/service_base.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Default service implementation for a resolver.
+template <typename InternetProtocol>
+class resolver_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public asio::io_service::service
+#else
+ : public asio::detail::service_base<
+ resolver_service<InternetProtocol> >
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static asio::io_service::id id;
+#endif
+
+ /// The protocol type.
+ typedef InternetProtocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename InternetProtocol::endpoint endpoint_type;
+
+ /// The query type.
+ typedef typename InternetProtocol::resolver_query query_type;
+
+ /// The iterator type.
+ typedef typename InternetProtocol::resolver_iterator iterator_type;
+
+private:
+ // The type of the platform-specific implementation.
+ typedef asio::detail::resolver_service<InternetProtocol>
+ service_impl_type;
+
+public:
+ /// The type of a resolver implementation.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef typename service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// Construct a new resolver service for the specified io_service.
+ explicit resolver_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ resolver_service<InternetProtocol> >(io_service),
+ service_impl_(asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Construct a new resolver implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+ /// Destroy a resolver implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ /// Cancel pending asynchronous operations.
+ void cancel(implementation_type& impl)
+ {
+ service_impl_.cancel(impl);
+ }
+
+ /// Resolve a query to a list of entries.
+ iterator_type resolve(implementation_type& impl, const query_type& query,
+ asio::error_code& ec)
+ {
+ return service_impl_.resolve(impl, query, ec);
+ }
+
+ /// Asynchronously resolve a query to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl, const query_type& query,
+ Handler handler)
+ {
+ service_impl_.async_resolve(impl, query, handler);
+ }
+
+ /// Resolve an endpoint to a list of entries.
+ iterator_type resolve(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ return service_impl_.resolve(impl, endpoint, ec);
+ }
+
+ /// Asynchronously resolve an endpoint to a list of entries.
+ template <typename ResolveHandler>
+ void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
+ ResolveHandler handler)
+ {
+ return service_impl_.async_resolve(impl, endpoint, handler);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_RESOLVER_SERVICE_HPP
diff --git a/src/libtorrent/asio/ip/tcp.hpp b/src/libtorrent/asio/ip/tcp.hpp
new file mode 100644
index 0000000..2dd2292
--- /dev/null
+++ b/src/libtorrent/asio/ip/tcp.hpp
@@ -0,0 +1,158 @@
+//
+// tcp.hpp
+// ~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_TCP_HPP
+#define ASIO_IP_TCP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/basic_socket_acceptor.hpp"
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/detail/socket_option.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for TCP.
+/**
+ * The asio::ip::tcp class contains flags necessary for TCP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class tcp
+{
+public:
+ /// The type of a TCP endpoint.
+ typedef basic_endpoint<tcp> endpoint;
+
+ /// The type of a resolver query.
+ typedef basic_resolver_query<tcp> resolver_query;
+
+ /// The type of a resolver iterator.
+ typedef basic_resolver_iterator<tcp> resolver_iterator;
+
+ /// Construct to represent the IPv4 TCP protocol.
+ static tcp v4()
+ {
+ return tcp(PF_INET);
+ }
+
+ /// Construct to represent the IPv6 TCP protocol.
+ static tcp v6()
+ {
+ return tcp(PF_INET6);
+ }
+
+ /// Obtain an identifier for the type of the protocol.
+ int type() const
+ {
+ return SOCK_STREAM;
+ }
+
+ /// Obtain an identifier for the protocol.
+ int protocol() const
+ {
+ return IPPROTO_TCP;
+ }
+
+ /// Obtain an identifier for the protocol family.
+ int family() const
+ {
+ return family_;
+ }
+
+ /// The TCP socket type.
+ typedef basic_stream_socket<tcp> socket;
+
+ /// The TCP acceptor type.
+ typedef basic_socket_acceptor<tcp> acceptor;
+
+ /// The TCP resolver type.
+ typedef basic_resolver<tcp> resolver;
+
+ /// The TCP iostream type.
+ typedef basic_socket_iostream<tcp> iostream;
+
+ /// Socket option for disabling the Nagle algorithm.
+ /**
+ * Implements the IPPROTO_TCP/TCP_NODELAY socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::no_delay option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::tcp::no_delay option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Boolean_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined no_delay;
+#else
+ typedef asio::detail::socket_option::boolean<
+ IPPROTO_TCP, TCP_NODELAY> no_delay;
+#endif
+
+ /// Compare two protocols for equality.
+ friend bool operator==(const tcp& p1, const tcp& p2)
+ {
+ return p1.family_ == p2.family_;
+ }
+
+ /// Compare two protocols for inequality.
+ friend bool operator!=(const tcp& p1, const tcp& p2)
+ {
+ return p1.family_ != p2.family_;
+ }
+
+private:
+ // Construct with a specific family.
+ explicit tcp(int family)
+ : family_(family)
+ {
+ }
+
+ int family_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_TCP_HPP
diff --git a/src/libtorrent/asio/ip/udp.hpp b/src/libtorrent/asio/ip/udp.hpp
new file mode 100644
index 0000000..47d6e41
--- /dev/null
+++ b/src/libtorrent/asio/ip/udp.hpp
@@ -0,0 +1,116 @@
+//
+// udp.hpp
+// ~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_UDP_HPP
+#define ASIO_IP_UDP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for UDP.
+/**
+ * The asio::ip::udp class contains flags necessary for UDP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class udp
+{
+public:
+ /// The type of a UDP endpoint.
+ typedef basic_endpoint<udp> endpoint;
+
+ /// The type of a resolver query.
+ typedef basic_resolver_query<udp> resolver_query;
+
+ /// The type of a resolver iterator.
+ typedef basic_resolver_iterator<udp> resolver_iterator;
+
+ /// Construct to represent the IPv4 UDP protocol.
+ static udp v4()
+ {
+ return udp(PF_INET);
+ }
+
+ /// Construct to represent the IPv6 UDP protocol.
+ static udp v6()
+ {
+ return udp(PF_INET6);
+ }
+
+ /// Obtain an identifier for the type of the protocol.
+ int type() const
+ {
+ return SOCK_DGRAM;
+ }
+
+ /// Obtain an identifier for the protocol.
+ int protocol() const
+ {
+ return IPPROTO_UDP;
+ }
+
+ /// Obtain an identifier for the protocol family.
+ int family() const
+ {
+ return family_;
+ }
+
+ /// The UDP socket type.
+ typedef basic_datagram_socket<udp> socket;
+
+ /// The UDP resolver type.
+ typedef basic_resolver<udp> resolver;
+
+ /// Compare two protocols for equality.
+ friend bool operator==(const udp& p1, const udp& p2)
+ {
+ return p1.family_ == p2.family_;
+ }
+
+ /// Compare two protocols for inequality.
+ friend bool operator!=(const udp& p1, const udp& p2)
+ {
+ return p1.family_ != p2.family_;
+ }
+
+private:
+ // Construct with a specific family.
+ explicit udp(int family)
+ : family_(family)
+ {
+ }
+
+ int family_;
+};
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_UDP_HPP
diff --git a/src/libtorrent/asio/ip/unicast.hpp b/src/libtorrent/asio/ip/unicast.hpp
new file mode 100644
index 0000000..dd0707d
--- /dev/null
+++ b/src/libtorrent/asio/ip/unicast.hpp
@@ -0,0 +1,70 @@
+//
+// unicast.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_UNICAST_HPP
+#define ASIO_IP_UNICAST_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ip/detail/socket_option.hpp"
+
+namespace asio {
+namespace ip {
+namespace unicast {
+
+/// Socket option for time-to-live associated with outgoing unicast packets.
+/**
+ * Implements the IPPROTO_IP/IP_UNICAST_TTL socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::unicast::hops option(4);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::ip::unicast::hops option;
+ * socket.get_option(option);
+ * int ttl = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined hops;
+#else
+typedef asio::ip::detail::socket_option::unicast_hops<
+ IPPROTO_IP, IP_TTL, IPPROTO_IPV6, IPV6_UNICAST_HOPS> hops;
+#endif
+
+} // namespace unicast
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_UNICAST_HPP
diff --git a/src/libtorrent/asio/ip/v6_only.hpp b/src/libtorrent/asio/ip/v6_only.hpp
new file mode 100644
index 0000000..d730fc7
--- /dev/null
+++ b/src/libtorrent/asio/ip/v6_only.hpp
@@ -0,0 +1,68 @@
+//
+// v6_only.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IP_V6_ONLY_HPP
+#define ASIO_IP_V6_ONLY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_option.hpp"
+
+namespace asio {
+namespace ip {
+
+/// Socket option for determining whether an IPv6 socket supports IPv6
+/// communication only.
+/**
+ * Implements the IPPROTO_IPV6/IP_V6ONLY socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::v6_only option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::ip::v6_only option;
+ * socket.get_option(option);
+ * bool v6_only = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * GettableSocketOption, SettableSocketOption.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+typedef implementation_defined v6_only;
+#elif defined(IPV6_V6ONLY)
+typedef asio::detail::socket_option::boolean<
+ IPPROTO_IPV6, IPV6_V6ONLY> v6_only;
+#else
+typedef asio::detail::socket_option::boolean<
+ asio::detail::custom_socket_option_level,
+ asio::detail::always_fail_option> v6_only;
+#endif
+
+} // namespace ip
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IP_V6_ONLY_HPP
diff --git a/src/libtorrent/asio/is_read_buffered.hpp b/src/libtorrent/asio/is_read_buffered.hpp
new file mode 100644
index 0000000..53b8f34
--- /dev/null
+++ b/src/libtorrent/asio/is_read_buffered.hpp
@@ -0,0 +1,62 @@
+//
+// is_read_buffered.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IS_READ_BUFFERED_HPP
+#define ASIO_IS_READ_BUFFERED_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffered_read_stream_fwd.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+
+namespace asio {
+
+namespace detail {
+
+template <typename Stream>
+char is_read_buffered_helper(buffered_stream<Stream>* s);
+
+template <typename Stream>
+char is_read_buffered_helper(buffered_read_stream<Stream>* s);
+
+struct is_read_buffered_big_type { char data[10]; };
+is_read_buffered_big_type is_read_buffered_helper(...);
+
+} // namespace detail
+
+/// The is_read_buffered class is a traits class that may be used to determine
+/// whether a stream type supports buffering of read data.
+template <typename Stream>
+class is_read_buffered
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The value member is true only if the Stream type supports buffering of
+ /// read data.
+ static const bool value;
+#else
+ BOOST_STATIC_CONSTANT(bool,
+ value = sizeof(detail::is_read_buffered_helper((Stream*)0)) == 1);
+#endif
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IS_READ_BUFFERED_HPP
diff --git a/src/libtorrent/asio/is_write_buffered.hpp b/src/libtorrent/asio/is_write_buffered.hpp
new file mode 100644
index 0000000..4231554
--- /dev/null
+++ b/src/libtorrent/asio/is_write_buffered.hpp
@@ -0,0 +1,62 @@
+//
+// is_write_buffered.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IS_WRITE_BUFFERED_HPP
+#define ASIO_IS_WRITE_BUFFERED_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffered_stream_fwd.hpp"
+#include "asio/buffered_write_stream_fwd.hpp"
+
+namespace asio {
+
+namespace detail {
+
+template <typename Stream>
+char is_write_buffered_helper(buffered_stream<Stream>* s);
+
+template <typename Stream>
+char is_write_buffered_helper(buffered_write_stream<Stream>* s);
+
+struct is_write_buffered_big_type { char data[10]; };
+is_write_buffered_big_type is_write_buffered_helper(...);
+
+} // namespace detail
+
+/// The is_write_buffered class is a traits class that may be used to determine
+/// whether a stream type supports buffering of written data.
+template <typename Stream>
+class is_write_buffered
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The value member is true only if the Stream type supports buffering of
+ /// written data.
+ static const bool value;
+#else
+ BOOST_STATIC_CONSTANT(bool,
+ value = sizeof(detail::is_write_buffered_helper((Stream*)0)) == 1);
+#endif
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IS_WRITE_BUFFERED_HPP
diff --git a/src/libtorrent/asio/placeholders.hpp b/src/libtorrent/asio/placeholders.hpp
new file mode 100644
index 0000000..bf93c7d
--- /dev/null
+++ b/src/libtorrent/asio/placeholders.hpp
@@ -0,0 +1,107 @@
+//
+// placeholders.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_PLACEHOLDERS_HPP
+#define ASIO_PLACEHOLDERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/bind/arg.hpp>
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace placeholders {
+
+#if defined(GENERATING_DOCUMENTATION)
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the error argument of a handler for any of the asynchronous functions.
+unspecified error;
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the bytes_transferred argument of a handler for asynchronous functions such
+/// as asio::basic_stream_socket::async_write_some or
+/// asio::async_write.
+unspecified bytes_transferred;
+
+/// An argument placeholder, for use with boost::bind(), that corresponds to
+/// the iterator argument of a handler for asynchronous functions such as
+/// asio::basic_resolver::resolve.
+unspecified iterator;
+
+#elif defined(__BORLANDC__) || defined(__GNUC__)
+
+inline boost::arg<1> error()
+{
+ return boost::arg<1>();
+}
+
+inline boost::arg<2> bytes_transferred()
+{
+ return boost::arg<2>();
+}
+
+inline boost::arg<2> iterator()
+{
+ return boost::arg<2>();
+}
+
+#else
+
+namespace detail
+{
+ template <int Number>
+ struct placeholder
+ {
+ static boost::arg<Number>& get()
+ {
+ static boost::arg<Number> result;
+ return result;
+ }
+ };
+}
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
+
+static boost::arg<1>& error
+ = asio::placeholders::detail::placeholder<1>::get();
+static boost::arg<2>& bytes_transferred
+ = asio::placeholders::detail::placeholder<2>::get();
+static boost::arg<2>& iterator
+ = asio::placeholders::detail::placeholder<2>::get();
+
+#else
+
+namespace
+{
+ boost::arg<1>& error
+ = asio::placeholders::detail::placeholder<1>::get();
+ boost::arg<2>& bytes_transferred
+ = asio::placeholders::detail::placeholder<2>::get();
+ boost::arg<2>& iterator
+ = asio::placeholders::detail::placeholder<2>::get();
+} // namespace
+
+#endif
+
+#endif
+
+} // namespace placeholders
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_PLACEHOLDERS_HPP
diff --git a/src/libtorrent/asio/read.hpp b/src/libtorrent/asio/read.hpp
new file mode 100644
index 0000000..46bca26
--- /dev/null
+++ b/src/libtorrent/asio/read.hpp
@@ -0,0 +1,516 @@
+//
+// read.hpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_READ_HPP
+#define ASIO_READ_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_streambuf.hpp"
+#include "asio/error.hpp"
+
+namespace asio {
+
+/**
+ * @defgroup read asio::read
+ */
+/*@{*/
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read(s, asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ * s, buffers,
+ * asio::transfer_all()); @endcode
+ */
+template <typename SyncReadStream, typename MutableBufferSequence>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest read_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the read operation is complete. False
+ * indicates that further calls to the stream's read_some function are required.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::read(s, asio::buffer(data, size),
+ * asio::transfer_at_least(32)); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename SyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest read_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the read operation is complete. False
+ * indicates that further calls to the stream's read_some function are required.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::read(
+ * s, b,
+ * asio::transfer_all()); @endcode
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest read_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the read operation is complete. False
+ * indicates that further calls to the stream's read_some function are required.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncReadStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition);
+
+/// Attempt to read a certain amount of data from a stream before returning.
+/**
+ * This function is used to read a certain number of bytes of data from a
+ * stream. The call will block until one of the following conditions is true:
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b The basic_streambuf object into which the data will be read.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest read_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the read operation is complete. False
+ * indicates that further calls to the stream's read_some function are required.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncReadStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec);
+
+/*@}*/
+/**
+ * @defgroup async_read asio::async_read
+ */
+/*@{*/
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * async_read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream. Although the buffers object may be copied as necessary, ownership of
+ * the underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes copied into the
+ * // buffers. If an error occurred,
+ * // this will be the number of
+ * // bytes successfully transferred
+ * // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::async_read(s, asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read(
+ * s, buffers,
+ * asio::transfer_all(),
+ * handler); @endcode
+ */
+template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename ReadHandler>
+void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+ ReadHandler handler);
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The supplied buffers are full. That is, the bytes transferred is equal to
+ * the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param buffers One or more buffers into which the data will be read. The sum
+ * of the buffer sizes indicates the maximum number of bytes to read from the
+ * stream. Although the buffers object may be copied as necessary, ownership of
+ * the underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest read_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the read operation is complete. False
+ * indicates that further calls to the stream's async_read_some function are
+ * required.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes copied into the
+ * // buffers. If an error occurred,
+ * // this will be the number of
+ * // bytes successfully transferred
+ * // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code asio::async_read(s,
+ * asio::buffer(data, size),
+ * asio::transfer_at_least(32),
+ * handler); @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncReadStream, typename MutableBufferSequence,
+ typename CompletionCondition, typename ReadHandler>
+void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
+ CompletionCondition completion_condition, ReadHandler handler);
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * async_read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A basic_streambuf object into which the data will be read. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes copied into the
+ * // buffers. If an error occurred,
+ * // this will be the number of
+ * // bytes successfully transferred
+ * // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::async_read(
+ * s, b,
+ * asio::transfer_all(),
+ * handler); @endcode
+ */
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
+ ReadHandler handler);
+
+/// Start an asynchronous operation to read a certain amount of data from a
+/// stream.
+/**
+ * This function is used to asynchronously read a certain number of bytes of
+ * data from a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions is
+ * true:
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * async_read_some function.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A basic_streambuf object into which the data will be read. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the read operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest read_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the read operation is complete. False
+ * indicates that further calls to the stream's async_read_some function are
+ * required.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes copied into the
+ * // buffers. If an error occurred,
+ * // this will be the number of
+ * // bytes successfully transferred
+ * // prior to the error.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ */
+template <typename AsyncReadStream, typename Allocator,
+ typename CompletionCondition, typename ReadHandler>
+void async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, ReadHandler handler);
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/impl/read.ipp"
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_READ_HPP
diff --git a/src/libtorrent/asio/read_until.hpp b/src/libtorrent/asio/read_until.hpp
new file mode 100644
index 0000000..8c7e3d3
--- /dev/null
+++ b/src/libtorrent/asio/read_until.hpp
@@ -0,0 +1,452 @@
+//
+// read_until.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_READ_UNTIL_HPP
+#define ASIO_READ_UNTIL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/regex.hpp>
+#include <string>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_streambuf.hpp"
+#include "asio/error.hpp"
+
+namespace asio {
+
+/**
+ * @defgroup read_until asio::read_until
+ */
+/*@{*/
+
+/// Read data into a streambuf until a delimiter is encountered.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * asio::read_until(s, b, '\n');
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line); @endcode
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim);
+
+/// Read data into a streambuf until a delimiter is encountered.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter. Returns 0 if an error occurred.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, char delim,
+ asio::error_code& ec);
+
+/// Read data into a streambuf until a delimiter is encountered.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * asio::read_until(s, b, "\r\n");
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line); @endcode
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim);
+
+/// Read data into a streambuf until a delimiter is encountered.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains the specified delimiter. The call will block
+ * until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains the
+ * delimiter, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the delimiter. Returns 0 if an error occurred.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim,
+ asio::error_code& ec);
+
+/// Read data into a streambuf until a regular expression is located.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains some data that matches a regular expression.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li A substring of the streambuf's get area matches the regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains data that
+ * matches the regular expression, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the substring that matches the regular expression.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To read data into a streambuf until a CR-LF sequence is encountered:
+ * @code asio::streambuf b;
+ * asio::read_until(s, b, boost::regex("\r\n"));
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line); @endcode
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr);
+
+/// Read data into a streambuf until a regular expression is located.
+/**
+ * This function is used to read data into the specified streambuf until the
+ * streambuf's get area contains some data that matches a regular expression.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li A substring of the streambuf's get area matches the regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * read_some function. If the streambuf's get area already contains data that
+ * matches the regular expression, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the SyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read.
+ *
+ * @param expr The regular expression.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes in the streambuf's get area up to and including
+ * the substring that matches the regular expression. Returns 0 if an error
+ * occurred.
+ */
+template <typename SyncReadStream, typename Allocator>
+std::size_t read_until(SyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+ asio::error_code& ec);
+
+/*@}*/
+/**
+* @defgroup async_read_until asio::async_read_until
+*/
+/*@{*/
+
+/// Start an asynchronous operation to read data into a streambuf until a
+/// delimiter is encountered.
+/**
+ * This function is used to asynchronously read data into the specified
+ * streambuf until the streambuf's get area contains the specified delimiter.
+ * The function call always returns immediately. The asynchronous operation
+ * will continue until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function. If the streambuf's get area already contains the
+ * delimiter, the asynchronous operation completes immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read. Ownership of
+ * the streambuf is retained by the caller, which must guarantee that it remains
+ * valid until the handler is called.
+ *
+ * @param delim The delimiter character.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // The number of bytes in the
+ * // streambuf's get area up to
+ * // and including the delimiter.
+ * // 0 if an error occurred.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To asynchronously read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ * if (!e)
+ * {
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line);
+ * ...
+ * }
+ * }
+ * ...
+ * asio::async_read_until(s, b, '\n', handler); @endcode
+ */
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b,
+ char delim, ReadHandler handler);
+
+/// Start an asynchronous operation to read data into a streambuf until a
+/// delimiter is encountered.
+/**
+ * This function is used to asynchronously read data into the specified
+ * streambuf until the streambuf's get area contains the specified delimiter.
+ * The function call always returns immediately. The asynchronous operation
+ * will continue until one of the following conditions is true:
+ *
+ * @li The get area of the streambuf contains the specified delimiter.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function. If the streambuf's get area already contains the
+ * delimiter, the asynchronous operation completes immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read. Ownership of
+ * the streambuf is retained by the caller, which must guarantee that it remains
+ * valid until the handler is called.
+ *
+ * @param delim The delimiter string.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // The number of bytes in the
+ * // streambuf's get area up to
+ * // and including the delimiter.
+ * // 0 if an error occurred.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To asynchronously read data into a streambuf until a newline is encountered:
+ * @code asio::streambuf b;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ * if (!e)
+ * {
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line);
+ * ...
+ * }
+ * }
+ * ...
+ * asio::async_read_until(s, b, "\r\n", handler); @endcode
+ */
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const std::string& delim,
+ ReadHandler handler);
+
+/// Start an asynchronous operation to read data into a streambuf until a
+/// regular expression is located.
+/**
+ * This function is used to asynchronously read data into the specified
+ * streambuf until the streambuf's get area contains some data that matches a
+ * regular expression. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li A substring of the streambuf's get area matches the regular expression.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of zero or more calls to the stream's
+ * async_read_some function. If the streambuf's get area already contains data
+ * that matches the regular expression, the function returns immediately.
+ *
+ * @param s The stream from which the data is to be read. The type must support
+ * the AsyncReadStream concept.
+ *
+ * @param b A streambuf object into which the data will be read. Ownership of
+ * the streambuf is retained by the caller, which must guarantee that it remains
+ * valid until the handler is called.
+ *
+ * @param expr The regular expression.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // The number of bytes in the
+ * // streambuf's get area up to
+ * // and including the substring
+ * // that matches the regular.
+ * // expression. 0 if an error
+ * // occurred.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To asynchronously read data into a streambuf until a CR-LF sequence is
+ * encountered:
+ * @code asio::streambuf b;
+ * ...
+ * void handler(const asio::error_code& e, std::size_t size)
+ * {
+ * if (!e)
+ * {
+ * std::istream is(&b);
+ * std::string line;
+ * std::getline(is, line);
+ * ...
+ * }
+ * }
+ * ...
+ * asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode
+ */
+template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
+void async_read_until(AsyncReadStream& s,
+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
+ ReadHandler handler);
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/impl/read_until.ipp"
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_READ_UNTIL_HPP
diff --git a/src/libtorrent/asio/socket_acceptor_service.hpp b/src/libtorrent/asio/socket_acceptor_service.hpp
new file mode 100644
index 0000000..48a6df2
--- /dev/null
+++ b/src/libtorrent/asio/socket_acceptor_service.hpp
@@ -0,0 +1,225 @@
+//
+// socket_acceptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SOCKET_ACCEPTOR_SERVICE_HPP
+#define ASIO_SOCKET_ACCEPTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/basic_socket.hpp"
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/reactive_socket_service.hpp"
+#include "asio/detail/win_iocp_socket_service.hpp"
+
+namespace asio {
+
+/// Default service implementation for a socket acceptor.
+template <typename Protocol>
+class socket_acceptor_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public asio::io_service::service
+#else
+ : public asio::detail::service_base<socket_acceptor_service<Protocol> >
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static asio::io_service::id id;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename protocol_type::endpoint endpoint_type;
+
+private:
+ // The type of the platform-specific implementation.
+#if defined(ASIO_HAS_IOCP)
+ typedef detail::win_iocp_socket_service<Protocol> service_impl_type;
+#elif defined(ASIO_HAS_EPOLL)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::epoll_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_KQUEUE)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::kqueue_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_DEV_POLL)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::dev_poll_reactor<false> > service_impl_type;
+#else
+ typedef detail::reactive_socket_service<
+ Protocol, detail::select_reactor<false> > service_impl_type;
+#endif
+
+public:
+ /// The native type of the socket acceptor.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef typename service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// The native acceptor type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_type;
+#else
+ typedef typename service_impl_type::native_type native_type;
+#endif
+
+ /// Construct a new socket acceptor service for the specified io_service.
+ explicit socket_acceptor_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ socket_acceptor_service<Protocol> >(io_service),
+ service_impl_(asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Construct a new socket acceptor implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+ /// Destroy a socket acceptor implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ /// Open a new socket acceptor implementation.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::error_code& ec)
+ {
+ return service_impl_.open(impl, protocol, ec);
+ }
+
+ /// Assign an existing native acceptor to a socket acceptor.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_type& native_acceptor,
+ asio::error_code& ec)
+ {
+ return service_impl_.assign(impl, protocol, native_acceptor, ec);
+ }
+
+ /// Determine whether the acceptor is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return service_impl_.is_open(impl);
+ }
+
+ /// Cancel all asynchronous operations associated with the acceptor.
+ asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return service_impl_.cancel(impl, ec);
+ }
+
+ /// Bind the socket acceptor to the specified local endpoint.
+ asio::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ return service_impl_.bind(impl, endpoint, ec);
+ }
+
+ /// Place the socket acceptor into the state where it will listen for new
+ /// connections.
+ asio::error_code listen(implementation_type& impl, int backlog,
+ asio::error_code& ec)
+ {
+ return service_impl_.listen(impl, backlog, ec);
+ }
+
+ /// Close a socket acceptor implementation.
+ asio::error_code close(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return service_impl_.close(impl, ec);
+ }
+
+ /// Get the native acceptor implementation.
+ native_type native(implementation_type& impl)
+ {
+ return service_impl_.native(impl);
+ }
+
+ /// Set a socket option.
+ template <typename SettableSocketOption>
+ asio::error_code set_option(implementation_type& impl,
+ const SettableSocketOption& option, asio::error_code& ec)
+ {
+ return service_impl_.set_option(impl, option, ec);
+ }
+
+ /// Get a socket option.
+ template <typename GettableSocketOption>
+ asio::error_code get_option(const implementation_type& impl,
+ GettableSocketOption& option, asio::error_code& ec) const
+ {
+ return service_impl_.get_option(impl, option, ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ template <typename IoControlCommand>
+ asio::error_code io_control(implementation_type& impl,
+ IoControlCommand& command, asio::error_code& ec)
+ {
+ return service_impl_.io_control(impl, command, ec);
+ }
+
+ /// Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.local_endpoint(impl, ec);
+ }
+
+ /// Accept a new connection.
+ template <typename SocketService>
+ asio::error_code accept(implementation_type& impl,
+ basic_socket<protocol_type, SocketService>& peer,
+ endpoint_type* peer_endpoint, asio::error_code& ec)
+ {
+ return service_impl_.accept(impl, peer, peer_endpoint, ec);
+ }
+
+ /// Start an asynchronous accept.
+ template <typename SocketService, typename AcceptHandler>
+ void async_accept(implementation_type& impl,
+ basic_socket<protocol_type, SocketService>& peer,
+ endpoint_type* peer_endpoint, AcceptHandler handler)
+ {
+ service_impl_.async_accept(impl, peer, peer_endpoint, handler);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SOCKET_ACCEPTOR_SERVICE_HPP
diff --git a/src/libtorrent/asio/socket_base.hpp b/src/libtorrent/asio/socket_base.hpp
new file mode 100644
index 0000000..67fe688
--- /dev/null
+++ b/src/libtorrent/asio/socket_base.hpp
@@ -0,0 +1,515 @@
+//
+// socket_base.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SOCKET_BASE_HPP
+#define ASIO_SOCKET_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/io_control.hpp"
+#include "asio/detail/socket_option.hpp"
+#include "asio/detail/socket_types.hpp"
+
+namespace asio {
+
+/// The socket_base class is used as a base for the basic_stream_socket and
+/// basic_datagram_socket class templates so that we have a common place to
+/// define the shutdown_type and enum.
+class socket_base
+{
+public:
+ /// Different ways a socket may be shutdown.
+ enum shutdown_type
+ {
+#if defined(GENERATING_DOCUMENTATION)
+ /// Shutdown the receive side of the socket.
+ shutdown_receive = implementation_defined,
+
+ /// Shutdown the send side of the socket.
+ shutdown_send = implementation_defined,
+
+ /// Shutdown both send and receive on the socket.
+ shutdown_both = implementation_defined
+#else
+ shutdown_receive = asio::detail::shutdown_receive,
+ shutdown_send = asio::detail::shutdown_send,
+ shutdown_both = asio::detail::shutdown_both
+#endif
+ };
+
+ /// Bitmask type for flags that can be passed to send and receive operations.
+ typedef int message_flags;
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// Peek at incoming data without removing it from the input queue.
+ static const int message_peek = implementation_defined;
+
+ /// Process out-of-band data.
+ static const int message_out_of_band = implementation_defined;
+
+ /// Specify that the data should not be subject to routing.
+ static const int message_do_not_route = implementation_defined;
+#else
+ BOOST_STATIC_CONSTANT(int,
+ message_peek = asio::detail::message_peek);
+ BOOST_STATIC_CONSTANT(int,
+ message_out_of_band = asio::detail::message_out_of_band);
+ BOOST_STATIC_CONSTANT(int,
+ message_do_not_route = asio::detail::message_do_not_route);
+#endif
+
+ /// Socket option to permit sending of broadcast messages.
+ /**
+ * Implements the SOL_SOCKET/SO_BROADCAST socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::socket_base::broadcast option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::socket_base::broadcast option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Boolean_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined broadcast;
+#else
+ typedef asio::detail::socket_option::boolean<
+ SOL_SOCKET, SO_BROADCAST> broadcast;
+#endif
+
+ /// Socket option to enable socket-level debugging.
+ /**
+ * Implements the SOL_SOCKET/SO_DEBUG socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::debug option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::debug option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Boolean_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined debug;
+#else
+ typedef asio::detail::socket_option::boolean<
+ SOL_SOCKET, SO_DEBUG> debug;
+#endif
+
+ /// Socket option to prevent routing, use local interfaces only.
+ /**
+ * Implements the SOL_SOCKET/SO_DONTROUTE socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::socket_base::do_not_route option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::udp::socket socket(io_service);
+ * ...
+ * asio::socket_base::do_not_route option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Boolean_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined do_not_route;
+#else
+ typedef asio::detail::socket_option::boolean<
+ SOL_SOCKET, SO_DONTROUTE> do_not_route;
+#endif
+
+ /// Socket option to send keep-alives.
+ /**
+ * Implements the SOL_SOCKET/SO_KEEPALIVE socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::keep_alive option(true);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::keep_alive option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Boolean_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined keep_alive;
+#else
+ typedef asio::detail::socket_option::boolean<
+ SOL_SOCKET, SO_KEEPALIVE> keep_alive;
+#endif
+
+ /// Socket option for the send buffer size of a socket.
+ /**
+ * Implements the SOL_SOCKET/SO_SNDBUF socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::send_buffer_size option(8192);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::send_buffer_size option;
+ * socket.get_option(option);
+ * int size = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Integer_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined send_buffer_size;
+#else
+ typedef asio::detail::socket_option::integer<
+ SOL_SOCKET, SO_SNDBUF> send_buffer_size;
+#endif
+
+ /// Socket option for the send low watermark.
+ /**
+ * Implements the SOL_SOCKET/SO_SNDLOWAT socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::send_low_watermark option(1024);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::send_low_watermark option;
+ * socket.get_option(option);
+ * int size = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Integer_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined send_low_watermark;
+#else
+ typedef asio::detail::socket_option::integer<
+ SOL_SOCKET, SO_SNDLOWAT> send_low_watermark;
+#endif
+
+ /// Socket option for the receive buffer size of a socket.
+ /**
+ * Implements the SOL_SOCKET/SO_RCVBUF socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::receive_buffer_size option(8192);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::receive_buffer_size option;
+ * socket.get_option(option);
+ * int size = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Integer_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined receive_buffer_size;
+#else
+ typedef asio::detail::socket_option::integer<
+ SOL_SOCKET, SO_RCVBUF> receive_buffer_size;
+#endif
+
+ /// Socket option for the receive low watermark.
+ /**
+ * Implements the SOL_SOCKET/SO_RCVLOWAT socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::receive_low_watermark option(1024);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::receive_low_watermark option;
+ * socket.get_option(option);
+ * int size = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Integer_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined receive_low_watermark;
+#else
+ typedef asio::detail::socket_option::integer<
+ SOL_SOCKET, SO_RCVLOWAT> receive_low_watermark;
+#endif
+
+ /// Socket option to allow the socket to be bound to an address that is
+ /// already in use.
+ /**
+ * Implements the SOL_SOCKET/SO_REUSEADDR socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::socket_base::reuse_address option(true);
+ * acceptor.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::socket_base::reuse_address option;
+ * acceptor.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Boolean_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined reuse_address;
+#else
+ typedef asio::detail::socket_option::boolean<
+ SOL_SOCKET, SO_REUSEADDR> reuse_address;
+#endif
+
+ /// Socket option to specify whether the socket lingers on close if unsent
+ /// data is present.
+ /**
+ * Implements the SOL_SOCKET/SO_LINGER socket option.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::linger option(true, 30);
+ * socket.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::linger option;
+ * socket.get_option(option);
+ * bool is_set = option.enabled();
+ * unsigned short timeout = option.timeout();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Linger_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined linger;
+#else
+ typedef asio::detail::socket_option::linger<
+ SOL_SOCKET, SO_LINGER> linger;
+#endif
+
+ /// Socket option to report aborted connections on accept.
+ /**
+ * Implements a custom socket option that determines whether or not an accept
+ * operation is permitted to fail with asio::error::connection_aborted.
+ * By default the option is false.
+ *
+ * @par Examples
+ * Setting the option:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::socket_base::enable_connection_aborted option(true);
+ * acceptor.set_option(option);
+ * @endcode
+ *
+ * @par
+ * Getting the current option value:
+ * @code
+ * asio::ip::tcp::acceptor acceptor(io_service);
+ * ...
+ * asio::socket_base::enable_connection_aborted option;
+ * acceptor.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ *
+ * @par Concepts:
+ * Socket_Option, Boolean_Socket_Option.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined enable_connection_aborted;
+#else
+ typedef asio::detail::socket_option::boolean<
+ asio::detail::custom_socket_option_level,
+ asio::detail::enable_connection_aborted_option>
+ enable_connection_aborted;
+#endif
+
+ /// IO control command to set the blocking mode of the socket.
+ /**
+ * Implements the FIONBIO IO control command.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::non_blocking_io command(true);
+ * socket.io_control(command);
+ * @endcode
+ *
+ * @par Concepts:
+ * IO_Control_Command, Boolean_IO_Control_Command.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined non_blocking_io;
+#else
+ typedef asio::detail::io_control::non_blocking_io non_blocking_io;
+#endif
+
+ /// IO control command to get the amount of data that can be read without
+ /// blocking.
+ /**
+ * Implements the FIONREAD IO control command.
+ *
+ * @par Example
+ * @code
+ * asio::ip::tcp::socket socket(io_service);
+ * ...
+ * asio::socket_base::bytes_readable command(true);
+ * socket.io_control(command);
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ *
+ * @par Concepts:
+ * IO_Control_Command, Size_IO_Control_Command.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined bytes_readable;
+#else
+ typedef asio::detail::io_control::bytes_readable bytes_readable;
+#endif
+
+ /// The maximum length of the queue of pending incoming connections.
+#if defined(GENERATING_DOCUMENTATION)
+ static const int max_connections = implementation_defined;
+#else
+ BOOST_STATIC_CONSTANT(int, max_connections = SOMAXCONN);
+#endif
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ ~socket_base()
+ {
+ }
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+private:
+ // Workaround to enable the empty base optimisation with Borland C++.
+ char dummy_;
+#endif
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SOCKET_BASE_HPP
diff --git a/src/libtorrent/asio/ssl.hpp b/src/libtorrent/asio/ssl.hpp
new file mode 100644
index 0000000..c661137
--- /dev/null
+++ b/src/libtorrent/asio/ssl.hpp
@@ -0,0 +1,26 @@
+//
+// ssl.hpp
+// ~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_HPP
+#define ASIO_SSL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/ssl/basic_context.hpp"
+#include "asio/ssl/context.hpp"
+#include "asio/ssl/context_base.hpp"
+#include "asio/ssl/context_service.hpp"
+#include "asio/ssl/stream.hpp"
+#include "asio/ssl/stream_base.hpp"
+#include "asio/ssl/stream_service.hpp"
+
+#endif // ASIO_SSL_HPP
diff --git a/src/libtorrent/asio/ssl/basic_context.hpp b/src/libtorrent/asio/ssl/basic_context.hpp
new file mode 100644
index 0000000..c1346e6
--- /dev/null
+++ b/src/libtorrent/asio/ssl/basic_context.hpp
@@ -0,0 +1,434 @@
+//
+// basic_context.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_BASIC_CONTEXT_HPP
+#define ASIO_SSL_BASIC_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <string>
+#include <boost/noncopyable.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/ssl/context_base.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// SSL context.
+template <typename Service>
+class basic_context
+ : public context_base,
+ private boost::noncopyable
+{
+public:
+ /// The type of the service that will be used to provide context operations.
+ typedef Service service_type;
+
+ /// The native implementation type of the locking dispatcher.
+ typedef typename service_type::impl_type impl_type;
+
+ /// Constructor.
+ basic_context(asio::io_service& io_service, method m)
+ : service_(asio::use_service<Service>(io_service)),
+ impl_(service_.null())
+ {
+ service_.create(impl_, m);
+ }
+
+ /// Destructor.
+ ~basic_context()
+ {
+ service_.destroy(impl_);
+ }
+
+ /// Get the underlying implementation in the native type.
+ /**
+ * This function may be used to obtain the underlying implementation of the
+ * context. This is intended to allow access to context functionality that is
+ * not otherwise provided.
+ */
+ impl_type impl()
+ {
+ return impl_;
+ }
+
+ /// Set options on the context.
+ /**
+ * This function may be used to configure the SSL options used by the context.
+ *
+ * @param o A bitmask of options. The available option values are defined in
+ * the context_base class. The options are bitwise-ored with any existing
+ * value for the options.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void set_options(options o)
+ {
+ asio::error_code ec;
+ service_.set_options(impl_, o, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Set options on the context.
+ /**
+ * This function may be used to configure the SSL options used by the context.
+ *
+ * @param o A bitmask of options. The available option values are defined in
+ * the context_base class. The options are bitwise-ored with any existing
+ * value for the options.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code set_options(options o,
+ asio::error_code& ec)
+ {
+ return service_.set_options(impl_, o, ec);
+ }
+
+ /// Set the peer verification mode.
+ /**
+ * This function may be used to configure the peer verification mode used by
+ * the context.
+ *
+ * @param v A bitmask of peer verification modes. The available verify_mode
+ * values are defined in the context_base class.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void set_verify_mode(verify_mode v)
+ {
+ asio::error_code ec;
+ service_.set_verify_mode(impl_, v, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Set the peer verification mode.
+ /**
+ * This function may be used to configure the peer verification mode used by
+ * the context.
+ *
+ * @param v A bitmask of peer verification modes. The available verify_mode
+ * values are defined in the context_base class.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code set_verify_mode(verify_mode v,
+ asio::error_code& ec)
+ {
+ return service_.set_verify_mode(impl_, v, ec);
+ }
+
+ /// Load a certification authority file for performing verification.
+ /**
+ * This function is used to load one or more trusted certification authorities
+ * from a file.
+ *
+ * @param filename The name of a file containing certification authority
+ * certificates in PEM format.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void load_verify_file(const std::string& filename)
+ {
+ asio::error_code ec;
+ service_.load_verify_file(impl_, filename, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Load a certification authority file for performing verification.
+ /**
+ * This function is used to load the certificates for one or more trusted
+ * certification authorities from a file.
+ *
+ * @param filename The name of a file containing certification authority
+ * certificates in PEM format.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code load_verify_file(const std::string& filename,
+ asio::error_code& ec)
+ {
+ return service_.load_verify_file(impl_, filename, ec);
+ }
+
+ /// Add a directory containing certificate authority files to be used for
+ /// performing verification.
+ /**
+ * This function is used to specify the name of a directory containing
+ * certification authority certificates. Each file in the directory must
+ * contain a single certificate. The files must be named using the subject
+ * name's hash and an extension of ".0".
+ *
+ * @param path The name of a directory containing the certificates.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void add_verify_path(const std::string& path)
+ {
+ asio::error_code ec;
+ service_.add_verify_path(impl_, path, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Add a directory containing certificate authority files to be used for
+ /// performing verification.
+ /**
+ * This function is used to specify the name of a directory containing
+ * certification authority certificates. Each file in the directory must
+ * contain a single certificate. The files must be named using the subject
+ * name's hash and an extension of ".0".
+ *
+ * @param path The name of a directory containing the certificates.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code add_verify_path(const std::string& path,
+ asio::error_code& ec)
+ {
+ return service_.add_verify_path(impl_, path, ec);
+ }
+
+ /// Use a certificate from a file.
+ /**
+ * This function is used to load a certificate into the context from a file.
+ *
+ * @param filename The name of the file containing the certificate.
+ *
+ * @param format The file format (ASN.1 or PEM).
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void use_certificate_file(const std::string& filename, file_format format)
+ {
+ asio::error_code ec;
+ service_.use_certificate_file(impl_, filename, format, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Use a certificate from a file.
+ /**
+ * This function is used to load a certificate into the context from a file.
+ *
+ * @param filename The name of the file containing the certificate.
+ *
+ * @param format The file format (ASN.1 or PEM).
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code use_certificate_file(const std::string& filename,
+ file_format format, asio::error_code& ec)
+ {
+ return service_.use_certificate_file(impl_, filename, format, ec);
+ }
+
+ /// Use a certificate chain from a file.
+ /**
+ * This function is used to load a certificate chain into the context from a
+ * file.
+ *
+ * @param filename The name of the file containing the certificate. The file
+ * must use the PEM format.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void use_certificate_chain_file(const std::string& filename)
+ {
+ asio::error_code ec;
+ service_.use_certificate_chain_file(impl_, filename, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Use a certificate chain from a file.
+ /**
+ * This function is used to load a certificate chain into the context from a
+ * file.
+ *
+ * @param filename The name of the file containing the certificate. The file
+ * must use the PEM format.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code use_certificate_chain_file(
+ const std::string& filename, asio::error_code& ec)
+ {
+ return service_.use_certificate_chain_file(impl_, filename, ec);
+ }
+
+ /// Use a private key from a file.
+ /**
+ * This function is used to load a private key into the context from a file.
+ *
+ * @param filename The name of the file containing the private key.
+ *
+ * @param format The file format (ASN.1 or PEM).
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void use_private_key_file(const std::string& filename, file_format format)
+ {
+ asio::error_code ec;
+ service_.use_private_key_file(impl_, filename, format, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Use a private key from a file.
+ /**
+ * This function is used to load a private key into the context from a file.
+ *
+ * @param filename The name of the file containing the private key.
+ *
+ * @param format The file format (ASN.1 or PEM).
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code use_private_key_file(const std::string& filename,
+ file_format format, asio::error_code& ec)
+ {
+ return service_.use_private_key_file(impl_, filename, format, ec);
+ }
+
+ /// Use an RSA private key from a file.
+ /**
+ * This function is used to load an RSA private key into the context from a
+ * file.
+ *
+ * @param filename The name of the file containing the RSA private key.
+ *
+ * @param format The file format (ASN.1 or PEM).
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void use_rsa_private_key_file(const std::string& filename, file_format format)
+ {
+ asio::error_code ec;
+ service_.use_rsa_private_key_file(impl_, filename, format, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Use an RSA private key from a file.
+ /**
+ * This function is used to load an RSA private key into the context from a
+ * file.
+ *
+ * @param filename The name of the file containing the RSA private key.
+ *
+ * @param format The file format (ASN.1 or PEM).
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code use_rsa_private_key_file(
+ const std::string& filename, file_format format,
+ asio::error_code& ec)
+ {
+ return service_.use_rsa_private_key_file(impl_, filename, format, ec);
+ }
+
+ /// Use the specified file to obtain the temporary Diffie-Hellman parameters.
+ /**
+ * This function is used to load Diffie-Hellman parameters into the context
+ * from a file.
+ *
+ * @param filename The name of the file containing the Diffie-Hellman
+ * parameters. The file must use the PEM format.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void use_tmp_dh_file(const std::string& filename)
+ {
+ asio::error_code ec;
+ service_.use_tmp_dh_file(impl_, filename, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Use the specified file to obtain the temporary Diffie-Hellman parameters.
+ /**
+ * This function is used to load Diffie-Hellman parameters into the context
+ * from a file.
+ *
+ * @param filename The name of the file containing the Diffie-Hellman
+ * parameters. The file must use the PEM format.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code use_tmp_dh_file(const std::string& filename,
+ asio::error_code& ec)
+ {
+ return service_.use_tmp_dh_file(impl_, filename, ec);
+ }
+
+ /// Set the password callback.
+ /**
+ * This function is used to specify a callback function to obtain password
+ * information about an encrypted key in PEM format.
+ *
+ * @param callback The function object to be used for obtaining the password.
+ * The function signature of the handler must be:
+ * @code std::string password_callback(
+ * std::size_t max_length, // The maximum size for a password.
+ * password_purpose purpose // Whether password is for reading or writing.
+ * ); @endcode
+ * The return value of the callback is a string containing the password.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ template <typename PasswordCallback>
+ void set_password_callback(PasswordCallback callback)
+ {
+ asio::error_code ec;
+ service_.set_password_callback(impl_, callback, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Set the password callback.
+ /**
+ * This function is used to specify a callback function to obtain password
+ * information about an encrypted key in PEM format.
+ *
+ * @param callback The function object to be used for obtaining the password.
+ * The function signature of the handler must be:
+ * @code std::string password_callback(
+ * std::size_t max_length, // The maximum size for a password.
+ * password_purpose purpose // Whether password is for reading or writing.
+ * ); @endcode
+ * The return value of the callback is a string containing the password.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ template <typename PasswordCallback>
+ asio::error_code set_password_callback(PasswordCallback callback,
+ asio::error_code& ec)
+ {
+ return service_.set_password_callback(impl_, callback, ec);
+ }
+
+private:
+ /// The backend service implementation.
+ service_type& service_;
+
+ /// The underlying native implementation.
+ impl_type impl_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_BASIC_CONTEXT_HPP
diff --git a/src/libtorrent/asio/ssl/context.hpp b/src/libtorrent/asio/ssl/context.hpp
new file mode 100644
index 0000000..7c29e01
--- /dev/null
+++ b/src/libtorrent/asio/ssl/context.hpp
@@ -0,0 +1,35 @@
+//
+// context.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_CONTEXT_HPP
+#define ASIO_SSL_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/ssl/basic_context.hpp"
+#include "asio/ssl/context_service.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// Typedef for the typical usage of context.
+typedef basic_context<context_service> context;
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_CONTEXT_HPP
diff --git a/src/libtorrent/asio/ssl/context_base.hpp b/src/libtorrent/asio/ssl/context_base.hpp
new file mode 100644
index 0000000..cc8a2a5
--- /dev/null
+++ b/src/libtorrent/asio/ssl/context_base.hpp
@@ -0,0 +1,164 @@
+//
+// context_base.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_CONTEXT_BASE_HPP
+#define ASIO_SSL_CONTEXT_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/ssl/detail/openssl_types.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// The context_base class is used as a base for the basic_context class
+/// template so that we have a common place to define various enums.
+class context_base
+{
+public:
+ /// Different methods supported by a context.
+ enum method
+ {
+ /// Generic SSL version 2.
+ sslv2,
+
+ /// SSL version 2 client.
+ sslv2_client,
+
+ /// SSL version 2 server.
+ sslv2_server,
+
+ /// Generic SSL version 3.
+ sslv3,
+
+ /// SSL version 3 client.
+ sslv3_client,
+
+ /// SSL version 3 server.
+ sslv3_server,
+
+ /// Generic TLS version 1.
+ tlsv1,
+
+ /// TLS version 1 client.
+ tlsv1_client,
+
+ /// TLS version 1 server.
+ tlsv1_server,
+
+ /// Generic SSL/TLS.
+ sslv23,
+
+ /// SSL/TLS client.
+ sslv23_client,
+
+ /// SSL/TLS server.
+ sslv23_server
+ };
+
+ /// Bitmask type for SSL options.
+ typedef int options;
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// Implement various bug workarounds.
+ static const int default_workarounds = implementation_defined;
+
+ /// Always create a new key when using tmp_dh parameters.
+ static const int single_dh_use = implementation_defined;
+
+ /// Disable SSL v2.
+ static const int no_sslv2 = implementation_defined;
+
+ /// Disable SSL v3.
+ static const int no_sslv3 = implementation_defined;
+
+ /// Disable TLS v1.
+ static const int no_tlsv1 = implementation_defined;
+#else
+ BOOST_STATIC_CONSTANT(int, default_workarounds = SSL_OP_ALL);
+ BOOST_STATIC_CONSTANT(int, single_dh_use = SSL_OP_SINGLE_DH_USE);
+ BOOST_STATIC_CONSTANT(int, no_sslv2 = SSL_OP_NO_SSLv2);
+ BOOST_STATIC_CONSTANT(int, no_sslv3 = SSL_OP_NO_SSLv3);
+ BOOST_STATIC_CONSTANT(int, no_tlsv1 = SSL_OP_NO_TLSv1);
+#endif
+
+ /// File format types.
+ enum file_format
+ {
+ /// ASN.1 file.
+ asn1,
+
+ /// PEM file.
+ pem
+ };
+
+ /// Bitmask type for peer verification.
+ typedef int verify_mode;
+
+#if defined(GENERATING_DOCUMENTATION)
+ /// No verification.
+ static const int verify_none = implementation_defined;
+
+ /// Verify the peer.
+ static const int verify_peer = implementation_defined;
+
+ /// Fail verification if the peer has no certificate. Ignored unless
+ /// verify_peer is set.
+ static const int verify_fail_if_no_peer_cert = implementation_defined;
+
+ /// Do not request client certificate on renegotiation. Ignored unless
+ /// verify_peer is set.
+ static const int verify_client_once = implementation_defined;
+#else
+ BOOST_STATIC_CONSTANT(int, verify_none = SSL_VERIFY_NONE);
+ BOOST_STATIC_CONSTANT(int, verify_peer = SSL_VERIFY_PEER);
+ BOOST_STATIC_CONSTANT(int,
+ verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ BOOST_STATIC_CONSTANT(int, verify_client_once = SSL_VERIFY_CLIENT_ONCE);
+#endif
+
+ /// Purpose of PEM password.
+ enum password_purpose
+ {
+ /// The password is needed for reading/decryption.
+ for_reading,
+
+ /// The password is needed for writing/encryption.
+ for_writing
+ };
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ ~context_base()
+ {
+ }
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+private:
+ // Workaround to enable the empty base optimisation with Borland C++.
+ char dummy_;
+#endif
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_CONTEXT_BASE_HPP
diff --git a/src/libtorrent/asio/ssl/context_service.hpp b/src/libtorrent/asio/ssl/context_service.hpp
new file mode 100644
index 0000000..0bdaf75
--- /dev/null
+++ b/src/libtorrent/asio/ssl/context_service.hpp
@@ -0,0 +1,175 @@
+//
+// context_service.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_CONTEXT_SERVICE_HPP
+#define ASIO_SSL_CONTEXT_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <string>
+#include <boost/noncopyable.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/ssl/context_base.hpp"
+#include "asio/ssl/detail/openssl_context_service.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// Default service implementation for a context.
+class context_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public asio::io_service::service
+#else
+ : public asio::detail::service_base<context_service>
+#endif
+{
+private:
+ // The type of the platform-specific implementation.
+ typedef detail::openssl_context_service service_impl_type;
+
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static asio::io_service::id id;
+#endif
+
+ /// The type of the context.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined impl_type;
+#else
+ typedef service_impl_type::impl_type impl_type;
+#endif
+
+ /// Constructor.
+ explicit context_service(asio::io_service& io_service)
+ : asio::detail::service_base<context_service>(io_service),
+ service_impl_(asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Return a null context implementation.
+ impl_type null() const
+ {
+ return service_impl_.null();
+ }
+
+ /// Create a new context implementation.
+ void create(impl_type& impl, context_base::method m)
+ {
+ service_impl_.create(impl, m);
+ }
+
+ /// Destroy a context implementation.
+ void destroy(impl_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ /// Set options on the context.
+ asio::error_code set_options(impl_type& impl,
+ context_base::options o, asio::error_code& ec)
+ {
+ return service_impl_.set_options(impl, o, ec);
+ }
+
+ /// Set peer verification mode.
+ asio::error_code set_verify_mode(impl_type& impl,
+ context_base::verify_mode v, asio::error_code& ec)
+ {
+ return service_impl_.set_verify_mode(impl, v, ec);
+ }
+
+ /// Load a certification authority file for performing verification.
+ asio::error_code load_verify_file(impl_type& impl,
+ const std::string& filename, asio::error_code& ec)
+ {
+ return service_impl_.load_verify_file(impl, filename, ec);
+ }
+
+ /// Add a directory containing certification authority files to be used for
+ /// performing verification.
+ asio::error_code add_verify_path(impl_type& impl,
+ const std::string& path, asio::error_code& ec)
+ {
+ return service_impl_.add_verify_path(impl, path, ec);
+ }
+
+ /// Use a certificate from a file.
+ asio::error_code use_certificate_file(impl_type& impl,
+ const std::string& filename, context_base::file_format format,
+ asio::error_code& ec)
+ {
+ return service_impl_.use_certificate_file(impl, filename, format, ec);
+ }
+
+ /// Use a certificate chain from a file.
+ asio::error_code use_certificate_chain_file(impl_type& impl,
+ const std::string& filename, asio::error_code& ec)
+ {
+ return service_impl_.use_certificate_chain_file(impl, filename, ec);
+ }
+
+ /// Use a private key from a file.
+ asio::error_code use_private_key_file(impl_type& impl,
+ const std::string& filename, context_base::file_format format,
+ asio::error_code& ec)
+ {
+ return service_impl_.use_private_key_file(impl, filename, format, ec);
+ }
+
+ /// Use an RSA private key from a file.
+ asio::error_code use_rsa_private_key_file(impl_type& impl,
+ const std::string& filename, context_base::file_format format,
+ asio::error_code& ec)
+ {
+ return service_impl_.use_rsa_private_key_file(impl, filename, format, ec);
+ }
+
+ /// Use the specified file to obtain the temporary Diffie-Hellman parameters.
+ asio::error_code use_tmp_dh_file(impl_type& impl,
+ const std::string& filename, asio::error_code& ec)
+ {
+ return service_impl_.use_tmp_dh_file(impl, filename, ec);
+ }
+
+ /// Set the password callback.
+ template <typename PasswordCallback>
+ asio::error_code set_password_callback(impl_type& impl,
+ PasswordCallback callback, asio::error_code& ec)
+ {
+ return service_impl_.set_password_callback(impl, callback, ec);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_CONTEXT_SERVICE_HPP
diff --git a/src/libtorrent/asio/ssl/detail/openssl_context_service.hpp b/src/libtorrent/asio/ssl/detail/openssl_context_service.hpp
new file mode 100644
index 0000000..5a90d5a
--- /dev/null
+++ b/src/libtorrent/asio/ssl/detail/openssl_context_service.hpp
@@ -0,0 +1,379 @@
+//
+// openssl_context_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
+#define ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstring>
+#include <string>
+#include <boost/function.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/ssl/context_base.hpp"
+#include "asio/ssl/detail/openssl_init.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class openssl_context_service
+ : public asio::detail::service_base<openssl_context_service>
+{
+public:
+ // The native type of the context.
+ typedef ::SSL_CTX* impl_type;
+
+ // The type for the password callback function object.
+ typedef boost::function<std::string(std::size_t,
+ context_base::password_purpose)> password_callback_type;
+
+ // Constructor.
+ openssl_context_service(asio::io_service& io_service)
+ : asio::detail::service_base<openssl_context_service>(io_service)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Return a null context implementation.
+ static impl_type null()
+ {
+ return 0;
+ }
+
+ // Create a new context implementation.
+ void create(impl_type& impl, context_base::method m)
+ {
+ ::SSL_METHOD* ssl_method = 0;
+ switch (m)
+ {
+ case context_base::sslv2:
+ ssl_method = ::SSLv2_method();
+ break;
+ case context_base::sslv2_client:
+ ssl_method = ::SSLv2_client_method();
+ break;
+ case context_base::sslv2_server:
+ ssl_method = ::SSLv2_server_method();
+ break;
+ case context_base::sslv3:
+ ssl_method = ::SSLv3_method();
+ break;
+ case context_base::sslv3_client:
+ ssl_method = ::SSLv3_client_method();
+ break;
+ case context_base::sslv3_server:
+ ssl_method = ::SSLv3_server_method();
+ break;
+ case context_base::tlsv1:
+ ssl_method = ::TLSv1_method();
+ break;
+ case context_base::tlsv1_client:
+ ssl_method = ::TLSv1_client_method();
+ break;
+ case context_base::tlsv1_server:
+ ssl_method = ::TLSv1_server_method();
+ break;
+ case context_base::sslv23:
+ ssl_method = ::SSLv23_method();
+ break;
+ case context_base::sslv23_client:
+ ssl_method = ::SSLv23_client_method();
+ break;
+ case context_base::sslv23_server:
+ ssl_method = ::SSLv23_server_method();
+ break;
+ default:
+ break;
+ }
+ impl = ::SSL_CTX_new(ssl_method);
+ }
+
+ // Destroy a context implementation.
+ void destroy(impl_type& impl)
+ {
+ if (impl != null())
+ {
+ if (impl->default_passwd_callback_userdata)
+ {
+ password_callback_type* callback =
+ static_cast<password_callback_type*>(
+ impl->default_passwd_callback_userdata);
+ delete callback;
+ impl->default_passwd_callback_userdata = 0;
+ }
+
+ ::SSL_CTX_free(impl);
+ impl = null();
+ }
+ }
+
+ // Set options on the context.
+ asio::error_code set_options(impl_type& impl,
+ context_base::options o, asio::error_code& ec)
+ {
+ ::SSL_CTX_set_options(impl, o);
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Set peer verification mode.
+ asio::error_code set_verify_mode(impl_type& impl,
+ context_base::verify_mode v, asio::error_code& ec)
+ {
+ ::SSL_CTX_set_verify(impl, v, 0);
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Load a certification authority file for performing verification.
+ asio::error_code load_verify_file(impl_type& impl,
+ const std::string& filename, asio::error_code& ec)
+ {
+ if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Add a directory containing certification authority files to be used for
+ // performing verification.
+ asio::error_code add_verify_path(impl_type& impl,
+ const std::string& path, asio::error_code& ec)
+ {
+ if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Use a certificate from a file.
+ asio::error_code use_certificate_file(impl_type& impl,
+ const std::string& filename, context_base::file_format format,
+ asio::error_code& ec)
+ {
+ int file_type;
+ switch (format)
+ {
+ case context_base::asn1:
+ file_type = SSL_FILETYPE_ASN1;
+ break;
+ case context_base::pem:
+ file_type = SSL_FILETYPE_PEM;
+ break;
+ default:
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+ }
+
+ if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Use a certificate chain from a file.
+ asio::error_code use_certificate_chain_file(impl_type& impl,
+ const std::string& filename, asio::error_code& ec)
+ {
+ if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Use a private key from a file.
+ asio::error_code use_private_key_file(impl_type& impl,
+ const std::string& filename, context_base::file_format format,
+ asio::error_code& ec)
+ {
+ int file_type;
+ switch (format)
+ {
+ case context_base::asn1:
+ file_type = SSL_FILETYPE_ASN1;
+ break;
+ case context_base::pem:
+ file_type = SSL_FILETYPE_PEM;
+ break;
+ default:
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+ }
+
+ if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Use an RSA private key from a file.
+ asio::error_code use_rsa_private_key_file(impl_type& impl,
+ const std::string& filename, context_base::file_format format,
+ asio::error_code& ec)
+ {
+ int file_type;
+ switch (format)
+ {
+ case context_base::asn1:
+ file_type = SSL_FILETYPE_ASN1;
+ break;
+ case context_base::pem:
+ file_type = SSL_FILETYPE_PEM;
+ break;
+ default:
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+ }
+
+ if (::SSL_CTX_use_RSAPrivateKey_file(
+ impl, filename.c_str(), file_type) != 1)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Use the specified file to obtain the temporary Diffie-Hellman parameters.
+ asio::error_code use_tmp_dh_file(impl_type& impl,
+ const std::string& filename, asio::error_code& ec)
+ {
+ ::BIO* bio = ::BIO_new_file(filename.c_str(), "r");
+ if (!bio)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0);
+ if (!dh)
+ {
+ ::BIO_free(bio);
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ::BIO_free(bio);
+ int result = ::SSL_CTX_set_tmp_dh(impl, dh);
+ if (result != 1)
+ {
+ ::DH_free(dh);
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ static int password_callback(char* buf, int size, int purpose, void* data)
+ {
+ using namespace std; // For strncat and strlen.
+
+ if (data)
+ {
+ password_callback_type* callback =
+ static_cast<password_callback_type*>(data);
+ std::string passwd = (*callback)(static_cast<std::size_t>(size),
+ purpose ? context_base::for_writing : context_base::for_reading);
+ *buf = '\0';
+ strncat(buf, passwd.c_str(), size);
+ return strlen(buf);
+ }
+
+ return 0;
+ }
+
+ // Set the password callback.
+ template <typename Password_Callback>
+ asio::error_code set_password_callback(impl_type& impl,
+ Password_Callback callback, asio::error_code& ec)
+ {
+ // Allocate callback function object if not already present.
+ if (impl->default_passwd_callback_userdata)
+ {
+ password_callback_type* callback_function =
+ static_cast<password_callback_type*>(
+ impl->default_passwd_callback_userdata);
+ *callback_function = callback;
+ }
+ else
+ {
+ password_callback_type* callback_function =
+ new password_callback_type(callback);
+ impl->default_passwd_callback_userdata = callback_function;
+ }
+
+ // Set the password callback.
+ SSL_CTX_set_default_passwd_cb(impl,
+ &openssl_context_service::password_callback);
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+private:
+ // Ensure openssl is initialised.
+ openssl_init<> init_;
+};
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
diff --git a/src/libtorrent/asio/ssl/detail/openssl_init.hpp b/src/libtorrent/asio/ssl/detail/openssl_init.hpp
new file mode 100644
index 0000000..07d7e66
--- /dev/null
+++ b/src/libtorrent/asio/ssl/detail/openssl_init.hpp
@@ -0,0 +1,143 @@
+//
+// openssl_init.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_DETAIL_OPENSSL_INIT_HPP
+#define ASIO_SSL_DETAIL_OPENSSL_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <vector>
+#include <boost/assert.hpp>
+#include <boost/shared_ptr.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/tss_ptr.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+template <bool Do_Init = true>
+class openssl_init
+ : private boost::noncopyable
+{
+private:
+ // Structure to perform the actual initialisation.
+ class do_init
+ {
+ public:
+ do_init()
+ {
+ if (Do_Init)
+ {
+ ::SSL_library_init();
+ ::SSL_load_error_strings();
+ ::OpenSSL_add_ssl_algorithms();
+
+ mutexes_.resize(::CRYPTO_num_locks());
+ for (size_t i = 0; i < mutexes_.size(); ++i)
+ mutexes_[i].reset(new asio::detail::mutex);
+ ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func);
+ ::CRYPTO_set_id_callback(&do_init::openssl_id_func);
+ }
+ }
+
+ ~do_init()
+ {
+ if (Do_Init)
+ {
+ ::CRYPTO_set_id_callback(0);
+ ::CRYPTO_set_locking_callback(0);
+ ::ERR_free_strings();
+ ::ERR_remove_state(0);
+ ::EVP_cleanup();
+ ::CRYPTO_cleanup_all_ex_data();
+ ::CONF_modules_unload(1);
+ ::ENGINE_cleanup();
+ }
+ }
+
+ // Helper function to manage a do_init singleton. The static instance of the
+ // openssl_init object ensures that this function is always called before
+ // main, and therefore before any other threads can get started. The do_init
+ // instance must be static in this function to ensure that it gets
+ // initialised before any other global objects try to use it.
+ static boost::shared_ptr<do_init> instance()
+ {
+ static boost::shared_ptr<do_init> init(new do_init);
+ return init;
+ }
+
+ private:
+ static unsigned long openssl_id_func()
+ {
+ void* id = instance()->thread_id_;
+ if (id == 0)
+ instance()->thread_id_ = id = &id; // Ugh.
+ BOOST_ASSERT(sizeof(unsigned long) >= sizeof(void*));
+ return reinterpret_cast<unsigned long>(id);
+ }
+
+ static void openssl_locking_func(int mode, int n,
+ const char *file, int line)
+ {
+ if (mode & CRYPTO_LOCK)
+ instance()->mutexes_[n]->lock();
+ else
+ instance()->mutexes_[n]->unlock();
+ }
+
+ // Mutexes to be used in locking callbacks.
+ std::vector<boost::shared_ptr<asio::detail::mutex> > mutexes_;
+
+ // The thread identifiers to be used by openssl.
+ asio::detail::tss_ptr<void> thread_id_;
+ };
+
+public:
+ // Constructor.
+ openssl_init()
+ : ref_(do_init::instance())
+ {
+ while (&instance_ == 0); // Ensure openssl_init::instance_ is linked in.
+ }
+
+ // Destructor.
+ ~openssl_init()
+ {
+ }
+
+private:
+ // Instance to force initialisation of openssl at global scope.
+ static openssl_init instance_;
+
+ // Reference to singleton do_init object to ensure that openssl does not get
+ // cleaned up until the last user has finished with it.
+ boost::shared_ptr<do_init> ref_;
+};
+
+template <bool Do_Init>
+openssl_init<Do_Init> openssl_init<Do_Init>::instance_;
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_OPENSSL_INIT_HPP
diff --git a/src/libtorrent/asio/ssl/detail/openssl_operation.hpp b/src/libtorrent/asio/ssl/detail/openssl_operation.hpp
new file mode 100644
index 0000000..c8603ac
--- /dev/null
+++ b/src/libtorrent/asio/ssl/detail/openssl_operation.hpp
@@ -0,0 +1,516 @@
+//
+// openssl_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
+#define ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/function.hpp>
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/buffer.hpp"
+#include "asio/placeholders.hpp"
+#include "asio/write.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+typedef boost::function<int (::SSL*)> ssl_primitive_func;
+typedef boost::function<void (const asio::error_code&, int)>
+ user_handler_func;
+
+// Network send_/recv buffer implementation
+//
+//
+class net_buffer
+{
+ static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare
+
+ unsigned char buf_[NET_BUF_SIZE];
+ unsigned char* data_start_;
+ unsigned char* data_end_;
+
+public:
+ net_buffer()
+ {
+ data_start_ = data_end_ = buf_;
+ }
+ unsigned char* get_unused_start() { return data_end_; }
+ unsigned char* get_data_start() { return data_start_; }
+ size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); }
+ size_t get_data_len() { return (data_end_ - data_start_); }
+ void data_added(size_t count)
+ {
+ data_end_ += count;
+ data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)?
+ (buf_ + NET_BUF_SIZE):
+ data_end_;
+ }
+ void data_removed(size_t count)
+ {
+ data_start_ += count;
+ if (data_start_ >= data_end_) reset();
+ }
+ void reset() { data_start_ = buf_; data_end_ = buf_; }
+ bool has_data() { return (data_start_ < data_end_); }
+}; // class net_buffer
+
+//
+// Operation class
+//
+//
+template <typename Stream>
+class openssl_operation
+{
+public:
+
+ // Constructor for asynchronous operations
+ openssl_operation(ssl_primitive_func primitive,
+ Stream& socket,
+ net_buffer& recv_buf,
+ SSL* session,
+ BIO* ssl_bio,
+ user_handler_func handler,
+ asio::io_service::strand& strand
+ )
+ : primitive_(primitive)
+ , user_handler_(handler)
+ , strand_(&strand)
+ , recv_buf_(recv_buf)
+ , socket_(socket)
+ , ssl_bio_(ssl_bio)
+ , session_(session)
+ {
+ write_ = boost::bind(
+ &openssl_operation::do_async_write,
+ this, boost::arg<1>(), boost::arg<2>()
+ );
+ read_ = boost::bind(
+ &openssl_operation::do_async_read,
+ this
+ );
+ handler_= boost::bind(
+ &openssl_operation::async_user_handler,
+ this, boost::arg<1>(), boost::arg<2>()
+ );
+ }
+
+ // Constructor for synchronous operations
+ openssl_operation(ssl_primitive_func primitive,
+ Stream& socket,
+ net_buffer& recv_buf,
+ SSL* session,
+ BIO* ssl_bio)
+ : primitive_(primitive)
+ , strand_(0)
+ , recv_buf_(recv_buf)
+ , socket_(socket)
+ , ssl_bio_(ssl_bio)
+ , session_(session)
+ {
+ write_ = boost::bind(
+ &openssl_operation::do_sync_write,
+ this, boost::arg<1>(), boost::arg<2>()
+ );
+ read_ = boost::bind(
+ &openssl_operation::do_sync_read,
+ this
+ );
+ handler_ = boost::bind(
+ &openssl_operation::sync_user_handler,
+ this, boost::arg<1>(), boost::arg<2>()
+ );
+ }
+
+ // Start operation
+ // In case of asynchronous it returns 0, in sync mode returns success code
+ // or throws an error...
+ int start()
+ {
+ int rc = primitive_( session_ );
+
+ bool is_operation_done = (rc > 0);
+ // For connect/accept/shutdown, the operation
+ // is done, when return code is 1
+ // for write, it is done, when is retcode > 0
+ // for read, is is done when retcode > 0
+
+ int error_code = !is_operation_done ?
+ ::SSL_get_error( session_, rc ) :
+ 0;
+ int sys_error_code = ERR_get_error();
+
+ bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
+ bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
+ ::BIO_ctrl_pending( ssl_bio_ ));
+ bool is_shut_down_received =
+ ((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) ==
+ SSL_RECEIVED_SHUTDOWN);
+ bool is_shut_down_sent =
+ ((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
+ SSL_SENT_SHUTDOWN);
+
+ if (is_shut_down_sent && is_shut_down_received && is_operation_done && !is_write_needed)
+ // SSL connection is shut down cleanly
+ return handler_(asio::error_code(), 1);
+
+ if (is_shut_down_received && !is_operation_done)
+ // Shutdown has been requested, while we were reading or writing...
+ // abort our action...
+ return handler_(asio::error::shut_down, 0);
+
+ if (!is_operation_done && !is_read_needed && !is_write_needed
+ && !is_shut_down_sent)
+ {
+ // The operation has failed... It is not completed and does
+ // not want network communication nor does want to send shutdown out...
+ if (error_code == SSL_ERROR_SYSCALL)
+ {
+ return handler_(asio::error_code(
+ sys_error_code, asio::error::system_category), rc);
+ }
+ else
+ {
+ return handler_(asio::error_code(
+ error_code, asio::error::get_ssl_category()), rc);
+ }
+ }
+
+ if (!is_operation_done && !is_write_needed)
+ {
+ // We may have left over data that we can pass to SSL immediately
+ if (recv_buf_.get_data_len() > 0)
+ {
+ // Pass the buffered data to SSL
+ int written = ::BIO_write
+ (
+ ssl_bio_,
+ recv_buf_.get_data_start(),
+ recv_buf_.get_data_len()
+ );
+
+ if (written > 0)
+ {
+ recv_buf_.data_removed(written);
+ }
+ else if (written < 0)
+ {
+ if (!BIO_should_retry(ssl_bio_))
+ {
+ // Some serios error with BIO....
+ return handler_(asio::error::no_recovery, 0);
+ }
+ }
+
+ return start();
+ }
+ else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
+ {
+ return read_();
+ }
+ }
+
+ // Continue with operation, flush any SSL data out to network...
+ return write_(is_operation_done, rc);
+ }
+
+// Private implementation
+private:
+ typedef boost::function<int (const asio::error_code&, int)>
+ int_handler_func;
+ typedef boost::function<int (bool, int)> write_func;
+ typedef boost::function<int ()> read_func;
+
+ ssl_primitive_func primitive_;
+ user_handler_func user_handler_;
+ asio::io_service::strand* strand_;
+ write_func write_;
+ read_func read_;
+ int_handler_func handler_;
+
+ net_buffer send_buf_; // buffers for network IO
+
+ // The recv buffer is owned by the stream, not the operation, since there can
+ // be left over bytes after passing the data up to the application, and these
+ // bytes need to be kept around for the next read operation issued by the
+ // application.
+ net_buffer& recv_buf_;
+
+ Stream& socket_;
+ BIO* ssl_bio_;
+ SSL* session_;
+
+ //
+ int sync_user_handler(const asio::error_code& error, int rc)
+ {
+ if (!error)
+ return rc;
+
+ throw asio::system_error(error);
+ }
+
+ int async_user_handler(asio::error_code error, int rc)
+ {
+ if (rc < 0)
+ {
+ if (!error)
+ error = asio::error::no_recovery;
+ rc = 0;
+ }
+
+ user_handler_(error, rc);
+ return 0;
+ }
+
+ // Writes bytes asynchronously from SSL to NET
+ int do_async_write(bool is_operation_done, int rc)
+ {
+ int len = ::BIO_ctrl_pending( ssl_bio_ );
+ if ( len )
+ {
+ // There is something to write into net, do it...
+ len = (int)send_buf_.get_unused_len() > len?
+ len:
+ send_buf_.get_unused_len();
+
+ if (len == 0)
+ {
+ // In case our send buffer is full, we have just to wait until
+ // previous send to complete...
+ return 0;
+ }
+
+ // Read outgoing data from bio
+ len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
+
+ if (len > 0)
+ {
+ unsigned char *data_start = send_buf_.get_unused_start();
+ send_buf_.data_added(len);
+
+ BOOST_ASSERT(strand_);
+ asio::async_write
+ (
+ socket_,
+ asio::buffer(data_start, len),
+ strand_->wrap
+ (
+ boost::bind
+ (
+ &openssl_operation::async_write_handler,
+ this,
+ is_operation_done,
+ rc,
+ asio::placeholders::error,
+ asio::placeholders::bytes_transferred
+ )
+ )
+ );
+
+ return 0;
+ }
+ else if (!BIO_should_retry(ssl_bio_))
+ {
+ // Seems like fatal error
+ // reading from SSL BIO has failed...
+ handler_(asio::error::no_recovery, 0);
+ return 0;
+ }
+ }
+
+ if (is_operation_done)
+ {
+ // Finish the operation, with success
+ handler_(asio::error_code(), rc);
+ return 0;
+ }
+
+ // OPeration is not done and writing to net has been made...
+ // start operation again
+ start();
+
+ return 0;
+ }
+
+ void async_write_handler(bool is_operation_done, int rc,
+ const asio::error_code& error, size_t bytes_sent)
+ {
+ if (!error)
+ {
+ // Remove data from send buffer
+ send_buf_.data_removed(bytes_sent);
+
+ if (is_operation_done)
+ handler_(asio::error_code(), rc);
+ else
+ // Since the operation was not completed, try it again...
+ start();
+ }
+ else
+ handler_(error, rc);
+ }
+
+ int do_async_read()
+ {
+ // Wait for new data
+ BOOST_ASSERT(strand_);
+ socket_.async_read_some
+ (
+ asio::buffer(recv_buf_.get_unused_start(),
+ recv_buf_.get_unused_len()),
+ strand_->wrap
+ (
+ boost::bind
+ (
+ &openssl_operation::async_read_handler,
+ this,
+ asio::placeholders::error,
+ asio::placeholders::bytes_transferred
+ )
+ )
+ );
+ return 0;
+ }
+
+ void async_read_handler(const asio::error_code& error,
+ size_t bytes_recvd)
+ {
+ if (!error)
+ {
+ recv_buf_.data_added(bytes_recvd);
+
+ // Pass the received data to SSL
+ int written = ::BIO_write
+ (
+ ssl_bio_,
+ recv_buf_.get_data_start(),
+ recv_buf_.get_data_len()
+ );
+
+ if (written > 0)
+ {
+ recv_buf_.data_removed(written);
+ }
+ else if (written < 0)
+ {
+ if (!BIO_should_retry(ssl_bio_))
+ {
+ // Some serios error with BIO....
+ handler_(asio::error::no_recovery, 0);
+ return;
+ }
+ }
+
+ // and try the SSL primitive again
+ start();
+ }
+ else
+ {
+ // Error in network level...
+ // SSL can't continue either...
+ handler_(error, 0);
+ }
+ }
+
+ // Syncronous functions...
+ int do_sync_write(bool is_operation_done, int rc)
+ {
+ int len = ::BIO_ctrl_pending( ssl_bio_ );
+ if ( len )
+ {
+ // There is something to write into net, do it...
+ len = (int)send_buf_.get_unused_len() > len?
+ len:
+ send_buf_.get_unused_len();
+
+ // Read outgoing data from bio
+ len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
+
+ if (len > 0)
+ {
+ size_t sent_len = asio::write(
+ socket_,
+ asio::buffer(send_buf_.get_unused_start(), len)
+ );
+
+ send_buf_.data_added(len);
+ send_buf_.data_removed(sent_len);
+ }
+ else if (!BIO_should_retry(ssl_bio_))
+ {
+ // Seems like fatal error
+ // reading from SSL BIO has failed...
+ throw asio::system_error(asio::error::no_recovery);
+ }
+ }
+
+ if (is_operation_done)
+ // Finish the operation, with success
+ return rc;
+
+ // Operation is not finished, start again.
+ return start();
+ }
+
+ int do_sync_read()
+ {
+ size_t len = socket_.read_some
+ (
+ asio::buffer(recv_buf_.get_unused_start(),
+ recv_buf_.get_unused_len())
+ );
+
+ // Write data to ssl
+ recv_buf_.data_added(len);
+
+ // Pass the received data to SSL
+ int written = ::BIO_write
+ (
+ ssl_bio_,
+ recv_buf_.get_data_start(),
+ recv_buf_.get_data_len()
+ );
+
+ if (written > 0)
+ {
+ recv_buf_.data_removed(written);
+ }
+ else if (written < 0)
+ {
+ if (!BIO_should_retry(ssl_bio_))
+ {
+ // Some serios error with BIO....
+ throw asio::system_error(asio::error::no_recovery);
+ }
+ }
+
+ // Try the operation again
+ return start();
+ }
+}; // class openssl_operation
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
diff --git a/src/libtorrent/asio/ssl/detail/openssl_stream_service.hpp b/src/libtorrent/asio/ssl/detail/openssl_stream_service.hpp
new file mode 100644
index 0000000..710c935
--- /dev/null
+++ b/src/libtorrent/asio/ssl/detail/openssl_stream_service.hpp
@@ -0,0 +1,531 @@
+//
+// stream_service.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
+#define ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <climits>
+#include <boost/config.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/strand.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/ssl/basic_context.hpp"
+#include "asio/ssl/stream_base.hpp"
+#include "asio/ssl/detail/openssl_operation.hpp"
+#include "asio/ssl/detail/openssl_types.hpp"
+
+namespace asio {
+namespace ssl {
+namespace detail {
+
+class openssl_stream_service
+ : public asio::detail::service_base<openssl_stream_service>
+{
+private:
+ enum { max_buffer_size = INT_MAX };
+
+ //Base handler for asyncrhonous operations
+ template <typename Stream>
+ class base_handler
+ {
+ public:
+ typedef boost::function<
+ void (const asio::error_code&, size_t)> func_t;
+
+ base_handler(asio::io_service& io_service)
+ : op_(NULL)
+ , io_service_(io_service)
+ , work_(io_service)
+ {}
+
+ void do_func(const asio::error_code& error, size_t size)
+ {
+ func_(error, size);
+ }
+
+ void set_operation(openssl_operation<Stream>* op) { op_ = op; }
+ void set_func(func_t func) { func_ = func; }
+
+ ~base_handler()
+ {
+ delete op_;
+ }
+
+ private:
+ func_t func_;
+ openssl_operation<Stream>* op_;
+ asio::io_service& io_service_;
+ asio::io_service::work work_;
+ }; // class base_handler
+
+ // Handler for asynchronous IO (write/read) operations
+ template<typename Stream, typename Handler>
+ class io_handler
+ : public base_handler<Stream>
+ {
+ public:
+ io_handler(Handler handler, asio::io_service& io_service)
+ : base_handler<Stream>(io_service)
+ , handler_(handler)
+ {
+ set_func(boost::bind(
+ &io_handler<Stream, Handler>::handler_impl,
+ this, boost::arg<1>(), boost::arg<2>() ));
+ }
+
+ private:
+ Handler handler_;
+ void handler_impl(const asio::error_code& error, size_t size)
+ {
+ handler_(error, size);
+ delete this;
+ }
+ }; // class io_handler
+
+ // Handler for asyncrhonous handshake (connect, accept) functions
+ template <typename Stream, typename Handler>
+ class handshake_handler
+ : public base_handler<Stream>
+ {
+ public:
+ handshake_handler(Handler handler, asio::io_service& io_service)
+ : base_handler<Stream>(io_service)
+ , handler_(handler)
+ {
+ set_func(boost::bind(
+ &handshake_handler<Stream, Handler>::handler_impl,
+ this, boost::arg<1>(), boost::arg<2>() ));
+ }
+
+ private:
+ Handler handler_;
+ void handler_impl(const asio::error_code& error, size_t)
+ {
+ handler_(error);
+ delete this;
+ }
+
+ }; // class handshake_handler
+
+ // Handler for asyncrhonous shutdown
+ template <typename Stream, typename Handler>
+ class shutdown_handler
+ : public base_handler<Stream>
+ {
+ public:
+ shutdown_handler(Handler handler, asio::io_service& io_service)
+ : base_handler<Stream>(io_service),
+ handler_(handler)
+ {
+ set_func(boost::bind(
+ &shutdown_handler<Stream, Handler>::handler_impl,
+ this, boost::arg<1>(), boost::arg<2>() ));
+ }
+
+ private:
+ Handler handler_;
+ void handler_impl(const asio::error_code& error, size_t)
+ {
+ handler_(error);
+ delete this;
+ }
+ }; // class shutdown_handler
+
+public:
+ // The implementation type.
+ typedef struct impl_struct
+ {
+ ::SSL* ssl;
+ ::BIO* ext_bio;
+ net_buffer recv_buf;
+ } * impl_type;
+
+ // Construct a new stream socket service for the specified io_service.
+ explicit openssl_stream_service(asio::io_service& io_service)
+ : asio::detail::service_base<openssl_stream_service>(io_service),
+ strand_(io_service)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Return a null stream implementation.
+ impl_type null() const
+ {
+ return 0;
+ }
+
+ // Create a new stream implementation.
+ template <typename Stream, typename Context_Service>
+ void create(impl_type& impl, Stream& next_layer,
+ basic_context<Context_Service>& context)
+ {
+ impl = new impl_struct;
+ impl->ssl = ::SSL_new(context.impl());
+ ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+ ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ ::BIO* int_bio = 0;
+ impl->ext_bio = 0;
+ ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
+ ::SSL_set_bio(impl->ssl, int_bio, int_bio);
+ }
+
+ // Destroy a stream implementation.
+ template <typename Stream>
+ void destroy(impl_type& impl, Stream& next_layer)
+ {
+ if (impl != 0)
+ {
+ ::BIO_free(impl->ext_bio);
+ ::SSL_free(impl->ssl);
+ delete impl;
+ impl = 0;
+ }
+ }
+
+ // Perform SSL handshaking.
+ template <typename Stream>
+ asio::error_code handshake(impl_type& impl, Stream& next_layer,
+ stream_base::handshake_type type, asio::error_code& ec)
+ {
+ try
+ {
+ openssl_operation<Stream> op(
+ type == stream_base::client ?
+ &ssl_wrap<mutex_type>::SSL_connect:
+ &ssl_wrap<mutex_type>::SSL_accept,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio);
+ op.start();
+ }
+ catch (asio::system_error& e)
+ {
+ ec = e.code();
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Start an asynchronous SSL handshake.
+ template <typename Stream, typename Handler>
+ void async_handshake(impl_type& impl, Stream& next_layer,
+ stream_base::handshake_type type, Handler handler)
+ {
+ typedef handshake_handler<Stream, Handler> connect_handler;
+
+ connect_handler* local_handler =
+ new connect_handler(handler, get_io_service());
+
+ openssl_operation<Stream>* op = new openssl_operation<Stream>
+ (
+ type == stream_base::client ?
+ &ssl_wrap<mutex_type>::SSL_connect:
+ &ssl_wrap<mutex_type>::SSL_accept,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio,
+ boost::bind
+ (
+ &base_handler<Stream>::do_func,
+ local_handler,
+ boost::arg<1>(),
+ boost::arg<2>()
+ ),
+ strand_
+ );
+ local_handler->set_operation(op);
+
+ strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
+ }
+
+ // Shut down SSL on the stream.
+ template <typename Stream>
+ asio::error_code shutdown(impl_type& impl, Stream& next_layer,
+ asio::error_code& ec)
+ {
+ try
+ {
+ openssl_operation<Stream> op(
+ &ssl_wrap<mutex_type>::SSL_shutdown,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio);
+ op.start();
+ }
+ catch (asio::system_error& e)
+ {
+ ec = e.code();
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+ }
+
+ // Asynchronously shut down SSL on the stream.
+ template <typename Stream, typename Handler>
+ void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler)
+ {
+ typedef shutdown_handler<Stream, Handler> disconnect_handler;
+
+ disconnect_handler* local_handler =
+ new disconnect_handler(handler, get_io_service());
+
+ openssl_operation<Stream>* op = new openssl_operation<Stream>
+ (
+ &ssl_wrap<mutex_type>::SSL_shutdown,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio,
+ boost::bind
+ (
+ &base_handler<Stream>::do_func,
+ local_handler,
+ boost::arg<1>(),
+ boost::arg<2>()
+ ),
+ strand_
+ );
+ local_handler->set_operation(op);
+
+ strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
+ }
+
+ // Write some data to the stream.
+ template <typename Stream, typename Const_Buffers>
+ std::size_t write_some(impl_type& impl, Stream& next_layer,
+ const Const_Buffers& buffers, asio::error_code& ec)
+ {
+ size_t bytes_transferred = 0;
+ try
+ {
+ std::size_t buffer_size = asio::buffer_size(*buffers.begin());
+ if (buffer_size > max_buffer_size)
+ buffer_size = max_buffer_size;
+
+ boost::function<int (SSL*)> send_func =
+ boost::bind(&::SSL_write, boost::arg<1>(),
+ asio::buffer_cast<const void*>(*buffers.begin()),
+ static_cast<int>(buffer_size));
+ openssl_operation<Stream> op(
+ send_func,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio
+ );
+ bytes_transferred = static_cast<size_t>(op.start());
+ }
+ catch (asio::system_error& e)
+ {
+ ec = e.code();
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+ }
+
+ // Start an asynchronous write.
+ template <typename Stream, typename Const_Buffers, typename Handler>
+ void async_write_some(impl_type& impl, Stream& next_layer,
+ const Const_Buffers& buffers, Handler handler)
+ {
+ typedef io_handler<Stream, Handler> send_handler;
+
+ send_handler* local_handler = new send_handler(handler, get_io_service());
+
+ std::size_t buffer_size = asio::buffer_size(*buffers.begin());
+ if (buffer_size > max_buffer_size)
+ buffer_size = max_buffer_size;
+
+ boost::function<int (SSL*)> send_func =
+ boost::bind(&::SSL_write, boost::arg<1>(),
+ asio::buffer_cast<const void*>(*buffers.begin()),
+ static_cast<int>(buffer_size));
+
+ openssl_operation<Stream>* op = new openssl_operation<Stream>
+ (
+ send_func,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio,
+ boost::bind
+ (
+ &base_handler<Stream>::do_func,
+ local_handler,
+ boost::arg<1>(),
+ boost::arg<2>()
+ ),
+ strand_
+ );
+ local_handler->set_operation(op);
+
+ strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
+ }
+
+ // Read some data from the stream.
+ template <typename Stream, typename Mutable_Buffers>
+ std::size_t read_some(impl_type& impl, Stream& next_layer,
+ const Mutable_Buffers& buffers, asio::error_code& ec)
+ {
+ size_t bytes_transferred = 0;
+ try
+ {
+ std::size_t buffer_size = asio::buffer_size(*buffers.begin());
+ if (buffer_size > max_buffer_size)
+ buffer_size = max_buffer_size;
+
+ boost::function<int (SSL*)> recv_func =
+ boost::bind(&::SSL_read, boost::arg<1>(),
+ asio::buffer_cast<void*>(*buffers.begin()),
+ static_cast<int>(buffer_size));
+ openssl_operation<Stream> op(recv_func,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio
+ );
+
+ bytes_transferred = static_cast<size_t>(op.start());
+ }
+ catch (asio::system_error& e)
+ {
+ ec = e.code();
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+ }
+
+ // Start an asynchronous read.
+ template <typename Stream, typename Mutable_Buffers, typename Handler>
+ void async_read_some(impl_type& impl, Stream& next_layer,
+ const Mutable_Buffers& buffers, Handler handler)
+ {
+ typedef io_handler<Stream, Handler> recv_handler;
+
+ recv_handler* local_handler = new recv_handler(handler, get_io_service());
+
+ std::size_t buffer_size = asio::buffer_size(*buffers.begin());
+ if (buffer_size > max_buffer_size)
+ buffer_size = max_buffer_size;
+
+ boost::function<int (SSL*)> recv_func =
+ boost::bind(&::SSL_read, boost::arg<1>(),
+ asio::buffer_cast<void*>(*buffers.begin()),
+ static_cast<int>(buffer_size));
+
+ openssl_operation<Stream>* op = new openssl_operation<Stream>
+ (
+ recv_func,
+ next_layer,
+ impl->recv_buf,
+ impl->ssl,
+ impl->ext_bio,
+ boost::bind
+ (
+ &base_handler<Stream>::do_func,
+ local_handler,
+ boost::arg<1>(),
+ boost::arg<2>()
+ ),
+ strand_
+ );
+ local_handler->set_operation(op);
+
+ strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
+ }
+
+ // Peek at the incoming data on the stream.
+ template <typename Stream, typename Mutable_Buffers>
+ std::size_t peek(impl_type& impl, Stream& next_layer,
+ const Mutable_Buffers& buffers, asio::error_code& ec)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Determine the amount of data that may be read without blocking.
+ template <typename Stream>
+ std::size_t in_avail(impl_type& impl, Stream& next_layer,
+ asio::error_code& ec)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+private:
+ asio::io_service::strand strand_;
+
+ typedef asio::detail::mutex mutex_type;
+
+ template<typename Mutex>
+ struct ssl_wrap
+ {
+ static Mutex ssl_mutex_;
+
+ static int SSL_accept(SSL *ssl)
+ {
+ typename Mutex::scoped_lock lock(ssl_mutex_);
+ return ::SSL_accept(ssl);
+ }
+
+ static int SSL_connect(SSL *ssl)
+ {
+ typename Mutex::scoped_lock lock(ssl_mutex_);
+ return ::SSL_connect(ssl);
+ }
+
+ static int SSL_shutdown(SSL *ssl)
+ {
+ typename Mutex::scoped_lock lock(ssl_mutex_);
+ return ::SSL_shutdown(ssl);
+ }
+ };
+};
+
+template<typename Mutex>
+Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_;
+
+} // namespace detail
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP
diff --git a/src/libtorrent/asio/ssl/detail/openssl_types.hpp b/src/libtorrent/asio/ssl/detail/openssl_types.hpp
new file mode 100644
index 0000000..1111361
--- /dev/null
+++ b/src/libtorrent/asio/ssl/detail/openssl_types.hpp
@@ -0,0 +1,31 @@
+//
+// openssl_types.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
+#define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <openssl/conf.h>
+#include <openssl/ssl.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
diff --git a/src/libtorrent/asio/ssl/stream.hpp b/src/libtorrent/asio/ssl/stream.hpp
new file mode 100644
index 0000000..77ced5b
--- /dev/null
+++ b/src/libtorrent/asio/ssl/stream.hpp
@@ -0,0 +1,503 @@
+//
+// stream.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_STREAM_HPP
+#define ASIO_SSL_STREAM_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/type_traits.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/ssl/basic_context.hpp"
+#include "asio/ssl/stream_base.hpp"
+#include "asio/ssl/stream_service.hpp"
+#include "asio/detail/throw_error.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// Provides stream-oriented functionality using SSL.
+/**
+ * The stream class template provides asynchronous and blocking stream-oriented
+ * functionality using SSL.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Example
+ * To use the SSL stream template with an ip::tcp::socket, you would write:
+ * @code
+ * asio::io_service io_service;
+ * asio::ssl::context context(io_service, asio::ssl::context::sslv23);
+ * asio::ssl::stream<asio::ip::tcp::socket> sock(io_service, context);
+ * @endcode
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncRead_Stream, SyncWriteStream.
+ */
+template <typename Stream, typename Service = stream_service>
+class stream
+ : public stream_base,
+ private boost::noncopyable
+{
+public:
+ /// The type of the next layer.
+ typedef typename boost::remove_reference<Stream>::type next_layer_type;
+
+ /// The type of the lowest layer.
+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+
+ /// The type of the service that will be used to provide stream operations.
+ typedef Service service_type;
+
+ /// The native implementation type of the stream.
+ typedef typename service_type::impl_type impl_type;
+
+ /// Construct a stream.
+ /**
+ * This constructor creates a stream and initialises the underlying stream
+ * object.
+ *
+ * @param arg The argument to be passed to initialise the underlying stream.
+ *
+ * @param context The SSL context to be used for the stream.
+ */
+ template <typename Arg, typename Context_Service>
+ explicit stream(Arg& arg, basic_context<Context_Service>& context)
+ : next_layer_(arg),
+ service_(asio::use_service<Service>(next_layer_.get_io_service())),
+ impl_(service_.null())
+ {
+ service_.create(impl_, next_layer_, context);
+ }
+
+ /// Destructor.
+ ~stream()
+ {
+ service_.destroy(impl_, next_layer_);
+ }
+
+ /// (Deprecated: use get_io_service().) Get the io_service associated with
+ /// the object.
+ /**
+ * This function may be used to obtain the io_service object that the stream
+ * uses to dispatch handlers for asynchronous operations.
+ *
+ * @return A reference to the io_service object that stream will use to
+ * dispatch handlers. Ownership is not transferred to the caller.
+ */
+ asio::io_service& io_service()
+ {
+ return next_layer_.get_io_service();
+ }
+
+ /// Get the io_service associated with the object.
+ /**
+ * This function may be used to obtain the io_service object that the stream
+ * uses to dispatch handlers for asynchronous operations.
+ *
+ * @return A reference to the io_service object that stream will use to
+ * dispatch handlers. Ownership is not transferred to the caller.
+ */
+ asio::io_service& get_io_service()
+ {
+ return next_layer_.get_io_service();
+ }
+
+ /// Get a reference to the next layer.
+ /**
+ * This function returns a reference to the next layer in a stack of stream
+ * layers.
+ *
+ * @return A reference to the next layer in the stack of stream layers.
+ * Ownership is not transferred to the caller.
+ */
+ next_layer_type& next_layer()
+ {
+ return next_layer_;
+ }
+
+ /// Get a reference to the lowest layer.
+ /**
+ * This function returns a reference to the lowest layer in a stack of
+ * stream layers.
+ *
+ * @return A reference to the lowest layer in the stack of stream layers.
+ * Ownership is not transferred to the caller.
+ */
+ lowest_layer_type& lowest_layer()
+ {
+ return next_layer_.lowest_layer();
+ }
+
+ /// Get the underlying implementation in the native type.
+ /**
+ * This function may be used to obtain the underlying implementation of the
+ * context. This is intended to allow access to stream functionality that is
+ * not otherwise provided.
+ */
+ impl_type impl()
+ {
+ return impl_;
+ }
+
+ /// Perform SSL handshaking.
+ /**
+ * This function is used to perform SSL handshaking on the stream. The
+ * function call will block until handshaking is complete or an error occurs.
+ *
+ * @param type The type of handshaking to be performed, i.e. as a client or as
+ * a server.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void handshake(handshake_type type)
+ {
+ asio::error_code ec;
+ service_.handshake(impl_, next_layer_, type, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Perform SSL handshaking.
+ /**
+ * This function is used to perform SSL handshaking on the stream. The
+ * function call will block until handshaking is complete or an error occurs.
+ *
+ * @param type The type of handshaking to be performed, i.e. as a client or as
+ * a server.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code handshake(handshake_type type,
+ asio::error_code& ec)
+ {
+ return service_.handshake(impl_, next_layer_, type, ec);
+ }
+
+ /// Start an asynchronous SSL handshake.
+ /**
+ * This function is used to asynchronously perform an SSL handshake on the
+ * stream. This function call always returns immediately.
+ *
+ * @param type The type of handshaking to be performed, i.e. as a client or as
+ * a server.
+ *
+ * @param handler The handler to be called when the handshake operation
+ * completes. Copies will be made of the handler as required. The equivalent
+ * function signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error // Result of operation.
+ * ); @endcode
+ */
+ template <typename HandshakeHandler>
+ void async_handshake(handshake_type type, HandshakeHandler handler)
+ {
+ service_.async_handshake(impl_, next_layer_, type, handler);
+ }
+
+ /// Shut down SSL on the stream.
+ /**
+ * This function is used to shut down SSL on the stream. The function call
+ * will block until SSL has been shut down or an error occurs.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ void shutdown()
+ {
+ asio::error_code ec;
+ service_.shutdown(impl_, next_layer_, ec);
+ asio::detail::throw_error(ec);
+ }
+
+ /// Shut down SSL on the stream.
+ /**
+ * This function is used to shut down SSL on the stream. The function call
+ * will block until SSL has been shut down or an error occurs.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ asio::error_code shutdown(asio::error_code& ec)
+ {
+ return service_.shutdown(impl_, next_layer_, ec);
+ }
+
+ /// Asynchronously shut down SSL on the stream.
+ /**
+ * This function is used to asynchronously shut down SSL on the stream. This
+ * function call always returns immediately.
+ *
+ * @param handler The handler to be called when the handshake operation
+ * completes. Copies will be made of the handler as required. The equivalent
+ * function signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error // Result of operation.
+ * ); @endcode
+ */
+ template <typename ShutdownHandler>
+ void async_shutdown(ShutdownHandler handler)
+ {
+ service_.async_shutdown(impl_, next_layer_, handler);
+ }
+
+ /// Write some data to the stream.
+ /**
+ * This function is used to write data on the stream. The function call will
+ * block until one or more bytes of data has been written successfully, or
+ * until an error occurs.
+ *
+ * @param buffers The data to be written.
+ *
+ * @returns The number of bytes written.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The write_some operation may not transmit all of the data to the
+ * peer. Consider using the @ref write function if you need to ensure that all
+ * data is written before the blocking operation completes.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = service_.write_some(impl_, next_layer_, buffers, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Write some data to the stream.
+ /**
+ * This function is used to write data on the stream. The function call will
+ * block until one or more bytes of data has been written successfully, or
+ * until an error occurs.
+ *
+ * @param buffers The data to be written to the stream.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. Returns 0 if an error occurred.
+ *
+ * @note The write_some operation may not transmit all of the data to the
+ * peer. Consider using the @ref write function if you need to ensure that all
+ * data is written before the blocking operation completes.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return service_.write_some(impl_, next_layer_, buffers, ec);
+ }
+
+ /// Start an asynchronous write.
+ /**
+ * This function is used to asynchronously write one or more bytes of data to
+ * the stream. The function call always returns immediately.
+ *
+ * @param buffers The data to be written to the stream. Although the buffers
+ * object may be copied as necessary, ownership of the underlying buffers is
+ * retained by the caller, which must guarantee that they remain valid until
+ * the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The equivalent function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes written.
+ * ); @endcode
+ *
+ * @note The async_write_some operation may not transmit all of the data to
+ * the peer. Consider using the @ref async_write function if you need to
+ * ensure that all data is written before the blocking operation completes.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_write_some(const ConstBufferSequence& buffers,
+ WriteHandler handler)
+ {
+ service_.async_write_some(impl_, next_layer_, buffers, handler);
+ }
+
+ /// Read some data from the stream.
+ /**
+ * This function is used to read data from the stream. The function call will
+ * block until one or more bytes of data has been read successfully, or until
+ * an error occurs.
+ *
+ * @param buffers The buffers into which the data will be read.
+ *
+ * @returns The number of bytes read.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note The read_some operation may not read all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = service_.read_some(impl_, next_layer_, buffers, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Read some data from the stream.
+ /**
+ * This function is used to read data from the stream. The function call will
+ * block until one or more bytes of data has been read successfully, or until
+ * an error occurs.
+ *
+ * @param buffers The buffers into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. Returns 0 if an error occurred.
+ *
+ * @note The read_some operation may not read all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return service_.read_some(impl_, next_layer_, buffers, ec);
+ }
+
+ /// Start an asynchronous read.
+ /**
+ * This function is used to asynchronously read one or more bytes of data from
+ * the stream. The function call always returns immediately.
+ *
+ * @param buffers The buffers into which the data will be read. Although the
+ * buffers object may be copied as necessary, ownership of the underlying
+ * buffers is retained by the caller, which must guarantee that they remain
+ * valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The equivalent function
+ * signature of the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes read.
+ * ); @endcode
+ *
+ * @note The async_read_some operation may not read all of the requested
+ * number of bytes. Consider using the @ref async_read function if you need to
+ * ensure that the requested amount of data is read before the asynchronous
+ * operation completes.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_read_some(const MutableBufferSequence& buffers,
+ ReadHandler handler)
+ {
+ service_.async_read_some(impl_, next_layer_, buffers, handler);
+ }
+
+ /// Peek at the incoming data on the stream.
+ /**
+ * This function is used to peek at the incoming data on the stream, without
+ * removing it from the input queue. The function call will block until data
+ * has been read successfully or an error occurs.
+ *
+ * @param buffers The buffers into which the data will be read.
+ *
+ * @returns The number of bytes read.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers)
+ {
+ asio::error_code ec;
+ std::size_t s = service_.peek(impl_, next_layer_, buffers, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Peek at the incoming data on the stream.
+ /**
+ * This function is used to peek at the incoming data on the stream, withoutxi
+ * removing it from the input queue. The function call will block until data
+ * has been read successfully or an error occurs.
+ *
+ * @param buffers The buffers into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. Returns 0 if an error occurred.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t peek(const MutableBufferSequence& buffers,
+ asio::error_code& ec)
+ {
+ return service_.peek(impl_, next_layer_, buffers, ec);
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ /**
+ * This function is used to determine the amount of data, in bytes, that may
+ * be read from the stream without blocking.
+ *
+ * @returns The number of bytes of data that can be read without blocking.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+ std::size_t in_avail()
+ {
+ asio::error_code ec;
+ std::size_t s = service_.in_avail(impl_, next_layer_, ec);
+ asio::detail::throw_error(ec);
+ return s;
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ /**
+ * This function is used to determine the amount of data, in bytes, that may
+ * be read from the stream without blocking.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes of data that can be read without blocking.
+ */
+ std::size_t in_avail(asio::error_code& ec)
+ {
+ return service_.in_avail(impl_, next_layer_, ec);
+ }
+
+private:
+ /// The next layer.
+ Stream next_layer_;
+
+ /// The backend service implementation.
+ service_type& service_;
+
+ /// The underlying native implementation.
+ impl_type impl_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_STREAM_HPP
diff --git a/src/libtorrent/asio/ssl/stream_base.hpp b/src/libtorrent/asio/ssl/stream_base.hpp
new file mode 100644
index 0000000..70ffbb2
--- /dev/null
+++ b/src/libtorrent/asio/ssl/stream_base.hpp
@@ -0,0 +1,60 @@
+//
+// stream_base.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_STREAM_BASE_HPP
+#define ASIO_SSL_STREAM_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/detail/workaround.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// The stream_base class is used as a base for the asio::ssl::stream
+/// class template so that we have a common place to define various enums.
+class stream_base
+{
+public:
+ /// Different handshake types.
+ enum handshake_type
+ {
+ /// Perform handshaking as a client.
+ client,
+
+ /// Perform handshaking as a server.
+ server
+ };
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ ~stream_base()
+ {
+ }
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+private:
+ // Workaround to enable the empty base optimisation with Borland C++.
+ char dummy_;
+#endif
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_STREAM_BASE_HPP
diff --git a/src/libtorrent/asio/ssl/stream_service.hpp b/src/libtorrent/asio/ssl/stream_service.hpp
new file mode 100644
index 0000000..3465605
--- /dev/null
+++ b/src/libtorrent/asio/ssl/stream_service.hpp
@@ -0,0 +1,186 @@
+//
+// stream_service.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
+// Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SSL_STREAM_SERVICE_HPP
+#define ASIO_SSL_STREAM_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/noncopyable.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/ssl/basic_context.hpp"
+#include "asio/ssl/stream_base.hpp"
+#include "asio/ssl/detail/openssl_stream_service.hpp"
+
+namespace asio {
+namespace ssl {
+
+/// Default service implementation for an SSL stream.
+class stream_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public asio::io_service::service
+#else
+ : public asio::detail::service_base<stream_service>
+#endif
+{
+private:
+ // The type of the platform-specific implementation.
+ typedef detail::openssl_stream_service service_impl_type;
+
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static asio::io_service::id id;
+#endif
+
+ /// The type of a stream implementation.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined impl_type;
+#else
+ typedef service_impl_type::impl_type impl_type;
+#endif
+
+ /// Construct a new stream service for the specified io_service.
+ explicit stream_service(asio::io_service& io_service)
+ : asio::detail::service_base<stream_service>(io_service),
+ service_impl_(asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Return a null stream implementation.
+ impl_type null() const
+ {
+ return service_impl_.null();
+ }
+
+ /// Create a new stream implementation.
+ template <typename Stream, typename Context_Service>
+ void create(impl_type& impl, Stream& next_layer,
+ basic_context<Context_Service>& context)
+ {
+ service_impl_.create(impl, next_layer, context);
+ }
+
+ /// Destroy a stream implementation.
+ template <typename Stream>
+ void destroy(impl_type& impl, Stream& next_layer)
+ {
+ service_impl_.destroy(impl, next_layer);
+ }
+
+ /// Perform SSL handshaking.
+ template <typename Stream>
+ asio::error_code handshake(impl_type& impl, Stream& next_layer,
+ stream_base::handshake_type type, asio::error_code& ec)
+ {
+ return service_impl_.handshake(impl, next_layer, type, ec);
+ }
+
+ /// Start an asynchronous SSL handshake.
+ template <typename Stream, typename HandshakeHandler>
+ void async_handshake(impl_type& impl, Stream& next_layer,
+ stream_base::handshake_type type, HandshakeHandler handler)
+ {
+ service_impl_.async_handshake(impl, next_layer, type, handler);
+ }
+
+ /// Shut down SSL on the stream.
+ template <typename Stream>
+ asio::error_code shutdown(impl_type& impl, Stream& next_layer,
+ asio::error_code& ec)
+ {
+ return service_impl_.shutdown(impl, next_layer, ec);
+ }
+
+ /// Asynchronously shut down SSL on the stream.
+ template <typename Stream, typename ShutdownHandler>
+ void async_shutdown(impl_type& impl, Stream& next_layer,
+ ShutdownHandler handler)
+ {
+ service_impl_.async_shutdown(impl, next_layer, handler);
+ }
+
+ /// Write some data to the stream.
+ template <typename Stream, typename ConstBufferSequence>
+ std::size_t write_some(impl_type& impl, Stream& next_layer,
+ const ConstBufferSequence& buffers, asio::error_code& ec)
+ {
+ return service_impl_.write_some(impl, next_layer, buffers, ec);
+ }
+
+ /// Start an asynchronous write.
+ template <typename Stream, typename ConstBufferSequence,
+ typename WriteHandler>
+ void async_write_some(impl_type& impl, Stream& next_layer,
+ const ConstBufferSequence& buffers, WriteHandler handler)
+ {
+ service_impl_.async_write_some(impl, next_layer, buffers, handler);
+ }
+
+ /// Read some data from the stream.
+ template <typename Stream, typename MutableBufferSequence>
+ std::size_t read_some(impl_type& impl, Stream& next_layer,
+ const MutableBufferSequence& buffers, asio::error_code& ec)
+ {
+ return service_impl_.read_some(impl, next_layer, buffers, ec);
+ }
+
+ /// Start an asynchronous read.
+ template <typename Stream, typename MutableBufferSequence,
+ typename ReadHandler>
+ void async_read_some(impl_type& impl, Stream& next_layer,
+ const MutableBufferSequence& buffers, ReadHandler handler)
+ {
+ service_impl_.async_read_some(impl, next_layer, buffers, handler);
+ }
+
+ /// Peek at the incoming data on the stream.
+ template <typename Stream, typename MutableBufferSequence>
+ std::size_t peek(impl_type& impl, Stream& next_layer,
+ const MutableBufferSequence& buffers, asio::error_code& ec)
+ {
+ return service_impl_.peek(impl, next_layer, buffers, ec);
+ }
+
+ /// Determine the amount of data that may be read without blocking.
+ template <typename Stream>
+ std::size_t in_avail(impl_type& impl, Stream& next_layer,
+ asio::error_code& ec)
+ {
+ return service_impl_.in_avail(impl, next_layer, ec);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace ssl
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SSL_STREAM_SERVICE_HPP
diff --git a/src/libtorrent/asio/strand.hpp b/src/libtorrent/asio/strand.hpp
new file mode 100644
index 0000000..065a9d9
--- /dev/null
+++ b/src/libtorrent/asio/strand.hpp
@@ -0,0 +1,186 @@
+//
+// strand.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_STRAND_HPP
+#define ASIO_STRAND_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/io_service.hpp"
+#include "asio/detail/strand_service.hpp"
+#include "asio/detail/wrapped_handler.hpp"
+
+namespace asio {
+
+/// Provides serialised handler execution.
+/**
+ * The io_service::strand class provides the ability to post and dispatch
+ * handlers with the guarantee that none of those handlers will execute
+ * concurrently.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Dispatcher.
+ */
+class io_service::strand
+{
+public:
+ /// Constructor.
+ /**
+ * Constructs the strand.
+ *
+ * @param io_service The io_service object that the strand will use to
+ * dispatch handlers that are ready to be run.
+ */
+ explicit strand(asio::io_service& io_service)
+ : service_(asio::use_service<
+ asio::detail::strand_service>(io_service))
+ {
+ service_.construct(impl_);
+ }
+
+ /// Destructor.
+ /**
+ * Destroys a strand.
+ *
+ * Handlers posted through the strand that have not yet been invoked will
+ * still be dispatched in a way that meets the guarantee of non-concurrency.
+ */
+ ~strand()
+ {
+ service_.destroy(impl_);
+ }
+
+ /// (Deprecated: use get_io_service().) Get the io_service associated with
+ /// the strand.
+ /**
+ * This function may be used to obtain the io_service object that the strand
+ * uses to dispatch handlers for asynchronous operations.
+ *
+ * @return A reference to the io_service object that the strand will use to
+ * dispatch handlers. Ownership is not transferred to the caller.
+ */
+ asio::io_service& io_service()
+ {
+ return service_.get_io_service();
+ }
+
+ /// Get the io_service associated with the strand.
+ /**
+ * This function may be used to obtain the io_service object that the strand
+ * uses to dispatch handlers for asynchronous operations.
+ *
+ * @return A reference to the io_service object that the strand will use to
+ * dispatch handlers. Ownership is not transferred to the caller.
+ */
+ asio::io_service& get_io_service()
+ {
+ return service_.get_io_service();
+ }
+
+ /// Request the strand to invoke the given handler.
+ /**
+ * This function is used to ask the strand to execute the given handler.
+ *
+ * The strand object guarantees that handlers posted or dispatched through
+ * the strand will not be executed concurrently. The handler may be executed
+ * inside this function if the guarantee can be met. If this function is
+ * called from within a handler that was posted or dispatched through the same
+ * strand, then the new handler will be executed immediately.
+ *
+ * The strand's guarantee is in addition to the guarantee provided by the
+ * underlying io_service. The io_service guarantees that the handler will only
+ * be called in a thread in which the io_service's run member function is
+ * currently being invoked.
+ *
+ * @param handler The handler to be called. The strand will make a copy of the
+ * handler object as required. The function signature of the handler must be:
+ * @code void handler(); @endcode
+ */
+ template <typename Handler>
+ void dispatch(Handler handler)
+ {
+ service_.dispatch(impl_, handler);
+ }
+
+ /// Request the strand to invoke the given handler and return
+ /// immediately.
+ /**
+ * This function is used to ask the strand to execute the given handler, but
+ * without allowing the strand to call the handler from inside this function.
+ *
+ * The strand object guarantees that handlers posted or dispatched through
+ * the strand will not be executed concurrently. The strand's guarantee is in
+ * addition to the guarantee provided by the underlying io_service. The
+ * io_service guarantees that the handler will only be called in a thread in
+ * which the io_service's run member function is currently being invoked.
+ *
+ * @param handler The handler to be called. The strand will make a copy of the
+ * handler object as required. The function signature of the handler must be:
+ * @code void handler(); @endcode
+ */
+ template <typename Handler>
+ void post(Handler handler)
+ {
+ service_.post(impl_, handler);
+ }
+
+ /// Create a new handler that automatically dispatches the wrapped handler
+ /// on the strand.
+ /**
+ * This function is used to create a new handler function object that, when
+ * invoked, will automatically pass the wrapped handler to the strand's
+ * dispatch function.
+ *
+ * @param handler The handler to be wrapped. The strand will make a copy of
+ * the handler object as required. The function signature of the handler must
+ * be: @code void handler(A1 a1, ... An an); @endcode
+ *
+ * @return A function object that, when invoked, passes the wrapped handler to
+ * the strand's dispatch function. Given a function object with the signature:
+ * @code R f(A1 a1, ... An an); @endcode
+ * If this function object is passed to the wrap function like so:
+ * @code strand.wrap(f); @endcode
+ * then the return value is a function object with the signature
+ * @code void g(A1 a1, ... An an); @endcode
+ * that, when invoked, executes code equivalent to:
+ * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode
+ */
+ template <typename Handler>
+#if defined(GENERATING_DOCUMENTATION)
+ unspecified
+#else
+ detail::wrapped_handler<strand, Handler>
+#endif
+ wrap(Handler handler)
+ {
+ return detail::wrapped_handler<io_service::strand, Handler>(*this, handler);
+ }
+
+private:
+ asio::detail::strand_service& service_;
+ asio::detail::strand_service::implementation_type impl_;
+};
+
+/// Typedef for backwards compatibility.
+typedef asio::io_service::strand strand;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_STRAND_HPP
diff --git a/src/libtorrent/asio/stream_socket_service.hpp b/src/libtorrent/asio/stream_socket_service.hpp
new file mode 100644
index 0000000..510d8cf
--- /dev/null
+++ b/src/libtorrent/asio/stream_socket_service.hpp
@@ -0,0 +1,286 @@
+//
+// stream_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_STREAM_SOCKET_SERVICE_HPP
+#define ASIO_STREAM_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error.hpp"
+#include "asio/io_service.hpp"
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/service_base.hpp"
+#include "asio/detail/win_iocp_socket_service.hpp"
+#include "asio/detail/reactive_socket_service.hpp"
+
+namespace asio {
+
+/// Default service implementation for a stream socket.
+template <typename Protocol>
+class stream_socket_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public asio::io_service::service
+#else
+ : public asio::detail::service_base<stream_socket_service<Protocol> >
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static asio::io_service::id id;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+private:
+ // The type of the platform-specific implementation.
+#if defined(ASIO_HAS_IOCP)
+ typedef detail::win_iocp_socket_service<Protocol> service_impl_type;
+#elif defined(ASIO_HAS_EPOLL)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::epoll_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_KQUEUE)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::kqueue_reactor<false> > service_impl_type;
+#elif defined(ASIO_HAS_DEV_POLL)
+ typedef detail::reactive_socket_service<
+ Protocol, detail::dev_poll_reactor<false> > service_impl_type;
+#else
+ typedef detail::reactive_socket_service<
+ Protocol, detail::select_reactor<false> > service_impl_type;
+#endif
+
+public:
+ /// The type of a stream socket implementation.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef typename service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// The native socket type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_type;
+#else
+ typedef typename service_impl_type::native_type native_type;
+#endif
+
+ /// Construct a new stream socket service for the specified io_service.
+ explicit stream_socket_service(asio::io_service& io_service)
+ : asio::detail::service_base<
+ stream_socket_service<Protocol> >(io_service),
+ service_impl_(asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Construct a new stream socket implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+ /// Destroy a stream socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ /// Open a stream socket.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::error_code& ec)
+ {
+ if (protocol.type() == SOCK_STREAM)
+ service_impl_.open(impl, protocol, ec);
+ else
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ /// Assign an existing native socket to a stream socket.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_type& native_socket,
+ asio::error_code& ec)
+ {
+ return service_impl_.assign(impl, protocol, native_socket, ec);
+ }
+
+ /// Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return service_impl_.is_open(impl);
+ }
+
+ /// Close a stream socket implementation.
+ asio::error_code close(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return service_impl_.close(impl, ec);
+ }
+
+ /// Get the native socket implementation.
+ native_type native(implementation_type& impl)
+ {
+ return service_impl_.native(impl);
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return service_impl_.cancel(impl, ec);
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.at_mark(impl, ec);
+ }
+
+ /// Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.available(impl, ec);
+ }
+
+ /// Bind the stream socket to the specified local endpoint.
+ asio::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ return service_impl_.bind(impl, endpoint, ec);
+ }
+
+ /// Connect the stream socket to the specified endpoint.
+ asio::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, asio::error_code& ec)
+ {
+ return service_impl_.connect(impl, peer_endpoint, ec);
+ }
+
+ /// Start an asynchronous connect.
+ template <typename ConnectHandler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, ConnectHandler handler)
+ {
+ service_impl_.async_connect(impl, peer_endpoint, handler);
+ }
+
+ /// Set a socket option.
+ template <typename SettableSocketOption>
+ asio::error_code set_option(implementation_type& impl,
+ const SettableSocketOption& option, asio::error_code& ec)
+ {
+ return service_impl_.set_option(impl, option, ec);
+ }
+
+ /// Get a socket option.
+ template <typename GettableSocketOption>
+ asio::error_code get_option(const implementation_type& impl,
+ GettableSocketOption& option, asio::error_code& ec) const
+ {
+ return service_impl_.get_option(impl, option, ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ template <typename IoControlCommand>
+ asio::error_code io_control(implementation_type& impl,
+ IoControlCommand& command, asio::error_code& ec)
+ {
+ return service_impl_.io_control(impl, command, ec);
+ }
+
+ /// Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.local_endpoint(impl, ec);
+ }
+
+ /// Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ return service_impl_.remote_endpoint(impl, ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ asio::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, asio::error_code& ec)
+ {
+ return service_impl_.shutdown(impl, what, ec);
+ }
+
+ /// Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ std::size_t send(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return service_impl_.send(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_send(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, WriteHandler handler)
+ {
+ service_impl_.async_send(impl, buffers, flags, handler);
+ }
+
+ /// Receive some data from the peer.
+ template <typename MutableBufferSequence>
+ std::size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return service_impl_.receive(impl, buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, ReadHandler handler)
+ {
+ service_impl_.async_receive(impl, buffers, flags, handler);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_STREAM_SOCKET_SERVICE_HPP
diff --git a/src/libtorrent/asio/streambuf.hpp b/src/libtorrent/asio/streambuf.hpp
new file mode 100644
index 0000000..e819867
--- /dev/null
+++ b/src/libtorrent/asio/streambuf.hpp
@@ -0,0 +1,31 @@
+//
+// streambuf.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_STREAMBUF_HPP
+#define ASIO_STREAMBUF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/basic_streambuf.hpp"
+
+namespace asio {
+
+/// Typedef for the typical usage of basic_streambuf.
+typedef basic_streambuf<> streambuf;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_STREAMBUF_HPP
diff --git a/src/libtorrent/asio/system_error.hpp b/src/libtorrent/asio/system_error.hpp
new file mode 100644
index 0000000..397ffb2
--- /dev/null
+++ b/src/libtorrent/asio/system_error.hpp
@@ -0,0 +1,117 @@
+//
+// system_error.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_SYSTEM_ERROR_HPP
+#define ASIO_SYSTEM_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <boost/config.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <cerrno>
+#include <exception>
+#include <string>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/error_code.hpp"
+
+namespace asio {
+
+/// The system_error class is used to represent system conditions that
+/// prevent the library from operating correctly.
+class system_error
+ : public std::exception
+{
+public:
+ /// Construct with an error code.
+ system_error(const error_code& code)
+ : code_(code),
+ context_()
+ {
+ }
+
+ /// Construct with an error code and context.
+ system_error(const error_code& code, const std::string& context)
+ : code_(code),
+ context_(context)
+ {
+ }
+
+ /// Copy constructor.
+ system_error(const system_error& other)
+ : std::exception(other),
+ code_(other.code_),
+ context_(other.context_),
+ what_()
+ {
+ }
+
+ /// Destructor.
+ virtual ~system_error() throw ()
+ {
+ }
+
+ /// Assignment operator.
+ system_error& operator=(const system_error& e)
+ {
+ context_ = e.context_;
+ code_ = e.code_;
+ what_.reset();
+ return *this;
+ }
+
+ /// Get a string representation of the exception.
+ virtual const char* what() const throw ()
+ {
+ try
+ {
+ if (!what_)
+ {
+ std::string tmp(context_);
+ if (tmp.length())
+ tmp += ": ";
+ tmp += code_.message();
+ what_.reset(new std::string(tmp));
+ }
+ return what_->c_str();
+ }
+ catch (std::exception&)
+ {
+ return "system_error";
+ }
+ }
+
+ /// Get the error code associated with the exception.
+ error_code code() const
+ {
+ return code_;
+ }
+
+private:
+ // The code associated with the error.
+ error_code code_;
+
+ // The context associated with the error.
+ std::string context_;
+
+ // The string representation of the error.
+ mutable boost::scoped_ptr<std::string> what_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_SYSTEM_ERROR_HPP
diff --git a/src/libtorrent/asio/thread.hpp b/src/libtorrent/asio/thread.hpp
new file mode 100644
index 0000000..7cc8cdf
--- /dev/null
+++ b/src/libtorrent/asio/thread.hpp
@@ -0,0 +1,91 @@
+//
+// thread.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_THREAD_HPP
+#define ASIO_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/thread.hpp"
+
+namespace asio {
+
+/// A simple abstraction for starting threads.
+/**
+ * The asio::thread class implements the smallest possible subset of the
+ * functionality of boost::thread. It is intended to be used only for starting
+ * a thread and waiting for it to exit. If more extensive threading
+ * capabilities are required, you are strongly advised to use something else.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe. at n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Example
+ * A typical use of asio::thread would be to launch a thread to run an
+ * io_service's event processing loop:
+ *
+ * @par
+ * @code asio::io_service io_service;
+ * // ...
+ * asio::thread t(boost::bind(&asio::io_service::run, &io_service));
+ * // ...
+ * t.join(); @endcode
+ */
+class thread
+ : private noncopyable
+{
+public:
+ /// Start a new thread that executes the supplied function.
+ /**
+ * This constructor creates a new thread that will execute the given function
+ * or function object.
+ *
+ * @param f The function or function object to be run in the thread. The
+ * function signature must be: @code void f(); @endcode
+ */
+ template <typename Function>
+ explicit thread(Function f)
+ : impl_(f)
+ {
+ }
+
+ /// Destructor.
+ ~thread()
+ {
+ }
+
+ /// Wait for the thread to exit.
+ /**
+ * This function will block until the thread has exited.
+ *
+ * If this function is not called before the thread object is destroyed, the
+ * thread itself will continue to run until completion. You will, however,
+ * no longer have the ability to wait for it to exit.
+ */
+ void join()
+ {
+ impl_.join();
+ }
+
+private:
+ detail::thread impl_;
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_THREAD_HPP
diff --git a/src/libtorrent/asio/time_traits.hpp b/src/libtorrent/asio/time_traits.hpp
new file mode 100644
index 0000000..18a30f2
--- /dev/null
+++ b/src/libtorrent/asio/time_traits.hpp
@@ -0,0 +1,78 @@
+//
+// time_traits.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_TIME_TRAITS_HPP
+#define ASIO_TIME_TRAITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/socket_types.hpp" // Must come before posix_time.
+
+#include "asio/detail/push_options.hpp"
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "asio/detail/pop_options.hpp"
+
+namespace asio {
+
+/// Time traits suitable for use with the deadline timer.
+template <typename Time>
+struct time_traits;
+
+/// Time traits specialised for posix_time.
+template <>
+struct time_traits<boost::posix_time::ptime>
+{
+ /// The time type.
+ typedef boost::posix_time::ptime time_type;
+
+ /// The duration type.
+ typedef boost::posix_time::time_duration duration_type;
+
+ /// Get the current time.
+ static time_type now()
+ {
+ return boost::posix_time::microsec_clock::universal_time();
+ }
+
+ /// Add a duration to a time.
+ static time_type add(const time_type& t, const duration_type& d)
+ {
+ return t + d;
+ }
+
+ /// Subtract one time from another.
+ static duration_type subtract(const time_type& t1, const time_type& t2)
+ {
+ return t1 - t2;
+ }
+
+ /// Test whether one time is less than another.
+ static bool less_than(const time_type& t1, const time_type& t2)
+ {
+ return t1 < t2;
+ }
+
+ /// Convert to POSIX duration type.
+ static boost::posix_time::time_duration to_posix_duration(
+ const duration_type& d)
+ {
+ return d;
+ }
+};
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_TIME_TRAITS_HPP
diff --git a/src/libtorrent/asio/version.hpp b/src/libtorrent/asio/version.hpp
new file mode 100644
index 0000000..df2fa9f
--- /dev/null
+++ b/src/libtorrent/asio/version.hpp
@@ -0,0 +1,23 @@
+//
+// version.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_VERSION_HPP
+#define ASIO_VERSION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+// ASIO_VERSION % 100 is the sub-minor version
+// ASIO_VERSION / 100 % 1000 is the minor version
+// ASIO_VERSION / 100000 is the major version
+#define ASIO_VERSION 100100 // 1.1.0
+
+#endif // ASIO_VERSION_HPP
diff --git a/src/libtorrent/asio/write.hpp b/src/libtorrent/asio/write.hpp
new file mode 100644
index 0000000..1c72c1c
--- /dev/null
+++ b/src/libtorrent/asio/write.hpp
@@ -0,0 +1,515 @@
+//
+// write.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_WRITE_HPP
+#define ASIO_WRITE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+#include "asio/detail/push_options.hpp"
+#include <cstddef>
+#include <boost/config.hpp>
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/basic_streambuf.hpp"
+#include "asio/error.hpp"
+
+namespace asio {
+
+/**
+ * @defgroup write asio::write
+ */
+/*@{*/
+
+/// Write all of the supplied data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * stream.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write(s, asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ * s, buffers,
+ * asio::transfer_all()); @endcode
+ */
+template <typename SyncWriteStream, typename ConstBufferSequence>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest write_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the write operation is complete. False
+ * indicates that further calls to the stream's write_some function are
+ * required.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::write(s, asio::buffer(data, size),
+ * asio::transfer_at_least(32)); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename SyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written. The sum
+ * of the buffer sizes indicates the maximum number of bytes to write to the
+ * stream.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest write_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the write operation is complete. False
+ * indicates that further calls to the stream's write_some function are
+ * required.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, asio::error_code& ec);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ *
+ * @note This overload is equivalent to calling:
+ * @code asio::write(
+ * s, b,
+ * asio::transfer_all()); @endcode
+ */
+template <typename SyncWriteStream, typename Allocator>
+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest write_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the write operation is complete. False
+ * indicates that further calls to the stream's write_some function are
+ * required.
+ *
+ * @returns The number of bytes transferred.
+ *
+ * @throws asio::system_error Thrown on failure.
+ */
+template <typename SyncWriteStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition);
+
+/// Write a certain amount of data to a stream before returning.
+/**
+ * This function is used to write a certain number of bytes of data to a stream.
+ * The call will block until one of the following conditions is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the SyncWriteStream concept.
+ *
+ * @param b The basic_streambuf object from which data will be written.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest write_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the write operation is complete. False
+ * indicates that further calls to the stream's write_some function are
+ * required.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. If an error occurs, returns the total
+ * number of bytes successfully transferred prior to the error.
+ */
+template <typename SyncWriteStream, typename Allocator,
+ typename CompletionCondition>
+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, asio::error_code& ec);
+
+/*@}*/
+/**
+ * @defgroup async_write asio::async_write
+ */
+/*@{*/
+
+/// Start an asynchronous operation to write of all of the supplied data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * async_write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes written from the
+ * // buffers. If an error occurred,
+ * // this will be less than the sum
+ * // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code
+ * asio::async_write(s, asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename WriteHandler>
+void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+ WriteHandler handler);
+
+/// Start an asynchronous operation to write a certain amount of data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied buffers has been written. That is, the
+ * bytes transferred is equal to the sum of the buffer sizes.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * async_write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param buffers One or more buffers containing the data to be written.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest write_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the write operation is complete. False
+ * indicates that further calls to the stream's async_write_some function are
+ * required.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes written from the
+ * // buffers. If an error occurred,
+ * // this will be less than the sum
+ * // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code asio::async_write(s,
+ * asio::buffer(data, size),
+ * asio::transfer_at_least(32),
+ * handler); @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+template <typename AsyncWriteStream, typename ConstBufferSequence,
+ typename CompletionCondition, typename WriteHandler>
+void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
+ CompletionCondition completion_condition, WriteHandler handler);
+
+/// Start an asynchronous operation to write a certain amount of data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li An error occurred.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * async_write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param b A basic_streambuf object from which data will be written. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes written from the
+ * // buffers. If an error occurred,
+ * // this will be less than the sum
+ * // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ */
+template <typename AsyncWriteStream, typename Allocator, typename WriteHandler>
+void async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
+ WriteHandler handler);
+
+/// Start an asynchronous operation to write a certain amount of data to a
+/// stream.
+/**
+ * This function is used to asynchronously write a certain number of bytes of
+ * data to a stream. The function call always returns immediately. The
+ * asynchronous operation will continue until one of the following conditions
+ * is true:
+ *
+ * @li All of the data in the supplied basic_streambuf has been written.
+ *
+ * @li The completion_condition function object returns true.
+ *
+ * This operation is implemented in terms of one or more calls to the stream's
+ * async_write_some function.
+ *
+ * @param s The stream to which the data is to be written. The type must support
+ * the AsyncWriteStream concept.
+ *
+ * @param b A basic_streambuf object from which data will be written. Ownership
+ * of the streambuf is retained by the caller, which must guarantee that it
+ * remains valid until the handler is called.
+ *
+ * @param completion_condition The function object to be called to determine
+ * whether the write operation is complete. The signature of the function object
+ * must be:
+ * @code bool completion_condition(
+ * const asio::error_code& error, // Result of latest write_some
+ * // operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes transferred
+ * // so far.
+ * ); @endcode
+ * A return value of true indicates that the write operation is complete. False
+ * indicates that further calls to the stream's async_write_some function are
+ * required.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of the
+ * handler must be:
+ * @code void handler(
+ * const asio::error_code& error, // Result of operation.
+ *
+ * std::size_t bytes_transferred // Number of bytes written from the
+ * // buffers. If an error occurred,
+ * // this will be less than the sum
+ * // of the buffer sizes.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. Invocation of
+ * the handler will be performed in a manner equivalent to using
+ * asio::io_service::post().
+ */
+template <typename AsyncWriteStream, typename Allocator,
+ typename CompletionCondition, typename WriteHandler>
+void async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
+ CompletionCondition completion_condition, WriteHandler handler);
+
+/*@}*/
+
+} // namespace asio
+
+#include "asio/impl/write.ipp"
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_WRITE_HPP
diff --git a/src/libtorrent/include/libtorrent/alert.hpp b/src/libtorrent/include/libtorrent/alert.hpp
new file mode 100644
index 0000000..ab8065f
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/alert.hpp
@@ -0,0 +1,168 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg, Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_ALERT_HPP_INCLUDED
+#define TORRENT_ALERT_HPP_INCLUDED
+
+#include <memory>
+#include <queue>
+#include <string>
+#include <typeinfo>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+
+#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
+#include <boost/preprocessor/repetition/enum.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/time.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+
+#ifndef TORRENT_MAX_ALERT_TYPES
+#define TORRENT_MAX_ALERT_TYPES 15
+#endif
+
+namespace libtorrent {
+
+ class TORRENT_EXPORT alert
+ {
+ public:
+ enum severity_t { debug, info, warning, critical, fatal, none };
+
+ alert(severity_t severity, const std::string& msg);
+ virtual ~alert();
+
+ // a timestamp is automatically created in the constructor
+ ptime timestamp() const;
+
+ std::string const& msg() const;
+
+ severity_t severity() const;
+
+ virtual std::auto_ptr<alert> clone() const = 0;
+
+ private:
+ std::string m_msg;
+ severity_t m_severity;
+ ptime m_timestamp;
+ };
+
+ class TORRENT_EXPORT alert_manager
+ {
+ public:
+ alert_manager();
+ ~alert_manager();
+
+ void post_alert(const alert& alert_);
+ bool pending() const;
+ std::auto_ptr<alert> get();
+
+ void set_severity(alert::severity_t severity);
+ bool should_post(alert::severity_t severity) const;
+
+ alert const* wait_for_alert(time_duration max_wait);
+
+ private:
+ std::queue<alert*> m_alerts;
+ alert::severity_t m_severity;
+ mutable boost::mutex m_mutex;
+ boost::condition m_condition;
+ };
+
+ struct TORRENT_EXPORT unhandled_alert : std::exception
+ {
+ unhandled_alert() {}
+ };
+
+ namespace detail {
+
+ struct void_;
+
+ template<class Handler
+ , BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, class T)>
+ void handle_alert_dispatch(
+ const std::auto_ptr<alert>& alert_, const Handler& handler
+ , const std::type_info& typeid_
+ , BOOST_PP_ENUM_BINARY_PARAMS(TORRENT_MAX_ALERT_TYPES, T, *p))
+ {
+ if (typeid_ == typeid(T0))
+ handler(*static_cast<T0*>(alert_.get()));
+ else
+ handle_alert_dispatch(alert_, handler, typeid_
+ , BOOST_PP_ENUM_SHIFTED_PARAMS(
+ TORRENT_MAX_ALERT_TYPES, p), (void_*)0);
+ }
+
+ template<class Handler>
+ void handle_alert_dispatch(
+ const std::auto_ptr<alert>& alert_
+ , const Handler& handler
+ , const std::type_info& typeid_
+ , BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, void_* BOOST_PP_INTERCEPT))
+ {
+ throw unhandled_alert();
+ }
+
+ } // namespace detail
+
+ template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
+ TORRENT_MAX_ALERT_TYPES, class T, detail::void_)>
+ struct TORRENT_EXPORT handle_alert
+ {
+ template<class Handler>
+ handle_alert(const std::auto_ptr<alert>& alert_
+ , const Handler& handler)
+ {
+ #define ALERT_POINTER_TYPE(z, n, text) (BOOST_PP_CAT(T, n)*)0
+
+ detail::handle_alert_dispatch(alert_, handler, typeid(*alert_)
+ , BOOST_PP_ENUM(TORRENT_MAX_ALERT_TYPES, ALERT_POINTER_TYPE, _));
+
+ #undef ALERT_POINTER_TYPE
+ }
+ };
+
+} // namespace libtorrent
+
+#endif // TORRENT_ALERT_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/alert_types.hpp b/src/libtorrent/include/libtorrent/alert_types.hpp
new file mode 100644
index 0000000..a1dcf43
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/alert_types.hpp
@@ -0,0 +1,445 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_ALERT_TYPES_HPP_INCLUDED
+#define TORRENT_ALERT_TYPES_HPP_INCLUDED
+
+#include "libtorrent/alert.hpp"
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ struct TORRENT_EXPORT torrent_alert: alert
+ {
+ torrent_alert(torrent_handle const& h, alert::severity_t s
+ , std::string const& msg)
+ : alert(s, msg)
+ , handle(h)
+ {}
+
+ torrent_handle handle;
+ };
+
+ struct TORRENT_EXPORT tracker_alert: torrent_alert
+ {
+ tracker_alert(torrent_handle const& h
+ , int times
+ , int status
+ , std::string const& msg)
+ : torrent_alert(h, alert::warning, msg)
+ , times_in_row(times)
+ , status_code(status)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new tracker_alert(*this)); }
+
+ int times_in_row;
+ int status_code;
+ };
+
+ struct TORRENT_EXPORT tracker_warning_alert: torrent_alert
+ {
+ tracker_warning_alert(torrent_handle const& h
+ , std::string const& msg)
+ : torrent_alert(h, alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new tracker_warning_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT scrape_reply_alert: torrent_alert
+ {
+ scrape_reply_alert(torrent_handle const& h
+ , int incomplete_
+ , int complete_
+ , std::string const& msg)
+ : torrent_alert(h, alert::info, msg)
+ , incomplete(incomplete_)
+ , complete(complete_)
+ {}
+
+ int incomplete;
+ int complete;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new scrape_reply_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT scrape_failed_alert: torrent_alert
+ {
+ scrape_failed_alert(torrent_handle const& h
+ , std::string const& msg)
+ : torrent_alert(h, alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new scrape_failed_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT tracker_reply_alert: torrent_alert
+ {
+ tracker_reply_alert(torrent_handle const& h
+ , int np
+ , std::string const& msg)
+ : torrent_alert(h, alert::info, msg)
+ , num_peers(np)
+ {}
+
+ int num_peers;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new tracker_reply_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT tracker_announce_alert: torrent_alert
+ {
+ tracker_announce_alert(torrent_handle const& h, std::string const& msg)
+ : torrent_alert(h, alert::info, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new tracker_announce_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT hash_failed_alert: torrent_alert
+ {
+ hash_failed_alert(
+ torrent_handle const& h
+ , int index
+ , std::string const& msg)
+ : torrent_alert(h, alert::info, msg)
+ , piece_index(index)
+ { TORRENT_ASSERT(index >= 0);}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new hash_failed_alert(*this)); }
+
+ int piece_index;
+ };
+
+ struct TORRENT_EXPORT peer_ban_alert: torrent_alert
+ {
+ peer_ban_alert(tcp::endpoint const& pip, torrent_handle h, std::string const& msg)
+ : torrent_alert(h, alert::info, msg)
+ , ip(pip)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new peer_ban_alert(*this)); }
+
+ tcp::endpoint ip;
+ };
+
+ struct TORRENT_EXPORT peer_error_alert: alert
+ {
+ peer_error_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg)
+ : alert(alert::debug, msg)
+ , ip(pip)
+ , pid(pid_)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new peer_error_alert(*this)); }
+
+ tcp::endpoint ip;
+ peer_id pid;
+ };
+
+ struct TORRENT_EXPORT invalid_request_alert: torrent_alert
+ {
+ invalid_request_alert(
+ peer_request const& r
+ , torrent_handle const& h
+ , tcp::endpoint const& sender
+ , peer_id const& pid_
+ , std::string const& msg)
+ : torrent_alert(h, alert::debug, msg)
+ , ip(sender)
+ , request(r)
+ , pid(pid_)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new invalid_request_alert(*this)); }
+
+ tcp::endpoint ip;
+ peer_request request;
+ peer_id pid;
+ };
+
+ struct TORRENT_EXPORT torrent_finished_alert: torrent_alert
+ {
+ torrent_finished_alert(
+ const torrent_handle& h
+ , const std::string& msg)
+ : torrent_alert(h, alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new torrent_finished_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT piece_finished_alert: torrent_alert
+ {
+ piece_finished_alert(
+ const torrent_handle& h
+ , int piece_num
+ , const std::string& msg)
+ : torrent_alert(h, alert::debug, msg)
+ , piece_index(piece_num)
+ { TORRENT_ASSERT(piece_index >= 0);}
+
+ int piece_index;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new piece_finished_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT block_finished_alert: torrent_alert
+ {
+ block_finished_alert(
+ const torrent_handle& h
+ , int block_num
+ , int piece_num
+ , const std::string& msg)
+ : torrent_alert(h, alert::debug, msg)
+ , block_index(block_num)
+ , piece_index(piece_num)
+ { TORRENT_ASSERT(block_index >= 0 && piece_index >= 0);}
+
+ int block_index;
+ int piece_index;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new block_finished_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT block_downloading_alert: torrent_alert
+ {
+ block_downloading_alert(
+ const torrent_handle& h
+ , char const* speedmsg
+ , int block_num
+ , int piece_num
+ , const std::string& msg)
+ : torrent_alert(h, alert::debug, msg)
+ , peer_speedmsg(speedmsg)
+ , block_index(block_num)
+ , piece_index(piece_num)
+ { TORRENT_ASSERT(block_index >= 0 && piece_index >= 0);}
+
+ std::string peer_speedmsg;
+ int block_index;
+ int piece_index;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new block_downloading_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT storage_moved_alert: torrent_alert
+ {
+ storage_moved_alert(torrent_handle const& h, std::string const& path)
+ : torrent_alert(h, alert::warning, path)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new storage_moved_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT torrent_deleted_alert: torrent_alert
+ {
+ torrent_deleted_alert(torrent_handle const& h, std::string const& msg)
+ : torrent_alert(h, alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new torrent_deleted_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT torrent_paused_alert: torrent_alert
+ {
+ torrent_paused_alert(torrent_handle const& h, std::string const& msg)
+ : torrent_alert(h, alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new torrent_paused_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT torrent_checked_alert: torrent_alert
+ {
+ torrent_checked_alert(torrent_handle const& h, std::string const& msg)
+ : torrent_alert(h, alert::info, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new torrent_checked_alert(*this)); }
+ };
+
+
+ struct TORRENT_EXPORT url_seed_alert: torrent_alert
+ {
+ url_seed_alert(
+ torrent_handle const& h
+ , const std::string& url_
+ , const std::string& msg)
+ : torrent_alert(h, alert::warning, msg)
+ , url(url_)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new url_seed_alert(*this)); }
+
+ std::string url;
+ };
+
+ struct TORRENT_EXPORT file_error_alert: torrent_alert
+ {
+ file_error_alert(
+ const torrent_handle& h
+ , const std::string& msg)
+ : torrent_alert(h, alert::fatal, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new file_error_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT metadata_failed_alert: torrent_alert
+ {
+ metadata_failed_alert(
+ const torrent_handle& h
+ , const std::string& msg)
+ : torrent_alert(h, alert::info, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new metadata_failed_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT metadata_received_alert: torrent_alert
+ {
+ metadata_received_alert(
+ const torrent_handle& h
+ , const std::string& msg)
+ : torrent_alert(h, alert::info, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new metadata_received_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT listen_failed_alert: alert
+ {
+ listen_failed_alert(
+ tcp::endpoint const& ep
+ , std::string const& msg)
+ : alert(alert::fatal, msg)
+ , endpoint(ep)
+ {}
+
+ tcp::endpoint endpoint;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new listen_failed_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT listen_succeeded_alert: alert
+ {
+ listen_succeeded_alert(
+ tcp::endpoint const& ep
+ , std::string const& msg)
+ : alert(alert::fatal, msg)
+ , endpoint(ep)
+ {}
+
+ tcp::endpoint endpoint;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new listen_succeeded_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT portmap_error_alert: alert
+ {
+ portmap_error_alert(const std::string& msg)
+ : alert(alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new portmap_error_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT portmap_alert: alert
+ {
+ portmap_alert(const std::string& msg)
+ : alert(alert::info, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new portmap_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT fastresume_rejected_alert: torrent_alert
+ {
+ fastresume_rejected_alert(torrent_handle const& h
+ , std::string const& msg)
+ : torrent_alert(h, alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new fastresume_rejected_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT peer_blocked_alert: alert
+ {
+ peer_blocked_alert(address const& ip_
+ , std::string const& msg)
+ : alert(alert::info, msg)
+ , ip(ip_)
+ {}
+
+ address ip;
+
+ virtual std::auto_ptr<alert> clone() const
+ { return std::auto_ptr<alert>(new peer_blocked_alert(*this)); }
+ };
+
+}
+
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/assert.hpp b/src/libtorrent/include/libtorrent/assert.hpp
new file mode 100644
index 0000000..dd3c6b7
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/assert.hpp
@@ -0,0 +1,49 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_ASSERT
+
+#include "libtorrent/config.hpp"
+#include <cassert>
+
+#if (defined __linux__ || defined __MACH__) && defined __GNUC__ && !defined(NDEBUG)
+
+TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, char const* function);
+#define TORRENT_ASSERT(x) if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__)
+
+#else
+#include <cassert>
+#define TORRENT_ASSERT(x) assert(x)
+#endif
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/aux_/session_impl.hpp b/src/libtorrent/include/libtorrent/aux_/session_impl.hpp
new file mode 100644
index 0000000..03e9cb6
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/aux_/session_impl.hpp
@@ -0,0 +1,671 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SESSION_IMPL_HPP_INCLUDED
+#define TORRENT_SESSION_IMPL_HPP_INCLUDED
+
+#include <ctime>
+#include <algorithm>
+#include <vector>
+#include <set>
+#include <list>
+#include <deque>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/limits.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/policy.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/peer_info.hpp"
+#include "libtorrent/alert.hpp"
+#include "libtorrent/fingerprint.hpp"
+#include "libtorrent/debug.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/piece_block_progress.hpp"
+#include "libtorrent/ip_filter.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/session_settings.hpp"
+#include "libtorrent/kademlia/dht_tracker.hpp"
+#include "libtorrent/session_status.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/stat.hpp"
+#include "libtorrent/file_pool.hpp"
+#include "libtorrent/bandwidth_manager.hpp"
+#include "libtorrent/natpmp.hpp"
+#include "libtorrent/upnp.hpp"
+#include "libtorrent/lsd.hpp"
+#include "libtorrent/socket_type.hpp"
+#include "libtorrent/connection_queue.hpp"
+#include "libtorrent/disk_io_thread.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ namespace fs = boost::filesystem;
+
+ namespace aux
+ {
+ struct session_impl;
+
+ // this data is shared between the main thread and the
+ // thread that initialize pieces
+ struct piece_checker_data
+ {
+ piece_checker_data()
+ : processing(false), progress(0.f), abort(false) {}
+
+ boost::shared_ptr<torrent> torrent_ptr;
+ fs::path save_path;
+
+ sha1_hash info_hash;
+
+ void parse_resume_data(
+ const entry& rd
+ , const torrent_info& info
+ , std::string& error);
+
+ std::vector<int> piece_map;
+ std::vector<piece_picker::downloading_piece> unfinished_pieces;
+ std::vector<piece_picker::block_info> block_info;
+ std::vector<tcp::endpoint> peers;
+ std::vector<tcp::endpoint> banned_peers;
+ entry resume_data;
+
+ // this is true if this torrent is being processed (checked)
+ // if it is not being processed, then it can be removed from
+ // the queue without problems, otherwise the abort flag has
+ // to be set.
+ bool processing;
+
+ // is filled in by storage::initialize_pieces()
+ // and represents the progress. It should be a
+ // value in the range [0, 1]
+ float progress;
+
+ // abort defaults to false and is typically
+ // filled in by torrent_handle when the user
+ // aborts the torrent
+ bool abort;
+ };
+
+ struct checker_impl: boost::noncopyable
+ {
+ checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
+ void operator()();
+ piece_checker_data* find_torrent(const sha1_hash& info_hash);
+ void remove_torrent(sha1_hash const& info_hash, int options);
+
+#ifndef NDEBUG
+ void check_invariant() const;
+#endif
+
+ // when the files has been checked
+ // the torrent is added to the session
+ session_impl& m_ses;
+
+ mutable boost::mutex m_mutex;
+ boost::condition m_cond;
+
+ // a list of all torrents that are currently in queue
+ // or checking their files
+ std::deque<boost::shared_ptr<piece_checker_data> > m_torrents;
+ std::deque<boost::shared_ptr<piece_checker_data> > m_processing;
+
+ bool m_abort;
+ };
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ struct tracker_logger;
+#endif
+
+ // this is the link between the main thread and the
+ // thread started to run the main downloader loop
+ struct session_impl: boost::noncopyable
+ {
+
+ // the size of each allocation that is chained in the send buffer
+ enum { send_buffer_size = 200 };
+
+#ifndef NDEBUG
+ friend class ::libtorrent::peer_connection;
+#endif
+ friend struct checker_impl;
+ friend class invariant_access;
+ typedef std::set<boost::intrusive_ptr<peer_connection> > connection_map;
+ typedef std::map<sha1_hash, boost::shared_ptr<torrent> > torrent_map;
+
+ session_impl(
+ std::pair<int, int> listen_port_range
+ , fingerprint const& cl_fprint
+ , char const* listen_interface
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , fs::path const& logpath
+#endif
+ );
+ ~session_impl();
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(
+ torrent*, void*)> ext);
+#endif
+ void operator()();
+
+ void open_listen_port() throw();
+
+ // if we are listening on an IPv6 interface
+ // this will return one of the IPv6 addresses on this
+ // machine, otherwise just an empty endpoint
+ tcp::endpoint get_ipv6_interface() const;
+
+ void async_accept(boost::shared_ptr<socket_acceptor> const& listener);
+ void on_incoming_connection(boost::shared_ptr<socket_type> const& s
+ , boost::weak_ptr<socket_acceptor> listener, asio::error_code const& e);
+
+ // must be locked to access the data
+ // in this struct
+ typedef boost::recursive_mutex mutex_t;
+ mutable mutex_t m_mutex;
+
+ boost::weak_ptr<torrent> find_torrent(const sha1_hash& info_hash);
+ peer_id const& get_peer_id() const { return m_peer_id; }
+
+ void close_connection(boost::intrusive_ptr<peer_connection> const& p);
+ void connection_failed(boost::intrusive_ptr<peer_connection> const& p
+ , tcp::endpoint const& a, char const* message);
+
+ void set_settings(session_settings const& s);
+ session_settings const& settings() const { return m_settings; }
+
+#ifndef TORRENT_DISABLE_DHT
+ void add_dht_node(std::pair<std::string, int> const& node);
+ void add_dht_node(udp::endpoint n);
+ void add_dht_router(std::pair<std::string, int> const& node);
+ void set_dht_settings(dht_settings const& s);
+ dht_settings const& get_dht_settings() const { return m_dht_settings; }
+ void start_dht(entry const& startup_state);
+ void stop_dht();
+ entry dht_state() const;
+#endif
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ void set_pe_settings(pe_settings const& settings);
+ pe_settings const& get_pe_settings() const { return m_pe_settings; }
+#endif
+
+ // called when a port mapping is successful, or a router returns
+ // a failure to map a port
+ void on_port_mapping(int tcp_port, int udp_port, std::string const& errmsg);
+
+ bool is_aborted() const { return m_abort; }
+
+ void set_ip_filter(ip_filter const& f);
+ void set_port_filter(port_filter const& f);
+
+ bool listen_on(
+ std::pair<int, int> const& port_range
+ , const char* net_interface = 0);
+ bool is_listening() const;
+
+ torrent_handle add_torrent(
+ boost::intrusive_ptr<torrent_info> ti
+ , fs::path const& save_path
+ , entry const& resume_data
+ , storage_mode_t storage_mode
+ , storage_constructor_type sc
+ , bool paused
+ , void* userdata);
+
+ torrent_handle add_torrent(
+ char const* tracker_url
+ , sha1_hash const& info_hash
+ , char const* name
+ , fs::path const& save_path
+ , entry const& resume_data
+ , storage_mode_t storage_mode
+ , storage_constructor_type sc
+ , bool paused
+ , void* userdata);
+
+ void remove_torrent(torrent_handle const& h, int options);
+
+ std::vector<torrent_handle> get_torrents();
+
+ void set_severity_level(alert::severity_t s);
+ std::auto_ptr<alert> pop_alert();
+
+ alert const* wait_for_alert(time_duration max_wait);
+
+ int upload_rate_limit() const;
+ int download_rate_limit() const;
+
+ void set_download_rate_limit(int bytes_per_second);
+ void set_upload_rate_limit(int bytes_per_second);
+ void set_max_half_open_connections(int limit);
+ void set_max_connections(int limit);
+ void set_max_uploads(int limit);
+
+ int max_connections() const { return m_max_connections; }
+ int max_uploads() const { return m_max_uploads; }
+ int max_half_open_connections() const { return m_half_open.limit(); }
+
+ int num_uploads() const { return m_num_unchoked; }
+ int num_connections() const
+ { return m_connections.size(); }
+
+ void unchoke_peer(peer_connection& c)
+ {
+ torrent* t = c.associated_torrent().lock().get();
+ TORRENT_ASSERT(t);
+ if (t->unchoke_peer(c))
+ ++m_num_unchoked;
+ }
+
+ session_status status() const;
+ void set_peer_id(peer_id const& id);
+ void set_key(int key);
+ unsigned short listen_port() const;
+
+ void abort();
+
+ torrent_handle find_torrent_handle(sha1_hash const& info_hash);
+
+ void announce_lsd(sha1_hash const& ih);
+
+ void set_peer_proxy(proxy_settings const& s)
+ { m_peer_proxy = s; }
+ void set_web_seed_proxy(proxy_settings const& s)
+ { m_web_seed_proxy = s; }
+ void set_tracker_proxy(proxy_settings const& s)
+ { m_tracker_proxy = s; }
+
+ proxy_settings const& peer_proxy() const
+ { return m_peer_proxy; }
+ proxy_settings const& web_seed_proxy() const
+ { return m_web_seed_proxy; }
+ proxy_settings const& tracker_proxy() const
+ { return m_tracker_proxy; }
+
+#ifndef TORRENT_DISABLE_DHT
+ void set_dht_proxy(proxy_settings const& s)
+ { m_dht_proxy = s; }
+ proxy_settings const& dht_proxy() const
+ { return m_dht_proxy; }
+#endif
+
+#ifdef TORRENT_STATS
+ void log_buffer_usage()
+ {
+ int send_buffer_capacity = 0;
+ int used_send_buffer = 0;
+ for (connection_map::const_iterator i = m_connections.begin()
+ , end(m_connections.end()); i != end; ++i)
+ {
+ send_buffer_capacity += (*i)->send_buffer_capacity();
+ used_send_buffer += (*i)->send_buffer_size();
+ }
+ TORRENT_ASSERT(send_buffer_capacity >= used_send_buffer);
+ m_buffer_usage_logger << log_time() << " send_buffer_size: " << send_buffer_capacity << std::endl;
+ m_buffer_usage_logger << log_time() << " used_send_buffer: " << used_send_buffer << std::endl;
+ m_buffer_usage_logger << log_time() << " send_buffer_utilization: "
+ << (used_send_buffer * 100.f / send_buffer_capacity) << std::endl;
+ }
+#endif
+ void start_lsd();
+ void start_natpmp();
+ void start_upnp();
+
+ void stop_lsd();
+ void stop_natpmp();
+ void stop_upnp();
+
+ // handles delayed alerts
+ alert_manager m_alerts;
+
+ std::pair<char*, int> allocate_buffer(int size);
+ void free_buffer(char* buf, int size);
+ void free_disk_buffer(char* buf);
+
+ address m_external_address;
+
+// private:
+
+ void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih);
+
+ // this pool is used to allocate and recycle send
+ // buffers from.
+ boost::pool<> m_send_buffers;
+ boost::mutex m_send_buffer_mutex;
+
+ // the file pool that all storages in this session's
+ // torrents uses. It sets a limit on the number of
+ // open files by this session.
+ // file pool must be destructed after the torrents
+ // since they will still have references to it
+ // when they are destructed.
+ file_pool m_files;
+
+ // handles disk io requests asynchronously
+ // peers have pointers into the disk buffer
+ // pool, and must be destructed before this
+ // object. The disk thread relies on the file
+ // pool object, and must be destructed before
+ // m_files.
+ disk_io_thread m_disk_thread;
+
+ // this is where all active sockets are stored.
+ // the selector can sleep while there's no activity on
+ // them
+ io_service m_io_service;
+ asio::strand m_strand;
+
+ // this is a list of half-open tcp connections
+ // (only outgoing connections)
+ // this has to be one of the last
+ // members to be destructed
+ connection_queue m_half_open;
+
+ // the bandwidth manager is responsible for
+ // handing out bandwidth to connections that
+ // asks for it, it can also throttle the
+ // rate.
+ bandwidth_manager<peer_connection, torrent> m_download_channel;
+ bandwidth_manager<peer_connection, torrent> m_upload_channel;
+
+ bandwidth_manager<peer_connection, torrent>* m_bandwidth_manager[2];
+
+ tracker_manager m_tracker_manager;
+ torrent_map m_torrents;
+
+ // this maps sockets to their peer_connection
+ // object. It is the complete list of all connected
+ // peers.
+ connection_map m_connections;
+
+ // filters incoming connections
+ ip_filter m_ip_filter;
+
+ // filters outgoing connections
+ port_filter m_port_filter;
+
+ // the peer id that is generated at the start of the session
+ peer_id m_peer_id;
+
+ // the key is an id that is used to identify the
+ // client with the tracker only. It is randomized
+ // at startup
+ int m_key;
+
+ // the number of retries we make when binding the
+ // listen socket. For each retry the port number
+ // is incremented by one
+ int m_listen_port_retries;
+
+ // the ip-address of the interface
+ // we are supposed to listen on.
+ // if the ip is set to zero, it means
+ // that we should let the os decide which
+ // interface to listen on
+ tcp::endpoint m_listen_interface;
+
+ // if we're listening on an IPv6 interface
+ // this is one of the non local IPv6 interfaces
+ // on this machine
+ tcp::endpoint m_ipv6_interface;
+
+ struct listen_socket_t
+ {
+ listen_socket_t(): external_port(0) {}
+ // this is typically set to the same as the local
+ // listen port. In case a NAT port forward was
+ // successfully opened, this will be set to the
+ // port that is open on the external (NAT) interface
+ // on the NAT box itself. This is the port that has
+ // to be published to peers, since this is the port
+ // the client is reachable through.
+ int external_port;
+
+ // the actual socket
+ boost::shared_ptr<socket_acceptor> sock;
+ };
+ // since we might be listening on multiple interfaces
+ // we might need more than one listen socket
+ std::list<listen_socket_t> m_listen_sockets;
+
+ listen_socket_t setup_listener(tcp::endpoint ep, int retries, bool v6_only = false);
+
+ // the settings for the client
+ session_settings m_settings;
+ // the proxy settings for different
+ // kinds of connections
+ proxy_settings m_peer_proxy;
+ proxy_settings m_web_seed_proxy;
+ proxy_settings m_tracker_proxy;
+#ifndef TORRENT_DISABLE_DHT
+ proxy_settings m_dht_proxy;
+#endif
+
+ // set to true when the session object
+ // is being destructed and the thread
+ // should exit
+ volatile bool m_abort;
+
+ int m_max_uploads;
+ int m_max_connections;
+
+ // the number of unchoked peers
+ int m_num_unchoked;
+
+ // this is initialized to the unchoke_interval
+ // session_setting and decreased every second.
+ // when it reaches zero, it is reset to the
+ // unchoke_interval and the unchoke set is
+ // recomputed.
+ int m_unchoke_time_scaler;
+
+ // works like unchoke_time_scaler but it
+ // is only decresed when the unchoke set
+ // is recomputed, and when it reaches zero,
+ // the optimistic unchoke is moved to another peer.
+ int m_optimistic_unchoke_time_scaler;
+
+ // works like unchoke_time_scaler. Each time
+ // it reaches 0, and all the connections are
+ // used, the worst connection will be disconnected
+ // from the torrent with the most peers
+ int m_disconnect_time_scaler;
+
+ // statistics gathered from all torrents.
+ stat m_stat;
+
+ // is false by default and set to true when
+ // the first incoming connection is established
+ // this is used to know if the client is behind
+ // NAT or not.
+ bool m_incoming_connection;
+
+ void second_tick(asio::error_code const& e);
+ ptime m_last_tick;
+
+#ifndef TORRENT_DISABLE_DHT
+ boost::intrusive_ptr<dht::dht_tracker> m_dht;
+ dht_settings m_dht_settings;
+ // if this is set to true, the dht listen port
+ // will be set to the same as the tcp listen port
+ // and will be synchronlized with it as it changes
+ // it defaults to true
+ bool m_dht_same_port;
+
+ // see m_external_listen_port. This is the same
+ // but for the udp port used by the DHT.
+ int m_external_udp_port;
+#endif
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ pe_settings m_pe_settings;
+#endif
+
+ boost::intrusive_ptr<natpmp> m_natpmp;
+ boost::intrusive_ptr<upnp> m_upnp;
+ boost::intrusive_ptr<lsd> m_lsd;
+
+ // the timer used to fire the second_tick
+ deadline_timer m_timer;
+
+ // the index of the torrent that will be offered to
+ // connect to a peer next time second_tick is called.
+ // This implements a round robin.
+ int m_next_connect_torrent;
+#ifndef NDEBUG
+ void check_invariant() const;
+#endif
+
+#ifdef TORRENT_STATS
+ // logger used to write bandwidth usage statistics
+ std::ofstream m_stats_logger;
+ int m_second_counter;
+ // used to log send buffer usage statistics
+ std::ofstream m_buffer_usage_logger;
+ // the number of send buffers that are allocated
+ int m_buffer_allocations;
+#endif
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<logger> create_log(std::string const& name
+ , int instance, bool append = true);
+
+ // this list of tracker loggers serves as tracker_callbacks when
+ // shutting down. This list is just here to keep them alive during
+ // whe shutting down process
+ std::list<boost::shared_ptr<tracker_logger> > m_tracker_loggers;
+
+ fs::path m_logpath;
+ public:
+ boost::shared_ptr<logger> m_logger;
+ private:
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ typedef std::list<boost::function<boost::shared_ptr<
+ torrent_plugin>(torrent*, void*)> > extension_list_t;
+
+ extension_list_t m_extensions;
+#endif
+
+ // data shared between the main thread
+ // and the checker thread
+ checker_impl m_checker_impl;
+
+ // the main working thread
+ boost::scoped_ptr<boost::thread> m_thread;
+
+ // the thread that calls initialize_pieces()
+ // on all torrents before they start downloading
+ boost::scoped_ptr<boost::thread> m_checker_thread;
+ };
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ struct tracker_logger : request_callback
+ {
+ tracker_logger(session_impl& ses): m_ses(ses) {}
+ void tracker_warning(std::string const& str)
+ {
+ debug_log("*** tracker warning: " + str);
+ }
+
+ void tracker_response(tracker_request const&
+ , std::vector<peer_entry>& peers
+ , int interval
+ , int complete
+ , int incomplete)
+ {
+ std::stringstream s;
+ s << "TRACKER RESPONSE:\n"
+ "interval: " << interval << "\n"
+ "peers:\n";
+ for (std::vector<peer_entry>::const_iterator i = peers.begin();
+ i != peers.end(); ++i)
+ {
+ s << " " << std::setfill(' ') << std::setw(16) << i->ip
+ << " " << std::setw(5) << std::dec << i->port << " ";
+ if (!i->pid.is_all_zeros()) s << " " << i->pid;
+ s << "\n";
+ }
+ debug_log(s.str());
+ }
+
+ void tracker_request_timed_out(
+ tracker_request const&)
+ {
+ debug_log("*** tracker timed out");
+ }
+
+ void tracker_request_error(
+ tracker_request const&
+ , int response_code
+ , const std::string& str)
+ {
+ debug_log(std::string("*** tracker error: ")
+ + boost::lexical_cast<std::string>(response_code) + ": "
+ + str);
+ }
+
+ void debug_log(const std::string& line)
+ {
+ (*m_ses.m_logger) << time_now_string() << " " << line << "\n";
+ }
+ session_impl& m_ses;
+ };
+#endif
+
+ }
+}
+
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/bandwidth_limit.hpp b/src/libtorrent/include/libtorrent/bandwidth_limit.hpp
new file mode 100644
index 0000000..e0675aa
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/bandwidth_limit.hpp
@@ -0,0 +1,120 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_BANDWIDTH_LIMIT_HPP_INCLUDED
+#define TORRENT_BANDWIDTH_LIMIT_HPP_INCLUDED
+
+#include <boost/integer_traits.hpp>
+
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent {
+
+// member of peer_connection
+struct bandwidth_limit
+{
+ static const int inf = boost::integer_traits<int>::const_max;
+
+ bandwidth_limit()
+ : m_quota_left(0)
+ , m_local_limit(inf)
+ , m_current_rate(0)
+ {}
+
+ void throttle(int limit)
+ {
+ TORRENT_ASSERT(limit > 0);
+ m_local_limit = limit;
+ }
+
+ int throttle() const
+ {
+ return m_local_limit;
+ }
+
+ void assign(int amount)
+ {
+ TORRENT_ASSERT(amount >= 0);
+ m_current_rate += amount;
+ m_quota_left += amount;
+ }
+
+ void use_quota(int amount)
+ {
+ TORRENT_ASSERT(amount <= m_quota_left);
+ m_quota_left -= amount;
+ }
+
+ int quota_left() const
+ {
+ return (std::max)(m_quota_left, 0);
+ }
+
+ void expire(int amount)
+ {
+ TORRENT_ASSERT(amount >= 0);
+ m_current_rate -= amount;
+ }
+
+ int max_assignable() const
+ {
+ if (m_local_limit == inf) return inf;
+ if (m_local_limit <= m_current_rate) return 0;
+ return m_local_limit - m_current_rate;
+ }
+
+private:
+
+ // this is the amount of bandwidth we have
+ // been assigned without using yet. i.e.
+ // the bandwidth that we use up every time
+ // we receive or send a message. Once this
+ // hits zero, we need to request more
+ // bandwidth from the torrent which
+ // in turn will request bandwidth from
+ // the bandwidth manager
+ int m_quota_left;
+
+ // the local limit is the number of bytes
+ // per window size we are allowed to use.
+ int m_local_limit;
+
+ // the current rate is the number of
+ // bytes we have been assigned within
+ // the window size.
+ int m_current_rate;
+};
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/bandwidth_manager.hpp b/src/libtorrent/include/libtorrent/bandwidth_manager.hpp
new file mode 100644
index 0000000..e7f985f
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/bandwidth_manager.hpp
@@ -0,0 +1,440 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED
+#define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED
+
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/version.hpp>
+#include <boost/bind.hpp>
+#include <boost/integer_traits.hpp>
+#include <boost/thread/mutex.hpp>
+#include <deque>
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/assert.hpp"
+#include "libtorrent/bandwidth_limit.hpp"
+#include "libtorrent/bandwidth_queue_entry.hpp"
+
+using boost::weak_ptr;
+using boost::shared_ptr;
+using boost::intrusive_ptr;
+using boost::bind;
+
+//#define TORRENT_VERBOSE_BANDWIDTH_LIMIT
+
+namespace libtorrent {
+
+// the maximum block of bandwidth quota to
+// hand out is 33kB. The block size may
+// be smaller on lower limits
+enum
+{
+ max_bandwidth_block_size = 33000,
+ min_bandwidth_block_size = 400
+};
+
+const time_duration bw_window_size = seconds(1);
+
+template<class PeerConnection, class Torrent>
+struct history_entry
+{
+ history_entry(intrusive_ptr<PeerConnection> p, weak_ptr<Torrent> t
+ , int a, ptime exp)
+ : expires_at(exp), amount(a), peer(p), tor(t) {}
+ ptime expires_at;
+ int amount;
+ intrusive_ptr<PeerConnection> peer;
+ weak_ptr<Torrent> tor;
+};
+
+template<class T>
+T clamp(T val, T ceiling, T floor) throw()
+{
+ TORRENT_ASSERT(ceiling >= floor);
+ if (val >= ceiling) return ceiling;
+ else if (val <= floor) return floor;
+ return val;
+}
+
+template<class PeerConnection, class Torrent>
+struct bandwidth_manager
+{
+ bandwidth_manager(io_service& ios, int channel) throw()
+ : m_ios(ios)
+ , m_history_timer(m_ios)
+ , m_limit(bandwidth_limit::inf)
+ , m_current_quota(0)
+ , m_channel(channel)
+ , m_in_hand_out_bandwidth(false)
+ , m_abort(false)
+ {}
+
+ void throttle(int limit) throw()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ TORRENT_ASSERT(limit >= 0);
+ m_limit = limit;
+ }
+
+ int throttle() const throw()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ return m_limit;
+ }
+
+ void close()
+ {
+ m_abort = true;
+ m_queue.clear();
+ m_history.clear();
+ m_current_quota = 0;
+ m_history_timer.cancel();
+ }
+
+#ifndef NDEBUG
+ bool is_in_history(PeerConnection const* peer) const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ return is_in_history(peer, l);
+ }
+
+ bool is_in_history(PeerConnection const* peer, boost::mutex::scoped_lock& l) const
+ {
+#if BOOST_VERSION >= 103500
+ TORRENT_ASSERT(l.owns_lock());
+#else
+ TORRENT_ASSERT(l.locked());
+#endif
+ for (typename history_t::const_iterator i
+ = m_history.begin(), end(m_history.end()); i != end; ++i)
+ {
+ if (i->peer.get() == peer) return true;
+ }
+ return false;
+ }
+#endif
+
+ int queue_size() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ return m_queue.size();
+ }
+
+ // non prioritized means that, if there's a line for bandwidth,
+ // others will cut in front of the non-prioritized peers.
+ // this is used by web seeds
+ void request_bandwidth(intrusive_ptr<PeerConnection> peer
+ , int blk, int priority)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ INVARIANT_CHECK;
+ if (m_abort) return;
+ TORRENT_ASSERT(blk > 0);
+
+ // make sure this peer isn't already in line
+ // waiting for bandwidth
+#ifndef NDEBUG
+ for (typename queue_t::iterator i = m_queue.begin()
+ , end(m_queue.end()); i != end; ++i)
+ {
+ TORRENT_ASSERT(i->peer < peer || peer < i->peer);
+ }
+#endif
+ TORRENT_ASSERT(peer->max_assignable_bandwidth(m_channel) > 0);
+
+ typename queue_t::reverse_iterator i(m_queue.rbegin());
+ while (i != m_queue.rend() && priority > i->priority)
+ {
+ ++i->priority;
+ ++i;
+ }
+ m_queue.insert(i.base(), bw_queue_entry<PeerConnection, Torrent>(peer, blk, priority));
+ if (!m_queue.empty()) hand_out_bandwidth(l);
+ }
+
+#ifndef NDEBUG
+ void check_invariant() const
+ {
+ int current_quota = 0;
+ for (typename history_t::const_iterator i
+ = m_history.begin(), end(m_history.end()); i != end; ++i)
+ {
+ current_quota += i->amount;
+ }
+ TORRENT_ASSERT(current_quota == m_current_quota);
+
+ typename queue_t::const_iterator j = m_queue.begin();
+ if (j != m_queue.end())
+ {
+ ++j;
+ for (typename queue_t::const_iterator i = m_queue.begin()
+ , end(m_queue.end()); i != end && j != end; ++i, ++j)
+ TORRENT_ASSERT(i->priority >= j->priority);
+ }
+ }
+#endif
+
+private:
+
+ void add_history_entry(history_entry<PeerConnection, Torrent> const& e)
+ {
+ try {
+ INVARIANT_CHECK;
+ m_history.push_front(e);
+ m_current_quota += e.amount;
+ // in case the size > 1 there is already a timer
+ // active that will be invoked, no need to set one up
+ if (m_history.size() > 1) return;
+
+ if (m_abort) return;
+
+ m_history_timer.expires_at(e.expires_at);
+ m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1));
+ }
+ catch (std::exception&) {}
+ }
+
+ void on_history_expire(asio::error_code const& e)
+ {
+ try {
+ if (e) return;
+
+ mutex_t::scoped_lock l(m_mutex);
+ INVARIANT_CHECK;
+ if (m_abort) return;
+
+ TORRENT_ASSERT(!m_history.empty());
+
+ ptime now(time_now());
+ while (!m_history.empty() && m_history.back().expires_at <= now)
+ {
+ history_entry<PeerConnection, Torrent> e = m_history.back();
+ m_history.pop_back();
+ m_current_quota -= e.amount;
+ TORRENT_ASSERT(m_current_quota >= 0);
+ intrusive_ptr<PeerConnection> c = e.peer;
+ shared_ptr<Torrent> t = e.tor.lock();
+ l.unlock();
+ if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount);
+ if (t) t->expire_bandwidth(m_channel, e.amount);
+ l.lock();
+ }
+
+ // now, wait for the next chunk to expire
+ if (!m_history.empty() && !m_abort)
+ {
+ m_history_timer.expires_at(m_history.back().expires_at);
+ m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1));
+ }
+
+ // since some bandwidth just expired, it
+ // means we can hand out more (in case there
+ // are still consumers in line)
+ if (!m_queue.empty()) hand_out_bandwidth(l);
+ }
+ catch (std::exception&) {}
+ }
+
+ void hand_out_bandwidth(boost::mutex::scoped_lock& l)
+ {
+#if BOOST_VERSION >= 103500
+ TORRENT_ASSERT(l.owns_lock());
+#else
+ TORRENT_ASSERT(l.locked());
+#endif
+ // if we're already handing out bandwidth, just return back
+ // to the loop further down on the callstack
+ if (m_in_hand_out_bandwidth) return;
+ m_in_hand_out_bandwidth = true;
+
+ try {
+ INVARIANT_CHECK;
+
+ ptime now(time_now());
+
+ int limit = m_limit;
+
+ // available bandwidth to hand out
+ int amount = limit - m_current_quota;
+
+#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
+ std::cerr << " hand_out_bandwidht. m_queue.size() = " << m_queue.size()
+ << " amount = " << amount
+ << " limit = " << limit
+ << " m_current_quota = " << m_current_quota << std::endl;
+#endif
+
+ if (amount <= 0)
+ {
+ m_in_hand_out_bandwidth = false;
+ return;
+ }
+
+ queue_t tmp;
+ while (!m_queue.empty() && amount > 0)
+ {
+ bw_queue_entry<PeerConnection, Torrent> qe = m_queue.front();
+ TORRENT_ASSERT(qe.max_block_size > 0);
+ m_queue.pop_front();
+
+ shared_ptr<Torrent> t = qe.torrent.lock();
+ if (!t) continue;
+ if (qe.peer->is_disconnecting())
+ {
+ l.unlock();
+ t->expire_bandwidth(m_channel, qe.max_block_size);
+ l.lock();
+ continue;
+ }
+
+ // at this point, max_assignable may actually be zero. Since
+ // the rate limit of the peer might have changed while it
+ // was in the queue.
+ int max_assignable = qe.peer->max_assignable_bandwidth(m_channel);
+ if (max_assignable == 0)
+ {
+ TORRENT_ASSERT(is_in_history(qe.peer.get(), l));
+ tmp.push_back(qe);
+ continue;
+ }
+
+ // this is the limit of the block size. It depends on the throttle
+ // so that it can be closer to optimal. Larger block sizes will give lower
+ // granularity to the rate but will be more efficient. At high rates
+ // the block sizes are bigger and at low rates, the granularity
+ // is more important and block sizes are smaller
+
+ // the minimum rate that can be given is the block size, so, the
+ // block size must be smaller for lower rates. This is because
+ // the history window is one second, and the block will be forgotten
+ // after one second.
+ int block_size = (std::min)(qe.peer->bandwidth_throttle(m_channel)
+ , limit / 10);
+
+ if (block_size < min_bandwidth_block_size)
+ {
+ block_size = (std::min)(int(min_bandwidth_block_size), limit);
+ }
+ else if (block_size > max_bandwidth_block_size)
+ {
+ if (limit == bandwidth_limit::inf)
+ {
+ block_size = max_bandwidth_block_size;
+ }
+ else
+ {
+ // try to make the block_size a divisor of
+ // m_limit to make the distributions as fair
+ // as possible
+ // TODO: move this calculcation to where the limit
+ // is changed
+ block_size = limit
+ / (limit / max_bandwidth_block_size);
+ }
+ }
+ if (block_size > qe.max_block_size) block_size = qe.max_block_size;
+
+#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
+ std::cerr << " block_size = " << block_size << " amount = " << amount << std::endl;
+#endif
+
+ // so, hand out max_assignable, but no more than
+ // the available bandwidth (amount) and no more
+ // than the max_bandwidth_block_size
+ int hand_out_amount = (std::min)((std::min)(block_size, max_assignable)
+ , amount);
+ TORRENT_ASSERT(hand_out_amount > 0);
+ amount -= hand_out_amount;
+ TORRENT_ASSERT(hand_out_amount <= qe.max_block_size);
+ l.unlock();
+ t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size);
+ qe.peer->assign_bandwidth(m_channel, hand_out_amount);
+ l.lock();
+ add_history_entry(history_entry<PeerConnection, Torrent>(
+ qe.peer, t, hand_out_amount, now + bw_window_size));
+ }
+ if (!tmp.empty()) m_queue.insert(m_queue.begin(), tmp.begin(), tmp.end());
+ }
+ catch (std::exception&)
+ {
+ m_in_hand_out_bandwidth = false;
+ throw;
+ }
+ m_in_hand_out_bandwidth = false;
+ }
+
+
+ typedef boost::mutex mutex_t;
+ mutable mutex_t m_mutex;
+
+ // the io_service used for the timer
+ io_service& m_ios;
+
+ // the timer that is waiting for the entries
+ // in the history queue to expire (slide out
+ // of the history window)
+ deadline_timer m_history_timer;
+
+ // the rate limit (bytes per second)
+ int m_limit;
+
+ // the sum of all recently handed out bandwidth blocks
+ int m_current_quota;
+
+ // these are the consumers that want bandwidth
+ typedef std::deque<bw_queue_entry<PeerConnection, Torrent> > queue_t;
+ queue_t m_queue;
+
+ // these are the consumers that have received bandwidth
+ // that will expire
+ typedef std::deque<history_entry<PeerConnection, Torrent> > history_t;
+ history_t m_history;
+
+ // this is the channel within the consumers
+ // that bandwidth is assigned to (upload or download)
+ int m_channel;
+
+ // this is true while we're in the hand_out_bandwidth loop
+ // to prevent recursive invocations to interfere
+ bool m_in_hand_out_bandwidth;
+
+ bool m_abort;
+};
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp b/src/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp
new file mode 100644
index 0000000..54f6690
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp
@@ -0,0 +1,56 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_BANDWIDTH_QUEUE_ENTRY_HPP_INCLUDED
+#define TORRENT_BANDWIDTH_QUEUE_ENTRY_HPP_INCLUDED
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace libtorrent {
+
+template<class PeerConnection, class Torrent>
+struct bw_queue_entry
+{
+ bw_queue_entry(boost::intrusive_ptr<PeerConnection> const& pe
+ , int blk, int prio)
+ : peer(pe), torrent(peer->associated_torrent())
+ , max_block_size(blk), priority(prio) {}
+ boost::intrusive_ptr<PeerConnection> peer;
+ boost::weak_ptr<Torrent> torrent;
+ int max_block_size;
+ int priority; // 0 is low prio
+};
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/bencode.hpp b/src/libtorrent/include/libtorrent/bencode.hpp
new file mode 100644
index 0000000..9bea1d8
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/bencode.hpp
@@ -0,0 +1,341 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+#ifndef TORRENT_BENCODE_HPP_INCLUDED
+#define TORRENT_BENCODE_HPP_INCLUDED
+
+
+
+/*
+ * This file declares the following functions:
+ *
+ *----------------------------------
+ * template<class OutIt>
+ * void libtorrent::bencode(OutIt out, const libtorrent::entry& e);
+ *
+ * Encodes a message entry with bencoding into the output
+ * iterator given. The bencoding is described in the BitTorrent
+ * protocol description document OutIt must be an OutputIterator
+ * of type char. This may throw libtorrent::invalid_encoding if
+ * the entry contains invalid nodes (undefined_t for example).
+ *
+ *----------------------------------
+ * template<class InIt>
+ * libtorrent::entry libtorrent::bdecode(InIt start, InIt end);
+ *
+ * Decodes the buffer given by the start and end iterators
+ * and returns the decoded entry. InIt must be an InputIterator
+ * of type char. May throw libtorrent::invalid_encoding if
+ * the string is not correctly bencoded.
+ *
+ */
+
+
+
+
+#include <cstdlib>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/static_assert.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/entry.hpp"
+#include "libtorrent/config.hpp"
+
+#include "libtorrent/assert.hpp"
+
+#if defined(_MSC_VER)
+namespace std
+{
+ using ::isdigit;
+ using ::atoi;
+};
+
+#define for if (false) {} else for
+#endif
+
+
+namespace libtorrent
+{
+
+ struct TORRENT_EXPORT invalid_encoding: std::exception
+ {
+ virtual const char* what() const throw() { return "invalid bencoding"; }
+ };
+
+ namespace detail
+ {
+ template <class OutIt>
+ void write_string(OutIt& out, const std::string& val)
+ {
+ std::string::const_iterator end = val.begin() + val.length();
+ std::copy(val.begin(), end, out);
+ }
+
+ TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val);
+
+ template <class OutIt>
+ void write_integer(OutIt& out, entry::integer_type val)
+ {
+ // the stack allocated buffer for keeping the
+ // decimal representation of the number can
+ // not hold number bigger than this:
+ BOOST_STATIC_ASSERT(sizeof(entry::integer_type) <= 8);
+ char buf[21];
+ for (char const* str = integer_to_str(buf, 21, val);
+ *str != 0; ++str)
+ {
+ *out = *str;
+ ++out;
+ }
+ }
+
+ template <class OutIt>
+ void write_char(OutIt& out, char c)
+ {
+ *out = c;
+ ++out;
+ }
+
+ template <class InIt>
+ std::string read_until(InIt& in, InIt end, char end_token, bool& err)
+ {
+ std::string ret;
+ if (in == end)
+ {
+ err = true;
+ return ret;
+ }
+ while (*in != end_token)
+ {
+ ret += *in;
+ ++in;
+ if (in == end)
+ {
+ err = true;
+ return ret;
+ }
+ }
+ return ret;
+ }
+
+ template<class InIt>
+ void read_string(InIt& in, InIt end, int len, std::string& str, bool& err)
+ {
+ TORRENT_ASSERT(len >= 0);
+ for (int i = 0; i < len; ++i)
+ {
+ if (in == end)
+ {
+ err = true;
+ return;
+ }
+ str += *in;
+ ++in;
+ }
+ }
+
+ template<class OutIt>
+ void bencode_recursive(OutIt& out, const entry& e)
+ {
+ switch(e.type())
+ {
+ case entry::int_t:
+ write_char(out, 'i');
+ write_integer(out, e.integer());
+ write_char(out, 'e');
+ break;
+ case entry::string_t:
+ write_integer(out, e.string().length());
+ write_char(out, ':');
+ write_string(out, e.string());
+ break;
+ case entry::list_t:
+ write_char(out, 'l');
+ for (entry::list_type::const_iterator i = e.list().begin(); i != e.list().end(); ++i)
+ bencode_recursive(out, *i);
+ write_char(out, 'e');
+ break;
+ case entry::dictionary_t:
+ write_char(out, 'd');
+ for (entry::dictionary_type::const_iterator i = e.dict().begin();
+ i != e.dict().end(); ++i)
+ {
+ // write key
+ write_integer(out, i->first.length());
+ write_char(out, ':');
+ write_string(out, i->first);
+ // write value
+ bencode_recursive(out, i->second);
+ }
+ write_char(out, 'e');
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+
+ template<class InIt>
+ void bdecode_recursive(InIt& in, InIt end, entry& ret, bool& err, int depth)
+ {
+ if (depth >= 100)
+ {
+ err = true;
+ return;
+ }
+
+ if (in == end)
+ {
+ err = true;
+ return;
+ }
+ switch (*in)
+ {
+
+ // ----------------------------------------------
+ // integer
+ case 'i':
+ {
+ ++in; // 'i'
+ std::string val = read_until(in, end, 'e', err);
+ if (err) return;
+ TORRENT_ASSERT(*in == 'e');
+ ++in; // 'e'
+ ret = entry(entry::int_t);
+ ret.integer() = boost::lexical_cast<entry::integer_type>(val);
+ } break;
+
+ // ----------------------------------------------
+ // list
+ case 'l':
+ {
+ ret = entry(entry::list_t);
+ ++in; // 'l'
+ while (*in != 'e')
+ {
+ ret.list().push_back(entry());
+ entry& e = ret.list().back();
+ bdecode_recursive(in, end, e, err, depth + 1);
+ if (err) return;
+ if (in == end)
+ {
+ err = true;
+ return;
+ }
+ }
+ TORRENT_ASSERT(*in == 'e');
+ ++in; // 'e'
+ } break;
+
+ // ----------------------------------------------
+ // dictionary
+ case 'd':
+ {
+ ret = entry(entry::dictionary_t);
+ ++in; // 'd'
+ while (*in != 'e')
+ {
+ entry key;
+ bdecode_recursive(in, end, key, err, depth + 1);
+ if (err) return;
+ entry& e = ret[key.string()];
+ bdecode_recursive(in, end, e, err, depth + 1);
+ if (err) return;
+ if (in == end)
+ {
+ err = true;
+ return;
+ }
+ }
+ TORRENT_ASSERT(*in == 'e');
+ ++in; // 'e'
+ } break;
+
+ // ----------------------------------------------
+ // string
+ default:
+ if (isdigit((unsigned char)*in))
+ {
+ std::string len_s = read_until(in, end, ':', err);
+ if (err) return;
+ TORRENT_ASSERT(*in == ':');
+ ++in; // ':'
+ int len = std::atoi(len_s.c_str());
+ ret = entry(entry::string_t);
+ read_string(in, end, len, ret.string(), err);
+ if (err) return;
+ }
+ else
+ {
+ err = true;
+ return;
+ }
+ }
+ }
+ }
+
+ template<class OutIt>
+ void bencode(OutIt out, const entry& e)
+ {
+ detail::bencode_recursive(out, e);
+ }
+
+ template<class InIt>
+ entry bdecode(InIt start, InIt end)
+ {
+ entry e;
+ bool err = false;
+ detail::bdecode_recursive(start, end, e, err, 0);
+ if (err)
+ {
+#ifdef BOOST_NO_EXCEPTIONS
+ return entry();
+#else
+ throw invalid_encoding();
+#endif
+ }
+ return e;
+ }
+
+}
+
+#endif // TORRENT_BENCODE_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/broadcast_socket.hpp b/src/libtorrent/include/libtorrent/broadcast_socket.hpp
new file mode 100644
index 0000000..f7aae34
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/broadcast_socket.hpp
@@ -0,0 +1,90 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_BROADCAST_SOCKET_HPP_INCLUDED
+#define TORRENT_BROADCAST_SOCKET_HPP_INCLUDED
+
+#include "libtorrent/config.hpp"
+#include "libtorrent/socket.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <list>
+
+namespace libtorrent
+{
+
+ TORRENT_EXPORT bool is_local(address const& a);
+ TORRENT_EXPORT bool is_loopback(address const& addr);
+ TORRENT_EXPORT bool is_multicast(address const& addr);
+ TORRENT_EXPORT bool is_any(address const& addr);
+ TORRENT_EXPORT int cidr_distance(address const& a1, address const& a2);
+
+ int common_bits(unsigned char const* b1
+ , unsigned char const* b2, int n);
+
+ TORRENT_EXPORT address guess_local_address(asio::io_service&);
+
+ typedef boost::function<void(udp::endpoint const& from
+ , char* buffer, int size)> receive_handler_t;
+
+ class TORRENT_EXPORT broadcast_socket
+ {
+ public:
+ broadcast_socket(asio::io_service& ios, udp::endpoint const& multicast_endpoint
+ , receive_handler_t const& handler, bool loopback = true);
+ ~broadcast_socket() { close(); }
+
+ void send(char const* buffer, int size, asio::error_code& ec);
+ void close();
+
+ private:
+
+ struct socket_entry
+ {
+ socket_entry(boost::shared_ptr<datagram_socket> const& s): socket(s) {}
+ boost::shared_ptr<datagram_socket> socket;
+ char buffer[1024];
+ udp::endpoint remote;
+ };
+
+ void on_receive(socket_entry* s, asio::error_code const& ec
+ , std::size_t bytes_transferred);
+
+ std::list<socket_entry> m_sockets;
+ udp::endpoint m_multicast_endpoint;
+ receive_handler_t m_on_receive;
+
+ };
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/bt_peer_connection.hpp b/src/libtorrent/include/libtorrent/bt_peer_connection.hpp
new file mode 100644
index 0000000..dc5237a
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/bt_peer_connection.hpp
@@ -0,0 +1,416 @@
+/*
+
+Copyright (c) 2003 - 2006, Arvid Norberg
+Copyright (c) 2007, Arvid Norberg, Un Shyam
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_BT_PEER_CONNECTION_HPP_INCLUDED
+#define TORRENT_BT_PEER_CONNECTION_HPP_INCLUDED
+
+#include <ctime>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <string>
+
+#include "libtorrent/debug.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/smart_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/array.hpp>
+#include <boost/optional.hpp>
+#include <boost/cstdint.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/buffer.hpp"
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/storage.hpp"
+#include "libtorrent/stat.hpp"
+#include "libtorrent/alert.hpp"
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/piece_block_progress.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/pe_crypto.hpp"
+
+namespace libtorrent
+{
+ class torrent;
+
+ namespace detail
+ {
+ struct session_impl;
+ }
+
+ class TORRENT_EXPORT bt_peer_connection
+ : public peer_connection
+ {
+ friend class invariant_access;
+ public:
+
+ // this is the constructor where the we are the active part.
+ // The peer_conenction should handshake and verify that the
+ // other end has the correct id
+ bt_peer_connection(
+ aux::session_impl& ses
+ , boost::weak_ptr<torrent> t
+ , boost::shared_ptr<socket_type> s
+ , tcp::endpoint const& remote
+ , policy::peer* peerinfo);
+
+ // with this constructor we have been contacted and we still don't
+ // know which torrent the connection belongs to
+ bt_peer_connection(
+ aux::session_impl& ses
+ , boost::shared_ptr<socket_type> s
+ , policy::peer* peerinfo);
+
+ ~bt_peer_connection();
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ bool supports_encryption() const
+ { return m_encrypted; }
+#endif
+
+ enum message_type
+ {
+ // standard messages
+ msg_choke = 0,
+ msg_unchoke,
+ msg_interested,
+ msg_not_interested,
+ msg_have,
+ msg_bitfield,
+ msg_request,
+ msg_piece,
+ msg_cancel,
+ // DHT extension
+ msg_dht_port,
+ // FAST extension
+ msg_suggest_piece = 0xd,
+ msg_have_all,
+ msg_have_none,
+ msg_reject_request,
+ msg_allowed_fast,
+
+ // extension protocol message
+ msg_extended = 20,
+
+ num_supported_messages
+ };
+
+ // called from the main loop when this connection has any
+ // work to do.
+
+ void on_sent(asio::error_code const& error
+ , std::size_t bytes_transferred);
+ void on_receive(asio::error_code const& error
+ , std::size_t bytes_transferred);
+
+ virtual void get_specific_peer_info(peer_info& p) const;
+ virtual bool in_handshake() const;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ bool support_extensions() const { return m_supports_extensions; }
+
+ template <class T>
+ T* supports_extension() const
+ {
+ for (extension_list_t::const_iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ T* ret = dynamic_cast<T*>(i->get());
+ if (ret) return ret;
+ }
+ return 0;
+ }
+#endif
+
+ // the message handlers are called
+ // each time a recv() returns some new
+ // data, the last time it will be called
+ // is when the entire packet has been
+ // received, then it will no longer
+ // be called. i.e. most handlers need
+ // to check how much of the packet they
+ // have received before any processing
+ void on_keepalive();
+ void on_choke(int received);
+ void on_unchoke(int received);
+ void on_interested(int received);
+ void on_not_interested(int received);
+ void on_have(int received);
+ void on_bitfield(int received);
+ void on_request(int received);
+ void on_piece(int received);
+ void on_cancel(int received);
+
+ // DHT extension
+ void on_dht_port(int received);
+
+ // FAST extension
+ void on_suggest_piece(int received);
+ void on_have_all(int received);
+ void on_have_none(int received);
+ void on_reject_request(int received);
+ void on_allowed_fast(int received);
+
+ void on_extended(int received);
+
+ void on_extended_handshake();
+
+ typedef void (bt_peer_connection::*message_handler)(int received);
+
+ // the following functions appends messages
+ // to the send buffer
+ void write_choke();
+ void write_unchoke();
+ void write_interested();
+ void write_not_interested();
+ void write_request(peer_request const& r);
+ void write_cancel(peer_request const& r);
+ void write_bitfield(std::vector<bool> const& bitfield);
+ void write_have(int index);
+ void write_piece(peer_request const& r, char* buffer);
+ void write_handshake();
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void write_extensions();
+#endif
+ void write_chat_message(const std::string& msg);
+ void write_metadata(std::pair<int, int> req);
+ void write_metadata_request(std::pair<int, int> req);
+ void write_keepalive();
+
+ // DHT extension
+ void write_dht_port(int listen_port);
+
+ // FAST extension
+ void write_have_all();
+ void write_have_none();
+ void write_reject_request(peer_request const&);
+ void write_allow_fast(int piece);
+
+ void on_connected();
+ void on_metadata();
+
+#ifndef NDEBUG
+ void check_invariant() const;
+ ptime m_last_choke;
+#endif
+
+ private:
+
+ bool dispatch_message(int received);
+ // returns the block currently being
+ // downloaded. And the progress of that
+ // block. If the peer isn't downloading
+ // a piece for the moment, the boost::optional
+ // will be invalid.
+ boost::optional<piece_block_progress> downloading_piece_progress() const;
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+
+ // if (is_local()), we are 'a' otherwise 'b'
+ //
+ // 1. a -> b dhkey, pad
+ // 2. b -> a dhkey, pad
+ // 3. a -> b sync, payload
+ // 4. b -> a sync, payload
+ // 5. a -> b payload
+
+ void write_pe1_2_dhkey();
+ void write_pe3_sync();
+ void write_pe4_sync(int crypto_select);
+
+ void write_pe_vc_cryptofield(buffer::interval& write_buf,
+ int crypto_field, int pad_size);
+
+ // stream key (info hash of attached torrent)
+ // secret is the DH shared secret
+ // initializes m_RC4_handler
+ void init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key);
+
+ // these functions encrypt the send buffer if m_rc4_encrypted
+ // is true, otherwise it passes the call to the
+ // peer_connection functions of the same names
+ void send_buffer(char* buf, int size);
+ buffer::interval allocate_send_buffer(int size);
+ template <class Destructor>
+ void append_send_buffer(char* buffer, int size, Destructor const& destructor)
+ {
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ if (m_rc4_encrypted)
+ m_RC4_handler->encrypt(buffer, size);
+#endif
+ peer_connection::append_send_buffer(buffer, size, destructor);
+ }
+ void setup_send();
+
+ // Returns offset at which bytestream (src, src + src_size)
+ // matches bytestream(target, target + target_size).
+ // If no sync found, return -1
+ int get_syncoffset(char const* src, int src_size,
+ char const* target, int target_size) const;
+#endif
+
+ enum state
+ {
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ read_pe_dhkey = 0,
+ read_pe_syncvc,
+ read_pe_synchash,
+ read_pe_skey_vc,
+ read_pe_cryptofield,
+ read_pe_pad,
+ read_pe_ia,
+ init_bt_handshake,
+ read_protocol_identifier,
+#else
+ read_protocol_identifier = 0,
+#endif
+ read_info_hash,
+ read_peer_id,
+
+ // handshake complete
+ read_packet_size,
+ read_packet
+ };
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ enum
+ {
+ handshake_len = 68,
+ dh_key_len = 96
+ };
+#endif
+
+ std::string m_client_version;
+
+ // state of on_receive
+ state m_state;
+
+ // the timeout in seconds
+ int m_timeout;
+
+ static const message_handler m_message_handler[num_supported_messages];
+
+ // this is a queue of ranges that describes
+ // where in the send buffer actual payload
+ // data is located. This is currently
+ // only used to be able to gather statistics
+ // seperately on payload and protocol data.
+ struct range
+ {
+ range(int s, int l)
+ : start(s)
+ , length(l)
+ {
+ TORRENT_ASSERT(s >= 0);
+ TORRENT_ASSERT(l > 0);
+ }
+ int start;
+ int length;
+ };
+ static bool range_below_zero(const range& r)
+ { return r.start < 0; }
+ std::deque<range> m_payloads;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ // this is set to true if the handshake from
+ // the peer indicated that it supports the
+ // extension protocol
+ bool m_supports_extensions;
+#endif
+ bool m_supports_dht_port;
+ bool m_supports_fast;
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ // this is set to true after the encryption method has been
+ // succesfully negotiated (either plaintext or rc4), to signal
+ // automatic encryption/decryption.
+ bool m_encrypted;
+
+ // true if rc4, false if plaintext
+ bool m_rc4_encrypted;
+
+ // used to disconnect peer if sync points are not found within
+ // the maximum number of bytes
+ int m_sync_bytes_read;
+
+ // hold information about latest allocated send buffer
+ // need to check for non zero (begin, end) for operations with this
+ buffer::interval m_enc_send_buffer;
+
+ // initialized during write_pe1_2_dhkey, and destroyed on
+ // creation of m_RC4_handler. Cannot reinitialize once
+ // initialized.
+ boost::scoped_ptr<DH_key_exchange> m_DH_key_exchange;
+
+ // if RC4 is negotiated, this is used for
+ // encryption/decryption during the entire session. Destroyed
+ // if plaintext is selected
+ boost::scoped_ptr<RC4_handler> m_RC4_handler;
+
+ // (outgoing only) synchronize verification constant with
+ // remote peer, this will hold RC4_decrypt(vc). Destroyed
+ // after the sync step.
+ boost::scoped_array<char> m_sync_vc;
+
+ // (incoming only) synchronize hash with remote peer, holds
+ // the sync hash (hash("req1",secret)). Destroyed after the
+ // sync step.
+ boost::scoped_ptr<sha1_hash> m_sync_hash;
+#endif // #ifndef TORRENT_DISABLE_ENCRYPTION
+
+#ifndef NDEBUG
+ // this is set to true when the client's
+ // bitfield is sent to this peer
+ bool m_sent_bitfield;
+
+ bool m_in_constructor;
+
+ bool m_sent_handshake;
+#endif
+
+ };
+}
+
+#endif // TORRENT_BT_PEER_CONNECTION_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/buffer.hpp b/src/libtorrent/include/libtorrent/buffer.hpp
new file mode 100644
index 0000000..a823a76
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/buffer.hpp
@@ -0,0 +1,200 @@
+/*
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of Rasterbar Software nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef LIBTORRENT_BUFFER_HPP
+#define LIBTORRENT_BUFFER_HPP
+
+#include <memory>
+#include <cstring>
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent {
+
+class buffer
+{
+public:
+ struct interval
+ {
+ interval(char* begin, char* end)
+ : begin(begin)
+ , end(end)
+ {}
+
+ char operator[](int index) const
+ {
+ TORRENT_ASSERT(begin + index < end);
+ return begin[index];
+ }
+
+ int left() const { TORRENT_ASSERT(end >= begin); return end - begin; }
+
+ char* begin;
+ char* end;
+ };
+
+ struct const_interval
+ {
+ const_interval(char const* begin, char const* end)
+ : begin(begin)
+ , end(end)
+ {}
+
+ char operator[](int index) const
+ {
+ TORRENT_ASSERT(begin + index < end);
+ return begin[index];
+ }
+
+ bool operator==(const const_interval& p_interval)
+ {
+ return (begin == p_interval.begin
+ && end == p_interval.end);
+ }
+
+ int left() const { TORRENT_ASSERT(end >= begin); return end - begin; }
+
+ char const* begin;
+ char const* end;
+ };
+
+ buffer(std::size_t n = 0)
+ : m_begin(0)
+ , m_end(0)
+ , m_last(0)
+ {
+ if (n) resize(n);
+ }
+
+ buffer(buffer const& b)
+ : m_begin(0)
+ , m_end(0)
+ , m_last(0)
+ {
+ if (b.size() == 0) return;
+ resize(b.size());
+ std::memcpy(m_begin, b.begin(), b.size());
+ }
+
+ buffer& operator=(buffer const& b)
+ {
+ resize(b.size());
+ std::memcpy(m_begin, b.begin(), b.size());
+ return *this;
+ }
+
+ ~buffer()
+ {
+ ::operator delete (m_begin);
+ }
+
+ buffer::interval data() { return interval(m_begin, m_end); }
+ buffer::const_interval data() const { return const_interval(m_begin, m_end); }
+
+ void resize(std::size_t n)
+ {
+ reserve(n);
+ m_end = m_begin + n;
+ }
+
+ void insert(char* point, char const* first, char const* last)
+ {
+ std::size_t p = point - m_begin;
+ if (point == m_end)
+ {
+ resize(size() + last - first);
+ std::memcpy(m_begin + p, first, last - first);
+ return;
+ }
+
+ resize(size() + last - first);
+ std::memmove(m_begin + p + (last - first), m_begin + p, last - first);
+ std::memcpy(m_begin + p, first, last - first);
+ }
+
+ void erase(char* begin, char* end)
+ {
+ TORRENT_ASSERT(end <= m_end);
+ TORRENT_ASSERT(begin >= m_begin);
+ TORRENT_ASSERT(begin <= end);
+ if (end == m_end)
+ {
+ resize(begin - m_begin);
+ return;
+ }
+ std::memmove(begin, end, m_end - end);
+ m_end = begin + (m_end - end);
+ }
+
+ void clear() { m_end = m_begin; }
+ std::size_t size() const { return m_end - m_begin; }
+ std::size_t capacity() const { return m_last - m_begin; }
+ void reserve(std::size_t n)
+ {
+ if (n <= capacity()) return;
+ TORRENT_ASSERT(n > 0);
+
+ char* buf = (char*)::operator new(n);
+ std::size_t s = size();
+ std::memcpy(buf, m_begin, s);
+ ::operator delete (m_begin);
+ m_begin = buf;
+ m_end = buf + s;
+ m_last = m_begin + n;
+ }
+
+ bool empty() const { return m_begin == m_end; }
+ char& operator[](std::size_t i) { TORRENT_ASSERT(i < size()); return m_begin[i]; }
+ char const& operator[](std::size_t i) const { TORRENT_ASSERT(i < size()); return m_begin[i]; }
+
+ char* begin() { return m_begin; }
+ char const* begin() const { return m_begin; }
+ char* end() { return m_end; }
+ char const* end() const { return m_end; }
+
+ void swap(buffer& b)
+ {
+ using std::swap;
+ swap(m_begin, b.m_begin);
+ swap(m_end, b.m_end);
+ swap(m_last, b.m_last);
+ }
+private:
+ char* m_begin; // first
+ char* m_end; // one passed end of size
+ char* m_last; // one passed end of allocation
+};
+
+
+}
+
+#endif // LIBTORRENT_BUFFER_HPP
+
diff --git a/src/libtorrent/include/libtorrent/chained_buffer.hpp b/src/libtorrent/include/libtorrent/chained_buffer.hpp
new file mode 100644
index 0000000..82fcb65
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/chained_buffer.hpp
@@ -0,0 +1,192 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_CHAINED_BUFFER_HPP_INCLUDED
+#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED
+
+#include <boost/function.hpp>
+#include <asio/buffer.hpp>
+#include <list>
+#include <cstring>
+
+namespace libtorrent
+{
+ struct chained_buffer
+ {
+ chained_buffer(): m_bytes(0), m_capacity(0) {}
+
+ struct buffer_t
+ {
+ boost::function<void(char*)> free; // destructs the buffer
+ char* buf; // the first byte of the buffer
+ int size; // the total size of the buffer
+
+ char* start; // the first byte to send/receive in the buffer
+ int used_size; // this is the number of bytes to send/receive
+ };
+
+ bool empty() const { return m_bytes == 0; }
+ int size() const { return m_bytes; }
+ int capacity() const { return m_capacity; }
+
+ void pop_front(int bytes_to_pop)
+ {
+ TORRENT_ASSERT(bytes_to_pop <= m_bytes);
+ while (bytes_to_pop > 0 && !m_vec.empty())
+ {
+ buffer_t& b = m_vec.front();
+ if (b.used_size > bytes_to_pop)
+ {
+ b.start += bytes_to_pop;
+ b.used_size -= bytes_to_pop;
+ m_bytes -= bytes_to_pop;
+ TORRENT_ASSERT(m_bytes <= m_capacity);
+ TORRENT_ASSERT(m_bytes >= 0);
+ TORRENT_ASSERT(m_capacity >= 0);
+ break;
+ }
+
+ b.free(b.buf);
+ m_bytes -= b.used_size;
+ m_capacity -= b.size;
+ bytes_to_pop -= b.used_size;
+ TORRENT_ASSERT(m_bytes >= 0);
+ TORRENT_ASSERT(m_capacity >= 0);
+ TORRENT_ASSERT(m_bytes <= m_capacity);
+ m_vec.pop_front();
+ }
+ }
+
+ template <class D>
+ void append_buffer(char* buffer, int size, int used_size, D const& destructor)
+ {
+ TORRENT_ASSERT(size >= used_size);
+ buffer_t b;
+ b.buf = buffer;
+ b.size = size;
+ b.start = buffer;
+ b.used_size = used_size;
+ b.free = destructor;
+ m_vec.push_back(b);
+
+ m_bytes += used_size;
+ m_capacity += size;
+ TORRENT_ASSERT(m_bytes <= m_capacity);
+ }
+
+ // returns the number of bytes available at the
+ // end of the last chained buffer.
+ int space_in_last_buffer()
+ {
+ if (m_vec.empty()) return 0;
+ buffer_t& b = m_vec.back();
+ return b.size - b.used_size - (b.start - b.buf);
+ }
+
+ // tries to copy the given buffer to the end of the
+ // last chained buffer. If there's not enough room
+ // it returns false
+ bool append(char const* buf, int size)
+ {
+ char* insert = allocate_appendix(size);
+ if (insert == 0) return false;
+ std::memcpy(insert, buf, size);
+ return true;
+ }
+
+ // tries to allocate memory from the end
+ // of the last buffer. If there isn't
+ // enough room, returns 0
+ char* allocate_appendix(int size)
+ {
+ if (m_vec.empty()) return 0;
+ buffer_t& b = m_vec.back();
+ char* insert = b.start + b.used_size;
+ if (insert + size > b.buf + b.size) return 0;
+ b.used_size += size;
+ m_bytes += size;
+ TORRENT_ASSERT(m_bytes <= m_capacity);
+ return insert;
+ }
+
+ std::list<asio::const_buffer> const& build_iovec(int to_send)
+ {
+ m_tmp_vec.clear();
+
+ for (std::list<buffer_t>::iterator i = m_vec.begin()
+ , end(m_vec.end()); to_send > 0 && i != end; ++i)
+ {
+ if (i->used_size > to_send)
+ {
+ TORRENT_ASSERT(to_send > 0);
+ m_tmp_vec.push_back(asio::const_buffer(i->start, to_send));
+ break;
+ }
+ TORRENT_ASSERT(i->used_size > 0);
+ m_tmp_vec.push_back(asio::const_buffer(i->start, i->used_size));
+ to_send -= i->used_size;
+ }
+ return m_tmp_vec;
+ }
+
+ ~chained_buffer()
+ {
+ for (std::list<buffer_t>::iterator i = m_vec.begin()
+ , end(m_vec.end()); i != end; ++i)
+ {
+ i->free(i->buf);
+ }
+ }
+
+ private:
+
+ // this is the list of all the buffers we want to
+ // send
+ std::list<buffer_t> m_vec;
+
+ // this is the number of bytes in the send buf.
+ // this will always be equal to the sum of the
+ // size of all buffers in vec
+ int m_bytes;
+
+ // the total size of all buffers in the chain
+ // including unused space
+ int m_capacity;
+
+ // this is the vector of buffers used when
+ // invoking the async write call
+ std::list<asio::const_buffer> m_tmp_vec;
+ };
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/connection_queue.hpp b/src/libtorrent/include/libtorrent/connection_queue.hpp
new file mode 100644
index 0000000..c229ec2
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/connection_queue.hpp
@@ -0,0 +1,105 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_CONNECTION_QUEUE
+#define TORRENT_CONNECTION_QUEUE
+
+#include <list>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include "libtorrent/socket.hpp"
+#include "libtorrent/time.hpp"
+
+namespace libtorrent
+{
+
+class connection_queue : public boost::noncopyable
+{
+public:
+ connection_queue(io_service& ios);
+
+ bool free_slots() const;
+
+ void enqueue(boost::function<void(int)> const& on_connect
+ , boost::function<void()> const& on_timeout
+ , time_duration timeout);
+ void done(int ticket);
+ void limit(int limit);
+ int limit() const;
+ void close();
+
+#ifndef NDEBUG
+
+ void check_invariant() const;
+
+#endif
+
+private:
+
+ void try_connect();
+ void on_timeout(asio::error_code const& e);
+
+ struct entry
+ {
+ entry(): connecting(false), ticket(0), expires(max_time()) {}
+ // called when the connection is initiated
+ boost::function<void(int)> on_connect;
+ // called if done hasn't been called within the timeout
+ boost::function<void()> on_timeout;
+ bool connecting;
+ int ticket;
+ ptime expires;
+ time_duration timeout;
+ };
+
+ std::list<entry> m_queue;
+
+ // the next ticket id a connection will be given
+ int m_next_ticket;
+ int m_num_connecting;
+ int m_half_open_limit;
+
+ deadline_timer m_timer;
+
+ typedef boost::recursive_mutex mutex_t;
+ mutable mutex_t m_mutex;
+
+#ifndef NDEBUG
+ bool m_in_timeout_function;
+#endif
+};
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/debug.hpp b/src/libtorrent/include/libtorrent/debug.hpp
new file mode 100644
index 0000000..96c2c9d
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/debug.hpp
@@ -0,0 +1,90 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_DEBUG_HPP_INCLUDED
+#define TORRENT_DEBUG_HPP_INCLUDED
+
+#include <string>
+#include <fstream>
+#include <iostream>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/convenience.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+
+namespace libtorrent
+{
+ // DEBUG API
+
+ namespace fs = boost::filesystem;
+
+ struct logger
+ {
+ logger(fs::path const& logpath, fs::path const& filename, int instance, bool append = true)
+ {
+ try
+ {
+ fs::path dir(fs::complete(logpath / ("libtorrent_logs" + boost::lexical_cast<std::string>(instance))));
+ if (!fs::exists(dir)) fs::create_directories(dir);
+ m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
+ *this << "\n\n\n*** starting log ***\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "failed to create log '" << filename.string() << "': " << e.what() << std::endl;
+ }
+ }
+
+ template <class T>
+ logger& operator<<(T const& v)
+ {
+ m_file << v;
+ m_file.flush();
+ return *this;
+ }
+
+ std::ofstream m_file;
+ };
+
+}
+
+#endif // TORRENT_DEBUG_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/disk_io_thread.hpp b/src/libtorrent/include/libtorrent/disk_io_thread.hpp
new file mode 100644
index 0000000..4e0e95a
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/disk_io_thread.hpp
@@ -0,0 +1,162 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_DISK_IO_THREAD
+#define TORRENT_DISK_IO_THREAD
+
+#ifdef TORRENT_DISK_STATS
+#include <fstream>
+#endif
+
+#include "libtorrent/storage.hpp"
+#include <boost/thread/thread.hpp>
+#include <boost/function.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/bind.hpp>
+#include <boost/pool/pool.hpp>
+#include <boost/noncopyable.hpp>
+#include <list>
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+
+ struct disk_io_job
+ {
+ disk_io_job()
+ : action(read)
+ , buffer(0)
+ , buffer_size(0)
+ , piece(0)
+ , offset(0)
+ , priority(0)
+ {}
+
+ enum action_t
+ {
+ read
+ , write
+ , hash
+ , move_storage
+ , release_files
+ , delete_files
+ };
+
+ action_t action;
+
+ char* buffer;
+ int buffer_size;
+ boost::intrusive_ptr<piece_manager> storage;
+ // arguments used for read and write
+ int piece, offset;
+ // used for move_storage. On errors, this is set
+ // to the error message
+ std::string str;
+
+ // priority decides whether or not this
+ // job will skip entries in the queue or
+ // not. It always skips in front of entries
+ // with lower priority
+ int priority;
+
+ // this is called when operation completes
+ boost::function<void(int, disk_io_job const&)> callback;
+ };
+
+ // this is a singleton consisting of the thread and a queue
+ // of disk io jobs
+ struct disk_io_thread : boost::noncopyable
+ {
+ disk_io_thread(int block_size = 16 * 1024);
+ ~disk_io_thread();
+
+#ifdef TORRENT_STATS
+ int disk_allocations() const
+ { return m_allocations; }
+#endif
+
+ void join();
+
+ // aborts read operations
+ void stop(boost::intrusive_ptr<piece_manager> s);
+ void add_job(disk_io_job const& j
+ , boost::function<void(int, disk_io_job const&)> const& f
+ = boost::function<void(int, disk_io_job const&)>());
+
+#ifndef NDEBUG
+ disk_io_job find_job(boost::intrusive_ptr<piece_manager> s
+ , int action, int piece) const;
+#endif
+ // keep track of the number of bytes in the job queue
+ // at any given time. i.e. the sum of all buffer_size.
+ // this is used to slow down the download global download
+ // speed when the queue buffer size is too big.
+ size_type queue_buffer_size() const
+ { return m_queue_buffer_size; }
+
+ void operator()();
+
+ char* allocate_buffer();
+ void free_buffer(char* buf);
+
+ private:
+
+ typedef boost::recursive_mutex mutex_t;
+ mutable mutex_t m_mutex;
+ boost::condition m_signal;
+ bool m_abort;
+ std::list<disk_io_job> m_jobs;
+ size_type m_queue_buffer_size;
+
+ // memory pool for read and write operations
+ boost::pool<> m_pool;
+
+#ifndef NDEBUG
+ int m_block_size;
+ disk_io_job m_current;
+#endif
+
+#ifdef TORRENT_DISK_STATS
+ std::ofstream m_log;
+#endif
+#ifdef TORRENT_STATS
+ int m_allocations;
+#endif
+
+ // thread for performing blocking disk io operations
+ boost::thread m_disk_io_thread;
+ };
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/entry.hpp b/src/libtorrent/include/libtorrent/entry.hpp
new file mode 100644
index 0000000..7238af3
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/entry.hpp
@@ -0,0 +1,307 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_ENTRY_HPP_INCLUDED
+#define TORRENT_ENTRY_HPP_INCLUDED
+
+/*
+ *
+ * This file declares the entry class. It is a
+ * variant-type that can be an integer, list,
+ * dictionary (map) or a string. This type is
+ * used to hold bdecoded data (which is the
+ * encoding BitTorrent messages uses).
+ *
+ * it has 4 accessors to access the actual
+ * type of the object. They are:
+ * integer()
+ * string()
+ * list()
+ * dict()
+ * The actual type has to match the type you
+ * are asking for, otherwise you will get an
+ * assertion failure.
+ * When you default construct an entry, it is
+ * uninitialized. You can initialize it through the
+ * assignment operator, copy-constructor or
+ * the constructor that takes a data_type enum.
+ *
+ *
+ */
+
+
+#include <iosfwd>
+#include <map>
+#include <list>
+#include <string>
+#include <stdexcept>
+
+#include "libtorrent/size_type.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ struct TORRENT_EXPORT type_error: std::runtime_error
+ {
+ type_error(const char* error): std::runtime_error(error) {}
+ };
+
+ namespace detail
+ {
+ template<int v1, int v2>
+ struct max2 { enum { value = v1>v2?v1:v2 }; };
+
+ template<int v1, int v2, int v3>
+ struct max3
+ {
+ enum
+ {
+ temp = max2<v1,v2>::value,
+ value = temp>v3?temp:v3
+ };
+ };
+
+ template<int v1, int v2, int v3, int v4>
+ struct max4
+ {
+ enum
+ {
+ temp = max3<v1,v2, v3>::value,
+ value = temp>v4?temp:v4
+ };
+ };
+ }
+
+ class entry;
+
+ class TORRENT_EXPORT entry
+ {
+ public:
+
+ // the key is always a string. If a generic entry would be allowed
+ // as a key, sorting would become a problem (e.g. to compare a string
+ // to a list). The definition doesn't mention such a limit though.
+ typedef std::map<std::string, entry> dictionary_type;
+ typedef std::string string_type;
+ typedef std::list<entry> list_type;
+ typedef size_type integer_type;
+
+ enum data_type
+ {
+ int_t,
+ string_t,
+ list_t,
+ dictionary_t,
+ undefined_t
+ };
+
+ data_type type() const;
+
+ entry(dictionary_type const&);
+ entry(string_type const&);
+ entry(list_type const&);
+ entry(integer_type const&);
+
+ entry();
+ entry(data_type t);
+ entry(entry const& e);
+ ~entry();
+
+ bool operator==(entry const& e) const;
+
+ void operator=(entry const&);
+ void operator=(dictionary_type const&);
+ void operator=(string_type const&);
+ void operator=(list_type const&);
+ void operator=(integer_type const&);
+
+ integer_type& integer();
+ const integer_type& integer() const;
+ string_type& string();
+ const string_type& string() const;
+ list_type& list();
+ const list_type& list() const;
+ dictionary_type& dict();
+ const dictionary_type& dict() const;
+
+ void swap(entry& e);
+
+ // these functions requires that the entry
+ // is a dictionary, otherwise they will throw
+ entry& operator[](char const* key);
+ entry& operator[](std::string const& key);
+#ifndef BOOST_NO_EXCEPTIONS
+ const entry& operator[](char const* key) const;
+ const entry& operator[](std::string const& key) const;
+#endif
+ entry* find_key(char const* key);
+ entry const* find_key(char const* key) const;
+
+ void print(std::ostream& os, int indent = 0) const;
+
+ protected:
+
+ void construct(data_type t);
+ void copy(const entry& e);
+ void destruct();
+
+ private:
+
+ data_type m_type;
+
+#if defined(_MSC_VER) && _MSC_VER < 1310
+ // workaround for msvc-bug.
+ // assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
+ // and sizeof(list<char>) == sizeof(list<entry>)
+ union
+ {
+ char data[
+ detail::max4<sizeof(std::list<char>)
+ , sizeof(std::map<std::string, char>)
+ , sizeof(string_type)
+ , sizeof(integer_type)>::value];
+ integer_type dummy_aligner;
+ };
+#else
+ union
+ {
+ char data[detail::max4<sizeof(list_type)
+ , sizeof(dictionary_type)
+ , sizeof(string_type)
+ , sizeof(integer_type)>::value];
+ integer_type dummy_aligner;
+ };
+#endif
+
+ };
+
+ inline std::ostream& operator<<(std::ostream& os, const entry& e)
+ {
+ e.print(os, 0);
+ return os;
+ }
+
+ inline entry::data_type entry::type() const { return m_type; }
+
+ inline entry::entry(): m_type(undefined_t) {}
+ inline entry::entry(data_type t): m_type(t) { construct(t); }
+ inline entry::entry(const entry& e) { copy(e); }
+ inline entry::~entry() { destruct(); }
+
+ inline void entry::operator=(const entry& e)
+ {
+ destruct();
+ copy(e);
+ }
+
+
+ inline entry::integer_type& entry::integer()
+ {
+ if (m_type == undefined_t) construct(int_t);
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != int_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == int_t);
+ return *reinterpret_cast<integer_type*>(data);
+ }
+
+ inline entry::integer_type const& entry::integer() const
+ {
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != int_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == int_t);
+ return *reinterpret_cast<const integer_type*>(data);
+ }
+
+ inline entry::string_type& entry::string()
+ {
+ if (m_type == undefined_t) construct(string_t);
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != string_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == string_t);
+ return *reinterpret_cast<string_type*>(data);
+ }
+
+ inline entry::string_type const& entry::string() const
+ {
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != string_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == string_t);
+ return *reinterpret_cast<const string_type*>(data);
+ }
+
+ inline entry::list_type& entry::list()
+ {
+ if (m_type == undefined_t) construct(list_t);
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != list_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == list_t);
+ return *reinterpret_cast<list_type*>(data);
+ }
+
+ inline entry::list_type const& entry::list() const
+ {
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != list_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == list_t);
+ return *reinterpret_cast<const list_type*>(data);
+ }
+
+ inline entry::dictionary_type& entry::dict()
+ {
+ if (m_type == undefined_t) construct(dictionary_t);
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == dictionary_t);
+ return *reinterpret_cast<dictionary_type*>(data);
+ }
+
+ inline entry::dictionary_type const& entry::dict() const
+ {
+#ifndef BOOST_NO_EXCEPTIONS
+ if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
+#endif
+ TORRENT_ASSERT(m_type == dictionary_t);
+ return *reinterpret_cast<const dictionary_type*>(data);
+ }
+
+}
+
+#endif // TORRENT_ENTRY_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/enum_net.hpp b/src/libtorrent/include/libtorrent/enum_net.hpp
new file mode 100644
index 0000000..56d89d4
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/enum_net.hpp
@@ -0,0 +1,65 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_ENUM_NET_HPP_INCLUDED
+#define TORRENT_ENUM_NET_HPP_INCLUDED
+
+#include "libtorrent/config.hpp"
+#include "libtorrent/socket.hpp"
+
+namespace libtorrent
+{
+
+ struct ip_interface
+ {
+ address interface_address;
+ address netmask;
+ };
+
+ // returns a list of the configured IP interfaces
+ // on the machine
+ TORRENT_EXPORT std::vector<ip_interface> enum_net_interfaces(asio::io_service& ios
+ , asio::error_code& ec);
+
+ // returns true if the specified address is on the same
+ // local network as the specified interface
+ TORRENT_EXPORT bool in_subnet(address const& addr, ip_interface const& iface);
+
+ // returns true if the specified address is on the same
+ // local network as us
+ TORRENT_EXPORT bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec);
+
+ TORRENT_EXPORT address router_for_interface(address const interface, asio::error_code& ec);
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/escape_string.hpp b/src/libtorrent/include/libtorrent/escape_string.hpp
new file mode 100644
index 0000000..e0e743e
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/escape_string.hpp
@@ -0,0 +1,46 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_ESCAPE_STRING_HPP_INCLUDED
+#define TORRENT_ESCAPE_STRING_HPP_INCLUDED
+
+#include <string>
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+ std::string TORRENT_EXPORT unescape_string(std::string const& s);
+ std::string TORRENT_EXPORT escape_string(const char* str, int len);
+ std::string TORRENT_EXPORT escape_path(const char* str, int len);
+}
+
+#endif // TORRENT_ESCAPE_STRING_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/extensions.hpp b/src/libtorrent/include/libtorrent/extensions.hpp
new file mode 100644
index 0000000..fd48588
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/extensions.hpp
@@ -0,0 +1,191 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_EXTENSIONS_HPP_INCLUDED
+#define TORRENT_EXTENSIONS_HPP_INCLUDED
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <vector>
+#include "libtorrent/config.hpp"
+#include "libtorrent/buffer.hpp"
+
+namespace libtorrent
+{
+ struct peer_plugin;
+ class bt_peer_connection;
+ struct peer_request;
+ class peer_connection;
+ class entry;
+
+ struct TORRENT_EXPORT torrent_plugin
+ {
+ virtual ~torrent_plugin() {}
+ // throwing an exception closes the connection
+ // returning a 0 pointer is valid and will not add
+ // the peer_plugin to the peer_connection
+ virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection*)
+ { return boost::shared_ptr<peer_plugin>(); }
+
+ virtual void on_piece_pass(int index) {}
+ virtual void on_piece_failed(int index) {}
+
+ // called aproximately once every second
+ virtual void tick() {}
+
+ // if true is returned, it means the handler handled the event,
+ // and no other plugins will have their handlers called, and the
+ // default behavior will be skipped
+ virtual bool on_pause() { return false; }
+ virtual bool on_resume() { return false;}
+
+ // this is called when the initial checking of
+ // files is completed.
+ virtual void on_files_checked() {}
+ };
+
+ struct TORRENT_EXPORT peer_plugin
+ {
+ virtual ~peer_plugin() {}
+
+ // can add entries to the extension handshake
+ // this is not called for web seeds
+ virtual void add_handshake(entry&) {}
+
+ // throwing an exception from any of the handlers (except add_handshake)
+ // closes the connection
+
+ // this is called when the initial BT handshake is received. Returning false
+ // means that the other end doesn't support this extension and will remove
+ // it from the list of plugins.
+ // this is not called for web seeds
+ virtual bool on_handshake() { return true; }
+
+ // called when the extension handshake from the other end is received
+ // if this returns false, it means that this extension isn't
+ // supported by this peer. It will result in this peer_plugin
+ // being removed from the peer_connection and destructed.
+ // this is not called for web seeds
+ virtual bool on_extension_handshake(entry const& h) { return true; }
+
+ // returning true from any of the message handlers
+ // indicates that the plugin has handeled the message.
+ // it will break the plugin chain traversing and not let
+ // anyone else handle the message, including the default
+ // handler.
+
+ virtual bool on_choke()
+ { return false; }
+
+ virtual bool on_unchoke()
+ { return false; }
+
+ virtual bool on_interested()
+ { return false; }
+
+ virtual bool on_not_interested()
+ { return false; }
+
+ virtual bool on_have(int index)
+ { return false; }
+
+ virtual bool on_bitfield(std::vector<bool> const& bitfield)
+ { return false; }
+
+ virtual bool on_have_all()
+ { return false; }
+
+ virtual bool on_have_none()
+ { return false; }
+
+ virtual bool on_allowed_fast(int index)
+ { return false; }
+
+ virtual bool on_request(peer_request const& req)
+ { return false; }
+
+ virtual bool on_piece(peer_request const& piece, char const* data)
+ { return false; }
+
+ virtual bool on_cancel(peer_request const& req)
+ { return false; }
+
+ virtual bool on_reject(peer_request const& req)
+ { return false; }
+
+ virtual bool on_suggest(int index)
+ { return false; }
+
+ // called when an extended message is received. If returning true,
+ // the message is not processed by any other plugin and if false
+ // is returned the next plugin in the chain will receive it to
+ // be able to handle it
+ // this is not called for web seeds
+ virtual bool on_extended(int length
+ , int msg, buffer::const_interval body)
+ { return false; }
+
+ // this is not called for web seeds
+ virtual bool on_unknown_message(int length, int msg
+ , buffer::const_interval body)
+ { return false; }
+
+ // called when a piece that this peer participated in either
+ // fails or passes the hash_check
+ virtual void on_piece_pass(int index) {}
+ virtual void on_piece_failed(int index) {}
+
+ // called aproximately once every second
+ virtual void tick() {}
+
+ // called each time a request message is to be sent. If true
+ // is returned, the original request message won't be sent and
+ // no other plugin will have this function called.
+ virtual bool write_request(peer_request const& r) { return false; }
+ };
+
+}
+
+#endif
+
+#endif // TORRENT_EXTENSIONS_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/extensions/logger.hpp b/src/libtorrent/include/libtorrent/extensions/logger.hpp
new file mode 100644
index 0000000..42e08fc
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/extensions/logger.hpp
@@ -0,0 +1,54 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_LOGGER_HPP_INCLUDED
+#define TORRENT_LOGGER_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace libtorrent
+{
+ struct torrent_plugin;
+ class torrent;
+ boost::shared_ptr<torrent_plugin> create_logger_plugin(torrent*);
+}
+
+#endif // TORRENT_LOGGER_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp b/src/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp
new file mode 100644
index 0000000..c42136d
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp
@@ -0,0 +1,55 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_METADATA_TRANSFER_HPP_INCLUDED
+#define TORRENT_METADATA_TRANSFER_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include "libtorrent/config.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace libtorrent
+{
+ struct torrent_plugin;
+ class torrent;
+ TORRENT_EXPORT boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent*, void*);
+}
+
+#endif // TORRENT_METADATA_TRANSFER_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/extensions/ut_pex.hpp b/src/libtorrent/include/libtorrent/extensions/ut_pex.hpp
new file mode 100644
index 0000000..ebf6aa8
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/extensions/ut_pex.hpp
@@ -0,0 +1,54 @@
+/*
+
+Copyright (c) 2006, MassaRoddel
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED
+#define TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include "libtorrent/config.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace libtorrent
+{
+ struct torrent_plugin;
+ class torrent;
+ TORRENT_EXPORT boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent*, void*);
+}
+
+#endif // TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/file.hpp b/src/libtorrent/include/libtorrent/file.hpp
new file mode 100644
index 0000000..bd0d035
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/file.hpp
@@ -0,0 +1,132 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_FILE_HPP_INCLUDED
+#define TORRENT_FILE_HPP_INCLUDED
+
+#include <memory>
+#include <stdexcept>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem/path.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/size_type.hpp"
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+ namespace fs = boost::filesystem;
+
+ struct TORRENT_EXPORT file_error: std::runtime_error
+ {
+ file_error(std::string const& msg): std::runtime_error(msg) {}
+ };
+
+ class TORRENT_EXPORT file: public boost::noncopyable
+ {
+ public:
+
+ class seek_mode
+ {
+ friend class file;
+ private:
+ seek_mode(int v): m_val(v) {}
+ int m_val;
+ };
+
+ static const seek_mode begin;
+ static const seek_mode end;
+
+ class open_mode
+ {
+ friend class file;
+ public:
+
+ open_mode(): m_mask(0) {}
+
+ open_mode operator|(open_mode m) const
+ { return open_mode(m.m_mask | m_mask); }
+
+ open_mode operator&(open_mode m) const
+ { return open_mode(m.m_mask & m_mask); }
+
+ open_mode operator|=(open_mode m)
+ {
+ m_mask |= m.m_mask;
+ return *this;
+ }
+
+ bool operator==(open_mode m) const { return m_mask == m.m_mask; }
+ bool operator!=(open_mode m) const { return m_mask != m.m_mask; }
+
+ private:
+
+ open_mode(int val): m_mask(val) {}
+ int m_mask;
+ };
+
+ static const open_mode in;
+ static const open_mode out;
+
+ file();
+ file(fs::path const& p, open_mode m);
+ ~file();
+
+ void open(fs::path const& p, open_mode m);
+ void close();
+ void set_size(size_type size);
+
+ size_type write(const char*, size_type num_bytes);
+ size_type read(char*, size_type num_bytes);
+
+ size_type seek(size_type pos, seek_mode m = begin);
+ size_type tell();
+
+ private:
+
+ struct impl;
+ const std::auto_ptr<impl> m_impl;
+
+ };
+
+}
+
+#endif // TORRENT_FILE_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/file_pool.hpp b/src/libtorrent/include/libtorrent/file_pool.hpp
new file mode 100644
index 0000000..a22c265
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/file_pool.hpp
@@ -0,0 +1,103 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_FILE_POOL_HPP
+#define TORRENT_FILE_POOL_HPP
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/filesystem/path.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/file.hpp"
+#include "libtorrent/time.hpp"
+
+namespace libtorrent
+{
+
+ using boost::multi_index::multi_index_container;
+ using boost::multi_index::ordered_non_unique;
+ using boost::multi_index::ordered_unique;
+ using boost::multi_index::indexed_by;
+ using boost::multi_index::member;
+ namespace fs = boost::filesystem;
+
+ struct TORRENT_EXPORT file_pool : boost::noncopyable
+ {
+ file_pool(int size = 40): m_size(size) {}
+
+ boost::shared_ptr<file> open_file(void* st, fs::path const& p, file::open_mode m);
+ void release(void* st);
+ void resize(int size);
+
+ private:
+ int m_size;
+
+ struct lru_file_entry
+ {
+ lru_file_entry(boost::shared_ptr<file> const& f)
+ : file_ptr(f)
+ , last_use(time_now()) {}
+ mutable boost::shared_ptr<file> file_ptr;
+ fs::path file_path;
+ void* key;
+ ptime last_use;
+ file::open_mode mode;
+ };
+
+ typedef multi_index_container<
+ lru_file_entry, indexed_by<
+ ordered_unique<member<lru_file_entry, fs::path
+ , &lru_file_entry::file_path> >
+ , ordered_non_unique<member<lru_file_entry, ptime
+ , &lru_file_entry::last_use> >
+ , ordered_non_unique<member<lru_file_entry, void*
+ , &lru_file_entry::key> >
+ >
+ > file_set;
+
+ file_set m_files;
+ boost::mutex m_mutex;
+ };
+}
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/fingerprint.hpp b/src/libtorrent/include/libtorrent/fingerprint.hpp
new file mode 100644
index 0000000..237fef0
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/fingerprint.hpp
@@ -0,0 +1,95 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_FINGERPRINT_HPP_INCLUDED
+#define TORRENT_FINGERPRINT_HPP_INCLUDED
+
+#include <string>
+#include <sstream>
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ struct fingerprint
+ {
+ fingerprint(const char* id_string, int major, int minor, int revision, int tag)
+ : major_version(major)
+ , minor_version(minor)
+ , revision_version(revision)
+ , tag_version(tag)
+ {
+ TORRENT_ASSERT(id_string);
+ TORRENT_ASSERT(major >= 0);
+ TORRENT_ASSERT(minor >= 0);
+ TORRENT_ASSERT(revision >= 0);
+ TORRENT_ASSERT(tag >= 0);
+ TORRENT_ASSERT(std::strlen(id_string) == 2);
+ name[0] = id_string[0];
+ name[1] = id_string[1];
+ }
+
+ std::string to_string() const
+ {
+ std::stringstream s;
+ s << "-" << name[0] << name[1]
+ << version_to_char(major_version)
+ << version_to_char(minor_version)
+ << version_to_char(revision_version)
+ << version_to_char(tag_version) << "-";
+ return s.str();
+ }
+
+ char name[2];
+ int major_version;
+ int minor_version;
+ int revision_version;
+ int tag_version;
+
+ private:
+
+ char version_to_char(int v) const
+ {
+ if (v >= 0 && v < 10) return '0' + v;
+ else if (v >= 10) return 'A' + (v - 10);
+ TORRENT_ASSERT(false);
+ return '0';
+ }
+
+ };
+
+}
+
+#endif // TORRENT_FINGERPRINT_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/hasher.hpp b/src/libtorrent/include/libtorrent/hasher.hpp
new file mode 100644
index 0000000..4dfeced
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/hasher.hpp
@@ -0,0 +1,122 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_HASHER_HPP_INCLUDED
+#define TORRENT_HASHER_HPP_INCLUDED
+
+#include <boost/cstdint.hpp>
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+#include "../zlib/zlib.h"
+
+#ifdef TORRENT_USE_OPENSSL
+extern "C"
+{
+#include <openssl/sha.h>
+}
+#else
+// from sha1.cpp
+struct TORRENT_EXPORT SHA_CTX
+{
+ boost::uint32_t state[5];
+ boost::uint32_t count[2];
+ boost::uint8_t buffer[64];
+};
+
+TORRENT_EXPORT void SHA1_Init(SHA_CTX* context);
+TORRENT_EXPORT void SHA1_Update(SHA_CTX* context, boost::uint8_t const* data, boost::uint32_t len);
+TORRENT_EXPORT void SHA1_Final(boost::uint8_t* digest, SHA_CTX* context);
+
+#endif
+
+namespace libtorrent
+{
+
+ class adler32_crc
+ {
+ public:
+ adler32_crc(): m_adler(adler32(0, 0, 0)) {}
+
+ void update(const char* data, int len)
+ {
+ TORRENT_ASSERT(data != 0);
+ TORRENT_ASSERT(len > 0);
+ m_adler = adler32(m_adler, (const Bytef*)data, len);
+ }
+ unsigned long final() const { return m_adler; }
+ void reset() { m_adler = adler32(0, 0, 0); }
+
+ private:
+
+ unsigned long m_adler;
+
+ };
+
+ class hasher
+ {
+ public:
+
+ hasher() { SHA1_Init(&m_context); }
+ hasher(const char* data, int len)
+ {
+ SHA1_Init(&m_context);
+ TORRENT_ASSERT(data != 0);
+ TORRENT_ASSERT(len > 0);
+ SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
+ }
+ void update(const char* data, int len)
+ {
+ TORRENT_ASSERT(data != 0);
+ TORRENT_ASSERT(len > 0);
+ SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
+ }
+
+ sha1_hash final()
+ {
+ sha1_hash digest;
+ SHA1_Final(digest.begin(), &m_context);
+ return digest;
+ }
+
+ void reset() { SHA1_Init(&m_context); }
+
+ private:
+
+ SHA_CTX m_context;
+
+ };
+}
+
+#endif // TORRENT_HASHER_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/http_connection.hpp b/src/libtorrent/include/libtorrent/http_connection.hpp
new file mode 100644
index 0000000..b65b303
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/http_connection.hpp
@@ -0,0 +1,165 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_HTTP_CONNECTION
+#define TORRENT_HTTP_CONNECTION
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+#include <vector>
+#include <string>
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/http_tracker_connection.hpp"
+#include "libtorrent/time.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+struct http_connection;
+
+typedef boost::function<void(asio::error_code const&
+ , http_parser const&, char const* data, int size)> http_handler;
+
+typedef boost::function<void(http_connection&)> http_connect_handler;
+
+// TODO: add bind interface
+
+// when bottled, the last two arguments to the handler
+// will always be 0
+struct http_connection : boost::enable_shared_from_this<http_connection>, boost::noncopyable
+{
+ http_connection(asio::io_service& ios, connection_queue& cc
+ , http_handler const& handler, bool bottled = true
+ , http_connect_handler const& ch = http_connect_handler())
+ : m_sock(ios)
+ , m_read_pos(0)
+ , m_resolver(ios)
+ , m_handler(handler)
+ , m_connect_handler(ch)
+ , m_timer(ios)
+ , m_last_receive(time_now())
+ , m_bottled(bottled)
+ , m_called(false)
+ , m_rate_limit(0)
+ , m_download_quota(0)
+ , m_limiter_timer_active(false)
+ , m_limiter_timer(ios)
+ , m_redirects(5)
+ , m_connection_ticket(-1)
+ , m_cc(cc)
+ {
+ TORRENT_ASSERT(!m_handler.empty());
+ }
+
+ void rate_limit(int limit);
+
+ int rate_limit() const
+ { return m_rate_limit; }
+
+ std::string sendbuffer;
+
+ void get(std::string const& url, time_duration timeout = seconds(30)
+ , int handle_redirects = 5);
+
+ void start(std::string const& hostname, std::string const& port
+ , time_duration timeout, int handle_redirect = 5);
+ void close();
+
+ tcp::socket const& socket() const { return m_sock; }
+
+private:
+
+ void on_resolve(asio::error_code const& e
+ , tcp::resolver::iterator i);
+ void connect(int ticket, tcp::endpoint target_address);
+ void on_connect_timeout();
+ void on_connect(asio::error_code const& e
+/* , tcp::resolver::iterator i*/);
+ void on_write(asio::error_code const& e);
+ void on_read(asio::error_code const& e, std::size_t bytes_transferred);
+ static void on_timeout(boost::weak_ptr<http_connection> p
+ , asio::error_code const& e);
+ void on_assign_bandwidth(asio::error_code const& e);
+
+ void callback(asio::error_code const& e, char const* data = 0, int size = 0);
+
+ std::vector<char> m_recvbuffer;
+ tcp::socket m_sock;
+ int m_read_pos;
+ tcp::resolver m_resolver;
+ http_parser m_parser;
+ http_handler m_handler;
+ http_connect_handler m_connect_handler;
+ deadline_timer m_timer;
+ time_duration m_timeout;
+ ptime m_last_receive;
+ // bottled means that the handler is called once, when
+ // everything is received (and buffered in memory).
+ // non bottled means that once the headers have been
+ // received, data is streamed to the handler
+ bool m_bottled;
+ // set to true the first time the handler is called
+ bool m_called;
+ std::string m_hostname;
+ std::string m_port;
+
+ // the current download limit, in bytes per second
+ // 0 is unlimited.
+ int m_rate_limit;
+
+ // the number of bytes we are allowed to receive
+ int m_download_quota;
+
+ // only hand out new quota 4 times a second if the
+ // quota is 0. If it isn't 0 wait for it to reach
+ // 0 and continue to hand out quota at that time.
+ bool m_limiter_timer_active;
+
+ // the timer fires every 250 millisecond as long
+ // as all the quota was used.
+ deadline_timer m_limiter_timer;
+
+ // the number of redirects to follow (in sequence)
+ int m_redirects;
+
+ int m_connection_ticket;
+ connection_queue& m_cc;
+};
+
+}
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/http_stream.hpp b/src/libtorrent/include/libtorrent/http_stream.hpp
new file mode 100644
index 0000000..041b7c8
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/http_stream.hpp
@@ -0,0 +1,102 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_HTTP_STREAM_HPP_INCLUDED
+#define TORRENT_HTTP_STREAM_HPP_INCLUDED
+
+#include "libtorrent/proxy_base.hpp"
+
+namespace libtorrent {
+
+class http_stream : public proxy_base
+{
+public:
+
+ explicit http_stream(asio::io_service& io_service)
+ : proxy_base(io_service)
+ , m_no_connect(false)
+ {}
+
+ void set_no_connect(bool c) { m_no_connect = c; }
+
+ void set_username(std::string const& user
+ , std::string const& password)
+ {
+ m_user = user;
+ m_password = password;
+ }
+
+ typedef boost::function<void(asio::error_code const&)> handler_type;
+
+ template <class Handler>
+ void async_connect(endpoint_type const& endpoint, Handler const& handler)
+ {
+ m_remote_endpoint = endpoint;
+
+ // the connect is split up in the following steps:
+ // 1. resolve name of proxy server
+ // 2. connect to proxy server
+ // 3. send HTTP CONNECT method and possibly username+password
+ // 4. read CONNECT response
+
+ // to avoid unnecessary copying of the handler,
+ // store it in a shaed_ptr
+ boost::shared_ptr<handler_type> h(new handler_type(handler));
+
+ tcp::resolver::query q(m_hostname
+ , boost::lexical_cast<std::string>(m_port));
+ m_resolver.async_resolve(q, boost::bind(
+ &http_stream::name_lookup, this, _1, _2, h));
+ }
+
+private:
+
+ void name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , boost::shared_ptr<handler_type> h);
+ void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+
+ // send and receive buffer
+ std::vector<char> m_buffer;
+ // proxy authentication
+ std::string m_user;
+ std::string m_password;
+
+ // this is true if the connection is HTTP based and
+ // want to talk directly to the proxy
+ bool m_no_connect;
+};
+
+}
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/http_tracker_connection.hpp b/src/libtorrent/include/libtorrent/http_tracker_connection.hpp
new file mode 100644
index 0000000..41df4c9
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/http_tracker_connection.hpp
@@ -0,0 +1,185 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
+#define TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <utility>
+#include <ctime>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/lexical_cast.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/session_settings.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/peer.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/buffer.hpp"
+#include "libtorrent/socket_type.hpp"
+#include "libtorrent/connection_queue.hpp"
+
+namespace libtorrent
+{
+
+ class http_parser
+ {
+ public:
+ http_parser();
+ std::string const& header(char const* key) const
+ {
+ static std::string empty;
+ std::map<std::string, std::string>::const_iterator i
+ = m_header.find(key);
+ if (i == m_header.end()) return empty;
+ return i->second;
+ }
+
+ std::string const& protocol() const { return m_protocol; }
+ int status_code() const { return m_status_code; }
+ std::string const& method() const { return m_method; }
+ std::string const& path() const { return m_path; }
+ std::string const& message() const { return m_server_message; }
+ buffer::const_interval get_body() const;
+ bool header_finished() const { return m_state == read_body; }
+ bool finished() const { return m_finished; }
+ boost::tuple<int, int> incoming(buffer::const_interval recv_buffer);
+ int body_start() const { return m_body_start_pos; }
+ int content_length() const { return m_content_length; }
+
+ void reset();
+
+ std::map<std::string, std::string> const& headers() const { return m_header; }
+
+ private:
+ int m_recv_pos;
+ int m_status_code;
+ std::string m_method;
+ std::string m_path;
+ std::string m_protocol;
+ std::string m_server_message;
+
+ int m_content_length;
+
+ enum { read_status, read_header, read_body } m_state;
+
+ std::map<std::string, std::string> m_header;
+ buffer::const_interval m_recv_buffer;
+ int m_body_start_pos;
+
+ bool m_finished;
+ };
+
+ class TORRENT_EXPORT http_tracker_connection
+ : public tracker_connection
+ {
+ friend class tracker_manager;
+ public:
+
+ http_tracker_connection(
+ asio::strand& str
+ , connection_queue& cc
+ , tracker_manager& man
+ , tracker_request const& req
+ , std::string const& hostname
+ , unsigned short port
+ , std::string request
+ , address bind_infc
+ , boost::weak_ptr<request_callback> c
+ , session_settings const& stn
+ , proxy_settings const& ps
+ , std::string const& password = "");
+
+ void close();
+
+ private:
+
+ boost::intrusive_ptr<http_tracker_connection> self()
+ { return boost::intrusive_ptr<http_tracker_connection>(this); }
+
+ void on_response();
+
+ void init_send_buffer(
+ std::string const& hostname
+ , std::string const& request);
+
+ void name_lookup(asio::error_code const& error, tcp::resolver::iterator i);
+ void connect(int ticket, tcp::endpoint target_address);
+ void connected(asio::error_code const& error);
+ void sent(asio::error_code const& error);
+ void receive(asio::error_code const& error
+ , std::size_t bytes_transferred);
+
+ virtual void on_timeout();
+
+ void parse(const entry& e);
+ peer_entry extract_peer_info(const entry& e);
+
+ tracker_manager& m_man;
+ http_parser m_parser;
+
+ asio::strand& m_strand;
+ tcp::resolver m_name_lookup;
+ int m_port;
+ socket_type m_socket;
+ int m_recv_pos;
+ std::vector<char> m_buffer;
+ std::string m_send_buffer;
+
+ session_settings const& m_settings;
+ proxy_settings const& m_proxy;
+ std::string m_password;
+
+ bool m_timed_out;
+
+ int m_connection_ticket;
+ connection_queue& m_cc;
+ };
+
+}
+
+#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/identify_client.hpp b/src/libtorrent/include/libtorrent/identify_client.hpp
new file mode 100644
index 0000000..e8cb3b9
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/identify_client.hpp
@@ -0,0 +1,58 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED
+#define TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/optional.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/fingerprint.hpp"
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+
+ TORRENT_EXPORT std::string identify_client(const peer_id& p);
+ TORRENT_EXPORT boost::optional<fingerprint> client_fingerprint(peer_id const& p);
+
+}
+
+#endif // TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/instantiate_connection.hpp b/src/libtorrent/include/libtorrent/instantiate_connection.hpp
new file mode 100644
index 0000000..71282f9
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/instantiate_connection.hpp
@@ -0,0 +1,49 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_INSTANTIATE_CONNECTION
+#define TORRENT_INSTANTIATE_CONNECTION
+
+#include "libtorrent/socket_type.hpp"
+#include <asio/io_service.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace libtorrent
+{
+ struct proxy_settings;
+
+ bool instantiate_connection(asio::io_service& ios
+ , proxy_settings const& ps, socket_type& s);
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/intrusive_ptr_base.hpp b/src/libtorrent/include/libtorrent/intrusive_ptr_base.hpp
new file mode 100644
index 0000000..5cccdf8
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/intrusive_ptr_base.hpp
@@ -0,0 +1,84 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_INTRUSIVE_PTR_BASE
+#define TORRENT_INTRUSIVE_PTR_BASE
+
+#include <boost/detail/atomic_count.hpp>
+#include <boost/checked_delete.hpp>
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ template<class T>
+ struct intrusive_ptr_base
+ {
+ intrusive_ptr_base(intrusive_ptr_base<T> const&)
+ : m_refs(0) {}
+
+ intrusive_ptr_base& operator=(intrusive_ptr_base const& rhs)
+ { return *this; }
+
+ friend void intrusive_ptr_add_ref(intrusive_ptr_base<T> const* s)
+ {
+ TORRENT_ASSERT(s->m_refs >= 0);
+ TORRENT_ASSERT(s != 0);
+ ++s->m_refs;
+ }
+
+ friend void intrusive_ptr_release(intrusive_ptr_base<T> const* s)
+ {
+ TORRENT_ASSERT(s->m_refs > 0);
+ TORRENT_ASSERT(s != 0);
+ if (--s->m_refs == 0)
+ boost::checked_delete(static_cast<T const*>(s));
+ }
+
+ boost::intrusive_ptr<T> self()
+ { return boost::intrusive_ptr<T>((T*)this); }
+
+ boost::intrusive_ptr<const T> self() const
+ { return boost::intrusive_ptr<const T>((T const*)this); }
+
+ int refcount() const { return m_refs; }
+
+ intrusive_ptr_base(): m_refs(0) {}
+ private:
+ // reference counter for intrusive_ptr
+ mutable boost::detail::atomic_count m_refs;
+ };
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/invariant_check.hpp b/src/libtorrent/include/libtorrent/invariant_check.hpp
new file mode 100644
index 0000000..c687b6a
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/invariant_check.hpp
@@ -0,0 +1,78 @@
+// Copyright Daniel Wallin 2004. Use, modification and distribution is
+// subject to the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef TORRENT_INVARIANT_ACCESS_HPP_INCLUDED
+#define TORRENT_INVARIANT_ACCESS_HPP_INCLUDED
+
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ class invariant_access
+ {
+ public:
+ template<class T>
+ static void check_invariant(T const& self)
+ {
+ self.check_invariant();
+ }
+ };
+
+ template<class T>
+ void check_invariant(T const& x)
+ {
+ invariant_access::check_invariant(x);
+ }
+
+ struct invariant_checker {};
+
+ template<class T>
+ struct invariant_checker_impl : invariant_checker
+ {
+ invariant_checker_impl(T const& self_)
+ : self(self_)
+ {
+ try
+ {
+ check_invariant(self);
+ }
+ catch (...)
+ {
+ TORRENT_ASSERT(false);
+ }
+ }
+
+ ~invariant_checker_impl()
+ {
+ try
+ {
+ check_invariant(self);
+ }
+ catch (...)
+ {
+ TORRENT_ASSERT(false);
+ }
+ }
+
+ T const& self;
+ };
+
+ template<class T>
+ invariant_checker_impl<T> make_invariant_checker(T const& x)
+ {
+ return invariant_checker_impl<T>(x);
+ }
+}
+
+#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
+#define INVARIANT_CHECK \
+ invariant_checker const& _invariant_check = make_invariant_checker(*this); \
+ (void)_invariant_check; \
+ do {} while (false)
+#else
+#define INVARIANT_CHECK do {} while (false)
+#endif
+
+#endif // TORRENT_INVARIANT_ACCESS_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/io.hpp b/src/libtorrent/include/libtorrent/io.hpp
new file mode 100644
index 0000000..f73c3e2
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/io.hpp
@@ -0,0 +1,153 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_IO_HPP_INCLUDED
+#define TORRENT_IO_HPP_INCLUDED
+
+#include <boost/cstdint.hpp>
+#include <string>
+
+namespace libtorrent
+{
+ namespace detail
+ {
+ template <class T> struct type {};
+
+ // reads an integer from a byte stream
+ // in big endian byte order and converts
+ // it to native endianess
+ template <class T, class InIt>
+ inline T read_impl(InIt& start, type<T>)
+ {
+ T ret = 0;
+ for (int i = 0; i < (int)sizeof(T); ++i)
+ {
+ ret <<= 8;
+ ret |= static_cast<unsigned char>(*start);
+ ++start;
+ }
+ return ret;
+ }
+
+ template <class T, class OutIt>
+ inline void write_impl(T val, OutIt& start)
+ {
+ for (int i = (int)sizeof(T)-1; i >= 0; --i)
+ {
+ *start = static_cast<unsigned char>((val >> (i * 8)) & 0xff);
+ ++start;
+ }
+ }
+
+ // -- adaptors
+
+ template <class InIt>
+ boost::int64_t read_int64(InIt& start)
+ { return read_impl(start, type<boost::int64_t>()); }
+
+ template <class InIt>
+ boost::uint64_t read_uint64(InIt& start)
+ { return read_impl(start, type<boost::uint64_t>()); }
+
+ template <class InIt>
+ boost::uint32_t read_uint32(InIt& start)
+ { return read_impl(start, type<boost::uint32_t>()); }
+
+ template <class InIt>
+ boost::int32_t read_int32(InIt& start)
+ { return read_impl(start, type<boost::int32_t>()); }
+
+ template <class InIt>
+ boost::int16_t read_int16(InIt& start)
+ { return read_impl(start, type<boost::int16_t>()); }
+
+ template <class InIt>
+ boost::uint16_t read_uint16(InIt& start)
+ { return read_impl(start, type<boost::uint16_t>()); }
+
+ template <class InIt>
+ boost::int8_t read_int8(InIt& start)
+ { return read_impl(start, type<boost::int8_t>()); }
+
+ template <class InIt>
+ boost::uint8_t read_uint8(InIt& start)
+ { return read_impl(start, type<boost::uint8_t>()); }
+
+
+ template <class OutIt>
+ void write_uint64(boost::uint64_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ template <class OutIt>
+ void write_int64(boost::int64_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ template <class OutIt>
+ void write_uint32(boost::uint32_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ template <class OutIt>
+ void write_int32(boost::int32_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ template <class OutIt>
+ void write_uint16(boost::uint16_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ template <class OutIt>
+ void write_int16(boost::int16_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ template <class OutIt>
+ void write_uint8(boost::uint8_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ template <class OutIt>
+ void write_int8(boost::int8_t val, OutIt& start)
+ { write_impl(val, start); }
+
+ inline void write_string(std::string const& str, char*& start)
+ {
+ std::copy(str.begin(), str.end(), start);
+ start += str.size();
+ }
+
+ template <class OutIt>
+ void write_string(std::string const& str, OutIt& start)
+ {
+ std::copy(str.begin(), str.end(), start);
+ }
+
+ }
+}
+
+#endif // TORRENT_IO_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/ip_filter.hpp b/src/libtorrent/include/libtorrent/ip_filter.hpp
new file mode 100644
index 0000000..1adb145
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/ip_filter.hpp
@@ -0,0 +1,317 @@
+/*
+
+Copyright (c) 2005, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_IP_FILTER_HPP
+#define TORRENT_IP_FILTER_HPP
+
+#include <set>
+#include <iostream>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/limits.hpp>
+#include <boost/utility.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+
+#include "libtorrent/config.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+inline bool operator<=(address const& lhs
+ , address const& rhs)
+{
+ return lhs < rhs || lhs == rhs;
+}
+
+template <class Addr>
+struct ip_range
+{
+ Addr first;
+ Addr last;
+ int flags;
+};
+
+namespace detail
+{
+
+ template<class Addr>
+ Addr zero()
+ {
+ Addr zero;
+ std::fill(zero.begin(), zero.end(), 0);
+ return zero;
+ }
+
+ template<>
+ inline boost::uint16_t zero<boost::uint16_t>() { return 0; }
+
+ template<class Addr>
+ Addr plus_one(Addr const& a)
+ {
+ Addr tmp(a);
+ typedef typename Addr::reverse_iterator iter;
+ for (iter i = tmp.rbegin()
+ , end(tmp.rend()); i != end; ++i)
+ {
+ if (*i < (std::numeric_limits<typename iter::value_type>::max)())
+ {
+ *i += 1;
+ break;
+ }
+ *i = 0;
+ }
+ return tmp;
+ }
+
+ inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; }
+
+ template<class Addr>
+ Addr minus_one(Addr const& a)
+ {
+ Addr tmp(a);
+ typedef typename Addr::reverse_iterator iter;
+ for (iter i = tmp.rbegin()
+ , end(tmp.rend()); i != end; ++i)
+ {
+ if (*i > 0)
+ {
+ *i -= 1;
+ break;
+ }
+ *i = (std::numeric_limits<typename iter::value_type>::max)();
+ }
+ return tmp;
+ }
+
+ inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; }
+
+ template<class Addr>
+ Addr max_addr()
+ {
+ Addr tmp;
+ std::fill(tmp.begin(), tmp.end()
+ , (std::numeric_limits<typename Addr::value_type>::max)());
+ return Addr(tmp);
+ }
+
+ template<>
+ inline boost::uint16_t max_addr<boost::uint16_t>()
+ { return (std::numeric_limits<boost::uint16_t>::max)(); }
+
+ // this is the generic implementation of
+ // a filter for a specific address type.
+ // it works with IPv4 and IPv6
+ template<class Addr>
+ class filter_impl
+ {
+ public:
+
+ filter_impl()
+ {
+ // make the entire ip-range non-blocked
+ m_access_list.insert(range(zero<Addr>(), 0));
+ }
+
+ void add_rule(Addr first, Addr last, int flags)
+ {
+ using boost::next;
+ using boost::prior;
+
+ TORRENT_ASSERT(!m_access_list.empty());
+ TORRENT_ASSERT(first < last || first == last);
+
+ typename range_t::iterator i = m_access_list.upper_bound(first);
+ typename range_t::iterator j = m_access_list.upper_bound(last);
+
+ if (i != m_access_list.begin()) --i;
+
+ TORRENT_ASSERT(j != m_access_list.begin());
+ TORRENT_ASSERT(j != i);
+
+ int first_access = i->access;
+ int last_access = prior(j)->access;
+
+ if (i->start != first && first_access != flags)
+ {
+ i = m_access_list.insert(i, range(first, flags));
+ }
+ else if (i != m_access_list.begin() && prior(i)->access == flags)
+ {
+ --i;
+ first_access = i->access;
+ }
+ TORRENT_ASSERT(!m_access_list.empty());
+ TORRENT_ASSERT(i != m_access_list.end());
+
+ if (i != j) m_access_list.erase(next(i), j);
+ if (i->start == first)
+ {
+ // we can do this const-cast because we know that the new
+ // start address will keep the set correctly ordered
+ const_cast<Addr&>(i->start) = first;
+ const_cast<int&>(i->access) = flags;
+ }
+ else if (first_access != flags)
+ {
+ m_access_list.insert(i, range(first, flags));
+ }
+
+ if ((j != m_access_list.end()
+ && minus_one(j->start) != last)
+ || (j == m_access_list.end()
+ && last != max_addr<Addr>()))
+ {
+ TORRENT_ASSERT(j == m_access_list.end() || last < minus_one(j->start));
+ if (last_access != flags)
+ j = m_access_list.insert(j, range(plus_one(last), last_access));
+ }
+
+ if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j);
+ TORRENT_ASSERT(!m_access_list.empty());
+ }
+
+ int access(Addr const& addr) const
+ {
+ TORRENT_ASSERT(!m_access_list.empty());
+ typename range_t::const_iterator i = m_access_list.upper_bound(addr);
+ if (i != m_access_list.begin()) --i;
+ TORRENT_ASSERT(i != m_access_list.end());
+ TORRENT_ASSERT(i->start <= addr && (boost::next(i) == m_access_list.end()
+ || addr < boost::next(i)->start));
+ return i->access;
+ }
+
+ template <class ExternalAddressType>
+ std::vector<ip_range<ExternalAddressType> > export_filter() const
+ {
+ std::vector<ip_range<ExternalAddressType> > ret;
+ ret.reserve(m_access_list.size());
+
+ for (typename range_t::const_iterator i = m_access_list.begin()
+ , end(m_access_list.end()); i != end;)
+ {
+ ip_range<ExternalAddressType> r;
+ r.first = ExternalAddressType(i->start);
+ r.flags = i->access;
+
+ ++i;
+ if (i == end)
+ r.last = ExternalAddressType(max_addr<Addr>());
+ else
+ r.last = ExternalAddressType(minus_one(i->start));
+
+ ret.push_back(r);
+ }
+ return ret;
+ }
+
+ private:
+
+ struct range
+ {
+ range(Addr addr, int access = 0): start(addr), access(access) {}
+ bool operator<(range const& r) const
+ { return start < r.start; }
+ bool operator<(Addr const& a) const
+ { return start < a; }
+ Addr start;
+ // the end of the range is implicit
+ // and given by the next entry in the set
+ int access;
+ };
+
+ typedef std::set<range> range_t;
+ range_t m_access_list;
+
+ };
+
+}
+
+class TORRENT_EXPORT ip_filter
+{
+public:
+
+ enum access_flags
+ {
+ blocked = 1
+ };
+
+ // both addresses MUST be of the same type (i.e. both must
+ // be either IPv4 or both must be IPv6)
+ void add_rule(address first, address last, int flags);
+ int access(address const& addr) const;
+
+ typedef boost::tuple<std::vector<ip_range<address_v4> >
+ , std::vector<ip_range<address_v6> > > filter_tuple_t;
+
+ filter_tuple_t export_filter() const;
+
+// void print() const;
+
+private:
+
+ detail::filter_impl<address_v4::bytes_type> m_filter4;
+ detail::filter_impl<address_v6::bytes_type> m_filter6;
+};
+
+class TORRENT_EXPORT port_filter
+{
+public:
+
+ enum access_flags
+ {
+ blocked = 1
+ };
+
+ void add_rule(boost::uint16_t first, boost::uint16_t last, int flags);
+ int access(boost::uint16_t port) const;
+
+private:
+
+ detail::filter_impl<boost::uint16_t> m_filter;
+
+};
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp b/src/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp
new file mode 100644
index 0000000..244e4bb
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp
@@ -0,0 +1,117 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef CLOSEST_NODES_050323_HPP
+#define CLOSEST_NODES_050323_HPP
+
+#include <vector>
+
+#include <libtorrent/kademlia/traversal_algorithm.hpp>
+#include <libtorrent/kademlia/node_id.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/observer.hpp>
+#include <libtorrent/kademlia/msg.hpp>
+
+#include <boost/function.hpp>
+
+namespace libtorrent { namespace dht
+{
+
+class rpc_manager;
+
+// -------- closest nodes -----------
+
+class closest_nodes : public traversal_algorithm
+{
+public:
+ typedef boost::function<
+ void(std::vector<node_entry> const&)
+ > done_callback;
+
+ static void initiate(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+ );
+
+private:
+ void done();
+ void invoke(node_id const& id, asio::ip::udp::endpoint addr);
+
+ closest_nodes(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+ );
+
+ done_callback m_done_callback;
+};
+
+class closest_nodes_observer : public observer
+{
+public:
+ closest_nodes_observer(
+ boost::intrusive_ptr<traversal_algorithm> const& algorithm
+ , node_id self
+ , node_id target)
+ : observer(algorithm->allocator())
+ , m_algorithm(algorithm)
+ , m_target(target)
+ , m_self(self)
+ {}
+ ~closest_nodes_observer();
+
+ void send(msg& p)
+ {
+ p.info_hash = m_target;
+ }
+
+ void timeout();
+ void reply(msg const&);
+ void abort() { m_algorithm = 0; }
+
+private:
+ boost::intrusive_ptr<traversal_algorithm> m_algorithm;
+ node_id const m_target;
+ node_id const m_self;
+};
+
+} } // namespace libtorrent::dht
+
+#endif // CLOSEST_NODES_050323_HPP
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp b/src/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp
new file mode 100644
index 0000000..6882d34
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp
@@ -0,0 +1,179 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_DISABLE_DHT
+
+#ifndef TORRENT_DHT_TRACKER
+#define TORRENT_DHT_TRACKER
+
+#include <fstream>
+#include <set>
+#include <numeric>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <boost/optional.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/thread/mutex.hpp>
+
+#include "libtorrent/kademlia/node.hpp"
+#include "libtorrent/kademlia/node_id.hpp"
+#include "libtorrent/kademlia/traversal_algorithm.hpp"
+#include "libtorrent/kademlia/packet_iterator.hpp"
+#include "libtorrent/session_settings.hpp"
+#include "libtorrent/session_status.hpp"
+
+namespace libtorrent { namespace dht
+{
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_DECLARE_LOG(dht_tracker);
+#endif
+
+ struct dht_tracker;
+
+ TORRENT_EXPORT void intrusive_ptr_add_ref(dht_tracker const*);
+ TORRENT_EXPORT void intrusive_ptr_release(dht_tracker const*);
+
+ struct dht_tracker
+ {
+ friend void intrusive_ptr_add_ref(dht_tracker const*);
+ friend void intrusive_ptr_release(dht_tracker const*);
+ dht_tracker(asio::io_service& ios, dht_settings const& settings
+ , asio::ip::address listen_interface, entry const& bootstrap);
+ void stop();
+
+ void add_node(udp::endpoint node);
+ void add_node(std::pair<std::string, int> const& node);
+ void add_router_node(std::pair<std::string, int> const& node);
+
+ void rebind(asio::ip::address listen_interface, int listen_port);
+
+ entry state() const;
+
+ void announce(sha1_hash const& ih, int listen_port
+ , boost::function<void(std::vector<tcp::endpoint> const&
+ , sha1_hash const&)> f);
+
+ void dht_status(session_status& s);
+
+ private:
+
+ boost::intrusive_ptr<dht_tracker> self()
+ { return boost::intrusive_ptr<dht_tracker>(this); }
+
+ void on_name_lookup(asio::error_code const& e
+ , udp::resolver::iterator host);
+ void on_router_name_lookup(asio::error_code const& e
+ , udp::resolver::iterator host);
+ void connection_timeout(asio::error_code const& e);
+ void refresh_timeout(asio::error_code const& e);
+ void tick(asio::error_code const& e);
+
+ // translate bittorrent kademlia message into the generic kademlia message
+ // used by the library
+ void on_receive(asio::error_code const& error, size_t bytes_transferred);
+ void on_bootstrap();
+ void send_packet(msg const& m);
+
+ asio::strand m_strand;
+ asio::ip::udp::socket m_socket;
+
+ node_impl m_dht;
+
+ // this is the index of the receive buffer we are currently receiving to
+ // the other buffer is the one containing the last message
+ int m_buffer;
+ std::vector<char> m_in_buf[2];
+ udp::endpoint m_remote_endpoint[2];
+ std::vector<char> m_send_buf;
+
+ ptime m_last_new_key;
+ deadline_timer m_timer;
+ deadline_timer m_connection_timer;
+ deadline_timer m_refresh_timer;
+ dht_settings const& m_settings;
+ int m_refresh_bucket;
+
+ // The mutex is used to abort the dht node
+ // it's only used to set m_abort to true
+ typedef boost::mutex mutex_t;
+ mutable mutex_t m_mutex;
+ bool m_abort;
+
+ // used to resolve hostnames for nodes
+ udp::resolver m_host_resolver;
+
+ // used to ignore abusive dht nodes
+ struct node_ban_entry
+ {
+ node_ban_entry(): count(0) {}
+ udp::endpoint src;
+ ptime limit;
+ int count;
+ };
+
+ enum { num_ban_nodes = 20 };
+
+ node_ban_entry m_ban_nodes[num_ban_nodes];
+
+ // reference counter for intrusive_ptr
+ mutable boost::detail::atomic_count m_refs;
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ int m_replies_sent[5];
+ int m_queries_received[5];
+ int m_replies_bytes_sent[5];
+ int m_queries_bytes_received[5];
+ int m_counter;
+ int m_announces;
+ int m_failed_announces;
+
+ int m_total_message_input;
+ int m_ut_message_input;
+ int m_lt_message_input;
+ int m_mp_message_input;
+ int m_gr_message_input;
+ int m_mo_message_input;
+
+ int m_total_in_bytes;
+ int m_total_out_bytes;
+
+ int m_queries_out_bytes;
+#endif
+ };
+}}
+
+#endif
+#endif
diff --git a/src/libtorrent/include/libtorrent/kademlia/find_data.hpp b/src/libtorrent/include/libtorrent/kademlia/find_data.hpp
new file mode 100644
index 0000000..17d77c9
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/find_data.hpp
@@ -0,0 +1,128 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef FIND_DATA_050323_HPP
+#define FIND_DATA_050323_HPP
+
+#include <vector>
+
+#include <libtorrent/kademlia/traversal_algorithm.hpp>
+#include <libtorrent/kademlia/node_id.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/rpc_manager.hpp>
+#include <libtorrent/kademlia/packet_iterator.hpp>
+#include <libtorrent/kademlia/observer.hpp>
+#include <libtorrent/kademlia/msg.hpp>
+
+#include <boost/optional.hpp>
+#include <boost/function.hpp>
+
+namespace libtorrent { namespace dht
+{
+
+using asio::ip::udp;
+
+typedef std::vector<char> packet_t;
+
+class rpc_manager;
+
+// -------- find data -----------
+
+class find_data : public traversal_algorithm
+{
+public:
+ typedef boost::function<void(msg const*)> done_callback;
+
+ static void initiate(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+ );
+
+ void got_data(msg const* m);
+
+private:
+ void done();
+ void invoke(node_id const& id, udp::endpoint addr);
+
+ find_data(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+ );
+
+ done_callback m_done_callback;
+ boost::shared_ptr<packet_t> m_packet;
+ bool m_done;
+};
+
+class find_data_observer : public observer
+{
+public:
+ find_data_observer(
+ boost::intrusive_ptr<find_data> const& algorithm
+ , node_id self
+ , node_id target)
+ : observer(algorithm->allocator())
+ , m_algorithm(algorithm)
+ , m_target(target)
+ , m_self(self)
+ {}
+ ~find_data_observer();
+
+ void send(msg& m)
+ {
+ m.reply = false;
+ m.message_id = messages::get_peers;
+ m.info_hash = m_target;
+ }
+
+ void timeout();
+ void reply(msg const&);
+ void abort() { m_algorithm = 0; }
+
+private:
+ boost::intrusive_ptr<find_data> m_algorithm;
+ node_id const m_target;
+ node_id const m_self;
+};
+
+} } // namespace libtorrent::dht
+
+#endif // FIND_DATA_050323_HPP
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/logging.hpp b/src/libtorrent/include/libtorrent/kademlia/logging.hpp
new file mode 100644
index 0000000..c0cbb31
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/logging.hpp
@@ -0,0 +1,146 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_LOGGING_HPP
+#define TORRENT_LOGGING_HPP
+
+#include <iostream>
+#include <fstream>
+
+namespace libtorrent { namespace dht
+{
+
+class log
+{
+public:
+ log(char const* id, std::ostream& stream)
+ : m_id(id)
+ , m_enabled(true)
+ , m_stream(stream)
+ {
+ }
+
+ char const* id() const
+ {
+ return m_id;
+ }
+
+ bool enabled() const
+ {
+ return m_enabled;
+ }
+
+ void enable(bool e)
+ {
+ m_enabled = e;
+ }
+
+ void flush() { m_stream.flush(); }
+
+ template<class T>
+ log& operator<<(T const& x)
+ {
+ m_stream << x;
+ return *this;
+ }
+
+private:
+ char const* m_id;
+ bool m_enabled;
+ std::ostream& m_stream;
+};
+
+class log_event
+{
+public:
+ log_event(log& log)
+ : log_(log)
+ {
+ if (log_.enabled())
+ log_ << '[' << log.id() << "] ";
+ }
+
+ ~log_event()
+ {
+ if (log_.enabled())
+ {
+ log_ << "\n";
+ log_.flush();
+ }
+ }
+
+ template<class T>
+ log_event& operator<<(T const& x)
+ {
+ log_ << x;
+ return *this;
+ }
+
+ operator bool() const
+ {
+ return log_.enabled();
+ }
+
+private:
+ log& log_;
+};
+
+class inverted_log_event : public log_event
+{
+public:
+ inverted_log_event(log& log) : log_event(log) {}
+
+ operator bool() const
+ {
+ return !log_event::operator bool();
+ }
+};
+
+} } // namespace libtorrent::dht
+
+#define TORRENT_DECLARE_LOG(name) \
+ libtorrent::dht::log& name ## _log()
+
+#define TORRENT_DEFINE_LOG(name) \
+ libtorrent::dht::log& name ## _log() \
+ { \
+ static std::ofstream log_file("dht.log", std::ios::app); \
+ static libtorrent::dht::log instance(#name, log_file); \
+ return instance; \
+ }
+
+#define TORRENT_LOG(name) \
+ if (libtorrent::dht::inverted_log_event event_object__ = name ## _log()); \
+ else static_cast<log_event&>(event_object__)
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/msg.hpp b/src/libtorrent/include/libtorrent/kademlia/msg.hpp
new file mode 100644
index 0000000..a205ce4
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/msg.hpp
@@ -0,0 +1,102 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef MSG_HPP
+#define MSG_HPP
+
+#include <string>
+#include <libtorrent/kademlia/node_id.hpp>
+#include "libtorrent/entry.hpp"
+#include <asio/ip/udp.hpp>
+
+namespace libtorrent {
+namespace dht {
+
+typedef std::vector<char> packet_t;
+
+using asio::ip::udp;
+
+namespace messages
+{
+ enum { ping = 0, find_node = 1, get_peers = 2, announce_peer = 3, error = 4 };
+ char const* const ids[] = { "ping", "find_node", "get_peers", "announce_peer", "error" };
+} // namespace messages
+
+struct msg
+{
+ msg() : reply(false), piggy_backed_ping(false)
+ , message_id(-1), port(0) {}
+
+ // true if this message is a reply
+ bool reply;
+ // true if this is a reply with a piggy backed ping
+ bool piggy_backed_ping;
+ // the kind if message
+ int message_id;
+ // if this is a reply, a copy of the transaction id
+ // from the request. If it's a request, a transaction
+ // id that should be sent back in the reply
+ std::string transaction_id;
+ // if this packet has a piggy backed ping, this
+ // is the transaction id of that ping
+ std::string ping_transaction_id;
+ // the node id of the process sending the message
+ node_id id;
+ // the address of the process sending or receiving
+ // the message.
+ udp::endpoint addr;
+ // if this is a nodes response, these are the nodes
+ typedef std::vector<node_entry> nodes_t;
+ nodes_t nodes;
+
+ typedef std::vector<tcp::endpoint> peers_t;
+ peers_t peers;
+
+ // similar to transaction_id but for write operations.
+ entry write_token;
+
+ // the info has for peer_requests, announce_peer
+ // and responses
+ node_id info_hash;
+
+ // port for announce_peer messages
+ int port;
+
+ // ERROR MESSAGES
+ int error_code;
+ std::string error_msg;
+};
+
+
+} }
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/kademlia/node.hpp b/src/libtorrent/include/libtorrent/kademlia/node.hpp
new file mode 100644
index 0000000..d93872d
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/node.hpp
@@ -0,0 +1,262 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef NODE_HPP
+#define NODE_HPP
+
+#include <algorithm>
+#include <map>
+#include <set>
+
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/rpc_manager.hpp>
+#include <libtorrent/kademlia/node_id.hpp>
+#include <libtorrent/kademlia/msg.hpp>
+
+#include <libtorrent/io.hpp>
+#include <libtorrent/session_settings.hpp>
+#include <libtorrent/assert.hpp>
+
+#include <boost/cstdint.hpp>
+#include <boost/optional.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/ref.hpp>
+
+#include "libtorrent/socket.hpp"
+
+namespace libtorrent { namespace dht
+{
+
+using asio::ip::udp;
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DECLARE_LOG(node);
+#endif
+
+// this is the entry for every peer
+// the timestamp is there to make it possible
+// to remove stale peers
+struct peer_entry
+{
+ tcp::endpoint addr;
+ ptime added;
+};
+
+// this is a group. It contains a set of group members
+struct torrent_entry
+{
+ std::set<peer_entry> peers;
+};
+
+inline bool operator<(peer_entry const& lhs, peer_entry const& rhs)
+{
+ return lhs.addr.address() == rhs.addr.address()
+ ? lhs.addr.port() < rhs.addr.port()
+ : lhs.addr.address() < rhs.addr.address();
+}
+
+struct null_type {};
+
+class announce_observer : public observer
+{
+public:
+ announce_observer(boost::pool<>& allocator
+ , sha1_hash const& info_hash
+ , int listen_port
+ , entry const& write_token)
+ : observer(allocator)
+ , m_info_hash(info_hash)
+ , m_listen_port(listen_port)
+ , m_token(write_token)
+ {}
+
+ void send(msg& m)
+ {
+ m.port = m_listen_port;
+ m.info_hash = m_info_hash;
+ m.write_token = m_token;
+ }
+
+ void timeout() {}
+ void reply(msg const&) {}
+ void abort() {}
+
+private:
+ sha1_hash m_info_hash;
+ int m_listen_port;
+ entry m_token;
+};
+
+class get_peers_observer : public observer
+{
+public:
+ get_peers_observer(sha1_hash const& info_hash
+ , int listen_port
+ , rpc_manager& rpc
+ , boost::function<void(std::vector<tcp::endpoint> const&, sha1_hash const&)> f)
+ : observer(rpc.allocator())
+ , m_info_hash(info_hash)
+ , m_listen_port(listen_port)
+ , m_rpc(rpc)
+ , m_fun(f)
+ {}
+
+ void send(msg& m)
+ {
+ m.port = m_listen_port;
+ m.info_hash = m_info_hash;
+ }
+
+ void timeout() {}
+ void reply(msg const& r)
+ {
+ observer_ptr o(new (m_rpc.allocator().malloc()) announce_observer(
+ m_rpc.allocator(), m_info_hash, m_listen_port, r.write_token));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+ m_rpc.invoke(messages::announce_peer, r.addr, o);
+ m_fun(r.peers, m_info_hash);
+ }
+ void abort() {}
+
+private:
+ sha1_hash m_info_hash;
+ int m_listen_port;
+ rpc_manager& m_rpc;
+ boost::function<void(std::vector<tcp::endpoint> const&, sha1_hash const&)> m_fun;
+};
+
+
+
+class node_impl : boost::noncopyable
+{
+typedef std::map<node_id, torrent_entry> table_t;
+public:
+ node_impl(boost::function<void(msg const&)> const& f
+ , dht_settings const& settings, boost::optional<node_id> node_id);
+
+ virtual ~node_impl() {}
+
+ void refresh(node_id const& id, boost::function0<void> f);
+ void bootstrap(std::vector<udp::endpoint> const& nodes
+ , boost::function0<void> f);
+ void find_node(node_id const& id, boost::function<
+ void(std::vector<node_entry> const&)> f);
+ void add_router_node(udp::endpoint router);
+
+ void incoming(msg const& m);
+
+ void refresh();
+ void refresh_bucket(int bucket);
+ int bucket_size(int bucket);
+
+ typedef routing_table::iterator iterator;
+
+ iterator begin() const { return m_table.begin(); }
+ iterator end() const { return m_table.end(); }
+
+ typedef table_t::iterator data_iterator;
+
+ node_id const& nid() const { return m_id; }
+ boost::tuple<int, int> size() const{ return m_table.size(); }
+ size_type num_global_nodes() const
+ { return m_table.num_global_nodes(); }
+
+ data_iterator begin_data() { return m_map.begin(); }
+ data_iterator end_data() { return m_map.end(); }
+ int data_size() const { return int(m_map.size()); }
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ void print_state(std::ostream& os) const
+ { m_table.print_state(os); }
+#endif
+
+ void announce(sha1_hash const& info_hash, int listen_port
+ , boost::function<void(std::vector<tcp::endpoint> const&
+ , sha1_hash const&)> f);
+
+ bool verify_token(msg const& m);
+ entry generate_token(msg const& m);
+
+ // the returned time is the delay until connection_timeout()
+ // should be called again the next time
+ time_duration connection_timeout();
+ time_duration refresh_timeout();
+
+ // generates a new secret number used to generate write tokens
+ void new_write_key();
+
+ // pings the given node, and adds it to
+ // the routing table if it respons and if the
+ // bucket is not full.
+ void add_node(udp::endpoint node);
+
+ void replacement_cache(bucket_t& nodes) const
+ { m_table.replacement_cache(nodes); }
+
+protected:
+ // is called when a find data request is received. Should
+ // return false if the data is not stored on this node. If
+ // the data is stored, it should be serialized into 'data'.
+ bool on_find(msg const& m, std::vector<tcp::endpoint>& peers) const;
+
+ // this is called when a store request is received. The data
+ // is store-parameters and the data to be stored.
+ void on_announce(msg const& m, msg& reply);
+
+ dht_settings const& m_settings;
+
+ // the maximum number of peers to send in a get_peers
+ // reply. Ordinary trackers usually limit this to 50.
+ // 50 => 6 * 50 = 250 bytes + packet overhead
+ int m_max_peers_reply;
+
+private:
+ void incoming_request(msg const& h);
+
+ node_id m_id;
+ routing_table m_table;
+ rpc_manager m_rpc;
+ table_t m_map;
+
+ ptime m_last_tracker_tick;
+
+ // secret random numbers used to create write tokens
+ int m_secret[2];
+};
+
+
+} } // namespace libtorrent::dht
+
+#endif // NODE_HPP
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/node_entry.hpp b/src/libtorrent/include/libtorrent/kademlia/node_entry.hpp
new file mode 100644
index 0000000..edc5dff
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/node_entry.hpp
@@ -0,0 +1,63 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef KADEMLIA_NODE_ENTRY_HPP
+#define KADEMLIA_NODE_ENTRY_HPP
+
+#include "libtorrent/kademlia/node_id.hpp"
+#include "libtorrent/socket.hpp"
+
+namespace libtorrent { namespace dht
+{
+
+struct node_entry
+{
+ node_entry(node_id const& id_, asio::ip::udp::endpoint addr_)
+ : id(id_)
+ , addr(addr_)
+ , fail_count(0) {}
+ node_entry(asio::ip::udp::endpoint addr_)
+ : id(0)
+ , addr(addr_)
+ , fail_count(0) {}
+
+ node_id id;
+ udp::endpoint addr;
+ // the number of times this node has failed to
+ // respond in a row
+ int fail_count;
+};
+
+} } // namespace libtorrent::dht
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/node_id.hpp b/src/libtorrent/include/libtorrent/kademlia/node_id.hpp
new file mode 100644
index 0000000..4173808
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/node_id.hpp
@@ -0,0 +1,62 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+#ifndef NODE_ID_HPP
+#define NODE_ID_HPP
+
+#include <algorithm>
+
+#include <boost/cstdint.hpp>
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent { namespace dht
+{
+
+typedef libtorrent::big_number node_id;
+
+// returns the distance between the two nodes
+// using the kademlia XOR-metric
+node_id distance(node_id const& n1, node_id const& n2);
+
+// returns true if: distance(n1, ref) < distance(n2, ref)
+bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref);
+
+// returns n in: 2^n <= distance(n1, n2) < 2^(n+1)
+// usefult for finding out which bucket a node belongs to
+int distance_exp(node_id const& n1, node_id const& n2);
+
+node_id generate_id();
+
+} } // namespace libtorrent::dht
+
+#endif // NODE_ID_HPP
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/observer.hpp b/src/libtorrent/include/libtorrent/kademlia/observer.hpp
new file mode 100644
index 0000000..073f453
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/observer.hpp
@@ -0,0 +1,102 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef OBSERVER_HPP
+#define OBSERVER_HPP
+
+#include <boost/pool/pool.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+namespace libtorrent {
+namespace dht {
+
+struct observer;
+struct msg;
+
+// defined in rpc_manager.cpp
+TORRENT_EXPORT void intrusive_ptr_add_ref(observer const*);
+TORRENT_EXPORT void intrusive_ptr_release(observer const*);
+
+struct observer : boost::noncopyable
+{
+ friend TORRENT_EXPORT void intrusive_ptr_add_ref(observer const*);
+ friend TORRENT_EXPORT void intrusive_ptr_release(observer const*);
+
+ observer(boost::pool<>& p)
+ : sent(time_now())
+ , pool_allocator(p)
+ , m_refs(0)
+ {
+#ifndef NDEBUG
+ m_in_constructor = true;
+#endif
+ }
+
+ virtual ~observer()
+ {
+ TORRENT_ASSERT(!m_in_constructor);
+ }
+
+ // these two callbacks lets the observer add
+ // information to the message before it's sent
+ virtual void send(msg& m) = 0;
+
+ // this is called when a reply is received
+ virtual void reply(msg const& m) = 0;
+
+ // this is called when no reply has been received within
+ // some timeout
+ virtual void timeout() = 0;
+
+ // if this is called the destructor should
+ // not invoke any new messages, and should
+ // only clean up. It means the rpc-manager
+ // is being destructed
+ virtual void abort() = 0;
+
+ udp::endpoint target_addr;
+ ptime sent;
+#ifndef NDEBUG
+ bool m_in_constructor;
+#endif
+private:
+ boost::pool<>& pool_allocator;
+ // reference counter for intrusive_ptr
+ mutable boost::detail::atomic_count m_refs;
+};
+
+typedef boost::intrusive_ptr<observer> observer_ptr;
+
+} }
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/kademlia/packet_iterator.hpp b/src/libtorrent/include/libtorrent/kademlia/packet_iterator.hpp
new file mode 100644
index 0000000..e906a90
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/packet_iterator.hpp
@@ -0,0 +1,95 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef PACKET_ITERATOR_HPP
+#define PACKET_ITERATOR_HPP
+
+#include <boost/iterator/iterator_facade.hpp>
+#include <vector>
+#include <stdexcept>
+
+namespace libtorrent { namespace dht
+{
+
+class packet_iterator: public boost::iterator_facade<
+ packet_iterator, const char, boost::forward_traversal_tag>
+{
+public:
+ typedef std::vector<char>::const_iterator base_iterator;
+
+ packet_iterator() {}
+
+ packet_iterator(std::vector<char>::const_iterator start
+ , std::vector<char>::const_iterator end
+ , std::string const& error_msg = "")
+ : m_base(start)
+ , m_end(end)
+ , m_msg(error_msg)
+ {}
+
+ base_iterator base() const
+ { return m_base; }
+
+ base_iterator end() const
+ { return m_end; }
+
+ int left() const { return int(m_end - m_base); }
+
+private:
+ friend class boost::iterator_core_access;
+
+ bool equal(packet_iterator const& other) const
+ { return m_base == other.m_base; }
+
+ void advance(int n)
+ {
+ m_base += n;
+ }
+
+ void increment()
+ { ++m_base; }
+
+ char const& dereference() const
+ {
+ if (m_base == m_end) throw std::runtime_error(m_msg);
+ return *m_base;
+ }
+
+ base_iterator m_base;
+ base_iterator m_end;
+ std::string m_msg;
+};
+
+} } // namespace libtorrent::dht
+
+#endif // PACKET_ITERATOR_HPP
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/refresh.hpp b/src/libtorrent/include/libtorrent/kademlia/refresh.hpp
new file mode 100644
index 0000000..953c4d8
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/refresh.hpp
@@ -0,0 +1,214 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef REFRESH_050324_HPP
+#define REFRESH_050324_HPP
+
+#include <vector>
+
+#include <libtorrent/kademlia/traversal_algorithm.hpp>
+#include <libtorrent/kademlia/node_id.hpp>
+#include <libtorrent/kademlia/observer.hpp>
+#include <libtorrent/kademlia/msg.hpp>
+
+#include <boost/function.hpp>
+
+namespace libtorrent { namespace dht
+{
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DECLARE_LOG(refresh);
+#endif
+
+class routing_table;
+class rpc_manager;
+
+class refresh : public traversal_algorithm
+{
+public:
+ typedef boost::function<void()> done_callback;
+
+ template<class InIt>
+ static void initiate(
+ node_id target
+ , int branch_factor
+ , int max_active_pings
+ , int max_results
+ , routing_table& table
+ , InIt first
+ , InIt last
+ , rpc_manager& rpc
+ , done_callback const& callback
+ );
+
+ void ping_reply(node_id id);
+ void ping_timeout(node_id id, bool prevent_request = false);
+
+private:
+ template<class InIt>
+ refresh(
+ node_id target
+ , int branch_factor
+ , int max_active_pings
+ , int max_results
+ , routing_table& table
+ , InIt first
+ , InIt last
+ , rpc_manager& rpc
+ , done_callback const& callback
+ );
+
+ void done();
+ void invoke(node_id const& id, udp::endpoint addr);
+
+ void invoke_pings_or_finish(bool prevent_request = false);
+
+ int m_max_active_pings;
+ int m_active_pings;
+
+ done_callback m_done_callback;
+
+ std::vector<result>::iterator m_leftover_nodes_iterator;
+};
+
+class refresh_observer : public observer
+{
+public:
+ refresh_observer(
+ boost::intrusive_ptr<refresh> const& algorithm
+ , node_id self
+ , node_id target)
+ : observer(algorithm->allocator())
+ , m_target(target)
+ , m_self(self)
+ , m_algorithm(algorithm)
+ {}
+ ~refresh_observer();
+
+ void send(msg& m)
+ {
+ m.info_hash = m_target;
+ }
+
+ void timeout();
+ void reply(msg const& m);
+ void abort() { m_algorithm = 0; }
+
+
+private:
+ node_id const m_target;
+ node_id const m_self;
+ boost::intrusive_ptr<refresh> m_algorithm;
+};
+
+class ping_observer : public observer
+{
+public:
+ ping_observer(
+ boost::intrusive_ptr<refresh> const& algorithm
+ , node_id self)
+ : observer(algorithm->allocator())
+ , m_self(self)
+ , m_algorithm(algorithm)
+ {}
+ ~ping_observer();
+
+ void send(msg& p) {}
+ void timeout();
+ void reply(msg const& m);
+ void abort() { m_algorithm = 0; }
+
+
+private:
+ node_id const m_self;
+ boost::intrusive_ptr<refresh> m_algorithm;
+};
+
+template<class InIt>
+inline refresh::refresh(
+ node_id target
+ , int branch_factor
+ , int max_active_pings
+ , int max_results
+ , routing_table& table
+ , InIt first
+ , InIt last
+ , rpc_manager& rpc
+ , done_callback const& callback
+)
+ : traversal_algorithm(
+ target
+ , branch_factor
+ , max_results
+ , table
+ , rpc
+ , first
+ , last
+ )
+ , m_max_active_pings(max_active_pings)
+ , m_active_pings(0)
+ , m_done_callback(callback)
+{
+ boost::intrusive_ptr<refresh> self(this);
+ add_requests();
+}
+
+template<class InIt>
+inline void refresh::initiate(
+ node_id target
+ , int branch_factor
+ , int max_active_pings
+ , int max_results
+ , routing_table& table
+ , InIt first
+ , InIt last
+ , rpc_manager& rpc
+ , done_callback const& callback
+)
+{
+ new refresh(
+ target
+ , branch_factor
+ , max_active_pings
+ , max_results
+ , table
+ , first
+ , last
+ , rpc
+ , callback
+ );
+}
+
+} } // namespace libtorrent::dht
+
+#endif // REFRESH_050324_HPP
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/routing_table.hpp b/src/libtorrent/include/libtorrent/kademlia/routing_table.hpp
new file mode 100644
index 0000000..acb4c18
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/routing_table.hpp
@@ -0,0 +1,249 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef ROUTING_TABLE_HPP
+#define ROUTING_TABLE_HPP
+
+#include <vector>
+#include <deque>
+#include <boost/cstdint.hpp>
+
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator/iterator_categories.hpp>
+#include <boost/utility.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/array.hpp>
+#include <set>
+
+#include <libtorrent/kademlia/logging.hpp>
+
+#include <libtorrent/kademlia/node_id.hpp>
+#include <libtorrent/kademlia/node_entry.hpp>
+#include <libtorrent/session_settings.hpp>
+#include <libtorrent/size_type.hpp>
+#include <libtorrent/assert.hpp>
+
+namespace libtorrent { namespace dht
+{
+
+using asio::ip::udp;
+
+//TORRENT_DECLARE_LOG(table);
+
+typedef std::vector<node_entry> bucket_t;
+
+// differences in the implementation from the description in
+// the paper:
+//
+// * The routing table tree is not allocated dynamically, there
+// are always 160 buckets.
+// * Nodes are not marked as being stale, they keep a counter
+// that tells how many times in a row they have failed. When
+// a new node is to be inserted, the node that has failed
+// the most times is replaced. If none of the nodes in the
+// bucket has failed, then it is put in the replacement
+// cache (just like in the paper).
+
+class routing_table;
+
+namespace aux
+{
+
+ // Iterates over a flattened routing_table structure.
+ class routing_table_iterator
+ : public boost::iterator_facade<
+ routing_table_iterator
+ , node_entry const
+ , boost::forward_traversal_tag
+ >
+ {
+ public:
+ routing_table_iterator()
+ {
+ }
+
+ private:
+ friend class libtorrent::dht::routing_table;
+ friend class boost::iterator_core_access;
+
+ typedef boost::array<std::pair<bucket_t, bucket_t>, 160>::const_iterator
+ bucket_iterator_t;
+
+ routing_table_iterator(
+ bucket_iterator_t begin
+ , bucket_iterator_t end)
+ : m_bucket_iterator(begin)
+ , m_bucket_end(end)
+ , m_iterator(begin != end ? begin->first.begin() : bucket_t::const_iterator())
+ {
+ if (m_bucket_iterator == m_bucket_end) return;
+ while (m_iterator == m_bucket_iterator->first.end())
+ {
+ if (++m_bucket_iterator == m_bucket_end)
+ break;
+ m_iterator = m_bucket_iterator->first.begin();
+ }
+ }
+
+ bool equal(routing_table_iterator const& other) const
+ {
+ return m_bucket_iterator == other.m_bucket_iterator
+ && (m_bucket_iterator == m_bucket_end
+ || m_iterator == other.m_iterator);
+ }
+
+ void increment()
+ {
+ TORRENT_ASSERT(m_bucket_iterator != m_bucket_end);
+ ++m_iterator;
+ while (m_iterator == m_bucket_iterator->first.end())
+ {
+ if (++m_bucket_iterator == m_bucket_end)
+ break;
+ m_iterator = m_bucket_iterator->first.begin();
+ }
+ }
+
+ node_entry const& dereference() const
+ {
+ TORRENT_ASSERT(m_bucket_iterator != m_bucket_end);
+ return *m_iterator;
+ }
+
+ bucket_iterator_t m_bucket_iterator;
+ bucket_iterator_t m_bucket_end;
+ bucket_t::const_iterator m_iterator;
+ };
+
+} // namespace aux
+
+class routing_table
+{
+public:
+ typedef aux::routing_table_iterator iterator;
+ typedef iterator const_iterator;
+
+ routing_table(node_id const& id, int bucket_size
+ , dht_settings const& settings);
+
+ void node_failed(node_id const& id);
+
+ // adds an endpoint that will never be added to
+ // the routing table
+ void add_router_node(udp::endpoint router);
+
+ // iterates over the router nodes added
+ typedef std::set<udp::endpoint>::const_iterator router_iterator;
+ router_iterator router_begin() const { return m_router_nodes.begin(); }
+ router_iterator router_end() const { return m_router_nodes.end(); }
+
+ // this function is called every time the node sees
+ // a sign of a node being alive. This node will either
+ // be inserted in the k-buckets or be moved to the top
+ // of its bucket.
+ bool node_seen(node_id const& id, udp::endpoint addr);
+
+ // returns time when the given bucket needs another refresh.
+ // if the given bucket is empty but there are nodes
+ // in a bucket closer to us, or if the bucket is non-empty and
+ // the time from the last activity is more than 15 minutes
+ ptime next_refresh(int bucket);
+
+ // fills the vector with the count nodes from our buckets that
+ // are nearest to the given id.
+ void find_node(node_id const& id, std::vector<node_entry>& l
+ , bool include_self, int count = 0);
+
+ // returns true if the given node would be placed in a bucket
+ // that is not full. If the node already exists in the table
+ // this function returns false
+ bool need_node(node_id const& id);
+
+ // this will set the given bucket's latest activity
+ // to the current time
+ void touch_bucket(int bucket);
+
+ int bucket_size(int bucket)
+ {
+ TORRENT_ASSERT(bucket >= 0 && bucket < 160);
+ return (int)m_buckets[bucket].first.size();
+ }
+ int bucket_size() const { return m_bucket_size; }
+
+ iterator begin() const;
+ iterator end() const;
+
+ boost::tuple<int, int> size() const;
+ size_type num_global_nodes() const;
+
+ // returns true if there are no working nodes
+ // in the routing table
+ bool need_bootstrap() const;
+ int num_active_buckets() const
+ { return 160 - m_lowest_active_bucket + 1; }
+
+ void replacement_cache(bucket_t& nodes) const;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ // used for debug and monitoring purposes. This will print out
+ // the state of the routing table to the given stream
+ void print_state(std::ostream& os) const;
+#endif
+
+private:
+
+ // constant called k in paper
+ int m_bucket_size;
+
+ dht_settings const& m_settings;
+
+ // 160 (k-bucket, replacement cache) pairs
+ typedef boost::array<std::pair<bucket_t, bucket_t>, 160> table_t;
+ table_t m_buckets;
+ // timestamps of the last activity in each bucket
+ typedef boost::array<ptime, 160> table_activity_t;
+ table_activity_t m_bucket_activity;
+ node_id m_id; // our own node id
+
+ // this is a set of all the endpoints that have
+ // been identified as router nodes. They will
+ // be used in searches, but they will never
+ // be added to the routing table.
+ std::set<udp::endpoint> m_router_nodes;
+
+ // this is the lowest bucket index with nodes in it
+ int m_lowest_active_bucket;
+};
+
+} } // namespace libtorrent::dht
+
+#endif // ROUTING_TABLE_HPP
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp b/src/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp
new file mode 100644
index 0000000..a7c47f2
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp
@@ -0,0 +1,140 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef RPC_MANAGER_HPP
+#define RPC_MANAGER_HPP
+
+#include <vector>
+#include <map>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/array.hpp>
+#include <boost/pool/pool.hpp>
+
+#include <libtorrent/socket.hpp>
+#include <libtorrent/entry.hpp>
+#include <libtorrent/kademlia/packet_iterator.hpp>
+#include <libtorrent/kademlia/node_id.hpp>
+#include <libtorrent/kademlia/logging.hpp>
+#include <libtorrent/kademlia/node_entry.hpp>
+#include <libtorrent/kademlia/observer.hpp>
+
+#include "libtorrent/time.hpp"
+
+namespace libtorrent { namespace dht
+{
+
+struct observer;
+
+using asio::ip::udp;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DECLARE_LOG(rpc);
+#endif
+
+struct null_observer : public observer
+{
+ null_observer(boost::pool<>& allocator): observer(allocator) {}
+ virtual void reply(msg const&) {}
+ virtual void timeout() {}
+ virtual void send(msg&) {}
+ void abort() {}
+};
+
+class routing_table;
+
+class rpc_manager
+{
+public:
+ typedef boost::function1<void, msg const&> fun;
+ typedef boost::function1<void, msg const&> send_fun;
+
+ rpc_manager(fun const& incoming_fun, node_id const& our_id
+ , routing_table& table, send_fun const& sf);
+ ~rpc_manager();
+
+ // returns true if the node needs a refresh
+ bool incoming(msg const&);
+ time_duration tick();
+
+ void invoke(int message_id, udp::endpoint target
+ , observer_ptr o);
+
+ void reply(msg& m);
+ void reply_with_ping(msg& m);
+
+#ifndef NDEBUG
+ void check_invariant() const;
+#endif
+
+ boost::pool<>& allocator() const
+ { return m_pool_allocator; }
+
+private:
+
+ enum { max_transactions = 2048 };
+
+ unsigned int new_transaction_id(observer_ptr o);
+ void update_oldest_transaction_id();
+
+ boost::uint32_t calc_connection_id(udp::endpoint addr);
+
+ mutable boost::pool<> m_pool_allocator;
+
+ typedef boost::array<observer_ptr, max_transactions>
+ transactions_t;
+ transactions_t m_transactions;
+ std::vector<observer_ptr > m_aborted_transactions;
+
+ // this is the next transaction id to be used
+ int m_next_transaction_id;
+ // this is the oldest transaction id still
+ // (possibly) in use. This is the transaction
+ // that will time out first, the one we are
+ // waiting for to time out
+ int m_oldest_transaction_id;
+
+ fun m_incoming;
+ send_fun m_send;
+ node_id m_our_id;
+ routing_table& m_table;
+ ptime m_timer;
+ node_id m_random_number;
+ bool m_destructing;
+};
+
+} } // namespace libtorrent::dht
+
+#endif
+
+
diff --git a/src/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp b/src/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp
new file mode 100644
index 0000000..74d79ed
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp
@@ -0,0 +1,161 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TRAVERSAL_ALGORITHM_050324_HPP
+#define TRAVERSAL_ALGORITHM_050324_HPP
+
+#include <vector>
+#include <set>
+
+#include <libtorrent/kademlia/node_id.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/logging.hpp>
+
+#include <boost/noncopyable.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/pool/pool.hpp>
+
+namespace libtorrent { namespace dht
+{
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DECLARE_LOG(traversal);
+#endif
+
+class rpc_manager;
+
+// this class may not be instantiated as a stack object
+class traversal_algorithm : boost::noncopyable
+{
+public:
+ void traverse(node_id const& id, udp::endpoint addr);
+ void finished(node_id const& id);
+ void failed(node_id const& id, bool prevent_request = false);
+ virtual ~traversal_algorithm() {}
+ boost::pool<>& allocator() const;
+
+protected:
+ template<class InIt>
+ traversal_algorithm(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , InIt start
+ , InIt end
+ );
+
+ void add_requests();
+ void add_entry(node_id const& id, udp::endpoint addr, unsigned char flags);
+
+ virtual void done() = 0;
+ virtual void invoke(node_id const& id, udp::endpoint addr) = 0;
+
+ struct result
+ {
+ result(node_id const& id, udp::endpoint addr, unsigned char f = 0)
+ : id(id), addr(addr), flags(f) {}
+
+ node_id id;
+ udp::endpoint addr;
+ enum { queried = 1, initial = 2, no_id = 4 };
+ unsigned char flags;
+ };
+
+ std::vector<result>::iterator last_iterator();
+
+ friend void intrusive_ptr_add_ref(traversal_algorithm* p)
+ {
+ p->m_ref_count++;
+ }
+
+ friend void intrusive_ptr_release(traversal_algorithm* p)
+ {
+ if (--p->m_ref_count == 0)
+ delete p;
+ }
+
+ int m_ref_count;
+
+ node_id m_target;
+ int m_branch_factor;
+ int m_max_results;
+ std::vector<result> m_results;
+ std::set<udp::endpoint> m_failed;
+ routing_table& m_table;
+ rpc_manager& m_rpc;
+ int m_invoke_count;
+};
+
+template<class InIt>
+traversal_algorithm::traversal_algorithm(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , InIt start // <- nodes to initiate traversal with
+ , InIt end
+)
+ : m_ref_count(0)
+ , m_target(target)
+ , m_branch_factor(branch_factor)
+ , m_max_results(max_results)
+ , m_table(table)
+ , m_rpc(rpc)
+ , m_invoke_count(0)
+{
+ using boost::bind;
+
+ for (InIt i = start; i != end; ++i)
+ {
+ add_entry(i->id, i->addr, result::initial);
+ }
+
+ // in case the routing table is empty, use the
+ // router nodes in the table
+ if (start == end)
+ {
+ for (routing_table::router_iterator i = table.router_begin()
+ , end(table.router_end()); i != end; ++i)
+ {
+ add_entry(node_id(0), *i, result::initial);
+ }
+ }
+
+}
+
+} } // namespace libtorrent::dht
+
+#endif // TRAVERSAL_ALGORITHM_050324_HPP
+
diff --git a/src/libtorrent/include/libtorrent/lsd.hpp b/src/libtorrent/include/libtorrent/lsd.hpp
new file mode 100644
index 0000000..6fb6b7c
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/lsd.hpp
@@ -0,0 +1,98 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_LSD_HPP
+#define TORRENT_LSD_HPP
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/broadcast_socket.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
+
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+#include <fstream>
+#endif
+
+namespace libtorrent
+{
+
+typedef boost::function<void(tcp::endpoint, sha1_hash)> peer_callback_t;
+
+class lsd : public intrusive_ptr_base<lsd>
+{
+public:
+ lsd(io_service& ios, address const& listen_interface
+ , peer_callback_t const& cb);
+ ~lsd();
+
+// void rebind(address const& listen_interface);
+
+ void announce(sha1_hash const& ih, int listen_port);
+ void close();
+
+private:
+
+ void resend_announce(asio::error_code const& e, std::string msg);
+ void on_announce(udp::endpoint const& from, char* buffer
+ , std::size_t bytes_transferred);
+// void setup_receive();
+
+ peer_callback_t m_callback;
+
+ // current retry count
+ int m_retry_count;
+
+ // the udp socket used to send and receive
+ // multicast messages on
+ broadcast_socket m_socket;
+
+ // used to resend udp packets in case
+ // they time out
+ deadline_timer m_broadcast_timer;
+
+ bool m_disabled;
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ std::ofstream m_log;
+#endif
+};
+
+}
+
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/natpmp.hpp b/src/libtorrent/include/libtorrent/natpmp.hpp
new file mode 100644
index 0000000..3b99239
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/natpmp.hpp
@@ -0,0 +1,151 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_NATPMP_HPP
+#define TORRENT_NATPMP_HPP
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
+
+#include <boost/function.hpp>
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+#include <fstream>
+#endif
+
+namespace libtorrent
+{
+
+// int: external tcp port
+// int: external udp port
+// std::string: error message
+typedef boost::function<void(int, int, std::string const&)> portmap_callback_t;
+
+class natpmp : public intrusive_ptr_base<natpmp>
+{
+public:
+ natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb);
+
+ void rebind(address const& listen_interface);
+
+ // maps the ports, if a port is set to 0
+ // it will not be mapped
+ void set_mappings(int tcp, int udp);
+
+ void close();
+
+private:
+
+ void update_mapping(int i, int port);
+ void send_map_request(int i);
+ void resend_request(int i, asio::error_code const& e);
+ void on_reply(asio::error_code const& e
+ , std::size_t bytes_transferred);
+ void try_next_mapping(int i);
+ void update_expiration_timer();
+ void refresh_mapping(int i);
+ void mapping_expired(asio::error_code const& e, int i);
+
+ struct mapping
+ {
+ mapping()
+ : need_update(false)
+ , local_port(0)
+ , external_port(0)
+ , protocol(1)
+ {}
+
+ // indicates that the mapping has changed
+ // and needs an update
+ bool need_update;
+
+ // the time the port mapping will expire
+ ptime expires;
+
+ // the local port for this mapping. If this is set
+ // to 0, the mapping is not in use
+ int local_port;
+
+ // the external (on the NAT router) port
+ // for the mapping. This is the port we
+ // should announce to others
+ int external_port;
+
+ // 1 = udp, 2 = tcp
+ int protocol;
+ };
+
+ portmap_callback_t m_callback;
+
+ // 0 is tcp and 1 is udp
+ mapping m_mappings[2];
+
+ // the endpoint to the nat router
+ udp::endpoint m_nat_endpoint;
+
+ // this is the mapping that is currently
+ // being updated. It is -1 in case no
+ // mapping is being updated at the moment
+ int m_currently_mapping;
+
+ // current retry count
+ int m_retry_count;
+
+ // used to receive responses in
+ char m_response_buffer[16];
+
+ // the endpoint we received the message from
+ udp::endpoint m_remote;
+
+ // the udp socket used to communicate
+ // with the NAT router
+ datagram_socket m_socket;
+
+ // used to resend udp packets in case
+ // they time out
+ deadline_timer m_send_timer;
+
+ // timer used to refresh mappings
+ deadline_timer m_refresh_timer;
+
+ bool m_disabled;
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ std::ofstream m_log;
+#endif
+};
+
+}
+
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/pch.hpp b/src/libtorrent/include/libtorrent/pch.hpp
new file mode 100644
index 0000000..7359998
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/pch.hpp
@@ -0,0 +1,96 @@
+#ifdef BOOST_BUILD_PCH_ENABLED
+
+#include <algorithm>
+#include <asio/ip/host_name.hpp>
+#include <assert.h>
+#include <bitset>
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/function.hpp>
+#include <boost/integer_traits.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/iterator/iterator_categories.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/iterator_adaptors.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/limits.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/next_prior.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/optional.hpp>
+#include <boost/preprocessor/repetition/enum.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
+#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
+#include <boost/ref.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/utility.hpp>
+#include <boost/version.hpp>
+#include <boost/weak_ptr.hpp>
+#include <cassert>
+#include <cctype>
+#include <cmath>
+#include <cstdlib>
+#include <ctime>
+#include <cwchar>
+#include <deque>
+#include <fstream>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <limits>
+#include <list>
+#include <map>
+#include <memory>
+#include <numeric>
+#include <queue>
+#include <set>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <typeinfo>
+#include <utility>
+#include <vector>
+#include <zlib.h>
+
+#ifdef __OBJC__
+#define Protocol Protocol_
+#endif
+
+#include <asio/ip/tcp.hpp>
+#include <asio/ip/udp.hpp>
+#include <asio/io_service.hpp>
+#include <asio/deadline_timer.hpp>
+#include <asio/write.hpp>
+#include <asio/strand.hpp>
+
+#ifdef __OBJC__
+#undef Protocol
+#endif
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/pe_crypto.hpp b/src/libtorrent/include/libtorrent/pe_crypto.hpp
new file mode 100644
index 0000000..5db77f6
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/pe_crypto.hpp
@@ -0,0 +1,124 @@
+/*
+
+Copyright (c) 2007, Un Shyam
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+
+#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED
+#define TORRENT_PE_CRYPTO_HPP_INCLUDED
+
+#include <openssl/dh.h>
+#include <openssl/engine.h>
+#include <openssl/rc4.h>
+
+#include "libtorrent/peer_id.hpp" // For sha1_hash
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ class DH_key_exchange
+ {
+ public:
+ DH_key_exchange ();
+ ~DH_key_exchange ();
+
+ // Get local public key, always 96 bytes
+ char const* get_local_key (void) const;
+
+ // read remote_pubkey, generate and store shared secret in
+ // m_dh_secret
+ void compute_secret (const char* remote_pubkey);
+
+ const char* get_secret (void) const;
+
+ private:
+ int get_local_key_size () const
+ {
+ TORRENT_ASSERT(m_DH);
+ return BN_num_bytes (m_DH->pub_key);
+ }
+
+ DH* m_DH;
+ static const unsigned char m_dh_prime[96];
+ static const unsigned char m_dh_generator[1];
+
+ char m_dh_local_key[96];
+ char m_dh_secret[96];
+ };
+
+ class RC4_handler // Non copyable
+ {
+ public:
+ // Input longkeys must be 20 bytes
+ RC4_handler (const sha1_hash& rc4_local_longkey,
+ const sha1_hash& rc4_remote_longkey)
+
+ {
+ RC4_set_key (&m_local_key, 20,
+ reinterpret_cast<unsigned char const*>(rc4_local_longkey.begin()));
+ RC4_set_key (&m_remote_key, 20,
+ reinterpret_cast<unsigned char const*>(rc4_remote_longkey.begin()));
+
+ // Discard first 1024 bytes
+ char buf[1024];
+ encrypt (buf, 1024);
+ decrypt (buf, 1024);
+ };
+
+ ~RC4_handler () {};
+
+ void encrypt (char* pos, int len)
+ {
+ TORRENT_ASSERT(len >= 0);
+ TORRENT_ASSERT(pos);
+
+ RC4 (&m_local_key, len, reinterpret_cast<unsigned char const*>(pos),
+ reinterpret_cast<unsigned char*>(pos));
+ }
+
+ void decrypt (char* pos, int len)
+ {
+ TORRENT_ASSERT(len >= 0);
+ TORRENT_ASSERT(pos);
+
+ RC4 (&m_remote_key, len, reinterpret_cast<unsigned char const*>(pos),
+ reinterpret_cast<unsigned char*>(pos));
+ }
+
+ private:
+ RC4_KEY m_local_key; // Key to encrypt outgoing data
+ RC4_KEY m_remote_key; // Key to decrypt incoming data
+ };
+
+} // namespace libtorrent
+
+#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED
+#endif // TORRENT_DISABLE_ENCRYPTION
diff --git a/src/libtorrent/include/libtorrent/peer.hpp b/src/libtorrent/include/libtorrent/peer.hpp
new file mode 100644
index 0000000..c404a61
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/peer.hpp
@@ -0,0 +1,63 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_PEER_HPP_INCLUDED
+#define TORRENT_PEER_HPP_INCLUDED
+
+#include <string>
+
+#include "libtorrent/peer_id.hpp"
+
+namespace libtorrent
+{
+
+ struct TORRENT_EXPORT peer_entry
+ {
+ std::string ip;
+ int port;
+ peer_id pid;
+
+ bool operator==(const peer_entry& p) const
+ {
+ return pid == p.pid;
+ }
+
+ bool operator<(const peer_entry& p) const
+ {
+ return pid < p.pid;
+ }
+ };
+
+}
+
+#endif // TORRENT_PEER_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/peer_connection.hpp b/src/libtorrent/include/libtorrent/peer_connection.hpp
new file mode 100644
index 0000000..97d76a3
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/peer_connection.hpp
@@ -0,0 +1,752 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_PEER_CONNECTION_HPP_INCLUDED
+#define TORRENT_PEER_CONNECTION_HPP_INCLUDED
+
+#include <ctime>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <string>
+
+#include "libtorrent/debug.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/smart_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/array.hpp>
+#include <boost/optional.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/pool/pool.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/buffer.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/storage.hpp"
+#include "libtorrent/stat.hpp"
+#include "libtorrent/alert.hpp"
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/piece_block_progress.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/bandwidth_limit.hpp"
+#include "libtorrent/policy.hpp"
+#include "libtorrent/socket_type.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
+#include "libtorrent/assert.hpp"
+#include "libtorrent/chained_buffer.hpp"
+
+namespace libtorrent
+{
+ class torrent;
+ struct peer_plugin;
+
+ namespace detail
+ {
+ struct session_impl;
+ }
+
+ struct TORRENT_EXPORT protocol_error: std::runtime_error
+ {
+ protocol_error(const std::string& msg): std::runtime_error(msg) {};
+ };
+
+ class TORRENT_EXPORT peer_connection
+ : public intrusive_ptr_base<peer_connection>
+ , public boost::noncopyable
+ {
+ friend class invariant_access;
+ public:
+
+ enum channels
+ {
+ upload_channel,
+ download_channel,
+ num_channels
+ };
+
+ // this is the constructor where the we are the active part.
+ // The peer_conenction should handshake and verify that the
+ // other end has the correct id
+ peer_connection(
+ aux::session_impl& ses
+ , boost::weak_ptr<torrent> t
+ , boost::shared_ptr<socket_type> s
+ , tcp::endpoint const& remote
+ , policy::peer* peerinfo);
+
+ // with this constructor we have been contacted and we still don't
+ // know which torrent the connection belongs to
+ peer_connection(
+ aux::session_impl& ses
+ , boost::shared_ptr<socket_type> s
+ , policy::peer* peerinfo);
+
+ virtual ~peer_connection();
+
+ void set_peer_info(policy::peer* pi)
+ { m_peer_info = pi; }
+
+ policy::peer* peer_info_struct() const
+ { return m_peer_info; }
+
+ enum peer_speed_t { slow, medium, fast };
+ peer_speed_t peer_speed();
+
+ void send_allowed_set();
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void add_extension(boost::shared_ptr<peer_plugin>);
+#endif
+
+ // this function is called once the torrent associated
+ // with this peer connection has retrieved the meta-
+ // data. If the torrent was spawned with metadata
+ // this is called from the constructor.
+ void init();
+
+ // this is called when the metadata is retrieved
+ // and the files has been checked
+ virtual void on_metadata() {}
+
+ void set_upload_limit(int limit);
+ void set_download_limit(int limit);
+
+ int upload_limit() const { return m_upload_limit; }
+ int download_limit() const { return m_download_limit; }
+
+ int prefer_whole_pieces() const
+ {
+ if (on_parole()) return 1;
+ return m_prefer_whole_pieces;
+ }
+
+ bool on_parole() const
+ { return peer_info_struct() && peer_info_struct()->on_parole; }
+
+ void prefer_whole_pieces(int num)
+ { m_prefer_whole_pieces = num; }
+
+ bool request_large_blocks() const
+ { return m_request_large_blocks; }
+
+ void request_large_blocks(bool b)
+ { m_request_large_blocks = b; }
+
+ void set_priority(int p)
+ { m_priority = p; }
+
+ void fast_reconnect(bool r);
+ bool fast_reconnect() const { return m_fast_reconnect; }
+
+ // this adds an announcement in the announcement queue
+ // it will let the peer know that we have the given piece
+ void announce_piece(int index);
+
+ // tells if this connection has data it want to send
+ // and has enough upload bandwidth quota left to send it.
+ bool can_write() const;
+ bool can_read() const;
+
+ bool is_seed() const;
+
+ bool has_timed_out() const;
+
+ // will send a keep-alive message to the peer
+ void keep_alive();
+
+ peer_id const& pid() const { return m_peer_id; }
+ void set_pid(const peer_id& pid) { m_peer_id = pid; }
+ bool has_piece(int i) const;
+
+ std::deque<piece_block> const& download_queue() const;
+ std::deque<piece_block> const& request_queue() const;
+ std::deque<peer_request> const& upload_queue() const;
+
+ bool is_interesting() const { return m_interesting; }
+ bool is_choked() const { return m_choked; }
+
+ bool is_peer_interested() const { return m_peer_interested; }
+ bool has_peer_choked() const { return m_peer_choked; }
+
+ void update_interest();
+
+ virtual void get_peer_info(peer_info& p) const;
+
+ // returns the torrent this connection is a part of
+ // may be zero if the connection is an incoming connection
+ // and it hasn't received enough information to determine
+ // which torrent it should be associated with
+ boost::weak_ptr<torrent> associated_torrent() const
+ { return m_torrent; }
+
+ const stat& statistics() const { return m_statistics; }
+ void add_stat(size_type downloaded, size_type uploaded);
+
+ // is called once every second by the main loop
+ void second_tick(float tick_interval);
+
+ boost::shared_ptr<socket_type> get_socket() const { return m_socket; }
+ tcp::endpoint const& remote() const { return m_remote; }
+
+ std::vector<bool> const& get_bitfield() const;
+ std::vector<int> const& allowed_fast();
+ std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; }
+
+ void timed_out();
+ // this will cause this peer_connection to be disconnected.
+ void disconnect();
+ bool is_disconnecting() const { return m_disconnecting; }
+
+ // this is called when the connection attempt has succeeded
+ // and the peer_connection is supposed to set m_connecting
+ // to false, and stop monitor writability
+ void on_connection_complete(asio::error_code const& e);
+
+ // returns true if this connection is still waiting to
+ // finish the connection attempt
+ bool is_connecting() const { return m_connecting; }
+
+ // returns true if the socket of this peer hasn't been
+ // attempted to connect yet (i.e. it's queued for
+ // connection attempt).
+ bool is_queued() const { return m_queued; }
+
+ // called when it's time for this peer_conncetion to actually
+ // initiate the tcp connection. This may be postponed until
+ // the library isn't using up the limitation of half-open
+ // tcp connections.
+ void connect(int ticket);
+
+ // This is called for every peer right after the upload
+ // bandwidth has been distributed among them
+ // It will reset the used bandwidth to 0.
+ void reset_upload_quota();
+
+ // free upload.
+ size_type total_free_upload() const;
+ void add_free_upload(size_type free_upload);
+
+ // trust management.
+ void received_valid_data(int index);
+ void received_invalid_data(int index);
+
+ size_type share_diff() const;
+
+ // a connection is local if it was initiated by us.
+ // if it was an incoming connection, it is remote
+ bool is_local() const { return m_active; }
+
+ bool on_local_network() const;
+ bool ignore_bandwidth_limits() const
+ { return m_ignore_bandwidth_limits; }
+
+ void set_failed() { m_failed = true; }
+ bool failed() const { return m_failed; }
+
+ int desired_queue_size() const { return m_desired_queue_size; }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ boost::shared_ptr<logger> m_logger;
+#endif
+
+ // the message handlers are called
+ // each time a recv() returns some new
+ // data, the last time it will be called
+ // is when the entire packet has been
+ // received, then it will no longer
+ // be called. i.e. most handlers need
+ // to check how much of the packet they
+ // have received before any processing
+ void incoming_keepalive();
+ void incoming_choke();
+ void incoming_unchoke();
+ void incoming_interested();
+ void incoming_not_interested();
+ void incoming_have(int piece_index);
+ void incoming_bitfield(std::vector<bool> const& bitfield);
+ void incoming_request(peer_request const& r);
+ void incoming_piece(peer_request const& p, char const* data);
+ void incoming_piece_fragment();
+ void incoming_cancel(peer_request const& r);
+
+ void incoming_dht_port(int listen_port);
+
+ void incoming_reject_request(peer_request const& r);
+ void incoming_have_all();
+ void incoming_have_none();
+ void incoming_allowed_fast(int index);
+ void incoming_suggest(int index);
+
+ // the following functions appends messages
+ // to the send buffer
+ void send_choke();
+ void send_unchoke();
+ void send_interested();
+ void send_not_interested();
+
+ // adds a block to the request queue
+ void add_request(piece_block const& b);
+ // removes a block from the request queue or download queue
+ // sends a cancel message if appropriate
+ // refills the request queue, and possibly ignoring pieces requested
+ // by peers in the ignore list (to avoid recursion)
+ void cancel_request(piece_block const& b);
+ void send_block_requests();
+
+ int max_assignable_bandwidth(int channel) const
+ { return m_bandwidth_limit[channel].max_assignable(); }
+
+ int bandwidth_throttle(int channel) const
+ { return m_bandwidth_limit[channel].throttle(); }
+
+ void assign_bandwidth(int channel, int amount);
+ void expire_bandwidth(int channel, int amount);
+
+#ifndef NDEBUG
+ void check_invariant() const;
+ ptime m_last_choke;
+#endif
+
+
+ // is true until we can be sure that the other end
+ // speaks our protocol (be it bittorrent or http).
+ virtual bool in_handshake() const = 0;
+
+ // returns the block currently being
+ // downloaded. And the progress of that
+ // block. If the peer isn't downloading
+ // a piece for the moment, the boost::optional
+ // will be invalid.
+ virtual boost::optional<piece_block_progress>
+ downloading_piece_progress() const
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "downloading_piece_progress() dispatched to the base class!\n";
+#endif
+ return boost::optional<piece_block_progress>();
+ }
+
+ // these functions are virtual to let bt_peer_connection hook into them
+ // and encrypt the content
+ virtual void send_buffer(char const* begin, int size);
+ virtual buffer::interval allocate_send_buffer(int size);
+ virtual void setup_send();
+
+ template <class Destructor>
+ void append_send_buffer(char* buffer, int size, Destructor const& destructor)
+ {
+ m_send_buffer.append_buffer(buffer, size, size, destructor);
+#ifdef TORRENT_STATS
+ m_ses.m_buffer_usage_logger << log_time() << " append_send_buffer: " << size << std::endl;
+ m_ses.log_buffer_usage();
+#endif
+ }
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ void set_country(char const* c)
+ {
+ TORRENT_ASSERT(strlen(c) == 2);
+ m_country[0] = c[0];
+ m_country[1] = c[1];
+ }
+ bool has_country() const { return m_country[0] != 0; }
+#endif
+
+ int send_buffer_size() const
+ { return m_send_buffer.size(); }
+
+ int send_buffer_capacity() const
+ { return m_send_buffer.capacity(); }
+
+ protected:
+
+ virtual void get_specific_peer_info(peer_info& p) const = 0;
+
+ virtual void write_choke() = 0;
+ virtual void write_unchoke() = 0;
+ virtual void write_interested() = 0;
+ virtual void write_not_interested() = 0;
+ virtual void write_request(peer_request const& r) = 0;
+ virtual void write_cancel(peer_request const& r) = 0;
+ virtual void write_have(int index) = 0;
+ virtual void write_keepalive() = 0;
+ virtual void write_piece(peer_request const& r, char* buffer) = 0;
+
+ virtual void write_reject_request(peer_request const& r) = 0;
+ virtual void write_allow_fast(int piece) = 0;
+
+ virtual void on_connected() = 0;
+ virtual void on_tick() {}
+
+ virtual void on_receive(asio::error_code const& error
+ , std::size_t bytes_transferred) = 0;
+ virtual void on_sent(asio::error_code const& error
+ , std::size_t bytes_transferred) = 0;
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ buffer::interval wr_recv_buffer()
+ {
+ if (m_recv_buffer.empty()) return buffer::interval(0,0);
+ return buffer::interval(&m_recv_buffer[0]
+ , &m_recv_buffer[0] + m_recv_pos);
+ }
+#endif
+
+ buffer::const_interval receive_buffer() const
+ {
+ if (m_recv_buffer.empty()) return buffer::const_interval(0,0);
+ return buffer::const_interval(&m_recv_buffer[0]
+ , &m_recv_buffer[0] + m_recv_pos);
+ }
+
+ void cut_receive_buffer(int size, int packet_size);
+
+ void reset_recv_buffer(int packet_size);
+ int packet_size() const { return m_packet_size; }
+
+ bool packet_finished() const
+ {
+ return m_packet_size <= m_recv_pos;
+ }
+
+ void setup_receive();
+
+ void attach_to_torrent(sha1_hash const& ih);
+
+ bool verify_piece(peer_request const& p) const;
+
+ // the bandwidth channels, upload and download
+ // keeps track of the current quotas
+ bandwidth_limit m_bandwidth_limit[num_channels];
+
+ // statistics about upload and download speeds
+ // and total amount of uploads and downloads for
+ // this peer
+ stat m_statistics;
+
+ // a back reference to the session
+ // the peer belongs to.
+ aux::session_impl& m_ses;
+
+ // called from the main loop when this connection has any
+ // work to do.
+ void on_send_data(asio::error_code const& error
+ , std::size_t bytes_transferred);
+ void on_receive_data(asio::error_code const& error
+ , std::size_t bytes_transferred);
+
+ // this is the limit on the number of outstanding requests
+ // we have to this peer. This is initialized to the settings
+ // in the session_settings structure. But it may be lowered
+ // if the peer is known to require a smaller limit (like BitComet).
+ // or if the extended handshake sets a limit.
+ // web seeds also has a limit on the queue size.
+ int m_max_out_request_queue;
+
+ void set_timeout(int s) { m_timeout = s; }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ typedef std::list<boost::shared_ptr<peer_plugin> > extension_list_t;
+ extension_list_t m_extensions;
+#endif
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ // in case the session settings is set
+ // to resolve countries, this is set to
+ // the two character country code this
+ // peer resides in.
+ char m_country[2];
+#endif
+
+ private:
+
+ void fill_send_buffer();
+ void on_disk_read_complete(int ret, disk_io_job const& j, peer_request r);
+ void on_disk_write_complete(int ret, disk_io_job const& j
+ , peer_request r, boost::shared_ptr<torrent> t);
+
+ // the timeout in seconds
+ int m_timeout;
+
+ // the time when we last got a part of a
+ // piece packet from this peer
+ ptime m_last_piece;
+ // the time we sent a request to
+ // this peer the last time
+ ptime m_last_request;
+ // the time we received the last
+ // piece request from the peer
+ ptime m_last_incoming_request;
+ // the time when we unchoked this peer
+ ptime m_last_unchoke;
+
+ int m_packet_size;
+ int m_recv_pos;
+ buffer m_recv_buffer;
+
+ chained_buffer m_send_buffer;
+
+ // the number of bytes we are currently reading
+ // from disk, that will be added to the send
+ // buffer as soon as they complete
+ int m_reading_bytes;
+
+ // timeouts
+ ptime m_last_receive;
+ ptime m_last_sent;
+
+ boost::shared_ptr<socket_type> m_socket;
+ // this is the peer we're actually talking to
+ // it may not necessarily be the peer we're
+ // connected to, in case we use a proxy
+ tcp::endpoint m_remote;
+
+ // this is the torrent this connection is
+ // associated with. If the connection is an
+ // incoming conncetion, this is set to zero
+ // until the info_hash is received. Then it's
+ // set to the torrent it belongs to.
+ boost::weak_ptr<torrent> m_torrent;
+ // is true if it was we that connected to the peer
+ // and false if we got an incoming connection
+ // could be considered: true = local, false = remote
+ bool m_active;
+
+ // remote peer's id
+ peer_id m_peer_id;
+
+ // other side says that it's interested in downloading
+ // from us.
+ bool m_peer_interested;
+
+ // the other side has told us that it won't send anymore
+ // data to us for a while
+ bool m_peer_choked;
+
+ // the peer has pieces we are interested in
+ bool m_interesting;
+
+ // we have choked the upload to the peer
+ bool m_choked;
+
+ // this is set to true if the connection timed
+ // out or closed the connection. In that
+ // case we will not try to reconnect to
+ // this peer
+ bool m_failed;
+
+ // if this is set to true, the peer will not
+ // request bandwidth from the limiter, but instead
+ // just send and receive as much as possible.
+ bool m_ignore_bandwidth_limits;
+
+ // the pieces the other end have
+ std::vector<bool> m_have_piece;
+ // this is set to true when a have_all
+ // message is received. This information
+ // is used to fill the bitmask in init()
+ bool m_have_all;
+
+ // the number of pieces this peer
+ // has. Must be the same as
+ // std::count(m_have_piece.begin(),
+ // m_have_piece.end(), true)
+ int m_num_pieces;
+
+ // the queue of requests we have got
+ // from this peer
+ std::deque<peer_request> m_requests;
+
+ // the blocks we have reserved in the piece
+ // picker and will request from this peer.
+ std::deque<piece_block> m_request_queue;
+
+ // the queue of blocks we have requested
+ // from this peer
+ std::deque<piece_block> m_download_queue;
+
+ // the number of request we should queue up
+ // at the remote end.
+ int m_desired_queue_size;
+
+ // the amount of data this peer has been given
+ // as free upload. This is distributed from
+ // peers from which we get free download
+ // this will be negative on a peer from which
+ // we get free download, and positive on peers
+ // that we give the free upload, to keep the balance.
+ size_type m_free_upload;
+
+ // if this is true, this peer is assumed to handle all piece
+ // requests in fifo order. All skipped blocks are re-requested
+ // immediately instead of having a looser requirement
+ // where blocks can be sent out of order. The default is to
+ // allow non-fifo order.
+ bool m_assume_fifo;
+
+ // the number of invalid piece-requests
+ // we have got from this peer. If the request
+ // queue gets empty, and there have been
+ // invalid requests, we can assume the
+ // peer is waiting for those pieces.
+ // we can then clear its download queue
+ // by sending choke, unchoke.
+ int m_num_invalid_requests;
+
+ // this is true if this connection has been added
+ // to the list of connections that will be closed.
+ bool m_disconnecting;
+
+ // the time when this peer sent us a not_interested message
+ // the last time.
+ ptime m_became_uninterested;
+
+ // the time when we sent a not_interested message to
+ // this peer the last time.
+ ptime m_became_uninteresting;
+
+ // this is true until this socket has become
+ // writable for the first time (i.e. the
+ // connection completed). While connecting
+ // the timeout will not be triggered. This is
+ // because windows XP SP2 may delay connection
+ // attempts, which means that the connection
+ // may not even have been attempted when the
+ // time out is reached.
+ bool m_connecting;
+
+ // This is true until connect is called on the
+ // peer_connection's socket. It is false on incoming
+ // connections.
+ bool m_queued;
+
+ // these are true when there's a asynchronous write
+ // or read operation in progress. Or an asyncronous bandwidth
+ // request is in progress.
+ bool m_writing;
+ bool m_reading;
+
+ // if set to non-zero, this peer will always prefer
+ // to request entire n pieces, rather than blocks.
+ // where n is the value of this variable.
+ // if it is 0, the download rate limit setting
+ // will be used to determine if whole pieces
+ // are preferred.
+ int m_prefer_whole_pieces;
+
+ // if this is true, the blocks picked by the piece
+ // picker will be merged before passed to the
+ // request function. i.e. subsequent blocks are
+ // merged into larger blocks. This is used by
+ // the http-downloader, to request whole pieces
+ // at a time.
+ bool m_request_large_blocks;
+
+ // this is the priority with which this peer gets
+ // download bandwidth quota assigned to it.
+ int m_priority;
+
+ int m_upload_limit;
+ int m_download_limit;
+
+ // this peer's peer info struct. This may
+ // be 0, in case the connection is incoming
+ // and hasn't been added to a torrent yet.
+ policy::peer* m_peer_info;
+
+ // this is a measurement of how fast the peer
+ // it allows some variance without changing
+ // back and forth between states
+ peer_speed_t m_speed;
+
+ // the ticket id from the connection queue.
+ // This is used to identify the connection
+ // so that it can be removed from the queue
+ // once the connection completes
+ int m_connection_ticket;
+
+ // bytes downloaded since last second
+ // timer timeout; used for determining
+ // approx download rate
+ int m_remote_bytes_dled;
+
+ // approximate peer download rate
+ int m_remote_dl_rate;
+
+ // a timestamp when the remote download rate
+ // was last updated
+ ptime m_remote_dl_update;
+
+ // the pieces we will send to the peer
+ // if requested (regardless of choke state)
+ std::set<int> m_accept_fast;
+
+ // the pieces the peer will send us if
+ // requested (regardless of choke state)
+ std::vector<int> m_allowed_fast;
+
+ // pieces that has been suggested to be
+ // downloaded from this peer
+ std::vector<int> m_suggested_pieces;
+
+ // the number of bytes send to the disk-io
+ // thread that hasn't yet been completely written.
+ int m_outstanding_writing_bytes;
+
+ // if this is true, the disconnection
+ // timestamp is not updated when the connection
+ // is closed. This means the time until we can
+ // reconnect to this peer is shorter, and likely
+ // immediate.
+ bool m_fast_reconnect;
+
+#ifndef NDEBUG
+ public:
+ bool m_in_constructor;
+#endif
+ };
+}
+
+#endif // TORRENT_PEER_CONNECTION_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/peer_id.hpp b/src/libtorrent/include/libtorrent/peer_id.hpp
new file mode 100644
index 0000000..a546c6e
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/peer_id.hpp
@@ -0,0 +1,193 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_PEER_ID_HPP_INCLUDED
+#define TORRENT_PEER_ID_HPP_INCLUDED
+
+#include <iostream>
+#include <iomanip>
+#include <cctype>
+#include <algorithm>
+#include <string>
+#include <cstring>
+
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ class TORRENT_EXPORT big_number
+ {
+ // private type
+ struct private_pointer {};
+ // the number of bytes of the number
+ enum { number_size = 20 };
+ public:
+ enum { size = number_size };
+
+ big_number() {}
+
+ big_number(std::string const& s)
+ {
+ TORRENT_ASSERT(s.size() >= 20);
+ int sl = int(s.size()) < size ? int(s.size()) : size;
+ std::memcpy(m_number, &s[0], sl);
+ }
+
+ // when initialized with 0
+ big_number(private_pointer*) { clear(); }
+
+ void clear()
+ {
+ std::fill(m_number,m_number+number_size,0);
+ }
+
+ bool is_all_zeros() const
+ {
+ return std::count(m_number,m_number+number_size,0) == number_size;
+ }
+
+ bool operator==(big_number const& n) const
+ {
+ return std::equal(n.m_number, n.m_number+number_size, m_number);
+ }
+
+ bool operator!=(big_number const& n) const
+ {
+ return !std::equal(n.m_number, n.m_number+number_size, m_number);
+ }
+
+ bool operator<(big_number const& n) const
+ {
+ for (int i = 0; i < number_size; ++i)
+ {
+ if (m_number[i] < n.m_number[i]) return true;
+ if (m_number[i] > n.m_number[i]) return false;
+ }
+ return false;
+ }
+
+ big_number operator~()
+ {
+ big_number ret;
+ for (int i = 0; i< number_size; ++i)
+ ret.m_number[i] = ~m_number[i];
+ return ret;
+ }
+
+ big_number& operator &= (big_number const& n)
+ {
+ for (int i = 0; i< number_size; ++i)
+ m_number[i] &= n.m_number[i];
+ return *this;
+ }
+
+ big_number& operator |= (big_number const& n)
+ {
+ for (int i = 0; i< number_size; ++i)
+ m_number[i] |= n.m_number[i];
+ return *this;
+ }
+
+ big_number& operator ^= (big_number const& n)
+ {
+ for (int i = 0; i< number_size; ++i)
+ m_number[i] ^= n.m_number[i];
+ return *this;
+ }
+
+ unsigned char& operator[](int i)
+ { TORRENT_ASSERT(i >= 0 && i < number_size); return m_number[i]; }
+
+ unsigned char const& operator[](int i) const
+ { TORRENT_ASSERT(i >= 0 && i < number_size); return m_number[i]; }
+
+ typedef const unsigned char* const_iterator;
+ typedef unsigned char* iterator;
+
+ const_iterator begin() const { return m_number; }
+ const_iterator end() const { return m_number+number_size; }
+
+ iterator begin() { return m_number; }
+ iterator end() { return m_number+number_size; }
+
+ private:
+
+ unsigned char m_number[number_size];
+
+ };
+
+ typedef big_number peer_id;
+ typedef big_number sha1_hash;
+
+ inline std::ostream& operator<<(std::ostream& os, big_number const& peer)
+ {
+ for (big_number::const_iterator i = peer.begin();
+ i != peer.end(); ++i)
+ {
+ os << std::hex << std::setw(2) << std::setfill('0')
+ << static_cast<unsigned int>(*i);
+ }
+ os << std::dec << std::setfill(' ');
+ return os;
+ }
+
+ inline std::istream& operator>>(std::istream& is, big_number& peer)
+ {
+ using namespace std;
+
+ for (big_number::iterator i = peer.begin();
+ i != peer.end(); ++i)
+ {
+ char c[2];
+ is >> c[0] >> c[1];
+ c[0] = tolower(c[0]);
+ c[1] = tolower(c[1]);
+ if (
+ ((c[0] < '0' || c[0] > '9') && (c[0] < 'a' || c[0] > 'f'))
+ || ((c[1] < '0' || c[1] > '9') && (c[1] < 'a' || c[1] > 'f'))
+ || is.fail())
+ {
+ is.setstate(ios_base::failbit);
+ return is;
+ }
+ *i = ((isdigit(c[0])?c[0]-'0':c[0]-'a'+10) << 4)
+ + (isdigit(c[1])?c[1]-'0':c[1]-'a'+10);
+ }
+ return is;
+ }
+
+}
+
+#endif // TORRENT_PEER_ID_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/peer_info.hpp b/src/libtorrent/include/libtorrent/peer_info.hpp
new file mode 100644
index 0000000..e65f33a
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/peer_info.hpp
@@ -0,0 +1,164 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_PEER_INFO_HPP_INCLUDED
+#define TORRENT_PEER_INFO_HPP_INCLUDED
+
+#include <vector>
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/size_type.hpp"
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+ struct TORRENT_EXPORT peer_info
+ {
+ enum
+ {
+ interesting = 0x1,
+ choked = 0x2,
+ remote_interested = 0x4,
+ remote_choked = 0x8,
+ supports_extensions = 0x10,
+ local_connection = 0x20,
+ handshake = 0x40,
+ connecting = 0x80,
+ queued = 0x100,
+ on_parole = 0x200,
+ seed = 0x400,
+ optimistic_unchoke = 0x800
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ , rc4_encrypted = 0x100000,
+ plaintext_encrypted = 0x200000
+#endif
+ };
+
+ unsigned int flags;
+
+ enum peer_source_flags
+ {
+ tracker = 0x1,
+ dht = 0x2,
+ pex = 0x4,
+ lsd = 0x8,
+ resume_data = 0x10,
+ incoming = 0x20
+ };
+
+ int source;
+
+ tcp::endpoint ip;
+ float up_speed;
+ float down_speed;
+ float payload_up_speed;
+ float payload_down_speed;
+ size_type total_download;
+ size_type total_upload;
+ peer_id pid;
+ std::vector<bool> pieces;
+ int upload_limit;
+ int download_limit;
+
+ // time since last request
+ time_duration last_request;
+
+ // time since last download or upload
+ time_duration last_active;
+
+ // the size of the send buffer for this peer, in bytes
+ int send_buffer_size;
+ // the number bytes that's actually used of the send buffer
+ int used_send_buffer;
+
+ // the number of failed hashes for this peer
+ int num_hashfails;
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ // in case the session settings is set
+ // to resolve countries, this is set to
+ // the two character country code this
+ // peer resides in.
+ char country[2];
+#endif
+
+ size_type load_balancing;
+
+ // this is the number of requests
+ // we have sent to this peer
+ // that we haven't got a response
+ // for yet
+ int download_queue_length;
+
+ // the number of requests that is
+ // tried to be maintained (this is
+ // typically a function of download speed)
+ int target_dl_queue_length;
+
+ // this is the number of requests
+ // the peer has sent to us
+ // that we haven't sent yet
+ int upload_queue_length;
+
+ // the number of times this IP
+ // has failed to connect
+ int failcount;
+
+ // the currently downloading piece
+ // if piece index is -1 all associated
+ // members are just set to 0
+ int downloading_piece_index;
+ int downloading_block_index;
+ int downloading_progress;
+ int downloading_total;
+
+ std::string client;
+
+ enum
+ {
+ standard_bittorrent = 0,
+ web_seed = 1
+ };
+ int connection_type;
+
+ // approximate peer download rate
+ int remote_dl_rate;
+
+ // number of bytes this peer has in
+ // the disk write queue
+ int pending_disk_bytes;
+ };
+
+}
+
+#endif // TORRENT_PEER_INFO_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/peer_request.hpp b/src/libtorrent/include/libtorrent/peer_request.hpp
new file mode 100644
index 0000000..445ff4d
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/peer_request.hpp
@@ -0,0 +1,49 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_PEER_REQUEST_HPP_INCLUDED
+#define TORRENT_PEER_REQUEST_HPP_INCLUDED
+
+namespace libtorrent
+{
+ struct TORRENT_EXPORT peer_request
+ {
+ int piece;
+ int start;
+ int length;
+ bool operator==(peer_request const& r) const
+ { return piece == r.piece && start == r.start && length == r.length; }
+ };
+}
+
+#endif // TORRENT_PEER_REQUEST_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/piece_block_progress.hpp b/src/libtorrent/include/libtorrent/piece_block_progress.hpp
new file mode 100644
index 0000000..481ffc9
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/piece_block_progress.hpp
@@ -0,0 +1,57 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_PIECE_BLOCK_PROGRESS_HPP_INCLUDED
+#define TORRENT_PIECE_BLOCK_PROGRESS_HPP_INCLUDED
+
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+ struct TORRENT_EXPORT piece_block_progress
+ {
+ // the piece and block index
+ // determines exactly which
+ // part of the torrent that
+ // is currently being downloaded
+ int piece_index;
+ int block_index;
+ // the number of bytes we have received
+ // of this block
+ int bytes_downloaded;
+ // the number of bytes in the block
+ int full_block_bytes;
+ };
+}
+
+#endif // TORRENT_PIECE_BLOCK_PROGRESS_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/piece_picker.hpp b/src/libtorrent/include/libtorrent/piece_picker.hpp
new file mode 100644
index 0000000..ef69c33
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/piece_picker.hpp
@@ -0,0 +1,462 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+#ifndef TORRENT_PIECE_PICKER_HPP_INCLUDED
+#define TORRENT_PIECE_PICKER_HPP_INCLUDED
+
+#include <algorithm>
+#include <vector>
+#include <bitset>
+#include <utility>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/static_assert.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/session_settings.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ class torrent;
+ class peer_connection;
+
+ struct TORRENT_EXPORT piece_block
+ {
+ piece_block(int p_index, int b_index)
+ : piece_index(p_index)
+ , block_index(b_index)
+ {}
+ int piece_index;
+ int block_index;
+
+ bool operator<(piece_block const& b) const
+ {
+ if (piece_index < b.piece_index) return true;
+ if (piece_index == b.piece_index) return block_index < b.block_index;
+ return false;
+ }
+
+ bool operator==(piece_block const& b) const
+ { return piece_index == b.piece_index && block_index == b.block_index; }
+
+ bool operator!=(piece_block const& b) const
+ { return piece_index != b.piece_index || block_index != b.block_index; }
+
+ };
+
+ class TORRENT_EXPORT piece_picker
+ {
+ public:
+
+ struct block_info
+ {
+ block_info(): peer(0), num_peers(0), state(state_none) {}
+ // the peer this block was requested or
+ // downloaded from. This is a pointer to
+ // a policy::peer object
+ void* peer;
+ // the number of peers that has this block in their
+ // download or request queues
+ unsigned num_peers:14;
+ // the state of this block
+ enum { state_none, state_requested, state_writing, state_finished };
+ unsigned state:2;
+ };
+
+ // the peers that are downloading this piece
+ // are considered fast peers or slow peers.
+ // none is set if the blocks were downloaded
+ // in a previous session
+ enum piece_state_t
+ { none, slow, medium, fast };
+
+ struct downloading_piece
+ {
+ downloading_piece(): finished(0), writing(0), requested(0) {}
+ piece_state_t state;
+
+ // the index of the piece
+ int index;
+ // info about each block
+ // this is a pointer into the m_block_info
+ // vector owned by the piece_picker
+ block_info* info;
+ // the number of blocks in the finished state
+ boost::int16_t finished;
+ // the number of blocks in the writing state
+ boost::int16_t writing;
+ // the number of blocks in the requested state
+ boost::int16_t requested;
+ };
+
+ piece_picker(int blocks_per_piece
+ , int total_num_blocks);
+
+ void get_availability(std::vector<int>& avail) const;
+
+ void set_sequenced_download_threshold(int sequenced_download_threshold);
+
+ // the vector tells which pieces we already have
+ // and which we don't have.
+ void files_checked(
+ std::vector<bool> const& pieces
+ , std::vector<downloading_piece> const& unfinished
+ , std::vector<int>& verify_pieces);
+
+ // increases the peer count for the given piece
+ // (is used when a HAVE or BITFIELD message is received)
+ void inc_refcount(int index);
+
+ // decreases the peer count for the given piece
+ // (used when a peer disconnects)
+ void dec_refcount(int index);
+
+ // these will increase and decrease the peer count
+ // of all pieces. They are used when seeds join
+ // or leave the swarm.
+ void inc_refcount_all();
+ void dec_refcount_all();
+
+ // This indicates that we just received this piece
+ // it means that the refcounter will indicate that
+ // we are not interested in this piece anymore
+ // (i.e. we don't have to maintain a refcount)
+ void we_have(int index);
+
+ // sets the priority of a piece.
+ // returns true if the priority was changed from 0 to non-0
+ // or vice versa
+ bool set_piece_priority(int index, int prio);
+
+ // returns the priority for the piece at 'index'
+ int piece_priority(int index) const;
+
+ // returns the current piece priorities for all pieces
+ void piece_priorities(std::vector<int>& pieces) const;
+
+ // ========== start deprecation ==============
+
+ // fills the bitmask with 1's for pieces that are filtered
+ void filtered_pieces(std::vector<bool>& mask) const;
+
+ // ========== end deprecation ==============
+
+ // pieces should be the vector that represents the pieces a
+ // client has. It returns a list of all pieces that this client
+ // has and that are interesting to download. It returns them in
+ // priority order. It doesn't care about the download flag.
+ // The user of this function must lookup if any piece is
+ // marked as being downloaded. If the user of this function
+ // decides to download a piece, it must mark it as being downloaded
+ // itself, by using the mark_as_downloading() member function.
+ // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
+ // The last argument is the policy::peer pointer for the peer that
+ // we'll download from.
+ void pick_pieces(std::vector<bool> const& pieces
+ , std::vector<piece_block>& interesting_blocks
+ , int num_pieces, int prefer_whole_pieces
+ , void* peer, piece_state_t speed
+ , bool rarest_first, bool on_parole
+ , std::vector<int> const& suggested_pieces) const;
+
+ // picks blocks from each of the pieces in the piece_list
+ // vector that is also in the piece bitmask. The blocks
+ // are added to interesting_blocks, and busy blocks are
+ // added to backup_blocks. num blocks is the number of
+ // blocks to be picked. Blocks are not picked from pieces
+ // that are being downloaded
+ int add_blocks(std::vector<int> const& piece_list
+ , const std::vector<bool>& pieces
+ , std::vector<piece_block>& interesting_blocks
+ , int num_blocks, int prefer_whole_pieces
+ , void* peer, std::vector<int> const& ignore) const;
+
+ // picks blocks only from downloading pieces
+ int add_blocks_downloading(
+ std::vector<bool> const& pieces
+ , std::vector<piece_block>& interesting_blocks
+ , std::vector<piece_block>& backup_blocks
+ , int num_blocks, int prefer_whole_pieces
+ , void* peer, piece_state_t speed
+ , bool on_parole) const;
+
+ // clears the peer pointer in all downloading pieces with this
+ // peer pointer
+ void clear_peer(void* peer);
+
+ // returns true if any client is currently downloading this
+ // piece-block, or if it's queued for downloading by some client
+ // or if it already has been successfully downloaded
+ bool is_requested(piece_block block) const;
+ // returns true if the block has been downloaded
+ bool is_downloaded(piece_block block) const;
+ // returns true if the block has been downloaded and written to disk
+ bool is_finished(piece_block block) const;
+
+ // marks this piece-block as queued for downloading
+ bool mark_as_downloading(piece_block block, void* peer
+ , piece_state_t s);
+ void mark_as_writing(piece_block block, void* peer);
+ void mark_as_finished(piece_block block, void* peer);
+ int num_peers(piece_block block) const;
+
+ // returns information about the given piece
+ void piece_info(int index, piece_picker::downloading_piece& st) const;
+
+ // if a piece had a hash-failure, it must be restored and
+ // made available for redownloading
+ void restore_piece(int index);
+
+ // clears the given piece's download flag
+ // this means that this piece-block can be picked again
+ void abort_download(piece_block block);
+
+ bool is_piece_finished(int index) const;
+
+ // returns the number of blocks there is in the given piece
+ int blocks_in_piece(int index) const;
+
+ // the number of downloaded blocks that hasn't passed
+ // the hash-check yet
+ int unverified_blocks() const;
+
+ void get_downloaders(std::vector<void*>& d, int index) const;
+
+ std::vector<downloading_piece> const& get_download_queue() const
+ { return m_downloads; }
+
+ void* get_downloader(piece_block block) const;
+
+ // the number of filtered pieces we don't have
+ int num_filtered() const { return m_num_filtered; }
+
+ // the number of filtered pieces we already have
+ int num_have_filtered() const { return m_num_have_filtered; }
+
+#ifndef NDEBUG
+ // used in debug mode
+ void check_invariant(const torrent* t = 0) const;
+ void verify_pick(std::vector<piece_block> const& picked
+ , std::vector<bool> const& bitfield) const;
+#endif
+
+ // functor that compares indices on downloading_pieces
+ struct has_index
+ {
+ has_index(int i): index(i) { TORRENT_ASSERT(i >= 0); }
+ bool operator()(const downloading_piece& p) const
+ { return p.index == index; }
+ int index;
+ };
+
+ int blocks_in_last_piece() const
+ { return m_blocks_in_last_piece; }
+
+ float distributed_copies() const;
+
+ private:
+
+ bool can_pick(int piece, std::vector<bool> const& bitmask) const;
+ std::pair<int, int> expand_piece(int piece, int whole_pieces
+ , std::vector<bool> const& have) const;
+
+ struct piece_pos
+ {
+ piece_pos() {}
+ piece_pos(int peer_count_, int index_)
+ : peer_count(peer_count_)
+ , downloading(0)
+ , piece_priority(1)
+ , index(index_)
+ {
+ TORRENT_ASSERT(peer_count_ >= 0);
+ TORRENT_ASSERT(index_ >= 0);
+ }
+
+ // the number of peers that has this piece
+ // (availability)
+ unsigned peer_count : 10;
+ // is 1 if the piece is marked as being downloaded
+ unsigned downloading : 1;
+ // is 0 if the piece is filtered (not to be downloaded)
+ // 1 is normal priority (default)
+ // 2 is higher priority than pieces at the same availability level
+ // 3 is same priority as partial pieces
+ // 4 is higher priority than partial pieces
+ // 5 and 6 same priority as availability 1 (ignores availability)
+ // 7 is maximum priority (ignores availability)
+ unsigned piece_priority : 3;
+ // index in to the piece_info vector
+ unsigned index : 18;
+
+ enum
+ {
+ // index is set to this to indicate that we have the
+ // piece. There is no entry for the piece in the
+ // buckets if this is the case.
+ we_have_index = 0x3ffff,
+ // the priority value that means the piece is filtered
+ filter_priority = 0,
+ // the max number the peer count can hold
+ max_peer_count = 0x3ff
+ };
+
+ bool have() const { return index == we_have_index; }
+ void set_have() { index = we_have_index; TORRENT_ASSERT(have()); }
+
+ bool filtered() const { return piece_priority == filter_priority; }
+ void filtered(bool f) { piece_priority = f ? filter_priority : 0; }
+
+ int priority(int limit) const
+ {
+ if (downloading || filtered() || have()) return 0;
+ // pieces we are currently downloading have high priority
+ int prio = peer_count * 2;
+ // if the peer_count is 0 or 1, the priority cannot be higher
+ if (prio <= 1) return prio;
+ if (prio >= limit * 2) prio = limit * 2;
+ // the different priority levels
+ switch (piece_priority)
+ {
+ case 1: return prio;
+ case 2: return prio - 1;
+ case 3: return (std::max)(prio / 2, 1);
+ case 4: return (std::max)(prio / 2 - 1, 1);
+ case 5: return (std::max)(prio / 3, 1);
+ case 6: return (std::max)(prio / 3 - 1, 1);
+ case 7: return 1;
+ }
+ return prio;
+ }
+
+ bool operator!=(piece_pos p) const
+ { return index != p.index || peer_count != p.peer_count; }
+
+ bool operator==(piece_pos p) const
+ { return index == p.index && peer_count == p.peer_count; }
+
+ };
+
+ BOOST_STATIC_ASSERT(sizeof(piece_pos) == sizeof(char) * 4);
+
+ bool is_ordered(int priority) const
+ {
+ return priority >= m_sequenced_download_threshold * 2;
+ }
+
+ void add(int index);
+ void move(int vec_index, int elem_index);
+ void sort_piece(std::vector<downloading_piece>::iterator dp);
+
+ downloading_piece& add_download_piece();
+ void erase_download_piece(std::vector<downloading_piece>::iterator i);
+
+ // this vector contains all pieces we don't have.
+ // in the first entry (index 0) is a vector of all pieces
+ // that no peer have, the vector at index 1 contains
+ // all pieces that exactly one peer have, index 2 contains
+ // all pieces exactly two peers have and so on.
+ // this is not entirely true. The availibility of a piece
+ // is adjusted depending on its priority. But the principle
+ // is that the higher index, the lower priority a piece has.
+ std::vector<std::vector<int> > m_piece_info;
+
+ // this maps indices to number of peers that has this piece and
+ // index into the m_piece_info vectors.
+ // piece_pos::we_have_index means that we have the piece, so it
+ // doesn't exist in the piece_info buckets
+ // pieces with the filtered flag set doesn't have entries in
+ // the m_piece_info buckets either
+ std::vector<piece_pos> m_piece_map;
+
+ // each piece that's currently being downloaded
+ // has an entry in this list with block allocations.
+ // i.e. it says wich parts of the piece that
+ // is being downloaded
+ std::vector<downloading_piece> m_downloads;
+
+ // this holds the information of the
+ // blocks in partially downloaded pieces.
+ // the first m_blocks_per_piece entries
+ // in the vector belongs to the first
+ // entry in m_downloads, the second
+ // m_blocks_per_piece entries to the
+ // second entry in m_downloads and so on.
+ std::vector<block_info> m_block_info;
+
+ int m_blocks_per_piece;
+ int m_blocks_in_last_piece;
+
+ // the number of filtered pieces that we don't already
+ // have. total_number_of_pieces - number_of_pieces_we_have
+ // - num_filtered is supposed to the number of pieces
+ // we still want to download
+ int m_num_filtered;
+
+ // the number of pieces we have that also are filtered
+ int m_num_have_filtered;
+
+ // the number of pieces we have
+ int m_num_have;
+
+ // the required popularity of a piece in order to download
+ // it in sequence instead of random order.
+ int m_sequenced_download_threshold;
+#ifndef NDEBUG
+ bool m_files_checked_called;
+#endif
+ };
+
+ inline int piece_picker::blocks_in_piece(int index) const
+ {
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < (int)m_piece_map.size());
+ if (index+1 == (int)m_piece_map.size())
+ return m_blocks_in_last_piece;
+ else
+ return m_blocks_per_piece;
+ }
+
+}
+
+#endif // TORRENT_PIECE_PICKER_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/policy.hpp b/src/libtorrent/include/libtorrent/policy.hpp
new file mode 100644
index 0000000..95397b4
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/policy.hpp
@@ -0,0 +1,263 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_POLICY_HPP_INCLUDED
+#define TORRENT_POLICY_HPP_INCLUDED
+
+#include <algorithm>
+#include <vector>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer.hpp"
+#include "libtorrent/piece_picker.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/size_type.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/time.hpp"
+
+namespace libtorrent
+{
+
+ class torrent;
+ class peer_connection;
+
+ enum
+ {
+ // the limits of the download queue size
+ min_request_queue = 2,
+
+ // the amount of free upload allowed before
+ // the peer is choked
+ free_upload_amount = 4 * 16 * 1024
+ };
+
+ void request_a_block(torrent& t, peer_connection& c);
+
+ class TORRENT_EXPORT policy
+ {
+ public:
+
+ policy(torrent* t);
+
+ // this is called every 10 seconds to allow
+ // for peer choking management
+ void pulse();
+
+ struct peer;
+ // this is called once for every peer we get from
+ // the tracker, pex, lsd or dht.
+ policy::peer* peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid
+ , int source, char flags);
+ void update_peer_port(int port, policy::peer* p, int src);
+
+ // called when an incoming connection is accepted
+ void new_connection(peer_connection& c);
+
+ // the given connection was just closed
+ void connection_closed(const peer_connection& c) throw();
+
+ // the peer has got at least one interesting piece
+ void peer_is_interesting(peer_connection& c);
+
+ void piece_finished(int index, bool successfully_verified);
+
+ // the peer choked us
+ void choked(peer_connection& c);
+
+ int count_choked() const;
+
+ // the peer unchoked us
+ void unchoked(peer_connection& c);
+
+ // the peer is interested in our pieces
+ void interested(peer_connection& c);
+
+ // the peer is not interested in our pieces
+ void not_interested(peer_connection& c);
+
+ void ip_filter_updated();
+
+#ifndef NDEBUG
+ bool has_connection(const peer_connection* p);
+
+ void check_invariant() const;
+#endif
+
+ struct peer
+ {
+ enum connection_type { not_connectable, connectable };
+
+ peer(tcp::endpoint const& ip, connection_type t, int src);
+
+ size_type total_download() const;
+ size_type total_upload() const;
+
+ // the ip/port pair this peer is or was connected on
+ // if it was a remote (incoming) connection, type is
+ // set thereafter. If it was a peer we got from the
+ // tracker, type is set to local_connection.
+ tcp::endpoint ip;
+ connection_type type;
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ // Hints encryption support of peer. Only effective for
+ // and when the outgoing encryption policy allows both
+ // encrypted and non encrypted connections
+ // (pe_settings::out_enc_policy == enabled). The initial
+ // state of this flag determines the initial connection
+ // attempt type (true = encrypted, false = standard).
+ // This will be toggled everytime either an encrypted or
+ // non-encrypted handshake fails.
+ bool pe_support;
+#endif
+ // the number of failed connection attempts this peer has
+ int failcount;
+
+ // the number of times this peer has been
+ // part of a piece that failed the hash check
+ int hashfails;
+
+ // this is true if the peer is a seed
+ bool seed;
+
+ int fast_reconnects;
+
+ // true if this peer currently is unchoked
+ // because of an optimistic unchoke.
+ // when the optimistic unchoke is moved to
+ // another peer, this peer will be choked
+ // if this is true
+ bool optimistically_unchoked;
+
+ // the time when this peer was optimistically unchoked
+ // the last time.
+ libtorrent::ptime last_optimistically_unchoked;
+
+ // the time when the peer connected to us
+ // or disconnected if it isn't connected right now
+ libtorrent::ptime connected;
+
+ // for every valid piece we receive where this
+ // peer was one of the participants, we increase
+ // this value. For every invalid piece we receive
+ // where this peer was a participant, we decrease
+ // this value. If it sinks below a threshold, its
+ // considered a bad peer and will be banned.
+ int trust_points;
+
+ // if this is true, the peer has previously participated
+ // in a piece that failed the piece hash check. This will
+ // put the peer on parole and only request entire pieces.
+ // if a piece pass that was partially requested from this
+ // peer it will leave parole mode and continue download
+ // pieces as normal peers.
+ bool on_parole;
+
+ // this is the accumulated amount of
+ // uploaded and downloaded data to this
+ // peer. It only accounts for what was
+ // shared during the last connection to
+ // this peer. i.e. These are only updated
+ // when the connection is closed. For the
+ // total amount of upload and download
+ // we'll have to add thes figures with the
+ // statistics from the peer_connection.
+ size_type prev_amount_upload;
+ size_type prev_amount_download;
+
+ // is set to true if this peer has been banned
+ bool banned;
+
+ // a bitmap combining the peer_source flags
+ // from peer_info.
+ int source;
+
+ // if the peer is connected now, this
+ // will refer to a valid peer_connection
+ peer_connection* connection;
+ };
+
+ int num_peers() const { return m_peers.size(); }
+
+ typedef std::multimap<address, peer>::iterator iterator;
+ typedef std::multimap<address, peer>::const_iterator const_iterator;
+ iterator begin_peer() { return m_peers.begin(); }
+ iterator end_peer() { return m_peers.end(); }
+ const_iterator begin_peer() const { return m_peers.begin(); }
+ const_iterator end_peer() const { return m_peers.end(); }
+
+ bool connect_one_peer();
+ bool disconnect_one_peer();
+
+ private:
+/*
+ bool unchoke_one_peer();
+ void choke_one_peer();
+ iterator find_choke_candidate();
+ iterator find_unchoke_candidate();
+
+ // the seed prefix means that the
+ // function is used while seeding.
+ bool seed_unchoke_one_peer();
+ void seed_choke_one_peer();
+ iterator find_seed_choke_candidate();
+ iterator find_seed_unchoke_candidate();
+*/
+ iterator find_disconnect_candidate();
+ iterator find_connect_candidate();
+
+ std::multimap<address, peer> m_peers;
+
+ torrent* m_torrent;
+
+ // free download we have got that hasn't
+ // been distributed yet.
+ size_type m_available_free_upload;
+
+ // if there is a connection limit,
+ // we disconnect one peer every minute in hope of
+ // establishing a connection with a better peer
+// ptime m_last_optimistic_disconnect;
+ };
+
+}
+
+#endif // TORRENT_POLICY_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/session.hpp b/src/libtorrent/include/libtorrent/session.hpp
new file mode 100644
index 0000000..d2ab6ab
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/session.hpp
@@ -0,0 +1,296 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SESSION_HPP_INCLUDED
+#define TORRENT_SESSION_HPP_INCLUDED
+
+#include <ctime>
+#include <algorithm>
+#include <vector>
+#include <set>
+#include <list>
+#include <deque>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/limits.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/thread.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/config.hpp"
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/alert.hpp"
+#include "libtorrent/session_status.hpp"
+#include "libtorrent/version.hpp"
+#include "libtorrent/fingerprint.hpp"
+#include "libtorrent/time.hpp"
+
+#include "libtorrent/storage.hpp"
+
+#ifdef _MSC_VER
+# include <eh.h>
+#endif
+
+namespace libtorrent
+{
+ struct torrent_plugin;
+ class torrent;
+ class ip_filter;
+ class port_filter;
+ class connection_queue;
+
+ namespace fs = boost::filesystem;
+
+ namespace aux
+ {
+ // workaround for microsofts
+ // hardware exceptions that makes
+ // it hard to debug stuff
+#ifdef _MSC_VER
+ struct eh_initializer
+ {
+ eh_initializer()
+ {
+ ::_set_se_translator(straight_to_debugger);
+ }
+
+ static void straight_to_debugger(unsigned int, _EXCEPTION_POINTERS*)
+ { throw; }
+ };
+#else
+ struct eh_initializer {};
+#endif
+ struct session_impl;
+
+ struct filesystem_init
+ {
+ filesystem_init();
+ };
+
+ }
+
+ class TORRENT_EXPORT session_proxy
+ {
+ friend class session;
+ public:
+ session_proxy() {}
+ private:
+ session_proxy(boost::shared_ptr<aux::session_impl> impl)
+ : m_impl(impl) {}
+ boost::shared_ptr<aux::session_impl> m_impl;
+ };
+
+ class TORRENT_EXPORT session: public boost::noncopyable, aux::eh_initializer
+ {
+ public:
+
+ session(fingerprint const& print = fingerprint("LT"
+ , LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0)
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , fs::path logpath = "."
+#endif
+ );
+ session(
+ fingerprint const& print
+ , std::pair<int, int> listen_port_range
+ , char const* listen_interface = "0.0.0.0"
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , fs::path logpath = "."
+#endif
+ );
+
+ ~session();
+
+ // returns a list of all torrents in this session
+ std::vector<torrent_handle> get_torrents() const;
+
+ // returns an invalid handle in case the torrent doesn't exist
+ torrent_handle find_torrent(sha1_hash const& info_hash) const;
+
+ // all torrent_handles must be destructed before the session is destructed!
+ torrent_handle add_torrent(
+ torrent_info const& ti
+ , fs::path const& save_path
+ , entry const& resume_data = entry()
+ , storage_mode_t storage_mode = storage_mode_sparse
+ , bool paused = false
+ , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED;
+
+ torrent_handle add_torrent(
+ boost::intrusive_ptr<torrent_info> ti
+ , fs::path const& save_path
+ , entry const& resume_data = entry()
+ , storage_mode_t storage_mode = storage_mode_sparse
+ , bool paused = false
+ , storage_constructor_type sc = default_storage_constructor
+ , void* userdata = 0);
+
+ torrent_handle add_torrent(
+ char const* tracker_url
+ , sha1_hash const& info_hash
+ , char const* name
+ , fs::path const& save_path
+ , entry const& resume_data = entry()
+ , storage_mode_t storage_mode = storage_mode_sparse
+ , bool paused = false
+ , storage_constructor_type sc = default_storage_constructor
+ , void* userdata = 0);
+
+ session_proxy abort() { return session_proxy(m_impl); }
+
+ session_status status() const;
+
+#ifndef TORRENT_DISABLE_DHT
+ void start_dht(entry const& startup_state = entry());
+ void stop_dht();
+ void set_dht_settings(dht_settings const& settings);
+ entry dht_state() const;
+ void add_dht_node(std::pair<std::string, int> const& node);
+ void add_dht_router(std::pair<std::string, int> const& node);
+#endif
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ void set_pe_settings(pe_settings const& settings);
+ pe_settings const& get_pe_settings() const;
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext);
+#endif
+
+ void set_ip_filter(ip_filter const& f);
+ void set_port_filter(port_filter const& f);
+ void set_peer_id(peer_id const& pid);
+ void set_key(int key);
+ peer_id id() const;
+
+ bool is_listening() const;
+
+ // if the listen port failed in some way
+ // you can retry to listen on another port-
+ // range with this function. If the listener
+ // succeeded and is currently listening,
+ // a call to this function will shut down the
+ // listen port and reopen it using these new
+ // properties (the given interface and port range).
+ // As usual, if the interface is left as 0
+ // this function will return false on failure.
+ // If it fails, it will also generate alerts describing
+ // the error. It will return true on success.
+ bool listen_on(
+ std::pair<int, int> const& port_range
+ , const char* net_interface = 0);
+
+ // returns the port we ended up listening on
+ unsigned short listen_port() const;
+
+ // Get the number of uploads.
+ int num_uploads() const;
+
+ // Get the number of connections. This number also contains the
+ // number of half open connections.
+ int num_connections() const;
+
+ enum options_t
+ {
+ none = 0,
+ delete_files = 1
+ };
+
+ void remove_torrent(const torrent_handle& h, int options = none);
+
+ void set_settings(session_settings const& s);
+ session_settings const& settings();
+
+ void set_peer_proxy(proxy_settings const& s);
+ void set_web_seed_proxy(proxy_settings const& s);
+ void set_tracker_proxy(proxy_settings const& s);
+
+ proxy_settings const& peer_proxy() const;
+ proxy_settings const& web_seed_proxy() const;
+ proxy_settings const& tracker_proxy() const;
+
+#ifndef TORRENT_DISABLE_DHT
+ void set_dht_proxy(proxy_settings const& s);
+ proxy_settings const& dht_proxy() const;
+#endif
+
+ int upload_rate_limit() const;
+ int download_rate_limit() const;
+ int max_half_open_connections() const;
+
+ void set_upload_rate_limit(int bytes_per_second);
+ void set_download_rate_limit(int bytes_per_second);
+ void set_max_uploads(int limit);
+ void set_max_connections(int limit);
+ void set_max_half_open_connections(int limit);
+
+ std::auto_ptr<alert> pop_alert();
+ void set_severity_level(alert::severity_t s);
+
+ alert const* wait_for_alert(time_duration max_wait);
+
+ connection_queue& get_connection_queue();
+
+ // starts/stops UPnP, NATPMP or LSD port mappers
+ // they are stopped by default
+ void start_lsd();
+ void start_natpmp();
+ void start_upnp();
+
+ void stop_lsd();
+ void stop_natpmp();
+ void stop_upnp();
+
+ private:
+
+ // just a way to initialize boost.filesystem
+ // before the session_impl is created
+ aux::filesystem_init m_dummy;
+
+ // data shared between the main thread
+ // and the working thread
+ boost::shared_ptr<aux::session_impl> m_impl;
+ };
+
+}
+
+#endif // TORRENT_SESSION_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/session_settings.hpp b/src/libtorrent/include/libtorrent/session_settings.hpp
new file mode 100644
index 0000000..2817d27
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/session_settings.hpp
@@ -0,0 +1,369 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SESSION_SETTINGS_HPP_INCLUDED
+#define TORRENT_SESSION_SETTINGS_HPP_INCLUDED
+
+#include "libtorrent/version.hpp"
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+
+ struct TORRENT_EXPORT proxy_settings
+ {
+ proxy_settings() : port(0), type(none) {}
+
+ std::string hostname;
+ int port;
+
+ std::string username;
+ std::string password;
+
+ enum proxy_type
+ {
+ // a plain tcp socket is used, and
+ // the other settings are ignored.
+ none,
+ // socks4 server, requires username.
+ socks4,
+ // the hostname and port settings are
+ // used to connect to the proxy. No
+ // username or password is sent.
+ socks5,
+ // the hostname and port are used to
+ // connect to the proxy. the username
+ // and password are used to authenticate
+ // with the proxy server.
+ socks5_pw,
+ // the http proxy is only available for
+ // tracker and web seed traffic
+ // assumes anonymous access to proxy
+ http,
+ // http proxy with basic authentication
+ // uses username and password
+ http_pw
+ };
+
+ proxy_type type;
+
+ };
+
+ struct TORRENT_EXPORT session_settings
+ {
+ session_settings(std::string const& user_agent_ = "libtorrent/"
+ LIBTORRENT_VERSION)
+ : user_agent(user_agent_)
+ , tracker_completion_timeout(60)
+ , tracker_receive_timeout(40)
+ , stop_tracker_timeout(5)
+ , tracker_maximum_response_length(1024*1024)
+ , piece_timeout(10)
+ , request_queue_time(3.f)
+ , max_allowed_in_request_queue(250)
+ , max_out_request_queue(200)
+ , whole_pieces_threshold(20)
+ , peer_timeout(120)
+ , urlseed_timeout(20)
+ , urlseed_pipeline_size(5)
+ , urlseed_wait_retry(30)
+ , file_pool_size(40)
+ , allow_multiple_connections_per_ip(false)
+ , max_failcount(3)
+ , min_reconnect_time(60)
+ , peer_connect_timeout(7)
+ , ignore_limits_on_local_network(true)
+ , connection_speed(20)
+ , send_redundant_have(false)
+ , lazy_bitfields(true)
+ , inactivity_timeout(600)
+ , unchoke_interval(15)
+ , optimistic_unchoke_multiplier(4)
+ , num_want(200)
+ , initial_picker_threshold(4)
+ , allowed_fast_set_size(10)
+ , max_outstanding_disk_bytes_per_connection(64 * 1024)
+ , handshake_timeout(10)
+#ifndef TORRENT_DISABLE_DHT
+ , use_dht_as_fallback(true)
+#endif
+ , free_torrent_hashes(true)
+ , upnp_ignore_nonrouters(true)
+ {}
+
+ // this is the user agent that will be sent to the tracker
+ // when doing requests. It is used to identify the client.
+ // It cannot contain \r or \n
+ std::string user_agent;
+
+ // the number of seconds to wait until giving up on a
+ // tracker request if it hasn't finished
+ int tracker_completion_timeout;
+
+ // the number of seconds where no data is received
+ // from the tracker until it should be considered
+ // as timed out
+ int tracker_receive_timeout;
+
+ // the time to wait when sending a stopped message
+ // before considering a tracker to have timed out.
+ // this is usually shorter, to make the client quit
+ // faster
+ int stop_tracker_timeout;
+
+ // if the content-length is greater than this value
+ // the tracker connection will be aborted
+ int tracker_maximum_response_length;
+
+ // the number of seconds from a request is sent until
+ // it times out if no piece response is returned.
+ int piece_timeout;
+
+ // the length of the request queue given in the number
+ // of seconds it should take for the other end to send
+ // all the pieces. i.e. the actual number of requests
+ // depends on the download rate and this number.
+ float request_queue_time;
+
+ // the number of outstanding block requests a peer is
+ // allowed to queue up in the client. If a peer sends
+ // more requests than this (before the first one has
+ // been sent) the last request will be dropped.
+ // the higher this is, the faster upload speeds the
+ // client can get to a single peer.
+ int max_allowed_in_request_queue;
+
+ // the maximum number of outstanding requests to
+ // send to a peer. This limit takes precedence over
+ // request_queue_time.
+ int max_out_request_queue;
+
+ // if a whole piece can be downloaded in this number
+ // of seconds, or less, the peer_connection will prefer
+ // to request whole pieces at a time from this peer.
+ // The benefit of this is to better utilize disk caches by
+ // doing localized accesses and also to make it easier
+ // to identify bad peers if a piece fails the hash check.
+ int whole_pieces_threshold;
+
+ // the number of seconds to wait for any activity on
+ // the peer wire before closing the connectiong due
+ // to time out.
+ int peer_timeout;
+
+ // same as peer_timeout, but only applies to url-seeds.
+ // this is usually set lower, because web servers are
+ // expected to be more reliable.
+ int urlseed_timeout;
+
+ // controls the pipelining size of url-seeds
+ int urlseed_pipeline_size;
+
+ // time to wait until a new retry takes place
+ int urlseed_wait_retry;
+
+ // sets the upper limit on the total number of files this
+ // session will keep open. The reason why files are
+ // left open at all is that some anti virus software
+ // hooks on every file close, and scans the file for
+ // viruses. deferring the closing of the files will
+ // be the difference between a usable system and
+ // a completely hogged down system. Most operating
+ // systems also has a limit on the total number of
+ // file descriptors a process may have open. It is
+ // usually a good idea to find this limit and set the
+ // number of connections and the number of files
+ // limits so their sum is slightly below it.
+ int file_pool_size;
+
+ // false to not allow multiple connections from the same
+ // IP address. true will allow it.
+ bool allow_multiple_connections_per_ip;
+
+ // the number of times we can fail to connect to a peer
+ // before we stop retrying it.
+ int max_failcount;
+
+ // the number of seconds to wait to reconnect to a peer.
+ // this time is multiplied with the failcount.
+ int min_reconnect_time;
+
+ // this is the timeout for a connection attempt. If
+ // the connect does not succeed within this time, the
+ // connection is dropped. The time is specified in seconds.
+ int peer_connect_timeout;
+
+ // if set to true, upload, download and unchoke limits
+ // are ignored for peers on the local network.
+ bool ignore_limits_on_local_network;
+
+ // the number of connection attempts that
+ // are made per second.
+ int connection_speed;
+
+ // if this is set to true, have messages will be sent
+ // to peers that already have the piece. This is
+ // typically not necessary, but it might be necessary
+ // for collecting statistics in some cases. Default is false.
+ bool send_redundant_have;
+
+ // if this is true, outgoing bitfields will never be fuil. If the
+ // client is seed, a few bits will be set to 0, and later filled
+ // in with have messages. This is to prevent certain ISPs
+ // from stopping people from seeding.
+ bool lazy_bitfields;
+
+ // if a peer is uninteresting and uninterested for longer
+ // than this number of seconds, it will be disconnected.
+ // default is 10 minutes
+ int inactivity_timeout;
+
+ // the number of seconds between chokes/unchokes
+ int unchoke_interval;
+
+ // the number of unchoke intervals between
+ // optimistic unchokes
+ int optimistic_unchoke_multiplier;
+
+ // if this is set, this IP will be reported do the
+ // tracker in the ip= parameter.
+ address announce_ip;
+
+ // the num want sent to trackers
+ int num_want;
+
+ // while we have fewer pieces than this, pick
+ // random pieces instead of rarest first.
+ int initial_picker_threshold;
+
+ // the number of allowed pieces to send to peers
+ // that supports the fast extensions
+ int allowed_fast_set_size;
+
+ // the maximum number of bytes a connection may have
+ // pending in the disk write queue before its download
+ // rate is being throttled. This prevents fast downloads
+ // to slow medias to allocate more and more memory
+ // indefinitely. This should be set to at least 32 kB
+ // to not completely disrupt normal downloads.
+ int max_outstanding_disk_bytes_per_connection;
+
+ // the number of seconds to wait for a handshake
+ // response from a peer. If no response is received
+ // within this time, the peer is disconnected.
+ int handshake_timeout;
+
+#ifndef TORRENT_DISABLE_DHT
+ // while this is true, the dht will note be used unless the
+ // tracker is online
+ bool use_dht_as_fallback;
+#endif
+
+ // if this is true, the piece hashes will be freed, in order
+ // to save memory, once the torrent is seeding. This will
+ // make the get_torrent_info() function to return an incomplete
+ // torrent object that cannot be passed back to add_torrent()
+ bool free_torrent_hashes;
+
+ // when this is true, the upnp port mapper will ignore
+ // any upnp devices that don't have an address that matches
+ // our currently configured router.
+ bool upnp_ignore_nonrouters;
+ };
+
+#ifndef TORRENT_DISABLE_DHT
+ struct dht_settings
+ {
+ dht_settings()
+ : max_peers_reply(50)
+ , search_branching(5)
+ , service_port(0)
+ , max_fail_count(20)
+ {}
+
+ // the maximum number of peers to send in a
+ // reply to get_peers
+ int max_peers_reply;
+
+ // the number of simultanous "connections" when
+ // searching the DHT.
+ int search_branching;
+
+ // the listen port for the dht. This is a UDP port.
+ // zero means use the same as the tcp interface
+ int service_port;
+
+ // the maximum number of times a node can fail
+ // in a row before it is removed from the table.
+ int max_fail_count;
+ };
+#endif
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+
+ struct pe_settings
+ {
+ pe_settings()
+ : out_enc_policy(enabled)
+ , in_enc_policy(enabled)
+ , allowed_enc_level(both)
+ , prefer_rc4(false)
+ {}
+
+ enum enc_policy
+ {
+ forced, // disallow non encrypted connections
+ enabled, // allow encrypted and non encrypted connections
+ disabled // disallow encrypted connections
+ };
+
+ enum enc_level
+ {
+ plaintext, // use only plaintext encryption
+ rc4, // use only rc4 encryption
+ both // allow both
+ };
+
+ enc_policy out_enc_policy;
+ enc_policy in_enc_policy;
+
+ enc_level allowed_enc_level;
+ // if the allowed encryption level is both, setting this to
+ // true will prefer rc4 if both methods are offered, plaintext
+ // otherwise
+ bool prefer_rc4;
+ };
+#endif
+
+}
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/size_type.hpp b/src/libtorrent/include/libtorrent/size_type.hpp
new file mode 100644
index 0000000..6020a5a
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/size_type.hpp
@@ -0,0 +1,52 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SIZE_TYPE_HPP_INCLUDED
+#define TORRENT_SIZE_TYPE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/cstdint.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace libtorrent
+{
+ typedef boost::int64_t size_type;
+}
+
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/socket.hpp b/src/libtorrent/include/libtorrent/socket.hpp
new file mode 100644
index 0000000..499842d
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/socket.hpp
@@ -0,0 +1,192 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SOCKET_HPP_INCLUDED
+#define TORRENT_SOCKET_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+// if building as Objective C++, asio's template
+// parameters Protocol has to be renamed to avoid
+// colliding with keywords
+
+#ifdef __OBJC__
+#define Protocol Protocol_
+#endif
+
+#include <asio/ip/tcp.hpp>
+#include <asio/ip/udp.hpp>
+#include <asio/io_service.hpp>
+#include <asio/deadline_timer.hpp>
+#include <asio/write.hpp>
+#include <asio/strand.hpp>
+#include <asio/time_traits.hpp>
+#include <asio/basic_deadline_timer.hpp>
+
+#ifdef __OBJC__
+#undef Protocol
+#endif
+
+#include "libtorrent/io.hpp"
+#include "libtorrent/time.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace libtorrent
+{
+
+/*
+ namespace asio = boost::asio;
+
+ using boost::asio::ipv4::tcp;
+ using boost::asio::ipv4::address;
+ using boost::asio::stream_socket;
+ using boost::asio::datagram_socket;
+ using boost::asio::socket_acceptor;
+ using boost::asio::io_service;
+ using boost::asio::ipv4::host_resolver;
+ using boost::asio::async_write;
+ using boost::asio::ipv4::host;
+ using boost::asio::deadline_timer;
+*/
+// namespace asio = ::asio;
+
+ using asio::ip::tcp;
+ using asio::ip::udp;
+ typedef asio::ip::tcp::socket stream_socket;
+ typedef asio::ip::address address;
+ typedef asio::ip::address_v4 address_v4;
+ typedef asio::ip::address_v6 address_v6;
+ typedef asio::ip::udp::socket datagram_socket;
+ typedef asio::ip::tcp::acceptor socket_acceptor;
+ typedef asio::io_service io_service;
+
+ using asio::async_write;
+
+ typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer;
+
+ inline std::ostream& print_endpoint(std::ostream& os, tcp::endpoint const& ep)
+ {
+ address const& addr = ep.address();
+ asio::error_code ec;
+ std::string a = addr.to_string(ec);
+ if (ec) return os;
+
+ if (addr.is_v6())
+ os << "[" << a << "]:";
+ else
+ os << a << ":";
+ os << ep.port();
+ return os;
+ }
+
+ namespace detail
+ {
+ template<class OutIt>
+ void write_address(address const& a, OutIt& out)
+ {
+ if (a.is_v4())
+ {
+ write_uint32(a.to_v4().to_ulong(), out);
+ }
+ else if (a.is_v6())
+ {
+ asio::ip::address_v6::bytes_type bytes
+ = a.to_v6().to_bytes();
+ std::copy(bytes.begin(), bytes.end(), out);
+ }
+ }
+
+ template<class InIt>
+ address read_v4_address(InIt& in)
+ {
+ unsigned long ip = read_uint32(in);
+ return asio::ip::address_v4(ip);
+ }
+
+ template<class InIt>
+ address read_v6_address(InIt& in)
+ {
+ typedef asio::ip::address_v6::bytes_type bytes_t;
+ bytes_t bytes;
+ for (bytes_t::iterator i = bytes.begin()
+ , end(bytes.end()); i != end; ++i)
+ *i = read_uint8(in);
+ return asio::ip::address_v6(bytes);
+ }
+
+ template<class Endpoint, class OutIt>
+ void write_endpoint(Endpoint const& e, OutIt& out)
+ {
+ write_address(e.address(), out);
+ write_uint16(e.port(), out);
+ }
+
+ template<class Endpoint, class InIt>
+ Endpoint read_v4_endpoint(InIt& in)
+ {
+ address addr = read_v4_address(in);
+ int port = read_uint16(in);
+ return Endpoint(addr, port);
+ }
+
+ template<class Endpoint, class InIt>
+ Endpoint read_v6_endpoint(InIt& in)
+ {
+ address addr = read_v6_address(in);
+ int port = read_uint16(in);
+ return Endpoint(addr, port);
+ }
+ }
+
+ struct v6only
+ {
+ v6only(bool enable): m_value(enable) {}
+ template<class Protocol>
+ int level(Protocol const&) const { return IPPROTO_IPV6; }
+ template<class Protocol>
+ int name(Protocol const&) const { return IPV6_V6ONLY; }
+ template<class Protocol>
+ int const* data(Protocol const&) const { return &m_value; }
+ template<class Protocol>
+ size_t size(Protocol const&) const { return sizeof(m_value); }
+ int m_value;
+ };
+
+}
+
+#endif // TORRENT_SOCKET_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/socket_type.hpp b/src/libtorrent/include/libtorrent/socket_type.hpp
new file mode 100644
index 0000000..9ed8f9a
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/socket_type.hpp
@@ -0,0 +1,51 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SOCKET_TYPE
+#define TORRENT_SOCKET_TYPE
+
+#include "libtorrent/socks5_stream.hpp"
+#include "libtorrent/socks4_stream.hpp"
+#include "libtorrent/http_stream.hpp"
+#include "libtorrent/variant_stream.hpp"
+
+namespace libtorrent
+{
+ typedef variant_stream<
+ stream_socket
+ , socks5_stream
+ , socks4_stream
+ , http_stream> socket_type;
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/socks4_stream.hpp b/src/libtorrent/include/libtorrent/socks4_stream.hpp
new file mode 100644
index 0000000..9530f9d
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/socks4_stream.hpp
@@ -0,0 +1,92 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SOCKS4_STREAM_HPP_INCLUDED
+#define TORRENT_SOCKS4_STREAM_HPP_INCLUDED
+
+#include "libtorrent/proxy_base.hpp"
+
+namespace libtorrent {
+
+class socks4_stream : public proxy_base
+{
+public:
+
+ explicit socks4_stream(asio::io_service& io_service)
+ : proxy_base(io_service)
+ {}
+
+ void set_username(std::string const& user)
+ {
+ m_user = user;
+ }
+
+ typedef boost::function<void(asio::error_code const&)> handler_type;
+
+ template <class Handler>
+ void async_connect(endpoint_type const& endpoint, Handler const& handler)
+ {
+ m_remote_endpoint = endpoint;
+
+ // the connect is split up in the following steps:
+ // 1. resolve name of proxy server
+ // 2. connect to proxy server
+ // 3. send SOCKS4 CONNECT message
+
+ // to avoid unnecessary copying of the handler,
+ // store it in a shaed_ptr
+ boost::shared_ptr<handler_type> h(new handler_type(handler));
+
+ tcp::resolver::query q(m_hostname
+ , boost::lexical_cast<std::string>(m_port));
+ m_resolver.async_resolve(q, boost::bind(
+ &socks4_stream::name_lookup, this, _1, _2, h));
+ }
+
+private:
+
+ void name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , boost::shared_ptr<handler_type> h);
+ void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+
+ // send and receive buffer
+ std::vector<char> m_buffer;
+ // proxy authentication
+ std::string m_user;
+};
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/socks5_stream.hpp b/src/libtorrent/include/libtorrent/socks5_stream.hpp
new file mode 100644
index 0000000..622557c
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/socks5_stream.hpp
@@ -0,0 +1,104 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_SOCKS5_STREAM_HPP_INCLUDED
+#define TORRENT_SOCKS5_STREAM_HPP_INCLUDED
+
+#include "libtorrent/proxy_base.hpp"
+
+namespace libtorrent {
+
+class socks5_stream : public proxy_base
+{
+public:
+
+ explicit socks5_stream(asio::io_service& io_service)
+ : proxy_base(io_service)
+ {}
+
+ void set_username(std::string const& user
+ , std::string const& password)
+ {
+ m_user = user;
+ m_password = password;
+ }
+
+ typedef boost::function<void(asio::error_code const&)> handler_type;
+
+ template <class Handler>
+ void async_connect(endpoint_type const& endpoint, Handler const& handler)
+ {
+ m_remote_endpoint = endpoint;
+
+ // the connect is split up in the following steps:
+ // 1. resolve name of proxy server
+ // 2. connect to proxy server
+ // 3. send SOCKS5 authentication method message
+ // 4. read SOCKS5 authentication response
+ // 5. send username+password
+ // 6. send SOCKS5 CONNECT message
+
+ // to avoid unnecessary copying of the handler,
+ // store it in a shaed_ptr
+ boost::shared_ptr<handler_type> h(new handler_type(handler));
+
+ tcp::resolver::query q(m_hostname
+ , boost::lexical_cast<std::string>(m_port));
+ m_resolver.async_resolve(q, boost::bind(
+ &socks5_stream::name_lookup, this, _1, _2, h));
+ }
+
+private:
+
+ void name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , boost::shared_ptr<handler_type> h);
+ void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake3(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void handshake4(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void socks_connect(boost::shared_ptr<handler_type> h);
+ void connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+ void connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h);
+
+ // send and receive buffer
+ std::vector<char> m_buffer;
+ // proxy authentication
+ std::string m_user;
+ std::string m_password;
+};
+
+}
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/stat.hpp b/src/libtorrent/include/libtorrent/stat.hpp
new file mode 100644
index 0000000..ef9b778
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/stat.hpp
@@ -0,0 +1,196 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_STAT_HPP_INCLUDED
+#define TORRENT_STAT_HPP_INCLUDED
+
+#include <algorithm>
+#include <vector>
+#include <assert.h>
+
+#include "libtorrent/size_type.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ class TORRENT_EXPORT stat
+ {
+ friend class invariant_access;
+ public:
+ enum { history = 10 };
+
+ stat()
+ : m_downloaded_payload(0)
+ , m_uploaded_payload(0)
+ , m_downloaded_protocol(0)
+ , m_uploaded_protocol(0)
+ , m_total_download_payload(0)
+ , m_total_upload_payload(0)
+ , m_total_download_protocol(0)
+ , m_total_upload_protocol(0)
+ , m_mean_download_rate(0)
+ , m_mean_upload_rate(0)
+ , m_mean_download_payload_rate(0)
+ , m_mean_upload_payload_rate(0)
+ {
+ std::fill(m_download_rate_history, m_download_rate_history+history, 0.f);
+ std::fill(m_upload_rate_history, m_upload_rate_history+history, 0.f);
+ std::fill(m_download_payload_rate_history, m_download_payload_rate_history+history, 0.f);
+ std::fill(m_upload_payload_rate_history, m_upload_payload_rate_history+history, 0.f);
+ }
+
+ void operator+=(const stat& s)
+ {
+ INVARIANT_CHECK;
+
+ m_downloaded_payload += s.m_downloaded_payload;
+ m_total_download_payload += s.m_downloaded_payload;
+ m_downloaded_protocol += s.m_downloaded_protocol;
+ m_total_download_protocol += s.m_downloaded_protocol;
+
+ m_uploaded_payload += s.m_uploaded_payload;
+ m_total_upload_payload += s.m_uploaded_payload;
+ m_uploaded_protocol += s.m_uploaded_protocol;
+ m_total_upload_protocol += s.m_uploaded_protocol;
+ }
+
+ void received_bytes(int bytes_payload, int bytes_protocol)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(bytes_payload >= 0);
+ TORRENT_ASSERT(bytes_protocol >= 0);
+
+ m_downloaded_payload += bytes_payload;
+ m_total_download_payload += bytes_payload;
+ m_downloaded_protocol += bytes_protocol;
+ m_total_download_protocol += bytes_protocol;
+ }
+
+ void sent_bytes(int bytes_payload, int bytes_protocol)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(bytes_payload >= 0);
+ TORRENT_ASSERT(bytes_protocol >= 0);
+
+ m_uploaded_payload += bytes_payload;
+ m_total_upload_payload += bytes_payload;
+ m_uploaded_protocol += bytes_protocol;
+ m_total_upload_protocol += bytes_protocol;
+ }
+
+ // should be called once every second
+ void second_tick(float tick_interval);
+
+ float upload_rate() const { return m_mean_upload_rate; }
+ float download_rate() const { return m_mean_download_rate; }
+
+ float upload_payload_rate() const { return m_mean_upload_payload_rate; }
+ float download_payload_rate() const { return m_mean_download_payload_rate; }
+
+ size_type total_payload_upload() const { return m_total_upload_payload; }
+ size_type total_payload_download() const { return m_total_download_payload; }
+
+ size_type total_protocol_upload() const { return m_total_upload_protocol; }
+ size_type total_protocol_download() const { return m_total_download_protocol; }
+
+ // this is used to offset the statistics when a
+ // peer_connection is opened and have some previous
+ // transfers from earlier connections.
+ void add_stat(size_type downloaded, size_type uploaded)
+ {
+ TORRENT_ASSERT(downloaded >= 0);
+ TORRENT_ASSERT(uploaded >= 0);
+ m_total_download_payload += downloaded;
+ m_total_upload_payload += uploaded;
+ }
+
+ private:
+
+#ifndef NDEBUG
+ void check_invariant() const
+ {
+ TORRENT_ASSERT(m_mean_upload_rate >= 0);
+ TORRENT_ASSERT(m_mean_download_rate >= 0);
+ TORRENT_ASSERT(m_mean_upload_payload_rate >= 0);
+ TORRENT_ASSERT(m_mean_download_payload_rate >= 0);
+ TORRENT_ASSERT(m_total_upload_payload >= 0);
+ TORRENT_ASSERT(m_total_download_payload >= 0);
+ TORRENT_ASSERT(m_total_upload_protocol >= 0);
+ TORRENT_ASSERT(m_total_download_protocol >= 0);
+ }
+#endif
+
+ // history of download/upload speeds a few seconds back
+ float m_download_rate_history[history];
+ float m_upload_rate_history[history];
+
+ float m_download_payload_rate_history[history];
+ float m_upload_payload_rate_history[history];
+
+ // the accumulators we are adding the downloads/uploads
+ // to this second. This only counts the actual payload
+ // and ignores the bytes sent as protocol chatter.
+ int m_downloaded_payload;
+ int m_uploaded_payload;
+
+ // the accumulators we are adding the downloads/uploads
+ // to this second. This only counts the protocol
+ // chatter and ignores the actual payload
+ int m_downloaded_protocol;
+ int m_uploaded_protocol;
+
+ // total download/upload counters
+ // only counting payload data
+ size_type m_total_download_payload;
+ size_type m_total_upload_payload;
+
+ // total download/upload counters
+ // only counting protocol chatter
+ size_type m_total_download_protocol;
+ size_type m_total_upload_protocol;
+
+ // current mean download/upload rates
+ float m_mean_download_rate;
+ float m_mean_upload_rate;
+
+ float m_mean_download_payload_rate;
+ float m_mean_upload_payload_rate;
+ };
+
+}
+
+#endif // TORRENT_STAT_HPP_INCLUDED
diff --git a/src/libtorrent/include/libtorrent/storage.hpp b/src/libtorrent/include/libtorrent/storage.hpp
new file mode 100644
index 0000000..a7b5e37
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/storage.hpp
@@ -0,0 +1,387 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_STORAGE_HPP_INCLUDE
+#define TORRENT_STORAGE_HPP_INCLUDE
+
+#include <vector>
+#include <bitset>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/limits.hpp>
+#include <boost/thread.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/filesystem/path.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/piece_picker.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/buffer.hpp"
+
+namespace libtorrent
+{
+ namespace aux
+ {
+ struct piece_checker_data;
+ }
+
+ namespace fs = boost::filesystem;
+
+ class session;
+ struct file_pool;
+ struct disk_io_job;
+
+ enum storage_mode_t
+ {
+ storage_mode_allocate = 0,
+ storage_mode_sparse,
+ storage_mode_compact
+ };
+
+#if defined(_WIN32) && defined(UNICODE)
+
+ TORRENT_EXPORT std::wstring safe_convert(std::string const& s);
+
+#endif
+
+ TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
+ torrent_info const& t
+ , fs::path p);
+
+ TORRENT_EXPORT bool match_filesizes(
+ torrent_info const& t
+ , fs::path p
+ , std::vector<std::pair<size_type, std::time_t> > const& sizes
+ , bool compact_mode
+ , std::string* error = 0);
+
+ struct TORRENT_EXPORT file_allocation_failed: std::exception
+ {
+ file_allocation_failed(const char* error_msg): m_msg(error_msg) {}
+ virtual const char* what() const throw() { return m_msg.c_str(); }
+ virtual ~file_allocation_failed() throw() {}
+ std::string m_msg;
+ };
+
+ struct TORRENT_EXPORT partial_hash
+ {
+ partial_hash(): offset(0) {}
+ // the number of bytes in the piece that has been hashed
+ int offset;
+ // the sha-1 context
+ hasher h;
+ };
+
+ struct TORRENT_EXPORT storage_interface
+ {
+ // create directories and set file sizes
+ // if allocate_files is true.
+ // allocate_files is true if allocation mode
+ // is set to full and sparse files are supported
+ virtual void initialize(bool allocate_files) = 0;
+
+ // may throw file_error if storage for slot does not exist
+ virtual size_type read(char* buf, int slot, int offset, int size) = 0;
+
+ // may throw file_error if storage for slot hasn't been allocated
+ virtual void write(const char* buf, int slot, int offset, int size) = 0;
+
+ virtual bool move_storage(fs::path save_path) = 0;
+
+ // verify storage dependent fast resume entries
+ virtual bool verify_resume_data(entry& rd, std::string& error) = 0;
+
+ // write storage dependent fast resume entries
+ virtual void write_resume_data(entry& rd) const = 0;
+
+ // moves (or copies) the content in src_slot to dst_slot
+ virtual void move_slot(int src_slot, int dst_slot) = 0;
+
+ // swaps the data in slot1 and slot2
+ virtual void swap_slots(int slot1, int slot2) = 0;
+
+ // swaps the puts the data in slot1 in slot2, the data in slot2
+ // in slot3 and the data in slot3 in slot1
+ virtual void swap_slots3(int slot1, int slot2, int slot3) = 0;
+
+ // returns the sha1-hash for the data at the given slot
+ virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0;
+
+ // this will close all open files that are opened for
+ // writing. This is called when a torrent has finished
+ // downloading.
+ virtual void release_files() = 0;
+
+ // this will close all open files and delete them
+ virtual void delete_files() = 0;
+
+ virtual ~storage_interface() {}
+ };
+
+ typedef storage_interface* (&storage_constructor_type)(
+ boost::intrusive_ptr<torrent_info const>, fs::path const&
+ , file_pool&);
+
+ TORRENT_EXPORT storage_interface* default_storage_constructor(
+ boost::intrusive_ptr<torrent_info const> ti
+ , fs::path const& path, file_pool& fp);
+
+ struct disk_io_thread;
+
+ class TORRENT_EXPORT piece_manager
+ : public intrusive_ptr_base<piece_manager>
+ , boost::noncopyable
+ {
+ friend class invariant_access;
+ friend struct disk_io_thread;
+ public:
+
+ piece_manager(
+ boost::shared_ptr<void> const& torrent
+ , boost::intrusive_ptr<torrent_info const> ti
+ , fs::path const& path
+ , file_pool& fp
+ , disk_io_thread& io
+ , storage_constructor_type sc);
+
+ ~piece_manager();
+
+ bool check_fastresume(aux::piece_checker_data& d
+ , std::vector<bool>& pieces, int& num_pieces, storage_mode_t storage_mode
+ , std::string& error_msg);
+ std::pair<bool, float> check_files(std::vector<bool>& pieces
+ , int& num_pieces, boost::recursive_mutex& mutex);
+
+ // frees a buffer that was returned from a read operation
+ void free_buffer(char* buf);
+
+ void write_resume_data(entry& rd) const;
+ bool verify_resume_data(entry& rd, std::string& error);
+
+ bool is_allocating() const
+ { return m_state == state_expand_pieces; }
+
+ void mark_failed(int index);
+
+ unsigned long piece_crc(
+ int slot_index
+ , int block_size
+ , piece_picker::block_info const* bi);
+
+ int slot_for(int piece) const;
+ int piece_for(int slot) const;
+
+ void async_read(
+ peer_request const& r
+ , boost::function<void(int, disk_io_job const&)> const& handler
+ , char* buffer = 0
+ , int priority = 0);
+
+ void async_write(
+ peer_request const& r
+ , char const* buffer
+ , boost::function<void(int, disk_io_job const&)> const& f);
+
+ void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);
+
+ fs::path save_path() const;
+
+ void async_release_files(
+ boost::function<void(int, disk_io_job const&)> const& handler
+ = boost::function<void(int, disk_io_job const&)>());
+
+ void async_delete_files(
+ boost::function<void(int, disk_io_job const&)> const& handler
+ = boost::function<void(int, disk_io_job const&)>());
+
+ void async_move_storage(fs::path const& p
+ , boost::function<void(int, disk_io_job const&)> const& handler);
+
+ // fills the vector that maps all allocated
+ // slots to the piece that is stored (or
+ // partially stored) there. -2 is the index
+ // of unassigned pieces and -1 is unallocated
+ void export_piece_map(std::vector<int>& pieces
+ , std::vector<bool> const& have) const;
+
+ bool compact_allocation() const
+ { return m_storage_mode == storage_mode_compact; }
+
+#ifndef NDEBUG
+ std::string name() const { return m_info->name(); }
+#endif
+
+ private:
+
+ bool allocate_slots(int num_slots, bool abort_on_disk = false);
+
+ int identify_data(
+ const std::vector<char>& piece_data
+ , int current_slot
+ , std::vector<bool>& have_pieces
+ , int& num_pieces
+ , const std::multimap<sha1_hash, int>& hash_to_piece
+ , boost::recursive_mutex& mutex);
+
+ size_type read_impl(
+ char* buf
+ , int piece_index
+ , int offset
+ , int size);
+
+ void write_impl(
+ const char* buf
+ , int piece_index
+ , int offset
+ , int size);
+
+ void switch_to_full_mode();
+ sha1_hash hash_for_piece_impl(int piece);
+
+ void release_files_impl() { m_storage->release_files(); }
+ void delete_files_impl() { m_storage->delete_files(); }
+
+ bool move_storage_impl(fs::path const& save_path);
+
+ int allocate_slot_for_piece(int piece_index);
+#ifndef NDEBUG
+ void check_invariant() const;
+#ifdef TORRENT_STORAGE_DEBUG
+ void debug_log() const;
+#endif
+#endif
+ boost::scoped_ptr<storage_interface> m_storage;
+
+ storage_mode_t m_storage_mode;
+
+ boost::intrusive_ptr<torrent_info const> m_info;
+
+ // slots that haven't had any file storage allocated
+ std::vector<int> m_unallocated_slots;
+ // slots that have file storage, but isn't assigned to a piece
+ std::vector<int> m_free_slots;
+
+ enum
+ {
+ has_no_slot = -3 // the piece has no storage
+ };
+
+ // maps piece indices to slots. If a piece doesn't
+ // have any storage, it is set to 'has_no_slot'
+ std::vector<int> m_piece_to_slot;
+
+ enum
+ {
+ unallocated = -1, // the slot is unallocated
+ unassigned = -2 // the slot is allocated but not assigned to a piece
+ };
+
+ // maps slots to piece indices, if a slot doesn't have a piece
+ // it can either be 'unassigned' or 'unallocated'
+ std::vector<int> m_slot_to_piece;
+
+ fs::path m_save_path;
+
+ mutable boost::recursive_mutex m_mutex;
+
+ enum {
+ // the default initial state
+ state_none,
+ // the file checking is complete
+ state_finished,
+ // creating the directories
+ state_create_files,
+ // checking the files
+ state_full_check,
+ // move pieces to their final position
+ state_expand_pieces
+ } m_state;
+ int m_current_slot;
+ // used during check. If any piece is found
+ // that is not in its final position, this
+ // is set to true
+ bool m_out_of_place;
+ // used to move pieces while expanding
+ // the storage from compact allocation
+ // to full allocation
+ buffer m_scratch_buffer;
+ buffer m_scratch_buffer2;
+ // the piece that is in the scratch buffer
+ int m_scratch_piece;
+
+ // this is saved in case we need to instantiate a new
+ // storage (osed when remapping files)
+ storage_constructor_type m_storage_constructor;
+
+ // temporary buffer used while checking
+ std::vector<char> m_piece_data;
+
+ // this maps a piece hash to piece index. It will be
+ // build the first time it is used (to save time if it
+ // isn't needed)
+ std::multimap<sha1_hash, int> m_hash_to_piece;
+
+ // this map contains partial hashes for downloading
+ // pieces. This is only accessed from within the
+ // disk-io thread.
+ std::map<int, partial_hash> m_piece_hasher;
+
+ disk_io_thread& m_io_thread;
+
+ // the reason for this to be a void pointer
+ // is to avoid creating a dependency on the
+ // torrent. This shared_ptr is here only
+ // to keep the torrent object alive until
+ // the piece_manager destructs. This is because
+ // the torrent_info object is owned by the torrent.
+ boost::shared_ptr<void> m_torrent;
+#ifndef NDEBUG
+ bool m_resume_data_verified;
+#endif
+ };
+
+}
+
+#endif // TORRENT_STORAGE_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/time.hpp b/src/libtorrent/include/libtorrent/time.hpp
new file mode 100644
index 0000000..f4d364e
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/time.hpp
@@ -0,0 +1,398 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_TIME_HPP_INCLUDED
+#define TORRENT_TIME_HPP_INCLUDED
+
+#include <ctime>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+namespace libtorrent
+{
+ inline char const* time_now_string()
+ {
+ time_t t = std::time(0);
+ tm* timeinfo = std::localtime(&t);
+ static char str[200];
+ std::strftime(str, 200, "%b %d %X", timeinfo);
+ return str;
+ }
+
+ std::string log_time();
+}
+
+#if (!defined (__MACH__) && !defined (_WIN32) && (!defined(_POSIX_MONOTONIC_CLOCK) \
+ || _POSIX_MONOTONIC_CLOCK < 0)) || defined (TORRENT_USE_BOOST_DATE_TIME)
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ typedef boost::posix_time::ptime ptime;
+ typedef boost::posix_time::time_duration time_duration;
+ inline ptime time_now()
+ { return boost::posix_time::microsec_clock::universal_time(); }
+ inline ptime min_time()
+ { return boost::posix_time::ptime(boost::posix_time::min_date_time); }
+ inline ptime max_time()
+ { return boost::posix_time::ptime(boost::posix_time::max_date_time); }
+ inline time_duration seconds(int s) { return boost::posix_time::seconds(s); }
+ inline time_duration milliseconds(int s) { return boost::posix_time::milliseconds(s); }
+ inline time_duration microsec(int s) { return boost::posix_time::microsec(s); }
+ inline time_duration minutes(int s) { return boost::posix_time::minutes(s); }
+ inline time_duration hours(int s) { return boost::posix_time::hours(s); }
+
+ inline int total_seconds(time_duration td)
+ { return td.total_seconds(); }
+ inline int total_milliseconds(time_duration td)
+ { return td.total_milliseconds(); }
+ inline boost::int64_t total_microseconds(time_duration td)
+ { return td.total_microseconds(); }
+
+}
+
+#else
+
+#include <asio/time_traits.hpp>
+#include <boost/cstdint.hpp>
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ // libtorrent time_duration type
+ struct time_duration
+ {
+ time_duration() {}
+ time_duration operator/(int rhs) const { return time_duration(diff / rhs); }
+ explicit time_duration(boost::int64_t d) : diff(d) {}
+ time_duration& operator-=(time_duration const& c) { diff -= c.diff; return *this; }
+ time_duration operator+(time_duration const& c) { return time_duration(diff + c.diff); }
+ boost::int64_t diff;
+ };
+
+ inline bool is_negative(time_duration dt) { return dt.diff < 0; }
+ inline bool operator<(time_duration lhs, time_duration rhs)
+ { return lhs.diff < rhs.diff; }
+ inline bool operator<=(time_duration lhs, time_duration rhs)
+ { return lhs.diff <= rhs.diff; }
+ inline bool operator>(time_duration lhs, time_duration rhs)
+ { return lhs.diff > rhs.diff; }
+ inline bool operator>=(time_duration lhs, time_duration rhs)
+ { return lhs.diff >= rhs.diff; }
+
+ // libtorrent time type
+ struct ptime
+ {
+ ptime() {}
+ explicit ptime(boost::int64_t t): time(t) {}
+ boost::int64_t time;
+ };
+
+ inline bool operator>(ptime lhs, ptime rhs)
+ { return lhs.time > rhs.time; }
+ inline bool operator>=(ptime lhs, ptime rhs)
+ { return lhs.time >= rhs.time; }
+ inline bool operator<=(ptime lhs, ptime rhs)
+ { return lhs.time <= rhs.time; }
+ inline bool operator<(ptime lhs, ptime rhs)
+ { return lhs.time < rhs.time; }
+ inline bool operator!=(ptime lhs, ptime rhs)
+ { return lhs.time != rhs.time;}
+ inline bool operator==(ptime lhs, ptime rhs)
+ { return lhs.time == rhs.time;}
+ inline time_duration operator-(ptime lhs, ptime rhs)
+ { return time_duration(lhs.time - rhs.time); }
+ inline ptime operator+(ptime lhs, time_duration rhs)
+ { return ptime(lhs.time + rhs.diff); }
+ inline ptime operator+(time_duration lhs, ptime rhs)
+ { return ptime(rhs.time + lhs.diff); }
+ inline ptime operator-(ptime lhs, time_duration rhs)
+ { return ptime(lhs.time - rhs.diff); }
+
+ ptime time_now();
+ inline ptime min_time() { return ptime(0); }
+ inline ptime max_time() { return ptime((std::numeric_limits<boost::int64_t>::max)()); }
+ int total_seconds(time_duration td);
+ int total_milliseconds(time_duration td);
+ boost::int64_t total_microseconds(time_duration td);
+}
+
+// asio time_traits
+namespace asio
+{
+ template<>
+ struct time_traits<libtorrent::ptime>
+ {
+ typedef libtorrent::ptime time_type;
+ typedef libtorrent::time_duration duration_type;
+ static time_type now()
+ { return time_type(libtorrent::time_now()); }
+ static time_type add(time_type t, duration_type d)
+ { return time_type(t.time + d.diff);}
+ static duration_type subtract(time_type t1, time_type t2)
+ { return duration_type(t1 - t2); }
+ static bool less_than(time_type t1, time_type t2)
+ { return t1 < t2; }
+ static boost::posix_time::time_duration to_posix_duration(
+ duration_type d)
+ { return boost::posix_time::microseconds(libtorrent::total_microseconds(d)); }
+ };
+}
+
+#if defined(__MACH__)
+
+#include <mach/mach_time.h>
+#include <boost/cstdint.hpp>
+#include "libtorrent/assert.hpp"
+
+// high precision timer for darwin intel and ppc
+
+namespace libtorrent
+{
+ namespace aux
+ {
+ inline boost::int64_t absolutetime_to_microseconds(boost::int64_t at)
+ {
+ static mach_timebase_info_data_t timebase_info = {0,0};
+ if (timebase_info.denom == 0)
+ mach_timebase_info(&timebase_info);
+ // make sure we don't overflow
+ TORRENT_ASSERT((at >= 0 && at >= at / 1000 * timebase_info.numer / timebase_info.denom)
+ || (at < 0 && at < at / 1000 * timebase_info.numer / timebase_info.denom));
+ return at / 1000 * timebase_info.numer / timebase_info.denom;
+ }
+
+ inline boost::int64_t microseconds_to_absolutetime(boost::int64_t ms)
+ {
+ static mach_timebase_info_data_t timebase_info = {0,0};
+ if (timebase_info.denom == 0)
+ {
+ mach_timebase_info(&timebase_info);
+ TORRENT_ASSERT(timebase_info.numer > 0);
+ TORRENT_ASSERT(timebase_info.denom > 0);
+ }
+ // make sure we don't overflow
+ TORRENT_ASSERT((ms >= 0 && ms <= ms * timebase_info.denom / timebase_info.numer * 1000)
+ || (ms < 0 && ms > ms * timebase_info.denom / timebase_info.numer * 1000));
+ return ms * timebase_info.denom / timebase_info.numer * 1000;
+ }
+ }
+
+ inline int total_seconds(time_duration td)
+ {
+ return aux::absolutetime_to_microseconds(td.diff)
+ / 1000000;
+ }
+ inline int total_milliseconds(time_duration td)
+ {
+ return aux::absolutetime_to_microseconds(td.diff)
+ / 1000;
+ }
+ inline boost::int64_t total_microseconds(time_duration td)
+ {
+ return aux::absolutetime_to_microseconds(td.diff);
+ }
+
+ inline ptime time_now() { return ptime(mach_absolute_time()); }
+
+ inline time_duration microsec(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_absolutetime(s));
+ }
+ inline time_duration milliseconds(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_absolutetime(s * 1000));
+ }
+ inline time_duration seconds(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_absolutetime(s * 1000000));
+ }
+ inline time_duration minutes(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_absolutetime(s * 1000000 * 60));
+ }
+ inline time_duration hours(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_absolutetime(s * 1000000 * 60 * 60));
+ }
+
+}
+#elif defined(_WIN32)
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ namespace aux
+ {
+ inline boost::int64_t performance_counter_to_microseconds(boost::int64_t pc)
+ {
+ static LARGE_INTEGER performace_counter_frequency = {0,0};
+ if (performace_counter_frequency.QuadPart == 0)
+ QueryPerformanceFrequency(&performace_counter_frequency);
+
+#ifndef NDEBUG
+ // make sure we don't overflow
+ boost::int64_t ret = (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
+ TORRENT_ASSERT((pc >= 0 && pc >= ret) || (pc < 0 && pc < ret));
+#endif
+ return (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
+ }
+
+ inline boost::int64_t microseconds_to_performance_counter(boost::int64_t ms)
+ {
+ static LARGE_INTEGER performace_counter_frequency = {0,0};
+ if (performace_counter_frequency.QuadPart == 0)
+ QueryPerformanceFrequency(&performace_counter_frequency);
+#ifndef NDEBUG
+ // make sure we don't overflow
+ boost::int64_t ret = (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
+ TORRENT_ASSERT((ms >= 0 && ms <= ret)
+ || (ms < 0 && ms > ret));
+#endif
+ return (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
+ }
+ }
+
+ inline int total_seconds(time_duration td)
+ {
+ return int(aux::performance_counter_to_microseconds(td.diff)
+ / 1000000);
+ }
+ inline int total_milliseconds(time_duration td)
+ {
+ return int(aux::performance_counter_to_microseconds(td.diff)
+ / 1000);
+ }
+ inline boost::int64_t total_microseconds(time_duration td)
+ {
+ return aux::performance_counter_to_microseconds(td.diff);
+ }
+
+ inline ptime time_now()
+ {
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ return ptime(now.QuadPart);
+ }
+
+ inline time_duration microsec(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_performance_counter(s));
+ }
+ inline time_duration milliseconds(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_performance_counter(
+ s * 1000));
+ }
+ inline time_duration seconds(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_performance_counter(
+ s * 1000000));
+ }
+ inline time_duration minutes(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_performance_counter(
+ s * 1000000 * 60));
+ }
+ inline time_duration hours(boost::int64_t s)
+ {
+ return time_duration(aux::microseconds_to_performance_counter(
+ s * 1000000 * 60 * 60));
+ }
+
+}
+
+#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
+
+#include <time.h>
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ inline int total_seconds(time_duration td)
+ {
+ return td.diff / 1000000;
+ }
+ inline int total_milliseconds(time_duration td)
+ {
+ return td.diff / 1000;
+ }
+ inline boost::int64_t total_microseconds(time_duration td)
+ {
+ return td.diff;
+ }
+
+ inline ptime time_now()
+ {
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ptime(boost::int64_t(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000);
+ }
+
+ inline time_duration microsec(boost::int64_t s)
+ {
+ return time_duration(s);
+ }
+ inline time_duration milliseconds(boost::int64_t s)
+ {
+ return time_duration(s * 1000);
+ }
+ inline time_duration seconds(boost::int64_t s)
+ {
+ return time_duration(s * 1000000);
+ }
+ inline time_duration minutes(boost::int64_t s)
+ {
+ return time_duration(s * 1000000 * 60);
+ }
+ inline time_duration hours(boost::int64_t s)
+ {
+ return time_duration(s * 1000000 * 60 * 60);
+ }
+
+}
+
+#endif
+
+#endif
+
+#endif
+
diff --git a/src/libtorrent/include/libtorrent/torrent.hpp b/src/libtorrent/include/libtorrent/torrent.hpp
new file mode 100644
index 0000000..92ea37a
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/torrent.hpp
@@ -0,0 +1,828 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_TORRENT_HPP_INCLUDE
+#define TORRENT_TORRENT_HPP_INCLUDE
+
+#include <algorithm>
+#include <vector>
+#include <set>
+#include <list>
+#include <iostream>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/limits.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/policy.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/stat.hpp"
+#include "libtorrent/alert.hpp"
+#include "libtorrent/piece_picker.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/escape_string.hpp"
+#include "libtorrent/bandwidth_limit.hpp"
+#include "libtorrent/bandwidth_queue_entry.hpp"
+#include "libtorrent/storage.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ struct logger;
+#endif
+
+ class piece_manager;
+ struct torrent_plugin;
+
+ namespace aux
+ {
+ struct session_impl;
+ struct piece_checker_data;
+ }
+
+ namespace fs = boost::filesystem;
+
+ // a torrent is a class that holds information
+ // for a specific download. It updates itself against
+ // the tracker
+ class TORRENT_EXPORT torrent: public request_callback
+ , public boost::enable_shared_from_this<torrent>
+ {
+ public:
+
+ torrent(
+ aux::session_impl& ses
+ , aux::checker_impl& checker
+ , boost::intrusive_ptr<torrent_info> tf
+ , fs::path const& save_path
+ , tcp::endpoint const& net_interface
+ , storage_mode_t m_storage_mode
+ , int block_size
+ , storage_constructor_type sc
+ , bool paused);
+
+ // used with metadata-less torrents
+ // (the metadata is downloaded from the peers)
+ torrent(
+ aux::session_impl& ses
+ , aux::checker_impl& checker
+ , char const* tracker_url
+ , sha1_hash const& info_hash
+ , char const* name
+ , fs::path const& save_path
+ , tcp::endpoint const& net_interface
+ , storage_mode_t m_storage_mode
+ , int block_size
+ , storage_constructor_type sc
+ , bool paused);
+
+ ~torrent();
+
+ // starts the announce timer
+ void start();
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void add_extension(boost::shared_ptr<torrent_plugin>);
+ void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
+ , void* userdata);
+#endif
+
+ // this is called when the torrent has metadata.
+ // it will initialize the storage and the piece-picker
+ void init();
+
+ // this will flag the torrent as aborted. The main
+ // loop in session_impl will check for this state
+ // on all torrents once every second, and take
+ // the necessary actions then.
+ void abort();
+ bool is_aborted() const { return m_abort; }
+
+ // returns true if this torrent is being allocated
+ // by the checker thread.
+ bool is_allocating() const;
+
+ session_settings const& settings() const;
+
+ aux::session_impl& session() { return m_ses; }
+
+ void set_sequenced_download_threshold(int threshold);
+
+ bool verify_resume_data(entry& rd, std::string& error)
+ { TORRENT_ASSERT(m_storage); return m_storage->verify_resume_data(rd, error); }
+
+ void second_tick(stat& accumulator, float tick_interval);
+
+ // debug purpose only
+ void print(std::ostream& os) const;
+
+ std::string name() const;
+
+ bool check_fastresume(aux::piece_checker_data&);
+ std::pair<bool, float> check_files();
+ void files_checked(std::vector<piece_picker::downloading_piece> const&
+ unfinished_pieces);
+
+ stat statistics() const { return m_stat; }
+ size_type bytes_left() const;
+ boost::tuples::tuple<size_type, size_type> bytes_done() const;
+ size_type quantized_bytes_done() const;
+
+ void ip_filter_updated() { m_policy.ip_filter_updated(); }
+
+ void pause();
+ void resume();
+ bool is_paused() const { return m_paused; }
+
+ void delete_files();
+
+ // ============ start deprecation =============
+ void filter_piece(int index, bool filter);
+ void filter_pieces(std::vector<bool> const& bitmask);
+ bool is_piece_filtered(int index) const;
+ void filtered_pieces(std::vector<bool>& bitmask) const;
+ void filter_files(std::vector<bool> const& files);
+ // ============ end deprecation =============
+
+ void piece_availability(std::vector<int>& avail) const;
+
+ void set_piece_priority(int index, int priority);
+ int piece_priority(int index) const;
+
+ void prioritize_pieces(std::vector<int> const& pieces);
+ void piece_priorities(std::vector<int>&) const;
+
+ void prioritize_files(std::vector<int> const& files);
+
+ torrent_status status() const;
+ void file_progress(std::vector<float>& fp) const;
+
+ void use_interface(const char* net_interface);
+ tcp::endpoint const& get_interface() const { return m_net_interface; }
+
+ void connect_to_url_seed(std::string const& url);
+ bool connect_to_peer(policy::peer* peerinfo);
+
+ void set_ratio(float ratio)
+ { TORRENT_ASSERT(ratio >= 0.0f); m_ratio = ratio; }
+
+ float ratio() const
+ { return m_ratio; }
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ void resolve_countries(bool r)
+ { m_resolve_countries = r; }
+
+ bool resolving_countries() const { return m_resolve_countries; }
+#endif
+
+// --------------------------------------------
+ // BANDWIDTH MANAGEMENT
+
+ bandwidth_limit m_bandwidth_limit[2];
+
+ void request_bandwidth(int channel
+ , boost::intrusive_ptr<peer_connection> const& p
+ , int priority);
+
+ void perform_bandwidth_request(int channel
+ , boost::intrusive_ptr<peer_connection> const& p
+ , int block_size, int priority);
+
+ void expire_bandwidth(int channel, int amount);
+ void assign_bandwidth(int channel, int amount, int blk);
+
+ int bandwidth_throttle(int channel) const;
+
+ int max_assignable_bandwidth(int channel) const
+ { return m_bandwidth_limit[channel].max_assignable(); }
+
+// --------------------------------------------
+ // PEER MANAGEMENT
+
+ // add or remove a url that will be attempted for
+ // finding the file(s) in this torrent.
+ void add_url_seed(std::string const& url)
+ { m_web_seeds.insert(url); }
+
+ void remove_url_seed(std::string const& url)
+ { m_web_seeds.erase(url); }
+
+ void retry_url_seed(std::string const& url);
+
+ std::set<std::string> url_seeds() const
+ { return m_web_seeds; }
+
+ bool free_upload_slots() const
+ { return m_num_uploads < m_max_uploads; }
+
+ void choke_peer(peer_connection& c);
+ bool unchoke_peer(peer_connection& c);
+
+ // used by peer_connection to attach itself to a torrent
+ // since incoming connections don't know what torrent
+ // they're a part of until they have received an info_hash.
+ void attach_peer(peer_connection* p);
+
+ // this will remove the peer and make sure all
+ // the pieces it had have their reference counter
+ // decreased in the piece_picker
+ void remove_peer(peer_connection* p);
+
+ void cancel_block(piece_block block);
+
+ bool want_more_peers() const;
+ bool try_connect_peer();
+
+ // the number of peers that belong to this torrent
+ int num_peers() const { return (int)m_connections.size(); }
+ int num_seeds() const;
+
+ typedef std::set<peer_connection*>::iterator peer_iterator;
+ typedef std::set<peer_connection*>::const_iterator const_peer_iterator;
+
+ const_peer_iterator begin() const { return m_connections.begin(); }
+ const_peer_iterator end() const { return m_connections.end(); }
+
+ peer_iterator begin() { return m_connections.begin(); }
+ peer_iterator end() { return m_connections.end(); }
+
+ void resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const;
+
+ void get_peer_info(std::vector<peer_info>& v);
+ void get_download_queue(std::vector<partial_piece_info>& queue);
+
+// --------------------------------------------
+ // TRACKER MANAGEMENT
+
+ // these are callbacks called by the tracker_connection instance
+ // (either http_tracker_connection or udp_tracker_connection)
+ // when this torrent got a response from its tracker request
+ // or when a failure occured
+ virtual void tracker_response(
+ tracker_request const& r
+ , std::vector<peer_entry>& e, int interval
+ , int complete, int incomplete);
+ virtual void tracker_request_timed_out(
+ tracker_request const& r);
+ virtual void tracker_request_error(tracker_request const& r
+ , int response_code, const std::string& str);
+ virtual void tracker_warning(std::string const& msg);
+ virtual void tracker_scrape_response(tracker_request const& req
+ , int complete, int incomplete, int downloaded);
+
+ // generates a request string for sending
+ // to the tracker
+ tracker_request generate_tracker_request();
+
+ // if no password and username is set
+ // this will return an empty string, otherwise
+ // it will concatenate the login and password
+ // ready to be sent over http (but without
+ // base64 encoding).
+ std::string tracker_login() const;
+
+ // returns the absolute time when the next tracker
+ // announce will take place.
+ ptime next_announce() const;
+
+ // returns true if it is time for this torrent to make another
+ // tracker request
+ bool should_request();
+
+ // forcefully sets next_announce to the current time
+ void force_tracker_request();
+ void force_tracker_request(ptime);
+ void scrape_tracker();
+
+ // sets the username and password that will be sent to
+ // the tracker
+ void set_tracker_login(std::string const& name, std::string const& pw);
+
+ // the tcp::endpoint of the tracker that we managed to
+ // announce ourself at the last time we tried to announce
+ const tcp::endpoint& current_tracker() const;
+
+// --------------------------------------------
+ // PIECE MANAGEMENT
+
+ // returns true if we have downloaded the given piece
+ bool have_piece(int index) const
+ {
+ TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size());
+ return m_have_pieces[index];
+ }
+
+ const std::vector<bool>& pieces() const
+ { return m_have_pieces; }
+
+ int num_pieces() const { return m_num_pieces; }
+
+ // when we get a have- or bitfield- messages, this is called for every
+ // piece a peer has gained.
+ void peer_has(int index)
+ {
+ if (m_picker.get())
+ {
+ TORRENT_ASSERT(!is_seed());
+ TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size());
+ m_picker->inc_refcount(index);
+ }
+#ifndef NDEBUG
+ else
+ {
+ TORRENT_ASSERT(is_seed());
+ }
+#endif
+ }
+
+ void peer_has_all()
+ {
+ if (m_picker.get())
+ {
+ TORRENT_ASSERT(!is_seed());
+ m_picker->inc_refcount_all();
+ }
+#ifndef NDEBUG
+ else
+ {
+ TORRENT_ASSERT(is_seed());
+ }
+#endif
+ }
+
+ // when peer disconnects, this is called for every piece it had
+ void peer_lost(int index)
+ {
+ if (m_picker.get())
+ {
+ TORRENT_ASSERT(!is_seed());
+ TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size());
+ m_picker->dec_refcount(index);
+ }
+#ifndef NDEBUG
+ else
+ {
+ TORRENT_ASSERT(is_seed());
+ }
+#endif
+ }
+
+ int block_size() const { TORRENT_ASSERT(m_block_size > 0); return m_block_size; }
+ peer_request to_req(piece_block const& p);
+
+ // this will tell all peers that we just got his piece
+ // and also let the piece picker know that we have this piece
+ // so it wont pick it for download
+ void announce_piece(int index);
+
+ void disconnect_all();
+
+ // this is called wheh the torrent has completed
+ // the download. It will post an event, disconnect
+ // all seeds and let the tracker know we're finished.
+ void completed();
+
+ // this is the asio callback that is called when a name
+ // lookup for a PEER is completed.
+ void on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , peer_id pid);
+
+ // this is the asio callback that is called when a name
+ // lookup for a WEB SEED is completed.
+ void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , std::string url, tcp::endpoint proxy);
+
+ // this is the asio callback that is called when a name
+ // lookup for a proxy for a web seed is completed.
+ void on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , std::string url);
+
+ // this is called when the torrent has finished. i.e.
+ // all the pieces we have not filtered have been downloaded.
+ // If no pieces are filtered, this is called first and then
+ // completed() is called immediately after it.
+ void finished();
+
+ void async_verify_piece(int piece_index, boost::function<void(bool)> const&);
+
+ // this is called from the peer_connection
+ // each time a piece has failed the hash
+ // test
+ void piece_finished(int index, bool passed_hash_check);
+ void piece_failed(int index);
+ void received_redundant_data(int num_bytes)
+ { TORRENT_ASSERT(num_bytes > 0); m_total_redundant_bytes += num_bytes; }
+
+ // this is true if we have all the pieces
+ bool is_seed() const
+ {
+ return valid_metadata()
+ && m_num_pieces == m_torrent_file->num_pieces();
+ }
+
+ // this is true if we have all the pieces that we want
+ bool is_finished() const
+ {
+ if (is_seed()) return true;
+ return valid_metadata() && m_torrent_file->num_pieces()
+ - m_num_pieces - m_picker->num_filtered() == 0;
+ }
+
+ fs::path save_path() const;
+ alert_manager& alerts() const;
+ piece_picker& picker()
+ {
+ TORRENT_ASSERT(m_picker.get());
+ return *m_picker;
+ }
+ bool has_picker() const
+ {
+ return m_picker.get() != 0;
+ }
+ policy& get_policy() { return m_policy; }
+ piece_manager& filesystem();
+ torrent_info const& torrent_file() const
+ { return *m_torrent_file; }
+
+ std::vector<announce_entry> const& trackers() const
+ { return m_trackers; }
+
+ void replace_trackers(std::vector<announce_entry> const& urls);
+
+ torrent_handle get_handle() const;
+
+ // LOGGING
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ virtual void debug_log(const std::string& line);
+#endif
+
+ // DEBUG
+#ifndef NDEBUG
+ void check_invariant() const;
+#endif
+
+// --------------------------------------------
+ // RESOURCE MANAGEMENT
+
+ void set_peer_upload_limit(tcp::endpoint ip, int limit);
+ void set_peer_download_limit(tcp::endpoint ip, int limit);
+
+ void set_upload_limit(int limit);
+ int upload_limit() const;
+ void set_download_limit(int limit);
+ int download_limit() const;
+
+ void set_max_uploads(int limit);
+ int max_uploads() const { return m_max_uploads; }
+ void set_max_connections(int limit);
+ int max_connections() const { return m_max_connections; }
+ void move_storage(fs::path const& save_path);
+
+ // unless this returns true, new connections must wait
+ // with their initialization.
+ bool ready_for_connections() const
+ { return m_connections_initialized; }
+ bool valid_metadata() const
+ { return m_torrent_file->is_valid(); }
+
+ // parses the info section from the given
+ // bencoded tree and moves the torrent
+ // to the checker thread for initial checking
+ // of the storage.
+ void set_metadata(entry const&);
+
+ private:
+
+ void on_files_deleted(int ret, disk_io_job const& j);
+ void on_files_released(int ret, disk_io_job const& j);
+ void on_torrent_paused(int ret, disk_io_job const& j);
+ void on_storage_moved(int ret, disk_io_job const& j);
+
+ void on_piece_verified(int ret, disk_io_job const& j
+ , boost::function<void(bool)> f);
+
+ void try_next_tracker();
+ int prioritize_tracker(int tracker_index);
+ void on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i
+ , boost::intrusive_ptr<peer_connection> p) const;
+ bool request_bandwidth_from_session(int channel) const;
+
+ void update_peer_interest();
+
+ boost::intrusive_ptr<torrent_info> m_torrent_file;
+
+ // is set to true when the torrent has
+ // been aborted.
+ bool m_abort;
+
+ // is true if this torrent has been paused
+ bool m_paused;
+ // this is true from the time when the torrent was
+ // paused to the time should_request() is called
+ bool m_just_paused;
+
+ tracker_request::event_t m_event;
+
+ void parse_response(const entry& e, std::vector<peer_entry>& peer_list);
+
+ // the size of a request block
+ // each piece is divided into these
+ // blocks when requested
+ int m_block_size;
+
+ // if this pointer is 0, the torrent is in
+ // a state where the metadata hasn't been
+ // received yet.
+ // the piece_manager keeps the torrent object
+ // alive by holding a shared_ptr to it and
+ // the torrent keeps the piece manager alive
+ // with this intrusive_ptr. This cycle is
+ // broken when torrent::abort() is called
+ // Then the torrent releases the piece_manager
+ // and when the piece_manager is complete with all
+ // outstanding disk io jobs (that keeps
+ // the piece_manager alive) it will destruct
+ // and release the torrent file. The reason for
+ // this is that the torrent_info is used by
+ // the piece_manager, and stored in the
+ // torrent, so the torrent cannot destruct
+ // before the piece_manager.
+ boost::intrusive_ptr<piece_manager> m_owning_storage;
+
+ // this is a weak (non owninig) pointer to
+ // the piece_manager. This is used after the torrent
+ // has been aborted, and it can no longer own
+ // the object.
+ piece_manager* m_storage;
+
+ // the time of next tracker request
+ ptime m_next_request;
+
+ // -----------------------------
+ // DATA FROM TRACKER RESPONSE
+
+ // the number number of seconds between requests
+ // from the tracker
+ int m_duration;
+
+ // the scrape data from the tracker response, this
+ // is optional and may be -1.
+ int m_complete;
+ int m_incomplete;
+
+#ifndef NDEBUG
+ public:
+#endif
+ std::set<peer_connection*> m_connections;
+#ifndef NDEBUG
+ private:
+#endif
+
+ // The list of web seeds in this torrent. Seeds
+ // with fatal errors are removed from the set
+ std::set<std::string> m_web_seeds;
+
+ // a list of web seeds that have failed and are
+ // waiting to be retried
+ std::map<std::string, ptime> m_web_seeds_next_retry;
+
+ // urls of the web seeds that we are currently
+ // resolving the address for
+ std::set<std::string> m_resolving_web_seeds;
+
+ // used to resolve the names of web seeds
+ mutable tcp::resolver m_host_resolver;
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ // this is true while there is a country
+ // resolution in progress. To avoid flodding
+ // the DNS request queue, only one ip is resolved
+ // at a time.
+ mutable bool m_resolving_country;
+
+ // this is true if the user has enabled
+ // country resolution in this torrent
+ bool m_resolve_countries;
+#endif
+
+ // this announce timer is used both
+ // by Local service discovery and
+ // by the DHT.
+ deadline_timer m_announce_timer;
+
+ static void on_announce_disp(boost::weak_ptr<torrent> p
+ , asio::error_code const& e);
+
+ // this is called once per announce interval
+ void on_announce();
+
+#ifndef TORRENT_DISABLE_DHT
+ static void on_dht_announce_response_disp(boost::weak_ptr<torrent> t
+ , std::vector<tcp::endpoint> const& peers);
+ void on_dht_announce_response(std::vector<tcp::endpoint> const& peers);
+ bool should_announce_dht() const;
+
+ // the time when the DHT was last announced of our
+ // presence on this torrent
+ ptime m_last_dht_announce;
+#endif
+
+ // this is the upload and download statistics for the whole torrent.
+ // it's updated from all its peers once every second.
+ libtorrent::stat m_stat;
+
+ // -----------------------------
+
+ // a back reference to the session
+ // this torrent belongs to.
+ aux::session_impl& m_ses;
+ aux::checker_impl& m_checker;
+
+ boost::scoped_ptr<piece_picker> m_picker;
+
+ // the queue of peer_connections that want more bandwidth
+ typedef std::deque<bw_queue_entry<peer_connection, torrent> > queue_t;
+ queue_t m_bandwidth_queue[2];
+
+ std::vector<announce_entry> m_trackers;
+ // this is an index into m_trackers
+
+ int m_last_working_tracker;
+ int m_currently_trying_tracker;
+ // the number of connection attempts that has
+ // failed in a row, this is currently used to
+ // determine the timeout until next try.
+ int m_failed_trackers;
+
+ // this is a counter that is decreased every
+ // second, and when it reaches 0, the policy::pulse()
+ // is called and the time scaler is reset to 10.
+ int m_time_scaler;
+
+ // the bitmask that says which pieces we have
+ std::vector<bool> m_have_pieces;
+
+ // the number of pieces we have. The same as
+ // std::accumulate(m_have_pieces.begin(),
+ // m_have_pieces.end(), 0)
+ int m_num_pieces;
+
+ // in case the piece picker hasn't been constructed
+ // when this settings is set, this variable will keep
+ // its value until the piece picker is created
+ int m_sequenced_download_threshold;
+
+ // is false by default and set to
+ // true when the first tracker reponse
+ // is received
+ bool m_got_tracker_response;
+
+ // the upload/download ratio that each peer
+ // tries to maintain.
+ // 0 is infinite
+ float m_ratio;
+
+ // the number of bytes that has been
+ // downloaded that failed the hash-test
+ size_type m_total_failed_bytes;
+ size_type m_total_redundant_bytes;
+
+ std::string m_username;
+ std::string m_password;
+
+ // the network interface all outgoing connections
+ // are opened through
+ tcp::endpoint m_net_interface;
+
+ fs::path m_save_path;
+
+ // determines the storage state for this torrent.
+ storage_mode_t m_storage_mode;
+
+ // defaults to 16 kiB, but can be set by the user
+ // when creating the torrent
+ const int m_default_block_size;
+
+ // this is set to false as long as the connections
+ // of this torrent hasn't been initialized. If we
+ // have metadata from the start, connections are
+ // initialized immediately, if we didn't have metadata,
+ // they are initialized right after files_checked().
+ // valid_resume_data() will return false as long as
+ // the connections aren't initialized, to avoid
+ // them from altering the piece-picker before it
+ // has been initialized with files_checked().
+ bool m_connections_initialized;
+
+ // if the torrent is started without metadata, it may
+ // still be given a name until the metadata is received
+ // once the metadata is received this field will no
+ // longer be used and will be reset
+ boost::scoped_ptr<std::string> m_name;
+
+ session_settings const& m_settings;
+
+ storage_constructor_type m_storage_constructor;
+
+ // the maximum number of uploads for this torrent
+ int m_max_uploads;
+
+ // the number of unchoked peers in this torrent
+ int m_num_uploads;
+
+ // the maximum number of connections for this torrent
+ int m_max_connections;
+
+#ifndef NDEBUG
+ bool m_files_checked;
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;
+ extension_list_t m_extensions;
+#endif
+
+#ifndef NDEBUG
+ // this is the amount downloaded when this torrent
+ // is started. i.e.
+ // total_done - m_initial_done <= total_payload_download
+ size_type m_initial_done;
+#endif
+
+ policy m_policy;
+ };
+
+ inline ptime torrent::next_announce() const
+ {
+ return m_next_request;
+ }
+
+ inline void torrent::force_tracker_request()
+ {
+ m_next_request = time_now();
+ }
+
+ inline void torrent::force_tracker_request(ptime t)
+ {
+ m_next_request = t;
+ }
+
+ inline void torrent::set_tracker_login(
+ std::string const& name
+ , std::string const& pw)
+ {
+ m_username = name;
+ m_password = pw;
+ }
+
+}
+
+#endif // TORRENT_TORRENT_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/torrent_handle.hpp b/src/libtorrent/include/libtorrent/torrent_handle.hpp
new file mode 100644
index 0000000..256209d
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/torrent_handle.hpp
@@ -0,0 +1,445 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_TORRENT_HANDLE_HPP_INCLUDED
+#define TORRENT_TORRENT_HANDLE_HPP_INCLUDED
+
+#include <vector>
+#include <set>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/peer_info.hpp"
+#include "libtorrent/piece_picker.hpp"
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/time.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/storage.hpp"
+
+namespace libtorrent
+{
+ namespace fs = boost::filesystem;
+
+ namespace aux
+ {
+ struct session_impl;
+ struct checker_impl;
+ }
+
+ struct torrent_plugin;
+
+ struct TORRENT_EXPORT duplicate_torrent: std::exception
+ {
+ virtual const char* what() const throw()
+ { return "torrent already exists in session"; }
+ };
+
+ struct TORRENT_EXPORT invalid_handle: std::exception
+ {
+ virtual const char* what() const throw()
+ { return "invalid torrent handle used"; }
+ };
+
+ struct TORRENT_EXPORT torrent_status
+ {
+ torrent_status()
+ : state(queued_for_checking)
+ , paused(false)
+ , progress(0.f)
+ , total_download(0)
+ , total_upload(0)
+ , total_payload_download(0)
+ , total_payload_upload(0)
+ , total_failed_bytes(0)
+ , total_redundant_bytes(0)
+ , download_rate(0)
+ , upload_rate(0)
+ , download_payload_rate(0)
+ , upload_payload_rate(0)
+ , num_seeds(0)
+ , num_peers(0)
+ , num_complete(-1)
+ , num_incomplete(-1)
+ , list_seeds(0)
+ , list_peers(0)
+ , pieces(0)
+ , num_pieces(0)
+ , total_done(0)
+ , total_wanted_done(0)
+ , total_wanted(0)
+ , distributed_copies(0.f)
+ , block_size(0)
+ , num_uploads(0)
+ , num_connections(0)
+ , uploads_limit(0)
+ , connections_limit(0)
+ , storage_mode(storage_mode_sparse)
+ , up_bandwidth_queue(0)
+ , down_bandwidth_queue(0)
+ {}
+
+ enum state_t
+ {
+ queued_for_checking,
+ checking_files,
+ connecting_to_tracker,
+ downloading_metadata,
+ downloading,
+ finished,
+ seeding,
+ allocating
+ };
+
+ state_t state;
+ bool paused;
+ float progress;
+ boost::posix_time::time_duration next_announce;
+ boost::posix_time::time_duration announce_interval;
+
+ std::string current_tracker;
+
+ // transferred this session!
+ // total, payload plus protocol
+ size_type total_download;
+ size_type total_upload;
+
+ // payload only
+ size_type total_payload_download;
+ size_type total_payload_upload;
+
+ // the amount of payload bytes that
+ // has failed their hash test
+ size_type total_failed_bytes;
+
+ // the number of payload bytes that
+ // has been received redundantly.
+ size_type total_redundant_bytes;
+
+ // current transfer rate
+ // payload plus protocol
+ float download_rate;
+ float upload_rate;
+
+ // the rate of payload that is
+ // sent and received
+ float download_payload_rate;
+ float upload_payload_rate;
+
+ // the number of peers this torrent is connected to
+ // that are seeding.
+ int num_seeds;
+
+ // the number of peers this torrent
+ // is connected to (including seeds).
+ int num_peers;
+
+ // if the tracker sends scrape info in its
+ // announce reply, these fields will be
+ // set to the total number of peers that
+ // have the whole file and the total number
+ // of peers that are still downloading
+ int num_complete;
+ int num_incomplete;
+
+ // this is the number of seeds whose IP we know
+ // but are not necessarily connected to
+ int list_seeds;
+
+ // this is the number of peers whose IP we know
+ // (including seeds), but are not necessarily
+ // connected to
+ int list_peers;
+
+ const std::vector<bool>* pieces;
+
+ // this is the number of pieces the client has
+ // downloaded. it is equal to:
+ // std::accumulate(pieces->begin(), pieces->end());
+ int num_pieces;
+
+ // the number of bytes of the file we have
+ // including pieces that may have been filtered
+ // after we downloaded them
+ size_type total_done;
+
+ // the number of bytes we have of those that we
+ // want. i.e. not counting bytes from pieces that
+ // are filtered as not wanted.
+ size_type total_wanted_done;
+
+ // the total number of bytes we want to download
+ // this may be smaller than the total torrent size
+ // in case any pieces are filtered as not wanted
+ size_type total_wanted;
+
+ // the number of distributed copies of the file.
+ // note that one copy may be spread out among many peers.
+ //
+ // the integer part tells how many copies
+ // there are of the rarest piece(s)
+ //
+ // the fractional part tells the fraction of pieces that
+ // have more copies than the rarest piece(s).
+ float distributed_copies;
+
+ // the block size that is used in this torrent. i.e.
+ // the number of bytes each piece request asks for
+ // and each bit in the download queue bitfield represents
+ int block_size;
+
+ int num_uploads;
+ int num_connections;
+ int uploads_limit;
+ int connections_limit;
+
+ // true if the torrent is saved in compact mode
+ // false if it is saved in full allocation mode
+ storage_mode_t storage_mode;
+
+ int up_bandwidth_queue;
+ int down_bandwidth_queue;
+ };
+
+ struct TORRENT_EXPORT block_info
+ {
+ enum block_state_t
+ { none, requested, writing, finished };
+
+ tcp::endpoint peer;
+ // number of bytes downloaded in this block
+ unsigned bytes_progress:16;
+ // the total number of bytes in this block
+ unsigned block_size:16;
+ // the state this block is in (see block_state_t)
+ unsigned state:2;
+ // the number of peers that has requested this block
+ // typically 0 or 1. If > 1, this block is in
+ // end game mode
+ unsigned num_peers:14;
+ };
+
+ struct TORRENT_EXPORT partial_piece_info
+ {
+ enum { max_blocks_per_piece = 256 };
+ int piece_index;
+ int blocks_in_piece;
+ // the number of blocks in the finished state
+ int finished;
+ // the number of blocks in the writing state
+ int writing;
+ // the number of blocks in the requested state
+ int requested;
+ block_info blocks[max_blocks_per_piece];
+ enum state_t { none, slow, medium, fast };
+ state_t piece_state;
+ };
+
+ struct TORRENT_EXPORT torrent_handle
+ {
+ friend class invariant_access;
+ friend struct aux::session_impl;
+ friend class torrent;
+
+ torrent_handle(): m_ses(0), m_chk(0), m_info_hash(0) {}
+
+ void get_peer_info(std::vector<peer_info>& v) const;
+ torrent_status status() const;
+ void get_download_queue(std::vector<partial_piece_info>& queue) const;
+
+ // fills the specified vector with the download progress [0, 1]
+ // of each file in the torrent. The files are ordered as in
+ // the torrent_info.
+ void file_progress(std::vector<float>& progress);
+
+ std::vector<announce_entry> const& trackers() const;
+ void replace_trackers(std::vector<announce_entry> const&) const;
+
+ void add_url_seed(std::string const& url) const;
+ void remove_url_seed(std::string const& url) const;
+ std::set<std::string> url_seeds() const;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
+ , void* userdata = 0);
+#endif
+
+ bool has_metadata() const;
+ const torrent_info& get_torrent_info() const;
+ bool is_valid() const;
+
+ bool is_seed() const;
+ bool is_paused() const;
+ void pause() const;
+ void resume() const;
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ void resolve_countries(bool r);
+ bool resolve_countries() const;
+#endif
+
+ // all these are deprecated, use piece
+ // priority functions instead
+
+ // ================ start deprecation ============
+
+ // marks the piece with the given index as filtered
+ // it will not be downloaded
+ void filter_piece(int index, bool filter) const TORRENT_DEPRECATED;
+ void filter_pieces(std::vector<bool> const& pieces) const TORRENT_DEPRECATED;
+ bool is_piece_filtered(int index) const TORRENT_DEPRECATED;
+ std::vector<bool> filtered_pieces() const TORRENT_DEPRECATED;
+ // marks the file with the given index as filtered
+ // it will not be downloaded
+ void filter_files(std::vector<bool> const& files) const TORRENT_DEPRECATED;
+
+ // ================ end deprecation ============
+
+ void piece_availability(std::vector<int>& avail) const;
+
+ // priority must be within the range [0, 7]
+ void piece_priority(int index, int priority) const;
+ int piece_priority(int index) const;
+
+ void prioritize_pieces(std::vector<int> const& pieces) const;
+ std::vector<int> piece_priorities() const;
+
+ void prioritize_files(std::vector<int> const& files) const;
+
+
+ // set the interface to bind outgoing connections
+ // to.
+ void use_interface(const char* net_interface) const;
+
+ entry write_resume_data() const;
+
+ // forces this torrent to reannounce
+ // (make a rerequest from the tracker)
+ void force_reannounce() const;
+
+ // forces a reannounce in the specified amount of time.
+ // This overrides the default announce interval, and no
+ // announce will take place until the given time has
+ // timed out.
+ void force_reannounce(boost::posix_time::time_duration) const;
+
+ // performs a scrape request
+ void scrape_tracker() const;
+
+ // returns the name of this torrent, in case it doesn't
+ // have metadata it returns the name assigned to it
+ // when it was added.
+ std::string name() const;
+
+ // TODO: add a feature where the user can tell the torrent
+ // to finish all pieces currently in the pipeline, and then
+ // abort the torrent.
+
+ void set_upload_limit(int limit) const;
+ int upload_limit() const;
+ void set_download_limit(int limit) const;
+ int download_limit() const;
+
+ void set_sequenced_download_threshold(int threshold) const;
+
+ void set_peer_upload_limit(tcp::endpoint ip, int limit) const;
+ void set_peer_download_limit(tcp::endpoint ip, int limit) const;
+
+ // manually connect a peer
+ void connect_peer(tcp::endpoint const& adr, int source = 0) const;
+
+ // valid ratios are 0 (infinite ratio) or [ 1.0 , inf )
+ // the ratio is uploaded / downloaded. less than 1 is not allowed
+ void set_ratio(float up_down_ratio) const;
+
+ fs::path save_path() const;
+
+ // -1 means unlimited unchokes
+ void set_max_uploads(int max_uploads) const;
+
+ // -1 means unlimited connections
+ void set_max_connections(int max_connections) const;
+
+ void set_tracker_login(std::string const& name
+ , std::string const& password) const;
+
+ // post condition: save_path() == save_path if true is returned
+ void move_storage(fs::path const& save_path) const;
+
+ const sha1_hash& info_hash() const
+ { return m_info_hash; }
+
+ bool operator==(const torrent_handle& h) const
+ { return m_info_hash == h.m_info_hash; }
+
+ bool operator!=(const torrent_handle& h) const
+ { return m_info_hash != h.m_info_hash; }
+
+ bool operator<(const torrent_handle& h) const
+ { return m_info_hash < h.m_info_hash; }
+
+ private:
+
+ torrent_handle(aux::session_impl* s,
+ aux::checker_impl* c,
+ const sha1_hash& h)
+ : m_ses(s)
+ , m_chk(c)
+ , m_info_hash(h)
+ {
+ TORRENT_ASSERT(m_ses != 0);
+ TORRENT_ASSERT(m_chk != 0);
+ }
+
+#ifndef NDEBUG
+ void check_invariant() const;
+#endif
+
+ aux::session_impl* m_ses;
+ aux::checker_impl* m_chk;
+ sha1_hash m_info_hash;
+
+ };
+
+
+}
+
+#endif // TORRENT_TORRENT_HANDLE_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/torrent_info.hpp b/src/libtorrent/include/libtorrent/torrent_info.hpp
new file mode 100644
index 0000000..1eab609
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/torrent_info.hpp
@@ -0,0 +1,341 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDE
+#define TORRENT_TORRENT_INFO_HPP_INCLUDE
+
+
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/optional.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/shared_ptr.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/entry.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/size_type.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/time.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ namespace pt = boost::posix_time;
+ namespace gr = boost::gregorian;
+
+ namespace fs = boost::filesystem;
+
+ struct TORRENT_EXPORT file_entry
+ {
+ file_entry(): offset(0), size(0), file_base(0) {}
+
+ fs::path path;
+ size_type offset; // the offset of this file inside the torrent
+ size_type size; // the size of this file
+ // the offset in the file where the storage starts.
+ // This is always 0 unless parts of the torrent is
+ // compressed into a single file, such as a so-called part file.
+ size_type file_base;
+ // if the path was incorrectly encoded, this is
+ // the original corrupt encoded string. It is
+ // preserved in order to be able to reproduce
+ // the correct info-hash
+ boost::shared_ptr<const fs::path> orig_path;
+ };
+
+ struct TORRENT_EXPORT file_slice
+ {
+ int file_index;
+ size_type offset;
+ size_type size;
+ };
+
+ struct TORRENT_EXPORT announce_entry
+ {
+ announce_entry(std::string const& u): url(u), tier(0) {}
+ std::string url;
+ int tier;
+ };
+
+ struct TORRENT_EXPORT invalid_torrent_file: std::exception
+ {
+ virtual const char* what() const throw() { return "invalid torrent file"; }
+ };
+
+ class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info>
+ {
+ public:
+
+ torrent_info();
+ torrent_info(sha1_hash const& info_hash);
+ torrent_info(entry const& torrent_file);
+ ~torrent_info();
+
+ entry create_torrent() const;
+ entry create_info_metadata() const;
+ void set_comment(char const* str);
+ void set_creator(char const* str);
+ void set_piece_size(int size);
+ void set_hash(int index, sha1_hash const& h);
+ void add_tracker(std::string const& url, int tier = 0);
+ void add_file(fs::path file, size_type size);
+ void add_url_seed(std::string const& url);
+
+ bool remap_files(std::vector<file_entry> const& map);
+
+ std::vector<file_slice> map_block(int piece, size_type offset
+ , int size, bool storage = false) const;
+ peer_request map_file(int file, size_type offset, int size
+ , bool storage = false) const;
+
+ std::vector<std::string> const& url_seeds() const
+ {
+ TORRENT_ASSERT(!m_half_metadata);
+ return m_url_seeds;
+ }
+
+ typedef std::vector<file_entry>::const_iterator file_iterator;
+ typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
+
+ // list the files in the torrent file
+ file_iterator begin_files(bool storage = false) const
+ {
+ if (!storage || m_remapped_files.empty())
+ return m_files.begin();
+ else
+ return m_remapped_files.begin();
+ }
+
+ file_iterator end_files(bool storage = false) const
+ {
+ if (!storage || m_remapped_files.empty())
+ return m_files.end();
+ else
+ return m_remapped_files.end();
+ }
+
+ reverse_file_iterator rbegin_files(bool storage = false) const
+ {
+ if (!storage || m_remapped_files.empty())
+ return m_files.rbegin();
+ else
+ return m_remapped_files.rbegin();
+ }
+
+ reverse_file_iterator rend_files(bool storage = false) const
+ {
+ if (!storage || m_remapped_files.empty())
+ return m_files.rend();
+ else
+ return m_remapped_files.rend();
+ }
+
+ int num_files(bool storage = false) const
+ {
+ TORRENT_ASSERT(m_piece_length > 0);
+ if (!storage || m_remapped_files.empty())
+ return (int)m_files.size();
+ else
+ return (int)m_remapped_files.size();
+ }
+
+ const file_entry& file_at(int index, bool storage = false) const
+ {
+ if (!storage || m_remapped_files.empty())
+ {
+ TORRENT_ASSERT(index >= 0 && index < (int)m_files.size());
+ return m_files[index];
+ }
+ else
+ {
+ TORRENT_ASSERT(index >= 0 && index < (int)m_remapped_files.size());
+ return m_remapped_files[index];
+ }
+ }
+
+ const std::vector<announce_entry>& trackers() const { return m_urls; }
+
+ size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; }
+ int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; }
+ int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; }
+ const sha1_hash& info_hash() const { return m_info_hash; }
+ const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; }
+
+// ------- start deprecation -------
+// this functionaily will be removed in a future version
+ void print(std::ostream& os) const TORRENT_DEPRECATED;
+// ------- end deprecation -------
+
+ bool is_valid() const { return m_piece_length > 0; }
+
+ bool priv() const { return m_private; }
+ void set_priv(bool v) { m_private = v; }
+
+ void convert_file_names();
+
+ int piece_size(int index) const;
+
+ const sha1_hash& hash_for_piece(int index) const
+ {
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < (int)m_piece_hash.size());
+ TORRENT_ASSERT(!m_half_metadata);
+ return m_piece_hash[index];
+ }
+
+ boost::optional<pt::ptime> creation_date() const;
+
+ const std::string& creator() const
+ { return m_created_by; }
+
+ const std::string& comment() const
+ { return m_comment; }
+
+ // dht nodes to add to the routing table/bootstrap from
+ typedef std::vector<std::pair<std::string, int> > nodes_t;
+
+ nodes_t const& nodes() const
+ {
+ TORRENT_ASSERT(!m_half_metadata);
+ return m_nodes;
+ }
+
+ void add_node(std::pair<std::string, int> const& node);
+
+ void parse_info_section(entry const& e);
+
+ entry const* extra(char const* key) const
+ { return m_extra_info.find_key(key); }
+
+ // frees parts of the metadata that isn't
+ // used by seeds
+ void seed_free();
+
+ void swap(torrent_info& ti);
+
+ private:
+
+ void read_torrent_info(const entry& libtorrent);
+
+ // the urls to the trackers
+ std::vector<announce_entry> m_urls;
+
+ std::vector<std::string> m_url_seeds;
+
+ // the length of one piece
+ // if this is 0, the torrent_info is
+ // in an uninitialized state
+ int m_piece_length;
+
+ // the sha-1 hashes of each piece
+ std::vector<sha1_hash> m_piece_hash;
+
+ // the list of files that this torrent consists of
+ std::vector<file_entry> m_files;
+
+ // this vector is typically empty. If it is not
+ // empty, it means the user has re-mapped the
+ // files in this torrent to different names
+ // on disk. This is only used when reading and
+ // writing the disk.
+ std::vector<file_entry> m_remapped_files;
+
+ nodes_t m_nodes;
+
+ // the sum of all filesizes
+ size_type m_total_size;
+
+ // the number of pieces in the torrent
+ int m_num_pieces;
+
+ // the hash that identifies this torrent
+ // is mutable because it's calculated
+ // lazily
+ mutable sha1_hash m_info_hash;
+
+ std::string m_name;
+
+ // if a creation date is found in the torrent file
+ // this will be set to that, otherwise it'll be
+ // 1970, Jan 1
+ pt::ptime m_creation_date;
+
+ // if a comment is found in the torrent file
+ // this will be set to that comment
+ std::string m_comment;
+
+ // an optional string naming the software used
+ // to create the torrent file
+ std::string m_created_by;
+
+ // this is used when creating a torrent. If there's
+ // only one file there are cases where it's impossible
+ // to know if it should be written as a multifile torrent
+ // or not. e.g. test/test there's one file and one directory
+ // and they have the same name.
+ bool m_multifile;
+
+ // this is true if the torrent is private. i.e., is should not
+ // be announced on the dht
+ bool m_private;
+
+ // contains any non-parsed entries from the info-section
+ // these are kept in order to be able to accurately
+ // reproduce the info-section when sending the metadata
+ // to peers.
+ entry m_extra_info;
+
+#ifndef NDEBUG
+ public:
+ // this is set to true when seed_free() is called
+ bool m_half_metadata;
+ private:
+#endif
+ };
+
+}
+
+#endif // TORRENT_TORRENT_INFO_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/tracker_manager.hpp b/src/libtorrent/include/libtorrent/tracker_manager.hpp
new file mode 100644
index 0000000..8fec956
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/tracker_manager.hpp
@@ -0,0 +1,257 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_TRACKER_MANAGER_HPP_INCLUDED
+#define TORRENT_TRACKER_MANAGER_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <utility>
+#include <ctime>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/session_settings.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/peer.hpp"
+#include "libtorrent/config.hpp"
+#include "libtorrent/time.hpp"
+#include "libtorrent/connection_queue.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
+
+namespace libtorrent
+{
+ struct request_callback;
+ class tracker_manager;
+ struct timeout_handler;
+ struct tracker_connection;
+
+ // encodes a string using the base64 scheme
+ TORRENT_EXPORT std::string base64encode(const std::string& s);
+
+ // returns -1 if gzip header is invalid or the header size in bytes
+ TORRENT_EXPORT int gzip_header(const char* buf, int size);
+
+ TORRENT_EXPORT boost::tuple<std::string, std::string, std::string, int, std::string>
+ parse_url_components(std::string url);
+
+ struct TORRENT_EXPORT tracker_request
+ {
+ tracker_request()
+ : kind(announce_request)
+ , event(none)
+ , key(0)
+ , num_want(0)
+ {}
+
+ enum
+ {
+ announce_request,
+ scrape_request
+ } kind;
+
+ enum event_t
+ {
+ none,
+ completed,
+ started,
+ stopped
+ };
+
+ sha1_hash info_hash;
+ peer_id pid;
+ size_type downloaded;
+ size_type uploaded;
+ size_type left;
+ unsigned short listen_port;
+ event_t event;
+ std::string url;
+ int key;
+ int num_want;
+ std::string ipv6;
+ };
+
+ struct TORRENT_EXPORT request_callback
+ {
+ friend class tracker_manager;
+ request_callback(): m_manager(0) {}
+ virtual ~request_callback() {}
+ virtual void tracker_warning(std::string const& msg) = 0;
+ virtual void tracker_scrape_response(tracker_request const& req
+ , int complete, int incomplete, int downloads) {}
+ virtual void tracker_response(
+ tracker_request const&
+ , std::vector<peer_entry>& peers
+ , int interval
+ , int complete
+ , int incomplete) = 0;
+ virtual void tracker_request_timed_out(
+ tracker_request const&) = 0;
+ virtual void tracker_request_error(
+ tracker_request const&
+ , int response_code
+ , const std::string& description) = 0;
+
+ tcp::endpoint m_tracker_address;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ virtual void debug_log(const std::string& line) = 0;
+#endif
+ private:
+ tracker_manager* m_manager;
+ };
+
+ TORRENT_EXPORT bool inflate_gzip(
+ std::vector<char>& buffer
+ , tracker_request const& req
+ , request_callback* requester
+ , int maximum_tracker_response_length);
+
+ struct TORRENT_EXPORT timeout_handler
+ : intrusive_ptr_base<timeout_handler>
+ , boost::noncopyable
+ {
+ timeout_handler(asio::strand& str);
+
+ void set_timeout(int completion_timeout, int read_timeout);
+ void restart_read_timeout();
+ void cancel();
+
+ virtual void on_timeout() = 0;
+ virtual ~timeout_handler() {}
+
+ private:
+
+ void timeout_callback(asio::error_code const&);
+
+ boost::intrusive_ptr<timeout_handler> self()
+ { return boost::intrusive_ptr<timeout_handler>(this); }
+
+ asio::strand& m_strand;
+ // used for timeouts
+ // this is set when the request has been sent
+ ptime m_start_time;
+ // this is set every time something is received
+ ptime m_read_time;
+ // the asio async operation
+ deadline_timer m_timeout;
+
+ int m_completion_timeout;
+ int m_read_timeout;
+
+ typedef boost::mutex mutex_t;
+ mutable mutex_t m_mutex;
+ bool m_abort;
+ };
+
+ struct TORRENT_EXPORT tracker_connection
+ : timeout_handler
+ {
+ tracker_connection(tracker_manager& man
+ , tracker_request const& req
+ , asio::strand& str
+ , address bind_interface
+ , boost::weak_ptr<request_callback> r);
+
+ boost::shared_ptr<request_callback> requester();
+ virtual ~tracker_connection() {}
+
+ tracker_request const& tracker_req() const { return m_req; }
+
+ void fail(int code, char const* msg);
+ void fail_timeout();
+ virtual void close();
+ address const& bind_interface() const { return m_bind_interface; }
+
+ protected:
+ boost::weak_ptr<request_callback> m_requester;
+ private:
+ address m_bind_interface;
+ tracker_manager& m_man;
+ const tracker_request m_req;
+ };
+
+ class TORRENT_EXPORT tracker_manager: boost::noncopyable
+ {
+ public:
+
+ tracker_manager(session_settings const& s, proxy_settings const& ps)
+ : m_settings(s)
+ , m_proxy(ps)
+ , m_abort(false) {}
+
+ void queue_request(
+ asio::strand& str
+ , connection_queue& cc
+ , tracker_request r
+ , std::string const& auth
+ , address bind_infc
+ , boost::weak_ptr<request_callback> c
+ = boost::weak_ptr<request_callback>());
+ void abort_all_requests();
+
+ void remove_request(tracker_connection const*);
+ bool empty() const;
+ int num_requests() const;
+
+ private:
+
+ typedef boost::recursive_mutex mutex_t;
+ mutable mutex_t m_mutex;
+
+ typedef std::list<boost::intrusive_ptr<tracker_connection> >
+ tracker_connections_t;
+ tracker_connections_t m_connections;
+ session_settings const& m_settings;
+ proxy_settings const& m_proxy;
+ bool m_abort;
+ };
+}
+
+#endif // TORRENT_TRACKER_MANAGER_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/udp_tracker_connection.hpp b/src/libtorrent/include/libtorrent/udp_tracker_connection.hpp
new file mode 100644
index 0000000..4fba505
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/udp_tracker_connection.hpp
@@ -0,0 +1,124 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_UDP_TRACKER_CONNECTION_HPP_INCLUDED
+#define TORRENT_UDP_TRACKER_CONNECTION_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <utility>
+#include <ctime>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/session_settings.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/peer.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/config.hpp"
+
+namespace libtorrent
+{
+ class TORRENT_EXPORT udp_tracker_connection: public tracker_connection
+ {
+ friend class tracker_manager;
+ public:
+
+ udp_tracker_connection(
+ asio::strand& str
+ , tracker_manager& man
+ , tracker_request const& req
+ , std::string const& hostname
+ , unsigned short port
+ , address bind_infc
+ , boost::weak_ptr<request_callback> c
+ , session_settings const& stn);
+
+ void close();
+
+ private:
+
+ enum action_t
+ {
+ action_connect,
+ action_announce,
+ action_scrape,
+ action_error
+ };
+
+ boost::intrusive_ptr<udp_tracker_connection> self()
+ { return boost::intrusive_ptr<udp_tracker_connection>(this); }
+
+ void name_lookup(asio::error_code const& error, udp::resolver::iterator i);
+ void timeout(asio::error_code const& error);
+
+ void send_udp_connect();
+ void connect_response(asio::error_code const& error, std::size_t bytes_transferred);
+
+ void send_udp_announce();
+ void announce_response(asio::error_code const& error, std::size_t bytes_transferred);
+
+ void send_udp_scrape();
+ void scrape_response(asio::error_code const& error, std::size_t bytes_transferred);
+
+ virtual void on_timeout();
+
+ tracker_manager& m_man;
+
+ asio::strand& m_strand;
+ udp::resolver m_name_lookup;
+ datagram_socket m_socket;
+ udp::endpoint m_target;
+ udp::endpoint m_sender;
+
+ int m_transaction_id;
+ boost::int64_t m_connection_id;
+ session_settings const& m_settings;
+ int m_attempts;
+ std::vector<char> m_buffer;
+ };
+
+}
+
+#endif // TORRENT_UDP_TRACKER_CONNECTION_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/utf8.hpp b/src/libtorrent/include/libtorrent/utf8.hpp
new file mode 100644
index 0000000..157a7fd
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/utf8.hpp
@@ -0,0 +1,161 @@
+/*
+ Copyright (C) 2004-2005 Cory Nelson
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// namespaces added by Arvid Norberg
+
+#ifndef __UTF8_H__
+#define __UTF8_H__
+
+#include <string>
+#include <iterator>
+#include <stdexcept>
+#include <cwchar>
+
+namespace libtorrent {
+namespace detail {
+
+template<typename InputIterator>
+wchar_t decode_utf8_mb(InputIterator &iter, InputIterator last)
+{
+ if (iter == last) throw std::runtime_error("incomplete UTF-8 sequence");
+ if (((*iter) & 0xc0) != 0x80) throw std::runtime_error("invalid UTF-8 sequence");
+
+ return (wchar_t)((*iter++) & 0x3f);
+}
+
+template<typename InputIterator>
+wchar_t decode_utf8(InputIterator &iter, InputIterator last)
+{
+ wchar_t ret;
+
+ if (((*iter) & 0x80) == 0) // one byte
+ {
+ ret = *iter++;
+ }
+ else if (((*iter) & 0xe0) == 0xc0) // two bytes
+ {
+ wchar_t byte1 = (*iter++) & 0x1f;
+ wchar_t byte2 = decode_utf8_mb(iter, last);
+ ret = (byte1 << 6) | byte2;
+ }
+ else if (((*iter) & 0xf0) == 0xe0) // three bytes
+ {
+ wchar_t byte1 = (*iter++) & 0x0f;
+ wchar_t byte2 = decode_utf8_mb(iter, last);
+ wchar_t byte3 = decode_utf8_mb(iter, last);
+ ret = (byte1 << 12) | (byte2 << 6) | byte3;
+ }
+ // TODO: support surrogate pairs
+ else throw std::runtime_error("UTF-8 not convertable to UTF-16");
+
+ return ret;
+}
+
+template<typename InputIterator, typename OutputIterator>
+OutputIterator utf8_wchar(InputIterator first, InputIterator last, OutputIterator dest)
+{
+ for(; first!=last; ++dest)
+ *dest = decode_utf8(first, last);
+ return dest;
+}
+
+template<typename InputIterator, typename OutputIterator>
+void encode_wchar(InputIterator iter, OutputIterator &dest)
+{
+ if(*iter <= 0x007F)
+ {
+ *dest=(char)*iter;
+ ++dest;
+ }
+ else if(*iter <= 0x07FF)
+ {
+ *dest = (char)(
+ 0xC0 |
+ ((*iter & 0x07C0) >> 6)
+ );
+ ++dest;
+
+ *dest = (char)(
+ 0x80 |
+ (*iter & 0x003F)
+ );
+ ++dest;
+ }
+ else if(*iter <= 0xFFFF)
+ {
+ *dest = (char)(
+ 0xE0 |
+ ((*iter & 0xF000) >> 12)
+ );
+ ++dest;
+
+ *dest = (char)(
+ 0x80 |
+ ((*iter & 0x0FC0) >> 6)
+ );
+ ++dest;
+
+ *dest = (char)(
+ 0x80 |
+ (*iter & 0x003F)
+ );
+ ++dest;
+ }
+}
+
+template<typename InputIterator, typename OutputIterator>
+OutputIterator wchar_utf8(InputIterator first, InputIterator last, OutputIterator dest)
+{
+ for(; first!=last; ++first)
+ encode_wchar(first, dest);
+ return dest;
+}
+
+}
+
+inline void utf8_wchar(const std::string &utf8, std::wstring &wide)
+{
+ wide.clear();
+ detail::utf8_wchar(utf8.begin(), utf8.end(), std::back_inserter(wide));
+}
+
+inline std::wstring utf8_wchar(const std::string &str)
+{
+ std::wstring ret;
+ utf8_wchar(str, ret);
+ return ret;
+}
+
+inline void wchar_utf8(const std::wstring &wide, std::string &utf8)
+{
+ utf8.clear();
+ detail::wchar_utf8(wide.begin(), wide.end(), std::back_inserter(utf8));
+}
+
+inline std::string wchar_utf8(const std::wstring &str)
+{
+ std::string ret;
+ wchar_utf8(str, ret);
+ return ret;
+}
+
+}
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/variant_stream.hpp b/src/libtorrent/include/libtorrent/variant_stream.hpp
new file mode 100644
index 0000000..bbe3d96
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/variant_stream.hpp
@@ -0,0 +1,676 @@
+// Copyright Daniel Wallin and Arvid Norberg 2007.
+// Use, modification and distribution is
+// subject to the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef VARIANT_STREAM_070211_HPP
+# define VARIANT_STREAM_070211_HPP
+
+# include <boost/variant.hpp>
+
+# include <boost/mpl/vector.hpp>
+# include <boost/mpl/void.hpp>
+# include <boost/mpl/remove.hpp>
+# include <boost/mpl/transform.hpp>
+# include <boost/mpl/size.hpp>
+
+# include <boost/preprocessor/repetition/enum_params.hpp>
+# include <boost/preprocessor/repetition/enum_binary_params.hpp>
+# include <boost/preprocessor/facilities/intercept.hpp>
+
+# include <boost/type_traits/add_pointer.hpp>
+# include <boost/noncopyable.hpp>
+
+#include <asio/io_service.hpp>
+
+# define NETWORK_VARIANT_STREAM_LIMIT 5
+
+namespace libtorrent {
+
+namespace aux
+{
+
+ struct delete_visitor
+ : boost::static_visitor<>
+ {
+ template <class T>
+ void operator()(T* p) const
+ {
+ delete p;
+ }
+
+ void operator()(boost::blank) const
+ {}
+ };
+
+// -------------- io_control -----------
+
+ template<class IO_Control_Command>
+ struct io_control_visitor_ec: boost::static_visitor<>
+ {
+ io_control_visitor_ec(IO_Control_Command& ioc, asio::error_code& ec_)
+ : ioc(ioc), ec(ec_) {}
+
+ template <class T>
+ void operator()(T* p) const
+ {
+ p->io_control(ioc, ec);
+ }
+
+ void operator()(boost::blank) const
+ {}
+
+ IO_Control_Command& ioc;
+ asio::error_code& ec;
+ };
+
+ template<class IO_Control_Command>
+ struct io_control_visitor
+ : boost::static_visitor<>
+ {
+ io_control_visitor(IO_Control_Command& ioc)
+ : ioc(ioc) {}
+
+ template <class T>
+ void operator()(T* p) const
+ {
+ p->io_control(ioc);
+ }
+
+ void operator()(boost::blank) const
+ {}
+
+ IO_Control_Command& ioc;
+ };
+// -------------- async_connect -----------
+
+ template <class EndpointType, class Handler>
+ struct async_connect_visitor
+ : boost::static_visitor<>
+ {
+ async_connect_visitor(EndpointType const& endpoint, Handler const& handler)
+ : endpoint(endpoint)
+ , handler(handler)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ {
+ p->async_connect(endpoint, handler);
+ }
+
+ void operator()(boost::blank) const
+ {}
+
+ EndpointType const& endpoint;
+ Handler const& handler;
+ };
+
+// -------------- bind -----------
+
+ template <class EndpointType>
+ struct bind_visitor_ec
+ : boost::static_visitor<>
+ {
+ bind_visitor_ec(EndpointType const& ep, asio::error_code& ec_)
+ : endpoint(ep)
+ , ec(ec_)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ { p->bind(endpoint, ec); }
+
+ void operator()(boost::blank) const {}
+
+ EndpointType const& endpoint;
+ asio::error_code& ec;
+ };
+
+ template <class EndpointType>
+ struct bind_visitor
+ : boost::static_visitor<>
+ {
+ bind_visitor(EndpointType const& ep)
+ : endpoint(ep)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ { p->bind(endpoint); }
+
+ void operator()(boost::blank) const {}
+
+ EndpointType const& endpoint;
+ };
+
+// -------------- open -----------
+
+ template <class Protocol>
+ struct open_visitor_ec
+ : boost::static_visitor<>
+ {
+ open_visitor_ec(Protocol const& p, asio::error_code& ec_)
+ : proto(p)
+ , ec(ec_)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ { p->open(proto, ec); }
+
+ void operator()(boost::blank) const {}
+
+ Protocol const& proto;
+ asio::error_code& ec;
+ };
+
+ template <class Protocol>
+ struct open_visitor
+ : boost::static_visitor<>
+ {
+ open_visitor(Protocol const& p)
+ : proto(p)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ { p->open(proto); }
+
+ void operator()(boost::blank) const {}
+
+ Protocol const& proto;
+ };
+
+// -------------- close -----------
+
+ struct close_visitor_ec
+ : boost::static_visitor<>
+ {
+ close_visitor_ec(asio::error_code& ec_)
+ : ec(ec_)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ { p->close(ec); }
+
+ void operator()(boost::blank) const {}
+
+ asio::error_code& ec;
+ };
+
+ struct close_visitor
+ : boost::static_visitor<>
+ {
+ template <class T>
+ void operator()(T* p) const
+ { p->close(); }
+
+ void operator()(boost::blank) const {}
+ };
+
+// -------------- remote_endpoint -----------
+
+ template <class EndpointType>
+ struct remote_endpoint_visitor_ec
+ : boost::static_visitor<EndpointType>
+ {
+ remote_endpoint_visitor_ec(asio::error_code& ec)
+ : error_code(ec)
+ {}
+
+ template <class T>
+ EndpointType operator()(T* p) const
+ { return p->remote_endpoint(error_code); }
+
+ EndpointType operator()(boost::blank) const
+ { return EndpointType(); }
+
+ asio::error_code& error_code;
+ };
+
+ template <class EndpointType>
+ struct remote_endpoint_visitor
+ : boost::static_visitor<EndpointType>
+ {
+ template <class T>
+ EndpointType operator()(T* p) const
+ { return p->remote_endpoint(); }
+
+ EndpointType operator()(boost::blank) const
+ { return EndpointType(); }
+ };
+
+// -------------- local_endpoint -----------
+
+ template <class EndpointType>
+ struct local_endpoint_visitor_ec
+ : boost::static_visitor<EndpointType>
+ {
+ local_endpoint_visitor_ec(asio::error_code& ec)
+ : error_code(ec)
+ {}
+
+ template <class T>
+ EndpointType operator()(T* p) const
+ {
+ return p->local_endpoint(error_code);
+ }
+
+ EndpointType operator()(boost::blank) const
+ {
+ return EndpointType();
+ }
+
+ asio::error_code& error_code;
+ };
+
+ template <class EndpointType>
+ struct local_endpoint_visitor
+ : boost::static_visitor<EndpointType>
+ {
+ template <class T>
+ EndpointType operator()(T* p) const
+ {
+ return p->local_endpoint();
+ }
+
+ EndpointType operator()(boost::blank) const
+ {
+ return EndpointType();
+ }
+ };
+
+// -------------- async_read_some -----------
+
+ template <class Mutable_Buffers, class Handler>
+ struct async_read_some_visitor
+ : boost::static_visitor<>
+ {
+ async_read_some_visitor(Mutable_Buffers const& buffers, Handler const& handler)
+ : buffers(buffers)
+ , handler(handler)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ {
+ p->async_read_some(buffers, handler);
+ }
+ void operator()(boost::blank) const
+ {}
+
+ Mutable_Buffers const& buffers;
+ Handler const& handler;
+ };
+
+// -------------- read_some -----------
+
+ template <class Mutable_Buffers>
+ struct read_some_visitor
+ : boost::static_visitor<std::size_t>
+ {
+ read_some_visitor(Mutable_Buffers const& buffers)
+ : buffers(buffers)
+ {}
+
+ template <class T>
+ std::size_t operator()(T* p) const
+ { return p->read_some(buffers); }
+
+ std::size_t operator()(boost::blank) const
+ { return 0; }
+
+ Mutable_Buffers const& buffers;
+ };
+
+ template <class Mutable_Buffers>
+ struct read_some_visitor_ec
+ : boost::static_visitor<std::size_t>
+ {
+ read_some_visitor_ec(Mutable_Buffers const& buffers, asio::error_code& ec_)
+ : buffers(buffers)
+ , ec(ec_)
+ {}
+
+ template <class T>
+ std::size_t operator()(T* p) const
+ { return p->read_some(buffers, ec); }
+
+ std::size_t operator()(boost::blank) const
+ { return 0; }
+
+ Mutable_Buffers const& buffers;
+ asio::error_code& ec;
+ };
+
+// -------------- async_write_some -----------
+
+ template <class Const_Buffers, class Handler>
+ struct async_write_some_visitor
+ : boost::static_visitor<>
+ {
+ async_write_some_visitor(Const_Buffers const& buffers, Handler const& handler)
+ : buffers(buffers)
+ , handler(handler)
+ {}
+
+ template <class T>
+ void operator()(T* p) const
+ {
+ p->async_write_some(buffers, handler);
+ }
+
+ void operator()(boost::blank) const
+ {}
+
+ Const_Buffers const& buffers;
+ Handler const& handler;
+ };
+
+// -------------- in_avail -----------
+
+ struct in_avail_visitor_ec
+ : boost::static_visitor<std::size_t>
+ {
+ in_avail_visitor_ec(asio::error_code& ec_)
+ : ec(ec_)
+ {}
+
+ template <class T>
+ std::size_t operator()(T* p) const
+ {
+ return p->in_avail(ec);
+ }
+
+ std::size_t operator()(boost::blank) const
+ {
+ return 0;
+ }
+
+ asio::error_code& ec;
+ };
+
+ struct in_avail_visitor
+ : boost::static_visitor<std::size_t>
+ {
+ template <class T>
+ std::size_t operator()(T* p) const
+ {
+ return p->in_avail();
+ }
+
+ void operator()(boost::blank) const
+ {}
+ };
+
+// -------------- io_service -----------
+
+ template <class IOService>
+ struct io_service_visitor
+ : boost::static_visitor<IOService&>
+ {
+ template <class T>
+ IOService& operator()(T* p) const
+ {
+ return p->io_service();
+ }
+
+ IOService& operator()(boost::blank) const
+ {
+ return *(IOService*)0;
+ }
+ };
+
+// -------------- lowest_layer -----------
+
+ template <class LowestLayer>
+ struct lowest_layer_visitor
+ : boost::static_visitor<LowestLayer&>
+ {
+ template <class T>
+ LowestLayer& operator()(T* p) const
+ {
+ return p->lowest_layer();
+ }
+
+ LowestLayer& operator()(boost::blank) const
+ {
+ return *(LowestLayer*)0;
+ }
+ };
+
+} // namespace aux
+
+template <
+ BOOST_PP_ENUM_BINARY_PARAMS(
+ NETWORK_VARIANT_STREAM_LIMIT, class S, = boost::mpl::void_ BOOST_PP_INTERCEPT
+ )
+>
+class variant_stream : boost::noncopyable
+{
+public:
+ typedef BOOST_PP_CAT(boost::mpl::vector, NETWORK_VARIANT_STREAM_LIMIT)<
+ BOOST_PP_ENUM_PARAMS(NETWORK_VARIANT_STREAM_LIMIT, S)
+ > types0;
+
+ typedef typename boost::mpl::remove<types0, boost::mpl::void_>::type types;
+
+ typedef typename boost::make_variant_over<
+ typename boost::mpl::push_back<
+ typename boost::mpl::transform<
+ types
+ , boost::add_pointer<boost::mpl::_>
+ >::type
+ , boost::blank
+ >::type
+ >::type variant_type;
+
+ typedef typename S0::lowest_layer_type lowest_layer_type;
+ typedef typename S0::endpoint_type endpoint_type;
+ typedef typename S0::protocol_type protocol_type;
+
+ explicit variant_stream() : m_variant(boost::blank()) {}
+
+ template <class S>
+ void instantiate(asio::io_service& ios)
+ {
+ std::auto_ptr<S> owned(new S(ios));
+ boost::apply_visitor(aux::delete_visitor(), m_variant);
+ m_variant = owned.get();
+ owned.release();
+ }
+
+ template <class S>
+ S& get()
+ {
+ return *boost::get<S*>(m_variant);
+ }
+
+ bool instantiated() const
+ {
+ return m_variant.which() != boost::mpl::size<types>::value;
+ }
+
+ ~variant_stream()
+ {
+ boost::apply_visitor(aux::delete_visitor(), m_variant);
+ }
+
+ template <class Mutable_Buffers>
+ std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(
+ aux::read_some_visitor_ec<Mutable_Buffers>(buffers, ec)
+ , m_variant
+ );
+ }
+
+ template <class Mutable_Buffers>
+ std::size_t read_some(Mutable_Buffers const& buffers)
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(
+ aux::read_some_visitor<Mutable_Buffers>(buffers)
+ , m_variant
+ );
+ }
+
+ template <class Mutable_Buffers, class Handler>
+ void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(
+ aux::async_read_some_visitor<Mutable_Buffers, Handler>(buffers, handler)
+ , m_variant
+ );
+ }
+
+ template <class Const_Buffers, class Handler>
+ void async_write_some(Const_Buffers const& buffers, Handler const& handler)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(
+ aux::async_write_some_visitor<Const_Buffers, Handler>(buffers, handler)
+ , m_variant
+ );
+ }
+
+ template <class Handler>
+ void async_connect(endpoint_type const& endpoint, Handler const& handler)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(
+ aux::async_connect_visitor<endpoint_type, Handler>(endpoint, handler), m_variant
+ );
+ }
+
+ template <class IO_Control_Command>
+ void io_control(IO_Control_Command& ioc)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(
+ aux::io_control_visitor<IO_Control_Command>(ioc), m_variant
+ );
+ }
+
+ template <class IO_Control_Command>
+ void io_control(IO_Control_Command& ioc, asio::error_code& ec)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(
+ aux::io_control_visitor_ec<IO_Control_Command>(ioc, ec)
+ , m_variant
+ );
+ }
+
+ void bind(endpoint_type const& endpoint)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(aux::bind_visitor<endpoint_type>(endpoint), m_variant);
+ }
+
+ void bind(endpoint_type const& endpoint, asio::error_code& ec)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(
+ aux::bind_visitor_ec<endpoint_type>(endpoint, ec), m_variant
+ );
+ }
+
+ void open(protocol_type const& p)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(aux::open_visitor<protocol_type>(p), m_variant);
+ }
+
+ void open(protocol_type const& p, asio::error_code& ec)
+ {
+ TORRENT_ASSERT(instantiated());
+ boost::apply_visitor(
+ aux::open_visitor_ec<protocol_type>(p, ec), m_variant
+ );
+ }
+
+ void close()
+ {
+ if (!instantiated()) return;
+ boost::apply_visitor(aux::close_visitor(), m_variant);
+ }
+
+ void close(asio::error_code& ec)
+ {
+ if (!instantiated()) return;
+ boost::apply_visitor(
+ aux::close_visitor_ec(ec), m_variant
+ );
+ }
+
+ std::size_t in_avail()
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(aux::in_avail_visitor(), m_variant);
+ }
+
+ std::size_t in_avail(asio::error_code& ec)
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(
+ aux::in_avail_visitor_ec(ec), m_variant
+ );
+ }
+
+ endpoint_type remote_endpoint()
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(aux::remote_endpoint_visitor<endpoint_type>(), m_variant);
+ }
+
+ endpoint_type remote_endpoint(asio::error_code& ec)
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(
+ aux::remote_endpoint_visitor_ec<endpoint_type>(ec), m_variant
+ );
+ }
+
+ endpoint_type local_endpoint()
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(aux::local_endpoint_visitor<endpoint_type>(), m_variant);
+ }
+
+ endpoint_type local_endpoint(asio::error_code& ec)
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(
+ aux::local_endpoint_visitor_ec<endpoint_type>(ec), m_variant
+ );
+ }
+
+ asio::io_service& io_service()
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(
+ aux::io_service_visitor<asio::io_service>(), m_variant
+ );
+ }
+
+ lowest_layer_type& lowest_layer()
+ {
+ TORRENT_ASSERT(instantiated());
+ return boost::apply_visitor(
+ aux::lowest_layer_visitor<lowest_layer_type>(), m_variant
+ );
+ }
+
+private:
+ variant_type m_variant;
+};
+
+} // namespace libtorrent
+
+#endif // VARIANT_STREAM_070211_HPP
+
diff --git a/src/libtorrent/include/libtorrent/version.hpp b/src/libtorrent/include/libtorrent/version.hpp
new file mode 100644
index 0000000..de1b8bc
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/version.hpp
@@ -0,0 +1,41 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_VERSION_HPP_INCLUDED
+#define TORRENT_VERSION_HPP_INCLUDED
+
+#define LIBTORRENT_VERSION_MAJOR 0
+#define LIBTORRENT_VERSION_MINOR 13
+
+#define LIBTORRENT_VERSION "0.13.0.0"
+
+#endif
diff --git a/src/libtorrent/include/libtorrent/web_peer_connection.hpp b/src/libtorrent/include/libtorrent/web_peer_connection.hpp
new file mode 100644
index 0000000..742d823
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/web_peer_connection.hpp
@@ -0,0 +1,181 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED
+#define TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED
+
+#include <ctime>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <string>
+
+#include "libtorrent/debug.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/smart_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/array.hpp>
+#include <boost/optional.hpp>
+#include <boost/cstdint.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/buffer.hpp"
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/storage.hpp"
+#include "libtorrent/stat.hpp"
+#include "libtorrent/alert.hpp"
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/piece_block_progress.hpp"
+#include "libtorrent/config.hpp"
+// parse_url
+#include "libtorrent/tracker_manager.hpp"
+// http_parser
+#include "libtorrent/http_tracker_connection.hpp"
+
+namespace libtorrent
+{
+ class torrent;
+
+ namespace detail
+ {
+ struct session_impl;
+ }
+
+ class TORRENT_EXPORT web_peer_connection
+ : public peer_connection
+ {
+ friend class invariant_access;
+ public:
+
+ // this is the constructor where the we are the active part.
+ // The peer_conenction should handshake and verify that the
+ // other end has the correct id
+ web_peer_connection(
+ aux::session_impl& ses
+ , boost::weak_ptr<torrent> t
+ , boost::shared_ptr<socket_type> s
+ , tcp::endpoint const& remote
+ , std::string const& url
+ , policy::peer* peerinfo);
+
+ ~web_peer_connection();
+
+ // called from the main loop when this connection has any
+ // work to do.
+ void on_sent(asio::error_code const& error
+ , std::size_t bytes_transferred);
+ void on_receive(asio::error_code const& error
+ , std::size_t bytes_transferred);
+
+ std::string const& url() const { return m_url; }
+
+ virtual void get_specific_peer_info(peer_info& p) const;
+ virtual bool in_handshake() const;
+
+ // the following functions appends messages
+ // to the send buffer
+ void write_choke() {}
+ void write_unchoke() {}
+ void write_interested() {}
+ void write_not_interested() {}
+ void write_request(peer_request const& r);
+ void write_cancel(peer_request const& r)
+ { incoming_reject_request(r); }
+ void write_have(int index) {}
+ void write_piece(peer_request const& r, char* buffer) { TORRENT_ASSERT(false); }
+ void write_keepalive() {}
+ void on_connected();
+ void write_reject_request(peer_request const&) {}
+ void write_allow_fast(int) {}
+
+#ifndef NDEBUG
+ void check_invariant() const;
+#endif
+
+ private:
+
+ // returns the block currently being
+ // downloaded. And the progress of that
+ // block. If the peer isn't downloading
+ // a piece for the moment, the boost::optional
+ // will be invalid.
+ boost::optional<piece_block_progress> downloading_piece_progress() const;
+
+ // this has one entry per bittorrent request
+ std::deque<peer_request> m_requests;
+ // this has one entry per http-request
+ // (might be more than the bt requests)
+ std::deque<int> m_file_requests;
+
+ std::string m_server_string;
+ http_parser m_parser;
+ std::string m_auth;
+ std::string m_host;
+ int m_port;
+ std::string m_path;
+ std::string m_url;
+
+ // the first request will contain a little bit more data
+ // than subsequent ones, things that aren't critical are left
+ // out to save bandwidth.
+ bool m_first_request;
+
+ // this is used for intermediate storage of pieces
+ // that is received in more than on HTTP responses
+ std::vector<char> m_piece;
+ // the mapping of the data in the m_piece buffer
+ peer_request m_intermediate_piece;
+
+ // the number of bytes into the receive buffer where
+ // current read cursor is.
+ int m_body_start;
+ // the number of bytes received in the current HTTP
+ // response. used to know where in the buffer the
+ // next response starts
+ int m_received_body;
+ };
+}
+
+#endif // TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED
+
diff --git a/src/libtorrent/include/libtorrent/xml_parse.hpp b/src/libtorrent/include/libtorrent/xml_parse.hpp
new file mode 100644
index 0000000..aaf71a8
--- /dev/null
+++ b/src/libtorrent/include/libtorrent/xml_parse.hpp
@@ -0,0 +1,211 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_XML_PARSE_HPP
+#define TORRENT_XML_PARSE_HPP
+
+#include <cctype>
+
+namespace libtorrent
+{
+ enum
+ {
+ xml_start_tag,
+ xml_end_tag,
+ xml_empty_tag,
+ xml_declaration_tag,
+ xml_string,
+ xml_attribute,
+ xml_comment,
+ xml_parse_error
+ };
+
+ // callback(int type, char const* name, char const* val)
+ // str2 is only used for attributes. name is element or attribute
+ // name and val is attribute value
+
+ template <class CallbackType>
+ void xml_parse(char* p, char* end, CallbackType callback)
+ {
+ for(;p != end; ++p)
+ {
+ char const* start = p;
+ char const* val_start = 0;
+ int token;
+ // look for tag start
+ for(; *p != '<' && p != end; ++p);
+
+ if (p != start)
+ {
+ if (p != end)
+ {
+ TORRENT_ASSERT(*p == '<');
+ *p = 0;
+ }
+ token = xml_string;
+ callback(token, start, val_start);
+ if (p != end) *p = '<';
+ }
+
+ if (p == end) break;
+
+ // skip '<'
+ ++p;
+
+ // parse the name of the tag.
+ for (start = p; p != end && *p != '>' && !std::isspace(*p); ++p);
+
+ char* tag_name_end = p;
+
+ // skip the attributes for now
+ for (; p != end && *p != '>'; ++p);
+
+ // parse error
+ if (p == end)
+ {
+ token = xml_parse_error;
+ start = "unexpected end of file";
+ callback(token, start, val_start);
+ break;
+ }
+
+ TORRENT_ASSERT(*p == '>');
+ // save the character that terminated the tag name
+ // it could be both '>' and ' '.
+ char save = *tag_name_end;
+ *tag_name_end = 0;
+
+ char* tag_end = p;
+ if (*start == '/')
+ {
+ ++start;
+ token = xml_end_tag;
+ callback(token, start, val_start);
+ }
+ else if (*(p-1) == '/')
+ {
+ *(p-1) = 0;
+ token = xml_empty_tag;
+ callback(token, start, val_start);
+ *(p-1) = '/';
+ tag_end = p - 1;
+ }
+ else if (*start == '?' && *(p-1) == '?')
+ {
+ *(p-1) = 0;
+ ++start;
+ token = xml_declaration_tag;
+ callback(token, start, val_start);
+ *(p-1) = '?';
+ tag_end = p - 1;
+ }
+ else if (start + 5 < p && memcmp(start, "!--", 3) == 0 && memcmp(p-2, "--", 2) == 0)
+ {
+ start += 3;
+ *(p-2) = 0;
+ token = xml_comment;
+ callback(token, start, val_start);
+ *(p-2) = '-';
+ tag_end = p - 2;
+ }
+ else
+ {
+ token = xml_start_tag;
+ callback(token, start, val_start);
+ }
+
+ *tag_name_end = save;
+
+ // parse attributes
+ for (char* i = tag_name_end; i < tag_end; ++i)
+ {
+ // find start of attribute name
+ for (; i != tag_end && std::isspace(*i); ++i);
+ if (i == tag_end) break;
+ start = i;
+ // find end of attribute name
+ for (; i != tag_end && *i != '=' && !std::isspace(*i); ++i);
+ char* name_end = i;
+
+ // look for equality sign
+ for (; i != tag_end && *i != '='; ++i);
+
+ if (i == tag_end)
+ {
+ token = xml_parse_error;
+ val_start = 0;
+ start = "garbage inside element brackets";
+ callback(token, start, val_start);
+ break;
+ }
+
+ ++i;
+ for (; i != tag_end && std::isspace(*i); ++i);
+ // check for parse error (values must be quoted)
+ if (i == tag_end || (*i != '\'' && *i != '\"'))
+ {
+ token = xml_parse_error;
+ val_start = 0;
+ start = "unquoted attribute value";
+ callback(token, start, val_start);
+ break;
+ }
+ char quote = *i;
+ ++i;
+ val_start = i;
+ for (; i != tag_end && *i != quote; ++i);
+ // parse error (missing end quote)
+ if (i == tag_end)
+ {
+ token = xml_parse_error;
+ val_start = 0;
+ start = "missing end quote on attribute";
+ callback(token, start, val_start);
+ break;
+ }
+ save = *i;
+ *i = 0;
+ *name_end = 0;
+ token = xml_attribute;
+ callback(token, start, val_start);
+ *name_end = '=';
+ *i = save;
+ }
+ }
+
+ }
+
+}
+
+
+#endif
+
diff --git a/src/libtorrent/src/alert.cpp b/src/libtorrent/src/alert.cpp
new file mode 100644
index 0000000..be6f718
--- /dev/null
+++ b/src/libtorrent/src/alert.cpp
@@ -0,0 +1,152 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg, Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/alert.hpp"
+#include <boost/thread/xtime.hpp>
+
+namespace libtorrent {
+
+ alert::alert(severity_t severity, const std::string& msg)
+ : m_msg(msg)
+ , m_severity(severity)
+ , m_timestamp(time_now())
+ {
+ }
+
+ alert::~alert()
+ {
+ }
+
+ ptime alert::timestamp() const
+ {
+ return m_timestamp;
+ }
+
+ const std::string& alert::msg() const
+ {
+ return m_msg;
+ }
+
+ alert::severity_t alert::severity() const
+ {
+ return m_severity;
+ }
+
+
+
+ alert_manager::alert_manager()
+ : m_severity(alert::fatal)
+ {}
+
+ alert_manager::~alert_manager()
+ {
+ while (!m_alerts.empty())
+ {
+ delete m_alerts.front();
+ m_alerts.pop();
+ }
+ }
+
+ alert const* alert_manager::wait_for_alert(time_duration max_wait)
+ {
+ boost::mutex::scoped_lock lock(m_mutex);
+
+ if (!m_alerts.empty()) return m_alerts.front();
+
+ int secs = total_seconds(max_wait);
+ max_wait -= seconds(secs);
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += secs;
+ boost::int64_t nsec = xt.nsec + total_microseconds(max_wait) * 1000;
+ if (nsec > 1000000000)
+ {
+ nsec -= 1000000000;
+ xt.sec += 1;
+ }
+ xt.nsec = boost::xtime::xtime_nsec_t(nsec);
+ if (!m_condition.timed_wait(lock, xt)) return 0;
+ TORRENT_ASSERT(!m_alerts.empty());
+ if (m_alerts.empty()) return 0;
+ return m_alerts.front();
+ }
+
+ void alert_manager::post_alert(const alert& alert_)
+ {
+ boost::mutex::scoped_lock lock(m_mutex);
+ if (m_severity > alert_.severity()) return;
+
+ // the internal limit is 100 alerts
+ if (m_alerts.size() == 100)
+ {
+ alert* result = m_alerts.front();
+ m_alerts.pop();
+ delete result;
+ }
+ m_alerts.push(alert_.clone().release());
+ m_condition.notify_all();
+ }
+
+ std::auto_ptr<alert> alert_manager::get()
+ {
+ boost::mutex::scoped_lock lock(m_mutex);
+
+ TORRENT_ASSERT(!m_alerts.empty());
+
+ alert* result = m_alerts.front();
+ m_alerts.pop();
+ return std::auto_ptr<alert>(result);
+ }
+
+ bool alert_manager::pending() const
+ {
+ boost::mutex::scoped_lock lock(m_mutex);
+
+ return !m_alerts.empty();
+ }
+
+ void alert_manager::set_severity(alert::severity_t severity)
+ {
+ boost::mutex::scoped_lock lock(m_mutex);
+
+ m_severity = severity;
+ }
+
+ bool alert_manager::should_post(alert::severity_t severity) const
+ {
+ return severity >= m_severity;
+ }
+
+} // namespace libtorrent
+
diff --git a/src/libtorrent/src/assert.cpp b/src/libtorrent/src/assert.cpp
new file mode 100644
index 0000000..1073e05
--- /dev/null
+++ b/src/libtorrent/src/assert.cpp
@@ -0,0 +1,77 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef NDEBUG
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#if defined __linux__ && defined __GNUC__
+#include <execinfo.h>
+#endif
+
+void assert_fail(char const* expr, int line, char const* file, char const* function)
+{
+
+ fprintf(stderr, "assertion failed. Please file a bugreport at "
+ "http://code.rasterbar.com/libtorrent/newticket\n"
+ "Please include the following information:\n\n"
+ "file: '%s'\n"
+ "line: %d\n"
+ "function: %s\n"
+ "expression: %s\n"
+ "stack:\n", file, line, function, expr);
+
+#if defined __linux__ && defined __GNUC__
+ void* stack[50];
+ int size = backtrace(stack, 50);
+ char** symbols = backtrace_symbols(stack, size);
+
+ for (int i = 0; i < size; ++i)
+ {
+ fprintf(stderr, "%d: %s\n", i, symbols[i]);
+ }
+
+ free(symbols);
+#endif
+ // send SIGINT to the current process
+ // to break into the debugger
+ raise(SIGINT);
+ abort();
+}
+
+#else
+
+void assert_fail(char const* expr, int line, char const* file, char const* function) {}
+
+#endif
+
diff --git a/src/libtorrent/src/broadcast_socket.cpp b/src/libtorrent/src/broadcast_socket.cpp
new file mode 100644
index 0000000..c7b7e71
--- /dev/null
+++ b/src/libtorrent/src/broadcast_socket.cpp
@@ -0,0 +1,248 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <asio/ip/host_name.hpp>
+#include <asio/ip/multicast.hpp>
+#include <boost/bind.hpp>
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/enum_net.hpp"
+#include "libtorrent/broadcast_socket.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ bool is_local(address const& a)
+ {
+ if (a.is_v6()) return a.to_v6().is_link_local();
+ address_v4 a4 = a.to_v4();
+ unsigned long ip = a4.to_ulong();
+ return ((ip & 0xff000000) == 0x0a000000
+ || (ip & 0xfff00000) == 0xac100000
+ || (ip & 0xffff0000) == 0xc0a80000);
+ }
+
+ bool is_loopback(address const& addr)
+ {
+ if (addr.is_v4())
+ return addr.to_v4() == address_v4::loopback();
+ else
+ return addr.to_v6() == address_v6::loopback();
+ }
+
+ bool is_multicast(address const& addr)
+ {
+ if (addr.is_v4())
+ return addr.to_v4().is_multicast();
+ else
+ return addr.to_v6().is_multicast();
+ }
+
+ bool is_any(address const& addr)
+ {
+ if (addr.is_v4())
+ return addr.to_v4() == address_v4::any();
+ else
+ return addr.to_v6() == address_v6::any();
+ }
+
+ address guess_local_address(asio::io_service& ios)
+ {
+ // make a best guess of the interface we're using and its IP
+ asio::error_code ec;
+ std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
+ address ret = address_v4::any();
+ for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
+ , end(interfaces.end()); i != end; ++i)
+ {
+ address const& a = i->interface_address;
+ if (is_loopback(a)
+ || is_multicast(a)
+ || is_any(a)) continue;
+
+ // prefer a v4 address, but return a v6 if
+ // there are no v4
+ if (a.is_v4()) return a;
+
+ if (ret != address_v4::any())
+ ret = a;
+ }
+ return ret;
+ }
+
+ // count the length of the common bit prefix
+ int common_bits(unsigned char const* b1
+ , unsigned char const* b2, int n)
+ {
+ for (int i = 0; i < n; ++i, ++b1, ++b2)
+ {
+ unsigned char a = *b1 ^ *b2;
+ if (a == 0) continue;
+ int ret = i * 8 + 8;
+ for (; a > 0; a >>= 1) --ret;
+ return ret;
+ }
+ return n * 8;
+ }
+
+ // returns the number of bits in that differ from the right
+ // between the addresses.
+ int cidr_distance(address const& a1, address const& a2)
+ {
+ if (a1.is_v4() == a2.is_v4())
+ {
+ // both are v4
+ address_v4::bytes_type b1 = a1.to_v4().to_bytes();
+ address_v4::bytes_type b2 = a2.to_v4().to_bytes();
+ return address_v4::bytes_type::static_size * 8
+ - common_bits(b1.c_array(), b2.c_array(), b1.size());
+ }
+
+ address_v6::bytes_type b1;
+ address_v6::bytes_type b2;
+ if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
+ else b1 = a1.to_v6().to_bytes();
+ if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
+ else b2 = a2.to_v6().to_bytes();
+ return address_v6::bytes_type::static_size * 8
+ - common_bits(b1.c_array(), b2.c_array(), b1.size());
+ }
+
+ broadcast_socket::broadcast_socket(asio::io_service& ios
+ , udp::endpoint const& multicast_endpoint
+ , receive_handler_t const& handler
+ , bool loopback)
+ : m_multicast_endpoint(multicast_endpoint)
+ , m_on_receive(handler)
+ {
+ TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));
+
+ using namespace asio::ip::multicast;
+
+ asio::error_code ec;
+ std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);
+
+ for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
+ , end(interfaces.end()); i != end; ++i)
+ {
+ // only broadcast to IPv4 addresses that are not local
+ if (!is_local(i->interface_address)) continue;
+ // only multicast on compatible networks
+ if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue;
+ // ignore any loopback interface
+ if (is_loopback(i->interface_address)) continue;
+
+ boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
+ if (i->interface_address.is_v4())
+ {
+ s->open(udp::v4(), ec);
+ if (ec) continue;
+ s->set_option(datagram_socket::reuse_address(true), ec);
+ if (ec) continue;
+ s->bind(udp::endpoint(address_v4::any(), multicast_endpoint.port()), ec);
+ if (ec) continue;
+ s->set_option(join_group(multicast_endpoint.address()), ec);
+ if (ec) continue;
+ s->set_option(outbound_interface(i->interface_address.to_v4()), ec);
+ if (ec) continue;
+ }
+ else
+ {
+ s->open(udp::v6(), ec);
+ if (ec) continue;
+ s->set_option(datagram_socket::reuse_address(true), ec);
+ if (ec) continue;
+ s->bind(udp::endpoint(address_v6::any(), multicast_endpoint.port()), ec);
+ if (ec) continue;
+ s->set_option(join_group(multicast_endpoint.address()), ec);
+ if (ec) continue;
+// s->set_option(outbound_interface(i->interface_address.to_v6()), ec);
+// if (ec) continue;
+ }
+ s->set_option(hops(255), ec);
+ if (ec) continue;
+ s->set_option(enable_loopback(loopback), ec);
+ if (ec) continue;
+ m_sockets.push_back(socket_entry(s));
+ socket_entry& se = m_sockets.back();
+ s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
+ , se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
+#ifndef NDEBUG
+// std::cerr << "broadcast socket [ if: " << i->to_v4().to_string()
+// << " group: " << multicast_endpoint.address() << " ]" << std::endl;
+#endif
+ }
+ }
+
+ void broadcast_socket::send(char const* buffer, int size, asio::error_code& ec)
+ {
+ for (std::list<socket_entry>::iterator i = m_sockets.begin()
+ , end(m_sockets.end()); i != end; ++i)
+ {
+ if (!i->socket) continue;
+ asio::error_code e;
+ i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
+#ifndef NDEBUG
+// std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl;
+#endif
+ if (e)
+ {
+ i->socket->close(e);
+ i->socket.reset();
+ }
+ }
+ }
+
+ void broadcast_socket::on_receive(socket_entry* s, asio::error_code const& ec
+ , std::size_t bytes_transferred)
+ {
+ if (ec || bytes_transferred == 0 || !m_on_receive) return;
+ m_on_receive(s->remote, s->buffer, bytes_transferred);
+ if (!s->socket) return;
+ s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
+ , s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
+ }
+
+ void broadcast_socket::close()
+ {
+ m_on_receive.clear();
+
+ for (std::list<socket_entry>::iterator i = m_sockets.begin()
+ , end(m_sockets.end()); i != end; ++i)
+ {
+ if (!i->socket) continue;
+ i->socket->close();
+ }
+ }
+}
+
+
diff --git a/src/libtorrent/src/bt_peer_connection.cpp b/src/libtorrent/src/bt_peer_connection.cpp
new file mode 100644
index 0000000..d70e7af
--- /dev/null
+++ b/src/libtorrent/src/bt_peer_connection.cpp
@@ -0,0 +1,2528 @@
+/*
+
+Copyright (c) 2003 - 2006, Arvid Norberg
+Copyright (c) 2007, Arvid Norberg, Un Shyam
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <iostream>
+#include <iomanip>
+#include <limits>
+#include <boost/bind.hpp>
+
+#include "libtorrent/bt_peer_connection.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/identify_client.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/alert_types.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/version.hpp"
+#include "libtorrent/extensions.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+#include "libtorrent/pe_crypto.hpp"
+#include "libtorrent/hasher.hpp"
+#endif
+
+using boost::bind;
+using boost::shared_ptr;
+using libtorrent::aux::session_impl;
+
+namespace libtorrent
+{
+ const bt_peer_connection::message_handler
+ bt_peer_connection::m_message_handler[] =
+ {
+ &bt_peer_connection::on_choke,
+ &bt_peer_connection::on_unchoke,
+ &bt_peer_connection::on_interested,
+ &bt_peer_connection::on_not_interested,
+ &bt_peer_connection::on_have,
+ &bt_peer_connection::on_bitfield,
+ &bt_peer_connection::on_request,
+ &bt_peer_connection::on_piece,
+ &bt_peer_connection::on_cancel,
+ &bt_peer_connection::on_dht_port,
+ 0, 0, 0,
+ // FAST extension messages
+ &bt_peer_connection::on_suggest_piece,
+ &bt_peer_connection::on_have_all,
+ &bt_peer_connection::on_have_none,
+ &bt_peer_connection::on_reject_request,
+ &bt_peer_connection::on_allowed_fast,
+ 0, 0,
+ &bt_peer_connection::on_extended
+ };
+
+
+ bt_peer_connection::bt_peer_connection(
+ session_impl& ses
+ , boost::weak_ptr<torrent> tor
+ , shared_ptr<socket_type> s
+ , tcp::endpoint const& remote
+ , policy::peer* peerinfo)
+ : peer_connection(ses, tor, s, remote
+ , peerinfo)
+ , m_state(read_protocol_identifier)
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ , m_supports_extensions(false)
+#endif
+ , m_supports_dht_port(false)
+ , m_supports_fast(false)
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ , m_encrypted(false)
+ , m_rc4_encrypted(false)
+ , m_sync_bytes_read(0)
+ , m_enc_send_buffer(0, 0)
+#endif
+#ifndef NDEBUG
+ , m_sent_bitfield(false)
+ , m_in_constructor(true)
+ , m_sent_handshake(false)
+#endif
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "*** bt_peer_connection\n";
+#endif
+
+#ifndef NDEBUG
+ m_in_constructor = false;
+#endif
+ }
+
+ bt_peer_connection::bt_peer_connection(
+ session_impl& ses
+ , boost::shared_ptr<socket_type> s
+ , policy::peer* peerinfo)
+ : peer_connection(ses, s, peerinfo)
+ , m_state(read_protocol_identifier)
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ , m_supports_extensions(false)
+#endif
+ , m_supports_dht_port(false)
+ , m_supports_fast(false)
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ , m_encrypted(false)
+ , m_rc4_encrypted(false)
+ , m_sync_bytes_read(0)
+ , m_enc_send_buffer(0, 0)
+#endif
+#ifndef NDEBUG
+ , m_sent_bitfield(false)
+ , m_in_constructor(true)
+ , m_sent_handshake(false)
+#endif
+ {
+
+ // we are not attached to any torrent yet.
+ // we have to wait for the handshake to see
+ // which torrent the connector want's to connect to
+
+
+ // upload bandwidth will only be given to connections
+ // that are part of a torrent. Since this is an incoming
+ // connection, we have to give it some initial bandwidth
+ // to send the handshake.
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ m_bandwidth_limit[download_channel].assign(2048);
+ m_bandwidth_limit[upload_channel].assign(2048);
+#else
+ m_bandwidth_limit[download_channel].assign(80);
+ m_bandwidth_limit[upload_channel].assign(80);
+#endif
+
+ // start in the state where we are trying to read the
+ // handshake from the other side
+ reset_recv_buffer(20);
+ setup_receive();
+#ifndef NDEBUG
+ m_in_constructor = false;
+#endif
+ }
+
+ bt_peer_connection::~bt_peer_connection()
+ {
+ }
+
+ void bt_peer_connection::on_connected()
+ {
+#ifndef TORRENT_DISABLE_ENCRYPTION
+
+ pe_settings::enc_policy const& out_enc_policy = m_ses.get_pe_settings().out_enc_policy;
+
+ if (out_enc_policy == pe_settings::forced)
+ {
+ write_pe1_2_dhkey();
+
+ m_state = read_pe_dhkey;
+ reset_recv_buffer(dh_key_len);
+ setup_receive();
+ }
+ else if (out_enc_policy == pe_settings::enabled)
+ {
+ TORRENT_ASSERT(peer_info_struct());
+
+ policy::peer* pi = peer_info_struct();
+ if (pi->pe_support == true)
+ {
+ // toggle encryption support flag, toggled back to
+ // true if encrypted portion of the handshake
+ // completes correctly
+ pi->pe_support = false;
+
+ // if this fails, we need to reconnect
+ // fast.
+ fast_reconnect(true);
+
+ write_pe1_2_dhkey();
+ m_state = read_pe_dhkey;
+ reset_recv_buffer(dh_key_len);
+ setup_receive();
+ }
+ else // pi->pe_support == false
+ {
+ // toggled back to false if standard handshake
+ // completes correctly (without encryption)
+ pi->pe_support = true;
+
+ write_handshake();
+ reset_recv_buffer(20);
+ setup_receive();
+ }
+ }
+ else if (out_enc_policy == pe_settings::disabled)
+#endif
+ {
+ write_handshake();
+
+ // start in the state where we are trying to read the
+ // handshake from the other side
+ reset_recv_buffer(20);
+ setup_receive();
+ }
+ }
+
+ void bt_peer_connection::on_metadata()
+ {
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+ write_bitfield(t->pieces());
+#ifndef TORRENT_DISABLE_DHT
+ if (m_supports_dht_port && m_ses.m_dht)
+ write_dht_port(m_ses.get_dht_settings().service_port);
+#endif
+ }
+
+ void bt_peer_connection::write_dht_port(int listen_port)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> DHT_PORT [ " << listen_port << " ]\n";
+#endif
+ char msg[] = {0,0,0,3, msg_dht_port, 0, 0};
+ char* ptr = msg + 5;
+ detail::write_uint16(listen_port, ptr);
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_have_all()
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(m_sent_handshake && !m_sent_bitfield);
+#ifndef NDEBUG
+ m_sent_bitfield = true;
+#endif
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> HAVE_ALL\n";
+#endif
+ char msg[] = {0,0,0,1, msg_have_all};
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_have_none()
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(m_sent_handshake && !m_sent_bitfield);
+#ifndef NDEBUG
+ m_sent_bitfield = true;
+#endif
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> HAVE_NONE\n";
+#endif
+ char msg[] = {0,0,0,1, msg_have_none};
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_reject_request(peer_request const& r)
+ {
+ INVARIANT_CHECK;
+
+ if (!m_supports_fast) return;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+ TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
+
+ char msg[] = {0,0,0,13, msg_reject_request,0,0,0,0, 0,0,0,0, 0,0,0,0};
+ char* ptr = msg + 5;
+ detail::write_int32(r.piece, ptr); // index
+ detail::write_int32(r.start, ptr); // begin
+ detail::write_int32(r.length, ptr); // length
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_allow_fast(int piece)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+ TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
+ TORRENT_ASSERT(m_supports_fast);
+
+ char msg[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0};
+ char* ptr = msg + 5;
+ detail::write_int32(piece, ptr);
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::get_specific_peer_info(peer_info& p) const
+ {
+ TORRENT_ASSERT(!associated_torrent().expired());
+
+ if (is_interesting()) p.flags |= peer_info::interesting;
+ if (is_choked()) p.flags |= peer_info::choked;
+ if (is_peer_interested()) p.flags |= peer_info::remote_interested;
+ if (has_peer_choked()) p.flags |= peer_info::remote_choked;
+ if (support_extensions()) p.flags |= peer_info::supports_extensions;
+ if (is_local()) p.flags |= peer_info::local_connection;
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ if (m_encrypted)
+ {
+ m_rc4_encrypted ?
+ p.flags |= peer_info::rc4_encrypted :
+ p.flags |= peer_info::plaintext_encrypted;
+ }
+#endif
+
+ if (!is_connecting() && in_handshake())
+ p.flags |= peer_info::handshake;
+ if (is_connecting() && !is_queued()) p.flags |= peer_info::connecting;
+ if (is_queued()) p.flags |= peer_info::queued;
+
+ p.client = m_client_version;
+ p.connection_type = peer_info::standard_bittorrent;
+
+ }
+
+ bool bt_peer_connection::in_handshake() const
+ {
+ return m_state < read_packet_size;
+ }
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+
+ void bt_peer_connection::write_pe1_2_dhkey()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_encrypted);
+ TORRENT_ASSERT(!m_rc4_encrypted);
+ TORRENT_ASSERT(!m_DH_key_exchange.get());
+ TORRENT_ASSERT(!m_sent_handshake);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ if (is_local())
+ (*m_logger) << " initiating encrypted handshake\n";
+#endif
+
+ m_DH_key_exchange.reset(new DH_key_exchange);
+
+ int pad_size = std::rand() % 512;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " pad size: " << pad_size << "\n";
+#endif
+
+ buffer::interval send_buf = allocate_send_buffer(dh_key_len + pad_size);
+
+ std::copy(m_DH_key_exchange->get_local_key(),
+ m_DH_key_exchange->get_local_key() + dh_key_len,
+ send_buf.begin);
+
+ std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand);
+ setup_send();
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " sent DH key\n";
+#endif
+ }
+
+ void bt_peer_connection::write_pe3_sync()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_encrypted);
+ TORRENT_ASSERT(!m_rc4_encrypted);
+ TORRENT_ASSERT(is_local());
+ TORRENT_ASSERT(!m_sent_handshake);
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ hasher h;
+ sha1_hash const& info_hash = t->torrent_file().info_hash();
+ char const* const secret = m_DH_key_exchange->get_secret();
+
+ int pad_size = rand() % 512;
+
+ // synchash,skeyhash,vc,crypto_provide,len(pad),pad,len(ia)
+ buffer::interval send_buf =
+ allocate_send_buffer(20 + 20 + 8 + 4 + 2 + pad_size + 2);
+
+ // sync hash (hash('req1',S))
+ h.reset();
+ h.update("req1",4);
+ h.update(secret, dh_key_len);
+ sha1_hash sync_hash = h.final();
+
+ std::copy(sync_hash.begin(), sync_hash.end(), send_buf.begin);
+ send_buf.begin += 20;
+
+ // stream key obfuscated hash [ hash('req2',SKEY) xor hash('req3',S) ]
+ h.reset();
+ h.update("req2",4);
+ h.update((const char*)info_hash.begin(), 20);
+ sha1_hash streamkey_hash = h.final();
+
+ h.reset();
+ h.update("req3",4);
+ h.update(secret, dh_key_len);
+ sha1_hash obfsc_hash = h.final();
+ obfsc_hash ^= streamkey_hash;
+
+ std::copy(obfsc_hash.begin(), obfsc_hash.end(), send_buf.begin);
+ send_buf.begin += 20;
+
+ // Discard DH key exchange data, setup RC4 keys
+ init_pe_RC4_handler(secret, info_hash);
+ m_DH_key_exchange.reset(); // secret should be invalid at this point
+
+ // write the verification constant and crypto field
+ TORRENT_ASSERT(send_buf.left() == 8 + 4 + 2 + pad_size + 2);
+ int encrypt_size = send_buf.left();
+
+ int crypto_provide = 0;
+ pe_settings::enc_level const& allowed_enc_level = m_ses.get_pe_settings().allowed_enc_level;
+
+ if (allowed_enc_level == pe_settings::both)
+ crypto_provide = 0x03;
+ else if (allowed_enc_level == pe_settings::rc4)
+ crypto_provide = 0x02;
+ else if (allowed_enc_level == pe_settings::plaintext)
+ crypto_provide = 0x01;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " crypto provide : [ ";
+ if (allowed_enc_level == pe_settings::both)
+ (*m_logger) << "plaintext rc4 ]\n";
+ else if (allowed_enc_level == pe_settings::rc4)
+ (*m_logger) << "rc4 ]\n";
+ else if (allowed_enc_level == pe_settings::plaintext)
+ (*m_logger) << "plaintext ]\n";
+#endif
+
+ write_pe_vc_cryptofield(send_buf, crypto_provide, pad_size);
+ m_RC4_handler->encrypt(send_buf.end - encrypt_size, encrypt_size);
+
+ TORRENT_ASSERT(send_buf.begin == send_buf.end);
+ setup_send();
+ }
+
+ void bt_peer_connection::write_pe4_sync(int crypto_select)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!is_local());
+ TORRENT_ASSERT(!m_encrypted);
+ TORRENT_ASSERT(!m_rc4_encrypted);
+ TORRENT_ASSERT(crypto_select == 0x02 || crypto_select == 0x01);
+ TORRENT_ASSERT(!m_sent_handshake);
+
+ int pad_size =rand() % 512;
+
+ const int buf_size = 8 + 4 + 2 + pad_size;
+ buffer::interval send_buf = allocate_send_buffer(buf_size);
+ write_pe_vc_cryptofield(send_buf, crypto_select, pad_size);
+
+ m_RC4_handler->encrypt(send_buf.end - buf_size, buf_size);
+ setup_send();
+
+ // encryption method has been negotiated
+ if (crypto_select == 0x02)
+ m_rc4_encrypted = true;
+ else // 0x01
+ m_rc4_encrypted = false;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " crypto select : [ ";
+ if (crypto_select == 0x01)
+ (*m_logger) << "plaintext ]\n";
+ else
+ (*m_logger) << "rc4 ]\n";
+#endif
+ }
+
+ void bt_peer_connection::write_pe_vc_cryptofield(buffer::interval& write_buf
+ , int crypto_field, int pad_size)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(crypto_field <= 0x03 && crypto_field > 0);
+ // vc,crypto_field,len(pad),pad, (len(ia))
+ TORRENT_ASSERT( (write_buf.left() == 8+4+2+pad_size+2 && is_local()) ||
+ (write_buf.left() == 8+4+2+pad_size && !is_local()) );
+ TORRENT_ASSERT(!m_sent_handshake);
+
+ // encrypt(vc, crypto_provide/select, len(Pad), len(IA))
+ // len(pad) is zero for now, len(IA) only for outgoing connections
+
+ // vc
+ std::fill(write_buf.begin, write_buf.begin + 8, 0);
+ write_buf.begin += 8;
+
+ detail::write_uint32(crypto_field, write_buf.begin);
+ detail::write_uint16(pad_size, write_buf.begin); // len (pad)
+
+ // fill pad with zeroes
+ std::generate(write_buf.begin, write_buf.begin + pad_size, &std::rand);
+ write_buf.begin += pad_size;
+
+ // append len(ia) if we are initiating
+ if (is_local())
+ detail::write_uint16(handshake_len, write_buf.begin); // len(IA)
+
+ TORRENT_ASSERT(write_buf.begin == write_buf.end);
+ }
+
+ void bt_peer_connection::init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(secret);
+
+ hasher h;
+ static const char keyA[] = "keyA";
+ static const char keyB[] = "keyB";
+
+ // encryption rc4 longkeys
+ // outgoing connection : hash ('keyA',S,SKEY)
+ // incoming connection : hash ('keyB',S,SKEY)
+
+ is_local() ? h.update(keyA, 4) : h.update(keyB, 4);
+ h.update(secret, dh_key_len);
+ h.update((char const*)stream_key.begin(), 20);
+ const sha1_hash local_key = h.final();
+
+ h.reset();
+
+ // decryption rc4 longkeys
+ // outgoing connection : hash ('keyB',S,SKEY)
+ // incoming connection : hash ('keyA',S,SKEY)
+
+ is_local() ? h.update(keyB, 4) : h.update(keyA, 4);
+ h.update(secret, dh_key_len);
+ h.update((char const*)stream_key.begin(), 20);
+ const sha1_hash remote_key = h.final();
+
+ TORRENT_ASSERT(!m_RC4_handler.get());
+ m_RC4_handler.reset(new RC4_handler (local_key, remote_key));
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " computed RC4 keys\n";
+#endif
+ }
+
+ void bt_peer_connection::send_buffer(char* buf, int size)
+ {
+ TORRENT_ASSERT(buf);
+ TORRENT_ASSERT(size > 0);
+
+ if (m_encrypted && m_rc4_encrypted)
+ m_RC4_handler->encrypt(buf, size);
+
+ peer_connection::send_buffer(buf, size);
+ }
+
+ buffer::interval bt_peer_connection::allocate_send_buffer(int size)
+ {
+ if (m_encrypted && m_rc4_encrypted)
+ {
+ TORRENT_ASSERT(m_enc_send_buffer.left() == 0);
+ m_enc_send_buffer = peer_connection::allocate_send_buffer(size);
+ return m_enc_send_buffer;
+ }
+ else
+ {
+ buffer::interval i = peer_connection::allocate_send_buffer(size);
+ return i;
+ }
+ }
+
+ void bt_peer_connection::setup_send()
+ {
+ if (m_encrypted && m_rc4_encrypted && m_enc_send_buffer.left())
+ {
+ TORRENT_ASSERT(m_enc_send_buffer.begin);
+ TORRENT_ASSERT(m_enc_send_buffer.end);
+
+ m_RC4_handler->encrypt(m_enc_send_buffer.begin, m_enc_send_buffer.left());
+ m_enc_send_buffer.end = m_enc_send_buffer.begin;
+ }
+ peer_connection::setup_send();
+ }
+
+ int bt_peer_connection::get_syncoffset(char const* src, int src_size,
+ char const* target, int target_size) const
+ {
+ TORRENT_ASSERT(target_size >= src_size);
+ TORRENT_ASSERT(src_size > 0);
+ TORRENT_ASSERT(src);
+ TORRENT_ASSERT(target);
+
+ int traverse_limit = target_size - src_size;
+
+ // TODO: this could be optimized using knuth morris pratt
+ for (int i = 0; i < traverse_limit; ++i)
+ {
+ char const* target_ptr = target + i;
+ if (std::equal(src, src+src_size, target_ptr))
+ return i;
+ }
+
+// // Partial sync
+// for (int i = 0; i < target_size; ++i)
+// {
+// // first is iterator in src[] at which mismatch occurs
+// // second is iterator in target[] at which mismatch occurs
+// std::pair<const char*, const char*> ret;
+// int src_sync_size;
+// if (i > traverse_limit) // partial sync test
+// {
+// ret = std::mismatch(src, src + src_size - (i - traverse_limit), &target[i]);
+// src_sync_size = ret.first - src;
+// if (src_sync_size == (src_size - (i - traverse_limit)))
+// return i;
+// }
+// else // complete sync test
+// {
+// ret = std::mismatch(src, src + src_size, &target[i]);
+// src_sync_size = ret.first - src;
+// if (src_sync_size == src_size)
+// return i;
+// }
+// }
+
+ // no complete sync
+ return -1;
+ }
+#endif // #ifndef TORRENT_DISABLE_ENCRYPTION
+
+ void bt_peer_connection::write_handshake()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_sent_handshake);
+#ifndef NDEBUG
+ m_sent_handshake = true;
+#endif
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ // add handshake to the send buffer
+ const char version_string[] = "BitTorrent protocol";
+ const int string_len = sizeof(version_string)-1;
+
+ buffer::interval i = allocate_send_buffer(1 + string_len + 8 + 20 + 20);
+ // length of version string
+ *i.begin = string_len;
+ ++i.begin;
+
+ // version string itself
+ std::copy(
+ version_string
+ , version_string + string_len
+ , i.begin);
+ i.begin += string_len;
+
+ // 8 zeroes
+ std::fill(i.begin, i.begin + 8, 0);
+
+#ifndef TORRENT_DISABLE_DHT
+ // indicate that we support the DHT messages
+ *(i.begin + 7) |= 0x01;
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ // we support extensions
+ *(i.begin + 5) |= 0x10;
+#endif
+
+ // we support FAST extension
+ *(i.begin + 7) |= 0x04;
+
+ i.begin += 8;
+
+ // info hash
+ sha1_hash const& ih = t->torrent_file().info_hash();
+ std::copy(ih.begin(), ih.end(), i.begin);
+ i.begin += 20;
+
+ // peer id
+ std::copy(
+ m_ses.get_peer_id().begin()
+ , m_ses.get_peer_id().end()
+ , i.begin);
+ i.begin += 20;
+ TORRENT_ASSERT(i.begin == i.end);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> HANDSHAKE\n";
+#endif
+ setup_send();
+ }
+
+ boost::optional<piece_block_progress> bt_peer_connection::downloading_piece_progress() const
+ {
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ buffer::const_interval recv_buffer = receive_buffer();
+ // are we currently receiving a 'piece' message?
+ if (m_state != read_packet
+ || recv_buffer.left() < 9
+ || recv_buffer[0] != msg_piece)
+ return boost::optional<piece_block_progress>();
+
+ const char* ptr = recv_buffer.begin + 1;
+ peer_request r;
+ r.piece = detail::read_int32(ptr);
+ r.start = detail::read_int32(ptr);
+ r.length = packet_size() - 9;
+
+ // is any of the piece message header data invalid?
+ if (!verify_piece(r))
+ return boost::optional<piece_block_progress>();
+
+ piece_block_progress p;
+
+ p.piece_index = r.piece;
+ p.block_index = r.start / t->block_size();
+ p.bytes_downloaded = recv_buffer.left() - 9;
+ p.full_block_bytes = r.length;
+
+ return boost::optional<piece_block_progress>(p);
+ }
+
+
+ // message handlers
+
+ // -----------------------------
+ // --------- KEEPALIVE ---------
+ // -----------------------------
+
+ void bt_peer_connection::on_keepalive()
+ {
+ INVARIANT_CHECK;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== KEEPALIVE\n";
+#endif
+ incoming_keepalive();
+ }
+
+ // -----------------------------
+ // ----------- CHOKE -----------
+ // -----------------------------
+
+ void bt_peer_connection::on_choke(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 1)
+ throw protocol_error("'choke' message size != 1");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ incoming_choke();
+ if (!m_supports_fast)
+ {
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+ while (!download_queue().empty())
+ {
+ piece_block const& b = download_queue().front();
+ peer_request r;
+ r.piece = b.piece_index;
+ r.start = b.block_index * t->block_size();
+ r.length = t->block_size();
+ incoming_reject_request(r);
+ }
+ }
+ }
+
+ // -----------------------------
+ // ---------- UNCHOKE ----------
+ // -----------------------------
+
+ void bt_peer_connection::on_unchoke(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 1)
+ throw protocol_error("'unchoke' message size != 1");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ incoming_unchoke();
+ }
+
+ // -----------------------------
+ // -------- INTERESTED ---------
+ // -----------------------------
+
+ void bt_peer_connection::on_interested(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 1)
+ throw protocol_error("'interested' message size != 1");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ incoming_interested();
+ }
+
+ // -----------------------------
+ // ------ NOT INTERESTED -------
+ // -----------------------------
+
+ void bt_peer_connection::on_not_interested(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 1)
+ throw protocol_error("'not interested' message size != 1");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ incoming_not_interested();
+ }
+
+ // -----------------------------
+ // ----------- HAVE ------------
+ // -----------------------------
+
+ void bt_peer_connection::on_have(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 5)
+ throw protocol_error("'have' message size != 5");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ const char* ptr = recv_buffer.begin + 1;
+ int index = detail::read_int32(ptr);
+
+ incoming_have(index);
+ }
+
+ // -----------------------------
+ // --------- BITFIELD ----------
+ // -----------------------------
+
+ void bt_peer_connection::on_bitfield(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ // if we don't have the metedata, we cannot
+ // verify the bitfield size
+ if (t->valid_metadata()
+ && packet_size() - 1 != ((int)get_bitfield().size() + 7) / 8)
+ throw protocol_error("bitfield with invalid size");
+
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ std::vector<bool> bitfield;
+
+ if (!t->valid_metadata())
+ bitfield.resize((packet_size() - 1) * 8);
+ else
+ bitfield.resize(get_bitfield().size());
+
+ // if we don't have metadata yet
+ // just remember the bitmask
+ // don't update the piecepicker
+ // (since it doesn't exist yet)
+ for (int i = 0; i < (int)bitfield.size(); ++i)
+ bitfield[i] = (recv_buffer[1 + (i>>3)] & (1 << (7 - (i&7)))) != 0;
+
+ incoming_bitfield(bitfield);
+ }
+
+ // -----------------------------
+ // ---------- REQUEST ----------
+ // -----------------------------
+
+ void bt_peer_connection::on_request(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 13)
+ throw protocol_error("'request' message size != 13");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ peer_request r;
+ const char* ptr = recv_buffer.begin + 1;
+ r.piece = detail::read_int32(ptr);
+ r.start = detail::read_int32(ptr);
+ r.length = detail::read_int32(ptr);
+
+ incoming_request(r);
+ }
+
+ // -----------------------------
+ // ----------- PIECE -----------
+ // -----------------------------
+
+ void bt_peer_connection::on_piece(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+
+ buffer::const_interval recv_buffer = receive_buffer();
+ int recv_pos = recv_buffer.end - recv_buffer.begin;
+
+ // classify the received data as protocol chatter
+ // or data payload for the statistics
+ if (recv_pos <= 9)
+ // only received protocol data
+ m_statistics.received_bytes(0, received);
+ else if (recv_pos - received >= 9)
+ // only received payload data
+ m_statistics.received_bytes(received, 0);
+ else
+ {
+ // received a bit of both
+ TORRENT_ASSERT(recv_pos - received < 9);
+ TORRENT_ASSERT(recv_pos > 9);
+ TORRENT_ASSERT(9 - (recv_pos - received) <= 9);
+ m_statistics.received_bytes(
+ recv_pos - 9
+ , 9 - (recv_pos - received));
+ }
+
+ incoming_piece_fragment();
+ if (!packet_finished()) return;
+
+ const char* ptr = recv_buffer.begin + 1;
+ peer_request p;
+ p.piece = detail::read_int32(ptr);
+ p.start = detail::read_int32(ptr);
+ p.length = packet_size() - 9;
+
+ incoming_piece(p, recv_buffer.begin + 9);
+ }
+
+ // -----------------------------
+ // ---------- CANCEL -----------
+ // -----------------------------
+
+ void bt_peer_connection::on_cancel(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 13)
+ throw protocol_error("'cancel' message size != 13");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ peer_request r;
+ const char* ptr = recv_buffer.begin + 1;
+ r.piece = detail::read_int32(ptr);
+ r.start = detail::read_int32(ptr);
+ r.length = detail::read_int32(ptr);
+
+ incoming_cancel(r);
+ }
+
+ // -----------------------------
+ // --------- DHT PORT ----------
+ // -----------------------------
+
+ void bt_peer_connection::on_dht_port(int received)
+ {
+ INVARIANT_CHECK;
+
+ if (!m_supports_dht_port)
+ throw protocol_error("got 'dht_port' message from peer that doesn't support it");
+
+ TORRENT_ASSERT(received > 0);
+ if (packet_size() != 3)
+ throw protocol_error("'dht_port' message size != 3");
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ const char* ptr = recv_buffer.begin + 1;
+ int listen_port = detail::read_uint16(ptr);
+
+ incoming_dht_port(listen_port);
+ }
+
+ void bt_peer_connection::on_suggest_piece(int received)
+ {
+ INVARIANT_CHECK;
+
+ if (!m_supports_fast)
+ throw protocol_error("got 'suggest_piece' without FAST extension support");
+
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ const char* ptr = recv_buffer.begin + 1;
+ int piece = detail::read_uint32(ptr);
+ incoming_suggest(piece);
+ }
+
+ void bt_peer_connection::on_have_all(int received)
+ {
+ INVARIANT_CHECK;
+
+ if (!m_supports_fast)
+ throw protocol_error("got 'have_all' without FAST extension support");
+ m_statistics.received_bytes(0, received);
+ incoming_have_all();
+ }
+
+ void bt_peer_connection::on_have_none(int received)
+ {
+ INVARIANT_CHECK;
+
+ if (!m_supports_fast)
+ throw protocol_error("got 'have_none' without FAST extension support");
+ m_statistics.received_bytes(0, received);
+ incoming_have_none();
+ }
+
+ void bt_peer_connection::on_reject_request(int received)
+ {
+ INVARIANT_CHECK;
+
+ if (!m_supports_fast)
+ throw protocol_error("got 'reject_request' without FAST extension support");
+
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ peer_request r;
+ const char* ptr = recv_buffer.begin + 1;
+ r.piece = detail::read_int32(ptr);
+ r.start = detail::read_int32(ptr);
+ r.length = detail::read_int32(ptr);
+
+ incoming_reject_request(r);
+ }
+
+ void bt_peer_connection::on_allowed_fast(int received)
+ {
+ INVARIANT_CHECK;
+
+ if (!m_supports_fast)
+ throw protocol_error("got 'allowed_fast' without FAST extension support");
+
+ m_statistics.received_bytes(0, received);
+ if (!packet_finished()) return;
+ buffer::const_interval recv_buffer = receive_buffer();
+ const char* ptr = recv_buffer.begin + 1;
+ int index = detail::read_int32(ptr);
+
+ incoming_allowed_fast(index);
+ }
+
+ // -----------------------------
+ // --------- EXTENDED ----------
+ // -----------------------------
+
+ void bt_peer_connection::on_extended(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+ m_statistics.received_bytes(0, received);
+ if (packet_size() < 2)
+ throw protocol_error("'extended' message smaller than 2 bytes");
+
+ if (associated_torrent().expired())
+ throw protocol_error("'extended' message sent before proper handshake");
+
+ buffer::const_interval recv_buffer = receive_buffer();
+ if (recv_buffer.left() < 2) return;
+
+ TORRENT_ASSERT(*recv_buffer.begin == msg_extended);
+ ++recv_buffer.begin;
+
+ int extended_id = detail::read_uint8(recv_buffer.begin);
+
+ if (extended_id == 0)
+ {
+ on_extended_handshake();
+ return;
+ }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_extended(packet_size() - 2, extended_id
+ , recv_buffer))
+ return;
+ }
+#endif
+
+ throw protocol_error("unknown extended message id: "
+ + boost::lexical_cast<std::string>(extended_id));
+ }
+
+ void bt_peer_connection::on_extended_handshake()
+ {
+ if (!packet_finished()) return;
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ entry root;
+ try
+ {
+ root = bdecode(recv_buffer.begin + 2, recv_buffer.end);
+ }
+ catch (std::exception& exc)
+ {
+ (void)exc;
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "invalid extended handshake: " << exc.what() << "\n";
+#endif
+ return;
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ std::stringstream ext;
+ root.print(ext);
+ (*m_logger) << "<== EXTENDED HANDSHAKE: \n" << ext.str();
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end;)
+ {
+ // a false return value means that the extension
+ // isn't supported by the other end. So, it is removed.
+ if (!(*i)->on_extension_handshake(root))
+ i = m_extensions.erase(i);
+ else
+ ++i;
+ }
+#endif
+
+ // there is supposed to be a remote listen port
+ if (entry* listen_port = root.find_key("p"))
+ {
+ if (listen_port->type() == entry::int_t
+ && peer_info_struct() != 0)
+ {
+ t->get_policy().update_peer_port(int(listen_port->integer())
+ , peer_info_struct(), peer_info::incoming);
+ }
+ }
+ // there should be a version too
+ // but where do we put that info?
+
+ if (entry* client_info = root.find_key("v"))
+ {
+ if (client_info->type() == entry::string_t)
+ m_client_version = client_info->string();
+ }
+
+ if (entry* reqq = root.find_key("reqq"))
+ {
+ if (reqq->type() == entry::int_t)
+ m_max_out_request_queue = int(reqq->integer());
+ if (m_max_out_request_queue < 1)
+ m_max_out_request_queue = 1;
+ }
+
+ if (entry* myip = root.find_key("yourip"))
+ {
+ // TODO: don't trust this blindly
+ if (myip->type() == entry::string_t)
+ {
+ std::string const& my_ip = myip->string().c_str();
+ if (my_ip.size() == address_v4::bytes_type::static_size)
+ {
+ address_v4::bytes_type bytes;
+ std::copy(my_ip.begin(), my_ip.end(), bytes.begin());
+ m_ses.m_external_address = address_v4(bytes);
+ }
+ else if (my_ip.size() == address_v6::bytes_type::static_size)
+ {
+ address_v6::bytes_type bytes;
+ std::copy(my_ip.begin(), my_ip.end(), bytes.begin());
+ m_ses.m_external_address = address_v6(bytes);
+ }
+ }
+ }
+ }
+
+ bool bt_peer_connection::dispatch_message(int received)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(received > 0);
+
+ // this means the connection has been closed already
+ if (associated_torrent().expired()) return false;
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ int packet_type = recv_buffer[0];
+ if (packet_type < 0
+ || packet_type >= num_supported_messages
+ || m_message_handler[packet_type] == 0)
+ {
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_unknown_message(packet_size(), packet_type
+ , buffer::const_interval(recv_buffer.begin+1
+ , recv_buffer.end)))
+ return packet_finished();
+ }
+#endif
+
+ throw protocol_error("unknown message id: "
+ + boost::lexical_cast<std::string>(packet_type)
+ + " size: " + boost::lexical_cast<std::string>(packet_size()));
+ }
+
+ TORRENT_ASSERT(m_message_handler[packet_type] != 0);
+
+ // call the correct handler for this packet type
+ (this->*m_message_handler[packet_type])(received);
+
+ return packet_finished();
+ }
+
+ void bt_peer_connection::write_keepalive()
+ {
+ INVARIANT_CHECK;
+
+ // Don't require the bitfield to have been sent at this point
+ // the case where m_sent_bitfield may not be true is if the
+ // torrent doesn't have any metadata, and a peer is timimg out.
+ // then the keep-alive message will be sent before the bitfield
+ // this is a violation to the original protocol, but necessary
+ // for the metadata extension.
+ TORRENT_ASSERT(m_sent_handshake);
+
+ char msg[] = {0,0,0,0};
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_cancel(peer_request const& r)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+ TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
+
+ char msg[17] = {0,0,0,13, msg_cancel};
+ char* ptr = msg + 5;
+ detail::write_int32(r.piece, ptr); // index
+ detail::write_int32(r.start, ptr); // begin
+ detail::write_int32(r.length, ptr); // length
+ send_buffer(msg, sizeof(msg));
+
+ if (!m_supports_fast)
+ incoming_reject_request(r);
+ }
+
+ void bt_peer_connection::write_request(peer_request const& r)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+ TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
+
+ char msg[17] = {0,0,0,13, msg_request};
+ char* ptr = msg + 5;
+
+ detail::write_int32(r.piece, ptr); // index
+ detail::write_int32(r.start, ptr); // begin
+ detail::write_int32(r.length, ptr); // length
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_bitfield(std::vector<bool> const& bitfield)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+ TORRENT_ASSERT(m_sent_handshake && !m_sent_bitfield);
+ TORRENT_ASSERT(t->valid_metadata());
+
+ // in this case, have_all or have_none should be sent instead
+ TORRENT_ASSERT(!m_supports_fast || !t->is_seed() || t->num_pieces() != 0);
+
+ if (m_supports_fast && t->is_seed())
+ {
+ write_have_all();
+ send_allowed_set();
+ return;
+ }
+ else if (m_supports_fast && t->num_pieces() == 0)
+ {
+ write_have_none();
+ send_allowed_set();
+ return;
+ }
+
+ int num_pieces = bitfield.size();
+ int lazy_pieces[50];
+ int num_lazy_pieces = 0;
+ int lazy_piece = 0;
+
+ TORRENT_ASSERT(t->is_seed() == (std::count(bitfield.begin(), bitfield.end(), true) == num_pieces));
+ if (t->is_seed() && m_ses.settings().lazy_bitfields)
+ {
+ num_lazy_pieces = (std::min)(50, num_pieces / 10);
+ if (num_lazy_pieces < 1) num_lazy_pieces = 1;
+ for (int i = 0; i < num_pieces; ++i)
+ {
+ if (rand() % (num_pieces - i) >= num_lazy_pieces - lazy_piece) continue;
+ lazy_pieces[lazy_piece++] = i;
+ }
+ TORRENT_ASSERT(lazy_piece == num_lazy_pieces);
+ lazy_piece = 0;
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> BITFIELD ";
+
+ std::stringstream bitfield_string;
+ for (int i = 0; i < (int)get_bitfield().size(); ++i)
+ {
+ if (lazy_piece < num_lazy_pieces
+ && lazy_pieces[lazy_piece] == i)
+ {
+ bitfield_string << "0";
+ ++lazy_piece;
+ continue;
+ }
+ if (bitfield[i]) bitfield_string << "1";
+ else bitfield_string << "0";
+ }
+ bitfield_string << "\n";
+ (*m_logger) << bitfield_string.str();
+ lazy_piece = 0;
+#endif
+ const int packet_size = (num_pieces + 7) / 8 + 5;
+
+ buffer::interval i = allocate_send_buffer(packet_size);
+
+ detail::write_int32(packet_size - 4, i.begin);
+ detail::write_uint8(msg_bitfield, i.begin);
+
+ std::fill(i.begin, i.end, 0);
+ for (int c = 0; c < num_pieces; ++c)
+ {
+ if (lazy_piece < num_lazy_pieces
+ && lazy_pieces[lazy_piece] == c)
+ {
+ ++lazy_piece;
+ continue;
+ }
+ if (bitfield[c])
+ i.begin[c >> 3] |= 1 << (7 - (c & 7));
+ }
+ TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8);
+
+#ifndef NDEBUG
+ m_sent_bitfield = true;
+#endif
+ setup_send();
+
+ if (num_lazy_pieces > 0)
+ {
+ for (int i = 0; i < num_lazy_pieces; ++i)
+ {
+ write_have(lazy_pieces[i]);
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> HAVE [ piece: " << lazy_pieces[i] << "]\n";
+#endif
+ }
+ }
+
+ if (m_supports_fast)
+ send_allowed_set();
+ }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void bt_peer_connection::write_extensions()
+ {
+ INVARIANT_CHECK;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> EXTENSIONS\n";
+#endif
+ TORRENT_ASSERT(m_supports_extensions);
+ TORRENT_ASSERT(m_sent_handshake);
+
+ entry handshake(entry::dictionary_t);
+ entry extension_list(entry::dictionary_t);
+
+ handshake["m"] = extension_list;
+
+ // only send the port in case we bade the connection
+ // on incoming connections the other end already knows
+ // our listen port
+ if (is_local()) handshake["p"] = m_ses.listen_port();
+ handshake["v"] = m_ses.settings().user_agent;
+ std::string remote_address;
+ std::back_insert_iterator<std::string> out(remote_address);
+ detail::write_address(remote().address(), out);
+ handshake["yourip"] = remote_address;
+ handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue;
+
+ tcp::endpoint ep = m_ses.get_ipv6_interface();
+ if (ep != tcp::endpoint())
+ {
+ std::string ipv6_address;
+ std::back_insert_iterator<std::string> out(ipv6_address);
+ detail::write_address(ep.address(), out);
+ handshake["ipv6"] = ipv6_address;
+ }
+
+ // loop backwards, to make the first extension be the last
+ // to fill in the handshake (i.e. give the first extensions priority)
+ for (extension_list_t::reverse_iterator i = m_extensions.rbegin()
+ , end(m_extensions.rend()); i != end; ++i)
+ {
+ (*i)->add_handshake(handshake);
+ }
+
+ std::vector<char> msg;
+ bencode(std::back_inserter(msg), handshake);
+
+ // make room for message
+ buffer::interval i = allocate_send_buffer(6 + msg.size());
+
+ // write the length of the message
+ detail::write_int32((int)msg.size() + 2, i.begin);
+ detail::write_uint8(msg_extended, i.begin);
+ // signal handshake message
+ detail::write_uint8(0, i.begin);
+
+ std::copy(msg.begin(), msg.end(), i.begin);
+ i.begin += msg.size();
+ TORRENT_ASSERT(i.begin == i.end);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ std::stringstream ext;
+ handshake.print(ext);
+ (*m_logger) << "==> EXTENDED HANDSHAKE: \n" << ext.str();
+#endif
+
+ setup_send();
+ }
+#endif
+
+ void bt_peer_connection::write_choke()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+
+ if (is_choked()) return;
+ char msg[] = {0,0,0,1,msg_choke};
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_unchoke()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+
+ char msg[] = {0,0,0,1,msg_unchoke};
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_interested()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+
+ char msg[] = {0,0,0,1,msg_interested};
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_not_interested()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+
+ char msg[] = {0,0,0,1,msg_not_interested};
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_have(int index)
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < associated_torrent().lock()->torrent_file().num_pieces());
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+
+ char msg[] = {0,0,0,5,msg_have,0,0,0,0};
+ char* ptr = msg + 5;
+ detail::write_int32(index, ptr);
+ send_buffer(msg, sizeof(msg));
+ }
+
+ void bt_peer_connection::write_piece(peer_request const& r, char* buffer)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ char msg[4 + 1 + 4 + 4];
+ char* ptr = msg;
+ TORRENT_ASSERT(r.length <= 16 * 1024);
+ detail::write_int32(r.length + 1 + 4 + 4, ptr);
+ detail::write_uint8(msg_piece, ptr);
+ detail::write_int32(r.piece, ptr);
+ detail::write_int32(r.start, ptr);
+ send_buffer(msg, sizeof(msg));
+
+ append_send_buffer(buffer, r.length
+ , boost::bind(&session_impl::free_disk_buffer
+ , boost::ref(m_ses), _1));
+
+ m_payloads.push_back(range(send_buffer_size() - r.length, r.length));
+ setup_send();
+ }
+
+ namespace
+ {
+ struct match_peer_id
+ {
+ match_peer_id(peer_id const& id, peer_connection const* pc)
+ : m_id(id), m_pc(pc)
+ { TORRENT_ASSERT(pc); }
+
+ bool operator()(std::pair<const address, policy::peer> const& p) const
+ {
+ return p.second.connection != m_pc
+ && p.second.connection
+ && p.second.connection->pid() == m_id
+ && !p.second.connection->pid().is_all_zeros()
+ && p.second.ip.address() == m_pc->remote().address();
+ }
+
+ peer_id const& m_id;
+ peer_connection const* m_pc;
+ };
+ }
+
+ // --------------------------
+ // RECEIVE DATA
+ // --------------------------
+
+ // throws exception when the client should be disconnected
+ void bt_peer_connection::on_receive(asio::error_code const& error
+ , std::size_t bytes_transferred)
+ {
+ INVARIANT_CHECK;
+
+ if (error) return;
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+
+ if (in_handshake())
+ m_statistics.received_bytes(0, bytes_transferred);
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ TORRENT_ASSERT(in_handshake() || !m_rc4_encrypted || m_encrypted);
+ if (m_rc4_encrypted && m_encrypted)
+ {
+ buffer::interval wr_buf = wr_recv_buffer();
+ m_RC4_handler->decrypt((wr_buf.end - bytes_transferred), bytes_transferred);
+ }
+#endif
+
+ buffer::const_interval recv_buffer = receive_buffer();
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ // m_state is set to read_pe_dhkey in initial state
+ // (read_protocol_identifier) for incoming, or in constructor
+ // for outgoing
+ if (m_state == read_pe_dhkey)
+ {
+ assert (!m_encrypted);
+ assert (!m_rc4_encrypted);
+ assert (packet_size() == dh_key_len);
+ assert (recv_buffer == receive_buffer());
+
+ if (!packet_finished()) return;
+
+ // write our dh public key. m_DH_key_exchange is
+ // initialized in write_pe1_2_dhkey()
+ if (!is_local())
+ write_pe1_2_dhkey();
+
+ // read dh key, generate shared secret
+ m_DH_key_exchange->compute_secret (recv_buffer.begin); // TODO handle errors
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " received DH key\n";
+#endif
+
+ // PadA/B can be a max of 512 bytes, and 20 bytes more for
+ // the sync hash (if incoming), or 8 bytes more for the
+ // encrypted verification constant (if outgoing). Instead
+ // of requesting the maximum possible, request the maximum
+ // possible to ensure we do not overshoot the standard
+ // handshake.
+
+ if (is_local())
+ {
+ m_state = read_pe_syncvc;
+ write_pe3_sync();
+
+ // initial payload is the standard handshake, this is
+ // always rc4 if sent here. m_rc4_encrypted is flagged
+ // again according to peer selection.
+ m_rc4_encrypted = true;
+ m_encrypted = true;
+ write_handshake();
+ m_rc4_encrypted = false;
+ m_encrypted = false;
+
+ // vc,crypto_select,len(pad),pad, encrypt(handshake)
+ // 8+4+2+0+handshake_len
+ reset_recv_buffer(8+4+2+0+handshake_len);
+ }
+ else
+ {
+ // already written dh key
+ m_state = read_pe_synchash;
+ // synchash,skeyhash,vc,crypto_provide,len(pad),pad,encrypt(handshake)
+ reset_recv_buffer(20+20+8+4+2+0+handshake_len);
+ }
+ TORRENT_ASSERT(!packet_finished());
+ return;
+ }
+
+ // cannot fall through into
+ if (m_state == read_pe_synchash)
+ {
+ TORRENT_ASSERT(!m_encrypted);
+ TORRENT_ASSERT(!m_rc4_encrypted);
+ TORRENT_ASSERT(!is_local());
+ TORRENT_ASSERT(recv_buffer == receive_buffer());
+
+ if (recv_buffer.left() < 20)
+ {
+ if (packet_finished())
+ {
+ throw protocol_error ("sync hash not found");
+ }
+ // else
+ return;
+ }
+
+ if (!m_sync_hash.get())
+ {
+ TORRENT_ASSERT(m_sync_bytes_read == 0);
+ hasher h;
+
+ // compute synchash (hash('req1',S))
+ h.update("req1", 4);
+ h.update(m_DH_key_exchange->get_secret(), dh_key_len);
+
+ m_sync_hash.reset(new sha1_hash(h.final()));
+ }
+
+ int syncoffset = get_syncoffset((char*)m_sync_hash->begin(), 20
+ , recv_buffer.begin, recv_buffer.left());
+
+ // No sync
+ if (syncoffset == -1)
+ {
+ std::size_t bytes_processed = recv_buffer.left() - 20;
+ m_sync_bytes_read += bytes_processed;
+ if (m_sync_bytes_read >= 512)
+ throw protocol_error("sync hash not found within 532 bytes");
+
+ cut_receive_buffer(bytes_processed, (std::min)(packet_size(), (512+20) - m_sync_bytes_read));
+
+ TORRENT_ASSERT(!packet_finished());
+ return;
+ }
+ // found complete sync
+ else
+ {
+ std::size_t bytes_processed = syncoffset + 20;
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " sync point (hash) found at offset "
+ << m_sync_bytes_read + bytes_processed - 20 << "\n";
+#endif
+ m_state = read_pe_skey_vc;
+ // skey,vc - 28 bytes
+ m_sync_hash.reset();
+ cut_receive_buffer(bytes_processed, 28);
+ }
+ }
+
+ if (m_state == read_pe_skey_vc)
+ {
+ TORRENT_ASSERT(!m_encrypted);
+ TORRENT_ASSERT(!m_rc4_encrypted);
+ TORRENT_ASSERT(!is_local());
+ TORRENT_ASSERT(packet_size() == 28);
+
+ if (!packet_finished()) return;
+
+ recv_buffer = receive_buffer();
+
+ // only calls info_hash() on the torrent_handle's, which
+ // never throws.
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ std::vector<torrent_handle> active_torrents = m_ses.get_torrents();
+ std::vector<torrent_handle>::const_iterator i;
+ hasher h;
+ sha1_hash skey_hash, obfs_hash;
+
+ for (i = active_torrents.begin(); i != active_torrents.end(); ++i)
+ {
+ torrent_handle const& t_h = *i; // TODO possible errors
+ sha1_hash const& info_hash = t_h.info_hash();
+ // TODO Does info_hash need to be checked for validity?
+
+ h.reset();
+ h.update("req2", 4);
+ h.update((char*)info_hash.begin(), 20);
+
+ skey_hash = h.final();
+
+ h.reset();
+ h.update("req3", 4);
+ h.update(m_DH_key_exchange->get_secret(), dh_key_len);
+
+ obfs_hash = h.final();
+ obfs_hash ^= skey_hash;
+
+ if (std::equal (recv_buffer.begin, recv_buffer.begin + 20,
+ (char*)obfs_hash.begin()))
+ {
+ if (!t)
+ {
+ attach_to_torrent(info_hash);
+ t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+ }
+
+ init_pe_RC4_handler(m_DH_key_exchange->get_secret(), info_hash);
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " stream key found, torrent located.\n";
+#endif
+ continue; // TODO Check flow control with multiple torrents
+ }
+ }
+
+ if (!m_RC4_handler.get())
+ throw protocol_error("invalid streamkey identifier (info hash) in encrypted handshake");
+
+ // verify constant
+ buffer::interval wr_recv_buf = wr_recv_buffer();
+ m_RC4_handler->decrypt(wr_recv_buf.begin + 20, 8);
+ wr_recv_buf.begin += 28;
+
+ const char sh_vc[] = {0,0,0,0, 0,0,0,0};
+ if (!std::equal(sh_vc, sh_vc+8, recv_buffer.begin + 20))
+ {
+ throw protocol_error("unable to verify constant");
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " verification constant found\n";
+#endif
+ m_state = read_pe_cryptofield;
+ reset_recv_buffer(4 + 2);
+ }
+
+ // cannot fall through into
+ if (m_state == read_pe_syncvc)
+ {
+ TORRENT_ASSERT(is_local());
+ TORRENT_ASSERT(!m_encrypted);
+ TORRENT_ASSERT(!m_rc4_encrypted);
+ TORRENT_ASSERT(recv_buffer == receive_buffer());
+
+ if (recv_buffer.left() < 8)
+ {
+ if (packet_finished())
+ {
+ throw protocol_error ("sync verification constant not found");
+ }
+ // else
+ return;
+ }
+
+ // generate the verification constant
+ if (!m_sync_vc.get())
+ {
+ TORRENT_ASSERT(m_sync_bytes_read == 0);
+
+ m_sync_vc.reset (new char[8]);
+ std::fill(m_sync_vc.get(), m_sync_vc.get() + 8, 0);
+ m_RC4_handler->decrypt(m_sync_vc.get(), 8);
+ }
+
+ TORRENT_ASSERT(m_sync_vc.get());
+ int syncoffset = get_syncoffset(m_sync_vc.get(), 8
+ , recv_buffer.begin, recv_buffer.left());
+
+ // No sync
+ if (syncoffset == -1)
+ {
+ std::size_t bytes_processed = recv_buffer.left() - 8;
+ m_sync_bytes_read += bytes_processed;
+ if (m_sync_bytes_read >= 512)
+ throw protocol_error("sync verification constant not found within 520 bytes");
+
+ cut_receive_buffer(bytes_processed, (std::min)(packet_size(), (512+8) - m_sync_bytes_read));
+
+ TORRENT_ASSERT(!packet_finished());
+ return;
+ }
+ // found complete sync
+ else
+ {
+ std::size_t bytes_processed = syncoffset + 8;
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " sync point (verification constant) found at offset "
+ << m_sync_bytes_read + bytes_processed - 8 << "\n";
+#endif
+ cut_receive_buffer (bytes_processed, 4 + 2);
+
+ // delete verification constant
+ m_sync_vc.reset();
+ m_state = read_pe_cryptofield;
+ // fall through
+ }
+ }
+
+ if (m_state == read_pe_cryptofield) // local/remote
+ {
+ TORRENT_ASSERT(!m_encrypted);
+ TORRENT_ASSERT(!m_rc4_encrypted);
+ TORRENT_ASSERT(packet_size() == 4+2);
+
+ if (!packet_finished()) return;
+
+ buffer::interval wr_buf = wr_recv_buffer();
+ m_RC4_handler->decrypt(wr_buf.begin, packet_size());
+
+ recv_buffer = receive_buffer();
+
+ int crypto_field = detail::read_int32(recv_buffer.begin);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ if (!is_local())
+ (*m_logger) << " crypto provide : [ ";
+ else
+ (*m_logger) << " crypto select : [ ";
+
+ if (crypto_field & 0x01)
+ (*m_logger) << "plaintext ";
+ if (crypto_field & 0x02)
+ (*m_logger) << "rc4 ";
+ (*m_logger) << "]\n";
+#endif
+
+ if (!is_local())
+ {
+ int crypto_select = 0;
+ // select a crypto method
+ switch (m_ses.get_pe_settings().allowed_enc_level)
+ {
+ case (pe_settings::plaintext):
+ {
+ if (!(crypto_field & 0x01))
+ throw protocol_error("plaintext not provided");
+ crypto_select = 0x01;
+ }
+ break;
+ case (pe_settings::rc4):
+ {
+ if (!(crypto_field & 0x02))
+ throw protocol_error("rc4 not provided");
+ crypto_select = 0x02;
+ }
+ break;
+ case (pe_settings::both):
+ {
+ if (m_ses.get_pe_settings().prefer_rc4)
+ {
+ if (crypto_field & 0x02)
+ crypto_select = 0x02;
+ else if (crypto_field & 0x01)
+ crypto_select = 0x01;
+ }
+ else
+ {
+ if (crypto_field & 0x01)
+ crypto_select = 0x01;
+ else if (crypto_field & 0x02)
+ crypto_select = 0x02;
+ }
+ if (!crypto_select)
+ throw protocol_error("rc4/plaintext not provided");
+ }
+ } // switch
+
+ // write the pe4 step
+ write_pe4_sync(crypto_select);
+ }
+ else // is_local()
+ {
+ // check if crypto select is valid
+ pe_settings::enc_level const& allowed_enc_level = m_ses.get_pe_settings().allowed_enc_level;
+
+ if (crypto_field == 0x02)
+ {
+ if (allowed_enc_level == pe_settings::plaintext)
+ throw protocol_error("rc4 selected by peer when not provided");
+ m_rc4_encrypted = true;
+ }
+ else if (crypto_field == 0x01)
+ {
+ if (allowed_enc_level == pe_settings::rc4)
+ throw protocol_error("plaintext selected by peer when not provided");
+ m_rc4_encrypted = false;
+ }
+ else
+ throw protocol_error("unsupported crypto method selected by peer");
+ }
+
+ int len_pad = detail::read_int16(recv_buffer.begin);
+ if (len_pad < 0 || len_pad > 512)
+ throw protocol_error("invalid pad length");
+
+ m_state = read_pe_pad;
+ if (!is_local())
+ reset_recv_buffer(len_pad + 2); // len(IA) at the end of pad
+ else
+ {
+ if (len_pad == 0)
+ {
+ m_encrypted = true;
+ m_state = init_bt_handshake;
+ }
+ else
+ reset_recv_buffer(len_pad);
+ }
+ }
+
+ if (m_state == read_pe_pad)
+ {
+ TORRENT_ASSERT(!m_encrypted);
+ if (!packet_finished()) return;
+
+ int pad_size = is_local() ? packet_size() : packet_size() - 2;
+
+ buffer::interval wr_buf = wr_recv_buffer();
+ m_RC4_handler->decrypt(wr_buf.begin, packet_size());
+
+ recv_buffer = receive_buffer();
+
+ if (!is_local())
+ {
+ recv_buffer.begin += pad_size;
+ int len_ia = detail::read_int16(recv_buffer.begin);
+
+ if (len_ia < 0) throw protocol_error("invalid len_ia in handshake");
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " len(IA) : " << len_ia << "\n";
+#endif
+ if (len_ia == 0)
+ {
+ // everything after this is Encrypt2
+ m_encrypted = true;
+ m_state = init_bt_handshake;
+ }
+ else
+ {
+ m_state = read_pe_ia;
+ reset_recv_buffer(len_ia);
+ }
+ }
+ else // is_local()
+ {
+ // everything that arrives after this is Encrypt2
+ m_encrypted = true;
+ m_state = init_bt_handshake;
+ }
+ }
+
+ if (m_state == read_pe_ia)
+ {
+ TORRENT_ASSERT(!is_local());
+ TORRENT_ASSERT(!m_encrypted);
+
+ if (!packet_finished()) return;
+
+ // ia is always rc4, so decrypt it
+ buffer::interval wr_buf = wr_recv_buffer();
+ m_RC4_handler->decrypt(wr_buf.begin, packet_size());
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " decrypted ia : " << packet_size() << " bytes\n";
+#endif
+
+ if (!m_rc4_encrypted)
+ {
+ m_RC4_handler.reset();
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " destroyed rc4 keys\n";
+#endif
+ }
+
+ // everything that arrives after this is Encrypt2
+ m_encrypted = true;
+
+ m_state = read_protocol_identifier;
+ cut_receive_buffer(0, 20);
+ }
+
+ if (m_state == init_bt_handshake)
+ {
+ TORRENT_ASSERT(m_encrypted);
+
+ // decrypt remaining received bytes
+ if (m_rc4_encrypted)
+ {
+ buffer::interval wr_buf = wr_recv_buffer();
+ wr_buf.begin += packet_size();
+ m_RC4_handler->decrypt(wr_buf.begin, wr_buf.left());
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " decrypted remaining " << wr_buf.left() << " bytes\n";
+#endif
+ }
+ else // !m_rc4_encrypted
+ {
+ m_RC4_handler.reset();
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " destroyed rc4 keys\n";
+#endif
+ }
+
+ // payload stream, start with 20 handshake bytes
+ m_state = read_protocol_identifier;
+ reset_recv_buffer(20);
+
+ // encrypted portion of handshake completed, toggle
+ // peer_info pe_support flag back to true
+ if (is_local() &&
+ m_ses.get_pe_settings().out_enc_policy == pe_settings::enabled)
+ {
+ policy::peer* pi = peer_info_struct();
+ TORRENT_ASSERT(pi);
+
+ pi->pe_support = true;
+ }
+ }
+
+#endif // #ifndef TORRENT_DISABLE_ENCRYPTION
+
+ if (m_state == read_protocol_identifier)
+ {
+ assert (packet_size() == 20);
+
+ if (!packet_finished()) return;
+ recv_buffer = receive_buffer();
+
+ int packet_size = recv_buffer[0];
+ const char protocol_string[] = "BitTorrent protocol";
+
+ if (packet_size != 19 ||
+ !std::equal(recv_buffer.begin + 1, recv_buffer.begin + 19, protocol_string))
+ {
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ if (!is_local() && m_ses.get_pe_settings().in_enc_policy == pe_settings::disabled)
+ throw protocol_error("encrypted incoming connections disabled");
+
+ // Don't attempt to perform an encrypted handshake
+ // within an encrypted connection
+ if (!m_encrypted && !is_local())
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " attempting encrypted connection\n";
+#endif
+ m_state = read_pe_dhkey;
+ cut_receive_buffer(0, dh_key_len);
+ TORRENT_ASSERT(!packet_finished());
+ return;
+ }
+
+ assert ((!is_local() && m_encrypted) || is_local());
+#endif // #ifndef TORRENT_DISABLE_ENCRYPTION
+ throw protocol_error("incorrect protocol identifier");
+ }
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ assert (m_state != read_pe_dhkey);
+
+ if (!is_local() &&
+ (m_ses.get_pe_settings().in_enc_policy == pe_settings::forced) &&
+ !m_encrypted)
+ throw protocol_error("non encrypted incoming connections disabled");
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " BitTorrent protocol\n";
+#endif
+
+ m_state = read_info_hash;
+ reset_recv_buffer(28);
+ }
+
+ // fall through
+ if (m_state == read_info_hash)
+ {
+ TORRENT_ASSERT(packet_size() == 28);
+
+ if (!packet_finished()) return;
+ recv_buffer = receive_buffer();
+
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ for (int i=0; i < 8; ++i)
+ {
+ for (int j=0; j < 8; ++j)
+ {
+ if (recv_buffer[i] & (0x80 >> j)) (*m_logger) << "1";
+ else (*m_logger) << "0";
+ }
+ }
+ (*m_logger) << "\n";
+ if (recv_buffer[7] & 0x01)
+ (*m_logger) << "supports DHT port message\n";
+ if (recv_buffer[7] & 0x04)
+ (*m_logger) << "supports FAST extensions\n";
+ if (recv_buffer[5] & 0x10)
+ (*m_logger) << "supports extensions protocol\n";
+#endif
+
+#ifndef DISABLE_EXTENSIONS
+ if ((recv_buffer[5] & 0x10))
+ m_supports_extensions = true;
+#endif
+ if (recv_buffer[7] & 0x01)
+ m_supports_dht_port = true;
+
+ if (recv_buffer[7] & 0x04)
+ m_supports_fast = true;
+
+ // ok, now we have got enough of the handshake. Is this connection
+ // attached to a torrent?
+ if (!t)
+ {
+ // now, we have to see if there's a torrent with the
+ // info_hash we got from the peer
+ sha1_hash info_hash;
+ std::copy(recv_buffer.begin + 8, recv_buffer.begin + 28
+ , (char*)info_hash.begin());
+
+ attach_to_torrent(info_hash);
+ }
+ else
+ {
+ // verify info hash
+ if (!std::equal(recv_buffer.begin + 8, recv_buffer.begin + 28
+ , (const char*)t->torrent_file().info_hash().begin()))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " received invalid info_hash\n";
+#endif
+ throw protocol_error("invalid info-hash in handshake");
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " info_hash received\n";
+#endif
+ }
+
+ t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ // if this is a local connection, we have already
+ // sent the handshake
+ if (!is_local()) write_handshake();
+// if (t->valid_metadata())
+// write_bitfield(t->pieces());
+
+ TORRENT_ASSERT(t->get_policy().has_connection(this));
+
+ m_state = read_peer_id;
+ reset_recv_buffer(20);
+ }
+
+ // fall through
+ if (m_state == read_peer_id)
+ {
+ if (!t)
+ {
+ TORRENT_ASSERT(!packet_finished()); // TODO
+ return;
+ }
+ TORRENT_ASSERT(packet_size() == 20);
+
+ if (!packet_finished()) return;
+ recv_buffer = receive_buffer();
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ {
+ peer_id tmp;
+ std::copy(recv_buffer.begin, recv_buffer.begin + 20, (char*)tmp.begin());
+ std::stringstream s;
+ s << "received peer_id: " << tmp << " client: " << identify_client(tmp) << "\n";
+ s << "as ascii: ";
+ for (peer_id::iterator i = tmp.begin(); i != tmp.end(); ++i)
+ {
+ if (std::isprint(*i)) s << *i;
+ else s << ".";
+ }
+ s << "\n";
+ (*m_logger) << s.str();
+ }
+#endif
+ peer_id pid;
+ std::copy(recv_buffer.begin, recv_buffer.begin + 20, (char*)pid.begin());
+ set_pid(pid);
+
+ if (t->settings().allow_multiple_connections_per_ip)
+ {
+ // now, let's see if this connection should be closed
+ policy& p = t->get_policy();
+ policy::iterator i = std::find_if(p.begin_peer(), p.end_peer()
+ , match_peer_id(pid, this));
+ if (i != p.end_peer())
+ {
+ TORRENT_ASSERT(i->second.connection->pid() == pid);
+ // we found another connection with the same peer-id
+ // which connection should be closed in order to be
+ // sure that the other end closes the same connection?
+ // the peer with greatest peer-id is the one allowed to
+ // initiate connections. So, if our peer-id is greater than
+ // the others, we should close the incoming connection,
+ // if not, we should close the outgoing one.
+ if (pid < m_ses.get_peer_id() && is_local())
+ {
+ i->second.connection->disconnect();
+ }
+ else
+ {
+ throw protocol_error("duplicate peer-id, connection closed");
+ }
+ }
+ }
+
+ if (pid == m_ses.get_peer_id())
+ {
+ throw protocol_error("closing connection to ourself");
+ }
+
+ m_client_version = identify_client(pid);
+ boost::optional<fingerprint> f = client_fingerprint(pid);
+ if (f && std::equal(f->name, f->name + 2, "BC"))
+ {
+ // if this is a bitcomet client, lower the request queue size limit
+ if (m_max_out_request_queue > 50) m_max_out_request_queue = 50;
+ }
+
+ // disconnect if the peer has the same peer-id as ourself
+ // since it most likely is ourself then
+ if (pid == m_ses.get_peer_id())
+ throw std::runtime_error("closing connection to ourself");
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end;)
+ {
+ if (!(*i)->on_handshake())
+ {
+ i = m_extensions.erase(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+
+ if (m_supports_extensions) write_extensions();
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== HANDSHAKE\n";
+#endif
+ // consider this a successful connection, reset the failcount
+ if (peer_info_struct()) peer_info_struct()->failcount = 0;
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ // Toggle pe_support back to false if this is a
+ // standard successful connection
+ if (is_local() && !m_encrypted &&
+ m_ses.get_pe_settings().out_enc_policy == pe_settings::enabled)
+ {
+ policy::peer* pi = peer_info_struct();
+ TORRENT_ASSERT(pi);
+
+ pi->pe_support = false;
+ }
+#endif
+
+ m_state = read_packet_size;
+ reset_recv_buffer(4);
+ if (t->valid_metadata())
+ {
+ write_bitfield(t->pieces());
+#ifndef TORRENT_DISABLE_DHT
+ if (m_supports_dht_port && m_ses.m_dht)
+ write_dht_port(m_ses.get_dht_settings().service_port);
+#endif
+ }
+
+ TORRENT_ASSERT(!packet_finished());
+ return;
+ }
+
+ // cannot fall through into
+ if (m_state == read_packet_size)
+ {
+ // Make sure this is not fallen though into
+ assert (recv_buffer == receive_buffer());
+
+ if (!t) return;
+ m_statistics.received_bytes(0, bytes_transferred);
+ if (!packet_finished()) return;
+
+ const char* ptr = recv_buffer.begin;
+ int packet_size = detail::read_int32(ptr);
+
+ // don't accept packets larger than 1 MB
+ if (packet_size > 1024*1024 || packet_size < 0)
+ {
+ // packet too large
+ throw std::runtime_error("packet > 1 MB ("
+ + boost::lexical_cast<std::string>(
+ (unsigned int)packet_size) + " bytes)");
+ }
+
+ if (packet_size == 0)
+ {
+ incoming_keepalive();
+ // keepalive message
+ m_state = read_packet_size;
+ reset_recv_buffer(4);
+ }
+ else
+ {
+ m_state = read_packet;
+ reset_recv_buffer(packet_size);
+ }
+ TORRENT_ASSERT(!packet_finished());
+ return;
+ }
+
+ if (m_state == read_packet)
+ {
+ TORRENT_ASSERT(recv_buffer == receive_buffer());
+ if (!t) return;
+ if (dispatch_message(bytes_transferred))
+ {
+ m_state = read_packet_size;
+ reset_recv_buffer(4);
+ }
+ TORRENT_ASSERT(!packet_finished());
+ return;
+ }
+
+ TORRENT_ASSERT(!packet_finished());
+ }
+
+ // --------------------------
+ // SEND DATA
+ // --------------------------
+
+ // throws exception when the client should be disconnected
+ void bt_peer_connection::on_sent(asio::error_code const& error
+ , std::size_t bytes_transferred)
+ {
+ INVARIANT_CHECK;
+
+ if (error) return;
+
+ // manage the payload markers
+ int amount_payload = 0;
+ if (!m_payloads.empty())
+ {
+ for (std::deque<range>::iterator i = m_payloads.begin();
+ i != m_payloads.end(); ++i)
+ {
+ i->start -= bytes_transferred;
+ if (i->start < 0)
+ {
+ if (i->start + i->length <= 0)
+ {
+ amount_payload += i->length;
+ }
+ else
+ {
+ amount_payload += -i->start;
+ i->length -= -i->start;
+ i->start = 0;
+ }
+ }
+ }
+ }
+
+ // TODO: move the erasing into the loop above
+ // remove all payload ranges that has been sent
+ m_payloads.erase(
+ std::remove_if(m_payloads.begin(), m_payloads.end(), range_below_zero)
+ , m_payloads.end());
+
+ TORRENT_ASSERT(amount_payload <= (int)bytes_transferred);
+ m_statistics.sent_bytes(amount_payload, bytes_transferred - amount_payload);
+ }
+
+#ifndef NDEBUG
+ void bt_peer_connection::check_invariant() const
+ {
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_DH_key_exchange.get())
+ || !is_local());
+
+ TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get());
+#endif
+ if (!in_handshake())
+ {
+ TORRENT_ASSERT(m_sent_handshake);
+ }
+
+ if (!m_in_constructor)
+ peer_connection::check_invariant();
+
+ if (!m_payloads.empty())
+ {
+ for (std::deque<range>::const_iterator i = m_payloads.begin();
+ i != m_payloads.end() - 1; ++i)
+ {
+ TORRENT_ASSERT(i->start + i->length <= (i+1)->start);
+ }
+ }
+ }
+#endif
+
+}
+
diff --git a/src/libtorrent/src/connection_queue.cpp b/src/libtorrent/src/connection_queue.cpp
new file mode 100644
index 0000000..a48456e
--- /dev/null
+++ b/src/libtorrent/src/connection_queue.cpp
@@ -0,0 +1,216 @@
+
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <boost/bind.hpp>
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/connection_queue.hpp"
+
+namespace libtorrent
+{
+
+ connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
+ , m_num_connecting(0)
+ , m_half_open_limit(0)
+ , m_timer(ios)
+#ifndef NDEBUG
+ , m_in_timeout_function(false)
+#endif
+ {}
+
+ bool connection_queue::free_slots() const
+ { return m_num_connecting < m_half_open_limit || m_half_open_limit <= 0; }
+
+ void connection_queue::enqueue(boost::function<void(int)> const& on_connect
+ , boost::function<void()> const& on_timeout
+ , time_duration timeout)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ m_queue.push_back(entry());
+ entry& e = m_queue.back();
+ e.on_connect = on_connect;
+ e.on_timeout = on_timeout;
+ e.ticket = m_next_ticket;
+ e.timeout = timeout;
+ ++m_next_ticket;
+ try_connect();
+ }
+
+ void connection_queue::done(int ticket)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ std::list<entry>::iterator i = std::find_if(m_queue.begin()
+ , m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
+ if (i == m_queue.end())
+ {
+ // this might not be here in case on_timeout calls remove
+ return;
+ }
+ if (i->connecting) --m_num_connecting;
+ m_queue.erase(i);
+ try_connect();
+ }
+
+ void connection_queue::close()
+ {
+ m_timer.cancel();
+ }
+
+ void connection_queue::limit(int limit)
+ { m_half_open_limit = limit; }
+
+ int connection_queue::limit() const
+ { return m_half_open_limit; }
+
+#ifndef NDEBUG
+
+ void connection_queue::check_invariant() const
+ {
+ int num_connecting = 0;
+ for (std::list<entry>::const_iterator i = m_queue.begin();
+ i != m_queue.end(); ++i)
+ {
+ if (i->connecting) ++num_connecting;
+ }
+ TORRENT_ASSERT(num_connecting == m_num_connecting);
+ }
+
+#endif
+
+ void connection_queue::try_connect()
+ {
+ INVARIANT_CHECK;
+
+ if (!free_slots())
+ return;
+
+ if (m_queue.empty())
+ {
+ m_timer.cancel();
+ return;
+ }
+
+ std::list<entry>::iterator i = std::find_if(m_queue.begin()
+ , m_queue.end(), boost::bind(&entry::connecting, _1) == false);
+ while (i != m_queue.end())
+ {
+ TORRENT_ASSERT(i->connecting == false);
+ ptime expire = time_now() + i->timeout;
+ if (m_num_connecting == 0)
+ {
+ m_timer.expires_at(expire);
+ m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
+ }
+ i->connecting = true;
+ ++m_num_connecting;
+ i->expires = expire;
+
+ INVARIANT_CHECK;
+
+ entry& ent = *i;
+ ++i;
+ try { ent.on_connect(ent.ticket); } catch (std::exception&) {}
+
+ if (!free_slots()) break;
+ i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
+ }
+ }
+
+#ifndef NDEBUG
+ struct function_guard
+ {
+ function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
+ ~function_guard() { val = false; }
+
+ bool& val;
+ };
+#endif
+
+ void connection_queue::on_timeout(asio::error_code const& e)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+#ifndef NDEBUG
+ function_guard guard_(m_in_timeout_function);
+#endif
+
+ TORRENT_ASSERT(!e || e == asio::error::operation_aborted);
+ if (e) return;
+
+ ptime next_expire = max_time();
+ ptime now = time_now();
+ std::list<entry> timed_out;
+ for (std::list<entry>::iterator i = m_queue.begin();
+ !m_queue.empty() && i != m_queue.end();)
+ {
+ if (i->connecting && i->expires < now)
+ {
+ std::list<entry>::iterator j = i;
+ ++i;
+ timed_out.splice(timed_out.end(), m_queue, j, i);
+ --m_num_connecting;
+ continue;
+ }
+ if (i->expires < next_expire)
+ next_expire = i->expires;
+ ++i;
+ }
+
+ // we don't want to call the timeout callback while we're locked
+ // since that is a recepie for dead-locks
+ l.unlock();
+
+ for (std::list<entry>::iterator i = timed_out.begin()
+ , end(timed_out.end()); i != end; ++i)
+ {
+ try { i->on_timeout(); } catch (std::exception&) {}
+ }
+
+ l.lock();
+
+ if (next_expire < max_time())
+ {
+ m_timer.expires_at(next_expire);
+ m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
+ }
+ try_connect();
+ }
+
+}
+
diff --git a/src/libtorrent/src/disk_io_thread.cpp b/src/libtorrent/src/disk_io_thread.cpp
new file mode 100644
index 0000000..f9a5723
--- /dev/null
+++ b/src/libtorrent/src/disk_io_thread.cpp
@@ -0,0 +1,358 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/storage.hpp"
+#include <deque>
+#include "libtorrent/disk_io_thread.hpp"
+
+#ifdef TORRENT_DISK_STATS
+
+#include "libtorrent/time.hpp"
+
+#endif
+
+namespace libtorrent
+{
+
+ disk_io_thread::disk_io_thread(int block_size)
+ : m_abort(false)
+ , m_queue_buffer_size(0)
+ , m_pool(block_size)
+#ifndef NDEBUG
+ , m_block_size(block_size)
+#endif
+ , m_disk_io_thread(boost::ref(*this))
+ {
+#ifdef TORRENT_STATS
+ m_allocations = 0;
+#endif
+#ifdef TORRENT_DISK_STATS
+ m_log.open("disk_io_thread.log", std::ios::trunc);
+#endif
+ }
+
+ disk_io_thread::~disk_io_thread()
+ {
+ TORRENT_ASSERT(m_abort == true);
+ }
+
+#ifndef NDEBUG
+ disk_io_job disk_io_thread::find_job(boost::intrusive_ptr<piece_manager> s
+ , int action, int piece) const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ for (std::list<disk_io_job>::const_iterator i = m_jobs.begin();
+ i != m_jobs.end(); ++i)
+ {
+ if (i->storage != s)
+ continue;
+ if ((i->action == action || action == -1) && i->piece == piece)
+ return *i;
+ }
+ if ((m_current.action == action || action == -1)
+ && m_current.piece == piece)
+ return m_current;
+
+ disk_io_job ret;
+ ret.action = (disk_io_job::action_t)-1;
+ ret.piece = -1;
+ return ret;
+ }
+
+#endif
+
+ void disk_io_thread::join()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_abort = true;
+ m_signal.notify_all();
+ l.unlock();
+
+ m_disk_io_thread.join();
+ }
+
+ // aborts read operations
+ void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ // read jobs are aborted, write and move jobs are syncronized
+ for (std::list<disk_io_job>::iterator i = m_jobs.begin();
+ i != m_jobs.end();)
+ {
+ if (i->storage != s)
+ {
+ ++i;
+ continue;
+ }
+ if (i->action == disk_io_job::read)
+ {
+ i->callback(-1, *i);
+ m_jobs.erase(i++);
+ continue;
+ }
+ ++i;
+ }
+ m_signal.notify_all();
+ }
+
+ bool range_overlap(int start1, int length1, int start2, int length2)
+ {
+ return (start1 <= start2 && start1 + length1 > start2)
+ || (start2 <= start1 && start2 + length2 > start1);
+ }
+
+ namespace
+ {
+ // The semantic of this operator is:
+ // shouls lhs come before rhs in the job queue
+ bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
+ {
+ // NOTE: comparison inverted to make higher priority
+ // skip _in_front_of_ lower priority
+ if (lhs.priority > rhs.priority) return true;
+ if (lhs.priority < rhs.priority) return false;
+
+ if (lhs.storage.get() < rhs.storage.get()) return true;
+ if (lhs.storage.get() > rhs.storage.get()) return false;
+ if (lhs.piece < rhs.piece) return true;
+ if (lhs.piece > rhs.piece) return false;
+ if (lhs.offset < rhs.offset) return true;
+// if (lhs.offset > rhs.offset) return false;
+ return false;
+ }
+ }
+
+ void disk_io_thread::add_job(disk_io_job const& j
+ , boost::function<void(int, disk_io_job const&)> const& f)
+ {
+ TORRENT_ASSERT(!j.callback);
+ TORRENT_ASSERT(j.storage);
+ mutex_t::scoped_lock l(m_mutex);
+
+ std::list<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
+ if (j.action == disk_io_job::read)
+ {
+ // when we're reading, we may not skip
+ // ahead of any write operation that overlaps
+ // the region we're reading
+ for (; i != m_jobs.rend(); i++)
+ {
+ // if *i should come before j, stop
+ // and insert j before i
+ if (*i < j) break;
+ // if we come across a write operation that
+ // overlaps the region we're reading, we need
+ // to stop
+ if (i->action == disk_io_job::write
+ && i->storage == j.storage
+ && i->piece == j.piece
+ && range_overlap(i->offset, i->buffer_size
+ , j.offset, j.buffer_size))
+ break;
+ }
+ }
+ else if (j.action == disk_io_job::write)
+ {
+ for (; i != m_jobs.rend(); ++i)
+ {
+ if (*i < j)
+ {
+ if (i != m_jobs.rbegin()
+ && i.base()->storage.get() != j.storage.get())
+ i = m_jobs.rbegin();
+ break;
+ }
+ }
+ }
+
+ // if we are placed in front of all other jobs, put it on the back of
+ // the queue, to sweep the disk in the same direction, and to avoid
+ // starvation. The exception is if the priority is higher than the
+ // job at the front of the queue
+ if (i == m_jobs.rend() && (m_jobs.empty() || j.priority <= m_jobs.back().priority))
+ i = m_jobs.rbegin();
+
+ std::list<disk_io_job>::iterator k = m_jobs.insert(i.base(), j);
+ k->callback.swap(const_cast<boost::function<void(int, disk_io_job const&)>&>(f));
+ if (j.action == disk_io_job::write)
+ m_queue_buffer_size += j.buffer_size;
+ TORRENT_ASSERT(j.storage.get());
+ m_signal.notify_all();
+ }
+
+ char* disk_io_thread::allocate_buffer()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+#ifdef TORRENT_STATS
+ ++m_allocations;
+#endif
+ return (char*)m_pool.ordered_malloc();
+ }
+
+ void disk_io_thread::free_buffer(char* buf)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+#ifdef TORRENT_STATS
+ --m_allocations;
+#endif
+ m_pool.ordered_free(buf);
+ }
+
+ void disk_io_thread::operator()()
+ {
+ for (;;)
+ {
+#ifdef TORRENT_DISK_STATS
+ m_log << log_time() << " idle" << std::endl;
+#endif
+ mutex_t::scoped_lock l(m_mutex);
+#ifndef NDEBUG
+ m_current.action = (disk_io_job::action_t)-1;
+ m_current.piece = -1;
+#endif
+ while (m_jobs.empty() && !m_abort)
+ m_signal.wait(l);
+ if (m_abort && m_jobs.empty()) return;
+
+ boost::function<void(int, disk_io_job const&)> handler;
+ handler.swap(m_jobs.front().callback);
+#ifndef NDEBUG
+ m_current = m_jobs.front();
+#endif
+ disk_io_job j = m_jobs.front();
+ m_jobs.pop_front();
+ m_queue_buffer_size -= j.buffer_size;
+ l.unlock();
+
+ int ret = 0;
+
+ bool free_current_buffer = true;
+ try
+ {
+ TORRENT_ASSERT(j.storage);
+#ifdef TORRENT_DISK_STATS
+ ptime start = time_now();
+#endif
+// std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
+ switch (j.action)
+ {
+ case disk_io_job::read:
+#ifdef TORRENT_DISK_STATS
+ m_log << log_time() << " read " << j.buffer_size << std::endl;
+#endif
+ free_current_buffer = false;
+ if (j.buffer == 0)
+ {
+ j.buffer = allocate_buffer();
+ TORRENT_ASSERT(j.buffer_size <= m_block_size);
+ if (j.buffer == 0)
+ {
+ ret = -1;
+ j.str = "out of memory";
+ break;
+ }
+ }
+ ret = int(j.storage->read_impl(j.buffer, j.piece, j.offset
+ , j.buffer_size));
+
+ // simulates slow drives
+ // usleep(300);
+ break;
+ case disk_io_job::write:
+#ifdef TORRENT_DISK_STATS
+ m_log << log_time() << " write " << j.buffer_size << std::endl;
+#endif
+ TORRENT_ASSERT(j.buffer);
+ TORRENT_ASSERT(j.buffer_size <= m_block_size);
+ j.storage->write_impl(j.buffer, j.piece, j.offset
+ , j.buffer_size);
+
+ // simulates a slow drive
+ // usleep(300);
+ break;
+ case disk_io_job::hash:
+ {
+#ifdef TORRENT_DISK_STATS
+ m_log << log_time() << " hash" << std::endl;
+#endif
+ sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
+ j.str.resize(20);
+ std::memcpy(&j.str[0], &h[0], 20);
+ }
+ break;
+ case disk_io_job::move_storage:
+#ifdef TORRENT_DISK_STATS
+ m_log << log_time() << " move" << std::endl;
+#endif
+ ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
+ j.str = j.storage->save_path().string();
+ break;
+ case disk_io_job::release_files:
+#ifdef TORRENT_DISK_STATS
+ m_log << log_time() << " release" << std::endl;
+#endif
+ j.storage->release_files_impl();
+ break;
+ case disk_io_job::delete_files:
+#ifdef TORRENT_DISK_STATS
+ m_log << log_time() << " delete" << std::endl;
+#endif
+ j.storage->delete_files_impl();
+ break;
+ }
+ }
+ catch (std::exception& e)
+ {
+// std::cerr << "DISK THREAD: exception: " << e.what() << std::endl;
+ try
+ {
+ j.str = e.what();
+ }
+ catch (std::exception&) {}
+ ret = -1;
+ }
+
+// if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
+// else std::cerr << "DISK THREAD: invoking callback" << std::endl;
+ try { if (handler) handler(ret, j); }
+ catch (std::exception&) {}
+
+#ifndef NDEBUG
+ m_current.storage = 0;
+ m_current.callback.clear();
+#endif
+
+ if (j.buffer && free_current_buffer) free_buffer(j.buffer);
+ }
+ }
+}
+
diff --git a/src/libtorrent/src/entry.cpp b/src/libtorrent/src/entry.cpp
new file mode 100644
index 0000000..c3e9104
--- /dev/null
+++ b/src/libtorrent/src/entry.cpp
@@ -0,0 +1,360 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <algorithm>
+#include <iostream>
+#include <iomanip>
+#include "libtorrent/entry.hpp"
+#include "libtorrent/config.hpp"
+
+#if defined(_MSC_VER)
+namespace std
+{
+ using ::isprint;
+}
+#define for if (false) {} else for
+#endif
+
+namespace
+{
+ template <class T>
+ void call_destructor(T* o)
+ {
+ TORRENT_ASSERT(o);
+ o->~T();
+ }
+
+ struct compare_string
+ {
+ compare_string(char const* s): m_str(s) {}
+
+ bool operator()(
+ std::pair<std::string
+ , libtorrent::entry> const& e) const
+ {
+ return m_str && e.first == m_str;
+ }
+ char const* m_str;
+ };
+}
+
+namespace libtorrent
+{
+ namespace detail
+ {
+ TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
+ {
+ int sign = 0;
+ if (val < 0)
+ {
+ sign = 1;
+ val = -val;
+ }
+ buf[--size] = '\0';
+ if (val == 0) buf[--size] = '0';
+ for (; size > sign && val != 0;)
+ {
+ buf[--size] = '0' + char(val % 10);
+ val /= 10;
+ }
+ if (sign) buf[--size] = '-';
+ return buf + size;
+ }
+ }
+
+ entry& entry::operator[](char const* key)
+ {
+ dictionary_type::iterator i = dict().find(key);
+ if (i != dict().end()) return i->second;
+ dictionary_type::iterator ret = dict().insert(
+ dict().begin()
+ , std::make_pair(std::string(key), entry()));
+ return ret->second;
+ }
+
+
+ entry& entry::operator[](std::string const& key)
+ {
+ return (*this)[key.c_str()];
+ }
+
+ entry* entry::find_key(char const* key)
+ {
+ dictionary_type::iterator i = std::find_if(
+ dict().begin()
+ , dict().end()
+ , compare_string(key));
+ if (i == dict().end()) return 0;
+ return &i->second;
+
+ }
+
+ entry const* entry::find_key(char const* key) const
+ {
+ dictionary_type::const_iterator i = dict().find(key);
+ if (i == dict().end()) return 0;
+ return &i->second;
+ }
+
+#ifndef BOOST_NO_EXCEPTIONS
+ const entry& entry::operator[](char const* key) const
+ {
+ dictionary_type::const_iterator i = dict().find(key);
+ if (i == dict().end()) throw type_error(
+ (std::string("key not found: ") + key).c_str());
+ return i->second;
+ }
+
+ const entry& entry::operator[](std::string const& key) const
+ {
+ return (*this)[key.c_str()];
+ }
+#endif
+
+ entry::entry(dictionary_type const& v)
+ : m_type(undefined_t)
+ {
+ new(data) dictionary_type(v);
+ m_type = dictionary_t;
+ }
+
+ entry::entry(string_type const& v)
+ : m_type(undefined_t)
+ {
+ new(data) string_type(v);
+ m_type = string_t;
+ }
+
+ entry::entry(list_type const& v)
+ : m_type(undefined_t)
+ {
+ new(data) list_type(v);
+ m_type = list_t;
+ }
+
+ entry::entry(integer_type const& v)
+ : m_type(undefined_t)
+ {
+ new(data) integer_type(v);
+ m_type = int_t;
+ }
+
+ void entry::operator=(dictionary_type const& v)
+ {
+ destruct();
+ new(data) dictionary_type(v);
+ m_type = dictionary_t;
+ }
+
+ void entry::operator=(string_type const& v)
+ {
+ destruct();
+ new(data) string_type(v);
+ m_type = string_t;
+ }
+
+ void entry::operator=(list_type const& v)
+ {
+ destruct();
+ new(data) list_type(v);
+ m_type = list_t;
+ }
+
+ void entry::operator=(integer_type const& v)
+ {
+ destruct();
+ new(data) integer_type(v);
+ m_type = int_t;
+ }
+
+ bool entry::operator==(entry const& e) const
+ {
+ if (m_type != e.m_type) return false;
+
+ switch(m_type)
+ {
+ case int_t:
+ return integer() == e.integer();
+ case string_t:
+ return string() == e.string();
+ case list_t:
+ return list() == e.list();
+ case dictionary_t:
+ return dict() == e.dict();
+ default:
+ TORRENT_ASSERT(m_type == undefined_t);
+ return true;
+ }
+ }
+
+ void entry::construct(data_type t)
+ {
+ switch(t)
+ {
+ case int_t:
+ new(data) integer_type;
+ break;
+ case string_t:
+ new(data) string_type;
+ break;
+ case list_t:
+ new(data) list_type;
+ break;
+ case dictionary_t:
+ new (data) dictionary_type;
+ break;
+ default:
+ TORRENT_ASSERT(m_type == undefined_t);
+ m_type = undefined_t;
+ return;
+ }
+ m_type = t;
+ }
+
+ void entry::copy(entry const& e)
+ {
+ switch(e.m_type)
+ {
+ case int_t:
+ new(data) integer_type(e.integer());
+ break;
+ case string_t:
+ new(data) string_type(e.string());
+ break;
+ case list_t:
+ new(data) list_type(e.list());
+ break;
+ case dictionary_t:
+ new (data) dictionary_type(e.dict());
+ break;
+ default:
+ m_type = undefined_t;
+ return;
+ }
+ m_type = e.m_type;
+ }
+
+ void entry::destruct()
+ {
+ switch(m_type)
+ {
+ case int_t:
+ call_destructor(reinterpret_cast<integer_type*>(data));
+ break;
+ case string_t:
+ call_destructor(reinterpret_cast<string_type*>(data));
+ break;
+ case list_t:
+ call_destructor(reinterpret_cast<list_type*>(data));
+ break;
+ case dictionary_t:
+ call_destructor(reinterpret_cast<dictionary_type*>(data));
+ break;
+ default:
+ TORRENT_ASSERT(m_type == undefined_t);
+ break;
+ }
+ m_type = undefined_t;
+ }
+
+ void entry::swap(entry& e)
+ {
+ // not implemented
+ TORRENT_ASSERT(false);
+ }
+
+ void entry::print(std::ostream& os, int indent) const
+ {
+ TORRENT_ASSERT(indent >= 0);
+ for (int i = 0; i < indent; ++i) os << " ";
+ switch (m_type)
+ {
+ case int_t:
+ os << integer() << "\n";
+ break;
+ case string_t:
+ {
+ bool binary_string = false;
+ for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
+ {
+ if (!std::isprint(static_cast<unsigned char>(*i)))
+ {
+ binary_string = true;
+ break;
+ }
+ }
+ if (binary_string)
+ {
+ os.unsetf(std::ios_base::dec);
+ os.setf(std::ios_base::hex);
+ for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
+ os << std::setfill('0') << std::setw(2)
+ << static_cast<unsigned int>((unsigned char)*i);
+ os.unsetf(std::ios_base::hex);
+ os.setf(std::ios_base::dec);
+ os << "\n";
+ }
+ else
+ {
+ os << string() << "\n";
+ }
+ } break;
+ case list_t:
+ {
+ os << "list\n";
+ for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
+ {
+ i->print(os, indent+1);
+ }
+ } break;
+ case dictionary_t:
+ {
+ os << "dictionary\n";
+ for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
+ {
+ for (int j = 0; j < indent+1; ++j) os << " ";
+ os << "[" << i->first << "]";
+ if (i->second.type() != entry::string_t
+ && i->second.type() != entry::int_t)
+ os << "\n";
+ else os << " ";
+ i->second.print(os, indent+2);
+ }
+ } break;
+ default:
+ os << "<uninitialized>\n";
+ }
+ }
+}
+
diff --git a/src/libtorrent/src/enum_net.cpp b/src/libtorrent/src/enum_net.cpp
new file mode 100644
index 0000000..ec3238d
--- /dev/null
+++ b/src/libtorrent/src/enum_net.cpp
@@ -0,0 +1,298 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/config.hpp"
+
+#if defined TORRENT_BSD || defined TORRENT_LINUX
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#elif defined TORRENT_WINDOWS
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <iphlpapi.h>
+#endif
+
+#include "libtorrent/enum_net.hpp"
+// for is_loopback and is_any
+#include "libtorrent/broadcast_socket.hpp"
+
+namespace libtorrent
+{
+ namespace
+ {
+ address sockaddr_to_address(sockaddr const* sin)
+ {
+ if (sin->sa_family == AF_INET)
+ {
+ typedef asio::ip::address_v4::bytes_type bytes_t;
+ bytes_t b;
+ memcpy(&b[0], &((sockaddr_in const*)sin)->sin_addr, b.size());
+ return address_v4(b);
+ }
+ else if (sin->sa_family == AF_INET6)
+ {
+ typedef asio::ip::address_v6::bytes_type bytes_t;
+ bytes_t b;
+ memcpy(&b[0], &((sockaddr_in6 const*)sin)->sin6_addr, b.size());
+ return address_v6(b);
+ }
+ return address();
+ }
+ }
+
+ bool in_subnet(address const& addr, ip_interface const& iface)
+ {
+ if (addr.is_v4() != iface.interface_address.is_v4()) return false;
+ // since netmasks seems unreliable for IPv6 interfaces
+ // (MacOS X returns AF_INET addresses as bitmasks) assume
+ // that any IPv6 address belongs to the subnet of any
+ // interface with an IPv6 address
+ if (addr.is_v6()) return true;
+
+ return (addr.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong())
+ == (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong());
+ }
+
+ bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec)
+ {
+ std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec);
+ if (ec) return false;
+ for (std::vector<ip_interface>::const_iterator i = net.begin()
+ , end(net.end()); i != end; ++i)
+ {
+ if (in_subnet(addr, *i)) return true;
+ }
+ return false;
+ }
+
+ std::vector<ip_interface> enum_net_interfaces(asio::io_service& ios, asio::error_code& ec)
+ {
+ std::vector<ip_interface> ret;
+
+#if defined TORRENT_LINUX || defined TORRENT_BSD
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ {
+ ec = asio::error::fault;
+ return ret;
+ }
+ ifconf ifc;
+ char buf[1024];
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
+ {
+ ec = asio::error_code(errno, asio::error::system_category);
+ close(s);
+ return ret;
+ }
+
+ char *ifr = (char*)ifc.ifc_req;
+ int remaining = ifc.ifc_len;
+
+ while (remaining)
+ {
+ ifreq const& item = *reinterpret_cast<ifreq*>(ifr);
+
+ if (item.ifr_addr.sa_family == AF_INET
+ || item.ifr_addr.sa_family == AF_INET6)
+ {
+ ip_interface iface;
+ iface.interface_address = sockaddr_to_address(&item.ifr_addr);
+
+ ifreq netmask = item;
+ if (ioctl(s, SIOCGIFNETMASK, &netmask) < 0)
+ {
+ if (iface.interface_address.is_v6())
+ {
+ // this is expected to fail (at least on MacOS X)
+ iface.netmask = address_v6::any();
+ }
+ else
+ {
+ ec = asio::error_code(errno, asio::error::system_category);
+ close(s);
+ return ret;
+ }
+ }
+ else
+ {
+ iface.netmask = sockaddr_to_address(&netmask.ifr_addr);
+ }
+ ret.push_back(iface);
+ }
+
+#if defined TORRENT_BSD
+ int current_size = item.ifr_addr.sa_len + IFNAMSIZ;
+#elif defined TORRENT_LINUX
+ int current_size = sizeof(ifreq);
+#endif
+ ifr += current_size;
+ remaining -= current_size;
+ }
+ close(s);
+
+#elif defined TORRENT_WINDOWS
+
+ SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == SOCKET_ERROR)
+ {
+ ec = asio::error_code(WSAGetLastError(), asio::error::system_category);
+ return ret;
+ }
+
+ INTERFACE_INFO buffer[30];
+ DWORD size;
+
+ if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer,
+ sizeof(buffer), &size, 0, 0) != 0)
+ {
+ ec = asio::error_code(WSAGetLastError(), asio::error::system_category);
+ closesocket(s);
+ return ret;
+ }
+ closesocket(s);
+
+ int n = size / sizeof(INTERFACE_INFO);
+
+ ip_interface iface;
+ for (int i = 0; i < n; ++i)
+ {
+ iface.interface_address = sockaddr_to_address(&buffer[i].iiAddress.Address);
+ iface.netmask = sockaddr_to_address(&buffer[i].iiNetmask.Address);
+ if (iface.interface_address == address_v4::any()) continue;
+ ret.push_back(iface);
+ }
+
+#else
+#warning THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK
+ // make a best guess of the interface we're using and its IP
+ udp::resolver r(ios);
+ udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0"));
+ if (ec) return ret;
+ ip_interface iface;
+ for (;i != udp::resolver_iterator(); ++i)
+ {
+ iface.interface_address = i->endpoint().address();
+ if (iface.interface_address.is_v4())
+ iface.netmask = address_v4::netmask(iface.interface_address.to_v4());
+ ret.push_back(iface);
+ }
+#endif
+ return ret;
+ }
+
+ address router_for_interface(address const interface, asio::error_code& ec)
+ {
+#ifdef TORRENT_WINDOWS
+
+ // Load Iphlpapi library
+ HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
+ if (!iphlp)
+ {
+ ec = asio::error::fault;
+ return address_v4::any();
+ }
+
+ // Get GetAdaptersInfo() pointer
+ typedef DWORD (WINAPI *GetAdaptersInfo_t)(PIP_ADAPTER_INFO, PULONG);
+ GetAdaptersInfo_t GetAdaptersInfo = (GetAdaptersInfo_t)GetProcAddress(iphlp, "GetAdaptersInfo");
+ if (!GetAdaptersInfo)
+ {
+ FreeLibrary(iphlp);
+ ec = asio::error::fault;
+ return address_v4::any();
+ }
+
+ PIP_ADAPTER_INFO adapter_info = 0;
+ ULONG out_buf_size = 0;
+ if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
+ {
+ FreeLibrary(iphlp);
+ ec = asio::error::fault;
+ return address_v4::any();
+ }
+
+ adapter_info = (IP_ADAPTER_INFO*)malloc(out_buf_size);
+ if (!adapter_info)
+ {
+ FreeLibrary(iphlp);
+ ec = asio::error::fault;
+ return address_v4::any();
+ }
+
+ address ret;
+ if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR)
+ {
+
+ for (PIP_ADAPTER_INFO adapter = adapter_info;
+ adapter != 0; adapter = adapter->Next)
+ {
+ address iface = address::from_string(adapter->IpAddressList.IpAddress.String, ec);
+ if (ec)
+ {
+ ec = asio::error_code();
+ continue;
+ }
+ if (is_loopback(iface) || is_any(iface)) continue;
+ if (interface == address() || interface == iface)
+ {
+ ret = address::from_string(adapter->GatewayList.IpAddress.String, ec);
+ break;
+ }
+ }
+ }
+
+ // Free memory
+ free(adapter_info);
+ FreeLibrary(iphlp);
+
+ return ret;
+
+#else
+ // TODO: temporary implementation
+ if (!interface.is_v4())
+ {
+ ec = asio::error::fault;
+ return address_v4::any();
+ }
+ return address_v4((interface.to_v4().to_ulong() & 0xffffff00) | 1);
+#endif
+ }
+
+}
+
+
diff --git a/src/libtorrent/src/escape_string.cpp b/src/libtorrent/src/escape_string.cpp
new file mode 100644
index 0000000..323a3e1
--- /dev/null
+++ b/src/libtorrent/src/escape_string.cpp
@@ -0,0 +1,151 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <string>
+#include <stdexcept>
+#include <sstream>
+#include <iomanip>
+#include <cctype>
+#include <algorithm>
+
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+ std::string unescape_string(std::string const& s)
+ {
+ std::string ret;
+ for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
+ {
+ if(*i == '+')
+ {
+ ret += ' ';
+ }
+ else if (*i != '%')
+ {
+ ret += *i;
+ }
+ else
+ {
+ ++i;
+ if (i == s.end())
+ throw std::runtime_error("invalid escaped string");
+
+ int high;
+ if(*i >= '0' && *i <= '9') high = *i - '0';
+ else if(*i >= 'A' && *i <= 'F') high = *i + 10 - 'A';
+ else if(*i >= 'a' && *i <= 'f') high = *i + 10 - 'a';
+ else throw std::runtime_error("invalid escaped string");
+
+ ++i;
+ if (i == s.end())
+ throw std::runtime_error("invalid escaped string");
+
+ int low;
+ if(*i >= '0' && *i <= '9') low = *i - '0';
+ else if(*i >= 'A' && *i <= 'F') low = *i + 10 - 'A';
+ else if(*i >= 'a' && *i <= 'f') low = *i + 10 - 'a';
+ else throw std::runtime_error("invalid escaped string");
+
+ ret += char(high * 16 + low);
+ }
+ }
+ return ret;
+ }
+
+
+ std::string escape_string(const char* str, int len)
+ {
+ TORRENT_ASSERT(str != 0);
+ TORRENT_ASSERT(len >= 0);
+ // http://www.ietf.org/rfc/rfc2396.txt
+ // section 2.3
+ // some trackers seems to require that ' is escaped
+// static const char unreserved_chars[] = "-_.!~*'()";
+ static const char unreserved_chars[] = "-_.!~*()"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789";
+
+ std::stringstream ret;
+ ret << std::hex << std::setfill('0');
+ for (int i = 0; i < len; ++i)
+ {
+ if (std::count(
+ unreserved_chars
+ , unreserved_chars+sizeof(unreserved_chars)-1
+ , *str))
+ {
+ ret << *str;
+ }
+ else
+ {
+ ret << '%'
+ << std::setw(2)
+ << (int)static_cast<unsigned char>(*str);
+ }
+ ++str;
+ }
+ return ret.str();
+ }
+
+ std::string escape_path(const char* str, int len)
+ {
+ TORRENT_ASSERT(str != 0);
+ TORRENT_ASSERT(len >= 0);
+ static const char unreserved_chars[] = "/-_.!~*()"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789";
+
+ std::stringstream ret;
+ ret << std::hex << std::setfill('0');
+ for (int i = 0; i < len; ++i)
+ {
+ if (std::count(
+ unreserved_chars
+ , unreserved_chars+sizeof(unreserved_chars)-1
+ , *str))
+ {
+ ret << *str;
+ }
+ else
+ {
+ ret << '%'
+ << std::setw(2)
+ << (int)static_cast<unsigned char>(*str);
+ }
+ ++str;
+ }
+ return ret.str();
+ }
+}
diff --git a/src/libtorrent/src/file.cpp b/src/libtorrent/src/file.cpp
new file mode 100644
index 0000000..7fde002
--- /dev/null
+++ b/src/libtorrent/src/file.cpp
@@ -0,0 +1,367 @@
+/*
+
+Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/file.hpp"
+#include "libtorrent/utf8.hpp"
+#include "libtorrent/assert.hpp"
+
+#ifdef UNICODE
+#include "libtorrent/storage.hpp"
+#endif
+
+#include <sstream>
+#include <windows.h>
+#include <winioctl.h>
+
+namespace
+{
+ // must be used to not leak memory in case something would throw
+ class auto_localfree
+ {
+ public:
+ auto_localfree(HLOCAL memory)
+ : m_memory(memory)
+ {
+ }
+ ~auto_localfree()
+ {
+ if (m_memory)
+ LocalFree(m_memory);
+ }
+ private:
+ HLOCAL m_memory;
+ };
+
+ std::string utf8_native(std::string const& s)
+ {
+ try
+ {
+ std::wstring ws;
+ libtorrent::utf8_wchar(s, ws);
+ std::size_t size = wcstombs(0, ws.c_str(), 0);
+ if (size == std::size_t(-1)) return s;
+ std::string ret;
+ ret.resize(size);
+ size = wcstombs(&ret[0], ws.c_str(), size + 1);
+ if (size == wchar_t(-1)) return s;
+ ret.resize(size);
+ return ret;
+ }
+ catch(std::exception)
+ {
+ return s;
+ }
+ }
+
+ void throw_exception(const char* thrower)
+ {
+ DWORD err = GetLastError();
+
+#ifdef UNICODE
+ wchar_t *wbuffer = 0;
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM
+ |FORMAT_MESSAGE_ALLOCATE_BUFFER
+ , 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
+ auto_localfree auto_free(wbuffer);
+ std::string tmp_utf8;
+ libtorrent::wchar_utf8(wbuffer, tmp_utf8);
+ char const* buffer = tmp_utf8.c_str();
+#else
+ char* buffer = 0;
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM
+ |FORMAT_MESSAGE_ALLOCATE_BUFFER
+ , 0, err, 0, (LPSTR)&buffer, 0, 0);
+ auto_localfree auto_free(buffer);
+#endif
+
+ std::stringstream s;
+ s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");
+
+ throw libtorrent::file_error(s.str());
+ }
+}
+
+namespace libtorrent
+{
+
+ struct file::impl : boost::noncopyable
+ {
+ enum open_flags
+ {
+ read_flag = 1,
+ write_flag = 2
+ };
+
+ enum seek_mode
+ {
+ seek_begin = FILE_BEGIN,
+ seek_from_here = FILE_CURRENT,
+ seek_end = FILE_END
+ };
+
+ impl()
+ {
+ m_file_handle = INVALID_HANDLE_VALUE;
+ }
+
+ void open(const char *file_name, open_flags flags)
+ {
+ TORRENT_ASSERT(file_name);
+ TORRENT_ASSERT(flags & (read_flag | write_flag));
+
+ DWORD access_mask = 0;
+ if (flags & read_flag)
+ access_mask |= GENERIC_READ;
+ if (flags & write_flag)
+ access_mask |= GENERIC_WRITE;
+
+ TORRENT_ASSERT(access_mask & (GENERIC_READ | GENERIC_WRITE));
+
+ #ifdef UNICODE
+ std::wstring wfile_name(safe_convert(file_name));
+ HANDLE new_handle = CreateFile(
+ wfile_name.c_str()
+ , access_mask
+ , FILE_SHARE_READ
+ , 0
+ , (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
+ , FILE_ATTRIBUTE_NORMAL
+ , 0);
+ #else
+ HANDLE new_handle = CreateFile(
+ utf8_native(file_name).c_str()
+ , access_mask
+ , FILE_SHARE_READ
+ , 0
+ , (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
+ , FILE_ATTRIBUTE_NORMAL
+ , 0);
+ #endif
+
+ if (new_handle == INVALID_HANDLE_VALUE)
+ throw_exception(file_name);
+ // try to make the file sparse if supported
+ if (access_mask & GENERIC_WRITE)
+ {
+ DWORD temp;
+ ::DeviceIoControl(new_handle, FSCTL_SET_SPARSE, 0, 0
+ , 0, 0, &temp, 0);
+ }
+ // will only close old file if the open succeeded
+ close();
+ m_file_handle = new_handle;
+ }
+
+ void close()
+ {
+ if (m_file_handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(m_file_handle);
+ m_file_handle = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ ~impl()
+ {
+ close();
+ }
+
+ size_type write(const char* buffer, size_type num_bytes)
+ {
+ TORRENT_ASSERT(buffer);
+ TORRENT_ASSERT((DWORD)num_bytes == num_bytes);
+ DWORD bytes_written = 0;
+ if (num_bytes != 0)
+ {
+ if (FALSE == WriteFile(
+ m_file_handle
+ , buffer
+ , (DWORD)num_bytes
+ , &bytes_written
+ , 0))
+ {
+ throw_exception("file::write");
+ }
+ }
+ return bytes_written;
+ }
+
+ size_type read(char* buffer, size_type num_bytes)
+ {
+ TORRENT_ASSERT(buffer);
+ TORRENT_ASSERT(num_bytes >= 0);
+ TORRENT_ASSERT((DWORD)num_bytes == num_bytes);
+
+ DWORD bytes_read = 0;
+ if (num_bytes != 0)
+ {
+ if (FALSE == ReadFile(
+ m_file_handle
+ , buffer
+ , (DWORD)num_bytes
+ , &bytes_read
+ , 0))
+ {
+ throw_exception("file::read");
+ }
+ }
+ return bytes_read;
+ }
+
+ void set_size(size_type s)
+ {
+ size_type pos = tell();
+ seek(s, seek_begin);
+ if (FALSE == ::SetEndOfFile(m_file_handle))
+ throw_exception("file::set_size");
+
+ seek(pos, seek_begin);
+ }
+
+ size_type seek(size_type pos, seek_mode from_where)
+ {
+ TORRENT_ASSERT(pos >= 0 || from_where != seek_begin);
+ TORRENT_ASSERT(pos <= 0 || from_where != seek_end);
+ LARGE_INTEGER offs;
+ offs.QuadPart = pos;
+ if (FALSE == SetFilePointerEx(
+ m_file_handle
+ , offs
+ , &offs
+ , from_where))
+ {
+ throw_exception("file::seek");
+ }
+ return offs.QuadPart;
+ }
+
+ size_type tell()
+ {
+ LARGE_INTEGER offs;
+ offs.QuadPart = 0;
+
+ // is there any other way to get offset?
+ if (FALSE == SetFilePointerEx(
+ m_file_handle
+ , offs
+ , &offs
+ , FILE_CURRENT))
+ {
+ throw_exception("file::tell");
+ }
+
+ size_type pos = offs.QuadPart;
+ TORRENT_ASSERT(pos >= 0);
+ return pos;
+ }
+/*
+ size_type size()
+ {
+ LARGE_INTEGER s;
+ if (FALSE == GetFileSizeEx(m_file_handle, &s))
+ {
+ throw_exception("file::size");
+ }
+
+ size_type size = s.QuadPart;
+ TORRENT_ASSERT(size >= 0);
+ return size;
+ }
+*/
+ private:
+
+ HANDLE m_file_handle;
+
+ };
+}
+
+namespace libtorrent
+{
+
+ const file::seek_mode file::begin(file::impl::seek_begin);
+ const file::seek_mode file::end(file::impl::seek_end);
+
+ const file::open_mode file::in(file::impl::read_flag);
+ const file::open_mode file::out(file::impl::write_flag);
+
+ file::file()
+ : m_impl(new libtorrent::file::impl())
+ {
+ }
+ file::file(boost::filesystem::path const& p, open_mode m)
+ : m_impl(new libtorrent::file::impl())
+ {
+ open(p,m);
+ }
+
+ file::~file()
+ {
+ }
+
+ void file::open(boost::filesystem::path const& p, open_mode m)
+ {
+ TORRENT_ASSERT(p.is_complete());
+ m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
+ }
+
+ void file::close()
+ {
+ m_impl->close();
+ }
+
+ size_type file::write(const char* buffer, size_type num_bytes)
+ {
+ return m_impl->write(buffer, num_bytes);
+ }
+
+ size_type file::read(char* buffer, size_type num_bytes)
+ {
+ return m_impl->read(buffer, num_bytes);
+ }
+
+ void file::set_size(size_type s)
+ {
+ m_impl->set_size(s);
+ }
+
+ size_type file::seek(size_type pos, seek_mode m)
+ {
+ return m_impl->seek(pos,impl::seek_mode(m.m_val));
+ }
+
+ size_type file::tell()
+ {
+ return m_impl->tell();
+ }
+}
diff --git a/src/libtorrent/src/file_pool.cpp b/src/libtorrent/src/file_pool.cpp
new file mode 100644
index 0000000..7bdf240
--- /dev/null
+++ b/src/libtorrent/src/file_pool.cpp
@@ -0,0 +1,134 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/file_pool.hpp"
+
+#include <iostream>
+
+namespace libtorrent
+{
+ using boost::multi_index::nth_index;
+ using boost::multi_index::get;
+
+ boost::shared_ptr<file> file_pool::open_file(void* st, fs::path const& p, file::open_mode m)
+ {
+ TORRENT_ASSERT(st != 0);
+ TORRENT_ASSERT(p.is_complete());
+ TORRENT_ASSERT(m == file::in || m == (file::in | file::out));
+ boost::mutex::scoped_lock l(m_mutex);
+ typedef nth_index<file_set, 0>::type path_view;
+ path_view& pt = get<0>(m_files);
+ path_view::iterator i = pt.find(p);
+ if (i != pt.end())
+ {
+ lru_file_entry e = *i;
+ e.last_use = time_now();
+
+ if (e.key != st)
+ {
+ // this means that another instance of the storage
+ // is using the exact same file.
+ throw file_error("torrent uses the same file as another torrent "
+ "(" + p.string() + ")");
+ }
+
+ e.key = st;
+ if ((e.mode & m) != m)
+ {
+ // close the file before we open it with
+ // the new read/write privilages
+ i->file_ptr.reset();
+ TORRENT_ASSERT(e.file_ptr.unique());
+ e.file_ptr.reset();
+ e.file_ptr.reset(new file(p, m));
+ e.mode = m;
+ }
+ pt.replace(i, e);
+ return e.file_ptr;
+ }
+ // the file is not in our cache
+ if ((int)m_files.size() >= m_size)
+ {
+ // the file cache is at its maximum size, close
+ // the least recently used (lru) file from it
+ typedef nth_index<file_set, 1>::type lru_view;
+ lru_view& lt = get<1>(m_files);
+ lru_view::iterator i = lt.begin();
+ // the first entry in this view is the least recently used
+ TORRENT_ASSERT(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
+ lt.erase(i);
+ }
+ lru_file_entry e(boost::shared_ptr<file>(new file(p, m)));
+ e.mode = m;
+ e.key = st;
+ e.file_path = p;
+ pt.insert(e);
+ return e.file_ptr;
+ }
+
+ void file_pool::release(void* st)
+ {
+ boost::mutex::scoped_lock l(m_mutex);
+ TORRENT_ASSERT(st != 0);
+ using boost::tie;
+
+ typedef nth_index<file_set, 2>::type key_view;
+ key_view& kt = get<2>(m_files);
+
+ key_view::iterator start, end;
+ tie(start, end) = kt.equal_range(st);
+ kt.erase(start, end);
+ }
+
+ void file_pool::resize(int size)
+ {
+ TORRENT_ASSERT(size > 0);
+ if (size == m_size) return;
+ boost::mutex::scoped_lock l(m_mutex);
+ m_size = size;
+ if (int(m_files.size()) <= m_size) return;
+
+ // close the least recently used files
+ typedef nth_index<file_set, 1>::type lru_view;
+ lru_view& lt = get<1>(m_files);
+ lru_view::iterator i = lt.begin();
+ while (int(m_files.size()) > m_size)
+ {
+ // the first entry in this view is the least recently used
+ TORRENT_ASSERT(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
+ lt.erase(i++);
+ }
+ }
+
+}
diff --git a/src/libtorrent/src/http_connection.cpp b/src/libtorrent/src/http_connection.cpp
new file mode 100644
index 0000000..92db5c4
--- /dev/null
+++ b/src/libtorrent/src/http_connection.cpp
@@ -0,0 +1,397 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/http_connection.hpp"
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <asio/ip/tcp.hpp>
+#include <string>
+
+using boost::bind;
+
+namespace libtorrent
+{
+
+ enum { max_bottled_buffer = 1024 * 1024 };
+
+void http_connection::get(std::string const& url, time_duration timeout
+ , int handle_redirects)
+{
+ std::string protocol;
+ std::string auth;
+ std::string hostname;
+ std::string path;
+ int port;
+ boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
+ std::stringstream headers;
+ headers << "GET " << path << " HTTP/1.0\r\n"
+ "Host:" << hostname <<
+ "\r\nConnection: close\r\n";
+ if (!auth.empty())
+ headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
+ headers << "\r\n";
+ sendbuffer = headers.str();
+ start(hostname, boost::lexical_cast<std::string>(port), timeout, handle_redirects);
+}
+
+void http_connection::start(std::string const& hostname, std::string const& port
+ , time_duration timeout, int handle_redirects)
+{
+ m_redirects = handle_redirects;
+ m_timeout = timeout;
+ m_timer.expires_from_now(m_timeout);
+ m_timer.async_wait(bind(&http_connection::on_timeout
+ , boost::weak_ptr<http_connection>(shared_from_this()), _1));
+ m_called = false;
+ m_parser.reset();
+ m_recvbuffer.clear();
+ m_read_pos = 0;
+ if (m_sock.is_open() && m_hostname == hostname && m_port == port)
+ {
+ asio::async_write(m_sock, asio::buffer(sendbuffer)
+ , bind(&http_connection::on_write, shared_from_this(), _1));
+ }
+ else
+ {
+ m_sock.close();
+ tcp::resolver::query query(hostname, port);
+ m_resolver.async_resolve(query, bind(&http_connection::on_resolve
+ , shared_from_this(), _1, _2));
+ m_hostname = hostname;
+ m_port = port;
+ }
+}
+
+void http_connection::on_connect_timeout()
+{
+ if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
+ m_connection_ticket = -1;
+
+ callback(asio::error::timed_out);
+ close();
+}
+
+void http_connection::on_timeout(boost::weak_ptr<http_connection> p
+ , asio::error_code const& e)
+{
+ boost::shared_ptr<http_connection> c = p.lock();
+ if (!c) return;
+ if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket);
+ c->m_connection_ticket = -1;
+
+ if (e == asio::error::operation_aborted) return;
+
+ if (c->m_last_receive + c->m_timeout < time_now())
+ {
+ c->callback(asio::error::timed_out);
+ c->close();
+ return;
+ }
+
+ if (!c->m_sock.is_open()) return;
+
+ c->m_timer.expires_at(c->m_last_receive + c->m_timeout);
+ c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
+}
+
+void http_connection::close()
+{
+ m_timer.cancel();
+ m_limiter_timer.cancel();
+ m_sock.close();
+ m_hostname.clear();
+ m_port.clear();
+
+ if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
+ m_connection_ticket = -1;
+
+ m_handler.clear();
+}
+
+void http_connection::on_resolve(asio::error_code const& e
+ , tcp::resolver::iterator i)
+{
+ if (e)
+ {
+ callback(e);
+ close();
+ return;
+ }
+ TORRENT_ASSERT(i != tcp::resolver::iterator());
+ m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
+ , bind(&http_connection::on_connect_timeout, shared_from_this())
+ , m_timeout);
+}
+
+void http_connection::connect(int ticket, tcp::endpoint target_address)
+{
+ m_connection_ticket = ticket;
+ m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
+ , shared_from_this(), _1/*, ++i*/));
+}
+
+void http_connection::on_connect(asio::error_code const& e
+ /*, tcp::resolver::iterator i*/)
+{
+ if (!e)
+ {
+ m_last_receive = time_now();
+ if (m_connect_handler) m_connect_handler(*this);
+ asio::async_write(m_sock, asio::buffer(sendbuffer)
+ , bind(&http_connection::on_write, shared_from_this(), _1));
+ }
+/* else if (i != tcp::resolver::iterator())
+ {
+ // The connection failed. Try the next endpoint in the list.
+ m_sock.close();
+ m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
+ , bind(&http_connection::on_connect_timeout, shared_from_this())
+ , m_timeout);
+ }
+*/ else
+ {
+ callback(e);
+ close();
+ }
+}
+
+void http_connection::callback(asio::error_code const& e, char const* data, int size)
+{
+ if (!m_bottled || !m_called)
+ {
+ m_called = true;
+ if (m_handler) m_handler(e, m_parser, data, size);
+ }
+}
+
+void http_connection::on_write(asio::error_code const& e)
+{
+ if (e)
+ {
+ callback(e);
+ close();
+ return;
+ }
+
+ std::string().swap(sendbuffer);
+ m_recvbuffer.resize(4096);
+
+ int amount_to_read = m_recvbuffer.size() - m_read_pos;
+ if (m_rate_limit > 0 && amount_to_read > m_download_quota)
+ {
+ amount_to_read = m_download_quota;
+ if (m_download_quota == 0)
+ {
+ if (!m_limiter_timer_active)
+ on_assign_bandwidth(asio::error_code());
+ return;
+ }
+ }
+ m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
+ , amount_to_read)
+ , bind(&http_connection::on_read
+ , shared_from_this(), _1, _2));
+}
+
+void http_connection::on_read(asio::error_code const& e
+ , std::size_t bytes_transferred)
+{
+ if (m_rate_limit)
+ {
+ m_download_quota -= bytes_transferred;
+ TORRENT_ASSERT(m_download_quota >= 0);
+ }
+
+ if (e == asio::error::eof)
+ {
+ TORRENT_ASSERT(bytes_transferred == 0);
+ char const* data = 0;
+ std::size_t size = 0;
+ if (m_bottled && m_parser.header_finished())
+ {
+ data = m_parser.get_body().begin;
+ size = m_parser.get_body().left();
+ }
+ callback(e, data, size);
+ close();
+ return;
+ }
+
+ if (e)
+ {
+ TORRENT_ASSERT(bytes_transferred == 0);
+ callback(e);
+ close();
+ return;
+ }
+
+ m_read_pos += bytes_transferred;
+ TORRENT_ASSERT(m_read_pos <= int(m_recvbuffer.size()));
+
+ if (m_bottled || !m_parser.header_finished())
+ {
+ libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
+ , &m_recvbuffer[0] + m_read_pos);
+ try
+ {
+ m_parser.incoming(rcv_buf);
+ }
+ catch (std::exception&)
+ {
+ m_timer.cancel();
+ m_handler(asio::error::fault, m_parser, 0, 0);
+ m_handler.clear();
+ return;
+ }
+
+ // having a nonempty path means we should handle redirects
+ if (m_redirects && m_parser.header_finished())
+ {
+ int code = m_parser.status_code();
+
+ if (code >= 300 && code < 400)
+ {
+ // attempt a redirect
+ std::string const& url = m_parser.header("location");
+ if (url.empty())
+ {
+ // missing location header
+ callback(e);
+ return;
+ }
+
+ asio::error_code ec;
+ m_sock.close(ec);
+ get(url, m_timeout, m_redirects - 1);
+ return;
+ }
+
+ m_redirects = 0;
+ }
+
+ if (!m_bottled && m_parser.header_finished())
+ {
+ if (m_read_pos > m_parser.body_start())
+ callback(e, &m_recvbuffer[0] + m_parser.body_start()
+ , m_read_pos - m_parser.body_start());
+ m_read_pos = 0;
+ m_last_receive = time_now();
+ }
+ else if (m_bottled && m_parser.finished())
+ {
+ m_timer.cancel();
+ callback(e, m_parser.get_body().begin, m_parser.get_body().left());
+ }
+ }
+ else
+ {
+ TORRENT_ASSERT(!m_bottled);
+ callback(e, &m_recvbuffer[0], m_read_pos);
+ m_read_pos = 0;
+ m_last_receive = time_now();
+ }
+
+ if (int(m_recvbuffer.size()) == m_read_pos)
+ m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer)));
+ if (m_read_pos == max_bottled_buffer)
+ {
+ callback(asio::error::eof);
+ close();
+ return;
+ }
+ int amount_to_read = m_recvbuffer.size() - m_read_pos;
+ if (m_rate_limit > 0 && amount_to_read > m_download_quota)
+ {
+ amount_to_read = m_download_quota;
+ if (m_download_quota == 0)
+ {
+ if (!m_limiter_timer_active)
+ on_assign_bandwidth(asio::error_code());
+ return;
+ }
+ }
+ m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
+ , amount_to_read)
+ , bind(&http_connection::on_read
+ , shared_from_this(), _1, _2));
+}
+
+void http_connection::on_assign_bandwidth(asio::error_code const& e)
+{
+ if ((e == asio::error::operation_aborted
+ && m_limiter_timer_active)
+ || !m_sock.is_open())
+ {
+ callback(asio::error::eof);
+ return;
+ }
+ m_limiter_timer_active = false;
+ if (e) return;
+
+ if (m_download_quota > 0) return;
+
+ m_download_quota = m_rate_limit / 4;
+
+ int amount_to_read = m_recvbuffer.size() - m_read_pos;
+ if (amount_to_read > m_download_quota)
+ amount_to_read = m_download_quota;
+
+ if (!m_sock.is_open()) return;
+
+ m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
+ , amount_to_read)
+ , bind(&http_connection::on_read
+ , shared_from_this(), _1, _2));
+
+ m_limiter_timer_active = true;
+ m_limiter_timer.expires_from_now(milliseconds(250));
+ m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
+ , shared_from_this(), _1));
+}
+
+void http_connection::rate_limit(int limit)
+{
+ if (!m_sock.is_open()) return;
+
+ if (!m_limiter_timer_active)
+ {
+ m_limiter_timer_active = true;
+ m_limiter_timer.expires_from_now(milliseconds(250));
+ m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
+ , shared_from_this(), _1));
+ }
+ m_rate_limit = limit;
+}
+
+}
+
diff --git a/src/libtorrent/src/http_stream.cpp b/src/libtorrent/src/http_stream.cpp
new file mode 100644
index 0000000..0973af7
--- /dev/null
+++ b/src/libtorrent/src/http_stream.cpp
@@ -0,0 +1,162 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/http_stream.hpp"
+#include "libtorrent/tracker_manager.hpp" // for base64encode
+
+namespace libtorrent
+{
+
+ void http_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , boost::shared_ptr<handler_type> h)
+ {
+ if (e || i == tcp::resolver::iterator())
+ {
+ (*h)(e);
+ close();
+ return;
+ }
+
+ m_sock.async_connect(i->endpoint(), boost::bind(
+ &http_stream::connected, this, _1, h));
+ }
+
+ void http_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ close();
+ return;
+ }
+
+ using namespace libtorrent::detail;
+
+ if (m_no_connect)
+ {
+ std::vector<char>().swap(m_buffer);
+ (*h)(e);
+ return;
+ }
+
+ // send CONNECT
+ std::back_insert_iterator<std::vector<char> > p(m_buffer);
+ write_string("CONNECT " + boost::lexical_cast<std::string>(m_remote_endpoint)
+ + " HTTP/1.0\r\n", p);
+ if (!m_user.empty())
+ {
+ write_string("Proxy-Authorization: Basic " + base64encode(
+ m_user + ":" + m_password) + "\r\n", p);
+ }
+ write_string("\r\n", p);
+ asio::async_write(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&http_stream::handshake1, this, _1, h));
+ }
+
+ void http_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ close();
+ return;
+ }
+
+ // read one byte from the socket
+ m_buffer.resize(1);
+ asio::async_read(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&http_stream::handshake2, this, _1, h));
+ }
+
+ void http_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ close();
+ return;
+ }
+
+ int read_pos = m_buffer.size();
+ // look for \n\n and \r\n\r\n
+ // both of which means end of http response header
+ bool found_end = false;
+ if (m_buffer[read_pos - 1] == '\n' && read_pos > 2)
+ {
+ if (m_buffer[read_pos - 2] == '\n')
+ {
+ found_end = true;
+ }
+ else if (read_pos > 4
+ && m_buffer[read_pos - 2] == '\r'
+ && m_buffer[read_pos - 3] == '\n'
+ && m_buffer[read_pos - 4] == '\r')
+ {
+ found_end = true;
+ }
+ }
+
+ if (found_end)
+ {
+ m_buffer.push_back(0);
+ char* status = strchr(&m_buffer[0], ' ');
+ if (status == 0)
+ {
+ (*h)(asio::error::operation_not_supported);
+ close();
+ return;
+ }
+
+ status++;
+ int code = atoi(status);
+ if (code != 200)
+ {
+ (*h)(asio::error::operation_not_supported);
+ close();
+ return;
+ }
+
+ (*h)(e);
+ std::vector<char>().swap(m_buffer);
+ return;
+ }
+
+ // read another byte from the socket
+ m_buffer.resize(read_pos + 1);
+ asio::async_read(m_sock, asio::buffer(&m_buffer[0] + read_pos, 1)
+ , boost::bind(&http_stream::handshake2, this, _1, h));
+ }
+
+}
+
diff --git a/src/libtorrent/src/http_tracker_connection.cpp b/src/libtorrent/src/http_tracker_connection.cpp
new file mode 100644
index 0000000..d99c6f9
--- /dev/null
+++ b/src/libtorrent/src/http_tracker_connection.cpp
@@ -0,0 +1,1001 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <iostream>
+#include <cctype>
+#include <iomanip>
+#include <sstream>
+#include <algorithm>
+
+#include "libtorrent/config.hpp"
+#include "zlib.h"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/bind.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/http_tracker_connection.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/instantiate_connection.hpp"
+
+using namespace libtorrent;
+using boost::bind;
+
+namespace
+{
+ enum
+ {
+ minimum_tracker_response_length = 3,
+ http_buffer_size = 2048
+ };
+
+
+ enum
+ {
+ FTEXT = 0x01,
+ FHCRC = 0x02,
+ FEXTRA = 0x04,
+ FNAME = 0x08,
+ FCOMMENT = 0x10,
+ FRESERVED = 0xe0,
+
+ GZIP_MAGIC0 = 0x1f,
+ GZIP_MAGIC1 = 0x8b
+ };
+
+}
+
+namespace
+{
+ bool url_has_argument(std::string const& url, std::string argument)
+ {
+ size_t i = url.find('?');
+ if (i == std::string::npos) return false;
+
+ argument += '=';
+
+ if (url.compare(i + 1, argument.size(), argument) == 0) return true;
+ argument.insert(0, "&");
+ return url.find(argument, i)
+ != std::string::npos;
+ }
+
+ char to_lower(char c) { return std::tolower(c); }
+}
+
+namespace libtorrent
+{
+ http_parser::http_parser()
+ : m_recv_pos(0)
+ , m_status_code(-1)
+ , m_content_length(-1)
+ , m_state(read_status)
+ , m_recv_buffer(0, 0)
+ , m_body_start_pos(0)
+ , m_finished(false)
+ {}
+
+ boost::tuple<int, int> http_parser::incoming(buffer::const_interval recv_buffer)
+ {
+ TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
+ boost::tuple<int, int> ret(0, 0);
+
+ // early exit if there's nothing new in the receive buffer
+ if (recv_buffer.left() == m_recv_buffer.left()) return ret;
+ m_recv_buffer = recv_buffer;
+
+ char const* pos = recv_buffer.begin + m_recv_pos;
+ if (m_state == read_status)
+ {
+ TORRENT_ASSERT(!m_finished);
+ char const* newline = std::find(pos, recv_buffer.end, '\n');
+ // if we don't have a full line yet, wait.
+ if (newline == recv_buffer.end) return ret;
+
+ if (newline == pos)
+ throw std::runtime_error("unexpected newline in HTTP response");
+
+ char const* line_end = newline;
+ if (pos != line_end && *(line_end - 1) == '\r') --line_end;
+
+ std::istringstream line(std::string(pos, line_end));
+ ++newline;
+ int incoming = (int)std::distance(pos, newline);
+ m_recv_pos += incoming;
+ boost::get<1>(ret) += incoming;
+ pos = newline;
+
+ line >> m_protocol;
+ if (m_protocol.substr(0, 5) == "HTTP/")
+ {
+ line >> m_status_code;
+ std::getline(line, m_server_message);
+ }
+ else
+ {
+ m_method = m_protocol;
+ std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
+ m_protocol.clear();
+ line >> m_path >> m_protocol;
+ m_status_code = 0;
+ }
+ m_state = read_header;
+ }
+
+ if (m_state == read_header)
+ {
+ TORRENT_ASSERT(!m_finished);
+ char const* newline = std::find(pos, recv_buffer.end, '\n');
+ std::string line;
+
+ while (newline != recv_buffer.end && m_state == read_header)
+ {
+ // if the LF character is preceeded by a CR
+ // charachter, don't copy it into the line string.
+ char const* line_end = newline;
+ if (pos != line_end && *(line_end - 1) == '\r') --line_end;
+ line.assign(pos, line_end);
+ ++newline;
+ m_recv_pos += newline - pos;
+ boost::get<1>(ret) += newline - pos;
+ pos = newline;
+
+ std::string::size_type separator = line.find(':');
+ if (separator == std::string::npos)
+ {
+ // this means we got a blank line,
+ // the header is finished and the body
+ // starts.
+ m_state = read_body;
+ m_body_start_pos = m_recv_pos;
+ break;
+ }
+
+ std::string name = line.substr(0, separator);
+ std::transform(name.begin(), name.end(), name.begin(), &to_lower);
+ ++separator;
+ // skip whitespace
+ while (separator < line.size()
+ && (line[separator] == ' ' || line[separator] == '\t'))
+ ++separator;
+ std::string value = line.substr(separator, std::string::npos);
+ m_header.insert(std::make_pair(name, value));
+
+ if (name == "content-length")
+ {
+ try
+ {
+ m_content_length = boost::lexical_cast<int>(value);
+ }
+ catch(boost::bad_lexical_cast&) {}
+ }
+ else if (name == "content-range")
+ {
+ std::stringstream range_str(value);
+ char dummy;
+ std::string bytes;
+ size_type range_start, range_end;
+ // apparently some web servers do not send the "bytes"
+ // in their content-range
+ if (value.find(' ') != std::string::npos)
+ range_str >> bytes;
+ range_str >> range_start >> dummy >> range_end;
+ if (!range_str || range_end < range_start
+ || range_end - range_start + 1 >= (std::numeric_limits<int>::max)())
+ {
+ throw std::runtime_error("invalid content-range in HTTP response: " + range_str.str());
+ }
+ // the http range is inclusive
+ m_content_length = int(range_end - range_start + 1);
+ }
+
+ TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
+ newline = std::find(pos, recv_buffer.end, '\n');
+ }
+ }
+
+ if (m_state == read_body)
+ {
+ int incoming = recv_buffer.end - pos;
+ if (m_recv_pos - m_body_start_pos + incoming > m_content_length
+ && m_content_length >= 0)
+ incoming = m_content_length - m_recv_pos + m_body_start_pos;
+
+ TORRENT_ASSERT(incoming >= 0);
+ m_recv_pos += incoming;
+ boost::get<0>(ret) += incoming;
+
+ if (m_content_length >= 0
+ && m_recv_pos - m_body_start_pos >= m_content_length)
+ {
+ m_finished = true;
+ }
+ }
+ return ret;
+ }
+
+ buffer::const_interval http_parser::get_body() const
+ {
+ TORRENT_ASSERT(m_state == read_body);
+ if (m_content_length >= 0)
+ return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
+ , m_recv_buffer.begin + (std::min)(m_recv_pos
+ , m_body_start_pos + m_content_length));
+ else
+ return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
+ , m_recv_buffer.begin + m_recv_pos);
+ }
+
+ void http_parser::reset()
+ {
+ m_recv_pos = 0;
+ m_body_start_pos = 0;
+ m_status_code = -1;
+ m_content_length = -1;
+ m_finished = false;
+ m_state = read_status;
+ m_recv_buffer.begin = 0;
+ m_recv_buffer.end = 0;
+ m_header.clear();
+ }
+
+ http_tracker_connection::http_tracker_connection(
+ asio::strand& str
+ , connection_queue& cc
+ , tracker_manager& man
+ , tracker_request const& req
+ , std::string const& hostname
+ , unsigned short port
+ , std::string request
+ , address bind_infc
+ , boost::weak_ptr<request_callback> c
+ , session_settings const& stn
+ , proxy_settings const& ps
+ , std::string const& auth)
+ : tracker_connection(man, req, str, bind_infc, c)
+ , m_man(man)
+ , m_strand(str)
+ , m_name_lookup(m_strand.io_service())
+ , m_port(port)
+ , m_recv_pos(0)
+ , m_buffer(http_buffer_size)
+ , m_settings(stn)
+ , m_proxy(ps)
+ , m_password(auth)
+ , m_timed_out(false)
+ , m_connection_ticket(-1)
+ , m_cc(cc)
+ {
+ m_send_buffer.assign("GET ");
+
+ // should we use the proxy?
+ if (m_proxy.type == proxy_settings::http
+ || m_proxy.type == proxy_settings::http_pw)
+ {
+ m_send_buffer += "http://";
+ m_send_buffer += hostname;
+ if (port != 80)
+ {
+ m_send_buffer += ":";
+ m_send_buffer += boost::lexical_cast<std::string>(port);
+ }
+ }
+
+ if (tracker_req().kind == tracker_request::scrape_request)
+ {
+ // find and replace "announce" with "scrape"
+ // in request
+
+ std::size_t pos = request.find("announce");
+ if (pos == std::string::npos)
+ throw std::runtime_error("scrape is not available on url: '"
+ + tracker_req().url +"'");
+ request.replace(pos, 8, "scrape");
+ }
+
+ m_send_buffer += request;
+
+ // if request-string already contains
+ // some parameters, append an ampersand instead
+ // of a question mark
+ size_t arguments_start = request.find('?');
+ if (arguments_start != std::string::npos)
+ m_send_buffer += "&";
+ else
+ m_send_buffer += "?";
+
+ if (!url_has_argument(request, "info_hash"))
+ {
+ m_send_buffer += "info_hash=";
+ m_send_buffer += escape_string(
+ reinterpret_cast<const char*>(req.info_hash.begin()), 20);
+ m_send_buffer += '&';
+ }
+
+ if (tracker_req().kind == tracker_request::announce_request)
+ {
+ if (!url_has_argument(request, "peer_id"))
+ {
+ m_send_buffer += "peer_id=";
+ m_send_buffer += escape_string(
+ reinterpret_cast<const char*>(req.pid.begin()), 20);
+ m_send_buffer += '&';
+ }
+
+ if (!url_has_argument(request, "port"))
+ {
+ m_send_buffer += "port=";
+ m_send_buffer += boost::lexical_cast<std::string>(req.listen_port);
+ m_send_buffer += '&';
+ }
+
+ if (!url_has_argument(request, "uploaded"))
+ {
+ m_send_buffer += "uploaded=";
+ m_send_buffer += boost::lexical_cast<std::string>(req.uploaded);
+ m_send_buffer += '&';
+ }
+
+ if (!url_has_argument(request, "downloaded"))
+ {
+ m_send_buffer += "downloaded=";
+ m_send_buffer += boost::lexical_cast<std::string>(req.downloaded);
+ m_send_buffer += '&';
+ }
+
+ if (!url_has_argument(request, "left"))
+ {
+ m_send_buffer += "left=";
+ m_send_buffer += boost::lexical_cast<std::string>(req.left);
+ m_send_buffer += '&';
+ }
+
+ if (req.event != tracker_request::none)
+ {
+ if (!url_has_argument(request, "event"))
+ {
+ const char* event_string[] = {"completed", "started", "stopped"};
+ m_send_buffer += "event=";
+ m_send_buffer += event_string[req.event - 1];
+ m_send_buffer += '&';
+ }
+ }
+ if (!url_has_argument(request, "key"))
+ {
+ m_send_buffer += "key=";
+ std::stringstream key_string;
+ key_string << std::hex << req.key;
+ m_send_buffer += key_string.str();
+ m_send_buffer += '&';
+ }
+
+ if (!url_has_argument(request, "compact"))
+ {
+ m_send_buffer += "compact=1&";
+ }
+ if (!url_has_argument(request, "numwant"))
+ {
+ m_send_buffer += "numwant=";
+ m_send_buffer += boost::lexical_cast<std::string>(
+ (std::min)(req.num_want, 999));
+ m_send_buffer += '&';
+ }
+ if (m_settings.announce_ip != address() && !url_has_argument(request, "ip"))
+ {
+ m_send_buffer += "ip=";
+ m_send_buffer += m_settings.announce_ip.to_string();
+ m_send_buffer += '&';
+ }
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ m_send_buffer += "supportcrypto=1&";
+#endif
+
+ if (!url_has_argument(request, "ipv6") && !req.ipv6.empty())
+ {
+ m_send_buffer += "ipv6=";
+ m_send_buffer += req.ipv6;
+ m_send_buffer += '&';
+ }
+
+ // extension that tells the tracker that
+ // we don't need any peer_id's in the response
+ if (!url_has_argument(request, "no_peer_id"))
+ {
+ m_send_buffer += "no_peer_id=1";
+ }
+ else
+ {
+ // remove the trailing '&'
+ m_send_buffer.resize(m_send_buffer.size() - 1);
+ }
+ }
+
+ m_send_buffer += " HTTP/1.0\r\nAccept-Encoding: gzip\r\n"
+ "User-Agent: ";
+ m_send_buffer += m_settings.user_agent;
+ m_send_buffer += "\r\n"
+ "Host: ";
+ m_send_buffer += hostname;
+ if (port != 80)
+ {
+ m_send_buffer += ':';
+ m_send_buffer += boost::lexical_cast<std::string>(port);
+ }
+ if (m_proxy.type == proxy_settings::http_pw)
+ {
+ m_send_buffer += "\r\nProxy-Authorization: Basic ";
+ m_send_buffer += base64encode(m_proxy.username + ":" + m_proxy.password);
+ }
+ if (!auth.empty())
+ {
+ m_send_buffer += "\r\nAuthorization: Basic ";
+ m_send_buffer += base64encode(auth);
+ }
+ m_send_buffer += "\r\n\r\n";
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb)
+ {
+ cb->debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]");
+ std::stringstream info_hash_str;
+ info_hash_str << req.info_hash;
+ cb->debug_log("info_hash: "
+ + boost::lexical_cast<std::string>(req.info_hash));
+ cb->debug_log("name lookup: " + hostname);
+ }
+#endif
+
+ tcp::resolver::query q(hostname
+ , boost::lexical_cast<std::string>(m_port));
+ m_name_lookup.async_resolve(q, m_strand.wrap(
+ boost::bind(&http_tracker_connection::name_lookup, self(), _1, _2)));
+ set_timeout(req.event == tracker_request::stopped
+ ? m_settings.stop_tracker_timeout
+ : m_settings.tracker_completion_timeout
+ , m_settings.tracker_receive_timeout);
+ }
+
+ void http_tracker_connection::on_timeout()
+ {
+ m_timed_out = true;
+ m_socket.close();
+ m_name_lookup.cancel();
+ if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
+ m_connection_ticket = -1;
+ fail_timeout();
+ }
+
+ void http_tracker_connection::close()
+ {
+ asio::error_code ec;
+ m_socket.close(ec);
+ m_name_lookup.cancel();
+ if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
+ m_connection_ticket = -1;
+ m_timed_out = true;
+ tracker_connection::close();
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<request_callback> cb = requester();
+ std::stringstream msg;
+ msg << "http_tracker_connection::close() " << m_man.num_requests();
+ if (cb) cb->debug_log(msg.str());
+#endif
+ }
+
+ void http_tracker_connection::name_lookup(asio::error_code const& error
+ , tcp::resolver::iterator i) try
+ {
+ boost::shared_ptr<request_callback> cb = requester();
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (cb) cb->debug_log("tracker name lookup handler called");
+#endif
+ if (error == asio::error::operation_aborted) return;
+ if (m_timed_out) return;
+
+ if (error || i == tcp::resolver::iterator())
+ {
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (cb) cb->debug_log("tracker name lookup successful");
+#endif
+ restart_read_timeout();
+
+ // look for an address that has the same kind as the one
+ // we're listening on. To make sure the tracker get our
+ // correct listening address.
+ tcp::resolver::iterator target = i;
+ tcp::resolver::iterator end;
+ tcp::endpoint target_address = *i;
+ for (; target != end && target->endpoint().address().is_v4()
+ != bind_interface().is_v4(); ++target);
+ if (target == end)
+ {
+ TORRENT_ASSERT(target_address.address().is_v4() != bind_interface().is_v4());
+ if (cb)
+ {
+ std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
+ std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
+ cb->tracker_warning("the tracker only resolves to an "
+ + tracker_address_type + " address, and you're listening on an "
+ + bind_address_type + " socket. This may prevent you from receiving incoming connections.");
+ }
+ }
+ else
+ {
+ target_address = *target;
+ }
+
+ if (cb) cb->m_tracker_address = target_address;
+ bool ret = instantiate_connection(m_strand.io_service(), m_proxy, m_socket);
+
+ TORRENT_ASSERT(ret);
+
+ if (m_proxy.type == proxy_settings::http
+ || m_proxy.type == proxy_settings::http_pw)
+ {
+ // the tracker connection will talk immediately to
+ // the proxy, without requiring CONNECT support
+ m_socket.get<http_stream>().set_no_connect(true);
+ }
+
+ m_socket.open(target_address.protocol());
+ m_socket.bind(tcp::endpoint(bind_interface(), 0));
+ m_cc.enqueue(bind(&http_tracker_connection::connect, self(), _1, target_address)
+ , bind(&http_tracker_connection::on_timeout, self())
+ , seconds(m_settings.tracker_receive_timeout));
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ };
+
+ void http_tracker_connection::connect(int ticket, tcp::endpoint target_address)
+ {
+ m_connection_ticket = ticket;
+ m_socket.async_connect(target_address, bind(&http_tracker_connection::connected, self(), _1));
+ }
+
+ void http_tracker_connection::connected(asio::error_code const& error) try
+ {
+ if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
+ m_connection_ticket = -1;
+ if (error == asio::error::operation_aborted) return;
+ if (m_timed_out) return;
+ if (error)
+ {
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb) cb->debug_log("tracker connection successful");
+#endif
+
+ restart_read_timeout();
+ async_write(m_socket, asio::buffer(m_send_buffer.c_str()
+ , m_send_buffer.size()), bind(&http_tracker_connection::sent
+ , self(), _1));
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ }
+
+ void http_tracker_connection::sent(asio::error_code const& error) try
+ {
+ if (error == asio::error::operation_aborted) return;
+ if (m_timed_out) return;
+ if (error)
+ {
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb) cb->debug_log("tracker send data completed");
+#endif
+ restart_read_timeout();
+ TORRENT_ASSERT(m_buffer.size() - m_recv_pos > 0);
+ m_socket.async_read_some(asio::buffer(&m_buffer[m_recv_pos]
+ , m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
+ , self(), _1, _2));
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ }; // msvc 7.1 seems to require this semi-colon
+
+
+ void http_tracker_connection::receive(asio::error_code const& error
+ , std::size_t bytes_transferred) try
+ {
+ if (error == asio::error::operation_aborted) return;
+ if (m_timed_out) return;
+
+ if (error)
+ {
+ if (error == asio::error::eof)
+ {
+ on_response();
+ close();
+ return;
+ }
+
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+ restart_read_timeout();
+ TORRENT_ASSERT(bytes_transferred > 0);
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb) cb->debug_log("tracker connection reading "
+ + boost::lexical_cast<std::string>(bytes_transferred));
+#endif
+
+ m_recv_pos += bytes_transferred;
+ m_parser.incoming(buffer::const_interval(&m_buffer[0]
+ , &m_buffer[0] + m_recv_pos));
+
+ // if the receive buffer is full, expand it with http_buffer_size
+ if ((int)m_buffer.size() == m_recv_pos)
+ {
+ if ((int)m_buffer.size() >= m_settings.tracker_maximum_response_length)
+ {
+ fail(200, "too large tracker response");
+ return;
+ }
+ TORRENT_ASSERT(http_buffer_size > 0);
+ if ((int)m_buffer.size() + http_buffer_size
+ > m_settings.tracker_maximum_response_length)
+ m_buffer.resize(m_settings.tracker_maximum_response_length);
+ else
+ m_buffer.resize(m_buffer.size() + http_buffer_size);
+ }
+
+ if (m_parser.header_finished())
+ {
+ int cl = atoi(m_parser.header("content-length").c_str());
+ if (cl > m_settings.tracker_maximum_response_length)
+ {
+ fail(-1, "content-length is greater than maximum response length");
+ return;
+ }
+
+ if (cl > 0 && cl < minimum_tracker_response_length && m_parser.status_code() == 200)
+ {
+ fail(-1, "content-length is smaller than minimum response length");
+ return;
+ }
+ }
+
+ if (m_parser.finished())
+ {
+ on_response();
+ close();
+ return;
+ }
+
+ TORRENT_ASSERT(m_buffer.size() - m_recv_pos > 0);
+ m_socket.async_read_some(asio::buffer(&m_buffer[m_recv_pos]
+ , m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
+ , self(), _1, _2));
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ };
+
+ void http_tracker_connection::on_response()
+ {
+ if (!m_parser.header_finished())
+ {
+ fail(-1, "premature end of file");
+ return;
+ }
+
+ std::string location = m_parser.header("location");
+
+ boost::shared_ptr<request_callback> cb = requester();
+
+ if (m_parser.status_code() >= 300 && m_parser.status_code() < 400)
+ {
+ if (location.empty())
+ {
+ std::string error_str = "got redirection response (";
+ error_str += boost::lexical_cast<std::string>(m_parser.status_code());
+ error_str += ") without 'Location' header";
+ fail(-1, error_str.c_str());
+ return;
+ }
+
+ // if the protocol isn't specified, assume http
+ if (location.compare(0, 7, "http://") != 0
+ && location.compare(0, 6, "udp://") != 0)
+ {
+ location.insert(0, "http://");
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (cb) cb->debug_log("Redirecting to \"" + location + "\"");
+#endif
+ if (cb) cb->tracker_warning("Redirecting to \"" + location + "\"");
+ tracker_request req = tracker_req();
+
+ req.url = location;
+
+ m_man.queue_request(m_strand, m_cc, req
+ , m_password, bind_interface(), m_requester);
+ close();
+ return;
+ }
+
+ if (m_parser.status_code() != 200)
+ {
+ fail(m_parser.status_code(), m_parser.message().c_str());
+ return;
+ }
+
+ buffer::const_interval buf(&m_buffer[0] + m_parser.body_start(), &m_buffer[0] + m_recv_pos);
+
+ std::string content_encoding = m_parser.header("content-encoding");
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (cb) cb->debug_log("content-encoding: \"" + content_encoding + "\"");
+#endif
+
+ if (content_encoding == "gzip" || content_encoding == "x-gzip")
+ {
+ if (!cb)
+ {
+ close();
+ return;
+ }
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + m_parser.body_start());
+ if (inflate_gzip(m_buffer, tracker_req(), cb.get(),
+ m_settings.tracker_maximum_response_length))
+ {
+ close();
+ return;
+ }
+ buf.begin = &m_buffer[0];
+ buf.end = &m_buffer[0] + m_buffer.size();
+ }
+ else if (!content_encoding.empty())
+ {
+ std::string error_str = "unknown content encoding in response: \"";
+ error_str += content_encoding;
+ error_str += "\"";
+ fail(-1, error_str.c_str());
+ return;
+ }
+
+ // handle tracker response
+ try
+ {
+ entry e = bdecode(buf.begin, buf.end);
+ parse(e);
+ }
+ catch (std::exception& e)
+ {
+ std::string error_str(e.what());
+ error_str += ": \"";
+ for (char const* i = buf.begin, *end(buf.end); i != end; ++i)
+ {
+ if (std::isprint(*i)) error_str += *i;
+ else error_str += "0x" + boost::lexical_cast<std::string>((unsigned int)*i) + " ";
+ }
+ error_str += "\"";
+ fail(m_parser.status_code(), error_str.c_str());
+ }
+ #ifndef NDEBUG
+ catch (...)
+ {
+ TORRENT_ASSERT(false);
+ }
+ #endif
+ close();
+ }
+
+ peer_entry http_tracker_connection::extract_peer_info(const entry& info)
+ {
+ peer_entry ret;
+
+ // extract peer id (if any)
+ entry const* i = info.find_key("peer id");
+ if (i != 0)
+ {
+ if (i->string().length() != 20)
+ throw std::runtime_error("invalid response from tracker");
+ std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
+ }
+ else
+ {
+ // if there's no peer_id, just initialize it to a bunch of zeroes
+ std::fill_n(ret.pid.begin(), 20, 0);
+ }
+
+ // extract ip
+ i = info.find_key("ip");
+ if (i == 0) throw std::runtime_error("invalid response from tracker");
+ ret.ip = i->string();
+
+ // extract port
+ i = info.find_key("port");
+ if (i == 0) throw std::runtime_error("invalid response from tracker");
+ ret.port = (unsigned short)i->integer();
+
+ return ret;
+ }
+
+ void http_tracker_connection::parse(entry const& e)
+ {
+ boost::shared_ptr<request_callback> cb = requester();
+ if (!cb) return;
+
+ try
+ {
+ // parse the response
+ try
+ {
+ entry const& failure = e["failure reason"];
+
+ fail(m_parser.status_code(), failure.string().c_str());
+ return;
+ }
+ catch (type_error const&) {}
+
+ try
+ {
+ entry const& warning = e["warning message"];
+ cb->tracker_warning(warning.string());
+ }
+ catch(type_error const&) {}
+
+ if (tracker_req().kind == tracker_request::scrape_request)
+ {
+ std::string ih;
+ std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
+ , std::back_inserter(ih));
+ entry scrape_data = e["files"][ih];
+
+ int complete = -1;
+ int incomplete = -1;
+ int downloaded = -1;
+
+ entry const* complete_ent = scrape_data.find_key("complete");
+ if (complete_ent && complete_ent->type() == entry::int_t)
+ complete = int(complete_ent->integer());
+
+ entry const* incomplete_ent = scrape_data.find_key("incomplete");
+ if (incomplete_ent && incomplete_ent->type() == entry::int_t)
+ incomplete = int(incomplete_ent->integer());
+
+ entry const* downloaded_ent = scrape_data.find_key("downloaded");
+ if (downloaded_ent && downloaded_ent->type() == entry::int_t)
+ downloaded = int(downloaded_ent->integer());
+
+ cb->tracker_scrape_response(tracker_req(), complete
+ , incomplete, downloaded);
+ return;
+ }
+
+ std::vector<peer_entry> peer_list;
+ int interval = (int)e["interval"].integer();
+
+ if (e["peers"].type() == entry::string_t)
+ {
+ std::string const& peers = e["peers"].string();
+ for (std::string::const_iterator i = peers.begin();
+ i != peers.end();)
+ {
+ if (std::distance(i, peers.end()) < 6) break;
+
+ peer_entry p;
+ p.pid.clear();
+ p.ip = detail::read_v4_address(i).to_string();
+ p.port = detail::read_uint16(i);
+ peer_list.push_back(p);
+ }
+ }
+ else
+ {
+ entry::list_type const& l = e["peers"].list();
+ for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
+ {
+ peer_entry p = extract_peer_info(*i);
+ peer_list.push_back(p);
+ }
+ }
+
+ if (entry const* ipv6_peers = e.find_key("peers6"))
+ {
+ std::string const& peers = ipv6_peers->string();
+ for (std::string::const_iterator i = peers.begin();
+ i != peers.end();)
+ {
+ if (std::distance(i, peers.end()) < 18) break;
+
+ peer_entry p;
+ p.pid.clear();
+ p.ip = detail::read_v6_address(i).to_string();
+ p.port = detail::read_uint16(i);
+ peer_list.push_back(p);
+ }
+ }
+
+ // look for optional scrape info
+ int complete = -1;
+ int incomplete = -1;
+
+ try { complete = int(e["complete"].integer()); }
+ catch(type_error&) {}
+
+ try { incomplete = int(e["incomplete"].integer()); }
+ catch(type_error&) {}
+
+ cb->tracker_response(tracker_req(), peer_list, interval, complete
+ , incomplete);
+ }
+ catch(type_error& e)
+ {
+ cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what());
+ }
+ catch(std::runtime_error& e)
+ {
+ cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what());
+ }
+ }
+
+}
+
diff --git a/src/libtorrent/src/identify_client.cpp b/src/libtorrent/src/identify_client.cpp
new file mode 100644
index 0000000..73221de
--- /dev/null
+++ b/src/libtorrent/src/identify_client.cpp
@@ -0,0 +1,381 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <cctype>
+#include <algorithm>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/optional.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/identify_client.hpp"
+#include "libtorrent/fingerprint.hpp"
+
+namespace
+{
+
+ using namespace libtorrent;
+
+ int decode_digit(char c)
+ {
+ if (std::isdigit(c)) return c - '0';
+ return unsigned(c) - 'A' + 10;
+ }
+
+ // takes a peer id and returns a valid boost::optional
+ // object if the peer id matched the azureus style encoding
+ // the returned fingerprint contains information about the
+ // client's id
+ boost::optional<fingerprint> parse_az_style(const peer_id& id)
+ {
+ fingerprint ret("..", 0, 0, 0, 0);
+
+ if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
+ || (id[3] < '0') || (id[4] < '0')
+ || (id[5] < '0') || (id[6] < '0')
+ || id[7] != '-')
+ return boost::optional<fingerprint>();
+
+ ret.name[0] = id[1];
+ ret.name[1] = id[2];
+ ret.major_version = decode_digit(id[3]);
+ ret.minor_version = decode_digit(id[4]);
+ ret.revision_version = decode_digit(id[5]);
+ ret.tag_version = decode_digit(id[6]);
+
+ return boost::optional<fingerprint>(ret);
+ }
+
+ // checks if a peer id can possibly contain a shadow-style
+ // identification
+ boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
+ {
+ fingerprint ret("..", 0, 0, 0, 0);
+
+ if (!std::isalnum(id[0]))
+ return boost::optional<fingerprint>();
+
+ if (std::equal(id.begin()+4, id.begin()+6, "--"))
+ {
+ if ((id[1] < '0') || (id[2] < '0')
+ || (id[3] < '0'))
+ return boost::optional<fingerprint>();
+ ret.major_version = decode_digit(id[1]);
+ ret.minor_version = decode_digit(id[2]);
+ ret.revision_version = decode_digit(id[3]);
+ }
+ else
+ {
+ if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
+ return boost::optional<fingerprint>();
+ ret.major_version = id[1];
+ ret.minor_version = id[2];
+ ret.revision_version = id[3];
+ }
+
+ ret.name[0] = id[0];
+ ret.name[1] = 0;
+
+ ret.tag_version = 0;
+ return boost::optional<fingerprint>(ret);
+ }
+
+ // checks if a peer id can possibly contain a mainline-style
+ // identification
+ boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
+ {
+ char ids[21];
+ std::copy(id.begin(), id.end(), ids);
+ ids[20] = 0;
+ fingerprint ret("..", 0, 0, 0, 0);
+ ret.name[1] = 0;
+ ret.tag_version = 0;
+ if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
+ , &ret.revision_version) != 4
+ || !std::isprint(ret.name[0]))
+ return boost::optional<fingerprint>();
+
+ return boost::optional<fingerprint>(ret);
+ }
+
+ struct map_entry
+ {
+ char const* id;
+ char const* name;
+ };
+
+ // only support BitTorrentSpecification
+ // must be ordered alphabetically
+ map_entry name_map[] =
+ {
+ {"A", "ABC"}
+ , {"AG", "Ares"}
+ , {"AR", "Arctic Torrent"}
+ , {"AV", "Avicora"}
+ , {"AX", "BitPump"}
+ , {"AZ", "Azureus"}
+ , {"A~", "Ares"}
+ , {"BB", "BitBuddy"}
+ , {"BC", "BitComet"}
+ , {"BF", "Bitflu"}
+ , {"BG", "BTG"}
+ , {"BR", "BitRocket"}
+ , {"BS", "BTSlave"}
+ , {"BX", "BittorrentX"}
+ , {"CD", "Enhanced CTorrent"}
+ , {"CT", "CTorrent"}
+ , {"DE", "Deluge Torrent"}
+ , {"EB", "EBit"}
+ , {"ES", "electric sheep"}
+ , {"HL", "Halite"}
+ , {"HN", "Hydranode"}
+ , {"KT", "KTorrent"}
+ , {"LK", "Linkage"}
+ , {"LP", "lphant"}
+ , {"LT", "libtorrent"}
+ , {"M", "Mainline"}
+ , {"ML", "MLDonkey"}
+ , {"MO", "Mono Torrent"}
+ , {"MP", "MooPolice"}
+ , {"MR", "Miro"}
+ , {"MT", "Moonlight Torrent"}
+ , {"O", "Osprey Permaseed"}
+ , {"PD", "Pando"}
+ , {"Q", "BTQueue"}
+ , {"QT", "Qt 4"}
+ , {"R", "Tribler"}
+ , {"S", "Shadow"}
+ , {"SB", "Swiftbit"}
+ , {"SN", "ShareNet"}
+ , {"SS", "SwarmScope"}
+ , {"ST", "SymTorrent"}
+ , {"SZ", "Shareaza"}
+ , {"S~", "Shareaza (beta)"}
+ , {"T", "BitTornado"}
+ , {"TN", "Torrent.NET"}
+ , {"TR", "Transmission"}
+ , {"TS", "TorrentStorm"}
+ , {"TT", "TuoTu"}
+ , {"U", "UPnP"}
+ , {"UL", "uLeecher"}
+ , {"UT", "uTorrent"}
+ , {"XL", "Xunlei"}
+ , {"XT", "XanTorrent"}
+ , {"XX", "Xtorrent"}
+ , {"ZT", "ZipTorrent"}
+ , {"lt", "rTorrent"}
+ , {"pX", "pHoeniX"}
+ , {"qB", "qBittorrent"}
+ , {"st", "SharkTorrent"}
+ };
+
+ struct generic_map_entry
+ {
+ int offset;
+ char const* id;
+ char const* name;
+ };
+ // non-standard names
+ generic_map_entry generic_mappings[] =
+ {
+ {0, "Deadman Walking-", "Deadman"}
+ , {5, "Azureus", "Azureus 2.0.3.2"}
+ , {0, "DansClient", "XanTorrent"}
+ , {4, "btfans", "SimpleBT"}
+ , {0, "PRC.P---", "Bittorrent Plus! II"}
+ , {0, "P87.P---", "Bittorrent Plus!"}
+ , {0, "S587Plus", "Bittorrent Plus!"}
+ , {0, "martini", "Martini Man"}
+ , {0, "Plus---", "Bittorrent Plus"}
+ , {0, "turbobt", "TurboBT"}
+ , {0, "a00---0", "Swarmy"}
+ , {0, "a02---0", "Swarmy"}
+ , {0, "T00---0", "Teeweety"}
+ , {0, "BTDWV-", "Deadman Walking"}
+ , {2, "BS", "BitSpirit"}
+ , {0, "Pando-", "Pando"}
+ , {0, "LIME", "LimeWire"}
+ , {0, "btuga", "BTugaXP"}
+ , {0, "oernu", "BTugaXP"}
+ , {0, "Mbrst", "Burst!"}
+ , {0, "PEERAPP", "PeerApp"}
+ , {0, "Plus", "Plus!"}
+ , {0, "-Qt-", "Qt"}
+ , {0, "exbc", "BitComet"}
+ , {0, "DNA", "BitTorrent DNA"}
+ , {0, "-G3", "G3 Torrent"}
+ , {0, "-FG", "FlashGet"}
+ , {0, "-ML", "MLdonkey"}
+ , {0, "XBT", "XBT"}
+ , {0, "OP", "Opera"}
+ , {2, "RS", "Rufus"}
+ , {0, "AZ2500BT", "BitTyrant"}
+ };
+
+ bool compare_id(map_entry const& lhs, map_entry const& rhs)
+ {
+ return lhs.id[0] < rhs.id[0]
+ || ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
+ }
+
+ std::string lookup(fingerprint const& f)
+ {
+ std::stringstream identity;
+
+ const int size = sizeof(name_map)/sizeof(name_map[0]);
+ map_entry tmp = {f.name, ""};
+ map_entry* i =
+ std::lower_bound(name_map, name_map + size
+ , tmp, &compare_id);
+
+#ifndef NDEBUG
+ for (int i = 1; i < size; ++i)
+ {
+ TORRENT_ASSERT(compare_id(name_map[i-1]
+ , name_map[i]));
+ }
+#endif
+
+ if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
+ identity << i->name;
+ else
+ {
+ identity << f.name[0];
+ if (f.name[1] != 0) identity << f.name[1];
+ }
+
+ identity << " " << (int)f.major_version
+ << "." << (int)f.minor_version
+ << "." << (int)f.revision_version;
+
+ if (f.name[1] != 0)
+ identity << "." << (int)f.tag_version;
+
+ return identity.str();
+ }
+
+ bool find_string(unsigned char const* id, char const* search)
+ {
+ return std::equal(search, search + std::strlen(search), id);
+ }
+}
+
+namespace libtorrent
+{
+
+ boost::optional<fingerprint> client_fingerprint(peer_id const& p)
+ {
+ // look for azureus style id
+ boost::optional<fingerprint> f;
+ f = parse_az_style(p);
+ if (f) return f;
+
+ // look for shadow style id
+ f = parse_shadow_style(p);
+ if (f) return f;
+
+ // look for mainline style id
+ f = parse_mainline_style(p);
+ if (f) return f;
+ return f;
+ }
+
+ std::string identify_client(peer_id const& p)
+ {
+ peer_id::const_iterator PID = p.begin();
+ boost::optional<fingerprint> f;
+
+ if (p.is_all_zeros()) return "Unknown";
+
+ // ----------------------
+ // non standard encodings
+ // ----------------------
+
+ int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]);
+
+ for (int i = 0; i < num_generic_mappings; ++i)
+ {
+ generic_map_entry const& e = generic_mappings[i];
+ if (find_string(PID + e.offset, e.id)) return e.name;
+ }
+
+ if (find_string(PID, "-BOW") && PID[7] == '-')
+ return "Bits on Wheels " + std::string(PID + 4, PID + 7);
+
+
+ if (find_string(PID, "eX"))
+ {
+ std::string user(PID + 2, PID + 14);
+ return std::string("eXeem ('") + user.c_str() + "')";
+ }
+
+ if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
+ return "Experimental 3.2.1b2";
+
+ if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
+ return "Experimental 3.1";
+
+
+ // look for azureus style id
+ f = parse_az_style(p);
+ if (f) return lookup(*f);
+
+ // look for shadow style id
+ f = parse_shadow_style(p);
+ if (f) return lookup(*f);
+
+ // look for mainline style id
+ f = parse_mainline_style(p);
+ if (f) return lookup(*f);
+
+
+ if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
+ return "Generic";
+
+ std::string unknown("Unknown [");
+ for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
+ {
+ unknown += std::isprint(*i)?*i:'.';
+ }
+ unknown += "]";
+ return unknown;
+ }
+
+}
diff --git a/src/libtorrent/src/instantiate_connection.cpp b/src/libtorrent/src/instantiate_connection.cpp
new file mode 100644
index 0000000..23a202d
--- /dev/null
+++ b/src/libtorrent/src/instantiate_connection.cpp
@@ -0,0 +1,82 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/session_settings.hpp"
+#include "libtorrent/socket_type.hpp"
+#include <boost/shared_ptr.hpp>
+#include <stdexcept>
+#include <asio/io_service.hpp>
+
+namespace libtorrent
+{
+
+ bool instantiate_connection(asio::io_service& ios
+ , proxy_settings const& ps, socket_type& s)
+ {
+ if (ps.type == proxy_settings::none)
+ {
+ s.instantiate<stream_socket>(ios);
+ }
+ else if (ps.type == proxy_settings::http
+ || ps.type == proxy_settings::http_pw)
+ {
+ s.instantiate<http_stream>(ios);
+ s.get<http_stream>().set_proxy(ps.hostname, ps.port);
+ if (ps.type == proxy_settings::http_pw)
+ s.get<http_stream>().set_username(ps.username, ps.password);
+ }
+ else if (ps.type == proxy_settings::socks5
+ || ps.type == proxy_settings::socks5_pw)
+ {
+ s.instantiate<socks5_stream>(ios);
+ s.get<socks5_stream>().set_proxy(ps.hostname, ps.port);
+ if (ps.type == proxy_settings::socks5_pw)
+ s.get<socks5_stream>().set_username(ps.username, ps.password);
+ }
+ else if (ps.type == proxy_settings::socks4)
+ {
+ s.instantiate<socks4_stream>(ios);
+ s.get<socks4_stream>().set_proxy(ps.hostname, ps.port);
+ s.get<socks4_stream>().set_username(ps.username);
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ }
+
+}
+
diff --git a/src/libtorrent/src/ip_filter.cpp b/src/libtorrent/src/ip_filter.cpp
new file mode 100644
index 0000000..eb91de0
--- /dev/null
+++ b/src/libtorrent/src/ip_filter.cpp
@@ -0,0 +1,91 @@
+/*
+
+Copyright (c) 2005, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/ip_filter.hpp"
+#include <boost/utility.hpp>
+//#include <iostream>
+
+
+namespace libtorrent
+{
+ void ip_filter::add_rule(address first, address last, int flags)
+ {
+ if (first.is_v4())
+ {
+ TORRENT_ASSERT(last.is_v4());
+ m_filter4.add_rule(first.to_v4().to_bytes(), last.to_v4().to_bytes(), flags);
+ }
+ else if (first.is_v6())
+ {
+ TORRENT_ASSERT(last.is_v6());
+ m_filter6.add_rule(first.to_v6().to_bytes(), last.to_v6().to_bytes(), flags);
+ }
+ else
+ TORRENT_ASSERT(false);
+ }
+
+ int ip_filter::access(address const& addr) const
+ {
+ if (addr.is_v4())
+ return m_filter4.access(addr.to_v4().to_bytes());
+ TORRENT_ASSERT(addr.is_v6());
+ return m_filter6.access(addr.to_v6().to_bytes());
+ }
+
+ ip_filter::filter_tuple_t ip_filter::export_filter() const
+ {
+ return boost::make_tuple(m_filter4.export_filter<address_v4>()
+ , m_filter6.export_filter<address_v6>());
+ }
+
+ void port_filter::add_rule(boost::uint16_t first, boost::uint16_t last, int flags)
+ {
+ m_filter.add_rule(first, last, flags);
+ }
+
+ int port_filter::access(boost::uint16_t port) const
+ {
+ return m_filter.access(port);
+ }
+/*
+ void ip_filter::print() const
+ {
+ for (range_t::iterator i = m_access_list.begin(); i != m_access_list.end(); ++i)
+ {
+ std::cout << i->start.as_string() << " " << i->access << "\n";
+ }
+ }
+*/
+}
+
diff --git a/src/libtorrent/src/kademlia/closest_nodes.cpp b/src/libtorrent/src/kademlia/closest_nodes.cpp
new file mode 100644
index 0000000..7e24182
--- /dev/null
+++ b/src/libtorrent/src/kademlia/closest_nodes.cpp
@@ -0,0 +1,138 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <libtorrent/kademlia/closest_nodes.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/rpc_manager.hpp>
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent { namespace dht
+{
+
+using asio::ip::udp;
+
+closest_nodes_observer::~closest_nodes_observer()
+{
+ if (m_algorithm) m_algorithm->failed(m_self, true);
+}
+
+void closest_nodes_observer::reply(msg const& in)
+{
+ if (!m_algorithm)
+ {
+ TORRENT_ASSERT(false);
+ return;
+ }
+
+ if (!in.nodes.empty())
+ {
+ for (msg::nodes_t::const_iterator i = in.nodes.begin()
+ , end(in.nodes.end()); i != end; ++i)
+ {
+ m_algorithm->traverse(i->id, i->addr);
+ }
+ }
+ m_algorithm->finished(m_self);
+ m_algorithm = 0;
+}
+
+void closest_nodes_observer::timeout()
+{
+ if (!m_algorithm) return;
+ m_algorithm->failed(m_self);
+ m_algorithm = 0;
+}
+
+
+closest_nodes::closest_nodes(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+)
+ : traversal_algorithm(
+ target
+ , branch_factor
+ , max_results
+ , table
+ , rpc
+ , table.begin()
+ , table.end()
+ )
+ , m_done_callback(callback)
+{
+ boost::intrusive_ptr<closest_nodes> self(this);
+ add_requests();
+}
+
+void closest_nodes::invoke(node_id const& id, udp::endpoint addr)
+{
+ observer_ptr o(new (m_rpc.allocator().malloc()) closest_nodes_observer(this, id, m_target));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+ m_rpc.invoke(messages::find_node, addr, o);
+}
+
+void closest_nodes::done()
+{
+ std::vector<node_entry> results;
+ int num_results = m_max_results;
+ for (std::vector<result>::iterator i = m_results.begin()
+ , end(m_results.end()); i != end && num_results > 0; ++i)
+ {
+ if (i->flags & result::no_id) continue;
+ if ((i->flags & result::queried) == 0) continue;
+ results.push_back(node_entry(i->id, i->addr));
+ --num_results;
+ }
+ m_done_callback(results);
+}
+
+void closest_nodes::initiate(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+)
+{
+ new closest_nodes(target, branch_factor, max_results, table, rpc, callback);
+}
+
+} } // namespace libtorrent::dht
+
diff --git a/src/libtorrent/src/kademlia/dht_tracker.cpp b/src/libtorrent/src/kademlia/dht_tracker.cpp
new file mode 100644
index 0000000..56bc765
--- /dev/null
+++ b/src/libtorrent/src/kademlia/dht_tracker.cpp
@@ -0,0 +1,1041 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <fstream>
+#include <set>
+#include <numeric>
+#include <stdexcept>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <boost/optional.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/operations.hpp>
+
+#include "libtorrent/kademlia/node.hpp"
+#include "libtorrent/kademlia/node_id.hpp"
+#include "libtorrent/kademlia/traversal_algorithm.hpp"
+#include "libtorrent/kademlia/dht_tracker.hpp"
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/version.hpp"
+
+using boost::ref;
+using boost::lexical_cast;
+using libtorrent::dht::node_impl;
+using libtorrent::dht::node_id;
+using libtorrent::dht::packet_t;
+using libtorrent::dht::msg;
+using libtorrent::dht::packet_iterator;
+namespace messages = libtorrent::dht::messages;
+using namespace libtorrent::detail;
+
+enum
+{
+ key_refresh = 5 // generate a new write token key every 5 minutes
+};
+
+using asio::ip::udp;
+typedef asio::ip::address_v4 address;
+
+namespace
+{
+ const int tick_period = 1; // minutes
+
+ struct count_peers
+ {
+ int& count;
+ count_peers(int& c): count(c) {}
+ void operator()(std::pair<libtorrent::dht::node_id
+ , libtorrent::dht::torrent_entry> const& t)
+ {
+ count += std::distance(t.second.peers.begin()
+ , t.second.peers.end());
+ }
+ };
+
+ boost::optional<node_id> read_id(libtorrent::entry const& d)
+ {
+ using namespace libtorrent;
+ using libtorrent::dht::node_id;
+
+ if (d.type() != entry::dictionary_t) return boost::optional<node_id>();
+ entry const* nid = d.find_key("node-id");
+ if (!nid
+ || nid->type() != entry::string_t
+ || nid->string().length() != 40)
+ return boost::optional<node_id>();
+ return boost::optional<node_id>(
+ boost::lexical_cast<node_id>(nid->string()));
+ }
+
+ template <class EndpointType>
+ void read_endpoint_list(libtorrent::entry const* n, std::vector<EndpointType>& epl)
+ {
+ using namespace libtorrent;
+ entry::list_type const& contacts = n->list();
+ for (entry::list_type::const_iterator i = contacts.begin()
+ , end(contacts.end()); i != end; ++i)
+ {
+ std::string const& p = i->string();
+ if (p.size() < 6) continue;
+ std::string::const_iterator in = p.begin();
+ if (p.size() == 6)
+ epl.push_back(read_v4_endpoint<EndpointType>(in));
+ else if (p.size() == 18)
+ epl.push_back(read_v6_endpoint<EndpointType>(in));
+ }
+ }
+
+}
+
+namespace libtorrent { namespace dht
+{
+
+ void intrusive_ptr_add_ref(dht_tracker const* c)
+ {
+ TORRENT_ASSERT(c != 0);
+ TORRENT_ASSERT(c->m_refs >= 0);
+ ++c->m_refs;
+ }
+
+ void intrusive_ptr_release(dht_tracker const* c)
+ {
+ TORRENT_ASSERT(c != 0);
+ TORRENT_ASSERT(c->m_refs > 0);
+ if (--c->m_refs == 0)
+ delete c;
+ }
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_DEFINE_LOG(dht_tracker)
+#endif
+
+ // class that puts the networking and the kademlia node in a single
+ // unit and connecting them together.
+ dht_tracker::dht_tracker(asio::io_service& ios, dht_settings const& settings
+ , asio::ip::address listen_interface, entry const& bootstrap)
+ : m_strand(ios)
+ , m_socket(ios, udp::endpoint(listen_interface, settings.service_port))
+ , m_dht(bind(&dht_tracker::send_packet, this, _1), settings
+ , read_id(bootstrap))
+ , m_buffer(0)
+ , m_last_new_key(time_now() - minutes(key_refresh))
+ , m_timer(ios)
+ , m_connection_timer(ios)
+ , m_refresh_timer(ios)
+ , m_settings(settings)
+ , m_refresh_bucket(160)
+ , m_abort(false)
+ , m_host_resolver(ios)
+ , m_refs(0)
+ {
+ using boost::bind;
+
+ m_in_buf[0].resize(1000);
+ m_in_buf[1].resize(1000);
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ m_counter = 0;
+ std::fill_n(m_replies_bytes_sent, 5, 0);
+ std::fill_n(m_queries_bytes_received, 5, 0);
+ std::fill_n(m_replies_sent, 5, 0);
+ std::fill_n(m_queries_received, 5, 0);
+ m_announces = 0;
+ m_failed_announces = 0;
+ m_total_message_input = 0;
+ m_ut_message_input = 0;
+ m_lt_message_input = 0;
+ m_mp_message_input = 0;
+ m_gr_message_input = 0;
+ m_mo_message_input = 0;
+ m_total_in_bytes = 0;
+ m_total_out_bytes = 0;
+ m_queries_out_bytes = 0;
+
+ // turns on and off individual components' logging
+
+// rpc_log().enable(false);
+// node_log().enable(false);
+// traversal_log().enable(false);
+// dht_tracker_log.enable(false);
+
+#endif
+ std::vector<udp::endpoint> initial_nodes;
+
+ if (bootstrap.type() == entry::dictionary_t)
+ {
+ try
+ {
+ if (entry const* nodes = bootstrap.find_key("nodes"))
+ read_endpoint_list<udp::endpoint>(nodes, initial_nodes);
+ } catch (std::exception&) {}
+ }
+
+ m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0]
+ , m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer]
+ , m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2)));
+ m_timer.expires_from_now(seconds(1));
+ m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, self(), _1)));
+
+ m_connection_timer.expires_from_now(seconds(10));
+ m_connection_timer.async_wait(m_strand.wrap(
+ bind(&dht_tracker::connection_timeout, self(), _1)));
+
+ m_refresh_timer.expires_from_now(seconds(5));
+ m_refresh_timer.async_wait(m_strand.wrap(bind(&dht_tracker::refresh_timeout, self(), _1)));
+
+ m_dht.bootstrap(initial_nodes, bind(&dht_tracker::on_bootstrap, self()));
+ }
+
+ void dht_tracker::stop()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_abort = true;
+ m_timer.cancel();
+ m_connection_timer.cancel();
+ m_refresh_timer.cancel();
+ m_socket.close();
+ m_host_resolver.cancel();
+ }
+
+ void dht_tracker::dht_status(session_status& s)
+ {
+ boost::tie(s.dht_nodes, s.dht_node_cache) = m_dht.size();
+ s.dht_torrents = m_dht.data_size();
+ s.dht_global_nodes = m_dht.num_global_nodes();
+ }
+
+ void dht_tracker::connection_timeout(asio::error_code const& e)
+ try
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (e || m_abort) return;
+
+ if (!m_socket.is_open()) return;
+ time_duration d = m_dht.connection_timeout();
+ m_connection_timer.expires_from_now(d);
+ m_connection_timer.async_wait(m_strand.wrap(bind(&dht_tracker::connection_timeout, self(), _1)));
+ }
+ catch (std::exception& exc)
+ {
+#ifndef NDEBUG
+ std::cerr << "exception-type: " << typeid(exc).name() << std::endl;
+ std::cerr << "what: " << exc.what() << std::endl;
+ TORRENT_ASSERT(false);
+#endif
+ };
+
+ void dht_tracker::refresh_timeout(asio::error_code const& e)
+ try
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (e || m_abort) return;
+
+ if (!m_socket.is_open()) return;
+ time_duration d = m_dht.refresh_timeout();
+ m_refresh_timer.expires_from_now(d);
+ m_refresh_timer.async_wait(m_strand.wrap(
+ bind(&dht_tracker::refresh_timeout, self(), _1)));
+ }
+ catch (std::exception&)
+ {
+ TORRENT_ASSERT(false);
+ };
+
+ void dht_tracker::rebind(asio::ip::address listen_interface, int listen_port)
+ {
+ m_socket.close();
+ udp::endpoint ep(listen_interface, listen_port);
+ m_socket.open(ep.protocol());
+ m_socket.bind(ep);
+ m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0]
+ , m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer]
+ , m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2)));
+ }
+
+ void dht_tracker::tick(asio::error_code const& e)
+ try
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (e || m_abort) return;
+
+ if (!m_socket.is_open()) return;
+ m_timer.expires_from_now(minutes(tick_period));
+ m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, self(), _1)));
+
+ ptime now = time_now();
+ if (now - m_last_new_key > minutes(key_refresh))
+ {
+ m_last_new_key = now;
+ m_dht.new_write_key();
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << time_now_string() << " new write key";
+#endif
+ }
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ static bool first = true;
+ if (first)
+ {
+ boost::filesystem::create_directory("libtorrent_logs");
+ }
+
+ std::ofstream st("libtorrent_logs/routing_table_state.txt", std::ios_base::trunc);
+ m_dht.print_state(st);
+
+ // count torrents
+ int torrents = std::distance(m_dht.begin_data(), m_dht.end_data());
+
+ // count peers
+ int peers = 0;
+ std::for_each(m_dht.begin_data(), m_dht.end_data(), count_peers(peers));
+
+ std::ofstream pc("libtorrent_logs/dht_stats.log", std::ios_base::app);
+ if (first)
+ {
+ first = false;
+ pc << "\n\n ***** starting log at " << time_now_string() << " *****\n\n"
+ << "minute:active nodes:passive nodes"
+ ":ping replies sent:ping queries recvd:ping"
+ ":ping replies sent:ping queries recvd:ping"
+ ":find_node replies bytes sent:find_node queries bytes recv"
+ ":find_node replies bytes sent:find_node queries bytes recv"
+ ":get_peers replies sent:get_peers queries recvd:get_peers"
+ ":get_peers replies bytes sent:get_peers queries bytes recv"
+ ":announce_peer replies sent:announce_peer queries recvd:announce_peer"
+ ":announce_peer replies bytes sent:announce_peer queries bytes recv"
+ ":error replies sent:error queries recvd:error"
+ ":error replies bytes sent:error queries bytes recv"
+ ":num torrents:num peers:announces per min"
+ ":failed announces per min:total msgs per min"
+ ":ut msgs per min:lt msgs per min:mp msgs per min"
+ ":gr msgs per min:bytes in per sec:bytes out per sec"
+ ":queries out bytes per sec\n\n";
+ }
+
+ int active;
+ int passive;
+ boost::tie(active, passive) = m_dht.size();
+ pc << (m_counter * tick_period)
+ << "\t" << active
+ << "\t" << passive;
+ for (int i = 0; i < 5; ++i)
+ pc << "\t" << (m_replies_sent[i] / float(tick_period))
+ << "\t" << (m_queries_received[i] / float(tick_period))
+ << "\t" << (m_replies_bytes_sent[i] / float(tick_period*60))
+ << "\t" << (m_queries_bytes_received[i] / float(tick_period*60));
+
+ pc << "\t" << torrents
+ << "\t" << peers
+ << "\t" << m_announces / float(tick_period)
+ << "\t" << m_failed_announces / float(tick_period)
+ << "\t" << (m_total_message_input / float(tick_period))
+ << "\t" << (m_ut_message_input / float(tick_period))
+ << "\t" << (m_lt_message_input / float(tick_period))
+ << "\t" << (m_mp_message_input / float(tick_period))
+ << "\t" << (m_gr_message_input / float(tick_period))
+ << "\t" << (m_mo_message_input / float(tick_period))
+ << "\t" << (m_total_in_bytes / float(tick_period*60))
+ << "\t" << (m_total_out_bytes / float(tick_period*60))
+ << "\t" << (m_queries_out_bytes / float(tick_period*60))
+ << std::endl;
+ ++m_counter;
+ std::fill_n(m_replies_bytes_sent, 5, 0);
+ std::fill_n(m_queries_bytes_received, 5, 0);
+ std::fill_n(m_replies_sent, 5, 0);
+ std::fill_n(m_queries_received, 5, 0);
+ m_announces = 0;
+ m_failed_announces = 0;
+ m_total_message_input = 0;
+ m_ut_message_input = 0;
+ m_lt_message_input = 0;
+ m_total_in_bytes = 0;
+ m_total_out_bytes = 0;
+ m_queries_out_bytes = 0;
+#endif
+ }
+ catch (std::exception&)
+ {
+ TORRENT_ASSERT(false);
+ };
+
+ void dht_tracker::announce(sha1_hash const& ih, int listen_port
+ , boost::function<void(std::vector<tcp::endpoint> const&
+ , sha1_hash const&)> f)
+ {
+ m_dht.announce(ih, listen_port, f);
+ }
+
+ // translate bittorrent kademlia message into the generice kademlia message
+ // used by the library
+ void dht_tracker::on_receive(asio::error_code const& error, size_t bytes_transferred)
+ try
+ {
+ if (error == asio::error::operation_aborted) return;
+ if (!m_socket.is_open()) return;
+
+ int current_buffer = m_buffer;
+ m_buffer = (m_buffer + 1) & 1;
+ m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0]
+ , m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer]
+ , m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2)));
+
+ if (error) return;
+
+ node_ban_entry* match = 0;
+ node_ban_entry* min = m_ban_nodes;
+ ptime now = time_now();
+ for (node_ban_entry* i = m_ban_nodes; i < m_ban_nodes + num_ban_nodes; ++i)
+ {
+ if (i->src == m_remote_endpoint[current_buffer])
+ {
+ match = i;
+ break;
+ }
+ if (i->count < min->count) min = i;
+ }
+
+ if (match)
+ {
+ ++match->count;
+ if (match->count >= 20)
+ {
+ if (now < match->limit)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ if (match->count == 20)
+ {
+ TORRENT_LOG(dht_tracker) << time_now_string() << " BANNING PEER [ ip: "
+ << m_remote_endpoint[current_buffer] << " | "
+ "time: " << total_seconds((now - match->limit) + seconds(5))
+ << " | count: " << match->count << " ]";
+ }
+#endif
+ // we've received 20 messages in less than 5 seconds from
+ // this node. Ignore it until it's silent for 5 minutes
+ match->limit = now + minutes(5);
+ return;
+ }
+
+ // we got 50 messages from this peer, but it was in
+ // more than 5 seconds. Reset the counter and the timer
+ match->count = 0;
+ match->limit = now + seconds(5);
+ }
+ }
+ else
+ {
+ min->count = 1;
+ min->limit = now + seconds(5);
+ min->src = m_remote_endpoint[current_buffer];
+ }
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ ++m_total_message_input;
+ m_total_in_bytes += bytes_transferred;
+#endif
+
+ try
+ {
+ using libtorrent::entry;
+ using libtorrent::bdecode;
+
+ TORRENT_ASSERT(bytes_transferred > 0);
+
+ entry e = bdecode(m_in_buf[current_buffer].begin()
+ , m_in_buf[current_buffer].end());
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << time_now_string() << " RECEIVED ["
+ << m_remote_endpoint[current_buffer] << "]:";
+#endif
+
+ libtorrent::dht::msg m;
+ m.message_id = 0;
+ m.addr = m_remote_endpoint[current_buffer];
+ m.transaction_id = e["t"].string();
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ try
+ {
+ entry const* ver = e.find_key("v");
+ if (!ver) throw std::exception();
+
+ std::string const& client = ver->string();
+ if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "UT"))
+ {
+ ++m_ut_message_input;
+ TORRENT_LOG(dht_tracker) << " client: uTorrent";
+ }
+ else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "LT"))
+ {
+ ++m_lt_message_input;
+ TORRENT_LOG(dht_tracker) << " client: libtorrent";
+ }
+ else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MP"))
+ {
+ ++m_mp_message_input;
+ TORRENT_LOG(dht_tracker) << " client: MooPolice";
+ }
+ else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "GR"))
+ {
+ ++m_gr_message_input;
+ TORRENT_LOG(dht_tracker) << " client: GetRight";
+ }
+ else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MO"))
+ {
+ ++m_mo_message_input;
+ TORRENT_LOG(dht_tracker) << " client: Mono Torrent";
+ }
+ else
+ {
+ TORRENT_LOG(dht_tracker) << " client: " << client;
+ }
+ }
+ catch (std::exception&)
+ {
+ TORRENT_LOG(dht_tracker) << " client: generic";
+ };
+#endif
+
+ std::string const& msg_type = e["y"].string();
+
+ if (msg_type == "r")
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " reply: transaction: "
+ << m.transaction_id;
+#endif
+
+ m.reply = true;
+ entry const& r = e["r"];
+ std::string const& id = r["id"].string();
+ if (id.size() != 20) throw std::runtime_error("invalid size of id");
+ std::copy(id.begin(), id.end(), m.id.begin());
+
+ if (entry const* n = r.find_key("values"))
+ {
+ m.peers.clear();
+ if (n->list().size() == 1)
+ {
+ // assume it's mainline format
+ std::string const& peers = n->list().front().string();
+ std::string::const_iterator i = peers.begin();
+ std::string::const_iterator end = peers.end();
+
+ while (std::distance(i, end) >= 6)
+ m.peers.push_back(read_v4_endpoint<tcp::endpoint>(i));
+ }
+ else
+ {
+ // assume it's uTorrent/libtorrent format
+ read_endpoint_list<tcp::endpoint>(n, m.peers);
+ }
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size();
+#endif
+ }
+
+ m.nodes.clear();
+ if (entry const* n = r.find_key("nodes"))
+ {
+ std::string const& nodes = n->string();
+ std::string::const_iterator i = nodes.begin();
+ std::string::const_iterator end = nodes.end();
+
+ while (std::distance(i, end) >= 26)
+ {
+ node_id id;
+ std::copy(i, i + 20, id.begin());
+ i += 20;
+ m.nodes.push_back(libtorrent::dht::node_entry(
+ id, read_v4_endpoint<udp::endpoint>(i)));
+ }
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
+#endif
+ }
+
+ if (entry const* n = r.find_key("nodes2"))
+ {
+ entry::list_type const& contacts = n->list();
+ for (entry::list_type::const_iterator i = contacts.begin()
+ , end(contacts.end()); i != end; ++i)
+ {
+ std::string const& p = i->string();
+ if (p.size() < 6 + 20) continue;
+ std::string::const_iterator in = p.begin();
+
+ node_id id;
+ std::copy(in, in + 20, id.begin());
+ in += 20;
+ if (p.size() == 6 + 20)
+ m.nodes.push_back(libtorrent::dht::node_entry(
+ id, read_v4_endpoint<udp::endpoint>(in)));
+ else if (p.size() == 18 + 20)
+ m.nodes.push_back(libtorrent::dht::node_entry(
+ id, read_v6_endpoint<udp::endpoint>(in)));
+ }
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " nodes2 + nodes: " << m.nodes.size();
+#endif
+ }
+
+ entry const* token = r.find_key("token");
+ if (token) m.write_token = *token;
+ }
+ else if (msg_type == "q")
+ {
+ m.reply = false;
+ entry const& a = e["a"];
+ std::string const& id = a["id"].string();
+ if (id.size() != 20) throw std::runtime_error("invalid size of id");
+ std::copy(id.begin(), id.end(), m.id.begin());
+
+ std::string request_kind(e["q"].string());
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " query: " << request_kind;
+#endif
+
+ if (request_kind == "ping")
+ {
+ m.message_id = libtorrent::dht::messages::ping;
+ }
+ else if (request_kind == "find_node")
+ {
+ std::string const& target = a["target"].string();
+ if (target.size() != 20) throw std::runtime_error("invalid size of target id");
+ std::copy(target.begin(), target.end(), m.info_hash.begin());
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " target: "
+ << boost::lexical_cast<std::string>(m.info_hash);
+#endif
+
+ m.message_id = libtorrent::dht::messages::find_node;
+ }
+ else if (request_kind == "get_peers")
+ {
+ std::string const& info_hash = a["info_hash"].string();
+ if (info_hash.size() != 20) throw std::runtime_error("invalid size of info-hash");
+ std::copy(info_hash.begin(), info_hash.end(), m.info_hash.begin());
+ m.message_id = libtorrent::dht::messages::get_peers;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " info_hash: "
+ << boost::lexical_cast<std::string>(m.info_hash);
+#endif
+ }
+ else if (request_kind == "announce_peer")
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ ++m_announces;
+#endif
+ std::string const& info_hash = a["info_hash"].string();
+ if (info_hash.size() != 20)
+ throw std::runtime_error("invalid size of info-hash");
+ std::copy(info_hash.begin(), info_hash.end(), m.info_hash.begin());
+ m.port = a["port"].integer();
+ m.write_token = a["token"];
+ m.message_id = libtorrent::dht::messages::announce_peer;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " info_hash: "
+ << boost::lexical_cast<std::string>(m.info_hash);
+ TORRENT_LOG(dht_tracker) << " port: " << m.port;
+
+ if (!m_dht.verify_token(m))
+ ++m_failed_announces;
+#endif
+ }
+ else
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " *** UNSUPPORTED REQUEST *** : "
+ << request_kind;
+#endif
+ throw std::runtime_error("unsupported request: " + request_kind);
+ }
+ }
+ else if (msg_type == "e")
+ {
+ entry::list_type const& list = e["e"].list();
+ m.message_id = messages::error;
+ m.error_msg = list.back().string();
+ m.error_code = list.front().integer();
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " incoming error: " << m.error_code << " "
+ << m.error_msg;
+#endif
+ throw std::runtime_error("DHT error message");
+ }
+ else
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " *** UNSUPPORTED MESSAGE TYPE *** : "
+ << msg_type;
+#endif
+ throw std::runtime_error("unsupported message type: " + msg_type);
+ }
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ if (!m.reply)
+ {
+ ++m_queries_received[m.message_id];
+ m_queries_bytes_received[m.message_id] += int(bytes_transferred);
+ }
+ TORRENT_LOG(dht_tracker) << e;
+#endif
+ TORRENT_ASSERT(m.message_id != messages::error);
+ m_dht.incoming(m);
+ }
+ catch (std::exception& e)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ int current_buffer = (m_buffer + 1) & 1;
+ std::string msg(m_in_buf[current_buffer].begin()
+ , m_in_buf[current_buffer].begin() + bytes_transferred);
+ TORRENT_LOG(dht_tracker) << "invalid incoming packet: "
+ << e.what() << "\n" << msg << "\n";
+#endif
+ }
+ }
+ catch (std::exception& e)
+ {
+ TORRENT_ASSERT(false);
+ };
+
+ entry dht_tracker::state() const
+ {
+ entry ret(entry::dictionary_t);
+ {
+ entry nodes(entry::list_t);
+ for (node_impl::iterator i(m_dht.begin())
+ , end(m_dht.end()); i != end; ++i)
+ {
+ std::string node;
+ std::back_insert_iterator<std::string> out(node);
+ write_endpoint(i->addr, out);
+ nodes.list().push_back(entry(node));
+ }
+ bucket_t cache;
+ m_dht.replacement_cache(cache);
+ for (bucket_t::iterator i(cache.begin())
+ , end(cache.end()); i != end; ++i)
+ {
+ std::string node;
+ std::back_insert_iterator<std::string> out(node);
+ write_endpoint(i->addr, out);
+ nodes.list().push_back(entry(node));
+ }
+ if (!nodes.list().empty())
+ ret["nodes"] = nodes;
+ }
+
+ ret["node-id"] = boost::lexical_cast<std::string>(m_dht.nid());
+ return ret;
+ }
+
+ void dht_tracker::add_node(udp::endpoint node)
+ {
+ m_dht.add_node(node);
+ }
+
+ void dht_tracker::add_node(std::pair<std::string, int> const& node)
+ {
+ udp::resolver::query q(node.first, lexical_cast<std::string>(node.second));
+ m_host_resolver.async_resolve(q, m_strand.wrap(
+ bind(&dht_tracker::on_name_lookup, self(), _1, _2)));
+ }
+
+ void dht_tracker::on_name_lookup(asio::error_code const& e
+ , udp::resolver::iterator host) try
+ {
+ if (e || host == udp::resolver::iterator()) return;
+ if (!m_socket.is_open()) return;
+ add_node(host->endpoint());
+ }
+ catch (std::exception&)
+ {
+ TORRENT_ASSERT(false);
+ };
+
+ void dht_tracker::add_router_node(std::pair<std::string, int> const& node)
+ {
+ udp::resolver::query q(node.first, lexical_cast<std::string>(node.second));
+ m_host_resolver.async_resolve(q, m_strand.wrap(
+ bind(&dht_tracker::on_router_name_lookup, self(), _1, _2)));
+ }
+
+ void dht_tracker::on_router_name_lookup(asio::error_code const& e
+ , udp::resolver::iterator host) try
+ {
+ if (e || host == udp::resolver::iterator()) return;
+ if (!m_socket.is_open()) return;
+ m_dht.add_router_node(host->endpoint());
+ }
+ catch (std::exception&)
+ {
+ TORRENT_ASSERT(false);
+ };
+
+ void dht_tracker::on_bootstrap()
+ {}
+
+ namespace
+ {
+ void write_nodes_entry(entry& r, libtorrent::dht::msg const& m)
+ {
+ bool ipv6_nodes = false;
+ r["nodes"] = entry(entry::string_t);
+ entry& n = r["nodes"];
+ std::back_insert_iterator<std::string> out(n.string());
+ for (msg::nodes_t::const_iterator i = m.nodes.begin()
+ , end(m.nodes.end()); i != end; ++i)
+ {
+ if (!i->addr.address().is_v4())
+ {
+ ipv6_nodes = true;
+ continue;
+ }
+ std::copy(i->id.begin(), i->id.end(), out);
+ write_endpoint(i->addr, out);
+ }
+
+ if (ipv6_nodes)
+ {
+ r["nodes2"] = entry(entry::list_t);
+ entry& p = r["nodes2"];
+ std::string endpoint;
+ for (msg::nodes_t::const_iterator i = m.nodes.begin()
+ , end(m.nodes.end()); i != end; ++i)
+ {
+ if (!i->addr.address().is_v6()) continue;
+ endpoint.resize(18 + 20);
+ std::string::iterator out = endpoint.begin();
+ std::copy(i->id.begin(), i->id.end(), out);
+ out += 20;
+ write_endpoint(i->addr, out);
+ endpoint.resize(out - endpoint.begin());
+ p.list().push_back(entry(endpoint));
+ }
+ }
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
+#endif
+ }
+ }
+
+ void dht_tracker::send_packet(msg const& m)
+ try
+ {
+ using libtorrent::bencode;
+ using libtorrent::entry;
+ entry e(entry::dictionary_t);
+ TORRENT_ASSERT(!m.transaction_id.empty() || m.message_id == messages::error);
+ e["t"] = m.transaction_id;
+ static char const version_str[] = {'L', 'T'
+ , LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR};
+ e["v"] = std::string(version_str, version_str + 4);
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << time_now_string()
+ << " SENDING [" << m.addr << "]:";
+ TORRENT_LOG(dht_tracker) << " transaction: " << m.transaction_id;
+#endif
+
+ if (m.message_id == messages::error)
+ {
+ TORRENT_ASSERT(m.reply);
+ e["y"] = "e";
+ entry error_list(entry::list_t);
+ TORRENT_ASSERT(m.error_code > 200 && m.error_code <= 204);
+ error_list.list().push_back(entry(m.error_code));
+ error_list.list().push_back(entry(m.error_msg));
+ e["e"] = error_list;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << time_now_string()
+ << " outgoing error: " << m.error_code << " " << m.error_msg;
+#endif
+ }
+ else if (m.reply)
+ {
+ e["y"] = "r";
+ e["r"] = entry(entry::dictionary_t);
+ entry& r = e["r"];
+ r["id"] = std::string(m.id.begin(), m.id.end());
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << time_now_string()
+ << " reply: " << messages::ids[m.message_id];
+#endif
+
+ if (m.write_token.type() != entry::undefined_t)
+ r["token"] = m.write_token;
+
+ switch (m.message_id)
+ {
+ case messages::ping:
+ break;
+ case messages::find_node:
+ {
+ write_nodes_entry(r, m);
+ break;
+ }
+ case messages::get_peers:
+ {
+ if (m.peers.empty())
+ {
+ write_nodes_entry(r, m);
+ }
+ else
+ {
+ r["values"] = entry(entry::list_t);
+ entry& p = r["values"];
+ std::string endpoint;
+ for (msg::peers_t::const_iterator i = m.peers.begin()
+ , end(m.peers.end()); i != end; ++i)
+ {
+ endpoint.resize(18);
+ std::string::iterator out = endpoint.begin();
+ write_endpoint(*i, out);
+ endpoint.resize(out - endpoint.begin());
+ p.list().push_back(entry(endpoint));
+ }
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size();
+#endif
+ }
+ break;
+ }
+
+ case messages::announce_peer:
+ break;
+ break;
+ }
+ }
+ else
+ {
+ e["y"] = "q";
+ e["a"] = entry(entry::dictionary_t);
+ entry& a = e["a"];
+ a["id"] = std::string(m.id.begin(), m.id.end());
+
+ if (m.write_token.type() != entry::undefined_t)
+ a["token"] = m.write_token;
+ TORRENT_ASSERT(m.message_id <= messages::error);
+ e["q"] = messages::ids[m.message_id];
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " query: "
+ << messages::ids[m.message_id];
+#endif
+
+ switch (m.message_id)
+ {
+ case messages::find_node:
+ {
+ a["target"] = std::string(m.info_hash.begin(), m.info_hash.end());
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " target: "
+ << boost::lexical_cast<std::string>(m.info_hash);
+#endif
+ break;
+ }
+ case messages::get_peers:
+ {
+ a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end());
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker) << " info_hash: "
+ << boost::lexical_cast<std::string>(m.info_hash);
+#endif
+ break;
+ }
+ case messages::announce_peer:
+ a["port"] = m.port;
+ a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end());
+ a["token"] = m.write_token;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(dht_tracker)
+ << " port: " << m.port
+ << " info_hash: " << boost::lexical_cast<std::string>(m.info_hash);
+#endif
+ break;
+ default: break;
+ }
+
+ }
+
+ m_send_buf.clear();
+ bencode(std::back_inserter(m_send_buf), e);
+ asio::error_code ec;
+ m_socket.send_to(asio::buffer(&m_send_buf[0]
+ , (int)m_send_buf.size()), m.addr, 0, ec);
+ if (ec) return;
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ m_total_out_bytes += m_send_buf.size();
+
+ if (m.reply)
+ {
+ ++m_replies_sent[m.message_id];
+ m_replies_bytes_sent[m.message_id] += int(m_send_buf.size());
+ }
+ else
+ {
+ m_queries_out_bytes += m_send_buf.size();
+ }
+ TORRENT_LOG(dht_tracker) << e;
+#endif
+
+ if (!m.piggy_backed_ping) return;
+
+ msg pm;
+ pm.reply = false;
+ pm.piggy_backed_ping = false;
+ pm.message_id = messages::ping;
+ pm.transaction_id = m.ping_transaction_id;
+ pm.id = m.id;
+ pm.addr = m.addr;
+
+ send_packet(pm);
+ }
+ catch (std::exception&)
+ {
+ // m_send may fail with "no route to host"
+ // but it shouldn't throw since an error code
+ // is passed in instead
+ TORRENT_ASSERT(false);
+ }
+
+}}
+
diff --git a/src/libtorrent/src/kademlia/find_data.cpp b/src/libtorrent/src/kademlia/find_data.cpp
new file mode 100644
index 0000000..9dc1618
--- /dev/null
+++ b/src/libtorrent/src/kademlia/find_data.cpp
@@ -0,0 +1,145 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <libtorrent/kademlia/find_data.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/rpc_manager.hpp>
+#include <libtorrent/io.hpp>
+
+namespace libtorrent { namespace dht
+{
+
+find_data_observer::~find_data_observer()
+{
+ if (m_algorithm) m_algorithm->failed(m_self);
+}
+
+void find_data_observer::reply(msg const& m)
+{
+ if (!m_algorithm)
+ {
+ TORRENT_ASSERT(false);
+ return;
+ }
+
+ if (!m.peers.empty())
+ {
+ m_algorithm->got_data(&m);
+ }
+ else
+ {
+ for (msg::nodes_t::const_iterator i = m.nodes.begin()
+ , end(m.nodes.end()); i != end; ++i)
+ {
+ m_algorithm->traverse(i->id, i->addr);
+ }
+ }
+ m_algorithm->finished(m_self);
+ m_algorithm = 0;
+}
+
+void find_data_observer::timeout()
+{
+ if (!m_algorithm) return;
+ m_algorithm->failed(m_self);
+ m_algorithm = 0;
+}
+
+
+find_data::find_data(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+)
+ : traversal_algorithm(
+ target
+ , branch_factor
+ , max_results
+ , table
+ , rpc
+ , table.begin()
+ , table.end()
+ )
+ , m_done_callback(callback)
+ , m_done(false)
+{
+ boost::intrusive_ptr<find_data> self(this);
+ add_requests();
+}
+
+void find_data::invoke(node_id const& id, asio::ip::udp::endpoint addr)
+{
+ if (m_done)
+ {
+ m_invoke_count = -1;
+ return;
+ }
+
+ observer_ptr o(new (m_rpc.allocator().malloc()) find_data_observer(this, id, m_target));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+ m_rpc.invoke(messages::get_peers, addr, o);
+}
+
+void find_data::got_data(msg const* m)
+{
+ m_done = true;
+ m_done_callback(m);
+}
+
+void find_data::done()
+{
+ if (m_invoke_count != 0) return;
+ if (!m_done) m_done_callback(0);
+}
+
+void find_data::initiate(
+ node_id target
+ , int branch_factor
+ , int max_results
+ , routing_table& table
+ , rpc_manager& rpc
+ , done_callback const& callback
+)
+{
+ std::cerr << "find_data::initiate, key: " << target << "\n";
+ new find_data(target, branch_factor, max_results, table, rpc, callback);
+}
+
+} } // namespace libtorrent::dht
+
diff --git a/src/libtorrent/src/kademlia/node.cpp b/src/libtorrent/src/kademlia/node.cpp
new file mode 100644
index 0000000..60dfa2d
--- /dev/null
+++ b/src/libtorrent/src/kademlia/node.cpp
@@ -0,0 +1,505 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <utility>
+#include <boost/bind.hpp>
+#include <boost/optional.hpp>
+#include <boost/function.hpp>
+#include <boost/iterator_adaptors.hpp>
+
+#include "libtorrent/io.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/random_sample.hpp"
+#include "libtorrent/kademlia/node_id.hpp"
+#include "libtorrent/kademlia/rpc_manager.hpp"
+#include "libtorrent/kademlia/packet_iterator.hpp"
+#include "libtorrent/kademlia/routing_table.hpp"
+#include "libtorrent/kademlia/node.hpp"
+
+#include "libtorrent/kademlia/refresh.hpp"
+#include "libtorrent/kademlia/closest_nodes.hpp"
+#include "libtorrent/kademlia/find_data.hpp"
+
+using boost::bind;
+
+namespace libtorrent { namespace dht
+{
+
+#ifdef _MSC_VER
+namespace
+{
+ char rand() { return (char)std::rand(); }
+}
+#endif
+
+// TODO: configurable?
+enum { announce_interval = 30 };
+
+using asio::ip::udp;
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DEFINE_LOG(node)
+#endif
+
+// remove peers that have timed out
+void purge_peers(std::set<peer_entry>& peers)
+{
+ for (std::set<peer_entry>::iterator i = peers.begin()
+ , end(peers.end()); i != end;)
+ {
+ // the peer has timed out
+ if (i->added + minutes(int(announce_interval * 1.5f)) < time_now())
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "peer timed out at: " << i->addr.address();
+#endif
+ peers.erase(i++);
+ }
+ else
+ ++i;
+ }
+}
+
+void nop() {}
+
+node_impl::node_impl(boost::function<void(msg const&)> const& f
+ , dht_settings const& settings, boost::optional<node_id> node_id)
+ : m_settings(settings)
+ , m_id(node_id ? *node_id : generate_id())
+ , m_table(m_id, 8, settings)
+ , m_rpc(bind(&node_impl::incoming_request, this, _1)
+ , m_id, m_table, f)
+ , m_last_tracker_tick(time_now())
+{
+ m_secret[0] = std::rand();
+ m_secret[1] = std::rand();
+}
+
+bool node_impl::verify_token(msg const& m)
+{
+ if (m.write_token.type() != entry::string_t)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "token of incorrect type " << m.write_token.type();
+#endif
+ return false;
+ }
+ std::string const& token = m.write_token.string();
+ if (token.length() != 4)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "token of incorrect length: " << token.length();
+#endif
+ return false;
+ }
+
+ hasher h1;
+ std::string address = m.addr.address().to_string();
+ h1.update(&address[0], address.length());
+ h1.update((char*)&m_secret[0], sizeof(m_secret[0]));
+ h1.update((char*)&m.info_hash[0], sha1_hash::size);
+
+ sha1_hash h = h1.final();
+ if (std::equal(token.begin(), token.end(), (signed char*)&h[0]))
+ return true;
+
+ hasher h2;
+ h2.update(&address[0], address.length());
+ h2.update((char*)&m_secret[1], sizeof(m_secret[1]));
+ h2.update((char*)&m.info_hash[0], sha1_hash::size);
+ h = h2.final();
+ if (std::equal(token.begin(), token.end(), (signed char*)&h[0]))
+ return true;
+ return false;
+}
+
+entry node_impl::generate_token(msg const& m)
+{
+ std::string token;
+ token.resize(4);
+ hasher h;
+ std::string address = m.addr.address().to_string();
+ h.update(&address[0], address.length());
+ h.update((char*)&m_secret[0], sizeof(m_secret[0]));
+ h.update((char*)&m.info_hash[0], sha1_hash::size);
+
+ sha1_hash hash = h.final();
+ std::copy(hash.begin(), hash.begin() + 4, (signed char*)&token[0]);
+ return entry(token);
+}
+
+void node_impl::refresh(node_id const& id
+ , boost::function0<void> f)
+{
+ // use the 'bucket size' closest nodes
+ // to start the refresh with
+ std::vector<node_entry> start;
+ start.reserve(m_table.bucket_size());
+ m_table.find_node(id, start, false);
+ refresh::initiate(id, m_settings.search_branching, 10, m_table.bucket_size()
+ , m_table, start.begin(), start.end(), m_rpc, f);
+}
+
+void node_impl::bootstrap(std::vector<udp::endpoint> const& nodes
+ , boost::function0<void> f)
+{
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "bootrapping: " << nodes.size();
+ for (std::vector<udp::endpoint>::const_iterator i = nodes.begin()
+ , end(nodes.end()); i != end; ++i)
+ TORRENT_LOG(node) << " " << *i;
+#endif
+ std::vector<node_entry> start;
+ start.reserve(nodes.size());
+ std::copy(nodes.begin(), nodes.end(), std::back_inserter(start));
+ refresh::initiate(m_id, m_settings.search_branching, 10, m_table.bucket_size()
+ , m_table, start.begin(), start.end(), m_rpc, f);
+}
+
+void node_impl::refresh()
+{
+ std::vector<node_entry> start;
+ start.reserve(m_table.size().get<0>());
+ std::copy(m_table.begin(), m_table.end(), std::back_inserter(start));
+
+ refresh::initiate(m_id, m_settings.search_branching, 10, m_table.bucket_size()
+ , m_table, start.begin(), start.end(), m_rpc, bind(&nop));
+}
+
+int node_impl::bucket_size(int bucket)
+{
+ return m_table.bucket_size(bucket);
+}
+
+void node_impl::new_write_key()
+{
+ m_secret[1] = m_secret[0];
+ m_secret[0] = std::rand();
+}
+
+void node_impl::refresh_bucket(int bucket) try
+{
+ TORRENT_ASSERT(bucket >= 0 && bucket < 160);
+
+ // generate a random node_id within the given bucket
+ node_id target = generate_id();
+ int num_bits = 160 - bucket;
+ node_id mask(0);
+ for (int i = 0; i < num_bits; ++i)
+ {
+ int byte = i / 8;
+ mask[byte] |= 0x80 >> (i % 8);
+ }
+
+ node_id root = m_id;
+ root &= mask;
+ target &= ~mask;
+ target |= root;
+
+ // make sure this is in another subtree than m_id
+ // clear the (num_bits - 1) bit and then set it to the
+ // inverse of m_id's corresponding bit.
+ target[(num_bits - 1) / 8] &= ~(0x80 >> ((num_bits - 1) % 8));
+ target[(num_bits - 1) / 8] |=
+ (~(m_id[(num_bits - 1) / 8])) & (0x80 >> ((num_bits - 1) % 8));
+
+ TORRENT_ASSERT(distance_exp(m_id, target) == bucket);
+
+ std::vector<node_entry> start;
+ start.reserve(m_table.bucket_size());
+ m_table.find_node(target, start, false, m_table.bucket_size());
+
+ refresh::initiate(target, m_settings.search_branching, 10, m_table.bucket_size()
+ , m_table, start.begin(), start.end(), m_rpc, bind(&nop));
+ m_table.touch_bucket(bucket);
+}
+catch (std::exception&) {}
+
+void node_impl::incoming(msg const& m)
+{
+ if (m_rpc.incoming(m))
+ {
+ refresh();
+ }
+}
+
+namespace
+{
+ void announce_fun(std::vector<node_entry> const& v, rpc_manager& rpc
+ , int listen_port, sha1_hash const& ih
+ , boost::function<void(std::vector<tcp::endpoint> const&, sha1_hash const&)> f)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "announce response [ ih: " << ih
+ << " p: " << listen_port
+ << " nodes: " << v.size() << " ]" ;
+#endif
+ bool nodes = false;
+ // only store on the first k nodes
+ for (std::vector<node_entry>::const_iterator i = v.begin()
+ , end(v.end()); i != end; ++i)
+ {
+ observer_ptr o(new (rpc.allocator().malloc()) get_peers_observer(ih, listen_port, rpc, f));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+ rpc.invoke(messages::get_peers, i->addr, o);
+ nodes = true;
+ }
+ }
+}
+
+void node_impl::add_router_node(udp::endpoint router)
+{
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "adding router node: " << router;
+#endif
+ m_table.add_router_node(router);
+}
+
+void node_impl::add_node(udp::endpoint node)
+{
+ // ping the node, and if we get a reply, it
+ // will be added to the routing table
+ observer_ptr o(new (m_rpc.allocator().malloc()) null_observer(m_rpc.allocator()));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+ m_rpc.invoke(messages::ping, node, o);
+}
+
+void node_impl::announce(sha1_hash const& info_hash, int listen_port
+ , boost::function<void(std::vector<tcp::endpoint> const&, sha1_hash const&)> f)
+{
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "announcing [ ih: " << info_hash << " p: " << listen_port << " ]" ;
+#endif
+ // search for nodes with ids close to id, and then invoke the
+ // get_peers and then announce_peer rpc on them.
+ closest_nodes::initiate(info_hash, m_settings.search_branching
+ , m_table.bucket_size(), m_table, m_rpc
+ , boost::bind(&announce_fun, _1, boost::ref(m_rpc), listen_port
+ , info_hash, f));
+}
+
+time_duration node_impl::refresh_timeout()
+{
+ int refresh = -1;
+ ptime now = time_now();
+ ptime next = now + minutes(15);
+ try
+ {
+ for (int i = 0; i < 160; ++i)
+ {
+ ptime r = m_table.next_refresh(i);
+ if (r <= next)
+ {
+ refresh = i;
+ next = r;
+ }
+ }
+ if (next < now)
+ {
+ TORRENT_ASSERT(refresh > -1);
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "refreshing bucket: " << refresh;
+#endif
+ refresh_bucket(refresh);
+ }
+ }
+ catch (std::exception&) {}
+
+ time_duration next_refresh = next - now;
+ time_duration min_next_refresh
+ = minutes(15) / (m_table.num_active_buckets());
+ if (min_next_refresh > seconds(40))
+ min_next_refresh = seconds(40);
+
+ if (next_refresh < min_next_refresh)
+ next_refresh = min_next_refresh;
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(node) << "next refresh: " << total_seconds(next_refresh) << " seconds";
+#endif
+
+ return next_refresh;
+}
+
+time_duration node_impl::connection_timeout()
+{
+ time_duration d = m_rpc.tick();
+ try
+ {
+ ptime now(time_now());
+ if (now - m_last_tracker_tick < minutes(10)) return d;
+ m_last_tracker_tick = now;
+
+ // look through all peers and see if any have timed out
+ for (data_iterator i = begin_data(), end(end_data()); i != end;)
+ {
+ torrent_entry& t = i->second;
+ node_id const& key = i->first;
+ ++i;
+ purge_peers(t.peers);
+
+ // if there are no more peers, remove the entry altogether
+ if (t.peers.empty())
+ {
+ table_t::iterator i = m_map.find(key);
+ if (i != m_map.end()) m_map.erase(i);
+ }
+ }
+ }
+ catch (std::exception&) {}
+
+ return d;
+}
+
+void node_impl::on_announce(msg const& m, msg& reply)
+{
+ if (!verify_token(m))
+ {
+ reply.message_id = messages::error;
+ reply.error_code = 203;
+ reply.error_msg = "Incorrect token in announce_peer";
+ return;
+ }
+
+ // the token was correct. That means this
+ // node is not spoofing its address. So, let
+ // the table get a chance to add it.
+ m_table.node_seen(m.id, m.addr);
+
+ torrent_entry& v = m_map[m.info_hash];
+ peer_entry e;
+ e.addr = tcp::endpoint(m.addr.address(), m.addr.port());
+ e.added = time_now();
+ std::set<peer_entry>::iterator i = v.peers.find(e);
+ if (i != v.peers.end()) v.peers.erase(i++);
+ v.peers.insert(i, e);
+}
+
+namespace
+{
+ tcp::endpoint get_endpoint(peer_entry const& p)
+ {
+ return p.addr;
+ }
+}
+
+bool node_impl::on_find(msg const& m, std::vector<tcp::endpoint>& peers) const
+{
+ table_t::const_iterator i = m_map.find(m.info_hash);
+ if (i == m_map.end()) return false;
+
+ torrent_entry const& v = i->second;
+
+ int num = (std::min)((int)v.peers.size(), m_settings.max_peers_reply);
+ peers.clear();
+ peers.reserve(num);
+ random_sample_n(boost::make_transform_iterator(v.peers.begin(), &get_endpoint)
+ , boost::make_transform_iterator(v.peers.end(), &get_endpoint)
+ , std::back_inserter(peers), num);
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ for (std::vector<tcp::endpoint>::iterator i = peers.begin()
+ , end(peers.end()); i != end; ++i)
+ {
+ TORRENT_LOG(node) << " " << *i;
+ }
+#endif
+ return true;
+}
+
+void node_impl::incoming_request(msg const& m)
+{
+ msg reply;
+ reply.message_id = m.message_id;
+ reply.addr = m.addr;
+ reply.reply = true;
+ reply.transaction_id = m.transaction_id;
+
+ switch (m.message_id)
+ {
+ case messages::ping:
+ break;
+ case messages::get_peers:
+ {
+ reply.info_hash = m.info_hash;
+ reply.write_token = generate_token(m);
+
+ if (!on_find(m, reply.peers))
+ {
+ // we don't have any peers for this info_hash,
+ // return nodes instead
+ m_table.find_node(m.info_hash, reply.nodes, false);
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ for (std::vector<node_entry>::iterator i = reply.nodes.begin()
+ , end(reply.nodes.end()); i != end; ++i)
+ {
+ TORRENT_LOG(node) << " " << i->id << " " << i->addr;
+ }
+#endif
+ }
+ }
+ break;
+ case messages::find_node:
+ {
+ reply.info_hash = m.info_hash;
+
+ m_table.find_node(m.info_hash, reply.nodes, false);
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ for (std::vector<node_entry>::iterator i = reply.nodes.begin()
+ , end(reply.nodes.end()); i != end; ++i)
+ {
+ TORRENT_LOG(node) << " " << i->id << " " << i->addr;
+ }
+#endif
+ }
+ break;
+ case messages::announce_peer:
+ on_announce(m, reply);
+ break;
+ default:
+ TORRENT_ASSERT(false);
+ };
+
+ if (m_table.need_node(m.id))
+ m_rpc.reply_with_ping(reply);
+ else
+ m_rpc.reply(reply);
+}
+
+
+} } // namespace libtorrent::dht
diff --git a/src/libtorrent/src/kademlia/node_id.cpp b/src/libtorrent/src/kademlia/node_id.cpp
new file mode 100644
index 0000000..758af2f
--- /dev/null
+++ b/src/libtorrent/src/kademlia/node_id.cpp
@@ -0,0 +1,117 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <algorithm>
+#include <iomanip>
+#include <ctime>
+#include <boost/bind.hpp>
+
+#include "libtorrent/kademlia/node_id.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/assert.hpp"
+
+using boost::bind;
+
+namespace libtorrent { namespace dht
+{
+
+// returns the distance between the two nodes
+// using the kademlia XOR-metric
+node_id distance(node_id const& n1, node_id const& n2)
+{
+ node_id ret;
+ node_id::iterator k = ret.begin();
+ for (node_id::const_iterator i = n1.begin(), j = n2.begin()
+ , end(n1.end()); i != end; ++i, ++j, ++k)
+ {
+ *k = *i ^ *j;
+ }
+ return ret;
+}
+
+// returns true if: distance(n1, ref) < distance(n2, ref)
+bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref)
+{
+ for (node_id::const_iterator i = n1.begin(), j = n2.begin()
+ , k = ref.begin(), end(n1.end()); i != end; ++i, ++j, ++k)
+ {
+ boost::uint8_t lhs = (*i ^ *k);
+ boost::uint8_t rhs = (*j ^ *k);
+ if (lhs < rhs) return true;
+ if (lhs > rhs) return false;
+ }
+ return false;
+}
+
+// returns n in: 2^n <= distance(n1, n2) < 2^(n+1)
+// useful for finding out which bucket a node belongs to
+int distance_exp(node_id const& n1, node_id const& n2)
+{
+ int byte = node_id::size - 1;
+ for (node_id::const_iterator i = n1.begin(), j = n2.begin()
+ , end(n1.end()); i != end; ++i, ++j, --byte)
+ {
+ TORRENT_ASSERT(byte >= 0);
+ boost::uint8_t t = *i ^ *j;
+ if (t == 0) continue;
+ // we have found the first non-zero byte
+ // return the bit-number of the first bit
+ // that differs
+ int bit = byte * 8;
+ for (int b = 7; b >= 0; --b)
+ if (t >= (1 << b)) return bit + b;
+ return bit;
+ }
+
+ return 0;
+}
+
+struct static_ { static_() { std::srand(std::time(0)); } } static__;
+
+node_id generate_id()
+{
+ char random[20];
+#ifdef _MSC_VER
+ std::generate(random, random + 20, &rand);
+#else
+ std::generate(random, random + 20, &std::rand);
+#endif
+
+ hasher h;
+ h.update(random, 20);
+ return h.final();
+}
+
+} } // namespace libtorrent::dht
+
diff --git a/src/libtorrent/src/kademlia/refresh.cpp b/src/libtorrent/src/kademlia/refresh.cpp
new file mode 100644
index 0000000..916b6d0
--- /dev/null
+++ b/src/libtorrent/src/kademlia/refresh.cpp
@@ -0,0 +1,180 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <libtorrent/kademlia/refresh.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/rpc_manager.hpp>
+#include <libtorrent/kademlia/logging.hpp>
+#include <libtorrent/kademlia/msg.hpp>
+
+#include <libtorrent/io.hpp>
+
+#include <boost/bind.hpp>
+
+using boost::bind;
+
+namespace libtorrent { namespace dht
+{
+
+using asio::ip::udp;
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DEFINE_LOG(refresh)
+#endif
+
+refresh_observer::~refresh_observer()
+{
+ if (m_algorithm) m_algorithm->failed(m_self, true);
+}
+
+void refresh_observer::reply(msg const& in)
+{
+ if (!m_algorithm) return;
+
+ if (!in.nodes.empty())
+ {
+ for (msg::nodes_t::const_iterator i = in.nodes.begin()
+ , end(in.nodes.end()); i != end; ++i)
+ {
+ m_algorithm->traverse(i->id, i->addr);
+ }
+ }
+ m_algorithm->finished(m_self);
+ m_algorithm = 0;
+}
+
+void refresh_observer::timeout()
+{
+ if (!m_algorithm) return;
+ m_algorithm->failed(m_self);
+ m_algorithm = 0;
+}
+
+ping_observer::~ping_observer()
+{
+ if (m_algorithm) m_algorithm->ping_timeout(m_self, true);
+}
+
+void ping_observer::reply(msg const& m)
+{
+ if (!m_algorithm) return;
+
+ m_algorithm->ping_reply(m_self);
+ m_algorithm = 0;
+}
+
+void ping_observer::timeout()
+{
+ if (!m_algorithm) return;
+ m_algorithm->ping_timeout(m_self);
+ m_algorithm = 0;
+}
+
+void refresh::invoke(node_id const& nid, udp::endpoint addr)
+{
+ observer_ptr o(new (m_rpc.allocator().malloc()) refresh_observer(
+ this, nid, m_target));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+
+ m_rpc.invoke(messages::find_node, addr, o);
+}
+
+void refresh::done()
+{
+ m_leftover_nodes_iterator = (int)m_results.size() > m_max_results ?
+ m_results.begin() + m_max_results : m_results.end();
+
+ invoke_pings_or_finish();
+}
+
+void refresh::ping_reply(node_id nid)
+{
+ m_active_pings--;
+ invoke_pings_or_finish();
+}
+
+void refresh::ping_timeout(node_id nid, bool prevent_request)
+{
+ m_active_pings--;
+ invoke_pings_or_finish(prevent_request);
+}
+
+void refresh::invoke_pings_or_finish(bool prevent_request)
+{
+ if (prevent_request)
+ {
+ --m_max_active_pings;
+ if (m_max_active_pings <= 0)
+ m_max_active_pings = 1;
+ }
+ else
+ {
+ while (m_active_pings < m_max_active_pings)
+ {
+ if (m_leftover_nodes_iterator == m_results.end()) break;
+
+ result const& node = *m_leftover_nodes_iterator;
+
+ // Skip initial nodes
+ if (node.flags & result::initial)
+ {
+ ++m_leftover_nodes_iterator;
+ continue;
+ }
+
+ try
+ {
+ observer_ptr o(new (m_rpc.allocator().malloc()) ping_observer(
+ this, node.id));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+ m_rpc.invoke(messages::ping, node.addr, o);
+ ++m_active_pings;
+ ++m_leftover_nodes_iterator;
+ }
+ catch (std::exception& e) {}
+ }
+ }
+
+ if (m_active_pings == 0)
+ {
+ m_done_callback();
+ }
+}
+
+} } // namespace libtorrent::dht
+
diff --git a/src/libtorrent/src/kademlia/routing_table.cpp b/src/libtorrent/src/kademlia/routing_table.cpp
new file mode 100644
index 0000000..3595776
--- /dev/null
+++ b/src/libtorrent/src/kademlia/routing_table.cpp
@@ -0,0 +1,449 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <deque>
+#include <algorithm>
+#include <functional>
+#include <numeric>
+#include <boost/cstdint.hpp>
+#include <boost/bind.hpp>
+
+#include "libtorrent/kademlia/routing_table.hpp"
+#include "libtorrent/kademlia/node_id.hpp"
+#include "libtorrent/session_settings.hpp"
+
+using boost::bind;
+using boost::uint8_t;
+
+namespace libtorrent { namespace dht
+{
+
+using asio::ip::udp;
+typedef asio::ip::address_v4 address;
+
+routing_table::routing_table(node_id const& id, int bucket_size
+ , dht_settings const& settings)
+ : m_bucket_size(bucket_size)
+ , m_settings(settings)
+ , m_id(id)
+ , m_lowest_active_bucket(160)
+{
+ // distribute the refresh times for the buckets in an
+ // attempt do even out the network load
+ for (int i = 0; i < 160; ++i)
+ m_bucket_activity[i] = time_now() - milliseconds(i*5625);
+ m_bucket_activity[0] = time_now() - minutes(15);
+}
+
+boost::tuple<int, int> routing_table::size() const
+{
+ int nodes = 0;
+ int replacements = 0;
+ for (table_t::const_iterator i = m_buckets.begin()
+ , end(m_buckets.end()); i != end; ++i)
+ {
+ nodes += i->first.size();
+ replacements += i->second.size();
+ }
+ return boost::make_tuple(nodes, replacements);
+}
+
+size_type routing_table::num_global_nodes() const
+{
+ int first_full = m_lowest_active_bucket;
+ int num_nodes = 1; // we are one of the nodes
+ for (; first_full < 160
+ && int(m_buckets[first_full].first.size()) < m_bucket_size;
+ ++first_full)
+ {
+ num_nodes += m_buckets[first_full].first.size();
+ }
+
+ return (2 << (160 - first_full)) * num_nodes;
+}
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+
+void routing_table::print_state(std::ostream& os) const
+{
+ os << "kademlia routing table state\n"
+ << "bucket_size: " << m_bucket_size << "\n"
+ << "global node count: " << num_global_nodes() << "\n"
+ << "node_id: " << m_id << "\n\n";
+
+ os << "number of nodes per bucket:\n-- live ";
+ for (int i = 8; i < 160; ++i)
+ os << "-";
+ os << "\n";
+
+ for (int k = 0; k < 8; ++k)
+ {
+ for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
+ i != end; ++i)
+ {
+ os << (int(i->first.size()) > (7 - k) ? "|" : " ");
+ }
+ os << "\n";
+ }
+ for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
+ i != end; ++i)
+ {
+ os << "+";
+ }
+ os << "\n";
+ for (int k = 0; k < 8; ++k)
+ {
+ for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
+ i != end; ++i)
+ {
+ os << (int(i->second.size()) > k ? "|" : " ");
+ }
+ os << "\n";
+ }
+ os << "-- cached ";
+ for (int i = 10; i < 160; ++i)
+ os << "-";
+ os << "\n\n";
+
+ os << "nodes:\n";
+ for (table_t::const_iterator i = m_buckets.begin(), end(m_buckets.end());
+ i != end; ++i)
+ {
+ int bucket_index = int(i - m_buckets.begin());
+ os << "=== BUCKET = " << bucket_index
+ << " = " << (bucket_index >= m_lowest_active_bucket?"active":"inactive")
+ << " = " << total_seconds(time_now() - m_bucket_activity[bucket_index])
+ << " s ago ===== \n";
+ for (bucket_t::const_iterator j = i->first.begin()
+ , end(i->first.end()); j != end; ++j)
+ {
+ os << "ip: " << j->addr << " fails: " << j->fail_count
+ << " id: " << j->id << "\n";
+ }
+ }
+}
+
+#endif
+
+void routing_table::touch_bucket(int bucket)
+{
+ m_bucket_activity[bucket] = time_now();
+}
+
+ptime routing_table::next_refresh(int bucket)
+{
+ TORRENT_ASSERT(bucket < 160);
+ TORRENT_ASSERT(bucket >= 0);
+ // lower than or equal to since a refresh of bucket 0 will
+ // effectively refresh the lowest active bucket as well
+ if (bucket < m_lowest_active_bucket && bucket > 0)
+ return time_now() + minutes(15);
+ return m_bucket_activity[bucket] + minutes(15);
+}
+
+void routing_table::replacement_cache(bucket_t& nodes) const
+{
+ for (table_t::const_iterator i = m_buckets.begin()
+ , end(m_buckets.end()); i != end; ++i)
+ {
+ std::copy(i->second.begin(), i->second.end()
+ , std::back_inserter(nodes));
+ }
+}
+
+bool routing_table::need_node(node_id const& id)
+{
+ int bucket_index = distance_exp(m_id, id);
+ TORRENT_ASSERT(bucket_index < (int)m_buckets.size());
+ TORRENT_ASSERT(bucket_index >= 0);
+ bucket_t& b = m_buckets[bucket_index].first;
+ bucket_t& rb = m_buckets[bucket_index].second;
+
+ // if the replacement cache is full, we don't
+ // need another node. The table is fine the
+ // way it is.
+ if ((int)rb.size() >= m_bucket_size) return false;
+
+ // if the node already exists, we don't need it
+ if (std::find_if(b.begin(), b.end(), bind(&node_entry::id, _1) == id)
+ != b.end()) return false;
+
+ if (std::find_if(rb.begin(), rb.end(), bind(&node_entry::id, _1) == id)
+ != rb.end()) return false;
+
+ return true;
+}
+
+void routing_table::node_failed(node_id const& id)
+{
+ int bucket_index = distance_exp(m_id, id);
+ TORRENT_ASSERT(bucket_index < (int)m_buckets.size());
+ TORRENT_ASSERT(bucket_index >= 0);
+ bucket_t& b = m_buckets[bucket_index].first;
+ bucket_t& rb = m_buckets[bucket_index].second;
+
+ bucket_t::iterator i = std::find_if(b.begin(), b.end()
+ , bind(&node_entry::id, _1) == id);
+
+ if (i == b.end()) return;
+
+ // if messages to ourself fails, ignore it
+ if (bucket_index == 0) return;
+
+ if (rb.empty())
+ {
+ ++i->fail_count;
+ if (i->fail_count >= m_settings.max_fail_count)
+ {
+ b.erase(i);
+ TORRENT_ASSERT(m_lowest_active_bucket <= bucket_index);
+ while (m_buckets[m_lowest_active_bucket].first.empty()
+ && m_lowest_active_bucket < 160)
+ {
+ ++m_lowest_active_bucket;
+ }
+ }
+ return;
+ }
+
+ b.erase(i);
+ b.push_back(rb.back());
+ rb.erase(rb.end() - 1);
+}
+
+void routing_table::add_router_node(udp::endpoint router)
+{
+ m_router_nodes.insert(router);
+}
+
+// this function is called every time the node sees
+// a sign of a node being alive. This node will either
+// be inserted in the k-buckets or be moved to the top
+// of its bucket.
+// the return value indicates if the table needs a refresh.
+// if true, the node should refresh the table (i.e. do a find_node
+// on its own id)
+bool routing_table::node_seen(node_id const& id, udp::endpoint addr)
+{
+ if (m_router_nodes.find(addr) != m_router_nodes.end()) return false;
+ int bucket_index = distance_exp(m_id, id);
+ TORRENT_ASSERT(bucket_index < (int)m_buckets.size());
+ TORRENT_ASSERT(bucket_index >= 0);
+ bucket_t& b = m_buckets[bucket_index].first;
+
+ bucket_t::iterator i = std::find_if(b.begin(), b.end()
+ , bind(&node_entry::id, _1) == id);
+
+ bool ret = need_bootstrap();
+
+ //m_bucket_activity[bucket_index] = time_now();
+
+ if (i != b.end())
+ {
+ // TODO: what do we do if we see a node with
+ // the same id as a node at a different address?
+// TORRENT_ASSERT(i->addr == addr);
+
+ // we already have the node in our bucket
+ // just move it to the back since it was
+ // the last node we had any contact with
+ // in this bucket
+ b.erase(i);
+ b.push_back(node_entry(id, addr));
+// TORRENT_LOG(table) << "replacing node: " << id << " " << addr;
+ return ret;
+ }
+
+ // if the node was not present in our list
+ // we will only insert it if there is room
+ // for it, or if some of our nodes have gone
+ // offline
+ if ((int)b.size() < m_bucket_size)
+ {
+ if (b.empty()) b.reserve(m_bucket_size);
+ b.push_back(node_entry(id, addr));
+ // if bucket index is 0, the node is ourselves
+ // don't updated m_lowest_active_bucket
+ if (bucket_index < m_lowest_active_bucket
+ && bucket_index > 0)
+ m_lowest_active_bucket = bucket_index;
+// TORRENT_LOG(table) << "inserting node: " << id << " " << addr;
+ return ret;
+ }
+
+ // if there is no room, we look for nodes marked as stale
+ // in the k-bucket. If we find one, we can replace it.
+ // A node is considered stale if it has failed at least one
+ // time. Here we choose the node that has failed most times.
+ // If we don't find one, place this node in the replacement-
+ // cache and replace any nodes that will fail in the future
+ // with nodes from that cache.
+
+ i = std::max_element(b.begin(), b.end()
+ , bind(&node_entry::fail_count, _1)
+ < bind(&node_entry::fail_count, _2));
+
+ if (i != b.end() && i->fail_count > 0)
+ {
+ // i points to a node that has been marked
+ // as stale. Replace it with this new one
+ b.erase(i);
+ b.push_back(node_entry(id, addr));
+// TORRENT_LOG(table) << "replacing stale node: " << id << " " << addr;
+ return ret;
+ }
+
+ // if we don't have any identified stale nodes in
+ // the bucket, and the bucket is full, we have to
+ // cache this node and wait until some node fails
+ // and then replace it.
+
+ bucket_t& rb = m_buckets[bucket_index].second;
+
+ i = std::find_if(rb.begin(), rb.end()
+ , bind(&node_entry::id, _1) == id);
+
+ // if the node is already in the replacement bucket
+ // just return.
+ if (i != rb.end()) return ret;
+
+ if ((int)rb.size() > m_bucket_size) rb.erase(rb.begin());
+ if (rb.empty()) rb.reserve(m_bucket_size);
+ rb.push_back(node_entry(id, addr));
+// TORRENT_LOG(table) << "inserting node in replacement cache: " << id << " " << addr;
+ return ret;
+}
+
+bool routing_table::need_bootstrap() const
+{
+ for (const_iterator i = begin(); i != end(); ++i)
+ {
+ if (i->fail_count == 0) return false;
+ }
+ return true;
+}
+
+// fills the vector with the k nodes from our buckets that
+// are nearest to the given id.
+void routing_table::find_node(node_id const& target
+ , std::vector<node_entry>& l, bool include_self, int count)
+{
+ l.clear();
+ if (count == 0) count = m_bucket_size;
+ l.reserve(count);
+
+ int bucket_index = distance_exp(m_id, target);
+ bucket_t& b = m_buckets[bucket_index].first;
+
+ // copy all nodes that hasn't failed into the target
+ // vector.
+ std::remove_copy_if(b.begin(), b.end(), std::back_inserter(l)
+ , bind(&node_entry::fail_count, _1));
+ TORRENT_ASSERT((int)l.size() <= count);
+
+ if ((int)l.size() == count)
+ {
+ TORRENT_ASSERT(std::count_if(l.begin(), l.end()
+ , boost::bind(&node_entry::fail_count, _1) != 0) == 0);
+ return;
+ }
+
+ // if we didn't have enough nodes in that bucket
+ // we have to reply with nodes from buckets closer
+ // to us. i.e. all the buckets in the range
+ // [0, bucket_index) if we are to include ourself
+ // or [1, bucket_index) if not.
+ bucket_t tmpb;
+ for (int i = include_self?0:1; i < bucket_index; ++i)
+ {
+ bucket_t& b = m_buckets[i].first;
+ std::remove_copy_if(b.begin(), b.end(), std::back_inserter(tmpb)
+ , bind(&node_entry::fail_count, _1));
+ }
+
+ std::random_shuffle(tmpb.begin(), tmpb.end());
+ size_t to_copy = (std::min)(m_bucket_size - l.size()
+ , tmpb.size());
+ std::copy(tmpb.begin(), tmpb.begin() + to_copy
+ , std::back_inserter(l));
+
+ TORRENT_ASSERT((int)l.size() <= m_bucket_size);
+
+ // return if we have enough nodes or if the bucket index
+ // is the biggest index available (there are no more buckets)
+ // to look in.
+ if ((int)l.size() == count
+ || bucket_index == (int)m_buckets.size() - 1)
+ {
+ TORRENT_ASSERT(std::count_if(l.begin(), l.end()
+ , boost::bind(&node_entry::fail_count, _1) != 0) == 0);
+ return;
+ }
+
+ for (size_t i = bucket_index + 1; i < m_buckets.size(); ++i)
+ {
+ bucket_t& b = m_buckets[i].first;
+
+ std::remove_copy_if(b.begin(), b.end(), std::back_inserter(l)
+ , bind(&node_entry::fail_count, _1));
+ if ((int)l.size() >= count)
+ {
+ l.erase(l.begin() + count, l.end());
+ TORRENT_ASSERT(std::count_if(l.begin(), l.end()
+ , boost::bind(&node_entry::fail_count, _1) != 0) == 0);
+ return;
+ }
+ }
+ TORRENT_ASSERT((int)l.size() == count
+ || std::distance(l.begin(), l.end()) < m_bucket_size);
+ TORRENT_ASSERT((int)l.size() <= count);
+
+ TORRENT_ASSERT(std::count_if(l.begin(), l.end()
+ , boost::bind(&node_entry::fail_count, _1) != 0) == 0);
+}
+
+routing_table::iterator routing_table::begin() const
+{
+ // +1 to avoid ourself
+ return iterator(m_buckets.begin() + 1, m_buckets.end());
+}
+
+routing_table::iterator routing_table::end() const
+{
+ return iterator(m_buckets.end(), m_buckets.end());
+}
+
+} } // namespace libtorrent::dht
+
diff --git a/src/libtorrent/src/kademlia/rpc_manager.cpp b/src/libtorrent/src/kademlia/rpc_manager.cpp
new file mode 100644
index 0000000..7295cf0
--- /dev/null
+++ b/src/libtorrent/src/kademlia/rpc_manager.cpp
@@ -0,0 +1,447 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+#include "libtorrent/socket.hpp"
+
+#include <boost/bind.hpp>
+#include <boost/mpl/max_element.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/sizeof.hpp>
+#include <boost/mpl/transform_view.hpp>
+#include <boost/mpl/deref.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <libtorrent/io.hpp>
+#include <libtorrent/invariant_check.hpp>
+#include <libtorrent/kademlia/rpc_manager.hpp>
+#include <libtorrent/kademlia/logging.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/find_data.hpp>
+#include <libtorrent/kademlia/closest_nodes.hpp>
+#include <libtorrent/kademlia/refresh.hpp>
+#include <libtorrent/kademlia/node.hpp>
+#include <libtorrent/kademlia/observer.hpp>
+#include <libtorrent/hasher.hpp>
+
+#include <fstream>
+
+using boost::shared_ptr;
+using boost::bind;
+
+namespace libtorrent { namespace dht
+{
+
+namespace io = libtorrent::detail;
+namespace mpl = boost::mpl;
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DEFINE_LOG(rpc)
+#endif
+
+void intrusive_ptr_add_ref(observer const* o)
+{
+ TORRENT_ASSERT(o->m_refs >= 0);
+ TORRENT_ASSERT(o != 0);
+ ++o->m_refs;
+}
+
+void intrusive_ptr_release(observer const* o)
+{
+ TORRENT_ASSERT(o->m_refs > 0);
+ TORRENT_ASSERT(o != 0);
+ if (--o->m_refs == 0)
+ {
+ boost::pool<>& p = o->pool_allocator;
+ o->~observer();
+ p.free(const_cast<observer*>(o));
+ }
+}
+
+node_id generate_id();
+
+typedef mpl::vector<
+ closest_nodes_observer
+ , find_data_observer
+ , announce_observer
+ , get_peers_observer
+ , refresh_observer
+ , ping_observer
+ , null_observer
+ > observer_types;
+
+typedef mpl::max_element<
+ mpl::transform_view<observer_types, mpl::sizeof_<mpl::_1> >
+ >::type max_observer_type_iter;
+
+rpc_manager::rpc_manager(fun const& f, node_id const& our_id
+ , routing_table& table, send_fun const& sf)
+ : m_pool_allocator(sizeof(mpl::deref<max_observer_type_iter::base>::type))
+ , m_next_transaction_id(rand() % max_transactions)
+ , m_oldest_transaction_id(m_next_transaction_id)
+ , m_incoming(f)
+ , m_send(sf)
+ , m_our_id(our_id)
+ , m_table(table)
+ , m_timer(time_now())
+ , m_random_number(generate_id())
+ , m_destructing(false)
+{
+ std::srand(time(0));
+}
+
+rpc_manager::~rpc_manager()
+{
+ m_destructing = true;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Destructing";
+#endif
+ std::for_each(m_aborted_transactions.begin(), m_aborted_transactions.end()
+ , bind(&observer::abort, _1));
+
+ for (transactions_t::iterator i = m_transactions.begin()
+ , end(m_transactions.end()); i != end; ++i)
+ {
+ if (*i) (*i)->abort();
+ }
+}
+
+#ifndef NDEBUG
+void rpc_manager::check_invariant() const
+{
+ TORRENT_ASSERT(m_oldest_transaction_id >= 0);
+ TORRENT_ASSERT(m_oldest_transaction_id < max_transactions);
+ TORRENT_ASSERT(m_next_transaction_id >= 0);
+ TORRENT_ASSERT(m_next_transaction_id < max_transactions);
+ TORRENT_ASSERT(!m_transactions[m_next_transaction_id]);
+
+ for (int i = (m_next_transaction_id + 1) % max_transactions;
+ i != m_oldest_transaction_id; i = (i + 1) % max_transactions)
+ {
+ TORRENT_ASSERT(!m_transactions[i]);
+ }
+}
+#endif
+
+bool rpc_manager::incoming(msg const& m)
+{
+ INVARIANT_CHECK;
+
+ if (m_destructing) return false;
+
+ if (m.reply)
+ {
+ // if we don't have the transaction id in our
+ // request list, ignore the packet
+
+ if (m.transaction_id.size() < 2)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Reply with invalid transaction id size: "
+ << m.transaction_id.size() << " from " << m.addr;
+#endif
+ msg reply;
+ reply.reply = true;
+ reply.message_id = messages::error;
+ reply.error_code = 203; // Protocol error
+ reply.error_msg = "reply with invalid transaction id, size "
+ + boost::lexical_cast<std::string>(m.transaction_id.size());
+ reply.addr = m.addr;
+ reply.transaction_id = "";
+ m_send(reply);
+ return false;
+ }
+
+ std::string::const_iterator i = m.transaction_id.begin();
+ int tid = io::read_uint16(i);
+
+ if (tid >= (int)m_transactions.size()
+ || tid < 0)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Reply with invalid transaction id: "
+ << tid << " from " << m.addr;
+#endif
+ msg reply;
+ reply.reply = true;
+ reply.message_id = messages::error;
+ reply.error_code = 203; // Protocol error
+ reply.error_msg = "reply with invalid transaction id";
+ reply.addr = m.addr;
+ reply.transaction_id = "";
+ m_send(reply);
+ return false;
+ }
+
+ observer_ptr o = m_transactions[tid];
+
+ if (!o)
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
+ << tid << " from " << m.addr << " (possibly timed out)";
+#endif
+ return false;
+ }
+
+ if (m.addr.address() != o->target_addr.address())
+ {
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Reply with incorrect address and valid transaction id: "
+ << tid << " from " << m.addr << " expected: " << o->target_addr;
+#endif
+ return false;
+ }
+
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ std::ofstream reply_stats("libtorrent_logs/round_trip_ms.log", std::ios::app);
+ reply_stats << m.addr << "\t" << total_milliseconds(time_now() - o->sent)
+ << std::endl;
+#endif
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Reply with transaction id: "
+ << tid << " from " << m.addr;
+#endif
+ o->reply(m);
+ m_transactions[tid] = 0;
+
+ if (m.piggy_backed_ping)
+ {
+ // there is a ping request piggy
+ // backed in this reply
+ msg ph;
+ ph.message_id = messages::ping;
+ ph.transaction_id = m.ping_transaction_id;
+ ph.addr = m.addr;
+ ph.reply = true;
+
+ reply(ph);
+ }
+ return m_table.node_seen(m.id, m.addr);
+ }
+ else
+ {
+ TORRENT_ASSERT(m.message_id != messages::error);
+ // this is an incoming request
+ m_incoming(m);
+ }
+ return false;
+}
+
+time_duration rpc_manager::tick()
+{
+ INVARIANT_CHECK;
+
+ const int timeout_ms = 10 * 1000;
+
+ // look for observers that has timed out
+
+ if (m_next_transaction_id == m_oldest_transaction_id) return milliseconds(timeout_ms);
+
+ std::vector<observer_ptr > timeouts;
+
+ for (;m_next_transaction_id != m_oldest_transaction_id;
+ m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions)
+ {
+ TORRENT_ASSERT(m_oldest_transaction_id >= 0);
+ TORRENT_ASSERT(m_oldest_transaction_id < max_transactions);
+
+ observer_ptr o = m_transactions[m_oldest_transaction_id];
+ if (!o) continue;
+
+ time_duration diff = o->sent + milliseconds(timeout_ms) - time_now();
+ if (diff > seconds(0))
+ {
+ if (diff < seconds(1)) return seconds(1);
+ return diff;
+ }
+
+ try
+ {
+ m_transactions[m_oldest_transaction_id] = 0;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Timing out transaction id: "
+ << m_oldest_transaction_id << " from " << o->target_addr;
+#endif
+ timeouts.push_back(o);
+ } catch (std::exception) {}
+ }
+
+ std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::timeout, _1));
+ timeouts.clear();
+
+ // clear the aborted transactions, will likely
+ // generate new requests. We need to swap, since the
+ // destrutors may add more observers to the m_aborted_transactions
+ std::vector<observer_ptr >().swap(m_aborted_transactions);
+ return milliseconds(timeout_ms);
+}
+
+unsigned int rpc_manager::new_transaction_id(observer_ptr o)
+{
+ INVARIANT_CHECK;
+
+ unsigned int tid = m_next_transaction_id;
+ m_next_transaction_id = (m_next_transaction_id + 1) % max_transactions;
+ if (m_transactions[m_next_transaction_id])
+ {
+ // moving the observer into the set of aborted transactions
+ // it will prevent it from spawning new requests right now,
+ // since that would break the invariant
+ observer_ptr o = m_transactions[m_next_transaction_id];
+ m_aborted_transactions.push_back(o);
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "[new_transaction_id] Aborting message with transaction id: "
+ << m_next_transaction_id << " sent to " << o->target_addr
+ << " " << total_seconds(time_now() - o->sent) << " seconds ago";
+#endif
+ m_transactions[m_next_transaction_id] = 0;
+ TORRENT_ASSERT(m_oldest_transaction_id == m_next_transaction_id);
+ }
+ TORRENT_ASSERT(!m_transactions[tid]);
+ m_transactions[tid] = o;
+ if (m_oldest_transaction_id == m_next_transaction_id)
+ {
+ m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions;
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "WARNING: transaction limit reached! Too many concurrent"
+ " messages! limit: " << (int)max_transactions;
+#endif
+ update_oldest_transaction_id();
+ }
+
+ return tid;
+}
+
+void rpc_manager::update_oldest_transaction_id()
+{
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_oldest_transaction_id != m_next_transaction_id);
+ while (!m_transactions[m_oldest_transaction_id])
+ {
+ m_oldest_transaction_id = (m_oldest_transaction_id + 1)
+ % max_transactions;
+ if (m_oldest_transaction_id == m_next_transaction_id)
+ break;
+ }
+}
+
+void rpc_manager::invoke(int message_id, udp::endpoint target_addr
+ , observer_ptr o)
+{
+ INVARIANT_CHECK;
+
+ if (m_destructing)
+ {
+ o->abort();
+ return;
+ }
+
+ msg m;
+ m.message_id = message_id;
+ m.reply = false;
+ m.id = m_our_id;
+ m.addr = target_addr;
+ TORRENT_ASSERT(!m_transactions[m_next_transaction_id]);
+#ifndef NDEBUG
+ int potential_new_id = m_next_transaction_id;
+#endif
+ try
+ {
+ m.transaction_id.clear();
+ std::back_insert_iterator<std::string> out(m.transaction_id);
+ io::write_uint16(m_next_transaction_id, out);
+
+ o->send(m);
+
+ o->sent = time_now();
+ o->target_addr = target_addr;
+
+ #ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(rpc) << "Invoking " << messages::ids[message_id]
+ << " -> " << target_addr;
+ #endif
+ m_send(m);
+ new_transaction_id(o);
+ }
+ catch (std::exception& e)
+ {
+ // m_send may fail with "no route to host"
+ TORRENT_ASSERT(potential_new_id == m_next_transaction_id);
+ o->abort();
+ }
+}
+
+void rpc_manager::reply(msg& m)
+{
+ INVARIANT_CHECK;
+
+ if (m_destructing) return;
+
+ TORRENT_ASSERT(m.reply);
+ m.piggy_backed_ping = false;
+ m.id = m_our_id;
+
+ m_send(m);
+}
+
+void rpc_manager::reply_with_ping(msg& m)
+{
+ INVARIANT_CHECK;
+
+ if (m_destructing) return;
+ TORRENT_ASSERT(m.reply);
+
+ m.piggy_backed_ping = true;
+ m.id = m_our_id;
+
+ m.ping_transaction_id.clear();
+ std::back_insert_iterator<std::string> out(m.ping_transaction_id);
+ io::write_uint16(m_next_transaction_id, out);
+
+ observer_ptr o(new (allocator().malloc()) null_observer(allocator()));
+#ifndef NDEBUG
+ o->m_in_constructor = false;
+#endif
+ TORRENT_ASSERT(!m_transactions[m_next_transaction_id]);
+ o->sent = time_now();
+ o->target_addr = m.addr;
+
+ m_send(m);
+ new_transaction_id(o);
+}
+
+
+
+} } // namespace libtorrent::dht
+
diff --git a/src/libtorrent/src/kademlia/traversal_algorithm.cpp b/src/libtorrent/src/kademlia/traversal_algorithm.cpp
new file mode 100644
index 0000000..b1e8033
--- /dev/null
+++ b/src/libtorrent/src/kademlia/traversal_algorithm.cpp
@@ -0,0 +1,193 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg & Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <libtorrent/kademlia/traversal_algorithm.hpp>
+#include <libtorrent/kademlia/routing_table.hpp>
+#include <libtorrent/kademlia/rpc_manager.hpp>
+
+#include <boost/bind.hpp>
+
+using boost::bind;
+using asio::ip::udp;
+
+namespace libtorrent { namespace dht
+{
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+TORRENT_DEFINE_LOG(traversal)
+#endif
+
+void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags)
+{
+ if (m_failed.find(addr) != m_failed.end()) return;
+
+ result entry(id, addr, flags);
+ if (entry.id.is_all_zeros())
+ {
+ entry.id = generate_id();
+ entry.flags |= result::no_id;
+ }
+
+ std::vector<result>::iterator i = std::lower_bound(
+ m_results.begin()
+ , m_results.end()
+ , entry
+ , bind(
+ compare_ref
+ , bind(&result::id, _1)
+ , bind(&result::id, _2)
+ , m_target
+ )
+ );
+
+ if (i == m_results.end() || i->id != id)
+ {
+ TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
+ , bind(&result::id, _1) == id) == m_results.end());
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(traversal) << "adding result: " << id << " " << addr;
+#endif
+ m_results.insert(i, entry);
+ }
+}
+
+boost::pool<>& traversal_algorithm::allocator() const
+{
+ return m_rpc.allocator();
+}
+
+void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
+{
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(traversal) << "node returned a list which included a node with id 0";
+#endif
+ add_entry(id, addr, 0);
+}
+
+void traversal_algorithm::finished(node_id const& id)
+{
+ --m_invoke_count;
+ add_requests();
+ if (m_invoke_count == 0) done();
+}
+
+// prevent request means that the total number of requests has
+// overflown. This query failed because it was the oldest one.
+// So, if this is true, don't make another request
+void traversal_algorithm::failed(node_id const& id, bool prevent_request)
+{
+ m_invoke_count--;
+
+ TORRENT_ASSERT(!id.is_all_zeros());
+ std::vector<result>::iterator i = std::find_if(
+ m_results.begin()
+ , m_results.end()
+ , bind(
+ std::equal_to<node_id>()
+ , bind(&result::id, _1)
+ , id
+ )
+ );
+
+ TORRENT_ASSERT(i != m_results.end());
+
+ if (i != m_results.end())
+ {
+ TORRENT_ASSERT(i->flags & result::queried);
+ m_failed.insert(i->addr);
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(traversal) << "failed: " << i->id << " " << i->addr;
+#endif
+ // don't tell the routing table about
+ // node ids that we just generated ourself
+ if ((i->flags & result::no_id) == 0)
+ m_table.node_failed(id);
+ m_results.erase(i);
+ }
+ if (prevent_request)
+ {
+ --m_branch_factor;
+ if (m_branch_factor <= 0) m_branch_factor = 1;
+ }
+ add_requests();
+ if (m_invoke_count == 0) done();
+}
+
+namespace
+{
+ bool bitwise_nand(unsigned char lhs, unsigned char rhs)
+ {
+ return (lhs & rhs) == 0;
+ }
+}
+
+void traversal_algorithm::add_requests()
+{
+ while (m_invoke_count < m_branch_factor)
+ {
+ // Find the first node that hasn't already been queried.
+ // TODO: Better heuristic
+ std::vector<result>::iterator i = std::find_if(
+ m_results.begin()
+ , last_iterator()
+ , bind(
+ &bitwise_nand
+ , bind(&result::flags, _1)
+ , (unsigned char)result::queried
+ )
+ );
+#ifdef TORRENT_DHT_VERBOSE_LOGGING
+ TORRENT_LOG(traversal) << "nodes left (" << this << "): " << (last_iterator() - i);
+#endif
+
+ if (i == last_iterator()) break;
+
+ try
+ {
+ invoke(i->id, i->addr);
+ ++m_invoke_count;
+ i->flags |= result::queried;
+ }
+ catch (std::exception& e) {}
+ }
+}
+
+std::vector<traversal_algorithm::result>::iterator traversal_algorithm::last_iterator()
+{
+ return (int)m_results.size() >= m_max_results ?
+ m_results.begin() + m_max_results
+ : m_results.end();
+}
+
+} } // namespace libtorrent::dht
+
diff --git a/src/libtorrent/src/logger.cpp b/src/libtorrent/src/logger.cpp
new file mode 100644
index 0000000..b33816a
--- /dev/null
+++ b/src/libtorrent/src/logger.cpp
@@ -0,0 +1,233 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/convenience.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <vector>
+
+#include "libtorrent/extensions/logger.hpp"
+#include "libtorrent/extensions.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/peer_connection.hpp"
+
+namespace libtorrent {
+
+namespace fs = boost::filesystem;
+
+namespace
+{
+
+ struct logger_peer_plugin : peer_plugin
+ {
+ logger_peer_plugin(std::string const& filename)
+ {
+ fs::path dir(fs::complete("libtorrent_ext_logs"));
+ if (!fs::exists(dir)) fs::create_directories(dir);
+ m_file.open((dir / filename).string().c_str(), std::ios_base::out | std::ios_base::out);
+ m_file << "\n\n\n";
+ log_timestamp();
+ m_file << "*** starting log ***\n";
+ }
+
+ void log_timestamp()
+ {
+ m_file << time_now_string() << ": ";
+ }
+
+ // can add entries to the extension handshake
+ virtual void add_handshake(entry&) {}
+
+ // called when the extension handshake from the other end is received
+ virtual bool on_extension_handshake(entry const& h)
+ {
+ log_timestamp();
+ m_file << "<== EXTENSION_HANDSHAKE\n";
+ h.print(m_file);
+ return true;
+ }
+
+ // returning true from any of the message handlers
+ // indicates that the plugin has handeled the message.
+ // it will break the plugin chain traversing and not let
+ // anyone else handle the message, including the default
+ // handler.
+
+ virtual bool on_choke()
+ {
+ log_timestamp();
+ m_file << "<== CHOKE\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_unchoke()
+ {
+ log_timestamp();
+ m_file << "<== UNCHOKE\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_interested()
+ {
+ log_timestamp();
+ m_file << "<== INTERESTED\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_not_interested()
+ {
+ log_timestamp();
+ m_file << "<== NOT_INTERESTED\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_have(int index)
+ {
+ log_timestamp();
+ m_file << "<== HAVE [" << index << "]\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_bitfield(std::vector<bool> const& bitfield)
+ {
+ log_timestamp();
+ m_file << "<== BITFIELD\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_request(peer_request const& r)
+ {
+ log_timestamp();
+ m_file << "<== REQUEST [ piece: " << r.piece << " | s: " << r.start
+ << " | l: " << r.length << " ]\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_piece(peer_request const& r, char const*)
+ {
+ log_timestamp();
+ m_file << "<== PIECE [ piece: " << r.piece << " | s: " << r.start
+ << " | l: " << r.length << " ]\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual bool on_cancel(peer_request const& r)
+ {
+ log_timestamp();
+ m_file << "<== CANCEL [ piece: " << r.piece << " | s: " << r.start
+ << " | l: " << r.length << " ]\n";
+ m_file.flush();
+ return false;
+ }
+
+ // called when an extended message is received. If returning true,
+ // the message is not processed by any other plugin and if false
+ // is returned the next plugin in the chain will receive it to
+ // be able to handle it
+ virtual bool on_extended(int length
+ , int msg, buffer::const_interval body)
+ { return false; }
+
+ virtual bool on_unknown_message(int length, int msg
+ , buffer::const_interval body)
+ {
+ if (body.left() < length) return false;
+ log_timestamp();
+ m_file << "<== UNKNOWN [ msg: " << msg
+ << " | l: " << length << " ]\n";
+ m_file.flush();
+ return false;
+ }
+
+ virtual void on_piece_pass(int index)
+ {
+ log_timestamp();
+ m_file << "*** HASH PASSED *** [ piece: " << index << " ]\n";
+ m_file.flush();
+ }
+
+ virtual void on_piece_failed(int index)
+ {
+ log_timestamp();
+ m_file << "*** HASH FAILED *** [ piece: " << index << " ]\n";
+ m_file.flush();
+ }
+
+ private:
+ std::ofstream m_file;
+ };
+
+ struct logger_plugin : torrent_plugin
+ {
+ virtual boost::shared_ptr<peer_plugin> new_connection(
+ peer_connection* pc)
+ {
+ return boost::shared_ptr<peer_plugin>(new logger_peer_plugin(
+ pc->remote().address().to_string() + "_"
+ + boost::lexical_cast<std::string>(pc->remote().port()) + ".log"));
+ }
+ };
+
+} }
+
+namespace libtorrent
+{
+
+ boost::shared_ptr<torrent_plugin> create_logger_plugin(torrent*)
+ {
+ return boost::shared_ptr<torrent_plugin>(new logger_plugin());
+ }
+
+}
+
+
diff --git a/src/libtorrent/src/lsd.cpp b/src/libtorrent/src/lsd.cpp
new file mode 100644
index 0000000..8ec1a5d
--- /dev/null
+++ b/src/libtorrent/src/lsd.cpp
@@ -0,0 +1,191 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/lsd.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/http_tracker_connection.hpp"
+
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <asio/ip/host_name.hpp>
+#include <asio/ip/multicast.hpp>
+#include <boost/thread/mutex.hpp>
+#include <cstdlib>
+#include <boost/config.hpp>
+
+using boost::bind;
+using namespace libtorrent;
+
+namespace libtorrent
+{
+ // defined in broadcast_socket.cpp
+ address guess_local_address(asio::io_service&);
+}
+
+lsd::lsd(io_service& ios, address const& listen_interface
+ , peer_callback_t const& cb)
+ : m_callback(cb)
+ , m_retry_count(1)
+ , m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143"), 6771)
+ , bind(&lsd::on_announce, self(), _1, _2, _3))
+ , m_broadcast_timer(ios)
+ , m_disabled(false)
+{
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
+#endif
+}
+
+lsd::~lsd() {}
+
+void lsd::announce(sha1_hash const& ih, int listen_port)
+{
+ if (m_disabled) return;
+
+ std::stringstream btsearch;
+ btsearch << "BT-SEARCH * HTTP/1.1\r\n"
+ "Host: 239.192.152.143:6771\r\n"
+ "Port: " << listen_port << "\r\n"
+ "Infohash: " << ih << "\r\n"
+ "\r\n\r\n";
+ std::string const& msg = btsearch.str();
+
+ m_retry_count = 1;
+ asio::error_code ec;
+ m_socket.send(msg.c_str(), int(msg.size()), ec);
+ if (ec)
+ {
+ m_disabled = true;
+ return;
+ }
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " ==> announce: ih: " << ih << " port: " << listen_port << std::endl;
+#endif
+
+ m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
+ m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
+}
+
+void lsd::resend_announce(asio::error_code const& e, std::string msg) try
+{
+ if (e) return;
+
+ asio::error_code ec;
+ m_socket.send(msg.c_str(), int(msg.size()), ec);
+
+ ++m_retry_count;
+ if (m_retry_count >= 5)
+ return;
+
+ m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
+ m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
+}
+catch (std::exception&)
+{}
+
+void lsd::on_announce(udp::endpoint const& from, char* buffer
+ , std::size_t bytes_transferred)
+{
+ using namespace libtorrent::detail;
+
+ http_parser p;
+
+ p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred));
+
+ if (!p.header_finished())
+ {
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " <== announce: incomplete HTTP message\n";
+#endif
+ return;
+ }
+
+ if (p.method() != "bt-search")
+ {
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " <== announce: invalid HTTP method: " << p.method() << std::endl;
+#endif
+ return;
+ }
+
+ std::string const& port_str = p.header("port");
+ if (port_str.empty())
+ {
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " <== announce: invalid BT-SEARCH, missing port" << std::endl;
+#endif
+ return;
+ }
+
+ std::string const& ih_str = p.header("infohash");
+ if (ih_str.empty())
+ {
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
+#endif
+ return;
+ }
+
+ sha1_hash ih(0);
+ std::istringstream ih_sstr(ih_str);
+ ih_sstr >> ih;
+ int port = atoi(port_str.c_str());
+
+ if (!ih.is_all_zeros() && port != 0)
+ {
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " *** incoming local announce " << from.address()
+ << ":" << port << " ih: " << ih << std::endl;
+#endif
+ // we got an announce, pass it on through the callback
+ try { m_callback(tcp::endpoint(from.address(), port), ih); }
+ catch (std::exception&) {}
+ }
+}
+
+void lsd::close()
+{
+ m_socket.close();
+ m_broadcast_timer.cancel();
+ m_disabled = true;
+ m_callback.clear();
+}
+
diff --git a/src/libtorrent/src/metadata_transfer.cpp b/src/libtorrent/src/metadata_transfer.cpp
new file mode 100644
index 0000000..0d1aea1
--- /dev/null
+++ b/src/libtorrent/src/metadata_transfer.cpp
@@ -0,0 +1,564 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <vector>
+#include <utility>
+#include <numeric>
+
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/bt_peer_connection.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/extensions.hpp"
+#include "libtorrent/extensions/metadata_transfer.hpp"
+#include "libtorrent/alert_types.hpp"
+
+namespace libtorrent { namespace
+{
+ int div_round_up(int numerator, int denominator)
+ {
+ return (numerator + denominator - 1) / denominator;
+ }
+
+ std::pair<int, int> req_to_offset(std::pair<int, int> req, int total_size)
+ {
+ TORRENT_ASSERT(req.first >= 0);
+ TORRENT_ASSERT(req.second > 0);
+ TORRENT_ASSERT(req.second <= 256);
+ TORRENT_ASSERT(req.first + req.second <= 256);
+
+ int start = div_round_up(req.first * total_size, 256);
+ int size = div_round_up((req.first + req.second) * total_size, 256) - start;
+ return std::make_pair(start, size);
+ }
+
+ std::pair<int, int> offset_to_req(std::pair<int, int> offset, int total_size)
+ {
+ int start = offset.first * 256 / total_size;
+ int size = (offset.first + offset.second) * 256 / total_size - start;
+
+ std::pair<int, int> ret(start, size);
+
+ TORRENT_ASSERT(start >= 0);
+ TORRENT_ASSERT(size > 0);
+ TORRENT_ASSERT(start <= 256);
+ TORRENT_ASSERT(start + size <= 256);
+
+ // assert the identity of this function
+#ifndef NDEBUG
+ std::pair<int, int> identity = req_to_offset(ret, total_size);
+ TORRENT_ASSERT(offset == identity);
+#endif
+ return ret;
+ }
+
+ struct metadata_plugin : torrent_plugin
+ {
+ metadata_plugin(torrent& t)
+ : m_torrent(t)
+ , m_metadata_progress(0)
+ , m_metadata_size(0)
+ {
+ m_requested_metadata.resize(256, 0);
+ }
+
+ virtual void on_files_checked()
+ {
+ // if the torrent is a seed, copy the metadata from
+ // the torrent before it is deallocated
+ if (m_torrent.is_seed())
+ metadata();
+ }
+
+ virtual boost::shared_ptr<peer_plugin> new_connection(
+ peer_connection* pc);
+
+ std::vector<char> const& metadata() const
+ {
+ if (m_metadata.empty())
+ {
+ bencode(std::back_inserter(m_metadata)
+ , m_torrent.torrent_file().create_info_metadata());
+
+ TORRENT_ASSERT(hasher(&m_metadata[0], m_metadata.size()).final()
+ == m_torrent.torrent_file().info_hash());
+ }
+ TORRENT_ASSERT(!m_metadata.empty());
+ return m_metadata;
+ }
+
+ bool received_metadata(char const* buf, int size, int offset, int total_size)
+ {
+ if (m_torrent.valid_metadata()) return false;
+
+ if ((int)m_metadata.size() < total_size)
+ m_metadata.resize(total_size);
+
+ std::copy(
+ buf
+ , buf + size
+ , &m_metadata[offset]);
+
+ if (m_have_metadata.empty())
+ m_have_metadata.resize(256, false);
+
+ std::pair<int, int> req = offset_to_req(std::make_pair(offset, size)
+ , total_size);
+
+ TORRENT_ASSERT(req.first + req.second <= (int)m_have_metadata.size());
+
+ std::fill(
+ m_have_metadata.begin() + req.first
+ , m_have_metadata.begin() + req.first + req.second
+ , true);
+
+ bool have_all = std::count(
+ m_have_metadata.begin()
+ , m_have_metadata.end()
+ , true) == 256;
+
+ if (!have_all) return false;
+
+ hasher h;
+ h.update(&m_metadata[0], (int)m_metadata.size());
+ sha1_hash info_hash = h.final();
+
+ if (info_hash != m_torrent.torrent_file().info_hash())
+ {
+ std::fill(
+ m_have_metadata.begin()
+ , m_have_metadata.begin() + req.first + req.second
+ , false);
+ m_metadata_progress = 0;
+ m_metadata_size = 0;
+
+ if (m_torrent.alerts().should_post(alert::info))
+ {
+ m_torrent.alerts().post_alert(metadata_failed_alert(
+ m_torrent.get_handle(), "invalid metadata received from swarm"));
+ }
+
+ return false;
+ }
+
+ entry metadata = bdecode(m_metadata.begin(), m_metadata.end());
+ m_torrent.set_metadata(metadata);
+
+ // clear the storage for the bitfield
+ std::vector<bool>().swap(m_have_metadata);
+ std::vector<int>().swap(m_requested_metadata);
+
+ return true;
+ }
+
+ // returns a range of the metadata that
+ // we should request.
+ std::pair<int, int> metadata_request();
+
+ void cancel_metadata_request(std::pair<int, int> req)
+ {
+ for (int i = req.first; i < req.first + req.second; ++i)
+ {
+ TORRENT_ASSERT(m_requested_metadata[i] > 0);
+ if (m_requested_metadata[i] > 0)
+ --m_requested_metadata[i];
+ }
+ }
+
+ // this is called from the peer_connection for
+ // each piece of metadata it receives
+ void metadata_progress(int total_size, int received)
+ {
+ m_metadata_progress += received;
+ m_metadata_size = total_size;
+ }
+
+ void on_piece_pass(int)
+ {
+ // if we became a seed, copy the metadata from
+ // the torrent before it is deallocated
+ if (m_torrent.is_seed())
+ metadata();
+ }
+
+ private:
+ torrent& m_torrent;
+
+ // this buffer is filled with the info-section of
+ // the metadata file while downloading it from
+ // peers, and while sending it.
+ // it is mutable because it's generated lazily
+ mutable std::vector<char> m_metadata;
+
+ int m_metadata_progress;
+ int m_metadata_size;
+
+ // this is a bitfield of size 256, each bit represents
+ // a piece of the metadata. It is set to one if we
+ // have that piece. This vector may be empty
+ // (size 0) if we haven't received any metadata
+ // or if we already have all metadata
+ std::vector<bool> m_have_metadata;
+ // this vector keeps track of how many times each meatdata
+ // block has been requested
+ std::vector<int> m_requested_metadata;
+ };
+
+
+ struct metadata_peer_plugin : peer_plugin
+ {
+ metadata_peer_plugin(torrent& t, peer_connection& pc
+ , metadata_plugin& tp)
+ : m_waiting_metadata_request(false)
+ , m_message_index(0)
+ , m_metadata_progress(0)
+ , m_no_metadata(min_time())
+ , m_metadata_request(min_time())
+ , m_torrent(t)
+ , m_pc(pc)
+ , m_tp(tp)
+ {}
+
+ // can add entries to the extension handshake
+ virtual void add_handshake(entry& h)
+ {
+ entry& messages = h["m"];
+ messages["LT_metadata"] = 14;
+ }
+
+ // called when the extension handshake from the other end is received
+ virtual bool on_extension_handshake(entry const& h)
+ {
+ entry const& messages = h["m"];
+ if (entry const* index = messages.find_key("LT_metadata"))
+ {
+ m_message_index = int(index->integer());
+ return true;
+ }
+ else
+ {
+ m_message_index = 0;
+ return false;
+ }
+ }
+
+ void write_metadata_request(std::pair<int, int> req)
+ {
+ TORRENT_ASSERT(req.first >= 0);
+ TORRENT_ASSERT(req.second > 0);
+ TORRENT_ASSERT(req.first + req.second <= 256);
+ TORRENT_ASSERT(!m_pc.associated_torrent().expired());
+ TORRENT_ASSERT(!m_pc.associated_torrent().lock()->valid_metadata());
+
+ int start = req.first;
+ int size = req.second;
+
+ // abort if the peer doesn't support the metadata extension
+ if (m_message_index == 0) return;
+
+ buffer::interval i = m_pc.allocate_send_buffer(9);
+
+ detail::write_uint32(1 + 1 + 3, i.begin);
+ detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
+ detail::write_uint8(m_message_index, i.begin);
+ // means 'request data'
+ detail::write_uint8(0, i.begin);
+ detail::write_uint8(start, i.begin);
+ detail::write_uint8(size - 1, i.begin);
+ TORRENT_ASSERT(i.begin == i.end);
+ m_pc.setup_send();
+ }
+
+ void write_metadata(std::pair<int, int> req)
+ {
+ TORRENT_ASSERT(req.first >= 0);
+ TORRENT_ASSERT(req.second > 0);
+ TORRENT_ASSERT(req.second <= 256);
+ TORRENT_ASSERT(req.first + req.second <= 256);
+ TORRENT_ASSERT(!m_pc.associated_torrent().expired());
+
+ // abort if the peer doesn't support the metadata extension
+ if (m_message_index == 0) return;
+
+ // only send metadata if the torrent is non-private
+ if (m_torrent.valid_metadata() && !m_torrent.torrent_file().priv())
+ {
+ std::pair<int, int> offset
+ = req_to_offset(req, (int)m_tp.metadata().size());
+
+ buffer::interval i = m_pc.allocate_send_buffer(15 + offset.second);
+
+ // yes, we have metadata, send it
+ detail::write_uint32(11 + offset.second, i.begin);
+ detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
+ detail::write_uint8(m_message_index, i.begin);
+ // means 'data packet'
+ detail::write_uint8(1, i.begin);
+ detail::write_uint32((int)m_tp.metadata().size(), i.begin);
+ detail::write_uint32(offset.first, i.begin);
+ std::vector<char> const& metadata = m_tp.metadata();
+ std::copy(metadata.begin() + offset.first
+ , metadata.begin() + offset.first + offset.second, i.begin);
+ i.begin += offset.second;
+ TORRENT_ASSERT(i.begin == i.end);
+ }
+ else
+ {
+ buffer::interval i = m_pc.allocate_send_buffer(4 + 3);
+ // we don't have the metadata, reply with
+ // don't have-message
+ detail::write_uint32(1 + 2, i.begin);
+ detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
+ detail::write_uint8(m_message_index, i.begin);
+ // means 'have no data'
+ detail::write_uint8(2, i.begin);
+ TORRENT_ASSERT(i.begin == i.end);
+ }
+ m_pc.setup_send();
+ }
+
+ virtual bool on_extended(int length
+ , int msg, buffer::const_interval body)
+ {
+ if (msg != 14) return false;
+ if (m_message_index == 0) return false;
+
+ if (length > 500 * 1024)
+ throw protocol_error("LT_metadata message larger than 500 kB");
+
+ if (body.left() < 1) return true;
+ int type = detail::read_uint8(body.begin);
+
+ switch (type)
+ {
+ case 0: // request
+ {
+ if (body.left() < 2) return true;
+ int start = detail::read_uint8(body.begin);
+ int size = detail::read_uint8(body.begin) + 1;
+
+ if (length != 3)
+ {
+ // invalid metadata request
+ throw protocol_error("invalid metadata request");
+ }
+
+ write_metadata(std::make_pair(start, size));
+ }
+ break;
+ case 1: // data
+ {
+ if (body.left() < 8) return true;
+
+ int total_size = detail::read_int32(body.begin);
+ int offset = detail::read_int32(body.begin);
+ int data_size = length - 9;
+
+ if (total_size > 500 * 1024)
+ throw protocol_error("metadata size larger than 500 kB");
+ if (total_size <= 0)
+ throw protocol_error("invalid metadata size");
+ if (offset > total_size || offset < 0)
+ throw protocol_error("invalid metadata offset");
+ if (offset + data_size > total_size)
+ throw protocol_error("invalid metadata message");
+
+ m_tp.metadata_progress(total_size
+ , body.left() - m_metadata_progress);
+ m_metadata_progress = body.left();
+
+ if (body.left() < data_size) return true;
+
+ m_waiting_metadata_request = false;
+ m_tp.received_metadata(body.begin, data_size
+ , offset, total_size);
+ m_metadata_progress = 0;
+ }
+ break;
+ case 2: // have no data
+ m_no_metadata = time_now();
+ if (m_waiting_metadata_request)
+ m_tp.cancel_metadata_request(m_last_metadata_request);
+ m_waiting_metadata_request = false;
+ break;
+ default:
+ throw protocol_error("unknown metadata extension message: "
+ + boost::lexical_cast<std::string>(type));
+ }
+ return true;
+ }
+
+ virtual void tick()
+ {
+ // if we don't have any metadata, and this peer
+ // supports the request metadata extension
+ // and we aren't currently waiting for a request
+ // reply. Then, send a request for some metadata.
+ if (!m_torrent.valid_metadata()
+ && m_message_index != 0
+ && !m_waiting_metadata_request
+ && has_metadata())
+ {
+ m_last_metadata_request = m_tp.metadata_request();
+ write_metadata_request(m_last_metadata_request);
+ m_waiting_metadata_request = true;
+ m_metadata_request = time_now();
+ }
+ }
+
+ bool has_metadata() const
+ {
+ return time_now() - m_no_metadata > minutes(5);
+ }
+
+ private:
+
+ // this is set to true when we send a metadata
+ // request to this peer, and reset to false when
+ // we receive a reply to our request.
+ bool m_waiting_metadata_request;
+
+ // this is the message index the remote peer uses
+ // for metadata extension messages.
+ int m_message_index;
+
+ // the number of bytes of metadata we have received
+ // so far from this per, only counting the current
+ // request. Any previously finished requests
+ // that have been forwarded to the torrent object
+ // do not count.
+ int m_metadata_progress;
+
+ // this is set to the current time each time we get a
+ // "I don't have metadata" message.
+ ptime m_no_metadata;
+
+ // this is set to the time when we last sent
+ // a request for metadata to this peer
+ ptime m_metadata_request;
+
+ // if we're waiting for a metadata request
+ // this was the request we sent
+ std::pair<int, int> m_last_metadata_request;
+
+ torrent& m_torrent;
+ peer_connection& m_pc;
+ metadata_plugin& m_tp;
+ };
+
+ boost::shared_ptr<peer_plugin> metadata_plugin::new_connection(
+ peer_connection* pc)
+ {
+ bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
+ if (!c) return boost::shared_ptr<peer_plugin>();
+ return boost::shared_ptr<peer_plugin>(new metadata_peer_plugin(m_torrent, *pc, *this));
+ }
+
+ std::pair<int, int> metadata_plugin::metadata_request()
+ {
+ // count the number of peers that supports the
+ // extension and that has metadata
+ int peers = 0;
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (torrent::peer_iterator i = m_torrent.begin()
+ , end(m_torrent.end()); i != end; ++i)
+ {
+ bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(*i);
+ if (c == 0) continue;
+ metadata_peer_plugin* p
+ = c->supports_extension<metadata_peer_plugin>();
+ if (p == 0) continue;
+ if (!p->has_metadata()) continue;
+ ++peers;
+ }
+#endif
+
+ // the number of blocks to request
+ int num_blocks = 256 / (peers + 1);
+ if (num_blocks < 1) num_blocks = 1;
+ TORRENT_ASSERT(num_blocks <= 128);
+
+ int min_element = (std::numeric_limits<int>::max)();
+ int best_index = 0;
+ for (int i = 0; i < 256 - num_blocks + 1; ++i)
+ {
+ int min = *std::min_element(m_requested_metadata.begin() + i
+ , m_requested_metadata.begin() + i + num_blocks);
+ min += std::accumulate(m_requested_metadata.begin() + i
+ , m_requested_metadata.begin() + i + num_blocks, (int)0);
+
+ if (min_element > min)
+ {
+ best_index = i;
+ min_element = min;
+ }
+ }
+
+ std::pair<int, int> ret(best_index, num_blocks);
+ for (int i = ret.first; i < ret.first + ret.second; ++i)
+ m_requested_metadata[i]++;
+
+ TORRENT_ASSERT(ret.first >= 0);
+ TORRENT_ASSERT(ret.second > 0);
+ TORRENT_ASSERT(ret.second <= 256);
+ TORRENT_ASSERT(ret.first + ret.second <= 256);
+
+ return ret;
+ }
+
+} }
+
+namespace libtorrent
+{
+
+ boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent* t, void*)
+ {
+ return boost::shared_ptr<torrent_plugin>(new metadata_plugin(*t));
+ }
+
+}
+
+
diff --git a/src/libtorrent/src/natpmp.cpp b/src/libtorrent/src/natpmp.cpp
new file mode 100644
index 0000000..38319d1
--- /dev/null
+++ b/src/libtorrent/src/natpmp.cpp
@@ -0,0 +1,398 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <boost/bind.hpp>
+#include <asio/ip/host_name.hpp>
+
+#include "libtorrent/natpmp.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/assert.hpp"
+#include "libtorrent/enum_net.hpp"
+
+using boost::bind;
+using namespace libtorrent;
+
+enum { num_mappings = 2 };
+
+namespace libtorrent
+{
+ // defined in upnp.cpp
+ bool is_local(address const& a);
+ address guess_local_address(asio::io_service&);
+}
+
+natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb)
+ : m_callback(cb)
+ , m_currently_mapping(-1)
+ , m_retry_count(0)
+ , m_socket(ios)
+ , m_send_timer(ios)
+ , m_refresh_timer(ios)
+ , m_disabled(false)
+{
+ m_mappings[0].protocol = 2; // tcp
+ m_mappings[1].protocol = 1; // udp
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log.open("natpmp.log", std::ios::in | std::ios::out | std::ios::trunc);
+#endif
+ rebind(listen_interface);
+}
+
+void natpmp::rebind(address const& listen_interface) try
+{
+ address local = address_v4::any();
+ if (listen_interface != address_v4::any())
+ {
+ local = listen_interface;
+ }
+ else
+ {
+ local = guess_local_address(m_socket.io_service());
+
+ if (local == address_v4::any())
+ {
+ throw std::runtime_error("local host is probably not on a NATed "
+ "network. disabling NAT-PMP");
+ }
+ }
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " local ip: " << local.to_string() << std::endl;
+#endif
+
+ if (!is_local(local))
+ {
+ // the local address seems to be an external
+ // internet address. Assume it is not behind a NAT
+ throw std::runtime_error("local IP is not on a local network");
+ }
+
+ m_disabled = false;
+
+ asio::error_code ec;
+ udp::endpoint nat_endpoint(router_for_interface(local, ec), 5351);
+ if (ec)
+ throw std::runtime_error("cannot retrieve router address");
+
+ if (nat_endpoint == m_nat_endpoint) return;
+ m_nat_endpoint = nat_endpoint;
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl;
+#endif
+
+ m_socket.open(udp::v4());
+ m_socket.bind(udp::endpoint(address_v4::any(), 0));
+
+ for (int i = 0; i < num_mappings; ++i)
+ {
+ if (m_mappings[i].local_port == 0)
+ continue;
+ refresh_mapping(i);
+ }
+}
+catch (std::exception& e)
+{
+ m_disabled = true;
+ std::stringstream msg;
+ msg << "NAT-PMP disabled: " << e.what();
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << msg.str() << std::endl;
+#endif
+ m_callback(0, 0, msg.str());
+};
+
+void natpmp::set_mappings(int tcp, int udp)
+{
+ if (m_disabled) return;
+ update_mapping(0, tcp);
+ update_mapping(1, udp);
+}
+
+void natpmp::update_mapping(int i, int port)
+{
+ natpmp::mapping& m = m_mappings[i];
+ if (port <= 0) return;
+ if (m.local_port != port)
+ m.need_update = true;
+
+ m.local_port = port;
+ // prefer the same external port as the local port
+ if (m.external_port == 0) m.external_port = port;
+
+ if (m_currently_mapping == -1)
+ {
+ // the socket is not currently in use
+ // send out a mapping request
+ m_retry_count = 0;
+ send_map_request(i);
+ m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
+ , m_remote, bind(&natpmp::on_reply, self(), _1, _2));
+ }
+}
+
+void natpmp::send_map_request(int i) try
+{
+ using namespace libtorrent::detail;
+
+ TORRENT_ASSERT(m_currently_mapping == -1
+ || m_currently_mapping == i);
+ m_currently_mapping = i;
+ mapping& m = m_mappings[i];
+ char buf[12];
+ char* out = buf;
+ write_uint8(0, out); // NAT-PMP version
+ write_uint8(m.protocol, out); // map "protocol"
+ write_uint16(0, out); // reserved
+ write_uint16(m.local_port, out); // private port
+ write_uint16(m.external_port, out); // requested public port
+ int ttl = m.external_port == 0 ? 0 : 3600;
+ write_uint32(ttl, out); // port mapping lifetime
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " ==> port map request: " << (m.protocol == 1 ? "udp" : "tcp")
+ << " local: " << m.local_port << " external: " << m.external_port
+ << " ttl: " << ttl << std::endl;
+#endif
+
+ m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint);
+ // linear back-off instead of exponential
+ ++m_retry_count;
+ m_send_timer.expires_from_now(milliseconds(250 * m_retry_count));
+ m_send_timer.async_wait(bind(&natpmp::resend_request, self(), i, _1));
+}
+catch (std::exception& e)
+{
+ std::string err = e.what();
+};
+
+void natpmp::resend_request(int i, asio::error_code const& e)
+{
+ if (e) return;
+ if (m_currently_mapping != i) return;
+ if (m_retry_count >= 9)
+ {
+ m_mappings[i].need_update = false;
+ // try again in two hours
+ m_mappings[i].expires = time_now() + hours(2);
+ return;
+ }
+ send_map_request(i);
+}
+
+void natpmp::on_reply(asio::error_code const& e
+ , std::size_t bytes_transferred)
+{
+ using namespace libtorrent::detail;
+ if (e) return;
+
+ try
+ {
+
+ if (m_remote != m_nat_endpoint)
+ {
+ m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
+ , m_remote, bind(&natpmp::on_reply, self(), _1, _2));
+ return;
+ }
+
+ m_send_timer.cancel();
+
+ TORRENT_ASSERT(m_currently_mapping >= 0);
+ int i = m_currently_mapping;
+ mapping& m = m_mappings[i];
+
+ char* in = m_response_buffer;
+ int version = read_uint8(in);
+ int cmd = read_uint8(in);
+ int result = read_uint16(in);
+ int time = read_uint32(in);
+ int private_port = read_uint16(in);
+ int public_port = read_uint16(in);
+ int lifetime = read_uint32(in);
+
+ (void)time; // to remove warning
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << time_now_string()
+ << " <== port map response: " << (cmd - 128 == 1 ? "udp" : "tcp")
+ << " local: " << private_port << " external: " << public_port
+ << " ttl: " << lifetime << std::endl;
+#endif
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ if (version != 0)
+ {
+ m_log << "*** unexpected version: " << version << std::endl;
+ }
+#endif
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ if (private_port != m.local_port)
+ {
+ m_log << "*** unexpected local port: " << private_port << std::endl;
+ }
+#endif
+
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ if (cmd != 128 + m.protocol)
+ {
+ m_log << "*** unexpected protocol: " << (cmd - 128) << std::endl;
+ }
+#endif
+
+ if (public_port == 0 || lifetime == 0)
+ {
+ // this means the mapping was
+ // successfully closed
+ m.local_port = 0;
+ }
+ else
+ {
+ m.expires = time_now() + seconds(int(lifetime * 0.7f));
+ m.external_port = public_port;
+ }
+
+ if (result != 0)
+ {
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << "*** ERROR: " << result << std::endl;
+#endif
+ std::stringstream errmsg;
+ errmsg << "NAT router reports error (" << result << ") ";
+ switch (result)
+ {
+ case 1: errmsg << "Unsupported protocol version"; break;
+ case 2: errmsg << "Not authorized to create port map (enable NAT-PMP on your router)"; break;
+ case 3: errmsg << "Network failure"; break;
+ case 4: errmsg << "Out of resources"; break;
+ case 5: errmsg << "Unsupported opcode"; break;
+ }
+ throw std::runtime_error(errmsg.str());
+ }
+
+ // don't report when we remove mappings
+ if (m.local_port != 0)
+ {
+ int tcp_port = 0;
+ int udp_port = 0;
+ if (m.protocol == 1) udp_port = m.external_port;
+ else tcp_port = public_port;
+ m_callback(tcp_port, udp_port, "");
+ }
+ }
+ catch (std::exception& e)
+ {
+ // try again in two hours
+ m_mappings[m_currently_mapping].expires = time_now() + hours(2);
+ m_callback(0, 0, e.what());
+ }
+ int i = m_currently_mapping;
+ m_currently_mapping = -1;
+ m_mappings[i].need_update = false;
+ m_send_timer.cancel();
+ update_expiration_timer();
+ try_next_mapping(i);
+}
+
+void natpmp::update_expiration_timer()
+{
+ ptime now = time_now();
+ ptime min_expire = now + seconds(3600);
+ int min_index = -1;
+ for (int i = 0; i < num_mappings; ++i)
+ if (m_mappings[i].expires < min_expire
+ && m_mappings[i].local_port != 0)
+ {
+ min_expire = m_mappings[i].expires;
+ min_index = i;
+ }
+
+ if (min_index >= 0)
+ {
+ m_refresh_timer.expires_from_now(min_expire - now);
+ m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, self(), _1, min_index));
+ }
+}
+
+void natpmp::mapping_expired(asio::error_code const& e, int i)
+{
+ if (e) return;
+#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
+ m_log << "*** mapping " << i << " expired, updating" << std::endl;
+#endif
+ refresh_mapping(i);
+}
+
+void natpmp::refresh_mapping(int i)
+{
+ m_mappings[i].need_update = true;
+ if (m_currently_mapping == -1)
+ {
+ // the socket is not currently in use
+ // send out a mapping request
+ m_retry_count = 0;
+ send_map_request(i);
+ m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
+ , m_remote, bind(&natpmp::on_reply, self(), _1, _2));
+ }
+}
+
+void natpmp::try_next_mapping(int i)
+{
+ ++i;
+ if (i >= num_mappings) i = 0;
+ if (m_mappings[i].need_update)
+ refresh_mapping(i);
+}
+
+void natpmp::close()
+{
+ asio::error_code ec;
+ m_socket.close(ec);
+ if (m_disabled) return;
+ for (int i = 0; i < num_mappings; ++i)
+ {
+ if (m_mappings[i].local_port == 0)
+ continue;
+ m_mappings[i].external_port = 0;
+ refresh_mapping(i);
+ }
+ m_refresh_timer.cancel();
+ m_send_timer.cancel();
+}
+
diff --git a/src/libtorrent/src/pe_crypto.cpp b/src/libtorrent/src/pe_crypto.cpp
new file mode 100644
index 0000000..69c7f76
--- /dev/null
+++ b/src/libtorrent/src/pe_crypto.cpp
@@ -0,0 +1,142 @@
+/*
+
+Copyright (c) 2007, Un Shyam & Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+
+#include <algorithm>
+
+#include <openssl/dh.h>
+#include <openssl/engine.h>
+
+#include "libtorrent/pe_crypto.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ // Set the prime P and the generator, generate local public key
+ DH_key_exchange::DH_key_exchange()
+ {
+ m_DH = DH_new();
+ if (m_DH == 0) throw std::bad_alloc();
+
+ m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL);
+ m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL);
+ if (m_DH->p == 0 || m_DH->g == 0)
+ {
+ DH_free(m_DH);
+ throw std::bad_alloc();
+ }
+
+ m_DH->length = 160l;
+
+ TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH));
+
+ if (DH_generate_key(m_DH) == 0 || m_DH->pub_key == 0)
+ {
+ DH_free(m_DH);
+ throw std::bad_alloc();
+ }
+
+ // DH can generate key sizes that are smaller than the size of
+ // P with exponentially decreasing probability, in which case
+ // the msb's of m_dh_local_key need to be zeroed
+ // appropriately.
+ int key_size = get_local_key_size();
+ int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH)
+ if (key_size != len_dh)
+ {
+ TORRENT_ASSERT(key_size > 0 && key_size < len_dh);
+
+ int pad_zero_size = len_dh - key_size;
+ std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0);
+ BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size);
+ }
+ else
+ BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value
+ }
+
+ DH_key_exchange::~DH_key_exchange()
+ {
+ TORRENT_ASSERT(m_DH);
+ DH_free(m_DH);
+ }
+
+ char const* DH_key_exchange::get_local_key() const
+ {
+ return m_dh_local_key;
+ }
+
+
+ // compute shared secret given remote public key
+ void DH_key_exchange::compute_secret(char const* remote_pubkey)
+ {
+ TORRENT_ASSERT(remote_pubkey);
+ BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
+ if (bn_remote_pubkey == 0) throw std::bad_alloc();
+ char dh_secret[96];
+
+ int secret_size = DH_compute_key((unsigned char*)dh_secret
+ , bn_remote_pubkey, m_DH);
+ if (secret_size < 0 || secret_size > 96) throw std::bad_alloc();
+
+ if (secret_size != 96)
+ {
+ TORRENT_ASSERT(secret_size < 96 && secret_size > 0);
+ std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0);
+ }
+ std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
+ BN_free(bn_remote_pubkey);
+ }
+
+ char const* DH_key_exchange::get_secret() const
+ {
+ return m_dh_secret;
+ }
+
+ const unsigned char DH_key_exchange::m_dh_prime[96] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63
+ };
+
+ const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 };
+
+} // namespace libtorrent
+
+#endif // #ifndef TORRENT_DISABLE_ENCRYPTION
+
diff --git a/src/libtorrent/src/peer_connection.cpp b/src/libtorrent/src/peer_connection.cpp
new file mode 100644
index 0000000..3e3d606
--- /dev/null
+++ b/src/libtorrent/src/peer_connection.cpp
@@ -0,0 +1,3209 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <iostream>
+#include <iomanip>
+#include <limits>
+#include <boost/bind.hpp>
+
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/identify_client.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/alert_types.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/file.hpp"
+#include "libtorrent/version.hpp"
+#include "libtorrent/extensions.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+#include "libtorrent/policy.hpp"
+#include "libtorrent/socket_type.hpp"
+#include "libtorrent/assert.hpp"
+
+using boost::bind;
+using boost::shared_ptr;
+using libtorrent::aux::session_impl;
+
+namespace libtorrent
+{
+
+ // outbound connection
+ peer_connection::peer_connection(
+ session_impl& ses
+ , boost::weak_ptr<torrent> tor
+ , shared_ptr<socket_type> s
+ , tcp::endpoint const& remote
+ , policy::peer* peerinfo)
+ :
+#ifndef NDEBUG
+ m_last_choke(time_now() - hours(1))
+ ,
+#endif
+ m_ses(ses)
+ , m_max_out_request_queue(m_ses.settings().max_out_request_queue)
+ , m_timeout(m_ses.settings().peer_timeout)
+ , m_last_piece(time_now())
+ , m_last_request(time_now())
+ , m_last_incoming_request(min_time())
+ , m_last_unchoke(min_time())
+ , m_packet_size(0)
+ , m_recv_pos(0)
+ , m_reading_bytes(0)
+ , m_last_receive(time_now())
+ , m_last_sent(time_now())
+ , m_socket(s)
+ , m_remote(remote)
+ , m_torrent(tor)
+ , m_active(true)
+ , m_peer_interested(false)
+ , m_peer_choked(true)
+ , m_interesting(false)
+ , m_choked(true)
+ , m_failed(false)
+ , m_ignore_bandwidth_limits(false)
+ , m_have_all(false)
+ , m_num_pieces(0)
+ , m_desired_queue_size(2)
+ , m_free_upload(0)
+ , m_assume_fifo(false)
+ , m_num_invalid_requests(0)
+ , m_disconnecting(false)
+ , m_became_uninterested(time_now())
+ , m_became_uninteresting(time_now())
+ , m_connecting(true)
+ , m_queued(true)
+ , m_writing(false)
+ , m_reading(false)
+ , m_prefer_whole_pieces(false)
+ , m_request_large_blocks(false)
+ , m_priority(1)
+ , m_upload_limit(bandwidth_limit::inf)
+ , m_download_limit(bandwidth_limit::inf)
+ , m_peer_info(peerinfo)
+ , m_speed(slow)
+ , m_connection_ticket(-1)
+ , m_remote_bytes_dled(0)
+ , m_remote_dl_rate(0)
+ , m_remote_dl_update(time_now())
+ , m_outstanding_writing_bytes(0)
+ , m_fast_reconnect(false)
+#ifndef NDEBUG
+ , m_in_constructor(true)
+#endif
+ {
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ std::fill(m_country, m_country + 2, 0);
+#endif
+#ifdef TORRENT_VERBOSE_LOGGING
+ m_logger = m_ses.create_log(m_remote.address().to_string() + "_"
+ + boost::lexical_cast<std::string>(m_remote.port()), m_ses.listen_port());
+ (*m_logger) << "*** OUTGOING CONNECTION\n";
+#endif
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+ std::fill(m_peer_id.begin(), m_peer_id.end(), 0);
+
+ if (t->ready_for_connections())
+ init();
+ }
+
+ // incoming connection
+ peer_connection::peer_connection(
+ session_impl& ses
+ , boost::shared_ptr<socket_type> s
+ , policy::peer* peerinfo)
+ :
+#ifndef NDEBUG
+ m_last_choke(time_now() - hours(1))
+ ,
+#endif
+ m_ses(ses)
+ , m_max_out_request_queue(m_ses.settings().max_out_request_queue)
+ , m_timeout(m_ses.settings().peer_timeout)
+ , m_last_piece(time_now())
+ , m_last_request(time_now())
+ , m_last_incoming_request(min_time())
+ , m_last_unchoke(min_time())
+ , m_packet_size(0)
+ , m_recv_pos(0)
+ , m_reading_bytes(0)
+ , m_last_receive(time_now())
+ , m_last_sent(time_now())
+ , m_socket(s)
+ , m_active(false)
+ , m_peer_interested(false)
+ , m_peer_choked(true)
+ , m_interesting(false)
+ , m_choked(true)
+ , m_failed(false)
+ , m_ignore_bandwidth_limits(false)
+ , m_have_all(false)
+ , m_num_pieces(0)
+ , m_desired_queue_size(2)
+ , m_free_upload(0)
+ , m_assume_fifo(false)
+ , m_num_invalid_requests(0)
+ , m_disconnecting(false)
+ , m_became_uninterested(time_now())
+ , m_became_uninteresting(time_now())
+ , m_connecting(false)
+ , m_queued(false)
+ , m_writing(false)
+ , m_reading(false)
+ , m_prefer_whole_pieces(false)
+ , m_request_large_blocks(false)
+ , m_priority(1)
+ , m_upload_limit(bandwidth_limit::inf)
+ , m_download_limit(bandwidth_limit::inf)
+ , m_peer_info(peerinfo)
+ , m_speed(slow)
+ , m_connection_ticket(-1)
+ , m_remote_bytes_dled(0)
+ , m_remote_dl_rate(0)
+ , m_remote_dl_update(time_now())
+ , m_outstanding_writing_bytes(0)
+ , m_fast_reconnect(false)
+#ifndef NDEBUG
+ , m_in_constructor(true)
+#endif
+ {
+ tcp::socket::non_blocking_io ioc(true);
+ m_socket->io_control(ioc);
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ std::fill(m_country, m_country + 2, 0);
+#endif
+ m_remote = m_socket->remote_endpoint();
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ TORRENT_ASSERT(m_socket->remote_endpoint() == remote());
+ m_logger = m_ses.create_log(remote().address().to_string() + "_"
+ + boost::lexical_cast<std::string>(remote().port()), m_ses.listen_port());
+ (*m_logger) << "*** INCOMING CONNECTION\n";
+#endif
+
+ std::fill(m_peer_id.begin(), m_peer_id.end(), 0);
+ }
+
+ void peer_connection::update_interest()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ bool interested = false;
+ const std::vector<bool>& we_have = t->pieces();
+ for (int j = 0; j != (int)we_have.size(); ++j)
+ {
+ if (!we_have[j]
+ && t->piece_priority(j) > 0
+ && m_have_piece[j])
+ {
+ interested = true;
+ break;
+ }
+ }
+ try
+ {
+ if (!interested)
+ send_not_interested();
+ else
+ t->get_policy().peer_is_interesting(*this);
+ }
+ // may throw an asio error if socket has disconnected
+ catch (std::exception&) {}
+
+ TORRENT_ASSERT(is_interesting() == interested);
+ }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void peer_connection::add_extension(boost::shared_ptr<peer_plugin> ext)
+ {
+ m_extensions.push_back(ext);
+ }
+#endif
+
+ void peer_connection::send_allowed_set()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ int num_allowed_pieces = m_ses.settings().allowed_fast_set_size;
+ int num_pieces = t->torrent_file().num_pieces();
+
+ if (num_allowed_pieces >= num_pieces)
+ {
+ for (int i = 0; i < num_pieces; ++i)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> ALLOWED_FAST [ " << i << " ]\n";
+#endif
+ write_allow_fast(i);
+ m_accept_fast.insert(i);
+ }
+ return;
+ }
+
+ std::string x;
+ address const& addr = m_remote.address();
+ if (addr.is_v4())
+ {
+ address_v4::bytes_type bytes = addr.to_v4().to_bytes();
+ x.assign((char*)&bytes[0], bytes.size());
+ }
+ else
+ {
+ address_v6::bytes_type bytes = addr.to_v6().to_bytes();
+ x.assign((char*)&bytes[0], bytes.size());
+ }
+ x.append((char*)&t->torrent_file().info_hash()[0], 20);
+
+ sha1_hash hash = hasher(&x[0], x.size()).final();
+ for (;;)
+ {
+ char* p = (char*)&hash[0];
+ for (int i = 0; i < 5; ++i)
+ {
+ int piece = detail::read_uint32(p) % num_pieces;
+ if (m_accept_fast.find(piece) == m_accept_fast.end())
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> ALLOWED_FAST [ " << piece << " ]\n";
+#endif
+ write_allow_fast(piece);
+ m_accept_fast.insert(piece);
+ if (int(m_accept_fast.size()) >= num_allowed_pieces
+ || int(m_accept_fast.size()) == num_pieces) return;
+ }
+ }
+ hash = hasher((char*)&hash[0], 20).final();
+ }
+ }
+
+ void peer_connection::init()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+ TORRENT_ASSERT(t->valid_metadata());
+ TORRENT_ASSERT(t->ready_for_connections());
+
+ m_have_piece.resize(t->torrent_file().num_pieces(), m_have_all);
+
+ // now that we have a piece_picker,
+ // update it with this peers pieces
+
+ int num_pieces = std::count(m_have_piece.begin(), m_have_piece.end(), true);
+ if (num_pieces == int(m_have_piece.size()))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " *** THIS IS A SEED ***\n";
+#endif
+ // if this is a web seed. we don't have a peer_info struct
+ if (m_peer_info) m_peer_info->seed = true;
+ // if we're a seed too, disconnect
+ if (t->is_finished())
+ {
+ throw std::runtime_error("seed to seed connection redundant, disconnecting");
+ }
+ m_num_pieces = num_pieces;
+ t->peer_has_all();
+ if (!t->is_finished())
+ t->get_policy().peer_is_interesting(*this);
+ return;
+ }
+
+ m_num_pieces = num_pieces;
+ // if we're a seed, we don't keep track of piece availability
+ if (!t->is_seed())
+ {
+ bool interesting = false;
+ for (int i = 0; i < int(m_have_piece.size()); ++i)
+ {
+ if (m_have_piece[i])
+ {
+ t->peer_has(i);
+ // if the peer has a piece and we don't, the peer is interesting
+ if (!t->have_piece(i)
+ && t->picker().piece_priority(i) != 0)
+ interesting = true;
+ }
+ }
+ if (interesting)
+ t->get_policy().peer_is_interesting(*this);
+ }
+ }
+
+ peer_connection::~peer_connection()
+ {
+// INVARIANT_CHECK;
+ TORRENT_ASSERT(!m_in_constructor);
+ TORRENT_ASSERT(m_disconnecting);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ if (m_logger)
+ {
+ (*m_logger) << time_now_string()
+ << " *** CONNECTION CLOSED\n";
+ }
+#endif
+#ifndef NDEBUG
+ if (m_peer_info)
+ TORRENT_ASSERT(m_peer_info->connection == 0);
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+#endif
+ }
+
+ void peer_connection::fast_reconnect(bool r)
+ {
+ if (peer_info_struct() && peer_info_struct()->fast_reconnects > 1) return;
+ m_fast_reconnect = r;
+ peer_info_struct()->connected = time_now()
+ - seconds(m_ses.settings().min_reconnect_time
+ * m_ses.settings().max_failcount);
+ if (peer_info_struct()) ++peer_info_struct()->fast_reconnects;
+ }
+
+ void peer_connection::announce_piece(int index)
+ {
+ // dont announce during handshake
+ if (in_handshake()) return;
+
+ // remove suggested pieces that we have
+ std::vector<int>::iterator i = std::find(
+ m_suggested_pieces.begin(), m_suggested_pieces.end(), index);
+ if (i != m_suggested_pieces.end()) m_suggested_pieces.erase(i);
+
+ // optimization, don't send have messages
+ // to peers that already have the piece
+ if (!m_ses.settings().send_redundant_have
+ && has_piece(index)) return;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> HAVE [ piece: " << index << "]\n";
+#endif
+ write_have(index);
+#ifndef NDEBUG
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+ TORRENT_ASSERT(t->have_piece(index));
+#endif
+ }
+
+ bool peer_connection::has_piece(int i) const
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+ TORRENT_ASSERT(t->valid_metadata());
+ TORRENT_ASSERT(i >= 0);
+ TORRENT_ASSERT(i < t->torrent_file().num_pieces());
+ return m_have_piece[i];
+ }
+
+ std::deque<piece_block> const& peer_connection::request_queue() const
+ {
+ return m_request_queue;
+ }
+
+ std::deque<piece_block> const& peer_connection::download_queue() const
+ {
+ return m_download_queue;
+ }
+
+ std::deque<peer_request> const& peer_connection::upload_queue() const
+ {
+ return m_requests;
+ }
+
+ void peer_connection::add_stat(size_type downloaded, size_type uploaded)
+ {
+ m_statistics.add_stat(downloaded, uploaded);
+ }
+
+ std::vector<bool> const& peer_connection::get_bitfield() const
+ {
+ return m_have_piece;
+ }
+
+ void peer_connection::received_valid_data(int index)
+ {
+ INVARIANT_CHECK;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
+ }
+#endif
+ }
+
+ void peer_connection::received_invalid_data(int index)
+ {
+ INVARIANT_CHECK;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { (*i)->on_piece_failed(index); } catch (std::exception&) {}
+ }
+#endif
+
+ if (peer_info_struct())
+ {
+ peer_info_struct()->on_parole = true;
+ ++peer_info_struct()->hashfails;
+ int& trust_points = peer_info_struct()->trust_points;
+
+ // we decrease more than we increase, to keep the
+ // allowed failed/passed ratio low.
+ // TODO: make this limit user settable
+ trust_points -= 2;
+ if (trust_points < -7) trust_points = -7;
+ }
+ }
+
+ size_type peer_connection::total_free_upload() const
+ {
+ return m_free_upload;
+ }
+
+ void peer_connection::add_free_upload(size_type free_upload)
+ {
+ INVARIANT_CHECK;
+
+ m_free_upload += free_upload;
+ }
+
+ // verifies a piece to see if it is valid (is within a valid range)
+ // and if it can correspond to a request generated by libtorrent.
+ bool peer_connection::verify_piece(const peer_request& p) const
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ TORRENT_ASSERT(t->valid_metadata());
+ torrent_info const& ti = t->torrent_file();
+
+ return p.piece >= 0
+ && p.piece < t->torrent_file().num_pieces()
+ && p.length > 0
+ && p.start >= 0
+ && (p.length == t->block_size()
+ || (p.length < t->block_size()
+ && p.piece == ti.num_pieces()-1
+ && p.start + p.length == ti.piece_size(p.piece))
+ || (m_request_large_blocks
+ && p.length <= ti.piece_length() * m_prefer_whole_pieces == 0 ?
+ 1 : m_prefer_whole_pieces))
+ && p.piece * size_type(ti.piece_length()) + p.start + p.length
+ <= ti.total_size()
+ && (p.start % t->block_size() == 0);
+ }
+
+ void peer_connection::attach_to_torrent(sha1_hash const& ih)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_disconnecting);
+ TORRENT_ASSERT(m_torrent.expired());
+ boost::weak_ptr<torrent> wpt = m_ses.find_torrent(ih);
+ boost::shared_ptr<torrent> t = wpt.lock();
+
+ if (t && t->is_aborted())
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " *** the torrent has been aborted\n";
+#endif
+ t.reset();
+ }
+
+ if (!t)
+ {
+ // we couldn't find the torrent!
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " *** couldn't find a torrent with the given info_hash: " << ih << "\n";
+ (*m_logger) << " torrents:\n";
+ session_impl::torrent_map const& torrents = m_ses.m_torrents;
+ for (session_impl::torrent_map::const_iterator i = torrents.begin()
+ , end(torrents.end()); i != end; ++i)
+ {
+ (*m_logger) << " " << i->second->torrent_file().info_hash() << "\n";
+ }
+#endif
+ throw std::runtime_error("got info-hash that is not in our session");
+ }
+
+ if (t->is_paused())
+ {
+ // paused torrents will not accept
+ // incoming connections
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " rejected connection to paused torrent\n";
+#endif
+ throw std::runtime_error("connection rejected by paused torrent");
+ }
+
+ TORRENT_ASSERT(m_torrent.expired());
+ // check to make sure we don't have another connection with the same
+ // info_hash and peer_id. If we do. close this connection.
+ t->attach_peer(this);
+ if (m_disconnecting) return;
+ m_torrent = wpt;
+
+ TORRENT_ASSERT(!m_torrent.expired());
+
+ // if the torrent isn't ready to accept
+ // connections yet, we'll have to wait with
+ // our initialization
+ if (t->ready_for_connections()) init();
+
+ TORRENT_ASSERT(!m_torrent.expired());
+
+ // assume the other end has no pieces
+ // if we don't have valid metadata yet,
+ // leave the vector unallocated
+ TORRENT_ASSERT(m_num_pieces == 0);
+ std::fill(m_have_piece.begin(), m_have_piece.end(), false);
+ TORRENT_ASSERT(!m_torrent.expired());
+ }
+
+ // message handlers
+
+ // -----------------------------
+ // --------- KEEPALIVE ---------
+ // -----------------------------
+
+ void peer_connection::incoming_keepalive()
+ {
+ INVARIANT_CHECK;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== KEEPALIVE\n";
+#endif
+ }
+
+ // -----------------------------
+ // ----------- CHOKE -----------
+ // -----------------------------
+
+ void peer_connection::incoming_choke()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_choke()) return;
+ }
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== CHOKE\n";
+#endif
+ m_peer_choked = true;
+ t->get_policy().choked(*this);
+
+ if (peer_info_struct() == 0 || !peer_info_struct()->on_parole)
+ {
+ // if the peer is not in parole mode, clear the queued
+ // up block requests
+ if (!t->is_seed())
+ {
+ piece_picker& p = t->picker();
+ for (std::deque<piece_block>::const_iterator i = m_request_queue.begin()
+ , end(m_request_queue.end()); i != end; ++i)
+ {
+ // since this piece was skipped, clear it and allow it to
+ // be requested from other peers
+ p.abort_download(*i);
+ }
+ }
+ m_request_queue.clear();
+ }
+ }
+
+ bool match_request(peer_request const& r, piece_block const& b, int block_size)
+ {
+ if (b.piece_index != r.piece) return false;
+ if (b.block_index != r.start / block_size) return false;
+ if (r.start % block_size != 0) return false;
+ return true;
+ }
+
+ // -----------------------------
+ // -------- REJECT PIECE -------
+ // -----------------------------
+
+ void peer_connection::incoming_reject_request(peer_request const& r)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_reject(r)) return;
+ }
+#endif
+
+ std::deque<piece_block>::iterator i = std::find_if(
+ m_download_queue.begin(), m_download_queue.end()
+ , bind(match_request, boost::cref(r), _1, t->block_size()));
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== REJECT_PIECE [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
+#endif
+
+ piece_block b(-1, 0);
+ if (i != m_download_queue.end())
+ {
+ b = *i;
+ m_download_queue.erase(i);
+
+ // if the peer is in parole mode, keep the request
+ if (peer_info_struct() && peer_info_struct()->on_parole)
+ {
+ m_request_queue.push_front(b);
+ }
+ else if (!t->is_seed())
+ {
+ piece_picker& p = t->picker();
+ p.abort_download(b);
+ }
+ }
+#ifdef TORRENT_VERBOSE_LOGGING
+ else
+ {
+ (*m_logger) << time_now_string()
+ << " *** PIECE NOT IN REQUEST QUEUE\n";
+ }
+#endif
+ if (has_peer_choked())
+ {
+ // if we're choked and we got a rejection of
+ // a piece in the allowed fast set, remove it
+ // from the allow fast set.
+ std::vector<int>::iterator i = std::find(
+ m_allowed_fast.begin(), m_allowed_fast.end(), r.piece);
+ if (i != m_allowed_fast.end()) m_allowed_fast.erase(i);
+ }
+ else
+ {
+ std::vector<int>::iterator i = std::find(m_suggested_pieces.begin()
+ , m_suggested_pieces.end(), r.piece);
+ if (i != m_suggested_pieces.end())
+ m_suggested_pieces.erase(i);
+ }
+
+ if (m_request_queue.empty())
+ {
+ if (m_download_queue.size() < 2)
+ {
+ request_a_block(*t, *this);
+ }
+ send_block_requests();
+ }
+ }
+
+ // -----------------------------
+ // ------- SUGGEST PIECE -------
+ // -----------------------------
+
+ void peer_connection::incoming_suggest(int index)
+ {
+ INVARIANT_CHECK;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== SUGGEST_PIECE [ piece: " << index << " ]\n";
+#endif
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ if (!t) return;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_suggest(index)) return;
+ }
+#endif
+
+ if (t->have_piece(index)) return;
+
+ if (m_suggested_pieces.size() > 9)
+ m_suggested_pieces.erase(m_suggested_pieces.begin());
+ m_suggested_pieces.push_back(index);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ** SUGGEST_PIECE [ piece: " << index << " added to set: " << m_suggested_pieces.size() << " ]\n";
+#endif
+ }
+
+ // -----------------------------
+ // ---------- UNCHOKE ----------
+ // -----------------------------
+
+ void peer_connection::incoming_unchoke()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_unchoke()) return;
+ }
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== UNCHOKE\n";
+#endif
+ m_peer_choked = false;
+ t->get_policy().unchoked(*this);
+ }
+
+ // -----------------------------
+ // -------- INTERESTED ---------
+ // -----------------------------
+
+ void peer_connection::incoming_interested()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_interested()) return;
+ }
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== INTERESTED\n";
+#endif
+ m_peer_interested = true;
+ t->get_policy().interested(*this);
+ }
+
+ // -----------------------------
+ // ------ NOT INTERESTED -------
+ // -----------------------------
+
+ void peer_connection::incoming_not_interested()
+ {
+ INVARIANT_CHECK;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_not_interested()) return;
+ }
+#endif
+
+ m_became_uninterested = time_now();
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== NOT_INTERESTED\n";
+#endif
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ m_peer_interested = false;
+ t->get_policy().not_interested(*this);
+ }
+
+ // -----------------------------
+ // ----------- HAVE ------------
+ // -----------------------------
+
+ void peer_connection::incoming_have(int index)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_have(index)) return;
+ }
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== HAVE [ piece: " << index << "]\n";
+#endif
+
+ // if we got an invalid message, abort
+ if (index >= (int)m_have_piece.size() || index < 0)
+ throw protocol_error("got 'have'-message with higher index "
+ "than the number of pieces");
+
+ if (m_have_piece[index])
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " got redundant HAVE message for index: " << index << "\n";
+#endif
+ }
+ else
+ {
+ m_have_piece[index] = true;
+
+ // only update the piece_picker if
+ // we have the metadata and if
+ // we're not a seed (in which case
+ // we won't have a piece picker)
+ if (t->valid_metadata())
+ {
+ ++m_num_pieces;
+ t->peer_has(index);
+
+ if (!t->have_piece(index)
+ && !t->is_seed()
+ && !is_interesting()
+ && t->picker().piece_priority(index) != 0)
+ t->get_policy().peer_is_interesting(*this);
+
+ // this will disregard all have messages we get within
+ // the first two seconds. Since some clients implements
+ // lazy bitfields, these will not be reliable to use
+ // for an estimated peer download rate.
+ if (!peer_info_struct() || time_now() - peer_info_struct()->connected > seconds(2))
+ {
+ // update bytes downloaded since last timer
+ m_remote_bytes_dled += t->torrent_file().piece_size(index);
+ }
+ }
+
+ if (is_seed())
+ {
+ TORRENT_ASSERT(m_peer_info);
+ m_peer_info->seed = true;
+ if (t->is_finished())
+ {
+ throw protocol_error("seed to seed connection redundant, disconnecting");
+ }
+ }
+ }
+ }
+
+ // -----------------------------
+ // --------- BITFIELD ----------
+ // -----------------------------
+
+ void peer_connection::incoming_bitfield(std::vector<bool> const& bitfield)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_bitfield(bitfield)) return;
+ }
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== BITFIELD ";
+
+ for (int i = 0; i < int(bitfield.size()); ++i)
+ {
+ if (bitfield[i]) (*m_logger) << "1";
+ else (*m_logger) << "0";
+ }
+ (*m_logger) << "\n";
+#endif
+
+ // if we don't have the metedata, we cannot
+ // verify the bitfield size
+ if (t->valid_metadata()
+ && (bitfield.size() / 8) != (m_have_piece.size() / 8))
+ throw protocol_error("got bitfield with invalid size: "
+ + boost::lexical_cast<std::string>(bitfield.size() / 8)
+ + "bytes. expected: "
+ + boost::lexical_cast<std::string>(m_have_piece.size() / 8)
+ + "bytes");
+
+ // if we don't have metadata yet
+ // just remember the bitmask
+ // don't update the piecepicker
+ // (since it doesn't exist yet)
+ if (!t->ready_for_connections())
+ {
+ m_have_piece = bitfield;
+ m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true);
+ if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bitfield.size()));
+ return;
+ }
+
+ TORRENT_ASSERT(t->valid_metadata());
+
+ int num_pieces = std::count(bitfield.begin(), bitfield.end(), true);
+ if (num_pieces == int(m_have_piece.size()))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " *** THIS IS A SEED ***\n";
+#endif
+ // if this is a web seed. we don't have a peer_info struct
+ if (m_peer_info) m_peer_info->seed = true;
+ // if we're a seed too, disconnect
+ if (t->is_finished())
+ {
+ throw protocol_error("seed to seed connection redundant, disconnecting");
+ }
+
+ std::fill(m_have_piece.begin(), m_have_piece.end(), true);
+ m_num_pieces = num_pieces;
+ t->peer_has_all();
+ if (!t->is_finished())
+ t->get_policy().peer_is_interesting(*this);
+ return;
+ }
+
+ // let the torrent know which pieces the
+ // peer has
+ // if we're a seed, we don't keep track of piece availability
+ if (!t->is_seed())
+ {
+ bool interesting = false;
+ for (int i = 0; i < (int)m_have_piece.size(); ++i)
+ {
+ bool have = bitfield[i];
+ if (have && !m_have_piece[i])
+ {
+ m_have_piece[i] = true;
+ ++m_num_pieces;
+ t->peer_has(i);
+ if (!t->have_piece(i) && t->picker().piece_priority(i) != 0)
+ interesting = true;
+ }
+ else if (!have && m_have_piece[i])
+ {
+ // this should probably not be allowed
+ m_have_piece[i] = false;
+ --m_num_pieces;
+ t->peer_lost(i);
+ }
+ }
+
+ if (interesting) t->get_policy().peer_is_interesting(*this);
+ }
+ else
+ {
+ for (int i = 0; i < (int)m_have_piece.size(); ++i)
+ {
+ bool have = bitfield[i];
+ if (have && !m_have_piece[i])
+ {
+ m_have_piece[i] = true;
+ ++m_num_pieces;
+ }
+ else if (!have && m_have_piece[i])
+ {
+ // this should probably not be allowed
+ m_have_piece[i] = false;
+ --m_num_pieces;
+ }
+ }
+ }
+ }
+
+ // -----------------------------
+ // ---------- REQUEST ----------
+ // -----------------------------
+
+ void peer_connection::incoming_request(peer_request const& r)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_request(r)) return;
+ }
+#endif
+
+ if (!t->valid_metadata())
+ {
+ // if we don't have valid metadata yet,
+ // we shouldn't get a request
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== UNEXPECTED_REQUEST [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " | "
+ "i: " << m_peer_interested << " | "
+ "t: " << t->torrent_file().piece_size(r.piece) << " | "
+ "n: " << t->torrent_file().num_pieces() << " ]\n";
+#endif
+ write_reject_request(r);
+ return;
+ }
+
+ if (int(m_requests.size()) > m_ses.settings().max_allowed_in_request_queue)
+ {
+ // don't allow clients to abuse our
+ // memory consumption.
+ // ignore requests if the client
+ // is making too many of them.
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== TOO MANY REQUESTS [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " | "
+ "i: " << m_peer_interested << " | "
+ "t: " << t->torrent_file().piece_size(r.piece) << " | "
+ "n: " << t->torrent_file().num_pieces() << " ]\n";
+
+ (*m_logger) << time_now_string()
+ << " ==> REJECT_PIECE [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " ]\n";
+
+ (*m_logger) << time_now_string()
+ << " ==> REJECT_PIECE [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " ]\n";
+#endif
+ write_reject_request(r);
+ return;
+ }
+
+ // make sure this request
+ // is legal and that the peer
+ // is not choked
+ if (r.piece >= 0
+ && r.piece < t->torrent_file().num_pieces()
+ && t->have_piece(r.piece)
+ && r.start >= 0
+ && r.start < t->torrent_file().piece_size(r.piece)
+ && r.length > 0
+ && r.length + r.start <= t->torrent_file().piece_size(r.piece)
+ && m_peer_interested
+ && r.length <= t->block_size())
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== REQUEST [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
+#endif
+ // if we have choked the client
+ // ignore the request
+ if (m_choked && m_accept_fast.find(r.piece) == m_accept_fast.end())
+ {
+ write_reject_request(r);
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " *** REJECTING REQUEST [ peer choked and piece not in allowed fast set ]\n";
+ (*m_logger) << time_now_string()
+ << " ==> REJECT_PIECE [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " ]\n";
+#endif
+ }
+ else
+ {
+ m_requests.push_back(r);
+ m_last_incoming_request = time_now();
+ fill_send_buffer();
+ }
+ }
+ else
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== INVALID_REQUEST [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " | "
+ "i: " << m_peer_interested << " | "
+ "t: " << t->torrent_file().piece_size(r.piece) << " | "
+ "n: " << t->torrent_file().num_pieces() << " | "
+ "h: " << t->have_piece(r.piece) << " | "
+ "block_limit: " << t->block_size() << " ]\n";
+
+ (*m_logger) << time_now_string()
+ << " ==> REJECT_PIECE [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " ]\n";
+#endif
+
+ write_reject_request(r);
+ ++m_num_invalid_requests;
+
+ if (t->alerts().should_post(alert::debug))
+ {
+ t->alerts().post_alert(invalid_request_alert(
+ r
+ , t->get_handle()
+ , m_remote
+ , m_peer_id
+ , "peer sent an illegal piece request"));
+ }
+ }
+ }
+
+ void peer_connection::incoming_piece_fragment()
+ {
+ m_last_piece = time_now();
+ }
+
+#ifndef NDEBUG
+ struct check_postcondition
+ {
+ check_postcondition(boost::shared_ptr<torrent> const& t_
+ , bool init_check = true): t(t_) { if (init_check) check(); }
+
+ ~check_postcondition() { check(); }
+
+ void check()
+ {
+ if (!t->is_seed())
+ {
+ const int blocks_per_piece = static_cast<int>(
+ t->torrent_file().piece_length() / t->block_size());
+
+ std::vector<piece_picker::downloading_piece> const& dl_queue
+ = t->picker().get_download_queue();
+
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i =
+ dl_queue.begin(); i != dl_queue.end(); ++i)
+ {
+ TORRENT_ASSERT(i->finished <= blocks_per_piece);
+ }
+ }
+ }
+
+ shared_ptr<torrent> t;
+ };
+#endif
+
+
+ // -----------------------------
+ // ----------- PIECE -----------
+ // -----------------------------
+
+ void peer_connection::incoming_piece(peer_request const& p, char const* data)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_piece(p, data)) return;
+ }
+#endif
+
+#ifndef NDEBUG
+ check_postcondition post_checker_(t);
+ t->check_invariant();
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== PIECE [ piece: " << p.piece << " | "
+ "s: " << p.start << " | "
+ "l: " << p.length << " | "
+ "ds: " << statistics().download_rate() << " | "
+ "qs: " << m_desired_queue_size << " ]\n";
+#endif
+
+ if (!verify_piece(p))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== INVALID_PIECE [ piece: " << p.piece << " | "
+ "start: " << p.start << " | "
+ "length: " << p.length << " ]\n";
+#endif
+ throw protocol_error("got invalid piece packet");
+ }
+
+ // if we're already seeding, don't bother,
+ // just ignore it
+ if (t->is_seed())
+ {
+ t->received_redundant_data(p.length);
+ return;
+ }
+
+ piece_picker& picker = t->picker();
+ piece_manager& fs = t->filesystem();
+
+ std::vector<piece_block> finished_blocks;
+ piece_block block_finished(p.piece, p.start / t->block_size());
+ TORRENT_ASSERT(p.start % t->block_size() == 0);
+ TORRENT_ASSERT(p.length == t->block_size()
+ || p.length == t->torrent_file().total_size() % t->block_size());
+
+ std::deque<piece_block>::iterator b
+ = std::find(
+ m_download_queue.begin()
+ , m_download_queue.end()
+ , block_finished);
+
+ if (b != m_download_queue.end())
+ {
+ if (m_assume_fifo)
+ {
+ for (std::deque<piece_block>::iterator i = m_download_queue.begin();
+ i != b; ++i)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " *** SKIPPED_PIECE [ piece: " << i->piece_index << " | "
+ "b: " << i->block_index << " ] ***\n";
+#endif
+ // since this piece was skipped, clear it and allow it to
+ // be requested from other peers
+ // TODO: send cancel?
+ picker.abort_download(*i);
+ }
+
+ // remove the request that just finished
+ // from the download queue plus the
+ // skipped blocks.
+ m_download_queue.erase(m_download_queue.begin(), b);
+ b = m_download_queue.begin();
+ TORRENT_ASSERT(*b == block_finished);
+ }
+ }
+ else
+ {
+ if (t->alerts().should_post(alert::debug))
+ {
+ t->alerts().post_alert(
+ peer_error_alert(
+ m_remote
+ , m_peer_id
+ , "got a block that was not in the request queue"));
+ }
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " *** The block we just got was not in the "
+ "request queue ***\n";
+#endif
+ t->received_redundant_data(p.length);
+ request_a_block(*t, *this);
+ send_block_requests();
+ return;
+ }
+
+ // if the block we got is already finished, then ignore it
+ if (picker.is_downloaded(block_finished))
+ {
+ t->received_redundant_data(p.length);
+
+ m_download_queue.erase(b);
+ request_a_block(*t, *this);
+ send_block_requests();
+ return;
+ }
+
+ fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete
+ , self(), _1, _2, p, t));
+ m_outstanding_writing_bytes += p.length;
+ TORRENT_ASSERT(!m_reading);
+ m_download_queue.erase(b);
+
+ // did we request this block from any other peers?
+ bool multi = picker.num_peers(block_finished) > 1;
+
+ picker.mark_as_writing(block_finished, peer_info_struct());
+
+ // if we requested this block from other peers, cancel it now
+ if (multi) t->cancel_block(block_finished);
+
+#ifndef NDEBUG
+ t->check_invariant();
+#endif
+ request_a_block(*t, *this);
+ send_block_requests();
+ }
+
+ void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j
+ , peer_request p, boost::shared_ptr<torrent> t)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ m_outstanding_writing_bytes -= p.length;
+ TORRENT_ASSERT(m_outstanding_writing_bytes >= 0);
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << time_now_string() << " *** DISK_WRITE_COMPLETE [ p: "
+ << p.piece << " o: " << p.start << " ]\n";
+#endif
+ // in case the outstanding bytes just dropped down
+ // to allow to receive more data
+ setup_receive();
+
+ piece_block block_finished(p.piece, p.start / t->block_size());
+
+ if (ret == -1 || !t)
+ {
+ if (t->has_picker()) t->picker().abort_download(block_finished);
+
+ if (!t)
+ {
+ m_ses.connection_failed(self(), remote(), j.str.c_str());
+ return;
+ }
+
+ if (t->alerts().should_post(alert::fatal))
+ {
+ std::string err = "torrent paused: disk write error, " + j.str;
+ t->alerts().post_alert(file_error_alert(t->get_handle(), err));
+ }
+ t->pause();
+ return;
+ }
+
+ if (t->is_seed()) return;
+
+ piece_picker& picker = t->picker();
+
+ TORRENT_ASSERT(p.piece == j.piece);
+ TORRENT_ASSERT(p.start == j.offset);
+ picker.mark_as_finished(block_finished, peer_info_struct());
+ if (t->alerts().should_post(alert::debug))
+ {
+ t->alerts().post_alert(block_finished_alert(t->get_handle(),
+ block_finished.block_index, block_finished.piece_index, "block finished"));
+ }
+
+#ifndef NDEBUG
+ try
+ {
+#endif
+
+ // did we just finish the piece?
+ if (picker.is_piece_finished(p.piece))
+ {
+#ifndef NDEBUG
+ check_postcondition post_checker2_(t, false);
+#endif
+ t->async_verify_piece(p.piece, bind(&torrent::piece_finished, t
+ , p.piece, _1));
+ }
+
+#ifndef NDEBUG
+ }
+ catch (std::exception const& e)
+ {
+ std::cerr << e.what() << std::endl;
+ TORRENT_ASSERT(false);
+ }
+#endif
+
+ if (!t->is_seed() && !m_torrent.expired())
+ {
+ // this is a free function defined in policy.cpp
+ request_a_block(*t, *this);
+ send_block_requests();
+ }
+
+ }
+
+ // -----------------------------
+ // ---------- CANCEL -----------
+ // -----------------------------
+
+ void peer_connection::incoming_cancel(peer_request const& r)
+ {
+ INVARIANT_CHECK;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_cancel(r)) return;
+ }
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== CANCEL [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
+#endif
+
+ std::deque<peer_request>::iterator i
+ = std::find(m_requests.begin(), m_requests.end(), r);
+
+ if (i != m_requests.end())
+ {
+ m_requests.erase(i);
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> REJECT_PIECE [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " ]\n";
+#endif
+ write_reject_request(r);
+ }
+ else
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** GOT CANCEL NOT IN THE QUEUE\n";
+#endif
+ }
+ }
+
+ // -----------------------------
+ // --------- DHT PORT ----------
+ // -----------------------------
+
+ void peer_connection::incoming_dht_port(int listen_port)
+ {
+ INVARIANT_CHECK;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " <== DHT_PORT [ p: " << listen_port << " ]\n";
+#endif
+#ifndef TORRENT_DISABLE_DHT
+ m_ses.add_dht_node(udp::endpoint(
+ m_remote.address(), listen_port));
+#endif
+ }
+
+ // -----------------------------
+ // --------- HAVE ALL ----------
+ // -----------------------------
+
+ void peer_connection::incoming_have_all()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== HAVE_ALL\n";
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_have_all()) return;
+ }
+#endif
+
+ m_have_all = true;
+
+ if (m_peer_info) m_peer_info->seed = true;
+
+ // if we don't have metadata yet
+ // just remember the bitmask
+ // don't update the piecepicker
+ // (since it doesn't exist yet)
+ if (!t->ready_for_connections())
+ {
+ // TODO: this might need something more
+ // so that once we have the metadata
+ // we can construct a full bitfield
+ return;
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << " *** THIS IS A SEED ***\n";
+#endif
+
+ // if we're a seed too, disconnect
+ if (t->is_finished())
+ throw protocol_error("seed to seed connection redundant, disconnecting");
+
+ TORRENT_ASSERT(!m_have_piece.empty());
+ std::fill(m_have_piece.begin(), m_have_piece.end(), true);
+ m_num_pieces = m_have_piece.size();
+
+ t->peer_has_all();
+ if (!t->is_finished())
+ t->get_policy().peer_is_interesting(*this);
+ }
+
+ // -----------------------------
+ // --------- HAVE NONE ---------
+ // -----------------------------
+
+ void peer_connection::incoming_have_none()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== HAVE_NONE\n";
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_have_none()) return;
+ }
+#endif
+
+ if (m_peer_info) m_peer_info->seed = false;
+ TORRENT_ASSERT(!m_have_piece.empty() || !t->ready_for_connections());
+ }
+
+ // -----------------------------
+ // ------- ALLOWED FAST --------
+ // -----------------------------
+
+ void peer_connection::incoming_allowed_fast(int index)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== ALLOWED_FAST [ " << index << " ]\n";
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if ((*i)->on_allowed_fast(index)) return;
+ }
+#endif
+
+ if (index < 0 || index >= int(m_have_piece.size()))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " <== INVALID_ALLOWED_FAST [ " << index << " | s: "
+ << int(m_have_piece.size()) << " ]\n";
+#endif
+ return;
+ }
+
+ // if we already have the piece, we can
+ // ignore this message
+ if (t->valid_metadata()
+ && t->have_piece(index))
+ return;
+
+ m_allowed_fast.push_back(index);
+
+ // if the peer has the piece and we want
+ // to download it, request it
+ if (int(m_have_piece.size()) > index
+ && m_have_piece[index]
+ && t->has_picker()
+ && t->picker().piece_priority(index) > 0)
+ {
+ t->get_policy().peer_is_interesting(*this);
+ }
+ }
+
+ std::vector<int> const& peer_connection::allowed_fast()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ m_allowed_fast.erase(std::remove_if(m_allowed_fast.begin()
+ , m_allowed_fast.end(), bind(&torrent::have_piece, t, _1))
+ , m_allowed_fast.end());
+
+ // TODO: sort the allowed fast set in priority order
+ return m_allowed_fast;
+ }
+
+ void peer_connection::add_request(piece_block const& block)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ TORRENT_ASSERT(t->valid_metadata());
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.piece_index < t->torrent_file().num_pieces());
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.block_index < t->torrent_file().piece_size(block.piece_index));
+ TORRENT_ASSERT(!t->picker().is_requested(block) || (t->picker().num_peers(block) > 0));
+ TORRENT_ASSERT(!t->have_piece(block.piece_index));
+ TORRENT_ASSERT(std::find(m_download_queue.begin(), m_download_queue.end(), block) == m_download_queue.end());
+ TORRENT_ASSERT(std::find(m_request_queue.begin(), m_request_queue.end(), block) == m_request_queue.end());
+
+
+ piece_picker::piece_state_t state;
+ peer_speed_t speed = peer_speed();
+ char const* speedmsg = 0;
+ if (speed == fast)
+ {
+ speedmsg = "fast";
+ state = piece_picker::fast;
+ }
+ else if (speed == medium)
+ {
+ speedmsg = "medium";
+ state = piece_picker::medium;
+ }
+ else
+ {
+ speedmsg = "slow";
+ state = piece_picker::slow;
+ }
+
+ if (!t->picker().mark_as_downloading(block, peer_info_struct(), state))
+ return;
+
+ if (t->alerts().should_post(alert::debug))
+ {
+ t->alerts().post_alert(block_downloading_alert(t->get_handle(),
+ speedmsg, block.block_index, block.piece_index, "block downloading"));
+ }
+
+ m_request_queue.push_back(block);
+ }
+
+ void peer_connection::cancel_request(piece_block const& block)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ // this peer might be disconnecting
+ if (!t) return;
+
+ TORRENT_ASSERT(t->valid_metadata());
+
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.piece_index < t->torrent_file().num_pieces());
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.block_index < t->torrent_file().piece_size(block.piece_index));
+
+ // if all the peers that requested this block has been
+ // cancelled, then just ignore the cancel.
+ if (!t->picker().is_requested(block)) return;
+
+ std::deque<piece_block>::iterator it
+ = std::find(m_download_queue.begin(), m_download_queue.end(), block);
+ if (it == m_download_queue.end())
+ {
+ it = std::find(m_request_queue.begin(), m_request_queue.end(), block);
+ // when a multi block is received, it is cancelled
+ // from all peers, so if this one hasn't requested
+ // the block, just ignore to cancel it.
+ if (it == m_request_queue.end()) return;
+
+ t->picker().abort_download(block);
+ m_request_queue.erase(it);
+ // since we found it in the request queue, it means it hasn't been
+ // sent yet, so we don't have to send a cancel.
+ return;
+ }
+
+ int block_offset = block.block_index * t->block_size();
+ int block_size
+ = (std::min)(t->torrent_file().piece_size(block.piece_index)-block_offset,
+ t->block_size());
+ TORRENT_ASSERT(block_size > 0);
+ TORRENT_ASSERT(block_size <= t->block_size());
+
+ peer_request r;
+ r.piece = block.piece_index;
+ r.start = block_offset;
+ r.length = block_size;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> CANCEL [ piece: " << block.piece_index << " | s: "
+ << block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n";
+#endif
+ write_cancel(r);
+ }
+
+ void peer_connection::send_choke()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_peer_info || !m_peer_info->optimistically_unchoked);
+
+ if (m_choked) return;
+ write_choke();
+ m_choked = true;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> CHOKE\n";
+#endif
+#ifndef NDEBUG
+ m_last_choke = time_now();
+#endif
+ m_num_invalid_requests = 0;
+
+ // reject the requests we have in the queue
+ std::for_each(m_requests.begin(), m_requests.end()
+ , bind(&peer_connection::write_reject_request, this, _1));
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ for (std::deque<peer_request>::iterator i = m_requests.begin()
+ , end(m_requests.end()); i != end; ++i)
+ {
+ peer_request const& r = *i;
+ (*m_logger) << time_now_string()
+ << " ==> REJECT_PIECE [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " ]\n";
+ }
+#endif
+ m_requests.clear();
+ }
+
+ void peer_connection::send_unchoke()
+ {
+ INVARIANT_CHECK;
+
+ if (!m_choked) return;
+ m_last_unchoke = time_now();
+ write_unchoke();
+ m_choked = false;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> UNCHOKE\n";
+#endif
+ }
+
+ void peer_connection::send_interested()
+ {
+ INVARIANT_CHECK;
+
+ if (m_interesting) return;
+ write_interested();
+ m_interesting = true;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> INTERESTED\n";
+#endif
+ }
+
+ void peer_connection::send_not_interested()
+ {
+ INVARIANT_CHECK;
+
+ if (!m_interesting) return;
+ write_not_interested();
+ m_interesting = false;
+
+ m_became_uninteresting = time_now();
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> NOT_INTERESTED\n";
+#endif
+ }
+
+ void peer_connection::send_block_requests()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ if ((int)m_download_queue.size() >= m_desired_queue_size) return;
+
+ while (!m_request_queue.empty()
+ && (int)m_download_queue.size() < m_desired_queue_size)
+ {
+ piece_block block = m_request_queue.front();
+
+ int block_offset = block.block_index * t->block_size();
+ int block_size = (std::min)(t->torrent_file().piece_size(
+ block.piece_index) - block_offset, t->block_size());
+ TORRENT_ASSERT(block_size > 0);
+ TORRENT_ASSERT(block_size <= t->block_size());
+
+ peer_request r;
+ r.piece = block.piece_index;
+ r.start = block_offset;
+ r.length = block_size;
+
+ m_request_queue.pop_front();
+ m_download_queue.push_back(block);
+/*
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " *** REQUEST-QUEUE** [ "
+ "piece: " << block.piece_index << " | "
+ "block: " << block.block_index << " ]\n";
+#endif
+*/
+ // if we are requesting large blocks, merge the smaller
+ // blocks that are in the same piece into larger requests
+ if (m_request_large_blocks)
+ {
+ int blocks_per_piece = t->torrent_file().piece_length() / t->block_size();
+
+ while (!m_request_queue.empty())
+ {
+ // check to see if this block is connected to the previous one
+ // if it is, merge them, otherwise, break this merge loop
+ piece_block const& front = m_request_queue.front();
+ if (front.piece_index * blocks_per_piece + front.block_index
+ != block.piece_index * blocks_per_piece + block.block_index + 1)
+ break;
+ block = m_request_queue.front();
+ m_request_queue.pop_front();
+ m_download_queue.push_back(block);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " *** MERGING REQUEST ** [ "
+ "piece: " << block.piece_index << " | "
+ "block: " << block.block_index << " ]\n";
+#endif
+
+ block_offset = block.block_index * t->block_size();
+ block_size = (std::min)(t->torrent_file().piece_size(
+ block.piece_index) - block_offset, t->block_size());
+ TORRENT_ASSERT(block_size > 0);
+ TORRENT_ASSERT(block_size <= t->block_size());
+
+ r.length += block_size;
+ }
+ }
+
+ TORRENT_ASSERT(verify_piece(r));
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ bool handled = false;
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ if (handled = (*i)->write_request(r)) break;
+ }
+ if (!handled)
+ {
+ write_request(r);
+ m_last_request = time_now();
+ }
+#else
+ write_request(r);
+ m_last_request = time_now();
+#endif
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> REQUEST [ "
+ "piece: " << r.piece << " | "
+ "s: " << r.start << " | "
+ "l: " << r.length << " | "
+ "ds: " << statistics().download_rate() << " B/s | "
+ "qs: " << m_desired_queue_size << " "
+ "blk: " << (m_request_large_blocks?"large":"single") << " ]\n";
+#endif
+ }
+ m_last_piece = time_now();
+ }
+
+
+ void close_socket_ignore_error(boost::shared_ptr<socket_type> s)
+ {
+ try { s->close(); } catch (std::exception&) {}
+ }
+
+ void peer_connection::timed_out()
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << "CONNECTION TIMED OUT: " << m_remote.address().to_string()
+ << "\n";
+#endif
+ m_ses.connection_failed(self(), m_remote, "timed out");
+ }
+
+ void peer_connection::disconnect()
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ TORRENT_ASSERT(!m_in_constructor);
+ boost::intrusive_ptr<peer_connection> me(this);
+
+ INVARIANT_CHECK;
+
+ if (m_disconnecting) return;
+ if (m_connecting && m_connection_ticket >= 0)
+ {
+ m_ses.m_half_open.done(m_connection_ticket);
+ m_connection_ticket = -1;
+ }
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+
+ if (t)
+ {
+ if (t->has_picker())
+ {
+ piece_picker& picker = t->picker();
+
+ while (!m_download_queue.empty())
+ {
+ picker.abort_download(m_download_queue.back());
+ m_download_queue.pop_back();
+ }
+ while (!m_request_queue.empty())
+ {
+ picker.abort_download(m_request_queue.back());
+ m_request_queue.pop_back();
+ }
+ }
+
+ t->remove_peer(this);
+ m_torrent.reset();
+ }
+
+ m_disconnecting = true;
+ m_ses.close_connection(me);
+ m_ses.m_io_service.post(boost::bind(&close_socket_ignore_error, m_socket));
+ }
+
+ void peer_connection::set_upload_limit(int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ if (limit == -1) limit = (std::numeric_limits<int>::max)();
+ if (limit < 10) limit = 10;
+ m_upload_limit = limit;
+ m_bandwidth_limit[upload_channel].throttle(m_upload_limit);
+ }
+
+ void peer_connection::set_download_limit(int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ if (limit == -1) limit = (std::numeric_limits<int>::max)();
+ if (limit < 10) limit = 10;
+ m_download_limit = limit;
+ m_bandwidth_limit[download_channel].throttle(m_download_limit);
+ }
+
+ size_type peer_connection::share_diff() const
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ float ratio = t->ratio();
+
+ // if we have an infinite ratio, just say we have downloaded
+ // much more than we have uploaded. And we'll keep uploading.
+ if (ratio == 0.f)
+ return (std::numeric_limits<size_type>::max)();
+
+ return m_free_upload
+ + static_cast<size_type>(m_statistics.total_payload_download() * ratio)
+ - m_statistics.total_payload_upload();
+ }
+
+ // defined in upnp.cpp
+ bool is_local(address const& a);
+
+ bool peer_connection::on_local_network() const
+ {
+ if (libtorrent::is_local(m_remote.address())
+ || is_loopback(m_remote.address())) return true;
+ return false;
+ }
+
+ void peer_connection::get_peer_info(peer_info& p) const
+ {
+ TORRENT_ASSERT(!associated_torrent().expired());
+
+ p.down_speed = statistics().download_rate();
+ p.up_speed = statistics().upload_rate();
+ p.payload_down_speed = statistics().download_payload_rate();
+ p.payload_up_speed = statistics().upload_payload_rate();
+ p.pid = pid();
+ p.ip = remote();
+ p.pending_disk_bytes = m_outstanding_writing_bytes;
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ p.country[0] = m_country[0];
+ p.country[1] = m_country[1];
+#endif
+
+ p.total_download = statistics().total_payload_download();
+ p.total_upload = statistics().total_payload_upload();
+
+ if (m_bandwidth_limit[upload_channel].throttle() == bandwidth_limit::inf)
+ p.upload_limit = -1;
+ else
+ p.upload_limit = m_bandwidth_limit[upload_channel].throttle();
+
+ if (m_bandwidth_limit[download_channel].throttle() == bandwidth_limit::inf)
+ p.download_limit = -1;
+ else
+ p.download_limit = m_bandwidth_limit[download_channel].throttle();
+
+ p.load_balancing = total_free_upload();
+
+ p.download_queue_length = int(download_queue().size() + m_request_queue.size());
+ p.target_dl_queue_length = int(desired_queue_size());
+ p.upload_queue_length = int(upload_queue().size());
+
+ if (boost::optional<piece_block_progress> ret = downloading_piece_progress())
+ {
+ p.downloading_piece_index = ret->piece_index;
+ p.downloading_block_index = ret->block_index;
+ p.downloading_progress = ret->bytes_downloaded;
+ p.downloading_total = ret->full_block_bytes;
+ }
+ else
+ {
+ p.downloading_piece_index = -1;
+ p.downloading_block_index = -1;
+ p.downloading_progress = 0;
+ p.downloading_total = 0;
+ }
+
+ p.pieces = get_bitfield();
+ ptime now = time_now();
+ p.last_request = now - m_last_request;
+ p.last_active = now - (std::max)(m_last_sent, m_last_receive);
+
+ // this will set the flags so that we can update them later
+ p.flags = 0;
+ get_specific_peer_info(p);
+
+ p.flags |= is_seed() ? peer_info::seed : 0;
+ if (peer_info_struct())
+ {
+ p.source = peer_info_struct()->source;
+ p.failcount = peer_info_struct()->failcount;
+ p.num_hashfails = peer_info_struct()->hashfails;
+ p.flags |= peer_info_struct()->on_parole ? peer_info::on_parole : 0;
+ p.flags |= peer_info_struct()->optimistically_unchoked ? peer_info::optimistic_unchoke : 0;
+ p.remote_dl_rate = m_remote_dl_rate;
+ }
+ else
+ {
+ p.source = 0;
+ p.failcount = 0;
+ p.num_hashfails = 0;
+ p.remote_dl_rate = 0;
+ }
+
+ p.send_buffer_size = m_send_buffer.capacity();
+ p.used_send_buffer = m_send_buffer.size();
+ }
+
+ void peer_connection::cut_receive_buffer(int size, int packet_size)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(packet_size > 0);
+ TORRENT_ASSERT(int(m_recv_buffer.size()) >= size);
+ TORRENT_ASSERT(int(m_recv_buffer.size()) >= m_recv_pos);
+ TORRENT_ASSERT(m_recv_pos >= size);
+
+ if (size > 0)
+ std::memmove(&m_recv_buffer[0], &m_recv_buffer[0] + size, m_recv_pos - size);
+
+ m_recv_pos -= size;
+
+#ifndef NDEBUG
+ std::fill(m_recv_buffer.begin() + m_recv_pos, m_recv_buffer.end(), 0);
+#endif
+
+ m_packet_size = packet_size;
+ if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size);
+ }
+
+ void peer_connection::second_tick(float tick_interval)
+ {
+ INVARIANT_CHECK;
+
+ try
+ {
+
+ ptime now(time_now());
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ on_tick();
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ (*i)->tick();
+ }
+#endif
+
+ m_ignore_bandwidth_limits = m_ses.settings().ignore_limits_on_local_network
+ && on_local_network();
+
+ m_statistics.second_tick(tick_interval);
+
+ if (!t->valid_metadata()) return;
+
+ // calculate the desired download queue size
+ const float queue_time = m_ses.settings().request_queue_time;
+ // (if the latency is more than this, the download will stall)
+ // so, the queue size is queue_time * down_rate / 16 kiB
+ // (16 kB is the size of each request)
+ // the minimum number of requests is 2 and the maximum is 48
+ // the block size doesn't have to be 16. So we first query the
+ // torrent for it
+ const int block_size = m_request_large_blocks
+ ? t->torrent_file().piece_length() : t->block_size();
+ TORRENT_ASSERT(block_size > 0);
+
+ m_desired_queue_size = static_cast<int>(queue_time
+ * statistics().download_rate() / block_size);
+ if (m_desired_queue_size > m_max_out_request_queue)
+ m_desired_queue_size = m_max_out_request_queue;
+ if (m_desired_queue_size < min_request_queue)
+ m_desired_queue_size = min_request_queue;
+
+ if (!m_download_queue.empty()
+ && now - m_last_piece > seconds(m_ses.settings().piece_timeout))
+ {
+ // this peer isn't sending the pieces we've
+ // requested (this has been observed by BitComet)
+ // in this case we'll clear our download queue and
+ // re-request the blocks.
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " *** PIECE_REQUESTS TIMED OUT [ " << (int)m_download_queue.size()
+ << " " << total_seconds(now - m_last_piece) << "] ***\n";
+#endif
+
+ if (t->is_seed())
+ {
+ m_download_queue.clear();
+ m_request_queue.clear();
+ }
+ else
+ {
+ piece_picker& picker = t->picker();
+
+ std::deque<piece_block> dl(m_download_queue);
+ for (std::deque<piece_block>::iterator i = dl.begin()
+ , end(dl.end()); i != end; ++i)
+ {
+ piece_block const& r = m_download_queue.back();
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> CANCEL [ piece: " << r.piece_index
+ << " | block: " << r.block_index
+ << " ]\n";
+#endif
+ write_cancel(t->to_req(r));
+ }
+ while (!m_request_queue.empty())
+ {
+ piece_block const& r = m_request_queue.back();
+ picker.abort_download(r);
+ m_request_queue.pop_back();
+ }
+
+ m_assume_fifo = true;
+
+ request_a_block(*t, *this);
+ send_block_requests();
+ }
+ }
+
+ // If the client sends more data
+ // we send it data faster, otherwise, slower.
+ // It will also depend on how much data the
+ // client has sent us. This is the mean to
+ // maintain the share ratio given by m_ratio
+ // with all peers.
+
+ if (t->is_finished() || is_choked() || t->ratio() == 0.0f)
+ {
+ // if we have downloaded more than one piece more
+ // than we have uploaded OR if we are a seed
+ // have an unlimited upload rate
+ m_bandwidth_limit[upload_channel].throttle(m_upload_limit);
+ }
+ else
+ {
+ size_type bias = 0x10000 + 2 * t->block_size() + m_free_upload;
+
+ double break_even_time = 15; // seconds.
+ size_type have_uploaded = m_statistics.total_payload_upload();
+ size_type have_downloaded = m_statistics.total_payload_download();
+ double download_speed = m_statistics.download_rate();
+
+ size_type soon_downloaded =
+ have_downloaded + (size_type)(download_speed * break_even_time*1.5);
+
+ if (t->ratio() != 1.f)
+ soon_downloaded = (size_type)(soon_downloaded*(double)t->ratio());
+
+ double upload_speed_limit = (std::min)((soon_downloaded - have_uploaded
+ + bias) / break_even_time, double(m_upload_limit));
+
+ upload_speed_limit = (std::min)(upload_speed_limit,
+ (double)(std::numeric_limits<int>::max)());
+
+ m_bandwidth_limit[upload_channel].throttle(
+ (std::min)((std::max)((int)upload_speed_limit, 20)
+ , m_upload_limit));
+ }
+
+ // update once every minute
+ if (now - m_remote_dl_update >= seconds(60))
+ {
+ float factor = 0.6666666666667f;
+
+ if (m_remote_dl_rate == 0) factor = 0.0f;
+
+ m_remote_dl_rate = int((m_remote_dl_rate * factor) +
+ ((m_remote_bytes_dled * (1.0f-factor)) / 60.f));
+
+ m_remote_bytes_dled = 0;
+ m_remote_dl_update = now;
+ }
+
+ fill_send_buffer();
+ }
+ catch (std::exception& e)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "**ERROR**: " << e.what() << "\n";
+#endif
+ m_ses.connection_failed(self(), remote(), e.what());
+ }
+ }
+
+ void peer_connection::fill_send_buffer()
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ if (!t) return;
+
+ // only add new piece-chunks if the send buffer is small enough
+ // otherwise there will be no end to how large it will be!
+
+ int buffer_size_watermark = int(m_statistics.upload_rate()) / 2;
+ if (buffer_size_watermark < 1024) buffer_size_watermark = 1024;
+ else if (buffer_size_watermark > 80 * 1024) buffer_size_watermark = 80 * 1024;
+
+ while (!m_requests.empty()
+ && (send_buffer_size() + m_reading_bytes < buffer_size_watermark))
+ {
+ TORRENT_ASSERT(t->valid_metadata());
+ peer_request& r = m_requests.front();
+
+ TORRENT_ASSERT(r.piece >= 0);
+ TORRENT_ASSERT(r.piece < (int)m_have_piece.size());
+ TORRENT_ASSERT(t->have_piece(r.piece));
+ TORRENT_ASSERT(r.start + r.length <= t->torrent_file().piece_size(r.piece));
+ TORRENT_ASSERT(r.length > 0 && r.start >= 0);
+
+ t->filesystem().async_read(r, bind(&peer_connection::on_disk_read_complete
+ , self(), _1, _2, r));
+ m_reading_bytes += r.length;
+
+ m_requests.erase(m_requests.begin());
+ }
+ }
+
+ void peer_connection::on_disk_read_complete(int ret, disk_io_job const& j, peer_request r)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ m_reading_bytes -= r.length;
+
+ if (ret != r.length || m_torrent.expired())
+ {
+ if (j.buffer) m_ses.free_disk_buffer(j.buffer);
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ if (!t)
+ {
+ m_ses.connection_failed(self(), remote(), j.str.c_str());
+ return;
+ }
+
+ if (t->alerts().should_post(alert::fatal))
+ {
+ std::string err = "torrent paused: disk read error";
+ if (!j.str.empty())
+ {
+ err += ", ";
+ err += j.str;
+ }
+ t->alerts().post_alert(file_error_alert(t->get_handle(), err));
+ }
+ t->pause();
+ return;
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> PIECE [ piece: " << r.piece << " | s: " << r.start
+ << " | l: " << r.length << " ]\n";
+#endif
+
+ write_piece(r, j.buffer);
+ setup_send();
+ }
+
+ void peer_connection::assign_bandwidth(int channel, int amount)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "bandwidth [ " << channel << " ] + " << amount << "\n";
+#endif
+
+ m_bandwidth_limit[channel].assign(amount);
+ if (channel == upload_channel)
+ {
+ TORRENT_ASSERT(m_writing);
+ m_writing = false;
+ setup_send();
+ }
+ else if (channel == download_channel)
+ {
+ TORRENT_ASSERT(m_reading);
+ m_reading = false;
+ setup_receive();
+ }
+ }
+
+ void peer_connection::expire_bandwidth(int channel, int amount)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ m_bandwidth_limit[channel].expire(amount);
+ if (channel == upload_channel)
+ {
+ setup_send();
+ }
+ else if (channel == download_channel)
+ {
+ setup_receive();
+ }
+ }
+
+ void peer_connection::setup_send()
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_writing) return;
+
+ shared_ptr<torrent> t = m_torrent.lock();
+
+ if (m_bandwidth_limit[upload_channel].quota_left() == 0
+ && !m_send_buffer.empty()
+ && !m_connecting
+ && t
+ && !m_ignore_bandwidth_limits)
+ {
+ // in this case, we have data to send, but no
+ // bandwidth. So, we simply request bandwidth
+ // from the torrent
+ TORRENT_ASSERT(t);
+ if (m_bandwidth_limit[upload_channel].max_assignable() > 0)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ upload ]\n";
+#endif
+
+ TORRENT_ASSERT(!m_writing);
+ // peers that we are not interested in are non-prioritized
+ m_writing = true;
+ t->request_bandwidth(upload_channel, self()
+ , is_interesting() * 2);
+ }
+ return;
+ }
+
+ if (!can_write())
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** CANNOT WRITE ["
+ " quota: " << m_bandwidth_limit[download_channel].quota_left() <<
+ " ignore: " << (m_ignore_bandwidth_limits?"yes":"no") <<
+ " buf: " << m_send_buffer.size() <<
+ " connecting: " << (m_connecting?"yes":"no") <<
+ " ]\n";
+#endif
+ return;
+ }
+
+ TORRENT_ASSERT(!m_writing);
+
+ // send the actual buffer
+ if (!m_send_buffer.empty())
+ {
+ int amount_to_send = m_send_buffer.size();
+ int quota_left = m_bandwidth_limit[upload_channel].quota_left();
+ if (!m_ignore_bandwidth_limits && amount_to_send > quota_left)
+ amount_to_send = quota_left;
+
+ TORRENT_ASSERT(amount_to_send > 0);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** ASYNC_WRITE [ bytes: " << amount_to_send << " ]\n";
+#endif
+ std::list<asio::const_buffer> const& vec = m_send_buffer.build_iovec(amount_to_send);
+ m_socket->async_write_some(vec, bind(&peer_connection::on_send_data, self(), _1, _2));
+
+ m_writing = true;
+ }
+ }
+
+ void peer_connection::setup_receive()
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** SETUP_RECEIVE [ reading: " << (m_reading?"yes":"no") << "]\n";
+#endif
+ if (m_reading) return;
+
+ shared_ptr<torrent> t = m_torrent.lock();
+
+ if (m_bandwidth_limit[download_channel].quota_left() == 0
+ && !m_connecting
+ && t
+ && !m_ignore_bandwidth_limits)
+ {
+ if (m_bandwidth_limit[download_channel].max_assignable() > 0)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ download ]\n";
+#endif
+ m_reading = true;
+ t->request_bandwidth(download_channel, self(), m_priority);
+ }
+ return;
+ }
+
+ if (!can_read())
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** CANNOT READ ["
+ " quota: " << m_bandwidth_limit[download_channel].quota_left() <<
+ " ignore: " << (m_ignore_bandwidth_limits?"yes":"no") <<
+ " outstanding: " << m_outstanding_writing_bytes <<
+ " outstanding-limit: " << m_ses.settings().max_outstanding_disk_bytes_per_connection <<
+ " ]\n";
+#endif
+ return;
+ }
+
+ TORRENT_ASSERT(m_packet_size > 0);
+ int max_receive = m_packet_size - m_recv_pos;
+ int quota_left = m_bandwidth_limit[download_channel].quota_left();
+ if (!m_ignore_bandwidth_limits && max_receive > quota_left)
+ max_receive = quota_left;
+
+ if (max_receive == 0) return;
+
+ TORRENT_ASSERT(m_recv_pos >= 0);
+ TORRENT_ASSERT(m_packet_size > 0);
+
+ TORRENT_ASSERT(can_read());
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** ASYNC_READ [ max: " << max_receive << " bytes ]\n";
+#endif
+ m_socket->async_read_some(asio::buffer(&m_recv_buffer[m_recv_pos]
+ , max_receive), bind(&peer_connection::on_receive_data, self(), _1, _2));
+ m_reading = true;
+ }
+
+ void peer_connection::reset_recv_buffer(int packet_size)
+ {
+ TORRENT_ASSERT(packet_size > 0);
+ if (m_recv_pos > m_packet_size)
+ {
+ cut_receive_buffer(m_packet_size, packet_size);
+ return;
+ }
+ m_recv_pos = 0;
+ m_packet_size = packet_size;
+ if (int(m_recv_buffer.size()) < m_packet_size)
+ m_recv_buffer.resize(m_packet_size);
+ }
+
+ void peer_connection::send_buffer(char const* buf, int size)
+ {
+ int free_space = m_send_buffer.space_in_last_buffer();
+ if (free_space > size) free_space = size;
+ if (free_space > 0)
+ {
+ m_send_buffer.append(buf, free_space);
+ size -= free_space;
+ buf += free_space;
+#ifdef TORRENT_STATS
+ m_ses.m_buffer_usage_logger << log_time() << " send_buffer: "
+ << free_space << std::endl;
+ m_ses.log_buffer_usage();
+#endif
+ }
+ if (size <= 0) return;
+
+ std::pair<char*, int> buffer = m_ses.allocate_buffer(size);
+ TORRENT_ASSERT(buffer.second >= size);
+ std::memcpy(buffer.first, buf, size);
+ m_send_buffer.append_buffer(buffer.first, buffer.second, size
+ , bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second));
+#ifdef TORRENT_STATS
+ m_ses.m_buffer_usage_logger << log_time() << " send_buffer_alloc: " << size << std::endl;
+ m_ses.log_buffer_usage();
+#endif
+ setup_send();
+ }
+
+// TODO: change this interface to automatically call setup_send() when the
+// return value is destructed
+ buffer::interval peer_connection::allocate_send_buffer(int size)
+ {
+ TORRENT_ASSERT(size > 0);
+ char* insert = m_send_buffer.allocate_appendix(size);
+ if (insert == 0)
+ {
+ std::pair<char*, int> buffer = m_ses.allocate_buffer(size);
+ TORRENT_ASSERT(buffer.second >= size);
+ m_send_buffer.append_buffer(buffer.first, buffer.second, size
+ , bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second));
+ buffer::interval ret(buffer.first, buffer.first + size);
+#ifdef TORRENT_STATS
+ m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer_alloc: " << size << std::endl;
+ m_ses.log_buffer_usage();
+#endif
+ return ret;
+ }
+ else
+ {
+#ifdef TORRENT_STATS
+ m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer: " << size << std::endl;
+ m_ses.log_buffer_usage();
+#endif
+ buffer::interval ret(insert, insert + size);
+ return ret;
+ }
+ }
+
+ template<class T>
+ struct set_to_zero
+ {
+ set_to_zero(T& v, bool cond): m_val(v), m_cond(cond) {}
+ void fire() { if (!m_cond) return; m_cond = false; m_val = 0; }
+ ~set_to_zero() { if (m_cond) m_val = 0; }
+ private:
+ T& m_val;
+ bool m_cond;
+ };
+
+ // --------------------------
+ // RECEIVE DATA
+ // --------------------------
+
+ // throws exception when the client should be disconnected
+ void peer_connection::on_receive_data(const asio::error_code& error
+ , std::size_t bytes_transferred) try
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_reading);
+ m_reading = false;
+
+ if (error)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "**ERROR**: " << error.message() << "[in peer_connection::on_receive_data]\n";
+#endif
+ set_failed();
+ on_receive(error, bytes_transferred);
+ throw std::runtime_error(error.message());
+ }
+
+ do
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "read " << bytes_transferred << " bytes\n";
+#endif
+ // correct the dl quota usage, if not all of the buffer was actually read
+ if (!m_ignore_bandwidth_limits)
+ m_bandwidth_limit[download_channel].use_quota(bytes_transferred);
+
+ if (m_disconnecting) return;
+
+ TORRENT_ASSERT(m_packet_size > 0);
+ TORRENT_ASSERT(bytes_transferred > 0);
+
+ m_last_receive = time_now();
+ m_recv_pos += bytes_transferred;
+ TORRENT_ASSERT(m_recv_pos <= int(m_recv_buffer.size()));
+
+ on_receive(error, bytes_transferred);
+
+ TORRENT_ASSERT(m_packet_size > 0);
+
+ if (m_peer_choked
+ && m_recv_pos == 0
+ && (m_recv_buffer.capacity() - m_packet_size) > 128)
+ {
+ buffer(m_packet_size).swap(m_recv_buffer);
+ }
+
+ int max_receive = m_packet_size - m_recv_pos;
+ int quota_left = m_bandwidth_limit[download_channel].quota_left();
+ if (!m_ignore_bandwidth_limits && max_receive > quota_left)
+ max_receive = quota_left;
+
+ if (max_receive == 0) break;
+
+ asio::error_code ec;
+ bytes_transferred = m_socket->read_some(asio::buffer(&m_recv_buffer[m_recv_pos]
+ , max_receive), ec);
+ if (ec && ec != asio::error::would_block)
+ throw asio::system_error(ec);
+ }
+ while (bytes_transferred > 0);
+
+ setup_receive();
+ }
+ catch (file_error& e)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ if (!t)
+ {
+ m_ses.connection_failed(self(), remote(), e.what());
+ return;
+ }
+
+ if (t->alerts().should_post(alert::fatal))
+ {
+ t->alerts().post_alert(
+ file_error_alert(t->get_handle()
+ , std::string("torrent paused: ") + e.what()));
+ }
+ t->pause();
+ }
+ catch (std::exception& e)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ m_ses.connection_failed(self(), remote(), e.what());
+ }
+ catch (...)
+ {
+ // all exceptions should derive from std::exception
+ TORRENT_ASSERT(false);
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ m_ses.connection_failed(self(), remote(), "connection failed for unknown reason");
+ }
+
+ bool peer_connection::can_write() const
+ {
+ INVARIANT_CHECK;
+
+ // if we have requests or pending data to be sent or announcements to be made
+ // we want to send data
+ return !m_send_buffer.empty()
+ && (m_bandwidth_limit[upload_channel].quota_left() > 0
+ || m_ignore_bandwidth_limits)
+ && !m_connecting;
+ }
+
+ bool peer_connection::can_read() const
+ {
+ INVARIANT_CHECK;
+
+ bool ret = (m_bandwidth_limit[download_channel].quota_left() > 0
+ || m_ignore_bandwidth_limits)
+ && !m_connecting
+ && m_outstanding_writing_bytes <
+ m_ses.settings().max_outstanding_disk_bytes_per_connection;
+
+#if defined(TORRENT_VERBOSE_LOGGING)
+ (*m_logger) << time_now_string() << " *** can_read() " << (ret?"yes":"no") << " reading: " << m_reading << "\n";
+#endif
+
+ return ret;
+ }
+
+ void peer_connection::connect(int ticket)
+ {
+ INVARIANT_CHECK;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << "CONNECTING: " << m_remote.address().to_string()
+ << ":" << m_remote.port() << "\n";
+#endif
+
+ m_connection_ticket = ticket;
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ m_queued = false;
+ TORRENT_ASSERT(m_connecting);
+ m_socket->open(t->get_interface().protocol());
+
+ // set the socket to non-blocking, so that we can
+ // read the entire buffer on each read event we get
+ tcp::socket::non_blocking_io ioc(true);
+ m_socket->io_control(ioc);
+ m_socket->bind(t->get_interface());
+ m_socket->async_connect(m_remote
+ , bind(&peer_connection::on_connection_complete, self(), _1));
+
+ if (t->alerts().should_post(alert::debug))
+ {
+ t->alerts().post_alert(peer_error_alert(
+ m_remote, m_peer_id, "connecting to peer"));
+ }
+ }
+
+ void peer_connection::on_connection_complete(asio::error_code const& e) try
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_disconnecting) return;
+
+ m_connecting = false;
+ m_ses.m_half_open.done(m_connection_ticket);
+
+ if (e)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string()
+ << ": " << e.message() << "\n";
+#endif
+ set_failed();
+ m_ses.connection_failed(self(), m_remote, e.message().c_str());
+ return;
+ }
+
+ if (m_disconnecting) return;
+ m_last_receive = time_now();
+
+ // this means the connection just succeeded
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << "COMPLETED: " << m_remote.address().to_string() << "\n";
+#endif
+
+ on_connected();
+ setup_send();
+ setup_receive();
+ }
+ catch (std::exception& ex)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ m_ses.connection_failed(self(), remote(), ex.what());
+ }
+ catch (...)
+ {
+ // all exceptions should derive from std::exception
+ TORRENT_ASSERT(false);
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ m_ses.connection_failed(self(), remote(), "connection failed for unkown reason");
+ }
+
+ // --------------------------
+ // SEND DATA
+ // --------------------------
+
+ // throws exception when the client should be disconnected
+ void peer_connection::on_send_data(asio::error_code const& error
+ , std::size_t bytes_transferred) try
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_writing);
+
+ m_send_buffer.pop_front(bytes_transferred);
+
+ m_writing = false;
+
+ if (!m_ignore_bandwidth_limits)
+ m_bandwidth_limit[upload_channel].use_quota(bytes_transferred);
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "wrote " << bytes_transferred << " bytes\n";
+#endif
+
+ if (error)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "**ERROR**: " << error.message() << " [in peer_connection::on_send_data]\n";
+#endif
+ set_failed();
+ throw std::runtime_error(error.message());
+ }
+ if (m_disconnecting) return;
+
+ TORRENT_ASSERT(!m_connecting);
+ TORRENT_ASSERT(bytes_transferred > 0);
+
+ m_last_sent = time_now();
+
+ on_sent(error, bytes_transferred);
+ fill_send_buffer();
+
+ setup_send();
+ }
+ catch (std::exception& e)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ m_ses.connection_failed(self(), remote(), e.what());
+ }
+ catch (...)
+ {
+ // all exceptions should derive from std::exception
+ TORRENT_ASSERT(false);
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ m_ses.connection_failed(self(), remote(), "connection failed for unknown reason");
+ }
+
+
+#ifndef NDEBUG
+ void peer_connection::check_invariant() const
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ // this peer is in the bandwidth history iff max_assignable < limit
+ TORRENT_ASSERT((m_bandwidth_limit[i].max_assignable() < m_bandwidth_limit[i].throttle())
+ == m_ses.m_bandwidth_manager[i]->is_in_history(this)
+ || m_bandwidth_limit[i].throttle() == bandwidth_limit::inf);
+ }
+ std::set<piece_block> unique;
+ std::copy(m_download_queue.begin(), m_download_queue.end(), std::inserter(unique, unique.begin()));
+ std::copy(m_request_queue.begin(), m_request_queue.end(), std::inserter(unique, unique.begin()));
+ TORRENT_ASSERT(unique.size() == m_download_queue.size() + m_request_queue.size());
+ if (m_peer_info)
+ {
+ TORRENT_ASSERT(m_peer_info->connection == this
+ || m_peer_info->connection == 0);
+
+ if (m_peer_info->optimistically_unchoked)
+ TORRENT_ASSERT(!is_choked());
+ }
+
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ if (!t) return;
+
+ if (m_peer_info)
+ {
+ policy::const_iterator i;
+ for (i = t->get_policy().begin_peer();
+ i != t->get_policy().end_peer(); ++i)
+ {
+ if (&i->second == m_peer_info) break;
+ }
+ TORRENT_ASSERT(i != t->get_policy().end_peer());
+ }
+ if (t->has_picker() && !t->is_aborted())
+ {
+ // make sure that pieces that have completed the download
+ // of all their blocks are in the disk io thread's queue
+ // to be checked.
+ const std::vector<piece_picker::downloading_piece>& dl_queue
+ = t->picker().get_download_queue();
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i =
+ dl_queue.begin(); i != dl_queue.end(); ++i)
+ {
+ const int blocks_per_piece = t->picker().blocks_in_piece(i->index);
+
+ bool complete = true;
+ for (int j = 0; j < blocks_per_piece; ++j)
+ {
+ if (i->info[j].state == piece_picker::block_info::state_finished)
+ continue;
+ complete = false;
+ break;
+ }
+ if (complete)
+ {
+ disk_io_job ret = m_ses.m_disk_thread.find_job(
+ &t->filesystem(), -1, i->index);
+ TORRENT_ASSERT(ret.action == disk_io_job::hash || ret.action == disk_io_job::write);
+ TORRENT_ASSERT(ret.piece == i->index);
+ }
+ }
+ }
+// expensive when using checked iterators
+/*
+ if (t->valid_metadata())
+ {
+ int piece_count = std::count(m_have_piece.begin()
+ , m_have_piece.end(), true);
+ if (m_num_pieces != piece_count)
+ {
+ TORRENT_ASSERT(false);
+ }
+ }
+*/
+
+// extremely expensive invariant check
+/*
+ if (!t->is_seed())
+ {
+ piece_picker& p = t->picker();
+ const std::vector<piece_picker::downloading_piece>& dlq = p.get_download_queue();
+ const int blocks_per_piece = static_cast<int>(
+ t->torrent_file().piece_length() / t->block_size());
+
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i =
+ dlq.begin(); i != dlq.end(); ++i)
+ {
+ for (int j = 0; j < blocks_per_piece; ++j)
+ {
+ if (std::find(m_request_queue.begin(), m_request_queue.end()
+ , piece_block(i->index, j)) != m_request_queue.end()
+ ||
+ std::find(m_download_queue.begin(), m_download_queue.end()
+ , piece_block(i->index, j)) != m_download_queue.end())
+ {
+ TORRENT_ASSERT(i->info[j].peer == m_remote);
+ }
+ else
+ {
+ TORRENT_ASSERT(i->info[j].peer != m_remote || i->info[j].finished);
+ }
+ }
+ }
+ }
+*/
+ }
+#endif
+
+ bool peer_connection::has_timed_out() const
+ {
+ // TODO: the timeout should be called by an event
+ INVARIANT_CHECK;
+
+ ptime now(time_now());
+
+ // if the socket is still connecting, don't
+ // consider it timed out. Because Windows XP SP2
+ // may delay connection attempts.
+ if (m_connecting) return false;
+
+ // if the peer hasn't said a thing for a certain
+ // time, it is considered to have timed out
+ time_duration d;
+ d = now - m_last_receive;
+ if (d > seconds(m_timeout))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** LAST ACTIVITY [ "
+ << total_seconds(d) << " seconds ago ] ***\n";
+#endif
+ return true;
+ }
+
+ // do not stall waiting for a handshake
+ if (in_handshake() && d > seconds(m_ses.settings().handshake_timeout))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** NO HANDSHAKE [ waited "
+ << total_seconds(d) << " seconds ] ***\n";
+#endif
+ return true;
+ }
+
+ // disconnect peers that we unchoked, but
+ // they didn't send a request within 20 seconds.
+ // but only if we're a seed
+ boost::shared_ptr<torrent> t = m_torrent.lock();
+ d = now - (std::max)(m_last_unchoke, m_last_incoming_request);
+ if (m_requests.empty()
+ && !m_choked
+ && m_peer_interested
+ && t && t->is_finished()
+ && d > seconds(20))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** NO REQUEST [ t: "
+ << total_seconds(d) << " ] ***\n";
+#endif
+ return true;
+ }
+
+ // TODO: as long as we have less than 95% of the
+ // global (or local) connection limit, connections should
+ // never time out for another reason
+
+ // if the peer hasn't become interested and we haven't
+ // become interested in the peer for 10 minutes, it
+ // has also timed out.
+ time_duration d1;
+ time_duration d2;
+ d1 = now - m_became_uninterested;
+ d2 = now - m_became_uninteresting;
+ time_duration time_limit = seconds(
+ m_ses.settings().inactivity_timeout);
+
+ // don't bother disconnect peers we haven't been intersted
+ // in (and that hasn't been interested in us) for a while
+ // unless we have used up all our connection slots
+ if (!m_interesting
+ && !m_peer_interested
+ && d1 > time_limit
+ && d2 > time_limit
+ && (m_ses.num_connections() >= m_ses.max_connections()
+ || (t && t->num_peers() >= t->max_connections())))
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " *** MUTUAL NO INTEREST [ "
+ "t1: " << total_seconds(d1) << " | "
+ "t2: " << total_seconds(d2) << " ] ***\n";
+#endif
+ return true;
+ }
+
+ return false;
+ }
+
+ peer_connection::peer_speed_t peer_connection::peer_speed()
+ {
+ shared_ptr<torrent> t = m_torrent.lock();
+ TORRENT_ASSERT(t);
+
+ int download_rate = int(statistics().download_payload_rate());
+ int torrent_download_rate = int(t->statistics().download_payload_rate());
+
+ if (download_rate > 512 && download_rate > torrent_download_rate / 16)
+ m_speed = fast;
+ else if (download_rate > 4096 && download_rate > torrent_download_rate / 64)
+ m_speed = medium;
+ else if (download_rate < torrent_download_rate / 15 && m_speed == fast)
+ m_speed = medium;
+ else if (download_rate < torrent_download_rate / 63 && m_speed == medium)
+ m_speed = slow;
+
+ return m_speed;
+ }
+
+ void peer_connection::keep_alive()
+ {
+ INVARIANT_CHECK;
+
+ time_duration d;
+ d = time_now() - m_last_sent;
+ if (total_seconds(d) < m_timeout / 2) return;
+
+ if (m_connecting) return;
+ if (in_handshake()) return;
+
+ // if the last send has not completed yet, do not send a keep
+ // alive
+ if (m_writing) return;
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string() << " ==> KEEPALIVE\n";
+#endif
+
+ m_last_sent = time_now();
+ write_keepalive();
+ }
+
+ bool peer_connection::is_seed() const
+ {
+ // if m_num_pieces == 0, we probably don't have the
+ // metadata yet.
+ return m_num_pieces == (int)m_have_piece.size() && m_num_pieces > 0;
+ }
+}
+
diff --git a/src/libtorrent/src/piece_picker.cpp b/src/libtorrent/src/piece_picker.cpp
new file mode 100644
index 0000000..9bd02f3
--- /dev/null
+++ b/src/libtorrent/src/piece_picker.cpp
@@ -0,0 +1,1924 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <cmath>
+#include <algorithm>
+#include <numeric>
+
+// non-standard header, is_sorted()
+//#include <algo.h>
+
+#include "libtorrent/piece_picker.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+
+#ifndef NDEBUG
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/torrent.hpp"
+#endif
+
+//#define TORRENT_PIECE_PICKER_INVARIANT_CHECK INVARIANT_CHECK
+#define TORRENT_PIECE_PICKER_INVARIANT_CHECK
+
+namespace libtorrent
+{
+
+ piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks)
+ : m_piece_info(2)
+ , m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece)
+ , m_num_filtered(0)
+ , m_num_have_filtered(0)
+ , m_num_have(0)
+ , m_sequenced_download_threshold(100)
+ {
+ TORRENT_ASSERT(blocks_per_piece > 0);
+ TORRENT_ASSERT(total_num_blocks >= 0);
+#ifndef NDEBUG
+ m_files_checked_called = false;
+#endif
+
+ // the piece index is stored in 20 bits, which limits the allowed
+ // number of pieces somewhat
+ if (m_piece_map.size() >= piece_pos::we_have_index)
+ throw std::runtime_error("too many pieces in torrent");
+
+ m_blocks_per_piece = blocks_per_piece;
+ m_blocks_in_last_piece = total_num_blocks % blocks_per_piece;
+ if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = blocks_per_piece;
+
+ TORRENT_ASSERT(m_blocks_in_last_piece <= m_blocks_per_piece);
+
+ // allocate the piece_map to cover all pieces
+ // and make them invalid (as if we don't have a single piece)
+ std::fill(m_piece_map.begin(), m_piece_map.end()
+ , piece_pos(0, 0));
+ m_num_have = 0;
+ }
+
+ // pieces is a bitmask with the pieces we have
+ void piece_picker::files_checked(
+ std::vector<bool> const& pieces
+ , std::vector<downloading_piece> const& unfinished
+ , std::vector<int>& verify_pieces)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+#ifndef NDEBUG
+ m_files_checked_called = true;
+#endif
+ for (std::vector<bool>::const_iterator i = pieces.begin();
+ i != pieces.end(); ++i)
+ {
+ int index = static_cast<int>(i - pieces.begin());
+ piece_pos& p = m_piece_map[index];
+ if (*i)
+ {
+ ++m_num_have;
+ p.set_have();
+ if (p.filtered())
+ {
+ ++m_num_have_filtered;
+ TORRENT_ASSERT(m_num_filtered > 0);
+ --m_num_filtered;
+ }
+ }
+ else
+ {
+ p.index = 0;
+ }
+ }
+
+ // if we have fast resume info
+ // use it
+ if (!unfinished.empty())
+ {
+ for (std::vector<downloading_piece>::const_iterator i
+ = unfinished.begin(); i != unfinished.end(); ++i)
+ {
+ for (int j = 0; j < m_blocks_per_piece; ++j)
+ {
+ if (i->info[j].state == block_info::state_finished)
+ mark_as_finished(piece_block(i->index, j), 0);
+ }
+ if (is_piece_finished(i->index))
+ {
+ verify_pieces.push_back(i->index);
+ }
+ }
+ }
+ }
+
+ void piece_picker::piece_info(int index, piece_picker::downloading_piece& st) const
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < int(m_piece_map.size()));
+
+ if (m_piece_map[index].downloading)
+ {
+ std::vector<downloading_piece>::const_iterator piece = std::find_if(
+ m_downloads.begin(), m_downloads.end()
+ , bind(&downloading_piece::index, _1) == index);
+ TORRENT_ASSERT(piece != m_downloads.end());
+ st = *piece;
+ st.info = 0;
+ return;
+ }
+ st.info = 0;
+ st.index = index;
+ st.writing = 0;
+ st.requested = 0;
+ if (m_piece_map[index].have())
+ {
+ st.finished = blocks_in_piece(index);
+ return;
+ }
+ st.finished = 0;
+ }
+
+ void piece_picker::set_sequenced_download_threshold(
+ int sequenced_download_threshold)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ if (sequenced_download_threshold == m_sequenced_download_threshold)
+ return;
+
+ TORRENT_ASSERT(sequenced_download_threshold > 0);
+ if (sequenced_download_threshold <= 0) return;
+
+ int old_limit = m_sequenced_download_threshold;
+ m_sequenced_download_threshold = sequenced_download_threshold;
+
+ for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
+ , end(m_piece_map.end()); i != end; ++i)
+ {
+ if (i->priority(old_limit) != i->priority(m_sequenced_download_threshold))
+ {
+ piece_pos& p = *i;
+ int prev_priority = p.priority(old_limit);
+ if (prev_priority == 0) continue;
+ move(prev_priority, p.index);
+ }
+ }
+
+ typedef std::vector<int> info_t;
+
+ if (old_limit < sequenced_download_threshold)
+ {
+ // the threshold was incremented, in case
+ // the previous max availability was reached
+ // we need to shuffle that bucket, if not, we
+ // don't have to do anything
+ if (int(m_piece_info.size()) > old_limit * 2)
+ {
+ info_t& in = m_piece_info[old_limit * 2];
+ std::random_shuffle(in.begin(), in.end());
+ int c = 0;
+ for (info_t::iterator i = in.begin()
+ , end(in.end()); i != end; ++i)
+ {
+ m_piece_map[*i].index = c++;
+ TORRENT_ASSERT(m_piece_map[*i].priority(old_limit) == old_limit * 2);
+ }
+ }
+ }
+ else if (int(m_piece_info.size()) > sequenced_download_threshold * 2)
+ {
+ info_t& in = m_piece_info[sequenced_download_threshold * 2];
+ std::sort(in.begin(), in.end());
+ int c = 0;
+ for (info_t::iterator i = in.begin()
+ , end(in.end()); i != end; ++i)
+ {
+ m_piece_map[*i].index = c++;
+ TORRENT_ASSERT(m_piece_map[*i].priority(
+ sequenced_download_threshold) == sequenced_download_threshold * 2);
+ }
+ }
+ }
+
+ piece_picker::downloading_piece& piece_picker::add_download_piece()
+ {
+ int num_downloads = m_downloads.size();
+ int block_index = num_downloads * m_blocks_per_piece;
+ if (int(m_block_info.size()) < block_index + m_blocks_per_piece)
+ {
+ block_info* base = 0;
+ if (!m_block_info.empty()) base = &m_block_info[0];
+ m_block_info.resize(block_index + m_blocks_per_piece);
+ if (!m_downloads.empty() && &m_block_info[0] != base)
+ {
+ // this means the memory was reallocated, update the pointers
+ for (int i = 0; i < int(m_downloads.size()); ++i)
+ m_downloads[i].info = &m_block_info[m_downloads[i].info - base];
+ }
+ }
+ m_downloads.push_back(downloading_piece());
+ downloading_piece& ret = m_downloads.back();
+ ret.info = &m_block_info[block_index];
+ for (int i = 0; i < m_blocks_per_piece; ++i)
+ {
+ ret.info[i].num_peers = 0;
+ ret.info[i].state = block_info::state_none;
+ ret.info[i].peer = 0;
+ }
+ return ret;
+ }
+
+ void piece_picker::erase_download_piece(std::vector<downloading_piece>::iterator i)
+ {
+ std::vector<downloading_piece>::iterator other = std::find_if(
+ m_downloads.begin(), m_downloads.end()
+ , bind(&downloading_piece::info, _1)
+ == &m_block_info[(m_downloads.size() - 1) * m_blocks_per_piece]);
+ TORRENT_ASSERT(other != m_downloads.end());
+
+ if (i != other)
+ {
+ std::copy(other->info, other->info + m_blocks_per_piece, i->info);
+ other->info = i->info;
+ }
+ m_downloads.erase(i);
+ }
+
+#ifndef NDEBUG
+
+ void piece_picker::verify_pick(std::vector<piece_block> const& picked
+ , std::vector<bool> const& bitfield) const
+ {
+ TORRENT_ASSERT(bitfield.size() == m_piece_map.size());
+ for (std::vector<piece_block>::const_iterator i = picked.begin()
+ , end(picked.end()); i != end; ++i)
+ {
+ TORRENT_ASSERT(i->piece_index >= 0);
+ TORRENT_ASSERT(i->piece_index < int(bitfield.size()));
+ TORRENT_ASSERT(bitfield[i->piece_index]);
+ TORRENT_ASSERT(!m_piece_map[i->piece_index].have());
+ }
+ }
+
+ void piece_picker::check_invariant(const torrent* t) const
+ {
+ TORRENT_ASSERT(sizeof(piece_pos) == 4);
+ TORRENT_ASSERT(m_num_have >= 0);
+ TORRENT_ASSERT(m_num_have_filtered >= 0);
+ TORRENT_ASSERT(m_num_filtered >= 0);
+
+ TORRENT_ASSERT(m_piece_info.empty() || m_piece_info[0].empty());
+
+ if (!m_downloads.empty())
+ {
+ for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin();
+ i != m_downloads.end() - 1; ++i)
+ {
+ downloading_piece const& dp = *i;
+ downloading_piece const& next = *(i + 1);
+ TORRENT_ASSERT(dp.finished + dp.writing >= next.finished + next.writing);
+ }
+ }
+
+ if (t != 0)
+ TORRENT_ASSERT((int)m_piece_map.size() == t->torrent_file().num_pieces());
+
+ for (int i = m_sequenced_download_threshold * 2 + 1; i < int(m_piece_info.size()); ++i)
+ TORRENT_ASSERT(m_piece_info[i].empty());
+
+ for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
+ , end(m_downloads.end()); i != end; ++i)
+ {
+ bool blocks_requested = false;
+ int num_blocks = blocks_in_piece(i->index);
+ int num_requested = 0;
+ int num_finished = 0;
+ int num_writing = 0;
+ for (int k = 0; k < num_blocks; ++k)
+ {
+ if (i->info[k].state == block_info::state_finished)
+ {
+ ++num_finished;
+ continue;
+ }
+ if (i->info[k].state == block_info::state_requested)
+ {
+ ++num_requested;
+ blocks_requested = true;
+ TORRENT_ASSERT(i->info[k].num_peers > 0);
+ }
+ if (i->info[k].state == block_info::state_writing)
+ {
+ ++num_writing;
+ }
+ }
+ TORRENT_ASSERT(blocks_requested == (i->state != none));
+ TORRENT_ASSERT(num_requested == i->requested);
+ TORRENT_ASSERT(num_writing == i->writing);
+ TORRENT_ASSERT(num_finished == i->finished);
+ }
+
+
+ int num_filtered = 0;
+ int num_have_filtered = 0;
+ int num_have = 0;
+ for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin();
+ i != m_piece_map.end(); ++i)
+ {
+ int index = static_cast<int>(i - m_piece_map.begin());
+ if (i->filtered())
+ {
+ if (i->index != piece_pos::we_have_index)
+ ++num_filtered;
+ else
+ ++num_have_filtered;
+ }
+ if (i->index == piece_pos::we_have_index)
+ ++num_have;
+
+#if 0
+ if (t != 0)
+ {
+ int actual_peer_count = 0;
+ for (torrent::const_peer_iterator peer = t->begin();
+ peer != t->end(); ++peer)
+ {
+ if (peer->second->has_piece(index)) actual_peer_count++;
+ }
+
+ TORRENT_ASSERT((int)i->peer_count == actual_peer_count);
+/*
+ int num_downloaders = 0;
+ for (std::vector<peer_connection*>::const_iterator peer = t->begin();
+ peer != t->end();
+ ++peer)
+ {
+ const std::vector<piece_block>& queue = (*peer)->download_queue();
+ if (std::find_if(queue.begin(), queue.end(), has_index(index)) == queue.end()) continue;
+
+ ++num_downloaders;
+ }
+
+ if (i->downloading)
+ {
+ TORRENT_ASSERT(num_downloaders == 1);
+ }
+ else
+ {
+ TORRENT_ASSERT(num_downloaders == 0);
+ }
+*/
+ }
+#endif
+
+ if (i->index == piece_pos::we_have_index)
+ {
+ TORRENT_ASSERT(t == 0 || t->have_piece(index));
+ TORRENT_ASSERT(i->downloading == 0);
+/*
+ // make sure there's no entry
+ // with this index. (there shouldn't
+ // be since the piece_map is piece_pos::we_have_index)
+ for (int i = 0; i < int(m_piece_info.size()); ++i)
+ {
+ for (int j = 0; j < int(m_piece_info[i].size()); ++j)
+ {
+ TORRENT_ASSERT(m_piece_info[i][j] != index);
+ }
+ }
+*/
+ }
+ else
+ {
+ if (t != 0)
+ TORRENT_ASSERT(!t->have_piece(index));
+
+ int prio = i->priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prio < int(m_piece_info.size()));
+ if (prio > 0)
+ {
+ const std::vector<int>& vec = m_piece_info[prio];
+ assert (i->index < vec.size());
+ TORRENT_ASSERT(vec[i->index] == index);
+ }
+/*
+ for (int k = 0; k < int(m_piece_info.size()); ++k)
+ {
+ for (int j = 0; j < int(m_piece_info[k].size()); ++j)
+ {
+ TORRENT_ASSERT(int(m_piece_info[k][j]) != index
+ || (prio > 0 && prio == k && int(i->index) == j));
+ }
+ }
+*/
+ }
+
+ int count = std::count_if(m_downloads.begin(), m_downloads.end()
+ , has_index(index));
+ if (i->downloading == 1)
+ {
+ TORRENT_ASSERT(count == 1);
+ }
+ else
+ {
+ TORRENT_ASSERT(count == 0);
+ }
+ }
+ TORRENT_ASSERT(num_have == m_num_have);
+ TORRENT_ASSERT(num_filtered == m_num_filtered);
+ TORRENT_ASSERT(num_have_filtered == m_num_have_filtered);
+ }
+#endif
+
+ float piece_picker::distributed_copies() const
+ {
+ const float num_pieces = static_cast<float>(m_piece_map.size());
+
+ int min_availability = piece_pos::max_peer_count;
+ // find the lowest availability count
+ // count the number of pieces that have that availability
+ // and also the number of pieces that have more than that.
+ int integer_part = 0;
+ int fraction_part = 0;
+ for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin()
+ , end(m_piece_map.end()); i != end; ++i)
+ {
+ int peer_count = int(i->peer_count);
+ // take ourself into account
+ if (i->have()) ++peer_count;
+ if (min_availability > peer_count)
+ {
+ min_availability = peer_count;
+ fraction_part += integer_part;
+ integer_part = 1;
+ }
+ else if (peer_count == min_availability)
+ {
+ ++integer_part;
+ }
+ else
+ {
+ TORRENT_ASSERT(peer_count > min_availability);
+ ++fraction_part;
+ }
+ }
+ TORRENT_ASSERT(integer_part + fraction_part == num_pieces);
+ return float(min_availability) + (fraction_part / num_pieces);
+ }
+
+ void piece_picker::add(int index)
+ {
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < int(m_piece_map.size()));
+ piece_pos& p = m_piece_map[index];
+ TORRENT_ASSERT(!p.filtered());
+ TORRENT_ASSERT(!p.have());
+
+ int priority = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(priority > 0);
+ if (int(m_piece_info.size()) <= priority)
+ m_piece_info.resize(priority + 1);
+
+ TORRENT_ASSERT(int(m_piece_info.size()) > priority);
+
+ if (is_ordered(priority))
+ {
+ // the piece should be inserted ordered, not randomly
+ std::vector<int>& v = m_piece_info[priority];
+// TORRENT_ASSERT(is_sorted(v.begin(), v.end()/*, std::greater<int>()*/));
+ std::vector<int>::iterator i = std::lower_bound(v.begin(), v.end()
+ , index/*, std::greater<int>()*/);
+ p.index = i - v.begin();
+ v.insert(i, index);
+ i = v.begin() + p.index + 1;
+ for (;i != v.end(); ++i)
+ {
+ ++m_piece_map[*i].index;
+ TORRENT_ASSERT(v[m_piece_map[*i].index] == *i);
+ }
+// TORRENT_ASSERT(is_sorted(v.begin(), v.end()/*, std::greater<int>()*/));
+ }
+ else if (m_piece_info[priority].size() < 2)
+ {
+ p.index = m_piece_info[priority].size();
+ m_piece_info[priority].push_back(index);
+ }
+ else
+ {
+ // find a random position in the destination vector where we will place
+ // this entry.
+ int dst_index = rand() % m_piece_info[priority].size();
+
+ // copy the entry at that position to the back
+ m_piece_map[m_piece_info[priority][dst_index]].index
+ = m_piece_info[priority].size();
+ m_piece_info[priority].push_back(m_piece_info[priority][dst_index]);
+
+ // and then replace the one at dst_index with the one we're moving.
+ // this procedure is to make sure there's no ordering when pieces
+ // are moved in sequenced order.
+ p.index = dst_index;
+ m_piece_info[priority][p.index] = index;
+ }
+ }
+
+ // will update the piece with the given properties (priority, elem_index)
+ // to place it at the correct position in the vectors.
+ void piece_picker::move(int priority, int elem_index)
+ {
+ TORRENT_ASSERT(priority > 0);
+ TORRENT_ASSERT(elem_index >= 0);
+ TORRENT_ASSERT(m_files_checked_called);
+
+ TORRENT_ASSERT(int(m_piece_info.size()) > priority);
+ TORRENT_ASSERT(int(m_piece_info[priority].size()) > elem_index);
+
+ int index = m_piece_info[priority][elem_index];
+ // update the piece_map
+ piece_pos& p = m_piece_map[index];
+ TORRENT_ASSERT(int(p.index) == elem_index || p.have());
+
+ int new_priority = p.priority(m_sequenced_download_threshold);
+
+ if (new_priority == priority) return;
+
+ if (int(m_piece_info.size()) <= new_priority
+ && new_priority > 0)
+ {
+ m_piece_info.resize(new_priority + 1);
+ TORRENT_ASSERT(int(m_piece_info.size()) > new_priority);
+ }
+
+ if (new_priority == 0)
+ {
+ // this means the piece should not have an entry
+ }
+ else if (is_ordered(new_priority))
+ {
+ // the piece should be inserted ordered, not randomly
+ std::vector<int>& v = m_piece_info[new_priority];
+// TORRENT_ASSERT(is_sorted(v.begin(), v.end()/*, std::greater<int>()*/));
+ std::vector<int>::iterator i = std::lower_bound(v.begin(), v.end()
+ , index/*, std::greater<int>()*/);
+ p.index = i - v.begin();
+ v.insert(i, index);
+ i = v.begin() + p.index + 1;
+ for (;i != v.end(); ++i)
+ {
+ ++m_piece_map[*i].index;
+ TORRENT_ASSERT(v[m_piece_map[*i].index] == *i);
+ }
+// TORRENT_ASSERT(is_sorted(v.begin(), v.end()/*, std::greater<int>()*/));
+ }
+ else if (m_piece_info[new_priority].size() < 2)
+ {
+ p.index = m_piece_info[new_priority].size();
+ m_piece_info[new_priority].push_back(index);
+ }
+ else
+ {
+ // find a random position in the destination vector where we will place
+ // this entry.
+ int dst_index = rand() % m_piece_info[new_priority].size();
+
+ // copy the entry at that position to the back
+ m_piece_map[m_piece_info[new_priority][dst_index]].index
+ = m_piece_info[new_priority].size();
+ m_piece_info[new_priority].push_back(m_piece_info[new_priority][dst_index]);
+
+ // and then replace the one at dst_index with the one we're moving.
+ // this procedure is to make sure there's no ordering when pieces
+ // are moved in sequenced order.
+ p.index = dst_index;
+ m_piece_info[new_priority][p.index] = index;
+ }
+ TORRENT_ASSERT(new_priority == 0 || p.index < m_piece_info[p.priority(m_sequenced_download_threshold)].size());
+ TORRENT_ASSERT(new_priority == 0 || m_piece_info[p.priority(m_sequenced_download_threshold)][p.index] == index);
+
+ if (is_ordered(priority))
+ {
+ // remove the element from the source vector and preserve the order
+ std::vector<int>& v = m_piece_info[priority];
+ v.erase(v.begin() + elem_index);
+ for (std::vector<int>::iterator i = v.begin() + elem_index;
+ i != v.end(); ++i)
+ {
+ --m_piece_map[*i].index;
+ TORRENT_ASSERT(v[m_piece_map[*i].index] == *i);
+ }
+ }
+ else
+ {
+ // this will remove elem from the source vector without
+ // preserving order, but the order is random anyway
+ int replace_index = m_piece_info[priority][elem_index] = m_piece_info[priority].back();
+ if (index != replace_index)
+ {
+ // update the entry we moved from the back
+ m_piece_map[replace_index].index = elem_index;
+
+ TORRENT_ASSERT(int(m_piece_info[priority].size()) > elem_index);
+ // this may not necessarily be the case. If we've just updated the threshold and are updating
+ // the piece map
+// TORRENT_ASSERT((int)m_piece_map[replace_index].priority(m_sequenced_download_threshold) == priority);
+ TORRENT_ASSERT(int(m_piece_map[replace_index].index) == elem_index);
+ TORRENT_ASSERT(m_piece_info[priority][elem_index] == replace_index);
+ }
+ else
+ {
+ TORRENT_ASSERT(int(m_piece_info[priority].size()) == elem_index+1);
+ }
+
+ m_piece_info[priority].pop_back();
+ }
+ }
+
+ void piece_picker::sort_piece(std::vector<downloading_piece>::iterator dp)
+ {
+ TORRENT_ASSERT(m_piece_map[dp->index].downloading);
+ if (dp == m_downloads.begin()) return;
+ int complete = dp->writing + dp->finished;
+ for (std::vector<downloading_piece>::iterator i = dp, j(dp-1);
+ i != m_downloads.begin(); --i, --j)
+ {
+ TORRENT_ASSERT(j >= m_downloads.begin());
+ if (j->finished + j->writing >= complete) return;
+ using std::swap;
+ swap(*j, *i);
+ if (j == m_downloads.begin()) break;
+ }
+ }
+
+ void piece_picker::restore_piece(int index)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < (int)m_piece_map.size());
+ TORRENT_ASSERT(m_files_checked_called);
+
+ TORRENT_ASSERT(m_piece_map[index].downloading == 1);
+
+ std::vector<downloading_piece>::iterator i
+ = std::find_if(m_downloads.begin(),
+ m_downloads.end(),
+ has_index(index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ erase_download_piece(i);
+
+ piece_pos& p = m_piece_map[index];
+ int prev_priority = p.priority(m_sequenced_download_threshold);
+ p.downloading = 0;
+ int new_priority = p.priority(m_sequenced_download_threshold);
+
+ if (new_priority == prev_priority) return;
+
+ if (prev_priority == 0)
+ {
+ add(index);
+ }
+ else
+ {
+ move(prev_priority, p.index);
+ }
+ }
+
+ void piece_picker::inc_refcount_all()
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+ TORRENT_ASSERT(m_files_checked_called);
+
+ // in general priority = availability * 2
+ // see piece_block::priority()
+
+ // this will insert two empty vectors at the start of the
+ // piece_info vector. It is done like this as an optimization,
+ // to swap vectors instead of copying them
+ while (m_piece_info.size() < 3
+ || (!m_piece_info.rbegin()->empty())
+ || (!(m_piece_info.rbegin()+1)->empty()))
+ {
+ m_piece_info.push_back(std::vector<int>());
+ }
+ TORRENT_ASSERT(m_piece_info.rbegin()->empty());
+ TORRENT_ASSERT((m_piece_info.rbegin()+1)->empty());
+ typedef std::vector<std::vector<int> > piece_info_t;
+ for (piece_info_t::reverse_iterator i = m_piece_info.rbegin(), j(i+1)
+ , k(j+1), end(m_piece_info.rend()); k != end; ++i, ++j, ++k)
+ {
+ k->swap(*i);
+ }
+ TORRENT_ASSERT(m_piece_info.begin()->empty());
+ TORRENT_ASSERT((m_piece_info.begin()+1)->empty());
+
+ // if we have some priorities that are clamped to the
+ // sequenced download, move that vector back down
+ int last_index = m_piece_info.size() - 1;
+ int cap_index = m_sequenced_download_threshold * 2;
+ if (last_index == cap_index)
+ {
+ // this is the case when the top bucket
+ // was moved up into the sequenced download bucket.
+ m_piece_info.push_back(std::vector<int>());
+ m_piece_info[cap_index].swap(m_piece_info[cap_index+1]);
+ ++last_index;
+ }
+ else if (last_index > cap_index)
+ {
+ if (last_index - cap_index == 1)
+ {
+ m_piece_info.push_back(std::vector<int>());
+ ++last_index;
+ }
+ m_piece_info[cap_index+1].swap(m_piece_info[cap_index+2]);
+ m_piece_info[cap_index].swap(m_piece_info[cap_index+1]);
+ }
+
+ // now, increase the peer count of all the pieces.
+ // because of different priorities, some pieces may have
+ // ended up in the wrong priority bucket. Adjust that.
+ for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
+ , end(m_piece_map.end()); i != end; ++i)
+ {
+ int prev_prio = i->priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prev_prio < int(m_piece_info.size()));
+ ++i->peer_count;
+ // if the assumption that the priority would
+ // increase by 2 when increasing the availability
+ // by one isn't true for this particular piece, correct it.
+ // that assumption is true for all pieces with priority 0 or 1
+ int new_prio = i->priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(new_prio <= cap_index);
+ if (prev_prio == 0 && new_prio > 0)
+ {
+ add(i - m_piece_map.begin());
+ continue;
+ }
+ if (new_prio == 0)
+ {
+ TORRENT_ASSERT(prev_prio == 0);
+ continue;
+ }
+ if (prev_prio == cap_index)
+ {
+ TORRENT_ASSERT(new_prio == cap_index);
+ continue;
+ }
+ if (new_prio == prev_prio + 2 && new_prio != cap_index)
+ {
+ TORRENT_ASSERT(new_prio != cap_index);
+ continue;
+ }
+ if (prev_prio + 2 >= cap_index)
+ {
+ // these two vectors will have moved one extra step
+ // passed the sequenced download threshold
+ ++prev_prio;
+ }
+ TORRENT_ASSERT(prev_prio + 2 != cap_index);
+ TORRENT_ASSERT(prev_prio + 2 != new_prio);
+ move(prev_prio + 2, i->index);
+ }
+ }
+
+ void piece_picker::dec_refcount_all()
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+ TORRENT_ASSERT(m_files_checked_called);
+ TORRENT_ASSERT(m_piece_info.size() >= 2);
+ TORRENT_ASSERT(m_piece_info.front().empty());
+ // swap all vectors two steps down
+ if (m_piece_info.size() > 2)
+ {
+ typedef std::vector<std::vector<int> > piece_info_t;
+ for (piece_info_t::iterator i = m_piece_info.begin(), j(i+1)
+ , k(j+1), end(m_piece_info.end()); k != end; ++i, ++j, ++k)
+ {
+ k->swap(*i);
+ }
+ }
+ else
+ {
+ m_piece_info.resize(3);
+ }
+ int last_index = m_piece_info.size() - 1;
+ if ((m_piece_info.size() & 1) == 0)
+ {
+ // if there's an even number of vectors, swap
+ // the last two to get the same layout in both cases
+ m_piece_info[last_index].swap(m_piece_info[last_index-1]);
+ }
+ TORRENT_ASSERT(m_piece_info.back().empty());
+ int pushed_out_index = m_piece_info.size() - 2;
+
+ int cap_index = m_sequenced_download_threshold * 2;
+ TORRENT_ASSERT(m_piece_info[last_index].empty());
+ if (last_index >= cap_index)
+ {
+ TORRENT_ASSERT(pushed_out_index == cap_index - 1
+ || m_piece_info[cap_index - 1].empty());
+ m_piece_info[cap_index].swap(m_piece_info[cap_index - 2]);
+ if (cap_index == pushed_out_index)
+ pushed_out_index = cap_index - 2;
+ }
+
+ // first is the vector that were
+ // bumped down to 0. The should always be moved
+ // since they have to be removed or reinserted
+ std::vector<int>().swap(m_piece_info.front());
+
+ for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
+ , end(m_piece_map.end()); i != end; ++i)
+ {
+ int prev_prio = i->priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prev_prio < int(m_piece_info.size()));
+ TORRENT_ASSERT(pushed_out_index < int(m_piece_info.size()));
+ TORRENT_ASSERT(i->peer_count > 0);
+ --i->peer_count;
+ // if the assumption that the priority would
+ // decrease by 2 when decreasing the availability
+ // by one isn't true for this particular piece, correct it.
+ // that assumption is true for all pieces with priority 0 or 1
+ if (prev_prio == 0)
+ {
+ TORRENT_ASSERT(i->priority(m_sequenced_download_threshold) == 0);
+ continue;
+ }
+
+ int new_prio = i->priority(m_sequenced_download_threshold);
+ if (prev_prio == cap_index)
+ {
+ if (new_prio == cap_index) continue;
+ prev_prio += 2;
+ }
+ else if (new_prio == prev_prio - 2)
+ {
+ continue;
+ }
+ else if (prev_prio == 2)
+ {
+ // if this piece was pushed down to priority 0, it was
+ // removed
+ TORRENT_ASSERT(new_prio > 0);
+ add(i - m_piece_map.begin());
+ continue;
+ }
+ else if (prev_prio == 1)
+ {
+ // if this piece was one of the vectors that was pushed to the
+ // top, adjust the prev_prio to point to that vector, so that
+ // the pieces are moved from there
+ prev_prio = pushed_out_index + 2;
+ }
+ move(prev_prio - 2, i->index);
+ }
+ }
+
+ void piece_picker::inc_refcount(int i)
+ {
+// TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+ TORRENT_ASSERT(i >= 0);
+ TORRENT_ASSERT(i < (int)m_piece_map.size());
+ TORRENT_ASSERT(m_files_checked_called);
+
+ piece_pos& p = m_piece_map[i];
+ int index = p.index;
+ int prev_priority = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prev_priority < int(m_piece_info.size()));
+
+ TORRENT_ASSERT(p.peer_count < piece_pos::max_peer_count);
+ p.peer_count++;
+ TORRENT_ASSERT(p.peer_count != 0);
+
+ // if we have the piece or if it's filtered
+ // we don't have to move any entries in the piece_info vector
+ if (p.priority(m_sequenced_download_threshold) == prev_priority) return;
+
+ if (prev_priority == 0)
+ {
+ add(i);
+ }
+ else
+ {
+ move(prev_priority, index);
+ }
+
+#ifndef NDEBUG
+// integrity_check();
+#endif
+ return;
+ }
+
+ void piece_picker::dec_refcount(int i)
+ {
+// TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_files_checked_called);
+ TORRENT_ASSERT(i >= 0);
+ TORRENT_ASSERT(i < (int)m_piece_map.size());
+
+ piece_pos& p = m_piece_map[i];
+ int prev_priority = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prev_priority < int(m_piece_info.size()));
+ int index = p.index;
+ TORRENT_ASSERT(p.peer_count > 0);
+
+ if (p.peer_count > 0)
+ p.peer_count--;
+
+ if (p.priority(m_sequenced_download_threshold) == prev_priority) return;
+
+ move(prev_priority, index);
+ }
+
+ // this is used to indicate that we succesfully have
+ // downloaded a piece, and that no further attempts
+ // to pick that piece should be made. The piece will
+ // be removed from the available piece list.
+ void piece_picker::we_have(int index)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < (int)m_piece_map.size());
+
+ piece_pos& p = m_piece_map[index];
+ int info_index = p.index;
+ int priority = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(priority < int(m_piece_info.size()));
+
+ if (p.downloading)
+ {
+ std::vector<downloading_piece>::iterator i
+ = std::find_if(m_downloads.begin()
+ , m_downloads.end()
+ , has_index(index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ erase_download_piece(i);
+ p.downloading = 0;
+ }
+
+ TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
+ , has_index(index)) == m_downloads.end());
+
+ if (p.have()) return;
+ if (p.filtered())
+ {
+ --m_num_filtered;
+ ++m_num_have_filtered;
+ }
+ ++m_num_have;
+ p.set_have();
+ if (priority == 0) return;
+ TORRENT_ASSERT(p.priority(m_sequenced_download_threshold) == 0);
+ move(priority, info_index);
+ }
+
+
+ bool piece_picker::set_piece_priority(int index, int new_piece_priority)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+ TORRENT_ASSERT(new_piece_priority >= 0);
+ TORRENT_ASSERT(new_piece_priority <= 7);
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < (int)m_piece_map.size());
+
+ piece_pos& p = m_piece_map[index];
+
+ // if the priority isn't changed, don't do anything
+ if (new_piece_priority == int(p.piece_priority)) return false;
+
+ int prev_priority = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prev_priority < int(m_piece_info.size()));
+
+ bool ret = false;
+ if (new_piece_priority == piece_pos::filter_priority
+ && p.piece_priority != piece_pos::filter_priority)
+ {
+ // the piece just got filtered
+ if (p.have()) ++m_num_have_filtered;
+ else ++m_num_filtered;
+ ret = true;
+ }
+ else if (new_piece_priority != piece_pos::filter_priority
+ && p.piece_priority == piece_pos::filter_priority)
+ {
+ // the piece just got unfiltered
+ if (p.have()) --m_num_have_filtered;
+ else --m_num_filtered;
+ ret = true;
+ }
+ TORRENT_ASSERT(m_num_filtered >= 0);
+ TORRENT_ASSERT(m_num_have_filtered >= 0);
+
+ p.piece_priority = new_piece_priority;
+ int new_priority = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prev_priority < int(m_piece_info.size()));
+
+ if (new_priority == prev_priority) return false;
+
+ if (prev_priority == 0)
+ {
+ add(index);
+ }
+ else
+ {
+ move(prev_priority, p.index);
+ }
+ return ret;
+ }
+
+ int piece_picker::piece_priority(int index) const
+ {
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < (int)m_piece_map.size());
+
+ return m_piece_map[index].piece_priority;
+ }
+
+ void piece_picker::piece_priorities(std::vector<int>& pieces) const
+ {
+ pieces.resize(m_piece_map.size());
+ std::vector<int>::iterator j = pieces.begin();
+ for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin(),
+ end(m_piece_map.end()); i != end; ++i, ++j)
+ {
+ *j = i->piece_priority;
+ }
+ }
+
+ // ============ start deprecation ==============
+
+ void piece_picker::filtered_pieces(std::vector<bool>& mask) const
+ {
+ mask.resize(m_piece_map.size());
+ std::vector<bool>::iterator j = mask.begin();
+ for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin(),
+ end(m_piece_map.end()); i != end; ++i, ++j)
+ {
+ *j = i->filtered();
+ }
+ }
+
+ // ============ end deprecation ==============
+
+ // pieces describes which pieces the peer we're requesting from
+ // has.
+ // interesting_blocks is an out parameter, and will be filled
+ // with (up to) num_blocks of interesting blocks that the peer has.
+ // prefer_whole_pieces can be set if this peer should download
+ // whole pieces rather than trying to download blocks from the
+ // same piece as other peers.
+ // the void* is the pointer to the policy::peer of the peer we're
+ // picking pieces from. This is used when downloading whole pieces,
+ // to only pick from the same piece the same peer is downloading
+ // from. state is supposed to be set to fast if the peer is downloading
+ // relatively fast, by some notion. Slow peers will prefer not
+ // to pick blocks from the same pieces as fast peers, and vice
+ // versa. Downloading pieces are marked as being fast, medium
+ // or slow once they're started.
+ void piece_picker::pick_pieces(const std::vector<bool>& pieces
+ , std::vector<piece_block>& interesting_blocks
+ , int num_blocks, int prefer_whole_pieces
+ , void* peer, piece_state_t speed, bool rarest_first
+ , bool on_parole, std::vector<int> const& suggested_pieces) const
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+ TORRENT_ASSERT(num_blocks > 0);
+ TORRENT_ASSERT(pieces.size() == m_piece_map.size());
+ TORRENT_ASSERT(m_files_checked_called);
+
+ TORRENT_ASSERT(m_piece_info.begin() != m_piece_info.end());
+
+ // this will be filled with blocks that we should not request
+ // unless we can't find num_blocks among the other ones.
+ // blocks that belong to pieces with a mismatching speed
+ // category for instance, or if we prefer whole pieces,
+ // blocks belonging to a piece that others have
+ // downloaded to
+ std::vector<piece_block> backup_blocks;
+ // suggested pieces for each vector is put in this vector
+ std::vector<int> suggested_bucket;
+ const std::vector<int> empty_vector;
+
+ // When prefer_whole_pieces is set (usually set when downloading from
+ // fast peers) the partial pieces will not be prioritized, but actually
+ // ignored as long as possible. All blocks found in downloading
+ // pieces are regarded as backup blocks
+
+ num_blocks = add_blocks_downloading(pieces
+ , interesting_blocks, backup_blocks, num_blocks
+ , prefer_whole_pieces, peer, speed, on_parole);
+
+ if (num_blocks <= 0) return;
+
+ if (rarest_first)
+ {
+ // this loop will loop from pieces with priority 1 and up
+ // until we either reach the end of the piece list or
+ // has filled the interesting_blocks with num_blocks
+ // blocks.
+
+ // +1 is to ignore pieces that no peer has. The bucket with index 0 contains
+ // pieces that 0 other peers have. bucket will point to a bucket with
+ // pieces with the same priority. It will be iterated in priority
+ // order (high priority/rare pices first). The content of each
+ // bucket is randomized
+ for (std::vector<std::vector<int> >::const_iterator bucket
+ = m_piece_info.begin() + 1; num_blocks > 0 && bucket != m_piece_info.end();
+ ++bucket)
+ {
+ if (bucket->empty()) continue;
+ if (!suggested_pieces.empty())
+ {
+ int bucket_index = bucket - m_piece_info.begin();
+ suggested_bucket.clear();
+ for (std::vector<int>::const_iterator i = suggested_pieces.begin()
+ , end(suggested_pieces.end()); i != end; ++i)
+ {
+ TORRENT_ASSERT(*i >= 0);
+ TORRENT_ASSERT(*i < int(m_piece_map.size()));
+ if (!can_pick(*i, pieces)) continue;
+ if (m_piece_map[*i].priority(m_sequenced_download_threshold) == bucket_index)
+ suggested_bucket.push_back(*i);
+ }
+ if (!suggested_bucket.empty())
+ {
+ num_blocks = add_blocks(suggested_bucket, pieces
+ , interesting_blocks, num_blocks
+ , prefer_whole_pieces, peer, empty_vector);
+ if (num_blocks == 0) break;
+ }
+ }
+ num_blocks = add_blocks(*bucket, pieces
+ , interesting_blocks, num_blocks
+ , prefer_whole_pieces, peer, suggested_bucket);
+ TORRENT_ASSERT(num_blocks >= 0);
+ }
+ }
+ else
+ {
+ // we're not using rarest first (only for the first
+ // bucket, since that's where the currently downloading
+ // pieces are)
+ int start_piece = rand() % m_piece_map.size();
+
+ // if we have suggested pieces, try to find one of those instead
+ for (std::vector<int>::const_iterator i = suggested_pieces.begin()
+ , end(suggested_pieces.end()); i != end; ++i)
+ {
+ if (!can_pick(*i, pieces)) continue;
+ start_piece = *i;
+ break;
+ }
+ int piece = start_piece;
+ while (num_blocks > 0)
+ {
+ while (!can_pick(piece, pieces))
+ {
+ ++piece;
+ if (piece == int(m_piece_map.size())) piece = 0;
+ // could not find any more pieces
+ if (piece == start_piece) return;
+ }
+
+ int start, end;
+ boost::tie(start, end) = expand_piece(piece, prefer_whole_pieces, pieces);
+ for (int k = start; k < end; ++k)
+ {
+ TORRENT_ASSERT(m_piece_map[piece].downloading == false);
+ TORRENT_ASSERT(m_piece_map[k].priority(m_sequenced_download_threshold) > 0);
+ int num_blocks_in_piece = blocks_in_piece(k);
+ if (prefer_whole_pieces == 0 && num_blocks_in_piece > num_blocks)
+ num_blocks_in_piece = num_blocks;
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ {
+ interesting_blocks.push_back(piece_block(k, j));
+ --num_blocks;
+ }
+ }
+ piece = end;
+ if (piece == int(m_piece_map.size())) piece = 0;
+ // could not find any more pieces
+ if (piece == start_piece) return;
+ }
+
+ }
+
+ if (num_blocks <= 0) return;
+
+ if (!backup_blocks.empty())
+ interesting_blocks.insert(interesting_blocks.end()
+ , backup_blocks.begin(), backup_blocks.end());
+ }
+
+ bool piece_picker::can_pick(int piece, std::vector<bool> const& bitmask) const
+ {
+ TORRENT_ASSERT(piece >= 0 && piece < int(m_piece_map.size()));
+ return bitmask[piece]
+ && !m_piece_map[piece].have()
+ && !m_piece_map[piece].downloading
+ && !m_piece_map[piece].filtered();
+ }
+
+ void piece_picker::clear_peer(void* peer)
+ {
+ for (std::vector<block_info>::iterator i = m_block_info.begin()
+ , end(m_block_info.end()); i != end; ++i)
+ if (i->peer == peer) i->peer = 0;
+ }
+
+ namespace
+ {
+ // the first bool is true if this is the only peer that has requested and downloaded
+ // blocks from this piece.
+ // the second bool is true if this is the only active peer that is requesting
+ // and downloading blocks from this piece. Active means having a connection.
+ boost::tuple<bool, bool> requested_from(piece_picker::downloading_piece const& p
+ , int num_blocks_in_piece, void* peer)
+ {
+ bool exclusive = true;
+ bool exclusive_active = true;
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ {
+ piece_picker::block_info const& info = p.info[j];
+ if (info.state != piece_picker::block_info::state_none
+ && info.peer != peer)
+ {
+ exclusive = false;
+ if (info.state == piece_picker::block_info::state_requested
+ && info.peer != 0)
+ {
+ exclusive_active = false;
+ return boost::make_tuple(exclusive, exclusive_active);
+ }
+ }
+ }
+ return boost::make_tuple(exclusive, exclusive_active);
+ }
+ }
+
+ int piece_picker::add_blocks(std::vector<int> const& piece_list
+ , std::vector<bool> const& pieces
+ , std::vector<piece_block>& interesting_blocks
+ , int num_blocks, int prefer_whole_pieces
+ , void* peer, std::vector<int> const& ignore) const
+ {
+ for (std::vector<int>::const_iterator i = piece_list.begin();
+ i != piece_list.end(); ++i)
+ {
+ TORRENT_ASSERT(*i >= 0);
+ TORRENT_ASSERT(*i < (int)m_piece_map.size());
+
+ // if the peer doesn't have the piece
+ // skip it
+ if (!pieces[*i]) continue;
+
+ // ignore pieces found in the ignore list
+ if (std::find(ignore.begin(), ignore.end(), *i) != ignore.end()) continue;
+
+ // skip the piece is the priority is 0
+ TORRENT_ASSERT(m_piece_map[*i].priority(m_sequenced_download_threshold) > 0);
+
+ int num_blocks_in_piece = blocks_in_piece(*i);
+
+ TORRENT_ASSERT(m_piece_map[*i].downloading == 0);
+ TORRENT_ASSERT(m_piece_map[*i].priority(m_sequenced_download_threshold) > 0);
+
+ // pick a new piece
+ if (prefer_whole_pieces == 0)
+ {
+ if (num_blocks_in_piece > num_blocks)
+ num_blocks_in_piece = num_blocks;
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ interesting_blocks.push_back(piece_block(*i, j));
+ num_blocks -= num_blocks_in_piece;
+ }
+ else
+ {
+ int start, end;
+ boost::tie(start, end) = expand_piece(*i, prefer_whole_pieces, pieces);
+ for (int k = start; k < end; ++k)
+ {
+ TORRENT_ASSERT(m_piece_map[k].priority(m_sequenced_download_threshold) > 0);
+ num_blocks_in_piece = blocks_in_piece(k);
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ {
+ interesting_blocks.push_back(piece_block(k, j));
+ --num_blocks;
+ }
+ }
+ }
+ if (num_blocks <= 0)
+ {
+#ifndef NDEBUG
+ verify_pick(interesting_blocks, pieces);
+#endif
+ return 0;
+ }
+ }
+#ifndef NDEBUG
+ verify_pick(interesting_blocks, pieces);
+#endif
+ return num_blocks;
+ }
+
+ int piece_picker::add_blocks_downloading(std::vector<bool> const& pieces
+ , std::vector<piece_block>& interesting_blocks
+ , std::vector<piece_block>& backup_blocks
+ , int num_blocks, int prefer_whole_pieces
+ , void* peer, piece_state_t speed, bool on_parole) const
+ {
+ for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
+ , end(m_downloads.end()); i != end; ++i)
+ {
+ if (!pieces[i->index]) continue;
+
+ int num_blocks_in_piece = blocks_in_piece(i->index);
+
+ // is true if all the other pieces that are currently
+ // requested from this piece are from the same
+ // peer as 'peer'.
+ bool exclusive;
+ bool exclusive_active;
+ boost::tie(exclusive, exclusive_active)
+ = requested_from(*i, num_blocks_in_piece, peer);
+
+ // peers on parole are only allowed to pick blocks from
+ // pieces that only they have downloaded/requested from
+ if (on_parole && !exclusive) continue;
+
+ if (prefer_whole_pieces > 0 && !exclusive_active) continue;
+
+ // don't pick too many back-up blocks
+ if (i->state != none
+ && i->state != speed
+ && !exclusive_active
+ && int(backup_blocks.size()) >= num_blocks)
+ continue;
+
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ {
+ // ignore completed blocks and already requested blocks
+ block_info const& info = i->info[j];
+ if (info.state != block_info::state_none)
+ continue;
+
+ TORRENT_ASSERT(i->info[j].state == block_info::state_none);
+
+ // if the piece is fast and the peer is slow, or vice versa,
+ // add the block as a backup.
+ // override this behavior if all the other blocks
+ // have been requested from the same peer or
+ // if the state of the piece is none (the
+ // piece will in that case change state).
+ if (i->state != none && i->state != speed
+ && !exclusive_active)
+ {
+ backup_blocks.push_back(piece_block(i->index, j));
+ continue;
+ }
+
+ // this block is interesting (we don't have it
+ // yet).
+ interesting_blocks.push_back(piece_block(i->index, j));
+ // we have found a block that's free to download
+ num_blocks--;
+ // if we prefer whole pieces, continue picking from this
+ // piece even though we have num_blocks
+ if (prefer_whole_pieces > 0) continue;
+ TORRENT_ASSERT(num_blocks >= 0);
+ if (num_blocks <= 0) break;
+ }
+ if (num_blocks <= 0) break;
+ }
+
+ TORRENT_ASSERT(num_blocks >= 0 || prefer_whole_pieces > 0);
+
+#ifndef NDEBUG
+ verify_pick(interesting_blocks, pieces);
+ verify_pick(backup_blocks, pieces);
+#endif
+
+ if (num_blocks <= 0) return 0;
+ if (on_parole) return num_blocks;
+
+ int to_copy;
+ if (prefer_whole_pieces == 0)
+ to_copy = (std::min)(int(backup_blocks.size()), num_blocks);
+ else
+ to_copy = int(backup_blocks.size());
+
+ interesting_blocks.insert(interesting_blocks.end()
+ , backup_blocks.begin(), backup_blocks.begin() + to_copy);
+ num_blocks -= to_copy;
+ backup_blocks.clear();
+
+ if (num_blocks <= 0) return 0;
+
+ if (prefer_whole_pieces > 0)
+ {
+ for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
+ , end(m_downloads.end()); i != end; ++i)
+ {
+ if (!pieces[i->index]) continue;
+ int num_blocks_in_piece = blocks_in_piece(i->index);
+ bool exclusive;
+ bool exclusive_active;
+ boost::tie(exclusive, exclusive_active)
+ = requested_from(*i, num_blocks_in_piece, peer);
+
+ if (exclusive_active) continue;
+
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ {
+ block_info const& info = i->info[j];
+ if (info.state != block_info::state_none) continue;
+ backup_blocks.push_back(piece_block(i->index, j));
+ }
+ }
+ }
+
+ if (int(backup_blocks.size()) >= num_blocks) return num_blocks;
+
+
+#ifndef NDEBUG
+// make sure that we at this point has added requests to all unrequested blocks
+// in all downloading pieces
+
+ for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
+ , end(m_downloads.end()); i != end; ++i)
+ {
+ if (!pieces[i->index]) continue;
+
+ int num_blocks_in_piece = blocks_in_piece(i->index);
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ {
+ block_info const& info = i->info[j];
+ if (info.state != block_info::state_none) continue;
+ std::vector<piece_block>::iterator k = std::find(
+ interesting_blocks.begin(), interesting_blocks.end()
+ , piece_block(i->index, j));
+ if (k != interesting_blocks.end()) continue;
+
+ k = std::find(backup_blocks.begin()
+ , backup_blocks.end(), piece_block(i->index, j));
+ if (k != backup_blocks.end()) continue;
+
+ std::cerr << "interesting blocks:" << std::endl;
+ for (k = interesting_blocks.begin(); k != interesting_blocks.end(); ++k)
+ std::cerr << "(" << k->piece_index << ", " << k->block_index << ") ";
+ std::cerr << std::endl;
+ std::cerr << "backup blocks:" << std::endl;
+ for (k = backup_blocks.begin(); k != backup_blocks.end(); ++k)
+ std::cerr << "(" << k->piece_index << ", " << k->block_index << ") ";
+ std::cerr << std::endl;
+ std::cerr << "num_blocks: " << num_blocks << std::endl;
+
+ for (std::vector<downloading_piece>::const_iterator l = m_downloads.begin()
+ , end(m_downloads.end()); l != end; ++l)
+ {
+ std::cerr << l->index << " : ";
+ int num_blocks_in_piece = blocks_in_piece(l->index);
+ for (int m = 0; m < num_blocks_in_piece; ++m)
+ std::cerr << l->info[m].state;
+ std::cerr << std::endl;
+ }
+
+ TORRENT_ASSERT(false);
+ }
+ }
+#endif
+
+ for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
+ , end(m_downloads.end()); i != end; ++i)
+ {
+ if (!pieces[i->index]) continue;
+
+ int num_blocks_in_piece = blocks_in_piece(i->index);
+
+ // fill in with blocks requested from other peers
+ // as backups
+ for (int j = 0; j < num_blocks_in_piece; ++j)
+ {
+ block_info const& info = i->info[j];
+ if (info.state != block_info::state_requested
+ || info.peer == peer)
+ continue;
+ backup_blocks.push_back(piece_block(i->index, j));
+ }
+ }
+#ifndef NDEBUG
+ verify_pick(backup_blocks, pieces);
+#endif
+ return num_blocks;
+ }
+
+ std::pair<int, int> piece_picker::expand_piece(int piece, int whole_pieces
+ , std::vector<bool> const& have) const
+ {
+ if (whole_pieces == 0) return std::make_pair(piece, piece + 1);
+
+ int start = piece - 1;
+ int lower_limit = piece - whole_pieces;
+ if (lower_limit < -1) lower_limit = -1;
+ while (start > lower_limit
+ && can_pick(start, have))
+ --start;
+ ++start;
+ TORRENT_ASSERT(start >= 0);
+ int end = piece + 1;
+ int upper_limit = start + whole_pieces;
+ if (upper_limit > int(m_piece_map.size())) upper_limit = int(m_piece_map.size());
+ while (end < upper_limit
+ && can_pick(end, have))
+ ++end;
+ return std::make_pair(start, end);
+ }
+
+ bool piece_picker::is_piece_finished(int index) const
+ {
+ TORRENT_ASSERT(index < (int)m_piece_map.size());
+ TORRENT_ASSERT(index >= 0);
+
+ if (m_piece_map[index].downloading == 0)
+ {
+ TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
+ , has_index(index)) == m_downloads.end());
+ return false;
+ }
+ std::vector<downloading_piece>::const_iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ TORRENT_ASSERT((int)i->finished <= m_blocks_per_piece);
+ int max_blocks = blocks_in_piece(index);
+ if ((int)i->finished < max_blocks) return false;
+
+#ifndef NDEBUG
+ for (int k = 0; k < max_blocks; ++k)
+ {
+ TORRENT_ASSERT(i->info[k].state == block_info::state_finished);
+ }
+#endif
+
+ TORRENT_ASSERT((int)i->finished == max_blocks);
+ return true;
+ }
+
+ bool piece_picker::is_requested(piece_block block) const
+ {
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+
+ if (m_piece_map[block.piece_index].downloading == 0) return false;
+ std::vector<downloading_piece>::const_iterator i
+ = std::find_if(
+ m_downloads.begin()
+ , m_downloads.end()
+ , has_index(block.piece_index));
+
+ TORRENT_ASSERT(i != m_downloads.end());
+ return i->info[block.block_index].state == block_info::state_requested;
+ }
+
+ bool piece_picker::is_downloaded(piece_block block) const
+ {
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+
+ if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
+ if (m_piece_map[block.piece_index].downloading == 0) return false;
+ std::vector<downloading_piece>::const_iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ return i->info[block.block_index].state == block_info::state_finished
+ || i->info[block.block_index].state == block_info::state_writing;
+ }
+
+ bool piece_picker::is_finished(piece_block block) const
+ {
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+
+ if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
+ if (m_piece_map[block.piece_index].downloading == 0) return false;
+ std::vector<downloading_piece>::const_iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ return i->info[block.block_index].state == block_info::state_finished;
+ }
+
+
+ bool piece_picker::mark_as_downloading(piece_block block
+ , void* peer, piece_state_t state)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+ TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
+ TORRENT_ASSERT(!m_piece_map[block.piece_index].have());
+
+ piece_pos& p = m_piece_map[block.piece_index];
+ if (p.downloading == 0)
+ {
+ int prio = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prio < int(m_piece_info.size()));
+ TORRENT_ASSERT(prio > 0);
+ p.downloading = 1;
+ move(prio, p.index);
+
+ downloading_piece& dp = add_download_piece();
+ dp.state = state;
+ dp.index = block.piece_index;
+ block_info& info = dp.info[block.block_index];
+ info.state = block_info::state_requested;
+ info.peer = peer;
+ info.num_peers = 1;
+ ++dp.requested;
+ }
+ else
+ {
+ std::vector<downloading_piece>::iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ block_info& info = i->info[block.block_index];
+ if (info.state == block_info::state_writing
+ || info.state == block_info::state_finished)
+ return false;
+ TORRENT_ASSERT(info.state == block_info::state_none
+ || (info.state == block_info::state_requested
+ && (info.num_peers > 0)));
+ info.peer = peer;
+ if (info.state != block_info::state_requested)
+ {
+ info.state = block_info::state_requested;
+ ++i->requested;
+ }
+ ++info.num_peers;
+ if (i->state == none) i->state = state;
+ }
+ return true;
+ }
+
+ int piece_picker::num_peers(piece_block block) const
+ {
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+ TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
+
+ piece_pos const& p = m_piece_map[block.piece_index];
+ if (!p.downloading) return 0;
+
+ std::vector<downloading_piece>::const_iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ TORRENT_ASSERT(i != m_downloads.end());
+
+ block_info const& info = i->info[block.block_index];
+ return info.num_peers;
+ }
+
+ void piece_picker::get_availability(std::vector<int>& avail) const
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ avail.resize(m_piece_map.size());
+ std::vector<int>::iterator j = avail.begin();
+ for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin()
+ , end(m_piece_map.end()); i != end; ++i, ++j)
+ *j = i->peer_count;
+ }
+
+ void piece_picker::mark_as_writing(piece_block block, void* peer)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+ TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
+
+ TORRENT_ASSERT(m_piece_map[block.piece_index].downloading);
+
+ std::vector<downloading_piece>::iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ block_info& info = i->info[block.block_index];
+ info.peer = peer;
+ TORRENT_ASSERT(info.state == block_info::state_requested);
+ if (info.state == block_info::state_requested) --i->requested;
+ TORRENT_ASSERT(i->requested >= 0);
+ TORRENT_ASSERT(info.state != block_info::state_writing);
+ ++i->writing;
+ info.state = block_info::state_writing;
+ if (info.num_peers > 0) --info.num_peers;
+
+ if (i->requested == 0)
+ {
+ // there are no blocks requested in this piece.
+ // remove the fast/slow state from it
+ i->state = none;
+ }
+ sort_piece(i);
+ }
+
+ void piece_picker::mark_as_finished(piece_block block, void* peer)
+ {
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+ TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
+
+ piece_pos& p = m_piece_map[block.piece_index];
+
+ if (p.downloading == 0)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ TORRENT_ASSERT(peer == 0);
+ int prio = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prio < int(m_piece_info.size()));
+ p.downloading = 1;
+ if (prio > 0) move(prio, p.index);
+ else TORRENT_ASSERT(p.priority(m_sequenced_download_threshold) == 0);
+
+ downloading_piece& dp = add_download_piece();
+ dp.state = none;
+ dp.index = block.piece_index;
+ block_info& info = dp.info[block.block_index];
+ info.peer = peer;
+ TORRENT_ASSERT(info.state == block_info::state_none);
+ if (info.state != block_info::state_finished)
+ {
+ ++dp.finished;
+ sort_piece(m_downloads.end() - 1);
+ }
+ info.state = block_info::state_finished;
+ }
+ else
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ std::vector<downloading_piece>::iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ TORRENT_ASSERT(i != m_downloads.end());
+ block_info& info = i->info[block.block_index];
+ info.peer = peer;
+ TORRENT_ASSERT(info.state == block_info::state_writing
+ || peer == 0);
+ TORRENT_ASSERT(i->writing >= 0);
+ ++i->finished;
+ if (info.state == block_info::state_writing)
+ {
+ --i->writing;
+ info.state = block_info::state_finished;
+ }
+ else
+ {
+ info.state = block_info::state_finished;
+ sort_piece(i);
+ }
+ }
+ }
+
+ void piece_picker::get_downloaders(std::vector<void*>& d, int index) const
+ {
+ TORRENT_ASSERT(index >= 0 && index <= (int)m_piece_map.size());
+ std::vector<downloading_piece>::const_iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
+ TORRENT_ASSERT(i != m_downloads.end());
+
+ d.clear();
+ for (int j = 0; j < blocks_in_piece(index); ++j)
+ {
+ d.push_back(i->info[j].peer);
+ }
+ }
+
+ void* piece_picker::get_downloader(piece_block block) const
+ {
+ std::vector<downloading_piece>::const_iterator i = std::find_if(
+ m_downloads.begin()
+ , m_downloads.end()
+ , has_index(block.piece_index));
+
+ if (i == m_downloads.end()) return 0;
+
+ TORRENT_ASSERT(block.block_index >= 0);
+
+ if (i->info[block.block_index].state == block_info::state_none)
+ return 0;
+
+ return i->info[block.block_index].peer;
+ }
+
+ void piece_picker::abort_download(piece_block block)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ TORRENT_ASSERT(block.piece_index >= 0);
+ TORRENT_ASSERT(block.block_index >= 0);
+ TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size());
+ TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
+
+ if (m_piece_map[block.piece_index].downloading == 0)
+ {
+ TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
+ , has_index(block.piece_index)) == m_downloads.end());
+ return;
+ }
+
+ std::vector<downloading_piece>::iterator i = std::find_if(m_downloads.begin()
+ , m_downloads.end(), has_index(block.piece_index));
+ TORRENT_ASSERT(i != m_downloads.end());
+
+ block_info& info = i->info[block.block_index];
+ --info.num_peers;
+ if (info.num_peers > 0) return;
+
+ if (i->info[block.block_index].state == block_info::state_finished
+ || i->info[block.block_index].state == block_info::state_writing)
+ {
+ return;
+ }
+
+ TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
+ TORRENT_ASSERT(i->info[block.block_index].state == block_info::state_requested);
+
+ // clear this block as being downloaded
+ info.state = block_info::state_none;
+ --i->requested;
+
+ // clear the downloader of this block
+ info.peer = 0;
+
+ // if there are no other blocks in this piece
+ // that's being downloaded, remove it from the list
+ if (i->requested + i->finished + i->writing == 0)
+ {
+ erase_download_piece(i);
+ piece_pos& p = m_piece_map[block.piece_index];
+ int prev_prio = p.priority(m_sequenced_download_threshold);
+ TORRENT_ASSERT(prev_prio < int(m_piece_info.size()));
+ p.downloading = 0;
+ int prio = p.priority(m_sequenced_download_threshold);
+ if (prev_prio == 0 && prio > 0) add(block.piece_index);
+ else if (prio > 0) move(prio, p.index);
+
+ TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
+ , has_index(block.piece_index)) == m_downloads.end());
+ }
+ else if (i->requested == 0)
+ {
+ // there are no blocks requested in this piece.
+ // remove the fast/slow state from it
+ i->state = none;
+ }
+ }
+
+ int piece_picker::unverified_blocks() const
+ {
+ int counter = 0;
+ for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin();
+ i != m_downloads.end(); ++i)
+ {
+ counter += (int)i->finished;
+ }
+ return counter;
+ }
+
+}
+
diff --git a/src/libtorrent/src/policy.cpp b/src/libtorrent/src/policy.cpp
new file mode 100644
index 0000000..1b6a60c
--- /dev/null
+++ b/src/libtorrent/src/policy.cpp
@@ -0,0 +1,1587 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <iostream>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/bind.hpp>
+#include <boost/utility.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/web_peer_connection.hpp"
+#include "libtorrent/policy.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/alert_types.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/time.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+#include "libtorrent/piece_picker.hpp"
+
+#ifndef NDEBUG
+#include "libtorrent/bt_peer_connection.hpp"
+#endif
+
+namespace libtorrent
+{
+ class peer_connection;
+}
+
+using boost::bind;
+
+namespace
+{
+ using namespace libtorrent;
+
+ size_type collect_free_download(
+ torrent::peer_iterator start
+ , torrent::peer_iterator end)
+ {
+ size_type accumulator = 0;
+ for (torrent::peer_iterator i = start; i != end; ++i)
+ {
+ // if the peer is interested in us, it means it may
+ // want to trade it's surplus uploads for downloads itself
+ // (and we should not consider it free). If the share diff is
+ // negative, there's no free download to get from this peer.
+ size_type diff = (*i)->share_diff();
+ TORRENT_ASSERT(diff < (std::numeric_limits<size_type>::max)());
+ if ((*i)->is_peer_interested() || diff <= 0)
+ continue;
+
+ TORRENT_ASSERT(diff > 0);
+ (*i)->add_free_upload(-diff);
+ accumulator += diff;
+ TORRENT_ASSERT(accumulator > 0);
+ }
+ TORRENT_ASSERT(accumulator >= 0);
+ return accumulator;
+ }
+
+
+ // returns the amount of free upload left after
+ // it has been distributed to the peers
+ size_type distribute_free_upload(
+ torrent::peer_iterator start
+ , torrent::peer_iterator end
+ , size_type free_upload)
+ {
+ if (free_upload <= 0) return free_upload;
+ int num_peers = 0;
+ size_type total_diff = 0;
+ for (torrent::peer_iterator i = start; i != end; ++i)
+ {
+ size_type d = (*i)->share_diff();
+ TORRENT_ASSERT(d < (std::numeric_limits<size_type>::max)());
+ total_diff += d;
+ if (!(*i)->is_peer_interested() || (*i)->share_diff() >= 0) continue;
+ ++num_peers;
+ }
+
+ if (num_peers == 0) return free_upload;
+ size_type upload_share;
+ if (total_diff >= 0)
+ {
+ upload_share = (std::min)(free_upload, total_diff) / num_peers;
+ }
+ else
+ {
+ upload_share = (free_upload + total_diff) / num_peers;
+ }
+ if (upload_share < 0) return free_upload;
+
+ for (torrent::peer_iterator i = start; i != end; ++i)
+ {
+ peer_connection* p = *i;
+ if (!p->is_peer_interested() || p->share_diff() >= 0) continue;
+ p->add_free_upload(upload_share);
+ free_upload -= upload_share;
+ }
+ return free_upload;
+ }
+
+ struct match_peer_endpoint
+ {
+ match_peer_endpoint(tcp::endpoint const& ep)
+ : m_ep(ep)
+ {}
+
+ bool operator()(std::pair<const address, policy::peer> const& p) const
+ { return p.second.ip == m_ep; }
+
+ tcp::endpoint const& m_ep;
+ };
+
+ struct match_peer_id
+ {
+ match_peer_id(peer_id const& id_)
+ : m_id(id_)
+ {}
+
+ bool operator()(std::pair<const address, policy::peer> const& p) const
+ { return p.second.connection && p.second.connection->pid() == m_id; }
+
+ peer_id const& m_id;
+ };
+
+ struct match_peer_connection
+ {
+ match_peer_connection(peer_connection const& c)
+ : m_conn(c)
+ {}
+
+ bool operator()(std::pair<const address, policy::peer> const& p) const
+ {
+ return p.second.connection == &m_conn
+ || (p.second.ip == m_conn.remote()
+ && p.second.type == policy::peer::connectable);
+ }
+
+ peer_connection const& m_conn;
+ };
+
+
+}
+
+namespace libtorrent
+{
+ // the case where ignore_peer is motivated is if two peers
+ // have only one piece that we don't have, and it's the
+ // same piece for both peers. Then they might get into an
+ // infinite loop, fighting to request the same blocks.
+ void request_a_block(torrent& t, peer_connection& c)
+ {
+ if (t.is_seed()) return;
+
+ TORRENT_ASSERT(t.valid_metadata());
+ TORRENT_ASSERT(c.peer_info_struct() != 0 || !dynamic_cast<bt_peer_connection*>(&c));
+ int num_requests = c.desired_queue_size()
+ - (int)c.download_queue().size()
+ - (int)c.request_queue().size();
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*c.m_logger) << time_now_string() << " PIECE_PICKER [ req: " << num_requests << " ]\n";
+#endif
+ TORRENT_ASSERT(c.desired_queue_size() > 0);
+ // if our request queue is already full, we
+ // don't have to make any new requests yet
+ if (num_requests <= 0) return;
+
+ piece_picker& p = t.picker();
+ std::vector<piece_block> interesting_pieces;
+ interesting_pieces.reserve(100);
+
+ int prefer_whole_pieces = c.prefer_whole_pieces();
+
+ bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold;
+
+ if (prefer_whole_pieces == 0)
+ {
+ prefer_whole_pieces = c.statistics().download_payload_rate()
+ * t.settings().whole_pieces_threshold
+ > t.torrent_file().piece_length() ? 1 : 0;
+ }
+
+ // if we prefer whole pieces, the piece picker will pick at least
+ // the number of blocks we want, but it will try to make the picked
+ // blocks be from whole pieces, possibly by returning more blocks
+ // than we requested.
+ TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint());
+
+ piece_picker::piece_state_t state;
+ peer_connection::peer_speed_t speed = c.peer_speed();
+ if (speed == peer_connection::fast) state = piece_picker::fast;
+ else if (speed == peer_connection::medium) state = piece_picker::medium;
+ else state = piece_picker::slow;
+
+ // this vector is filled with the interesting pieces
+ // that some other peer is currently downloading
+ // we should then compare this peer's download speed
+ // with the other's, to see if we should abort another
+ // peer_connection in favour of this one
+ std::vector<piece_block> busy_pieces;
+ busy_pieces.reserve(num_requests);
+
+ std::vector<int> const& suggested = c.suggested_pieces();
+ std::vector<bool> const& bitfield = c.get_bitfield();
+
+ if (c.has_peer_choked())
+ {
+ // if we are choked we can only pick pieces from the
+ // allowed fast set. The allowed fast set is sorted
+ // in ascending priority order
+ std::vector<int> const& allowed_fast = c.allowed_fast();
+
+ // build a bitmask with only the allowed pieces in it
+ std::vector<bool> mask(c.get_bitfield().size(), false);
+ for (std::vector<int>::const_iterator i = allowed_fast.begin()
+ , end(allowed_fast.end()); i != end; ++i)
+ if (bitfield[*i]) mask[*i] = true;
+
+ p.pick_pieces(mask, interesting_pieces
+ , num_requests, prefer_whole_pieces, c.peer_info_struct()
+ , state, rarest_first, c.on_parole(), suggested);
+ }
+ else
+ {
+ // picks the interesting pieces from this peer
+ // the integer is the number of pieces that
+ // should be guaranteed to be available for download
+ // (if num_requests is too big, too many pieces are
+ // picked and cpu-time is wasted)
+ // the last argument is if we should prefer whole pieces
+ // for this peer. If we're downloading one piece in 20 seconds
+ // then use this mode.
+ p.pick_pieces(bitfield, interesting_pieces
+ , num_requests, prefer_whole_pieces, c.peer_info_struct()
+ , state, rarest_first, c.on_parole(), suggested);
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*c.m_logger) << time_now_string() << " PIECE_PICKER [ php: " << prefer_whole_pieces
+ << " picked: " << interesting_pieces.size() << " ]\n";
+#endif
+ std::deque<piece_block> const& dq = c.download_queue();
+ std::deque<piece_block> const& rq = c.request_queue();
+ for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
+ i != interesting_pieces.end(); ++i)
+ {
+ if (prefer_whole_pieces == 0 && num_requests <= 0) break;
+
+ if (p.is_requested(*i))
+ {
+ if (num_requests <= 0) break;
+ // don't request pieces we already have in our request queue
+ if (std::find(dq.begin(), dq.end(), *i) != dq.end()
+ || std::find(rq.begin(), rq.end(), *i) != rq.end())
+ continue;
+
+ TORRENT_ASSERT(p.num_peers(*i) > 0);
+ busy_pieces.push_back(*i);
+ continue;
+ }
+
+ TORRENT_ASSERT(p.num_peers(*i) == 0);
+ // ok, we found a piece that's not being downloaded
+ // by somebody else. request it from this peer
+ // and return
+ c.add_request(*i);
+ TORRENT_ASSERT(p.num_peers(*i) == 1);
+ TORRENT_ASSERT(p.is_requested(*i));
+ num_requests--;
+ }
+
+ if (busy_pieces.empty() || num_requests <= 0)
+ {
+ // in this case, we could not find any blocks
+ // that was free. If we couldn't find any busy
+ // blocks as well, we cannot download anything
+ // more from this peer.
+
+ c.send_block_requests();
+ return;
+ }
+
+ // if all blocks has the same number of peers on them
+ // we want to pick a random block
+ std::random_shuffle(busy_pieces.begin(), busy_pieces.end());
+
+ // find the block with the fewest requests to it
+ std::vector<piece_block>::iterator i = std::min_element(
+ busy_pieces.begin(), busy_pieces.end()
+ , bind(&piece_picker::num_peers, boost::cref(p), _1) <
+ bind(&piece_picker::num_peers, boost::cref(p), _2));
+#ifndef NDEBUG
+ piece_picker::downloading_piece st;
+ p.piece_info(i->piece_index, st);
+ TORRENT_ASSERT(st.requested + st.finished + st.writing == p.blocks_in_piece(i->piece_index));
+#endif
+ TORRENT_ASSERT(p.is_requested(*i));
+ TORRENT_ASSERT(p.num_peers(*i) > 0);
+ c.add_request(*i);
+ c.send_block_requests();
+ }
+
+ policy::policy(torrent* t)
+ : m_torrent(t)
+ , m_available_free_upload(0)
+// , m_last_optimistic_disconnect(min_time())
+ { TORRENT_ASSERT(t); }
+
+ // disconnects and removes all peers that are now filtered
+ void policy::ip_filter_updated()
+ {
+ aux::session_impl& ses = m_torrent->session();
+ piece_picker* p = 0;
+ if (m_torrent->has_picker())
+ p = &m_torrent->picker();
+ for (iterator i = m_peers.begin()
+ , end(m_peers.end()); i != end;)
+ {
+ if ((ses.m_ip_filter.access(i->second.ip.address()) & ip_filter::blocked) == 0)
+ {
+ ++i;
+ continue;
+ }
+
+ if (i->second.connection)
+ {
+ i->second.connection->disconnect();
+ if (ses.m_alerts.should_post(alert::info))
+ {
+ ses.m_alerts.post_alert(peer_blocked_alert(i->second.ip.address()
+ , "disconnected blocked peer"));
+ }
+ TORRENT_ASSERT(i->second.connection == 0
+ || i->second.connection->peer_info_struct() == 0);
+ }
+ else
+ {
+ if (ses.m_alerts.should_post(alert::info))
+ {
+ ses.m_alerts.post_alert(peer_blocked_alert(i->second.ip.address()
+ , "blocked peer removed from peer list"));
+ }
+ }
+ if (p) p->clear_peer(&i->second);
+ m_peers.erase(i++);
+ }
+ }
+/*
+ // finds the peer that has the worst download rate
+ // and returns it. May return 0 if all peers are
+ // choked.
+ policy::iterator policy::find_choke_candidate()
+ {
+ INVARIANT_CHECK;
+
+ iterator worst_peer = m_peers.end();
+ size_type min_weight = (std::numeric_limits<int>::min)();
+
+#ifndef NDEBUG
+ int unchoked_counter = m_num_unchoked;
+#endif
+
+ // TODO: make this selection better
+
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ peer_connection* c = i->connection;
+
+ if (c == 0) continue;
+ if (c->is_choked()) continue;
+#ifndef NDEBUG
+ unchoked_counter--;
+#endif
+ if (c->is_disconnecting()) continue;
+ // if the peer isn't interested, just choke it
+ if (!c->is_peer_interested())
+ return i;
+
+ size_type diff = i->total_download()
+ - i->total_upload();
+
+ size_type weight = static_cast<int>(c->statistics().download_rate() * 10.f)
+ + diff
+ + ((c->is_interesting() && c->has_peer_choked())?-10:10)*1024;
+
+ if (weight >= min_weight && worst_peer != m_peers.end()) continue;
+
+ min_weight = weight;
+ worst_peer = i;
+ continue;
+ }
+ TORRENT_ASSERT(unchoked_counter == 0);
+ return worst_peer;
+ }
+
+ policy::iterator policy::find_unchoke_candidate()
+ {
+ INVARIANT_CHECK;
+
+ // if all of our peers are unchoked, there's
+ // no left to unchoke
+ if (m_num_unchoked == m_torrent->num_peers())
+ return m_peers.end();
+
+ iterator unchoke_peer = m_peers.end();
+ ptime min_time = libtorrent::min_time();
+ float max_down_speed = 0.f;
+
+ // TODO: make this selection better
+
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ peer_connection* c = i->connection;
+ if (c == 0) continue;
+ if (c->is_disconnecting()) continue;
+ if (!c->is_choked()) continue;
+ if (!c->is_peer_interested()) continue;
+ if (c->share_diff() < -free_upload_amount
+ && m_torrent->ratio() != 0) continue;
+ if (c->statistics().download_rate() < max_down_speed) continue;
+
+ min_time = i->last_optimistically_unchoked;
+ max_down_speed = c->statistics().download_rate();
+ unchoke_peer = i;
+ }
+ return unchoke_peer;
+ }
+*/
+ policy::iterator policy::find_disconnect_candidate()
+ {
+ INVARIANT_CHECK;
+
+ iterator disconnect_peer = m_peers.end();
+ double slowest_transfer_rate = (std::numeric_limits<double>::max)();
+
+ ptime now = time_now();
+
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ peer_connection* c = i->second.connection;
+ if (c == 0) continue;
+ if (c->is_disconnecting()) continue;
+
+ // never disconnect an interesting peer if we have a candidate that
+ // isn't interesting
+ if (disconnect_peer != m_peers.end()
+ && c->is_interesting()
+ && !disconnect_peer->second.connection->is_interesting())
+ continue;
+
+ double transferred_amount
+ = (double)c->statistics().total_payload_download();
+
+ time_duration connected_time = now - i->second.connected;
+
+ double connected_time_in_seconds = total_seconds(connected_time);
+
+ double transfer_rate
+ = transferred_amount / (connected_time_in_seconds + 1);
+
+ // prefer to disconnect uninteresting peers, and secondly slow peers
+ if (transfer_rate <= slowest_transfer_rate)
+ {
+ slowest_transfer_rate = transfer_rate;
+ disconnect_peer = i;
+ }
+ }
+ return disconnect_peer;
+ }
+
+ policy::iterator policy::find_connect_candidate()
+ {
+// too expensive
+// INVARIANT_CHECK;
+
+ ptime now = time_now();
+ ptime min_connect_time(now);
+ iterator candidate = m_peers.end();
+
+ int max_failcount = m_torrent->settings().max_failcount;
+ int min_reconnect_time = m_torrent->settings().min_reconnect_time;
+ int min_cidr_distance = (std::numeric_limits<int>::max)();
+ bool finished = m_torrent->is_finished();
+ address external_ip = m_torrent->session().m_external_address;
+
+ if (external_ip == address())
+ {
+ // set external_ip to a random value, to
+ // radomize which peers we prefer
+ address_v4::bytes_type bytes;
+ std::generate(bytes.begin(), bytes.end(), &std::rand);
+ external_ip = address_v4(bytes);
+ }
+
+ aux::session_impl& ses = m_torrent->session();
+
+ for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
+ {
+ if (i->second.connection) continue;
+ if (i->second.banned) continue;
+ if (i->second.type == peer::not_connectable) continue;
+ if (i->second.seed && finished) continue;
+ if (i->second.failcount >= max_failcount) continue;
+
+ // prefer peers with lower failcount
+ if (candidate != m_peers.end()
+ && candidate->second.failcount < i->second.failcount)
+ continue;
+
+ if (now - i->second.connected < seconds(i->second.failcount * min_reconnect_time))
+ continue;
+ if (ses.m_port_filter.access(i->second.ip.port()) & port_filter::blocked)
+ continue;
+
+ TORRENT_ASSERT(i->second.connected <= now);
+
+ if (i->second.connected > min_connect_time) continue;
+ int distance = cidr_distance(external_ip, i->second.ip.address());
+ if (distance > min_cidr_distance) continue;
+
+ min_cidr_distance = distance;
+ min_connect_time = i->second.connected;
+ candidate = i;
+ }
+
+ TORRENT_ASSERT(min_connect_time <= now);
+
+#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
+ if (candidate != m_peers.end())
+ {
+ (*m_torrent->session().m_logger) << "*** FOUND CONNECTION CANDIDATE ["
+ " ip: " << candidate->second.ip <<
+ " d: " << min_cidr_distance <<
+ " external: " << external_ip <<
+ " t: " << total_seconds(time_now() - min_connect_time) <<
+ " ]\n";
+ }
+#endif
+
+ return candidate;
+ }
+/*
+ policy::iterator policy::find_seed_choke_candidate()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_num_unchoked > 0);
+ // first choice candidate.
+ // it is a candidate we owe nothing to and which has been unchoked
+ // the longest.
+ iterator candidate = m_peers.end();
+
+ // not valid when candidate == 0
+ ptime last_unchoke = min_time();
+
+ // second choice candidate.
+ // if there is no first choice candidate, this candidate will be chosen.
+ // it is the candidate that we owe the least to.
+ iterator second_candidate = m_peers.end();
+ size_type lowest_share_diff = 0; // not valid when secondCandidate==0
+
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ peer_connection* c = i->connection;
+ // ignore peers that are choked or
+ // whose connection is closed
+ if (c == 0) continue;
+
+ if (c->is_choked()) continue;
+ if (c->is_disconnecting()) continue;
+
+ size_type share_diff = c->share_diff();
+
+ // select as second candidate the one that we owe the least
+ // to
+ if (second_candidate == m_peers.end()
+ || share_diff <= lowest_share_diff)
+ {
+ lowest_share_diff = share_diff;
+ second_candidate = i;
+ }
+
+ // select as first candidate the one that we don't owe anything to
+ // and has been waiting for an unchoke the longest
+ if (share_diff > 0) continue;
+ if (candidate == m_peers.end()
+ || last_unchoke > i->last_optimistically_unchoked)
+ {
+ last_unchoke = i->last_optimistically_unchoked;
+ candidate = i;
+ }
+ }
+ if (candidate != m_peers.end()) return candidate;
+ TORRENT_ASSERT(second_candidate != m_peers.end());
+ return second_candidate;
+ }
+
+ policy::iterator policy::find_seed_unchoke_candidate()
+ {
+ INVARIANT_CHECK;
+
+ iterator candidate = m_peers.end();
+ ptime last_unchoke = time_now();
+
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ peer_connection* c = i->connection;
+ if (c == 0) continue;
+ if (!c->is_choked()) continue;
+ if (!c->is_peer_interested()) continue;
+ if (c->is_disconnecting()) continue;
+ if (last_unchoke < i->last_optimistically_unchoked) continue;
+ last_unchoke = i->last_optimistically_unchoked;
+ candidate = i;
+ }
+ return candidate;
+ }
+
+ bool policy::seed_unchoke_one_peer()
+ {
+ INVARIANT_CHECK;
+
+ iterator p = find_seed_unchoke_candidate();
+ if (p != m_peers.end())
+ {
+ TORRENT_ASSERT(p->connection->is_choked());
+ p->connection->send_unchoke();
+ p->last_optimistically_unchoked = time_now();
+ ++m_num_unchoked;
+ }
+ return p != m_peers.end();
+ }
+
+ void policy::seed_choke_one_peer()
+ {
+ INVARIANT_CHECK;
+
+ iterator p = find_seed_choke_candidate();
+ if (p != m_peers.end())
+ {
+ TORRENT_ASSERT(!p->connection->is_choked());
+ p->connection->send_choke();
+ --m_num_unchoked;
+ }
+ }
+*/
+ void policy::pulse()
+ {
+ INVARIANT_CHECK;
+
+ if (m_torrent->is_paused()) return;
+
+ piece_picker* p = 0;
+ if (m_torrent->has_picker())
+ p = &m_torrent->picker();
+
+ ptime now = time_now();
+ // remove old disconnected peers from the list
+ for (iterator i = m_peers.begin(); i != m_peers.end();)
+ {
+ // this timeout has to be customizable!
+ // don't remove banned peers, they should
+ // remain banned
+ if (i->second.connection == 0
+ && i->second.connected != min_time()
+ && !i->second.banned
+ && now - i->second.connected > minutes(120))
+ {
+ if (p) p->clear_peer(&i->second);
+ m_peers.erase(i++);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+
+ // -------------------------------------
+ // maintain the number of connections
+ // -------------------------------------
+/*
+ // count the number of connected peers except for peers
+ // that are currently in the process of disconnecting
+ int num_connected_peers = 0;
+
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ if (i->connection && !i->connection->is_disconnecting())
+ ++num_connected_peers;
+ }
+
+ if (m_torrent->max_connections() != (std::numeric_limits<int>::max)())
+ {
+ int max_connections = m_torrent->max_connections();
+
+ if (num_connected_peers >= max_connections)
+ {
+ // every minute, disconnect the worst peer in hope of finding a better peer
+
+ ptime local_time = time_now();
+ if (m_last_optimistic_disconnect + seconds(120) <= local_time
+ && find_connect_candidate() != m_peers.end())
+ {
+ m_last_optimistic_disconnect = local_time;
+ --max_connections; // this will have the effect of disconnecting the worst peer
+ }
+ }
+ else
+ {
+ // don't do a disconnect earlier than 1 minute after some peer was connected
+ m_last_optimistic_disconnect = time_now();
+ }
+
+ while (num_connected_peers > max_connections)
+ {
+ bool ret = disconnect_one_peer();
+ (void)ret;
+ TORRENT_ASSERT(ret);
+ --num_connected_peers;
+ }
+ }
+*/
+ // ------------------------
+ // upload shift
+ // ------------------------
+
+ // this part will shift downloads
+ // from peers that are seeds and peers
+ // that don't want to download from us
+ // to peers that cannot upload anything
+ // to us. The shifting will make sure
+ // that the torrent's share ratio
+ // will be maintained
+
+ // if the share ratio is 0 (infinite)
+ // m_available_free_upload isn't used
+ // because it isn't necessary
+ if (m_torrent->ratio() != 0.f)
+ {
+ // accumulate all the free download we get
+ // and add it to the available free upload
+ m_available_free_upload
+ += collect_free_download(
+ m_torrent->begin()
+ , m_torrent->end());
+
+ // distribute the free upload among the peers
+ m_available_free_upload = distribute_free_upload(
+ m_torrent->begin()
+ , m_torrent->end()
+ , m_available_free_upload);
+ }
+/*
+ // ------------------------
+ // seed choking policy
+ // ------------------------
+ if (m_torrent->is_seed())
+ {
+ if (m_num_unchoked > m_torrent->m_uploads_quota.given)
+ {
+ do
+ {
+ iterator p = find_seed_choke_candidate();
+ --m_num_unchoked;
+ TORRENT_ASSERT(p != m_peers.end());
+ if (p == m_peers.end()) break;
+
+ TORRENT_ASSERT(!p->connection->is_choked());
+ p->connection->send_choke();
+ } while (m_num_unchoked > m_torrent->m_uploads_quota.given);
+ }
+ else if (m_num_unchoked > 0)
+ {
+ // optimistic unchoke. trade the 'worst'
+ // unchoked peer with one of the choked
+ // TODO: This rotation should happen
+ // far less frequent than this!
+ TORRENT_ASSERT(m_num_unchoked <= m_torrent->num_peers());
+ iterator p = find_seed_unchoke_candidate();
+ if (p != m_peers.end())
+ {
+ TORRENT_ASSERT(p->connection->is_choked());
+ seed_choke_one_peer();
+ p->connection->send_unchoke();
+ ++m_num_unchoked;
+ }
+
+ }
+
+ // make sure we have enough
+ // unchoked peers
+ while (m_num_unchoked < m_torrent->m_uploads_quota.given)
+ {
+ if (!seed_unchoke_one_peer()) break;
+ }
+#ifndef NDEBUG
+ check_invariant();
+#endif
+ }
+
+ // ----------------------------
+ // downloading choking policy
+ // ----------------------------
+ else
+ {
+ if (m_torrent->ratio() != 0)
+ {
+ // choke peers that have leeched too much without giving anything back
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ peer_connection* c = i->connection;
+ if (c == 0) continue;
+
+ size_type diff = i->connection->share_diff();
+ if (diff < -free_upload_amount
+ && !c->is_choked())
+ {
+ // if we have uploaded more than a piece for free, choke peer and
+ // wait until we catch up with our download.
+ c->send_choke();
+ --m_num_unchoked;
+ }
+ }
+ }
+
+ if (m_torrent->m_uploads_quota.given < m_torrent->num_peers())
+ {
+ TORRENT_ASSERT(m_torrent->m_uploads_quota.given >= 0);
+
+ // make sure we don't have too many
+ // unchoked peers
+ if (m_num_unchoked > m_torrent->m_uploads_quota.given)
+ {
+ do
+ {
+ iterator p = find_choke_candidate();
+ if (p == m_peers.end()) break;
+ TORRENT_ASSERT(p != m_peers.end());
+ TORRENT_ASSERT(!p->connection->is_choked());
+ p->connection->send_choke();
+ --m_num_unchoked;
+ } while (m_num_unchoked > m_torrent->m_uploads_quota.given);
+ }
+ // this should prevent the choke/unchoke
+ // problem, since it will not unchoke unless
+ // there actually are any choked peers
+ else if (count_choked() > 0)
+ {
+ // optimistic unchoke. trade the 'worst'
+ // unchoked peer with one of the choked
+ TORRENT_ASSERT(m_num_unchoked <= m_torrent->num_peers());
+ iterator p = find_unchoke_candidate();
+ if (p != m_peers.end())
+ {
+ TORRENT_ASSERT(p->connection->is_choked());
+ choke_one_peer();
+ p->connection->send_unchoke();
+ ++m_num_unchoked;
+ }
+ }
+ }
+
+ // make sure we have enough
+ // unchoked peers
+ while (m_num_unchoked < m_torrent->m_uploads_quota.given
+ && unchoke_one_peer());
+ }
+*/
+ }
+
+ int policy::count_choked() const
+ {
+ int ret = 0;
+ for (const_iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ if (!i->second.connection
+ || i->second.connection->is_connecting()
+ || i->second.connection->is_disconnecting()
+ || !i->second.connection->is_peer_interested())
+ continue;
+ if (i->second.connection->is_choked()) ++ret;
+ }
+ return ret;
+ }
+
+ void policy::new_connection(peer_connection& c)
+ {
+ TORRENT_ASSERT(!c.is_local());
+
+// INVARIANT_CHECK;
+
+ // if the connection comes from the tracker,
+ // it's probably just a NAT-check. Ignore the
+ // num connections constraint then.
+
+ // TODO: only allow _one_ connection to use this
+ // override at a time
+ TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint());
+
+ if (m_torrent->num_peers() >= m_torrent->max_connections()
+ && m_torrent->session().num_connections() >= m_torrent->session().max_connections()
+ && c.remote().address() != m_torrent->current_tracker().address())
+ {
+ throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (c.remote().address() == m_torrent->current_tracker().address())
+ {
+ m_torrent->debug_log("overriding connection limit for tracker NAT-check");
+ }
+#endif
+
+ iterator i;
+
+ if (m_torrent->settings().allow_multiple_connections_per_ip)
+ {
+ tcp::endpoint remote = c.remote();
+ std::pair<iterator, iterator> range = m_peers.equal_range(remote.address());
+ i = std::find_if(range.first, range.second, match_peer_endpoint(remote));
+
+ if (i == range.second) i = m_peers.end();
+ }
+ else
+ {
+ i = m_peers.find(c.remote().address());
+ }
+
+ if (i != m_peers.end())
+ {
+ if (i->second.banned)
+ throw protocol_error("ip address banned, closing");
+
+ if (i->second.connection != 0)
+ {
+ TORRENT_ASSERT(i->second.connection != &c);
+ // the new connection is a local (outgoing) connection
+ // or the current one is already connected
+ if (!i->second.connection->is_connecting() || c.is_local())
+ {
+ throw protocol_error("duplicate connection, closing");
+ }
+ else
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ m_torrent->debug_log("duplicate connection. existing connection"
+ " is connecting and this connection is incoming. closing existing "
+ "connection in favour of this one");
+#endif
+ i->second.connection->disconnect();
+ }
+ }
+ }
+ else
+ {
+ // we don't have any info about this peer.
+ // add a new entry
+ TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint());
+
+ peer p(c.remote(), peer::not_connectable, 0);
+ i = m_peers.insert(std::make_pair(c.remote().address(), p));
+ }
+
+ c.set_peer_info(&i->second);
+ TORRENT_ASSERT(i->second.connection == 0);
+ c.add_stat(i->second.prev_amount_download, i->second.prev_amount_upload);
+ i->second.prev_amount_download = 0;
+ i->second.prev_amount_upload = 0;
+ i->second.connection = &c;
+ TORRENT_ASSERT(i->second.connection);
+ if (!c.fast_reconnect())
+ i->second.connected = time_now();
+// m_last_optimistic_disconnect = time_now();
+ }
+
+ void policy::update_peer_port(int port, policy::peer* p, int src)
+ {
+ TORRENT_ASSERT(p != 0);
+ if (p->ip.port() == port) return;
+
+ if (m_torrent->settings().allow_multiple_connections_per_ip)
+ {
+ tcp::endpoint remote(p->ip.address(), port);
+ std::pair<iterator, iterator> range = m_peers.equal_range(remote.address());
+ iterator i = std::find_if(range.first, range.second
+ , match_peer_endpoint(remote));
+ if (i != m_peers.end())
+ {
+ policy::peer& pp = i->second;
+ if (pp.connection)
+ {
+ throw protocol_error("duplicate connection");
+ }
+ if (m_torrent->has_picker())
+ m_torrent->picker().clear_peer(&i->second);
+ m_peers.erase(i);
+ }
+ }
+ else
+ {
+ TORRENT_ASSERT(m_peers.count(p->ip.address()) == 1);
+ }
+ p->ip.port(port);
+ p->source |= src;
+ }
+
+ policy::peer* policy::peer_from_tracker(tcp::endpoint const& remote, peer_id const& pid
+ , int src, char flags)
+ {
+// too expensive
+// INVARIANT_CHECK;
+
+ // just ignore the obviously invalid entries
+ if (remote.address() == address() || remote.port() == 0)
+ return 0;
+
+ aux::session_impl& ses = m_torrent->session();
+
+ port_filter const& pf = ses.m_port_filter;
+ if (pf.access(remote.port()) & port_filter::blocked)
+ {
+ if (ses.m_alerts.should_post(alert::info))
+ {
+ ses.m_alerts.post_alert(peer_blocked_alert(remote.address()
+ , "outgoing port blocked, peer not added to peer list"));
+ }
+ return 0;
+ }
+
+ try
+ {
+ iterator i;
+
+ if (m_torrent->settings().allow_multiple_connections_per_ip)
+ {
+ std::pair<iterator, iterator> range = m_peers.equal_range(remote.address());
+ i = std::find_if(range.first, range.second, match_peer_endpoint(remote));
+ if (i == range.second) i = m_peers.end();
+ }
+ else
+ {
+ i = m_peers.find(remote.address());
+ }
+
+ if (i == m_peers.end())
+ {
+ // if the IP is blocked, don't add it
+ if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
+ {
+ if (ses.m_alerts.should_post(alert::info))
+ {
+ ses.m_alerts.post_alert(peer_blocked_alert(remote.address()
+ , "blocked peer not added to peer list"));
+ }
+ return 0;
+ }
+
+ // we don't have any info about this peer.
+ // add a new entry
+ i = m_peers.insert(std::make_pair(remote.address()
+ , peer(remote, peer::connectable, src)));
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ if (flags & 0x01) i->second.pe_support = true;
+#endif
+ if (flags & 0x02) i->second.seed = true;
+ }
+ else
+ {
+ i->second.type = peer::connectable;
+
+ i->second.ip = remote;
+ i->second.source |= src;
+
+ // if this peer has failed before, decrease the
+ // counter to allow it another try, since somebody
+ // else is appearantly able to connect to it
+ // if it comes from the DHT it might be stale though
+ if (i->second.failcount > 0 && src != peer_info::dht)
+ --i->second.failcount;
+
+ // if we're connected to this peer
+ // we already know if it's a seed or not
+ // so we don't have to trust this source
+ if ((flags & 0x02) && !i->second.connection) i->second.seed = true;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (i->second.connection)
+ {
+ // this means we're already connected
+ // to this peer. don't connect to
+ // it again.
+
+ m_torrent->debug_log("already connected to peer: " + remote.address().to_string() + ":"
+ + boost::lexical_cast<std::string>(remote.port()) + " "
+ + boost::lexical_cast<std::string>(i->second.connection->pid()));
+
+ TORRENT_ASSERT(i->second.connection->associated_torrent().lock().get() == m_torrent);
+ }
+#endif
+ }
+ return &i->second;
+ }
+ catch(std::exception& e)
+ {
+ if (m_torrent->alerts().should_post(alert::debug))
+ {
+ m_torrent->alerts().post_alert(
+ peer_error_alert(remote, pid, e.what()));
+ }
+ }
+ return 0;
+ }
+
+ // this is called when we are choked by a peer
+ // i.e. a peer lets us know that we will not receive
+ // anything for a while
+ void policy::choked(peer_connection&)
+ {
+ }
+
+ void policy::piece_finished(int index, bool successfully_verified)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(index >= 0 && index < m_torrent->torrent_file().num_pieces());
+
+ if (successfully_verified)
+ {
+ // have all peers update their interested-flag
+ for (iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ if (i->second.connection == 0) continue;
+ // if we're not interested, we will not become interested
+ if (!i->second.connection->is_interesting()) continue;
+ if (!i->second.connection->has_piece(index)) continue;
+
+ i->second.connection->update_interest();
+ }
+ }
+ }
+
+ // this is called when we are unchoked by a peer
+ // i.e. a peer lets us know that we will receive
+ // data from now on
+ void policy::unchoked(peer_connection& c)
+ {
+// INVARIANT_CHECK;
+ if (c.is_interesting())
+ {
+ request_a_block(*m_torrent, c);
+ }
+ }
+
+ // called when a peer is interested in us
+ void policy::interested(peer_connection& c)
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(std::find_if(m_peers.begin(), m_peers.end()
+ , boost::bind<bool>(std::equal_to<peer_connection*>(), bind(&peer::connection
+ , bind(&iterator::value_type::second, _1)), &c)) != m_peers.end());
+
+ // if the peer is choked and we have upload slots left,
+ // then unchoke it. Another condition that has to be met
+ // is that the torrent doesn't keep track of the individual
+ // up/down ratio for each peer (ratio == 0) or (if it does
+ // keep track) this particular connection isn't a leecher.
+ // If the peer was choked because it was leeching, don't
+ // unchoke it again.
+ // The exception to this last condition is if we're a seed.
+ // In that case we don't care if people are leeching, they
+ // can't pay for their downloads anyway.
+ if (c.is_choked()
+ && m_torrent->session().num_uploads() < m_torrent->session().max_uploads()
+ && (m_torrent->ratio() == 0
+ || c.share_diff() >= -free_upload_amount
+ || m_torrent->is_finished()))
+ {
+ m_torrent->session().unchoke_peer(c);
+ }
+#if defined(TORRENT_VERBOSE_LOGGING)
+ else if (c.is_choked())
+ {
+ std::string reason;
+ if (m_torrent->session().num_uploads() >= m_torrent->session().max_uploads())
+ {
+ reason = "the number of uploads ("
+ + boost::lexical_cast<std::string>(m_torrent->session().num_uploads())
+ + ") is more than or equal to the limit ("
+ + boost::lexical_cast<std::string>(m_torrent->session().max_uploads())
+ + ")";
+ }
+ else
+ {
+ reason = "the share ratio ("
+ + boost::lexical_cast<std::string>(c.share_diff())
+ + ") is <= free_upload_amount ("
+ + boost::lexical_cast<std::string>(int(free_upload_amount))
+ + ") and we are not seeding and the ratio ("
+ + boost::lexical_cast<std::string>(m_torrent->ratio())
+ + ")is non-zero";
+ }
+ (*c.m_logger) << time_now_string() << " DID NOT UNCHOKE [ " << reason << " ]\n";
+ }
+#endif
+ }
+
+ // called when a peer is no longer interested in us
+ void policy::not_interested(peer_connection& c)
+ {
+ INVARIANT_CHECK;
+
+ if (m_torrent->ratio() != 0.f)
+ {
+ TORRENT_ASSERT(c.share_diff() < (std::numeric_limits<size_type>::max)());
+ size_type diff = c.share_diff();
+ if (diff > 0 && c.is_seed())
+ {
+ // the peer is a seed and has sent
+ // us more than we have sent it back.
+ // consider the download as free download
+ m_available_free_upload += diff;
+ c.add_free_upload(-diff);
+ }
+ }
+/*
+ if (!c.is_choked())
+ {
+ c.send_choke();
+ --m_num_unchoked;
+
+ if (m_torrent->is_seed()) seed_unchoke_one_peer();
+ else unchoke_one_peer();
+ }
+*/
+ }
+/*
+ bool policy::unchoke_one_peer()
+ {
+ INVARIANT_CHECK;
+
+ iterator p = find_unchoke_candidate();
+ if (p == m_peers.end()) return false;
+ TORRENT_ASSERT(p->connection);
+ TORRENT_ASSERT(!p->connection->is_disconnecting());
+
+ TORRENT_ASSERT(p->connection->is_choked());
+ p->connection->send_unchoke();
+ p->last_optimistically_unchoked = time_now();
+ ++m_num_unchoked;
+ return true;
+ }
+
+ void policy::choke_one_peer()
+ {
+ INVARIANT_CHECK;
+
+ iterator p = find_choke_candidate();
+ if (p == m_peers.end()) return;
+ TORRENT_ASSERT(p->connection);
+ TORRENT_ASSERT(!p->connection->is_disconnecting());
+ TORRENT_ASSERT(!p->connection->is_choked());
+ p->connection->send_choke();
+ --m_num_unchoked;
+ }
+*/
+ bool policy::connect_one_peer()
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_torrent->want_more_peers());
+
+ iterator p = find_connect_candidate();
+ if (p == m_peers.end()) return false;
+
+ TORRENT_ASSERT(!p->second.banned);
+ TORRENT_ASSERT(!p->second.connection);
+ TORRENT_ASSERT(p->second.type == peer::connectable);
+
+ try
+ {
+ if (!m_torrent->connect_to_peer(&p->second))
+ {
+ ++p->second.failcount;
+ return false;
+ }
+ p->second.connection->add_stat(p->second.prev_amount_download, p->second.prev_amount_upload);
+ p->second.prev_amount_download = 0;
+ p->second.prev_amount_upload = 0;
+ return true;
+ }
+ catch (std::exception& e)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING)
+ (*m_torrent->session().m_logger) << "*** CONNECTION FAILED '"
+ << e.what() << "'\n";
+#endif
+ std::cerr << e.what() << std::endl;
+ ++p->second.failcount;
+ return false;
+ }
+ }
+
+ bool policy::disconnect_one_peer()
+ {
+ iterator p = find_disconnect_candidate();
+ if (p == m_peers.end())
+ return false;
+#if defined(TORRENT_VERBOSE_LOGGING)
+ (*p->second.connection->m_logger) << "*** CLOSING CONNECTION 'too many connections'\n";
+#endif
+
+ p->second.connection->disconnect();
+ return true;
+ }
+
+ // this is called whenever a peer connection is closed
+ void policy::connection_closed(const peer_connection& c) throw()
+ {
+// too expensive
+// INVARIANT_CHECK;
+
+ peer* p = c.peer_info_struct();
+
+ TORRENT_ASSERT((std::find_if(
+ m_peers.begin()
+ , m_peers.end()
+ , match_peer_connection(c))
+ != m_peers.end()) == (p != 0));
+
+ // if we couldn't find the connection in our list, just ignore it.
+ if (p == 0) return;
+
+ TORRENT_ASSERT(p->connection == &c);
+
+ p->connection = 0;
+ p->optimistically_unchoked = false;
+
+ // if fast reconnect is true, we won't
+ // update the timestamp, and it will remain
+ // the time when we initiated the connection.
+ if (!c.fast_reconnect())
+ p->connected = time_now();
+
+ if (c.failed())
+ {
+ ++p->failcount;
+// p->connected = time_now();
+ }
+
+ // if the share ratio is 0 (infinite), the
+ // m_available_free_upload isn't used,
+ // because it isn't necessary.
+ if (m_torrent->ratio() != 0.f)
+ {
+ TORRENT_ASSERT(c.associated_torrent().lock().get() == m_torrent);
+ TORRENT_ASSERT(c.share_diff() < (std::numeric_limits<size_type>::max)());
+ m_available_free_upload += c.share_diff();
+ }
+ p->prev_amount_download += c.statistics().total_payload_download();
+ p->prev_amount_upload += c.statistics().total_payload_upload();
+ }
+
+ void policy::peer_is_interesting(peer_connection& c)
+ {
+// INVARIANT_CHECK;
+
+ c.send_interested();
+ if (c.has_peer_choked()
+ && c.allowed_fast().empty())
+ return;
+ request_a_block(*m_torrent, c);
+ }
+
+#ifndef NDEBUG
+ bool policy::has_connection(const peer_connection* c)
+ {
+// too expensive
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(c);
+ try { TORRENT_ASSERT(c->remote() == c->get_socket()->remote_endpoint()); }
+ catch (std::exception&) {}
+
+ return std::find_if(
+ m_peers.begin()
+ , m_peers.end()
+ , match_peer_connection(*c)) != m_peers.end();
+ }
+
+ void policy::check_invariant() const
+ {
+ if (m_torrent->is_aborted()) return;
+
+ int connected_peers = 0;
+
+ int total_connections = 0;
+ int nonempty_connections = 0;
+
+ std::set<tcp::endpoint> unique_test;
+ for (const_iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ peer const& p = i->second;
+ if (!m_torrent->settings().allow_multiple_connections_per_ip)
+ {
+ TORRENT_ASSERT(m_peers.count(p.ip.address()) == 1);
+ }
+ else
+ {
+ TORRENT_ASSERT(unique_test.count(p.ip) == 0);
+ unique_test.insert(p.ip);
+ TORRENT_ASSERT(i->first == p.ip.address());
+// TORRENT_ASSERT(p.connection == 0 || p.ip == p.connection->remote());
+ }
+ ++total_connections;
+ if (!p.connection)
+ {
+ continue;
+ }
+ if (p.optimistically_unchoked)
+ {
+ TORRENT_ASSERT(p.connection);
+ TORRENT_ASSERT(!p.connection->is_choked());
+ }
+ TORRENT_ASSERT(p.connection->peer_info_struct() == 0
+ || p.connection->peer_info_struct() == &p);
+ ++nonempty_connections;
+ if (!p.connection->is_disconnecting())
+ ++connected_peers;
+ }
+
+ int num_torrent_peers = 0;
+ for (torrent::const_peer_iterator i = m_torrent->begin();
+ i != m_torrent->end(); ++i)
+ {
+ if ((*i)->is_disconnecting()) continue;
+ // ignore web_peer_connections since they are not managed
+ // by the policy class
+ if (dynamic_cast<web_peer_connection*>(*i)) continue;
+ ++num_torrent_peers;
+ }
+
+ if (m_torrent->has_picker())
+ {
+ piece_picker& p = m_torrent->picker();
+ std::vector<piece_picker::downloading_piece> downloaders = p.get_download_queue();
+
+ std::set<void*> peer_set;
+ std::vector<void*> peers;
+ for (std::vector<piece_picker::downloading_piece>::iterator i = downloaders.begin()
+ , end(downloaders.end()); i != end; ++i)
+ {
+ p.get_downloaders(peers, i->index);
+ std::copy(peers.begin(), peers.end()
+ , std::insert_iterator<std::set<void*> >(peer_set, peer_set.begin()));
+ }
+
+ for (std::set<void*>::iterator i = peer_set.begin()
+ , end(peer_set.end()); i != end; ++i)
+ {
+ policy::peer* p = static_cast<policy::peer*>(*i);
+ if (p == 0) continue;
+ if (p->connection == 0) continue;
+ TORRENT_ASSERT(std::find_if(m_peers.begin(), m_peers.end()
+ , match_peer_connection(*p->connection)) != m_peers.end());
+ }
+ }
+
+ // this invariant is a bit complicated.
+ // the usual case should be that connected_peers
+ // == num_torrent_peers. But when there's an incoming
+ // connection, it will first be added to the policy
+ // and then be added to the torrent.
+ // When there's an outgoing connection, it will first
+ // be added to the torrent and then to the policy.
+ // that's why the two second cases are in there.
+/*
+ TORRENT_ASSERT(connected_peers == num_torrent_peers
+ || (connected_peers == num_torrent_peers + 1
+ && connected_peers > 0)
+ || (connected_peers + 1 == num_torrent_peers
+ && num_torrent_peers > 0));
+*/
+ }
+#endif
+
+ policy::peer::peer(const tcp::endpoint& ip_, peer::connection_type t, int src)
+ : ip(ip_)
+ , type(t)
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ , pe_support(true)
+#endif
+ , failcount(0)
+ , hashfails(0)
+ , seed(false)
+ , fast_reconnects(0)
+ , optimistically_unchoked(false)
+ , last_optimistically_unchoked(min_time())
+ , connected(min_time())
+ , trust_points(0)
+ , on_parole(false)
+ , prev_amount_upload(0)
+ , prev_amount_download(0)
+ , banned(false)
+ , source(src)
+ , connection(0)
+ {
+ TORRENT_ASSERT(connected < time_now());
+ }
+
+ size_type policy::peer::total_download() const
+ {
+ if (connection != 0)
+ {
+ TORRENT_ASSERT(prev_amount_download == 0);
+ return connection->statistics().total_payload_download();
+ }
+ else
+ {
+ return prev_amount_download;
+ }
+ }
+
+ size_type policy::peer::total_upload() const
+ {
+ if (connection != 0)
+ {
+ TORRENT_ASSERT(prev_amount_upload == 0);
+ return connection->statistics().total_payload_upload();
+ }
+ else
+ {
+ return prev_amount_upload;
+ }
+ }
+}
+
diff --git a/src/libtorrent/src/session.cpp b/src/libtorrent/src/session.cpp
new file mode 100644
index 0000000..331ffa3
--- /dev/null
+++ b/src/libtorrent/src/session.cpp
@@ -0,0 +1,470 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg, Magnus Jonsson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <iterator>
+#include <algorithm>
+#include <set>
+#include <cctype>
+#include <algorithm>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/limits.hpp>
+#include <boost/bind.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/fingerprint.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/alert_types.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/file.hpp"
+#include "libtorrent/bt_peer_connection.hpp"
+#include "libtorrent/ip_filter.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+#include "libtorrent/kademlia/dht_tracker.hpp"
+
+using boost::shared_ptr;
+using boost::weak_ptr;
+using boost::bind;
+using boost::mutex;
+using libtorrent::aux::session_impl;
+
+namespace libtorrent
+{
+
+ std::string log_time()
+ {
+ static const ptime start = time_now();
+ char ret[200];
+ std::sprintf(ret, "%d", total_milliseconds(time_now() - start));
+ return ret;
+ }
+
+ namespace aux
+ {
+ filesystem_init::filesystem_init()
+ {
+#if BOOST_VERSION < 103400
+ using namespace boost::filesystem;
+ if (path::default_name_check_writable())
+ path::default_name_check(no_check);
+#endif
+ }
+ }
+
+ session::session(
+ fingerprint const& id
+ , std::pair<int, int> listen_port_range
+ , char const* listen_interface
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , fs::path logpath
+#endif
+ )
+ : m_impl(new session_impl(listen_port_range, id, listen_interface
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , logpath
+#endif
+ ))
+ {
+ // turn off the filename checking in boost.filesystem
+ TORRENT_ASSERT(listen_port_range.first > 0);
+ TORRENT_ASSERT(listen_port_range.first < listen_port_range.second);
+#ifndef NDEBUG
+ // this test was added after it came to my attention
+ // that devstudios managed c++ failed to generate
+ // correct code for boost.function
+ boost::function0<void> test = boost::ref(*m_impl);
+ TORRENT_ASSERT(!test.empty());
+#endif
+ }
+
+ session::session(fingerprint const& id
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , fs::path logpath
+#endif
+ )
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ : m_impl(new session_impl(std::make_pair(0, 0), id, "0.0.0.0", logpath))
+#else
+ : m_impl(new session_impl(std::make_pair(0, 0), id, "0.0.0.0"))
+#endif
+ {
+#ifndef NDEBUG
+ boost::function0<void> test = boost::ref(*m_impl);
+ TORRENT_ASSERT(!test.empty());
+#endif
+ }
+
+ session::~session()
+ {
+ TORRENT_ASSERT(m_impl);
+ // if there is at least one destruction-proxy
+ // abort the session and let the destructor
+ // of the proxy to syncronize
+ if (!m_impl.unique())
+ m_impl->abort();
+ }
+
+ void session::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext)
+ {
+ m_impl->add_extension(ext);
+ }
+
+ void session::set_ip_filter(ip_filter const& f)
+ {
+ m_impl->set_ip_filter(f);
+ }
+
+ void session::set_port_filter(port_filter const& f)
+ {
+ m_impl->set_port_filter(f);
+ }
+
+ void session::set_peer_id(peer_id const& id)
+ {
+ m_impl->set_peer_id(id);
+ }
+
+ peer_id session::id() const
+ {
+ return m_impl->get_peer_id();
+ }
+
+ void session::set_key(int key)
+ {
+ m_impl->set_key(key);
+ }
+
+ std::vector<torrent_handle> session::get_torrents() const
+ {
+ return m_impl->get_torrents();
+ }
+
+ torrent_handle session::find_torrent(sha1_hash const& info_hash) const
+ {
+ return m_impl->find_torrent_handle(info_hash);
+ }
+
+
+ // if the torrent already exists, this will throw duplicate_torrent
+ torrent_handle session::add_torrent(
+ torrent_info const& ti
+ , fs::path const& save_path
+ , entry const& resume_data
+ , storage_mode_t storage_mode
+ , bool paused
+ , storage_constructor_type sc)
+ {
+ TORRENT_ASSERT(!ti.m_half_metadata);
+ boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
+ return m_impl->add_torrent(tip, save_path, resume_data
+ , storage_mode, sc, paused, 0);
+ }
+
+ torrent_handle session::add_torrent(
+ boost::intrusive_ptr<torrent_info> ti
+ , fs::path const& save_path
+ , entry const& resume_data
+ , storage_mode_t storage_mode
+ , bool paused
+ , storage_constructor_type sc
+ , void* userdata)
+ {
+ TORRENT_ASSERT(!ti->m_half_metadata);
+ return m_impl->add_torrent(ti, save_path, resume_data
+ , storage_mode, sc, paused, userdata);
+ }
+
+ torrent_handle session::add_torrent(
+ char const* tracker_url
+ , sha1_hash const& info_hash
+ , char const* name
+ , fs::path const& save_path
+ , entry const& e
+ , storage_mode_t storage_mode
+ , bool paused
+ , storage_constructor_type sc
+ , void* userdata)
+ {
+ return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
+ , storage_mode, sc, paused, userdata);
+ }
+
+ void session::remove_torrent(const torrent_handle& h, int options)
+ {
+ m_impl->remove_torrent(h, options);
+ }
+
+ bool session::listen_on(
+ std::pair<int, int> const& port_range
+ , const char* net_interface)
+ {
+ return m_impl->listen_on(port_range, net_interface);
+ }
+
+ unsigned short session::listen_port() const
+ {
+ return m_impl->listen_port();
+ }
+
+ session_status session::status() const
+ {
+ return m_impl->status();
+ }
+
+#ifndef TORRENT_DISABLE_DHT
+
+ void session::start_dht(entry const& startup_state)
+ {
+ m_impl->start_dht(startup_state);
+ }
+
+ void session::stop_dht()
+ {
+ m_impl->stop_dht();
+ }
+
+ void session::set_dht_settings(dht_settings const& settings)
+ {
+ m_impl->set_dht_settings(settings);
+ }
+
+ entry session::dht_state() const
+ {
+ return m_impl->dht_state();
+ }
+
+ void session::add_dht_node(std::pair<std::string, int> const& node)
+ {
+ m_impl->add_dht_node(node);
+ }
+
+ void session::add_dht_router(std::pair<std::string, int> const& node)
+ {
+ m_impl->add_dht_router(node);
+ }
+
+#endif
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ void session::set_pe_settings(pe_settings const& settings)
+ {
+ m_impl->set_pe_settings(settings);
+ }
+
+ pe_settings const& session::get_pe_settings() const
+ {
+ return m_impl->get_pe_settings();
+ }
+#endif
+
+ bool session::is_listening() const
+ {
+ return m_impl->is_listening();
+ }
+
+ void session::set_settings(session_settings const& s)
+ {
+ m_impl->set_settings(s);
+ }
+
+ session_settings const& session::settings()
+ {
+ return m_impl->settings();
+ }
+
+ void session::set_peer_proxy(proxy_settings const& s)
+ {
+ m_impl->set_peer_proxy(s);
+ }
+
+ void session::set_web_seed_proxy(proxy_settings const& s)
+ {
+ m_impl->set_web_seed_proxy(s);
+ }
+
+ void session::set_tracker_proxy(proxy_settings const& s)
+ {
+ m_impl->set_tracker_proxy(s);
+ }
+
+ proxy_settings const& session::peer_proxy() const
+ {
+ return m_impl->peer_proxy();
+ }
+
+ proxy_settings const& session::web_seed_proxy() const
+ {
+ return m_impl->web_seed_proxy();
+ }
+
+ proxy_settings const& session::tracker_proxy() const
+ {
+ return m_impl->tracker_proxy();
+ }
+
+
+#ifndef TORRENT_DISABLE_DHT
+ void session::set_dht_proxy(proxy_settings const& s)
+ {
+ m_impl->set_dht_proxy(s);
+ }
+
+ proxy_settings const& session::dht_proxy() const
+ {
+ return m_impl->dht_proxy();
+ }
+#endif
+
+ void session::set_max_uploads(int limit)
+ {
+ m_impl->set_max_uploads(limit);
+ }
+
+ void session::set_max_connections(int limit)
+ {
+ m_impl->set_max_connections(limit);
+ }
+
+ int session::max_half_open_connections() const
+ {
+ return m_impl->max_half_open_connections();
+ }
+
+ void session::set_max_half_open_connections(int limit)
+ {
+ m_impl->set_max_half_open_connections(limit);
+ }
+
+ int session::upload_rate_limit() const
+ {
+ return m_impl->upload_rate_limit();
+ }
+
+ int session::download_rate_limit() const
+ {
+ return m_impl->download_rate_limit();
+ }
+
+ void session::set_upload_rate_limit(int bytes_per_second)
+ {
+ m_impl->set_upload_rate_limit(bytes_per_second);
+ }
+
+ void session::set_download_rate_limit(int bytes_per_second)
+ {
+ m_impl->set_download_rate_limit(bytes_per_second);
+ }
+
+ int session::num_uploads() const
+ {
+ return m_impl->num_uploads();
+ }
+
+ int session::num_connections() const
+ {
+ return m_impl->num_connections();
+ }
+
+ std::auto_ptr<alert> session::pop_alert()
+ {
+ return m_impl->pop_alert();
+ }
+
+ alert const* session::wait_for_alert(time_duration max_wait)
+ {
+ return m_impl->wait_for_alert(max_wait);
+ }
+
+ void session::set_severity_level(alert::severity_t s)
+ {
+ m_impl->set_severity_level(s);
+ }
+
+ void session::start_lsd()
+ {
+ m_impl->start_lsd();
+ }
+
+ void session::start_natpmp()
+ {
+ m_impl->start_natpmp();
+ }
+
+ void session::start_upnp()
+ {
+ m_impl->start_upnp();
+ }
+
+ void session::stop_lsd()
+ {
+ m_impl->stop_lsd();
+ }
+
+ void session::stop_natpmp()
+ {
+ m_impl->stop_natpmp();
+ }
+
+ void session::stop_upnp()
+ {
+ m_impl->stop_upnp();
+ }
+
+ connection_queue& session::get_connection_queue()
+ {
+ return m_impl->m_half_open;
+ }
+}
+
diff --git a/src/libtorrent/src/session_impl.cpp b/src/libtorrent/src/session_impl.cpp
new file mode 100644
index 0000000..0254379
--- /dev/null
+++ b/src/libtorrent/src/session_impl.cpp
@@ -0,0 +1,2701 @@
+/*
+
+Copyright (c) 2006, Arvid Norberg, Magnus Jonsson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <iterator>
+#include <algorithm>
+#include <set>
+#include <cctype>
+#include <algorithm>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/limits.hpp>
+#include <boost/bind.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/fingerprint.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/alert_types.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/file.hpp"
+#include "libtorrent/bt_peer_connection.hpp"
+#include "libtorrent/ip_filter.hpp"
+#include "libtorrent/socket.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+#include "libtorrent/kademlia/dht_tracker.hpp"
+#include "libtorrent/enum_net.hpp"
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+
+#include <openssl/crypto.h>
+
+namespace
+{
+ // openssl requires this to clean up internal
+ // structures it allocates
+ struct openssl_cleanup
+ {
+ ~openssl_cleanup() { CRYPTO_cleanup_all_ex_data(); }
+ } openssl_global_destructor;
+}
+
+#endif
+#ifdef _WIN32
+// for ERROR_SEM_TIMEOUT
+#include <winerror.h>
+#endif
+
+using boost::shared_ptr;
+using boost::weak_ptr;
+using boost::bind;
+using boost::mutex;
+using libtorrent::aux::session_impl;
+
+namespace libtorrent {
+
+namespace fs = boost::filesystem;
+
+namespace detail
+{
+
+ std::string generate_auth_string(std::string const& user
+ , std::string const& passwd)
+ {
+ if (user.empty()) return std::string();
+ return user + ":" + passwd;
+ }
+
+
+ } namespace aux {
+ // This is the checker thread
+ // it is looping in an infinite loop
+ // until the session is aborted. It will
+ // normally just block in a wait() call,
+ // waiting for a signal from session that
+ // there's a new torrent to check.
+
+ void checker_impl::operator()()
+ {
+ eh_initializer();
+ // if we're currently performing a full file check,
+ // this is the torrent being processed
+ boost::shared_ptr<piece_checker_data> processing;
+ boost::shared_ptr<piece_checker_data> t;
+ for (;;)
+ {
+ // temporary torrent used while checking fastresume data
+ try
+ {
+ t.reset();
+ {
+ boost::mutex::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ // if the job queue is empty and
+ // we shouldn't abort
+ // wait for a signal
+ while (m_torrents.empty() && !m_abort && !processing)
+ m_cond.wait(l);
+
+ if (m_abort)
+ {
+ // no lock is needed here, because the main thread
+ // has already been shut down by now
+ processing.reset();
+ t.reset();
+ std::for_each(m_torrents.begin(), m_torrents.end()
+ , boost::bind(&torrent::abort
+ , boost::bind(&shared_ptr<torrent>::get
+ , boost::bind(&piece_checker_data::torrent_ptr, _1))));
+ m_torrents.clear();
+ std::for_each(m_processing.begin(), m_processing.end()
+ , boost::bind(&torrent::abort
+ , boost::bind(&shared_ptr<torrent>::get
+ , boost::bind(&piece_checker_data::torrent_ptr, _1))));
+ m_processing.clear();
+ return;
+ }
+
+ if (!m_torrents.empty())
+ {
+ t = m_torrents.front();
+ if (t->abort)
+ {
+ // make sure the locking order is
+ // consistent to avoid dead locks
+ // we need to lock the session because closing
+ // torrents assume to have access to it
+ l.unlock();
+ session_impl::mutex_t::scoped_lock l2(m_ses.m_mutex);
+ l.lock();
+
+ t->torrent_ptr->abort();
+ m_torrents.pop_front();
+ continue;
+ }
+ }
+ }
+
+ if (t)
+ {
+ std::string error_msg;
+ t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file()
+ , error_msg);
+
+ // lock the session to add the new torrent
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
+ {
+ m_ses.m_alerts.post_alert(fastresume_rejected_alert(
+ t->torrent_ptr->get_handle()
+ , error_msg));
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << "fastresume data for "
+ << t->torrent_ptr->torrent_file().name() << " rejected: "
+ << error_msg << "\n";
+#endif
+ }
+
+ mutex::scoped_lock l2(m_mutex);
+
+ if (m_torrents.empty() || m_torrents.front() != t)
+ {
+ // this means the torrent was removed right after it was
+ // added. Abort the checking.
+ t.reset();
+ continue;
+ }
+
+ // clear the resume data now that it has been used
+ // (the fast resume data is now parsed and stored in t)
+ t->resume_data = entry();
+ bool up_to_date = t->torrent_ptr->check_fastresume(*t);
+
+ if (up_to_date)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_torrents.empty());
+ TORRENT_ASSERT(m_torrents.front() == t);
+
+ t->torrent_ptr->files_checked(t->unfinished_pieces);
+ m_torrents.pop_front();
+
+ // we cannot add the torrent if the session is aborted.
+ if (!m_ses.is_aborted())
+ {
+ m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(torrent_checked_alert(
+ t->torrent_ptr->get_handle()
+ , "torrent finished checking"));
+ }
+ if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(torrent_finished_alert(
+ t->torrent_ptr->get_handle()
+ , "torrent is complete"));
+ }
+
+ peer_id id;
+ std::fill(id.begin(), id.end(), 0);
+ for (std::vector<tcp::endpoint>::const_iterator i = t->peers.begin();
+ i != t->peers.end(); ++i)
+ {
+ t->torrent_ptr->get_policy().peer_from_tracker(*i, id
+ , peer_info::resume_data, 0);
+ }
+
+ for (std::vector<tcp::endpoint>::const_iterator i = t->banned_peers.begin();
+ i != t->banned_peers.end(); ++i)
+ {
+ policy::peer* p = t->torrent_ptr->get_policy().peer_from_tracker(*i, id
+ , peer_info::resume_data, 0);
+ if (p) p->banned = true;
+ }
+ }
+ else
+ {
+ t->torrent_ptr->abort();
+ }
+ t.reset();
+ continue;
+ }
+
+ l.unlock();
+
+ // move the torrent from
+ // m_torrents to m_processing
+ TORRENT_ASSERT(m_torrents.front() == t);
+
+ m_torrents.pop_front();
+ m_processing.push_back(t);
+ if (!processing)
+ {
+ processing = t;
+ processing->processing = true;
+ t.reset();
+ }
+ }
+ }
+ catch (const std::exception& e)
+ {
+ // This will happen if the storage fails to initialize
+ // for example if one of the files has an invalid filename.
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ mutex::scoped_lock l2(m_mutex);
+
+ if (m_ses.m_alerts.should_post(alert::fatal))
+ {
+ m_ses.m_alerts.post_alert(
+ file_error_alert(
+ t->torrent_ptr->get_handle()
+ , e.what()));
+ }
+ t->torrent_ptr->abort();
+
+ TORRENT_ASSERT(!m_torrents.empty());
+ m_torrents.pop_front();
+ }
+ catch(...)
+ {
+#ifndef NDEBUG
+ std::cerr << "error while checking resume data\n";
+#endif
+ mutex::scoped_lock l(m_mutex);
+ TORRENT_ASSERT(!m_torrents.empty());
+ m_torrents.pop_front();
+ TORRENT_ASSERT(false);
+ }
+
+ if (!processing) continue;
+
+ try
+ {
+ TORRENT_ASSERT(processing);
+
+ float finished = false;
+ float progress = 0.f;
+ boost::tie(finished, progress) = processing->torrent_ptr->check_files();
+
+ {
+ mutex::scoped_lock l2(m_mutex);
+
+ INVARIANT_CHECK;
+
+ processing->progress = progress;
+ if (processing->abort)
+ {
+ TORRENT_ASSERT(!m_processing.empty());
+ TORRENT_ASSERT(m_processing.front() == processing);
+ m_processing.pop_front();
+
+ // make sure the lock order is correct
+ l2.unlock();
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ l2.lock();
+ processing->torrent_ptr->abort();
+
+ processing.reset();
+ if (!m_processing.empty())
+ {
+ processing = m_processing.front();
+ processing->processing = true;
+ }
+ continue;
+ }
+ }
+ if (finished)
+ {
+ // lock the session to add the new torrent
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ mutex::scoped_lock l2(m_mutex);
+
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_processing.empty());
+ TORRENT_ASSERT(m_processing.front() == processing);
+
+ // TODO: factor out the adding of torrents to the session
+ // and to the checker thread to avoid duplicating the
+ // check for abortion.
+ if (!m_ses.is_aborted())
+ {
+ processing->torrent_ptr->files_checked(processing->unfinished_pieces);
+ m_ses.m_torrents.insert(std::make_pair(
+ processing->info_hash, processing->torrent_ptr));
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(torrent_checked_alert(
+ processing->torrent_ptr->get_handle()
+ , "torrent finished checking"));
+ }
+ if (processing->torrent_ptr->is_seed()
+ && m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(torrent_finished_alert(
+ processing->torrent_ptr->get_handle()
+ , "torrent is complete"));
+ }
+
+ peer_id id;
+ std::fill(id.begin(), id.end(), 0);
+ for (std::vector<tcp::endpoint>::const_iterator i = processing->peers.begin();
+ i != processing->peers.end(); ++i)
+ {
+ processing->torrent_ptr->get_policy().peer_from_tracker(*i, id
+ , peer_info::resume_data, 0);
+ }
+
+ for (std::vector<tcp::endpoint>::const_iterator i = processing->banned_peers.begin();
+ i != processing->banned_peers.end(); ++i)
+ {
+ policy::peer* p = processing->torrent_ptr->get_policy().peer_from_tracker(*i, id
+ , peer_info::resume_data, 0);
+ if (p) p->banned = true;
+ }
+ }
+ else
+ {
+ processing->torrent_ptr->abort();
+ }
+ processing.reset();
+ m_processing.pop_front();
+ if (!m_processing.empty())
+ {
+ processing = m_processing.front();
+ processing->processing = true;
+ }
+ }
+ }
+ catch(std::exception const& e)
+ {
+ // This will happen if the storage fails to initialize
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ mutex::scoped_lock l2(m_mutex);
+
+ if (m_ses.m_alerts.should_post(alert::fatal))
+ {
+ m_ses.m_alerts.post_alert(
+ file_error_alert(
+ processing->torrent_ptr->get_handle()
+ , e.what()));
+ }
+
+ processing->torrent_ptr->abort();
+
+ if (!m_processing.empty()
+ && m_processing.front() == processing)
+ m_processing.pop_front();
+ processing.reset();
+ if (!m_processing.empty())
+ {
+ processing = m_processing.front();
+ processing->processing = true;
+ }
+ }
+ catch(...)
+ {
+#ifndef NDEBUG
+ std::cerr << "error while checking files\n";
+#endif
+ mutex::scoped_lock l(m_mutex);
+ TORRENT_ASSERT(!m_processing.empty());
+
+ processing.reset();
+ m_processing.pop_front();
+ if (!m_processing.empty())
+ {
+ processing = m_processing.front();
+ processing->processing = true;
+ }
+
+ TORRENT_ASSERT(false);
+ }
+ }
+ }
+
+ aux::piece_checker_data* checker_impl::find_torrent(sha1_hash const& info_hash)
+ {
+ INVARIANT_CHECK;
+ for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
+ = m_torrents.begin(); i != m_torrents.end(); ++i)
+ {
+ if ((*i)->info_hash == info_hash) return i->get();
+ }
+ for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
+ = m_processing.begin(); i != m_processing.end(); ++i)
+ {
+ if ((*i)->info_hash == info_hash) return i->get();
+ }
+
+ return 0;
+ }
+
+ void checker_impl::remove_torrent(sha1_hash const& info_hash, int options)
+ {
+ INVARIANT_CHECK;
+ for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
+ = m_torrents.begin(); i != m_torrents.end(); ++i)
+ {
+ if ((*i)->info_hash == info_hash)
+ {
+ TORRENT_ASSERT((*i)->processing == false);
+ if (options & session::delete_files)
+ (*i)->torrent_ptr->delete_files();
+ m_torrents.erase(i);
+ return;
+ }
+ }
+ for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
+ = m_processing.begin(); i != m_processing.end(); ++i)
+ {
+ if ((*i)->info_hash == info_hash)
+ {
+ TORRENT_ASSERT((*i)->processing == false);
+ if (options & session::delete_files)
+ (*i)->torrent_ptr->delete_files();
+ m_processing.erase(i);
+ return;
+ }
+ }
+
+ TORRENT_ASSERT(false);
+ }
+
+#ifndef NDEBUG
+ void checker_impl::check_invariant() const
+ {
+ for (std::deque<boost::shared_ptr<piece_checker_data> >::const_iterator i
+ = m_torrents.begin(); i != m_torrents.end(); ++i)
+ {
+ TORRENT_ASSERT(*i);
+ TORRENT_ASSERT((*i)->torrent_ptr);
+ }
+ for (std::deque<boost::shared_ptr<piece_checker_data> >::const_iterator i
+ = m_processing.begin(); i != m_processing.end(); ++i)
+ {
+ TORRENT_ASSERT(*i);
+ TORRENT_ASSERT((*i)->torrent_ptr);
+ }
+ }
+#endif
+
+ struct seed_random_generator
+ {
+ seed_random_generator()
+ {
+ std::srand(total_microseconds(time_now() - min_time()));
+ }
+ };
+
+ session_impl::session_impl(
+ std::pair<int, int> listen_port_range
+ , fingerprint const& cl_fprint
+ , char const* listen_interface
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , fs::path const& logpath
+#endif
+ )
+ : m_send_buffers(send_buffer_size)
+ , m_files(40)
+ , m_strand(m_io_service)
+ , m_half_open(m_io_service)
+ , m_download_channel(m_io_service, peer_connection::download_channel)
+ , m_upload_channel(m_io_service, peer_connection::upload_channel)
+ , m_tracker_manager(m_settings, m_tracker_proxy)
+ , m_listen_port_retries(listen_port_range.second - listen_port_range.first)
+ , m_listen_interface(address::from_string(listen_interface), listen_port_range.first)
+ , m_abort(false)
+ , m_max_uploads(8)
+ , m_max_connections(200)
+ , m_num_unchoked(0)
+ , m_unchoke_time_scaler(0)
+ , m_optimistic_unchoke_time_scaler(0)
+ , m_disconnect_time_scaler(0)
+ , m_incoming_connection(false)
+ , m_last_tick(time_now())
+#ifndef TORRENT_DISABLE_DHT
+ , m_dht_same_port(true)
+ , m_external_udp_port(0)
+#endif
+ , m_timer(m_io_service)
+ , m_next_connect_torrent(0)
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ , m_logpath(logpath)
+#endif
+ , m_checker_impl(*this)
+ {
+#ifdef WIN32
+ // windows XP has a limit on the number of
+ // simultaneous half-open TCP connections
+ DWORD windows_version = ::GetVersion();
+ if ((windows_version & 0xff) >= 6)
+ {
+ // on vista the limit is 5 (in home edition)
+ m_half_open.limit(4);
+ }
+ else
+ {
+ // on XP SP2 it's 10
+ m_half_open.limit(8);
+ }
+#endif
+
+ m_bandwidth_manager[peer_connection::download_channel] = &m_download_channel;
+ m_bandwidth_manager[peer_connection::upload_channel] = &m_upload_channel;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ m_logger = create_log("main_session", listen_port(), false);
+ (*m_logger) << time_now_string() << "\n";
+#endif
+
+#ifdef TORRENT_STATS
+ m_stats_logger.open("session_stats.log", std::ios::trunc);
+ m_stats_logger <<
+ "1. second\n"
+ "2. upload rate\n"
+ "3. download rate\n"
+ "4. downloading torrents\n"
+ "5. seeding torrents\n"
+ "6. peers\n"
+ "7. connecting peers\n"
+ "8. disk block buffers\n"
+ "\n";
+ m_buffer_usage_logger.open("buffer_stats.log", std::ios::trunc);
+ m_second_counter = 0;
+ m_buffer_allocations = 0;
+#endif
+
+ // ---- generate a peer id ----
+ static seed_random_generator seeder;
+
+ m_key = rand() + (rand() << 15) + (rand() << 30);
+ std::string print = cl_fprint.to_string();
+ TORRENT_ASSERT(print.length() <= 20);
+
+ // the client's fingerprint
+ std::copy(
+ print.begin()
+ , print.begin() + print.length()
+ , m_peer_id.begin());
+
+ // http-accepted characters:
+ static char const printable[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz-_.!~*'()";
+
+ // the random number
+ for (unsigned char* i = m_peer_id.begin() + print.length();
+ i != m_peer_id.end(); ++i)
+ {
+ *i = printable[rand() % (sizeof(printable)-1)];
+ }
+
+ m_timer.expires_from_now(seconds(1));
+ m_timer.async_wait(m_strand.wrap(
+ bind(&session_impl::second_tick, this, _1)));
+
+ m_thread.reset(new boost::thread(boost::ref(*this)));
+ m_checker_thread.reset(new boost::thread(boost::ref(m_checker_impl)));
+ }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ void session_impl::add_extension(
+ boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext)
+ {
+ m_extensions.push_back(ext);
+ }
+#endif
+
+#ifndef TORRENT_DISABLE_DHT
+ void session_impl::add_dht_node(udp::endpoint n)
+ {
+ if (m_dht) m_dht->add_node(n);
+ }
+#endif
+
+ void session_impl::abort()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_abort) return;
+#if defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " *** ABORT CALLED ***\n";
+#endif
+ // abort the main thread
+ m_abort = true;
+ if (m_lsd) m_lsd->close();
+ if (m_upnp) m_upnp->close();
+ if (m_natpmp) m_natpmp->close();
+#ifndef TORRENT_DISABLE_DHT
+ if (m_dht) m_dht->stop();
+#endif
+ m_timer.cancel();
+
+ // close the listen sockets
+ for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
+ , end(m_listen_sockets.end()); i != end; ++i)
+ {
+ i->sock->close();
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " aborting all torrents\n";
+#endif
+ // abort all torrents
+ for (torrent_map::iterator i = m_torrents.begin()
+ , end(m_torrents.end()); i != end; ++i)
+ {
+ i->second->abort();
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " aborting all tracker requests\n";
+#endif
+ m_tracker_manager.abort_all_requests();
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " sending event=stopped to trackers\n";
+ int counter = 0;
+#endif
+ for (torrent_map::iterator i = m_torrents.begin();
+ i != m_torrents.end(); ++i)
+ {
+ torrent& t = *i->second;
+
+ if ((!t.is_paused() || t.should_request())
+ && !t.trackers().empty())
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ ++counter;
+#endif
+ tracker_request req = t.generate_tracker_request();
+ TORRENT_ASSERT(req.event == tracker_request::stopped);
+ req.listen_port = 0;
+ if (!m_listen_sockets.empty())
+ req.listen_port = m_listen_sockets.front().external_port;
+ req.key = m_key;
+ std::string login = i->second->tracker_login();
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<tracker_logger> tl(new tracker_logger(*this));
+ m_tracker_loggers.push_back(tl);
+ m_tracker_manager.queue_request(m_strand, m_half_open, req, login
+ , m_listen_interface.address(), tl);
+#else
+ m_tracker_manager.queue_request(m_strand, m_half_open, req, login
+ , m_listen_interface.address());
+#endif
+ }
+ }
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " sent " << counter << " tracker stop requests\n";
+#endif
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " aborting all connections (" << m_connections.size() << ")\n";
+#endif
+ // abort all connections
+ while (!m_connections.empty())
+ {
+#ifndef NDEBUG
+ int conn = m_connections.size();
+#endif
+ (*m_connections.begin())->disconnect();
+ TORRENT_ASSERT(conn == int(m_connections.size()) + 1);
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " shutting down connection queue\n";
+#endif
+ m_half_open.close();
+
+ m_download_channel.close();
+ m_upload_channel.close();
+
+ mutex::scoped_lock l2(m_checker_impl.m_mutex);
+ // abort the checker thread
+ m_checker_impl.m_abort = true;
+
+ m_io_service.stop();
+ }
+
+ void session_impl::set_port_filter(port_filter const& f)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_port_filter = f;
+ }
+
+ void session_impl::set_ip_filter(ip_filter const& f)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ m_ip_filter = f;
+
+ // Close connections whose endpoint is filtered
+ // by the new ip-filter
+ for (torrent_map::iterator i = m_torrents.begin()
+ , end(m_torrents.end()); i != end; ++i)
+ i->second->ip_filter_updated();
+ }
+
+ void session_impl::set_settings(session_settings const& s)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(s.file_pool_size > 0);
+
+ // less than 5 seconds unchoke interval is insane
+ TORRENT_ASSERT(s.unchoke_interval >= 5);
+ m_settings = s;
+ if (m_settings.connection_speed <= 0) m_settings.connection_speed = 200;
+
+ m_files.resize(m_settings.file_pool_size);
+ // replace all occurances of '\n' with ' '.
+ std::string::iterator i = m_settings.user_agent.begin();
+ while ((i = std::find(i, m_settings.user_agent.end(), '\n'))
+ != m_settings.user_agent.end())
+ *i = ' ';
+ }
+
+ tcp::endpoint session_impl::get_ipv6_interface() const
+ {
+ return m_ipv6_interface;
+ }
+
+ session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep
+ , int retries, bool v6_only)
+ {
+ asio::error_code ec;
+ listen_socket_t s;
+ s.sock.reset(new socket_acceptor(m_io_service));
+ s.sock->open(ep.protocol(), ec);
+ s.sock->set_option(socket_acceptor::reuse_address(true), ec);
+ if (ep.protocol() == tcp::v6()) s.sock->set_option(v6only(v6_only), ec);
+ s.sock->bind(ep, ec);
+ while (ec && retries > 0)
+ {
+ ec = asio::error_code();
+ TORRENT_ASSERT(!ec);
+ --retries;
+ ep.port(ep.port() + 1);
+ s.sock->bind(ep, ec);
+ }
+ if (ec)
+ {
+ // instead of giving up, try
+ // let the OS pick a port
+ ep.port(0);
+ ec = asio::error_code();
+ s.sock->bind(ep, ec);
+ }
+ if (ec)
+ {
+ // not even that worked, give up
+ if (m_alerts.should_post(alert::fatal))
+ {
+ std::stringstream msg;
+ msg << "cannot bind to interface '";
+ print_endpoint(msg, ep) << "' " << ec.message();
+ m_alerts.post_alert(listen_failed_alert(ep, msg.str()));
+ }
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ std::stringstream msg;
+ msg << "cannot bind to interface '";
+ print_endpoint(msg, ep) << "' " << ec.message();
+ (*m_logger) << msg.str() << "\n";
+#endif
+ return listen_socket_t();
+ }
+ s.external_port = s.sock->local_endpoint(ec).port();
+ s.sock->listen(0, ec);
+ if (ec)
+ {
+ if (m_alerts.should_post(alert::fatal))
+ {
+ std::stringstream msg;
+ msg << "cannot listen on interface '";
+ print_endpoint(msg, ep) << "' " << ec.message();
+ m_alerts.post_alert(listen_failed_alert(ep, msg.str()));
+ }
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ std::stringstream msg;
+ msg << "cannot listen on interface '";
+ print_endpoint(msg, ep) << "' " << ec.message();
+ (*m_logger) << msg.str() << "\n";
+#endif
+ return listen_socket_t();
+ }
+
+ if (m_alerts.should_post(alert::fatal))
+ {
+ std::string msg = "listening on interface "
+ + boost::lexical_cast<std::string>(ep);
+ m_alerts.post_alert(listen_succeeded_alert(ep, msg));
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << "listening on: " << ep
+ << " external port: " << s.external_port << "\n";
+#endif
+ return s;
+ }
+
+ void session_impl::open_listen_port() throw()
+ {
+ // close the open listen sockets
+ m_listen_sockets.clear();
+ m_incoming_connection = false;
+
+ if (is_any(m_listen_interface.address()))
+ {
+ // this means we should open two listen sockets
+ // one for IPv4 and one for IPv6
+
+ listen_socket_t s = setup_listener(
+ tcp::endpoint(address_v4::any(), m_listen_interface.port())
+ , m_listen_port_retries);
+
+ if (s.sock)
+ {
+ m_listen_sockets.push_back(s);
+ async_accept(s.sock);
+ }
+
+ s = setup_listener(
+ tcp::endpoint(address_v6::any(), m_listen_interface.port())
+ , m_listen_port_retries, true);
+
+ if (s.sock)
+ {
+ m_listen_sockets.push_back(s);
+ async_accept(s.sock);
+ }
+ }
+ else
+ {
+ // we should only open a single listen socket, that
+ // binds to the given interface
+
+ listen_socket_t s = setup_listener(
+ m_listen_interface, m_listen_port_retries);
+
+ if (s.sock)
+ {
+ m_listen_sockets.push_back(s);
+ async_accept(s.sock);
+ }
+ }
+
+ m_ipv6_interface = tcp::endpoint();
+
+ for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
+ , end(m_listen_sockets.end()); i != end; ++i)
+ {
+ asio::error_code ec;
+ tcp::endpoint ep = i->sock->local_endpoint(ec);
+ if (ec || ep.address().is_v4()) continue;
+
+ if (ep.address().to_v6() != address_v6::any())
+ {
+ // if we're listening on a specific address
+ // pick it
+ m_ipv6_interface = ep;
+ }
+ else
+ {
+ // if we're listening on any IPv6 address, enumerate them and
+ // pick the first non-local address
+ std::vector<ip_interface> const& ifs = enum_net_interfaces(m_io_service, ec);
+ for (std::vector<ip_interface>::const_iterator i = ifs.begin()
+ , end(ifs.end()); i != end; ++i)
+ {
+ if (i->interface_address.is_v4()
+ || i->interface_address.to_v6().is_link_local()
+ || i->interface_address.to_v6().is_loopback()) continue;
+ m_ipv6_interface = tcp::endpoint(i->interface_address, ep.port());
+ break;
+ }
+ break;
+ }
+ }
+
+ if (!m_listen_sockets.empty())
+ {
+ asio::error_code ec;
+ tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec);
+ if (!ec)
+ {
+ if (m_natpmp.get()) m_natpmp->set_mappings(local.port(), 0);
+ if (m_upnp.get()) m_upnp->set_mappings(local.port(), 0);
+ }
+ }
+ }
+
+ void session_impl::async_accept(boost::shared_ptr<socket_acceptor> const& listener)
+ {
+ shared_ptr<socket_type> c(new socket_type);
+ c->instantiate<stream_socket>(m_io_service);
+ listener->async_accept(c->get<stream_socket>()
+ , bind(&session_impl::on_incoming_connection, this, c
+ , boost::weak_ptr<socket_acceptor>(listener), _1));
+ }
+
+ void session_impl::on_incoming_connection(shared_ptr<socket_type> const& s
+ , weak_ptr<socket_acceptor> listen_socket, asio::error_code const& e) try
+ {
+ boost::shared_ptr<socket_acceptor> listener = listen_socket.lock();
+ if (!listener) return;
+
+ if (e == asio::error::operation_aborted) return;
+
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_abort) return;
+
+ asio::error_code ec;
+ if (e)
+ {
+ tcp::endpoint ep = listener->local_endpoint(ec);
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ std::string msg = "error accepting connection on '"
+ + boost::lexical_cast<std::string>(ep) + "' " + e.message();
+ (*m_logger) << msg << "\n";
+#endif
+#ifdef _WIN32
+ // Windows sometimes generates this error. It seems to be
+ // non-fatal and we have to do another async_accept.
+ if (e.value() == ERROR_SEM_TIMEOUT)
+ {
+ async_accept(listener);
+ return;
+ }
+#endif
+#ifdef TORRENT_BSD
+ // Leopard sometimes generates an "invalid argument" error. It seems to be
+ // non-fatal and we have to do another async_accept.
+ if (e.value() == EINVAL)
+ {
+ async_accept(listener);
+ return;
+ }
+#endif
+ if (m_alerts.should_post(alert::fatal))
+ {
+ std::string msg = "error accepting connection on '"
+ + boost::lexical_cast<std::string>(ep) + "' " + e.message();
+ m_alerts.post_alert(listen_failed_alert(ep, msg));
+ }
+ return;
+ }
+ async_accept(listener);
+
+ // we got a connection request!
+ tcp::endpoint endp = s->remote_endpoint(ec);
+
+ if (ec)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << endp << " <== INCOMING CONNECTION FAILED, could "
+ "not retrieve remote endpoint " << ec.message() << "\n";
+#endif
+ return;
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << endp << " <== INCOMING CONNECTION\n";
+#endif
+
+ // local addresses do not count, since it's likely
+ // coming from our own client through local service discovery
+ // and it does not reflect whether or not a router is open
+ // for incoming connections or not.
+ if (!is_local(endp.address()))
+ m_incoming_connection = true;
+
+ if (m_ip_filter.access(endp.address()) & ip_filter::blocked)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << "filtered blocked ip\n";
+#endif
+ if (m_alerts.should_post(alert::info))
+ {
+ m_alerts.post_alert(peer_blocked_alert(endp.address()
+ , "incoming connection blocked by IP filter"));
+ }
+ return;
+ }
+
+ // don't allow more connections than the max setting
+ if (num_connections() >= max_connections())
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << "number of connections limit exceeded (conns: "
+ << num_connections() << ", limit: " << max_connections()
+ << "), connection rejected\n";
+#endif
+ return;
+ }
+
+ // check if we have any active torrents
+ // if we don't reject the connection
+ if (m_torrents.empty()) return;
+
+ bool has_active_torrent = false;
+ for (torrent_map::iterator i = m_torrents.begin()
+ , end(m_torrents.end()); i != end; ++i)
+ {
+ if (!i->second->is_paused())
+ {
+ has_active_torrent = true;
+ break;
+ }
+ }
+ if (!has_active_torrent) return;
+
+ boost::intrusive_ptr<peer_connection> c(
+ new bt_peer_connection(*this, s, 0));
+#ifndef NDEBUG
+ c->m_in_constructor = false;
+#endif
+
+ m_connections.insert(c);
+ }
+ catch (std::exception& exc)
+ {
+#ifndef NDEBUG
+ std::string err = exc.what();
+#endif
+ };
+
+ void session_impl::connection_failed(boost::intrusive_ptr<peer_connection> const& peer
+ , tcp::endpoint const& a, char const* message)
+#ifndef NDEBUG
+ try
+#endif
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+// too expensive
+// INVARIANT_CHECK;
+
+ connection_map::iterator p = m_connections.find(peer);
+
+ // the connection may have been disconnected in the receive or send phase
+ if (p == m_connections.end()) return;
+ if (m_alerts.should_post(alert::debug))
+ {
+ m_alerts.post_alert(
+ peer_error_alert(
+ a
+ , (*p)->pid()
+ , message));
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING)
+ (*(*p)->m_logger) << "*** CONNECTION FAILED " << message << "\n";
+#endif
+ (*p)->set_failed();
+ (*p)->disconnect();
+ }
+#ifndef NDEBUG
+ catch (...)
+ {
+ TORRENT_ASSERT(false);
+ };
+#endif
+
+ void session_impl::close_connection(boost::intrusive_ptr<peer_connection> const& p)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+// too expensive
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(p->is_disconnecting());
+ connection_map::iterator i = m_connections.find(p);
+ if (i != m_connections.end())
+ {
+ if (!(*i)->is_choked()) --m_num_unchoked;
+ m_connections.erase(i);
+ }
+ }
+
+ void session_impl::set_peer_id(peer_id const& id)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_peer_id = id;
+ }
+
+ void session_impl::set_key(int key)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_key = key;
+ }
+
+ void session_impl::second_tick(asio::error_code const& e) try
+ {
+ session_impl::mutex_t::scoped_lock l(m_mutex);
+
+// too expensive
+// INVARIANT_CHECK;
+
+ if (m_abort) return;
+
+ if (e)
+ {
+#if defined(TORRENT_LOGGING)
+ (*m_logger) << "*** SECOND TIMER FAILED " << e.message() << "\n";
+#endif
+ abort();
+ return;
+ }
+
+ float tick_interval = total_microseconds(time_now() - m_last_tick) / 1000000.f;
+ m_last_tick = time_now();
+
+ m_timer.expires_from_now(seconds(1));
+ m_timer.async_wait(m_strand.wrap(
+ bind(&session_impl::second_tick, this, _1)));
+
+#ifdef TORRENT_STATS
+ ++m_second_counter;
+ int downloading_torrents = 0;
+ int seeding_torrents = 0;
+ for (torrent_map::iterator i = m_torrents.begin()
+ , end(m_torrents.end()); i != end; ++i)
+ {
+ if (i->second->is_seed())
+ ++seeding_torrents;
+ else
+ ++downloading_torrents;
+ }
+ int num_complete_connections = 0;
+ int num_half_open = 0;
+ for (connection_map::iterator i = m_connections.begin()
+ , end(m_connections.end()); i != end; ++i)
+ {
+ if ((*i)->is_connecting())
+ ++num_half_open;
+ else
+ ++num_complete_connections;
+ }
+
+ m_stats_logger
+ << m_second_counter << "\t"
+ << m_stat.upload_rate() << "\t"
+ << m_stat.download_rate() << "\t"
+ << downloading_torrents << "\t"
+ << seeding_torrents << "\t"
+ << num_complete_connections << "\t"
+ << num_half_open << "\t"
+ << m_disk_thread.disk_allocations() << "\t"
+ << std::endl;
+#endif
+
+
+ // let torrents connect to peers if they want to
+ // if there are any torrents and any free slots
+
+ // this loop will "hand out" max(connection_speed
+ // , half_open.free_slots()) to the torrents, in a
+ // round robin fashion, so that every torrent is
+ // equallt likely to connect to a peer
+
+ if (!m_torrents.empty()
+ && m_half_open.free_slots()
+ && num_connections() < m_max_connections)
+ {
+ // this is the maximum number of connections we will
+ // attempt this tick
+ int max_connections = m_settings.connection_speed;
+
+ torrent_map::iterator i = m_torrents.begin();
+ if (m_next_connect_torrent < int(m_torrents.size()))
+ std::advance(i, m_next_connect_torrent);
+ else
+ m_next_connect_torrent = 0;
+ int steps_since_last_connect = 0;
+ int num_torrents = int(m_torrents.size());
+ for (;;)
+ {
+ torrent& t = *i->second;
+ if (t.want_more_peers())
+ {
+ try
+ {
+ if (t.try_connect_peer())
+ {
+ --max_connections;
+ steps_since_last_connect = 0;
+ }
+ }
+ catch (std::bad_alloc&)
+ {
+ // we ran out of memory trying to connect to a peer
+ // lower the global limit to the number of peers
+ // we already have
+ m_max_connections = num_connections();
+ if (m_max_connections < 2) m_max_connections = 2;
+ }
+ }
+ ++m_next_connect_torrent;
+ ++steps_since_last_connect;
+ ++i;
+ if (i == m_torrents.end())
+ {
+ TORRENT_ASSERT(m_next_connect_torrent == num_torrents);
+ i = m_torrents.begin();
+ m_next_connect_torrent = 0;
+ }
+ // if we have gone one whole loop without
+ // handing out a single connection, break
+ if (steps_since_last_connect > num_torrents) break;
+ // if there are no more free connection slots, abort
+ if (m_half_open.free_slots() == 0) break;
+ // if we should not make any more connections
+ // attempts this tick, abort
+ if (max_connections == 0) break;
+ // maintain the global limit on number of connections
+ if (num_connections() >= m_max_connections) break;
+ }
+ }
+
+ // do the second_tick() on each connection
+ // this will update their statistics (download and upload speeds)
+ // also purge sockets that have timed out
+ // and keep sockets open by keeping them alive.
+ for (connection_map::iterator i = m_connections.begin();
+ i != m_connections.end();)
+ {
+ // we need to do like this because j->second->disconnect() will
+ // erase the connection from the map we're iterating
+ connection_map::iterator j = i;
+ ++i;
+ // if this socket has timed out
+ // close it.
+ peer_connection& c = *j->get();
+ if (c.has_timed_out())
+ {
+ if (m_alerts.should_post(alert::debug))
+ {
+ m_alerts.post_alert(
+ peer_error_alert(
+ c.remote()
+ , c.pid()
+ , "connection timed out"));
+ }
+#if defined(TORRENT_VERBOSE_LOGGING)
+ (*c.m_logger) << "*** CONNECTION TIMED OUT\n";
+#endif
+
+ c.set_failed();
+ c.disconnect();
+ continue;
+ }
+
+ c.keep_alive();
+ }
+
+ // check each torrent for tracker updates
+ // TODO: do this in a timer-event in each torrent instead
+ for (torrent_map::iterator i = m_torrents.begin();
+ i != m_torrents.end();)
+ {
+ torrent& t = *i->second;
+ TORRENT_ASSERT(!t.is_aborted());
+ if (t.should_request())
+ {
+ tracker_request req = t.generate_tracker_request();
+ req.listen_port = 0;
+ if (!m_listen_sockets.empty())
+ req.listen_port = m_listen_sockets.front().external_port;
+ req.key = m_key;
+ m_tracker_manager.queue_request(m_strand, m_half_open, req
+ , t.tracker_login(), m_listen_interface.address(), i->second);
+
+ if (m_alerts.should_post(alert::info))
+ {
+ m_alerts.post_alert(
+ tracker_announce_alert(
+ t.get_handle(), "tracker announce"));
+ }
+ }
+
+ // second_tick() will set the used upload quota
+ t.second_tick(m_stat, tick_interval);
+ ++i;
+ }
+
+ m_stat.second_tick(tick_interval);
+
+ // --------------------------------------------------------------
+ // unchoke set and optimistic unchoke calculations
+ // --------------------------------------------------------------
+ m_unchoke_time_scaler--;
+ if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
+ {
+ m_unchoke_time_scaler = settings().unchoke_interval;
+
+ std::vector<peer_connection*> peers;
+ for (connection_map::iterator i = m_connections.begin()
+ , end(m_connections.end()); i != end; ++i)
+ {
+ peer_connection* p = i->get();
+ torrent* t = p->associated_torrent().lock().get();
+ if (!p->peer_info_struct()
+ || t == 0
+ || !p->is_peer_interested()
+ || p->is_disconnecting()
+ || p->is_connecting()
+ || (p->share_diff() < -free_upload_amount
+ && !t->is_seed()))
+ {
+ if (!(*i)->is_choked() && t)
+ {
+ policy::peer* pi = p->peer_info_struct();
+ if (pi && pi->optimistically_unchoked)
+ {
+ pi->optimistically_unchoked = false;
+ // force a new optimistic unchoke
+ m_optimistic_unchoke_time_scaler = 0;
+ }
+ t->choke_peer(*(*i));
+ }
+ continue;
+ }
+ peers.push_back(i->get());
+ }
+
+ // sort the peers that are eligible for unchoke by download rate and secondary
+ // by total upload. The reason for this is, if all torrents are being seeded,
+ // the download rate will be 0, and the peers we have sent the least to should
+ // be unchoked
+ std::sort(peers.begin(), peers.end()
+ , bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _1))
+ < bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _2)));
+
+ std::stable_sort(peers.begin(), peers.end()
+ , bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _1))
+ > bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _2)));
+
+ // reserve one upload slot for optimistic unchokes
+ int unchoke_set_size = m_max_uploads - 1;
+
+ m_num_unchoked = 0;
+ // go through all the peers and unchoke the first ones and choke
+ // all the other ones.
+ for (std::vector<peer_connection*>::iterator i = peers.begin()
+ , end(peers.end()); i != end; ++i)
+ {
+ peer_connection* p = *i;
+ TORRENT_ASSERT(p);
+ torrent* t = p->associated_torrent().lock().get();
+ TORRENT_ASSERT(t);
+ if (unchoke_set_size > 0)
+ {
+ if (p->is_choked())
+ {
+ if (!t->unchoke_peer(*p))
+ continue;
+ }
+
+ --unchoke_set_size;
+ ++m_num_unchoked;
+
+ TORRENT_ASSERT(p->peer_info_struct());
+ if (p->peer_info_struct()->optimistically_unchoked)
+ {
+ // force a new optimistic unchoke
+ m_optimistic_unchoke_time_scaler = 0;
+ p->peer_info_struct()->optimistically_unchoked = false;
+ }
+ }
+ else
+ {
+ TORRENT_ASSERT(p->peer_info_struct());
+ if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
+ t->choke_peer(*p);
+ if (!p->is_choked())
+ ++m_num_unchoked;
+ }
+ }
+
+ m_optimistic_unchoke_time_scaler--;
+ if (m_optimistic_unchoke_time_scaler <= 0)
+ {
+ m_optimistic_unchoke_time_scaler
+ = settings().optimistic_unchoke_multiplier;
+
+ // find the peer that has been waiting the longest to be optimistically
+ // unchoked
+ connection_map::iterator current_optimistic_unchoke = m_connections.end();
+ connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
+ ptime last_unchoke = max_time();
+
+ for (connection_map::iterator i = m_connections.begin()
+ , end(m_connections.end()); i != end; ++i)
+ {
+ peer_connection* p = i->get();
+ TORRENT_ASSERT(p);
+ policy::peer* pi = p->peer_info_struct();
+ if (!pi) continue;
+ torrent* t = p->associated_torrent().lock().get();
+ if (!t) continue;
+
+ if (pi->optimistically_unchoked)
+ {
+ TORRENT_ASSERT(!p->is_choked());
+ TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
+ current_optimistic_unchoke = i;
+ }
+
+ if (pi->last_optimistically_unchoked < last_unchoke
+ && !p->is_connecting()
+ && !p->is_disconnecting()
+ && p->is_peer_interested()
+ && t->free_upload_slots()
+ && p->is_choked())
+ {
+ last_unchoke = pi->last_optimistically_unchoked;
+ optimistic_unchoke_candidate = i;
+ }
+ }
+
+ if (optimistic_unchoke_candidate != m_connections.end()
+ && optimistic_unchoke_candidate != current_optimistic_unchoke)
+ {
+ if (current_optimistic_unchoke != m_connections.end())
+ {
+ torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get();
+ TORRENT_ASSERT(t);
+ (*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
+ t->choke_peer(*current_optimistic_unchoke->get());
+ }
+ else
+ {
+ ++m_num_unchoked;
+ }
+
+ torrent* t = (*optimistic_unchoke_candidate)->associated_torrent().lock().get();
+ TORRENT_ASSERT(t);
+ bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->get());
+ TORRENT_ASSERT(ret);
+ (*optimistic_unchoke_candidate)->peer_info_struct()->optimistically_unchoked = true;
+ }
+ }
+ }
+
+ // --------------------------------------------------------------
+ // disconnect peers when we have too many
+ // --------------------------------------------------------------
+ --m_disconnect_time_scaler;
+ if (m_disconnect_time_scaler <= 0)
+ {
+ m_disconnect_time_scaler = 60;
+
+ // every 60 seconds, disconnect the worst peer
+ // if we have reached the connection limit
+ if (num_connections() >= max_connections() && !m_torrents.empty())
+ {
+ torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
+ , bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _1))
+ < bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _2)));
+
+ TORRENT_ASSERT(i != m_torrents.end());
+ i->second->get_policy().disconnect_one_peer();
+ }
+ }
+ }
+ catch (std::exception& exc)
+ {
+#ifndef NDEBUG
+ std::cerr << exc.what() << std::endl;
+ TORRENT_ASSERT(false);
+#endif
+ }; // msvc 7.1 seems to require this
+
+ void session_impl::operator()()
+ {
+ eh_initializer();
+
+ {
+ session_impl::mutex_t::scoped_lock l(m_mutex);
+ if (m_listen_interface.port() != 0) open_listen_port();
+ }
+
+ ptime timer = time_now();
+
+ do
+ {
+ try
+ {
+ m_io_service.run();
+ TORRENT_ASSERT(m_abort == true);
+ }
+ catch (std::exception& e)
+ {
+#ifndef NDEBUG
+ std::cerr << e.what() << "\n";
+ std::string err = e.what();
+#endif
+ TORRENT_ASSERT(false);
+ }
+ }
+ while (!m_abort);
+
+ ptime end = time_now() + seconds(m_settings.stop_tracker_timeout);
+ while (time_now() < end && !m_tracker_manager.empty())
+ {
+ m_io_service.reset();
+ m_io_service.poll();
+ // sleep 200 milliseconds
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ boost::int64_t nsec = xt.nsec + 200 * 1000000;
+ if (nsec > 1000000000)
+ {
+ nsec -= 1000000000;
+ xt.sec += 1;
+ }
+ xt.nsec = boost::xtime::xtime_nsec_t(nsec);
+ boost::thread::sleep(xt);
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " locking mutex\n";
+#endif
+ session_impl::mutex_t::scoped_lock l(m_mutex);
+
+#ifndef NDEBUG
+ for (torrent_map::iterator i = m_torrents.begin();
+ i != m_torrents.end(); ++i)
+ {
+ TORRENT_ASSERT(i->second->num_peers() == 0);
+ }
+#endif
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " cleaning up torrents\n";
+#endif
+ m_torrents.clear();
+
+ TORRENT_ASSERT(m_torrents.empty());
+ TORRENT_ASSERT(m_connections.empty());
+ }
+
+
+ // the return value from this function is valid only as long as the
+ // session is locked!
+ boost::weak_ptr<torrent> session_impl::find_torrent(sha1_hash const& info_hash)
+ {
+ std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
+ = m_torrents.find(info_hash);
+#ifndef NDEBUG
+ for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator j
+ = m_torrents.begin(); j != m_torrents.end(); ++j)
+ {
+ torrent* p = boost::get_pointer(j->second);
+ TORRENT_ASSERT(p);
+ }
+#endif
+ if (i != m_torrents.end()) return i->second;
+ return boost::weak_ptr<torrent>();
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<logger> session_impl::create_log(std::string const& name
+ , int instance, bool append)
+ {
+ // current options are file_logger, cout_logger and null_logger
+ return boost::shared_ptr<logger>(new logger(m_logpath, name + ".log", instance, append));
+ }
+#endif
+
+ std::vector<torrent_handle> session_impl::get_torrents()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ mutex::scoped_lock l2(m_checker_impl.m_mutex);
+ std::vector<torrent_handle> ret;
+ for (std::deque<boost::shared_ptr<aux::piece_checker_data> >::iterator i
+ = m_checker_impl.m_torrents.begin()
+ , end(m_checker_impl.m_torrents.end()); i != end; ++i)
+ {
+ if ((*i)->abort) continue;
+ ret.push_back(torrent_handle(this, &m_checker_impl
+ , (*i)->info_hash));
+ }
+
+ for (std::deque<boost::shared_ptr<aux::piece_checker_data> >::iterator i
+ = m_checker_impl.m_processing.begin()
+ , end(m_checker_impl.m_processing.end()); i != end; ++i)
+ {
+ if ((*i)->abort) continue;
+ ret.push_back(torrent_handle(this, &m_checker_impl
+ , (*i)->info_hash));
+ }
+
+ for (session_impl::torrent_map::iterator i
+ = m_torrents.begin(), end(m_torrents.end());
+ i != end; ++i)
+ {
+ if (i->second->is_aborted()) continue;
+ ret.push_back(torrent_handle(this, &m_checker_impl
+ , i->first));
+ }
+ return ret;
+ }
+
+ torrent_handle session_impl::find_torrent_handle(sha1_hash const& info_hash)
+ {
+ return torrent_handle(this, &m_checker_impl, info_hash);
+ }
+
+ torrent_handle session_impl::add_torrent(
+ boost::intrusive_ptr<torrent_info> ti
+ , fs::path const& save_path
+ , entry const& resume_data
+ , storage_mode_t storage_mode
+ , storage_constructor_type sc
+ , bool paused
+ , void* userdata)
+ {
+ TORRENT_ASSERT(!save_path.empty());
+
+ if (ti->begin_files() == ti->end_files())
+ throw std::runtime_error("no files in torrent");
+
+ // lock the session and the checker thread (the order is important!)
+ mutex_t::scoped_lock l(m_mutex);
+ mutex::scoped_lock l2(m_checker_impl.m_mutex);
+
+// INVARIANT_CHECK;
+
+ if (is_aborted())
+ throw std::runtime_error("session is closing");
+
+ // is the torrent already active?
+ if (!find_torrent(ti->info_hash()).expired())
+ throw duplicate_torrent();
+
+ // is the torrent currently being checked?
+ if (m_checker_impl.find_torrent(ti->info_hash()))
+ throw duplicate_torrent();
+
+ // create the torrent and the data associated with
+ // the checker thread and store it before starting
+ // the thread
+ boost::shared_ptr<torrent> torrent_ptr(
+ new torrent(*this, m_checker_impl, ti, save_path
+ , m_listen_interface, storage_mode, 16 * 1024
+ , sc, paused));
+ torrent_ptr->start();
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
+ if (tp) torrent_ptr->add_extension(tp);
+ }
+#endif
+
+ boost::shared_ptr<aux::piece_checker_data> d(
+ new aux::piece_checker_data);
+ d->torrent_ptr = torrent_ptr;
+ d->save_path = save_path;
+ d->info_hash = ti->info_hash();
+ d->resume_data = resume_data;
+
+#ifndef TORRENT_DISABLE_DHT
+ if (m_dht)
+ {
+ torrent_info::nodes_t const& nodes = ti->nodes();
+ std::for_each(nodes.begin(), nodes.end(), bind(
+ (void(dht::dht_tracker::*)(std::pair<std::string, int> const&))
+ &dht::dht_tracker::add_node
+ , boost::ref(m_dht), _1));
+ }
+#endif
+
+ // add the torrent to the queue to be checked
+ m_checker_impl.m_torrents.push_back(d);
+ // and notify the thread that it got another
+ // job in its queue
+ m_checker_impl.m_cond.notify_one();
+
+ return torrent_handle(this, &m_checker_impl, ti->info_hash());
+ }
+
+ torrent_handle session_impl::add_torrent(
+ char const* tracker_url
+ , sha1_hash const& info_hash
+ , char const* name
+ , fs::path const& save_path
+ , entry const&
+ , storage_mode_t storage_mode
+ , storage_constructor_type sc
+ , bool paused
+ , void* userdata)
+ {
+
+ // TODO: support resume data in this case
+ TORRENT_ASSERT(!save_path.empty());
+ {
+ // lock the checker_thread
+ mutex::scoped_lock l(m_checker_impl.m_mutex);
+
+ // is the torrent currently being checked?
+ if (m_checker_impl.find_torrent(info_hash))
+ throw duplicate_torrent();
+ }
+
+ // lock the session
+ session_impl::mutex_t::scoped_lock l(m_mutex);
+
+// INVARIANT_CHECK;
+
+ // is the torrent already active?
+ if (!find_torrent(info_hash).expired())
+ throw duplicate_torrent();
+
+ // you cannot add new torrents to a session that is closing down
+ TORRENT_ASSERT(!is_aborted());
+
+ // create the torrent and the data associated with
+ // the checker thread and store it before starting
+ // the thread
+ boost::shared_ptr<torrent> torrent_ptr(
+ new torrent(*this, m_checker_impl, tracker_url, info_hash, name
+ , save_path, m_listen_interface, storage_mode, 16 * 1024
+ , sc, paused));
+ torrent_ptr->start();
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
+ if (tp) torrent_ptr->add_extension(tp);
+ }
+#endif
+
+ m_torrents.insert(
+ std::make_pair(info_hash, torrent_ptr)).first;
+
+ return torrent_handle(this, &m_checker_impl, info_hash);
+ }
+
+ void session_impl::remove_torrent(const torrent_handle& h, int options)
+ {
+ if (h.m_ses != this) return;
+ TORRENT_ASSERT(h.m_chk == &m_checker_impl || h.m_chk == 0);
+ TORRENT_ASSERT(h.m_ses != 0);
+
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ session_impl::torrent_map::iterator i =
+ m_torrents.find(h.m_info_hash);
+ if (i != m_torrents.end())
+ {
+ torrent& t = *i->second;
+ if (options & session::delete_files)
+ t.delete_files();
+ t.abort();
+
+ if ((!t.is_paused() || t.should_request())
+ && !t.trackers().empty())
+ {
+ tracker_request req = t.generate_tracker_request();
+ TORRENT_ASSERT(req.event == tracker_request::stopped);
+ req.listen_port = 0;
+ if (!m_listen_sockets.empty())
+ req.listen_port = m_listen_sockets.front().external_port;
+ req.key = m_key;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<tracker_logger> tl(new tracker_logger(*this));
+ m_tracker_loggers.push_back(tl);
+ m_tracker_manager.queue_request(m_strand, m_half_open, req
+ , t.tracker_login(), m_listen_interface.address(), tl);
+#else
+ m_tracker_manager.queue_request(m_strand, m_half_open, req
+ , t.tracker_login(), m_listen_interface.address());
+#endif
+
+ if (m_alerts.should_post(alert::info))
+ {
+ m_alerts.post_alert(
+ tracker_announce_alert(
+ t.get_handle(), "tracker announce, event=stopped"));
+ }
+ }
+#ifndef NDEBUG
+ sha1_hash i_hash = t.torrent_file().info_hash();
+#endif
+ m_torrents.erase(i);
+ TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end());
+ return;
+ }
+
+ if (h.m_chk)
+ {
+ mutex::scoped_lock l(m_checker_impl.m_mutex);
+
+ aux::piece_checker_data* d = m_checker_impl.find_torrent(h.m_info_hash);
+ if (d != 0)
+ {
+ if (d->processing) d->abort = true;
+ else m_checker_impl.remove_torrent(h.m_info_hash, options);
+ return;
+ }
+ }
+ }
+
+ bool session_impl::listen_on(
+ std::pair<int, int> const& port_range
+ , const char* net_interface)
+ {
+ session_impl::mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ tcp::endpoint new_interface;
+ if (net_interface && std::strlen(net_interface) > 0)
+ new_interface = tcp::endpoint(address::from_string(net_interface), port_range.first);
+ else
+ new_interface = tcp::endpoint(address_v4::any(), port_range.first);
+
+ m_listen_port_retries = port_range.second - port_range.first;
+
+ // if the interface is the same and the socket is open
+ // don't do anything
+ if (new_interface == m_listen_interface
+ && !m_listen_sockets.empty()) return true;
+
+ m_listen_interface = new_interface;
+
+ open_listen_port();
+
+ bool new_listen_address = m_listen_interface.address() != new_interface.address();
+
+#ifndef TORRENT_DISABLE_DHT
+ if ((new_listen_address || m_dht_same_port) && m_dht)
+ {
+ if (m_dht_same_port)
+ m_dht_settings.service_port = new_interface.port();
+ // the listen interface changed, rebind the dht listen socket as well
+ m_dht->rebind(new_interface.address()
+ , m_dht_settings.service_port);
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(0, m_dht_settings.service_port);
+ if (m_upnp.get())
+ m_upnp->set_mappings(0, m_dht_settings.service_port);
+ }
+#endif
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ m_logger = create_log("main_session", listen_port(), false);
+ (*m_logger) << time_now_string() << "\n";
+#endif
+
+ return !m_listen_sockets.empty();
+ }
+
+ unsigned short session_impl::listen_port() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_listen_sockets.empty()) return 0;
+ return m_listen_sockets.front().external_port;;
+ }
+
+ void session_impl::announce_lsd(sha1_hash const& ih)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ // use internal listen port for local peers
+ if (m_lsd.get())
+ m_lsd->announce(ih, m_listen_interface.port());
+ }
+
+ void session_impl::on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = find_torrent(ih).lock();
+ if (!t) return;
+ // don't add peers from lsd to private torrents
+ if (t->torrent_file().priv()) return;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string()
+ << ": added peer from local discovery: " << peer << "\n";
+#endif
+ t->get_policy().peer_from_tracker(peer, peer_id(0), peer_info::lsd, 0);
+ }
+
+ void session_impl::on_port_mapping(int tcp_port, int udp_port
+ , std::string const& errmsg)
+ {
+#ifndef TORRENT_DISABLE_DHT
+ if (udp_port != 0)
+ {
+ m_external_udp_port = udp_port;
+ m_dht_settings.service_port = udp_port;
+ if (m_alerts.should_post(alert::info))
+ {
+ std::stringstream msg;
+ msg << "successfully mapped UDP port " << udp_port;
+ m_alerts.post_alert(portmap_alert(msg.str()));
+ }
+ }
+#endif
+
+ if (tcp_port != 0)
+ {
+ if (!m_listen_sockets.empty())
+ m_listen_sockets.front().external_port = tcp_port;
+ if (m_alerts.should_post(alert::info))
+ {
+ std::stringstream msg;
+ msg << "successfully mapped TCP port " << tcp_port;
+ m_alerts.post_alert(portmap_alert(msg.str()));
+ }
+ }
+
+ if (!errmsg.empty())
+ {
+ if (m_alerts.should_post(alert::warning))
+ {
+ std::stringstream msg;
+ msg << "Error while mapping ports on NAT router: " << errmsg;
+ m_alerts.post_alert(portmap_error_alert(msg.str()));
+ }
+ }
+ }
+
+ session_status session_impl::status() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+// INVARIANT_CHECK;
+
+ session_status s;
+
+ s.up_bandwidth_queue = m_upload_channel.queue_size();
+ s.down_bandwidth_queue = m_download_channel.queue_size();
+
+ s.has_incoming_connections = m_incoming_connection;
+ s.num_peers = (int)m_connections.size();
+
+ s.download_rate = m_stat.download_rate();
+ s.upload_rate = m_stat.upload_rate();
+
+ s.payload_download_rate = m_stat.download_payload_rate();
+ s.payload_upload_rate = m_stat.upload_payload_rate();
+
+ s.total_download = m_stat.total_protocol_download()
+ + m_stat.total_payload_download();
+
+ s.total_upload = m_stat.total_protocol_upload()
+ + m_stat.total_payload_upload();
+
+ s.total_payload_download = m_stat.total_payload_download();
+ s.total_payload_upload = m_stat.total_payload_upload();
+
+#ifndef TORRENT_DISABLE_DHT
+ if (m_dht)
+ {
+ m_dht->dht_status(s);
+ }
+ else
+ {
+ s.dht_nodes = 0;
+ s.dht_node_cache = 0;
+ s.dht_torrents = 0;
+ s.dht_global_nodes = 0;
+ }
+#endif
+
+ return s;
+ }
+
+#ifndef TORRENT_DISABLE_DHT
+
+ void session_impl::start_dht(entry const& startup_state)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_dht)
+ {
+ m_dht->stop();
+ m_dht = 0;
+ }
+ if (m_dht_settings.service_port == 0
+ || m_dht_same_port)
+ {
+ m_dht_same_port = true;
+ // if you hit this assert you are trying to start the
+ // DHT with the same port as the tcp listen port
+ // (which is default) _before_ you have opened the
+ // tcp listen port (so there is no configured port to use)
+ // basically, make sure you call listen_on() before
+ // start_dht(). See documentation for listen_on() for
+ // more information.
+ TORRENT_ASSERT(m_listen_interface.port() > 0);
+ m_dht_settings.service_port = m_listen_interface.port();
+ }
+ m_external_udp_port = m_dht_settings.service_port;
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(0, m_dht_settings.service_port);
+ if (m_upnp.get())
+ m_upnp->set_mappings(0, m_dht_settings.service_port);
+ m_dht = new dht::dht_tracker(m_io_service
+ , m_dht_settings, m_listen_interface.address()
+ , startup_state);
+ }
+
+ void session_impl::stop_dht()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (!m_dht) return;
+ m_dht->stop();
+ m_dht = 0;
+ }
+
+ void session_impl::set_dht_settings(dht_settings const& settings)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ // only change the dht listen port in case the settings
+ // contains a vaiid port, and if it is different from
+ // the current setting
+ if (settings.service_port != 0)
+ m_dht_same_port = false;
+ else
+ m_dht_same_port = true;
+ if (!m_dht_same_port
+ && settings.service_port != m_dht_settings.service_port
+ && m_dht)
+ {
+ m_dht->rebind(m_listen_interface.address()
+ , settings.service_port);
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(0, m_dht_settings.service_port);
+ if (m_upnp.get())
+ m_upnp->set_mappings(0, m_dht_settings.service_port);
+ m_external_udp_port = settings.service_port;
+ }
+ m_dht_settings = settings;
+ if (m_dht_same_port)
+ m_dht_settings.service_port = m_listen_interface.port();
+ }
+
+ entry session_impl::dht_state() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (!m_dht) return entry();
+ return m_dht->state();
+ }
+
+ void session_impl::add_dht_node(std::pair<std::string, int> const& node)
+ {
+ TORRENT_ASSERT(m_dht);
+ mutex_t::scoped_lock l(m_mutex);
+ m_dht->add_node(node);
+ }
+
+ void session_impl::add_dht_router(std::pair<std::string, int> const& node)
+ {
+ TORRENT_ASSERT(m_dht);
+ mutex_t::scoped_lock l(m_mutex);
+ m_dht->add_router_node(node);
+ }
+
+#endif
+
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ void session_impl::set_pe_settings(pe_settings const& settings)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_pe_settings = settings;
+ }
+#endif
+
+ bool session_impl::is_listening() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ return !m_listen_sockets.empty();
+ }
+
+ session_impl::~session_impl()
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << "\n\n *** shutting down session *** \n\n";
+#endif
+ abort();
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " waiting for main thread\n";
+#endif
+ m_thread->join();
+
+ TORRENT_ASSERT(m_torrents.empty());
+
+ // it's important that the main thread is closed completely before
+ // the checker thread is terminated. Because all the connections
+ // have to be closed and removed from the torrents before they
+ // can be destructed. (because the weak pointers in the
+ // peer_connections will be invalidated when the torrents are
+ // destructed and then the invariant will be broken).
+
+ {
+ mutex::scoped_lock l(m_checker_impl.m_mutex);
+ // abort the checker thread
+ m_checker_impl.m_abort = true;
+
+ // abort the currently checking torrent
+ if (!m_checker_impl.m_torrents.empty())
+ {
+ m_checker_impl.m_torrents.front()->abort = true;
+ }
+ m_checker_impl.m_cond.notify_one();
+ }
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " waiting for checker thread\n";
+#endif
+ m_checker_thread->join();
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " waiting for disk io thread\n";
+#endif
+ m_disk_thread.join();
+
+ TORRENT_ASSERT(m_torrents.empty());
+ TORRENT_ASSERT(m_connections.empty());
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_logger) << time_now_string() << " shutdown complete!\n";
+#endif
+ }
+
+ void session_impl::set_max_uploads(int limit)
+ {
+ TORRENT_ASSERT(limit > 0 || limit == -1);
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (limit <= 0) limit = (std::numeric_limits<int>::max)();
+ m_max_uploads = limit;
+ }
+
+ void session_impl::set_max_connections(int limit)
+ {
+ TORRENT_ASSERT(limit > 0 || limit == -1);
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (limit <= 0) limit = (std::numeric_limits<int>::max)();
+ m_max_connections = limit;
+ }
+
+ void session_impl::set_max_half_open_connections(int limit)
+ {
+ TORRENT_ASSERT(limit > 0 || limit == -1);
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (limit <= 0) limit = (std::numeric_limits<int>::max)();
+ m_half_open.limit(limit);
+ }
+
+ void session_impl::set_download_rate_limit(int bytes_per_second)
+ {
+ TORRENT_ASSERT(bytes_per_second > 0 || bytes_per_second == -1);
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (bytes_per_second <= 0) bytes_per_second = bandwidth_limit::inf;
+ m_bandwidth_manager[peer_connection::download_channel]->throttle(bytes_per_second);
+ }
+
+ void session_impl::set_upload_rate_limit(int bytes_per_second)
+ {
+ TORRENT_ASSERT(bytes_per_second > 0 || bytes_per_second == -1);
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (bytes_per_second <= 0) bytes_per_second = bandwidth_limit::inf;
+ m_bandwidth_manager[peer_connection::upload_channel]->throttle(bytes_per_second);
+ }
+
+ std::auto_ptr<alert> session_impl::pop_alert()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+// too expensive
+// INVARIANT_CHECK;
+
+ if (m_alerts.pending())
+ return m_alerts.get();
+ return std::auto_ptr<alert>(0);
+ }
+
+ alert const* session_impl::wait_for_alert(time_duration max_wait)
+ {
+ return m_alerts.wait_for_alert(max_wait);
+ }
+
+ void session_impl::set_severity_level(alert::severity_t s)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_alerts.set_severity(s);
+ }
+
+ int session_impl::upload_rate_limit() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ int ret = m_bandwidth_manager[peer_connection::upload_channel]->throttle();
+ return ret == (std::numeric_limits<int>::max)() ? -1 : ret;
+ }
+
+ int session_impl::download_rate_limit() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ int ret = m_bandwidth_manager[peer_connection::download_channel]->throttle();
+ return ret == (std::numeric_limits<int>::max)() ? -1 : ret;
+ }
+
+ void session_impl::start_lsd()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_lsd) return;
+
+ m_lsd = new lsd(m_io_service
+ , m_listen_interface.address()
+ , bind(&session_impl::on_lsd_peer, this, _1, _2));
+ }
+
+ void session_impl::start_natpmp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_natpmp) return;
+
+ m_natpmp = new natpmp(m_io_service
+ , m_listen_interface.address()
+ , bind(&session_impl::on_port_mapping
+ , this, _1, _2, _3));
+
+ m_natpmp->set_mappings(m_listen_interface.port(),
+#ifndef TORRENT_DISABLE_DHT
+ m_dht ? m_dht_settings.service_port :
+#endif
+ 0);
+ }
+
+ void session_impl::start_upnp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_upnp) return;
+
+ m_upnp = new upnp(m_io_service, m_half_open
+ , m_listen_interface.address()
+ , m_settings.user_agent
+ , bind(&session_impl::on_port_mapping
+ , this, _1, _2, _3)
+ , m_settings.upnp_ignore_nonrouters);
+
+ m_upnp->discover_device();
+ m_upnp->set_mappings(m_listen_interface.port(),
+#ifndef TORRENT_DISABLE_DHT
+ m_dht ? m_dht_settings.service_port :
+#endif
+ 0);
+ }
+
+ void session_impl::stop_lsd()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_lsd.get())
+ m_lsd->close();
+ m_lsd = 0;
+ }
+
+ void session_impl::stop_natpmp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_natpmp.get())
+ m_natpmp->close();
+ m_natpmp = 0;
+ }
+
+ void session_impl::stop_upnp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_upnp.get())
+ m_upnp->close();
+ m_upnp = 0;
+ }
+
+ void session_impl::free_disk_buffer(char* buf)
+ {
+ m_disk_thread.free_buffer(buf);
+ }
+
+ std::pair<char*, int> session_impl::allocate_buffer(int size)
+ {
+ TORRENT_ASSERT(size > 0);
+ int num_buffers = (size + send_buffer_size - 1) / send_buffer_size;
+ TORRENT_ASSERT(num_buffers > 0);
+
+ boost::mutex::scoped_lock l(m_send_buffer_mutex);
+#ifdef TORRENT_STATS
+ m_buffer_allocations += num_buffers;
+ m_buffer_usage_logger << log_time() << " protocol_buffer: "
+ << (m_buffer_allocations * send_buffer_size) << std::endl;
+#endif
+ std::pair<char*, int> ret((char*)m_send_buffers.ordered_malloc(num_buffers)
+ , num_buffers * send_buffer_size);
+ if (ret.first == 0) throw std::bad_alloc();
+ return ret;
+ }
+
+ void session_impl::free_buffer(char* buf, int size)
+ {
+ TORRENT_ASSERT(size > 0);
+ TORRENT_ASSERT(size % send_buffer_size == 0);
+ int num_buffers = size / send_buffer_size;
+ TORRENT_ASSERT(num_buffers > 0);
+
+ boost::mutex::scoped_lock l(m_send_buffer_mutex);
+#ifdef TORRENT_STATS
+ m_buffer_allocations -= num_buffers;
+ TORRENT_ASSERT(m_buffer_allocations >= 0);
+ m_buffer_usage_logger << log_time() << " protocol_buffer: "
+ << (m_buffer_allocations * send_buffer_size) << std::endl;
+#endif
+ m_send_buffers.ordered_free(buf, num_buffers);
+ }
+
+#ifndef NDEBUG
+ void session_impl::check_invariant() const
+ {
+ TORRENT_ASSERT(m_max_connections > 0);
+ TORRENT_ASSERT(m_max_uploads > 0);
+ int unchokes = 0;
+ int num_optimistic = 0;
+ for (connection_map::const_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ TORRENT_ASSERT(*i);
+ boost::shared_ptr<torrent> t = (*i)->associated_torrent().lock();
+
+ peer_connection* p = i->get();
+ TORRENT_ASSERT(!p->is_disconnecting());
+ if (!p->is_choked()) ++unchokes;
+ if (p->peer_info_struct()
+ && p->peer_info_struct()->optimistically_unchoked)
+ {
+ ++num_optimistic;
+ TORRENT_ASSERT(!p->is_choked());
+ }
+ if (t && p->peer_info_struct())
+ {
+ TORRENT_ASSERT(t->get_policy().has_connection(p));
+ }
+ }
+ TORRENT_ASSERT(num_optimistic == 0 || num_optimistic == 1);
+ if (m_num_unchoked != unchokes)
+ {
+ TORRENT_ASSERT(false);
+ }
+ for (std::map<sha1_hash, boost::shared_ptr<torrent> >::const_iterator j
+ = m_torrents.begin(); j != m_torrents.end(); ++j)
+ {
+ TORRENT_ASSERT(boost::get_pointer(j->second));
+ }
+ }
+#endif
+
+ void piece_checker_data::parse_resume_data(
+ const entry& resume_data
+ , const torrent_info& info
+ , std::string& error)
+ {
+ // if we don't have any resume data, return
+ if (resume_data.type() == entry::undefined_t) return;
+
+ entry rd = resume_data;
+
+ try
+ {
+ if (rd["file-format"].string() != "libtorrent resume file")
+ {
+ error = "missing file format tag";
+ return;
+ }
+
+ if (rd["file-version"].integer() > 1)
+ {
+ error = "incompatible file version "
+ + boost::lexical_cast<std::string>(rd["file-version"].integer());
+ return;
+ }
+
+ // verify info_hash
+ sha1_hash hash = rd["info-hash"].string();
+ if (hash != info.info_hash())
+ {
+ error = "mismatching info-hash: " + boost::lexical_cast<std::string>(hash);
+ return;
+ }
+
+ // the peers
+
+ if (entry* peers_entry = rd.find_key("peers"))
+ {
+ entry::list_type& peer_list = peers_entry->list();
+
+ std::vector<tcp::endpoint> tmp_peers;
+ tmp_peers.reserve(peer_list.size());
+ for (entry::list_type::iterator i = peer_list.begin();
+ i != peer_list.end(); ++i)
+ {
+ tcp::endpoint a(
+ address::from_string((*i)["ip"].string())
+ , (unsigned short)(*i)["port"].integer());
+ tmp_peers.push_back(a);
+ }
+
+ peers.swap(tmp_peers);
+ }
+
+ if (entry* banned_peers_entry = rd.find_key("banned_peers"))
+ {
+ entry::list_type& peer_list = banned_peers_entry->list();
+
+ std::vector<tcp::endpoint> tmp_peers;
+ tmp_peers.reserve(peer_list.size());
+ for (entry::list_type::iterator i = peer_list.begin();
+ i != peer_list.end(); ++i)
+ {
+ tcp::endpoint a(
+ address::from_string((*i)["ip"].string())
+ , (unsigned short)(*i)["port"].integer());
+ tmp_peers.push_back(a);
+ }
+
+ banned_peers.swap(tmp_peers);
+ }
+
+ // read piece map
+ const entry::list_type& slots = rd["slots"].list();
+ if ((int)slots.size() > info.num_pieces())
+ {
+ error = "file has more slots than torrent (slots: "
+ + boost::lexical_cast<std::string>(slots.size()) + " size: "
+ + boost::lexical_cast<std::string>(info.num_pieces()) + " )";
+ return;
+ }
+
+ std::vector<int> tmp_pieces;
+ tmp_pieces.reserve(slots.size());
+ for (entry::list_type::const_iterator i = slots.begin();
+ i != slots.end(); ++i)
+ {
+ int index = (int)i->integer();
+ if (index >= info.num_pieces() || index < -2)
+ {
+ error = "too high index number in slot map (index: "
+ + boost::lexical_cast<std::string>(index) + " size: "
+ + boost::lexical_cast<std::string>(info.num_pieces()) + ")";
+ return;
+ }
+ tmp_pieces.push_back(index);
+ }
+
+ // only bother to check the partial pieces if we have the same block size
+ // as in the fast resume data. If the blocksize has changed, then throw
+ // away all partial pieces.
+ std::vector<piece_picker::downloading_piece> tmp_unfinished;
+ int num_blocks_per_piece = (int)rd["blocks per piece"].integer();
+ if (num_blocks_per_piece == info.piece_length() / torrent_ptr->block_size())
+ {
+ // the unfinished pieces
+
+ entry::list_type& unfinished = rd["unfinished"].list();
+ int unfinished_size = int(unfinished.size());
+ block_info.resize(num_blocks_per_piece * unfinished_size);
+ tmp_unfinished.reserve(unfinished_size);
+ int index = 0;
+ for (entry::list_type::iterator i = unfinished.begin();
+ i != unfinished.end(); ++i, ++index)
+ {
+ piece_picker::downloading_piece p;
+ p.info = &block_info[index * num_blocks_per_piece];
+ p.index = (int)(*i)["piece"].integer();
+ if (p.index < 0 || p.index >= info.num_pieces())
+ {
+ error = "invalid piece index in unfinished piece list (index: "
+ + boost::lexical_cast<std::string>(p.index) + " size: "
+ + boost::lexical_cast<std::string>(info.num_pieces()) + ")";
+ return;
+ }
+
+ const std::string& bitmask = (*i)["bitmask"].string();
+
+ const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
+ if ((int)bitmask.size() != num_bitmask_bytes)
+ {
+ error = "invalid size of bitmask (" + boost::lexical_cast<std::string>(bitmask.size()) + ")";
+ return;
+ }
+ for (int j = 0; j < num_bitmask_bytes; ++j)
+ {
+ unsigned char bits = bitmask[j];
+ int num_bits = (std::min)(num_blocks_per_piece - j*8, 8);
+ for (int k = 0; k < num_bits; ++k)
+ {
+ const int bit = j * 8 + k;
+ if (bits & (1 << k))
+ {
+ p.info[bit].state = piece_picker::block_info::state_finished;
+ ++p.finished;
+ }
+ }
+ }
+
+ if (p.finished == 0) continue;
+
+ std::vector<int>::iterator slot_iter
+ = std::find(tmp_pieces.begin(), tmp_pieces.end(), p.index);
+ if (slot_iter == tmp_pieces.end())
+ {
+ // this piece is marked as unfinished
+ // but doesn't have any storage
+ error = "piece " + boost::lexical_cast<std::string>(p.index) + " is "
+ "marked as unfinished, but doesn't have any storage";
+ return;
+ }
+
+ TORRENT_ASSERT(*slot_iter == p.index);
+ int slot_index = static_cast<int>(slot_iter - tmp_pieces.begin());
+ const entry* ad = i->find_key("adler32");
+
+ if (ad && ad->type() == entry::int_t)
+ {
+ unsigned long adler
+ = torrent_ptr->filesystem().piece_crc(
+ slot_index
+ , torrent_ptr->block_size()
+ , p.info);
+
+ // crc's didn't match, don't use the resume data
+ if (ad->integer() != entry::integer_type(adler))
+ {
+ error = "checksum mismatch on piece "
+ + boost::lexical_cast<std::string>(p.index);
+ return;
+ }
+ }
+
+ tmp_unfinished.push_back(p);
+ }
+ }
+
+ if (!torrent_ptr->verify_resume_data(rd, error))
+ return;
+
+ piece_map.swap(tmp_pieces);
+ unfinished_pieces.swap(tmp_unfinished);
+ }
+ catch (invalid_encoding&)
+ {
+ return;
+ }
+ catch (type_error&)
+ {
+ return;
+ }
+ catch (file_error&)
+ {
+ return;
+ }
+ }
+}}
+
diff --git a/src/libtorrent/src/sha1.cpp b/src/libtorrent/src/sha1.cpp
new file mode 100644
index 0000000..a7ea671
--- /dev/null
+++ b/src/libtorrent/src/sha1.cpp
@@ -0,0 +1,317 @@
+/*
+SHA-1 C++ conversion
+
+original version:
+
+SHA-1 in C
+By Steve Reid <sreid at sea-to-sky.net>
+100% Public Domain
+
+changelog at the end of the file.
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <cstdio>
+#include <cstring>
+
+// if you don't want boost
+// replace with
+// #include <stdint.h>
+
+#include <boost/cstdint.hpp>
+using boost::uint32_t;
+using boost::uint8_t;
+
+#include "libtorrent/config.hpp"
+
+struct TORRENT_EXPORT SHA_CTX
+{
+ uint32_t state[5];
+ uint32_t count[2];
+ uint8_t buffer[64];
+};
+
+TORRENT_EXPORT void SHA1_Init(SHA_CTX* context);
+TORRENT_EXPORT void SHA1_Update(SHA_CTX* context, uint8_t const* data, uint32_t len);
+TORRENT_EXPORT void SHA1_Final(uint8_t* digest, SHA_CTX* context);
+
+namespace
+{
+ union CHAR64LONG16
+ {
+ uint8_t c[64];
+ uint32_t l[16];
+ };
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+// blk0() and blk() perform the initial expand.
+// I got the idea of expanding during the round function from SSLeay
+ struct little_endian_blk0
+ {
+ static uint32_t apply(CHAR64LONG16* block, int i)
+ {
+ return block->l[i] = (rol(block->l[i],24)&0xFF00FF00)
+ | (rol(block->l[i],8)&0x00FF00FF);
+ }
+ };
+
+ struct big_endian_blk0
+ {
+ static uint32_t apply(CHAR64LONG16* block, int i)
+ {
+ return block->l[i];
+ }
+ };
+
+
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+// (R0+R1), R2, R3, R4 are the different operations used in SHA1
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+BlkFun::apply(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+ // Hash a single 512-bit block. This is the core of the algorithm.
+ template <class BlkFun>
+ void SHA1Transform(uint32_t state[5], uint8_t const buffer[64])
+ {
+ using namespace std;
+ uint32_t a, b, c, d, e;
+
+ CHAR64LONG16* block;
+ uint8_t workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+
+ // Copy context->state[] to working vars
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ // 4 rounds of 20 operations each. Loop unrolled.
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ // Add the working vars back into context.state[]
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ // Wipe variables
+ a = b = c = d = e = 0;
+ }
+
+ void SHAPrintContext(SHA_CTX *context, char *msg)
+ {
+ using namespace std;
+ printf("%s (%d,%d) %x %x %x %x %x\n"
+ , msg, context->count[0], context->count[1]
+ , context->state[0], context->state[1]
+ , context->state[2], context->state[3]
+ , context->state[4]);
+ }
+
+ template <class BlkFun>
+ void internal_update(SHA_CTX* context, uint8_t const* data, uint32_t len)
+ {
+ using namespace std;
+ uint32_t i, j; // JHB
+
+#ifdef VERBOSE
+ SHAPrintContext(context, "before");
+#endif
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63)
+ {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform<BlkFun>(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64)
+ {
+ SHA1Transform<BlkFun>(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else
+ {
+ i = 0;
+ }
+ memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+ SHAPrintContext(context, "after ");
+#endif
+ }
+
+ bool is_big_endian()
+ {
+ uint32_t test = 1;
+ return *reinterpret_cast<uint8_t*>(&test) == 0;
+ }
+}
+
+// SHA1Init - Initialize new context
+
+void SHA1_Init(SHA_CTX* context)
+{
+ // SHA1 initialization constants
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+// Run your data through this.
+
+void SHA1_Update(SHA_CTX* context, uint8_t const* data, uint32_t len)
+{
+#if defined __BIG_ENDIAN__
+ internal_update<big_endian_blk0>(context, data, len);
+#elif defined LITTLE_ENDIAN
+ internal_update<little_endian_blk0>(context, data, len);
+#else
+ // select different functions depending on endianess
+ // and figure out the endianess runtime
+ if (is_big_endian())
+ internal_update<big_endian_blk0>(context, data, len);
+ else
+ internal_update<little_endian_blk0>(context, data, len);
+#endif
+}
+
+
+// Add padding and return the message digest.
+
+void SHA1_Final(uint8_t* digest, SHA_CTX* context)
+{
+ uint8_t finalcount[8];
+
+ for (uint32_t i = 0; i < 8; ++i)
+ {
+ // Endian independent
+ finalcount[i] = static_cast<uint8_t>(
+ (context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255);
+ }
+
+ SHA1_Update(context, (uint8_t const*)"\200", 1);
+ while ((context->count[0] & 504) != 448)
+ SHA1_Update(context, (uint8_t const*)"\0", 1);
+ SHA1_Update(context, finalcount, 8); // Should cause a SHA1Transform()
+
+ for (uint32_t i = 0; i < 20; ++i)
+ {
+ digest[i] = static_cast<unsigned char>(
+ (context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+}
+
+/************************************************************
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown at burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it. This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid at sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve at edmweb.com to sreid at sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz at celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Converted to C++ 6/04
+By Arvid Norberg <arvidn at sourceforge.net>
+1- made the input buffer const, and made the
+ previous SHA1HANDSOFF implicit
+2- uses C99 types with size guarantees
+ from boost
+3- if none of __BIG_ENDIAN__ or LITTLE_ENDIAN
+ are defined, endianess is determined
+ at runtime. templates are used to duplicate
+ the transform function for each endianess
+4- using anonymous namespace to avoid external
+ linkage on internal functions
+5- using standard C++ includes
+6- made API compatible with openssl
+
+still 100% PD
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
diff --git a/src/libtorrent/src/socks4_stream.cpp b/src/libtorrent/src/socks4_stream.cpp
new file mode 100644
index 0000000..c96dde8
--- /dev/null
+++ b/src/libtorrent/src/socks4_stream.cpp
@@ -0,0 +1,152 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/socks4_stream.hpp"
+
+namespace libtorrent
+{
+
+ void socks4_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ // SOCKS4 doesn't support IPv6 addresses
+ while (i != tcp::resolver::iterator() && i->endpoint().address().is_v6())
+ ++i;
+
+ if (i == tcp::resolver::iterator())
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ (*h)(ec);
+ close(ec);
+ return;
+ }
+
+ m_sock.async_connect(i->endpoint(), boost::bind(
+ &socks4_stream::connected, this, _1, h));
+ }
+
+ void socks4_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ using namespace libtorrent::detail;
+
+ m_buffer.resize(m_user.size() + 9);
+ char* p = &m_buffer[0];
+ write_uint8(4, p); // SOCKS VERSION 4
+ write_uint8(1, p); // SOCKS CONNECT
+ write_uint16(m_remote_endpoint.port(), p);
+ write_uint32(m_remote_endpoint.address().to_v4().to_ulong(), p);
+ std::copy(m_user.begin(), m_user.end(), p);
+ p += m_user.size();
+ write_uint8(0, p); // NULL terminator
+
+ asio::async_write(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks4_stream::handshake1, this, _1, h));
+ }
+
+ void socks4_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ m_buffer.resize(8);
+ asio::async_read(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks4_stream::handshake2, this, _1, h));
+ }
+
+ void socks4_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ using namespace libtorrent::detail;
+
+ char* p = &m_buffer[0];
+ int reply_version = read_uint8(p);
+ int status_code = read_uint8(p);
+
+ if (reply_version != 0)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ (*h)(ec);
+ close(ec);
+ return;
+ }
+
+ // access granted
+ if (status_code == 90)
+ {
+ std::vector<char>().swap(m_buffer);
+ (*h)(e);
+ return;
+ }
+
+ asio::error_code ec = asio::error::fault;
+ switch (status_code)
+ {
+ case 91: ec = asio::error::connection_refused; break;
+ case 92: ec = asio::error::no_permission; break;
+ case 93: ec = asio::error::no_permission; break;
+ }
+ (*h)(ec);
+ close(ec);
+ }
+
+}
+
diff --git a/src/libtorrent/src/socks5_stream.cpp b/src/libtorrent/src/socks5_stream.cpp
new file mode 100644
index 0000000..f0c41c0
--- /dev/null
+++ b/src/libtorrent/src/socks5_stream.cpp
@@ -0,0 +1,333 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/socks5_stream.hpp"
+#include "libtorrent/assert.hpp"
+
+namespace libtorrent
+{
+
+ void socks5_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
+ , boost::shared_ptr<handler_type> h)
+ {
+ if (e || i == tcp::resolver::iterator())
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ m_sock.async_connect(i->endpoint(), boost::bind(
+ &socks5_stream::connected, this, _1, h));
+ }
+
+ void socks5_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ using namespace libtorrent::detail;
+ // send SOCKS5 authentication methods
+ m_buffer.resize(m_user.empty()?3:4);
+ char* p = &m_buffer[0];
+ write_uint8(5, p); // SOCKS VERSION 5
+ if (m_user.empty())
+ {
+ write_uint8(1, p); // 1 authentication method (no auth)
+ write_uint8(0, p); // no authentication
+ }
+ else
+ {
+ write_uint8(2, p); // 2 authentication methods
+ write_uint8(0, p); // no authentication
+ write_uint8(2, p); // username/password
+ }
+ asio::async_write(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks5_stream::handshake1, this, _1, h));
+ }
+
+ void socks5_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ m_buffer.resize(2);
+ asio::async_read(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks5_stream::handshake2, this, _1, h));
+ }
+
+ void socks5_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ using namespace libtorrent::detail;
+
+ char* p = &m_buffer[0];
+ int version = read_uint8(p);
+ int method = read_uint8(p);
+
+ if (version < 5)
+ {
+ (*h)(asio::error::operation_not_supported);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ if (method == 0)
+ {
+ socks_connect(h);
+ }
+ else if (method == 2)
+ {
+ if (m_user.empty())
+ {
+ (*h)(asio::error::operation_not_supported);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ // start sub-negotiation
+ m_buffer.resize(m_user.size() + m_password.size() + 3);
+ char* p = &m_buffer[0];
+ write_uint8(1, p);
+ write_uint8(m_user.size(), p);
+ write_string(m_user, p);
+ write_uint8(m_password.size(), p);
+ write_string(m_password, p);
+ asio::async_write(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks5_stream::handshake3, this, _1, h));
+ }
+ else
+ {
+ (*h)(asio::error::operation_not_supported);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+ }
+
+ void socks5_stream::handshake3(asio::error_code const& e
+ , boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ m_buffer.resize(2);
+ asio::async_read(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks5_stream::handshake4, this, _1, h));
+ }
+
+ void socks5_stream::handshake4(asio::error_code const& e
+ , boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ using namespace libtorrent::detail;
+
+ char* p = &m_buffer[0];
+ int version = read_uint8(p);
+ int status = read_uint8(p);
+
+ if (version != 1)
+ {
+ (*h)(asio::error::operation_not_supported);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ if (status != 0)
+ {
+ (*h)(asio::error::operation_not_supported);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ std::vector<char>().swap(m_buffer);
+ socks_connect(h);
+ }
+
+ void socks5_stream::socks_connect(boost::shared_ptr<handler_type> h)
+ {
+ using namespace libtorrent::detail;
+
+ // send SOCKS5 connect command
+ m_buffer.resize(6 + (m_remote_endpoint.address().is_v4()?4:16));
+ char* p = &m_buffer[0];
+ write_uint8(5, p); // SOCKS VERSION 5
+ write_uint8(1, p); // CONNECT command
+ write_uint8(0, p); // reserved
+ write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
+ write_address(m_remote_endpoint.address(), p);
+ write_uint16(m_remote_endpoint.port(), p);
+ TORRENT_ASSERT(p - &m_buffer[0] == int(m_buffer.size()));
+
+ asio::async_write(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks5_stream::connect1, this, _1, h));
+ }
+
+ void socks5_stream::connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ m_buffer.resize(6 + 4); // assume an IPv4 address
+ asio::async_read(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks5_stream::connect2, this, _1, h));
+ }
+
+ void socks5_stream::connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ using namespace libtorrent::detail;
+
+ // send SOCKS5 connect command
+ char* p = &m_buffer[0];
+ int version = read_uint8(p);
+ if (version < 5)
+ {
+ (*h)(asio::error::operation_not_supported);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+ int response = read_uint8(p);
+ if (response != 0)
+ {
+ asio::error_code e = asio::error::fault;
+ switch (response)
+ {
+ case 1: e = asio::error::fault; break;
+ case 2: e = asio::error::no_permission; break;
+ case 3: e = asio::error::network_unreachable; break;
+ case 4: e = asio::error::host_unreachable; break;
+ case 5: e = asio::error::connection_refused; break;
+ case 6: e = asio::error::timed_out; break;
+ case 7: e = asio::error::operation_not_supported; break;
+ case 8: e = asio::error::address_family_not_supported; break;
+ }
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+ p += 1; // reserved
+ int atyp = read_uint8(p);
+ // we ignore the proxy IP it was bound to
+ if (atyp == 1)
+ {
+ std::vector<char>().swap(m_buffer);
+ (*h)(e);
+ return;
+ }
+ int skip_bytes = 0;
+ if (atyp == 4)
+ {
+ skip_bytes = 12;
+ }
+ else if (atyp == 3)
+ {
+ skip_bytes = read_uint8(p) - 3;
+ }
+ else
+ {
+ (*h)(asio::error::operation_not_supported);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+ m_buffer.resize(skip_bytes);
+
+ asio::async_read(m_sock, asio::buffer(m_buffer)
+ , boost::bind(&socks5_stream::connect3, this, _1, h));
+ }
+
+ void socks5_stream::connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h)
+ {
+ if (e)
+ {
+ (*h)(e);
+ asio::error_code ec;
+ close(ec);
+ return;
+ }
+
+ std::vector<char>().swap(m_buffer);
+ (*h)(e);
+ }
+}
+
diff --git a/src/libtorrent/src/stat.cpp b/src/libtorrent/src/stat.cpp
new file mode 100644
index 0000000..d695edc
--- /dev/null
+++ b/src/libtorrent/src/stat.cpp
@@ -0,0 +1,93 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+// TODO: Use two algorithms to estimate transfer rate.
+// one (simple) for transfer rates that are >= 1 packet
+// per second and one (low pass-filter) for rates < 1
+// packet per second.
+
+#include "libtorrent/pch.hpp"
+
+#include <numeric>
+#include <algorithm>
+
+#include "libtorrent/stat.hpp"
+#include "libtorrent/invariant_check.hpp"
+
+#if defined _MSC_VER && _MSC_VER <= 1200
+#define for if (false) {} else for
+#endif
+
+using namespace libtorrent;
+
+void libtorrent::stat::second_tick(float tick_interval)
+{
+ INVARIANT_CHECK;
+
+ for (int i = history - 2; i >= 0; --i)
+ {
+ m_download_rate_history[i + 1] = m_download_rate_history[i];
+ m_upload_rate_history[i + 1] = m_upload_rate_history[i];
+ m_download_payload_rate_history[i + 1] = m_download_payload_rate_history[i];
+ m_upload_payload_rate_history[i + 1] = m_upload_payload_rate_history[i];
+ }
+
+ m_download_rate_history[0] = (m_downloaded_payload + m_downloaded_protocol)
+ / tick_interval;
+ m_upload_rate_history[0] = (m_uploaded_payload + m_uploaded_protocol)
+ / tick_interval;
+ m_download_payload_rate_history[0] = m_downloaded_payload / tick_interval;
+ m_upload_payload_rate_history[0] = m_uploaded_payload / tick_interval;
+
+ m_downloaded_payload = 0;
+ m_uploaded_payload = 0;
+ m_downloaded_protocol = 0;
+ m_uploaded_protocol = 0;
+
+ m_mean_download_rate = 0;
+ m_mean_upload_rate = 0;
+ m_mean_download_payload_rate = 0;
+ m_mean_upload_payload_rate = 0;
+
+ for (int i = 0; i < history; ++i)
+ {
+ m_mean_download_rate += m_download_rate_history[i];
+ m_mean_upload_rate += m_upload_rate_history[i];
+ m_mean_download_payload_rate += m_download_payload_rate_history[i];
+ m_mean_upload_payload_rate += m_upload_payload_rate_history[i];
+ }
+
+ m_mean_download_rate /= history;
+ m_mean_upload_rate /= history;
+ m_mean_download_payload_rate /= history;
+ m_mean_upload_payload_rate /= history;
+}
diff --git a/src/libtorrent/src/storage.cpp b/src/libtorrent/src/storage.cpp
new file mode 100644
index 0000000..062902a
--- /dev/null
+++ b/src/libtorrent/src/storage.cpp
@@ -0,0 +1,2330 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg, Daniel Wallin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <ctime>
+#include <iterator>
+#include <algorithm>
+#include <set>
+#include <functional>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/ref.hpp>
+#include <boost/bind.hpp>
+#include <boost/version.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/storage.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/file.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/file_pool.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+
+#ifndef NDEBUG
+#include <ios>
+#include <iostream>
+#include <iomanip>
+#include <cstdio>
+#endif
+
+#if defined(__APPLE__)
+// for getattrlist()
+#include <sys/attr.h>
+#include <unistd.h>
+// for statfs()
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#if defined(__linux__)
+#include <sys/statfs.h>
+#endif
+
+#if defined(__FreeBSD__)
+// for statfs()
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#if defined(_WIN32) && defined(UNICODE)
+
+#include <windows.h>
+#include <boost/filesystem/exception.hpp>
+#include "libtorrent/utf8.hpp"
+#include "libtorrent/buffer.hpp"
+
+namespace libtorrent
+{
+ std::wstring safe_convert(std::string const& s)
+ {
+ try
+ {
+ return libtorrent::utf8_wchar(s);
+ }
+ catch (std::exception)
+ {
+ std::wstring ret;
+ const char* end = &s[0] + s.size();
+ for (const char* i = &s[0]; i < end;)
+ {
+ wchar_t c = '.';
+ int result = std::mbtowc(&c, i, end - i);
+ if (result > 0) i += result;
+ else ++i;
+ ret += c;
+ }
+ return ret;
+ }
+ }
+}
+#endif
+
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+namespace
+{
+ using libtorrent::safe_convert;
+ using namespace boost::filesystem;
+
+ // based on code from Boost.Fileystem
+ bool create_directories_win(const fs::path& ph)
+ {
+ if (ph.empty() || exists(ph))
+ {
+ if ( !ph.empty() && !is_directory(ph) )
+ boost::throw_exception( filesystem_error(
+ "boost::filesystem::create_directories",
+ ph, "path exists and is not a directory",
+ not_directory_error ) );
+ return false;
+ }
+
+ // First create branch, by calling ourself recursively
+ create_directories_win(ph.branch_path());
+ // Now that parent's path exists, create the directory
+ std::wstring wph(safe_convert(ph.native_directory_string()));
+ CreateDirectory(wph.c_str(), 0);
+ return true;
+ }
+
+ bool exists_win( const fs::path & ph )
+ {
+ std::wstring wpath(safe_convert(ph.string()));
+ if(::GetFileAttributes( wpath.c_str() ) == 0xFFFFFFFF)
+ {
+ UINT err = ::GetLastError();
+ if((err == ERROR_FILE_NOT_FOUND)
+ || (err == ERROR_INVALID_PARAMETER)
+ || (err == ERROR_NOT_READY)
+ || (err == ERROR_PATH_NOT_FOUND)
+ || (err == ERROR_INVALID_NAME)
+ || (err == ERROR_BAD_NETPATH ))
+ return false; // GetFileAttributes failed because the path does not exist
+ // for any other error we assume the file does exist and fall through,
+ // this may not be the best policy though... (JM 20040330)
+ return true;
+ }
+ return true;
+ }
+
+ boost::intmax_t file_size_win( const fs::path & ph )
+ {
+ std::wstring wpath(safe_convert(ph.string()));
+ // by now, intmax_t is 64-bits on all Windows compilers
+ WIN32_FILE_ATTRIBUTE_DATA fad;
+ if ( !::GetFileAttributesExW( wpath.c_str(),
+ ::GetFileExInfoStandard, &fad ) )
+ boost::throw_exception( filesystem_error(
+ "boost::filesystem::file_size",
+ ph, detail::system_error_code() ) );
+ if ( (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=0 )
+ boost::throw_exception( filesystem_error(
+ "boost::filesystem::file_size",
+ ph, "invalid: is a directory",
+ is_directory_error ) );
+ return (static_cast<boost::intmax_t>(fad.nFileSizeHigh)
+ << (sizeof(fad.nFileSizeLow)*8))
+ + fad.nFileSizeLow;
+ }
+
+ std::time_t last_write_time_win( const fs::path & ph )
+ {
+ struct _stat path_stat;
+ std::wstring wph(safe_convert(ph.native_file_string()));
+ if ( ::_wstat( wph.c_str(), &path_stat ) != 0 )
+ boost::throw_exception( filesystem_error(
+ "boost::filesystem::last_write_time",
+ ph, detail::system_error_code() ) );
+ return path_stat.st_mtime;
+ }
+
+ void rename_win( const fs::path & old_path,
+ const fs::path & new_path )
+ {
+ std::wstring wold_path(safe_convert(old_path.string()));
+ std::wstring wnew_path(safe_convert(new_path.string()));
+ if ( !::MoveFile( wold_path.c_str(), wnew_path.c_str() ) )
+ boost::throw_exception( filesystem_error(
+ "boost::filesystem::rename",
+ old_path, new_path, detail::system_error_code() ) );
+ }
+
+} // anonymous namespace
+
+#endif
+
+#if BOOST_VERSION < 103200
+bool operator<(fs::path const& lhs, fs::path const& rhs)
+{
+ return lhs.string() < rhs.string();
+}
+#endif
+
+namespace fs = boost::filesystem;
+using boost::bind;
+using namespace ::boost::multi_index;
+using boost::multi_index::multi_index_container;
+
+#if !defined(NDEBUG) && defined(TORRENT_STORAGE_DEBUG)
+namespace
+{
+ using namespace libtorrent;
+
+ void print_to_log(const std::string& s)
+ {
+ static std::ofstream log("log.txt");
+ log << s;
+ log.flush();
+ }
+}
+#endif
+
+namespace libtorrent
+{
+
+ std::vector<std::pair<size_type, std::time_t> > get_filesizes(
+ torrent_info const& t, fs::path p)
+ {
+ p = complete(p);
+ std::vector<std::pair<size_type, std::time_t> > sizes;
+ for (torrent_info::file_iterator i = t.begin_files(true);
+ i != t.end_files(true); ++i)
+ {
+ size_type size = 0;
+ std::time_t time = 0;
+ try
+ {
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ fs::path f = p / i->path;
+ size = file_size_win(f);
+ time = last_write_time_win(f);
+#elif defined(_WIN32) && defined(UNICODE)
+ fs::wpath f = safe_convert((p / i->path).string());
+ size = file_size(f);
+ time = last_write_time(f);
+#else
+ fs::path f = p / i->path;
+ size = file_size(f);
+ time = last_write_time(f);
+#endif
+ }
+ catch (std::exception&) {}
+ sizes.push_back(std::make_pair(size, time));
+ }
+ return sizes;
+ }
+
+ // matches the sizes and timestamps of the files passed in
+ // in non-compact mode, actual file sizes and timestamps
+ // are allowed to be bigger and more recent than the fast
+ // resume data. This is because full allocation will not move
+ // pieces, so any older version of the resume data will
+ // still be a correct subset of the actual data on disk.
+ bool match_filesizes(
+ torrent_info const& t
+ , fs::path p
+ , std::vector<std::pair<size_type, std::time_t> > const& sizes
+ , bool compact_mode
+ , std::string* error)
+ {
+ if ((int)sizes.size() != t.num_files(true))
+ {
+ if (error) *error = "mismatching number of files";
+ return false;
+ }
+ p = complete(p);
+
+ std::vector<std::pair<size_type, std::time_t> >::const_iterator s
+ = sizes.begin();
+ for (torrent_info::file_iterator i = t.begin_files(true);
+ i != t.end_files(true); ++i, ++s)
+ {
+ size_type size = 0;
+ std::time_t time = 0;
+ try
+ {
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ fs::path f = p / i->path;
+ size = file_size_win(f);
+ time = last_write_time_win(f);
+#elif defined(_WIN32) && defined(UNICODE)
+ fs::wpath f = safe_convert((p / i->path).string());
+ size = file_size(f);
+ time = last_write_time(f);
+#else
+ fs::path f = p / i->path;
+ size = file_size(f);
+ time = last_write_time(f);
+#endif
+ }
+ catch (std::exception&) {}
+ if ((compact_mode && size != s->first)
+ || (!compact_mode && size < s->first))
+ {
+ if (error) *error = "filesize mismatch for file '"
+ + i->path.native_file_string()
+ + "', size: " + boost::lexical_cast<std::string>(size)
+ + ", expected to be " + boost::lexical_cast<std::string>(s->first)
+ + " bytes";
+ return false;
+ }
+ if ((compact_mode && time != s->second)
+ || (!compact_mode && time < s->second))
+ {
+ if (error) *error = "timestamp mismatch for file '"
+ + i->path.native_file_string()
+ + "', modification date: " + boost::lexical_cast<std::string>(time)
+ + ", expected to have modification date "
+ + boost::lexical_cast<std::string>(s->second);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ class storage : public storage_interface, boost::noncopyable
+ {
+ public:
+ storage(boost::intrusive_ptr<torrent_info const> info, fs::path const& path, file_pool& fp)
+ : m_info(info)
+ , m_files(fp)
+ {
+ TORRENT_ASSERT(info->begin_files(true) != info->end_files(true));
+ m_save_path = fs::complete(path);
+ TORRENT_ASSERT(m_save_path.is_complete());
+ }
+
+ void release_files();
+ void delete_files();
+ void initialize(bool allocate_files);
+ bool move_storage(fs::path save_path);
+ size_type read(char* buf, int slot, int offset, int size);
+ void write(const char* buf, int slot, int offset, int size);
+ void move_slot(int src_slot, int dst_slot);
+ void swap_slots(int slot1, int slot2);
+ void swap_slots3(int slot1, int slot2, int slot3);
+ bool verify_resume_data(entry& rd, std::string& error);
+ void write_resume_data(entry& rd) const;
+ sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size);
+
+ size_type read_impl(char* buf, int slot, int offset, int size, bool fill_zero);
+
+ ~storage()
+ { m_files.release(this); }
+
+ boost::intrusive_ptr<torrent_info const> m_info;
+ fs::path m_save_path;
+ // the file pool is typically stored in
+ // the session, to make all storage
+ // instances use the same pool
+ file_pool& m_files;
+
+ // temporary storage for moving pieces
+ buffer m_scratch_buffer;
+ };
+
+ sha1_hash storage::hash_for_slot(int slot, partial_hash& ph, int piece_size)
+ {
+#ifndef NDEBUG
+ hasher partial;
+ hasher whole;
+ int slot_size1 = piece_size;
+ m_scratch_buffer.resize(slot_size1);
+ read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true);
+ if (ph.offset > 0)
+ partial.update(&m_scratch_buffer[0], ph.offset);
+ whole.update(&m_scratch_buffer[0], slot_size1);
+ hasher partial_copy = ph.h;
+ TORRENT_ASSERT(ph.offset == 0 || partial_copy.final() == partial.final());
+#endif
+ int slot_size = piece_size - ph.offset;
+ if (slot_size > 0)
+ {
+ m_scratch_buffer.resize(slot_size);
+ read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true);
+ ph.h.update(&m_scratch_buffer[0], slot_size);
+ }
+#ifndef NDEBUG
+ sha1_hash ret = ph.h.final();
+ TORRENT_ASSERT(ret == whole.final());
+ return ret;
+#else
+ return ph.h.final();
+#endif
+ }
+
+ void storage::initialize(bool allocate_files)
+ {
+ // first, create all missing directories
+ fs::path last_path;
+ for (torrent_info::file_iterator file_iter = m_info->begin_files(true),
+ end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter)
+ {
+ fs::path dir = (m_save_path / file_iter->path).branch_path();
+
+ if (dir != last_path)
+ {
+
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ last_path = dir;
+ if (!exists_win(last_path))
+ create_directories_win(last_path);
+#elif defined(_WIN32) && defined(UNICODE)
+ last_path = dir;
+ fs::wpath wp = safe_convert(last_path.string());
+ if (!exists(wp))
+ create_directories(wp);
+#else
+ last_path = dir;
+ if (!exists(last_path))
+ create_directories(last_path);
+#endif
+ }
+
+ // if the file is empty, just create it. But also make sure
+ // the directory exists.
+ if (file_iter->size == 0)
+ {
+ try {
+ file(m_save_path / file_iter->path, file::out);
+ } catch (std::exception&) {}
+ continue;
+ }
+
+ try {
+ if (allocate_files)
+ {
+ m_files.open_file(this, m_save_path / file_iter->path, file::in | file::out)
+ ->set_size(file_iter->size);
+ }
+ } catch (std::exception&) {}
+ }
+ // close files that were opened in write mode
+ m_files.release(this);
+ }
+
+ void storage::release_files()
+ {
+ m_files.release(this);
+ buffer().swap(m_scratch_buffer);
+ }
+
+ void storage::delete_files()
+ {
+ // make sure we don't have the files open
+ m_files.release(this);
+ buffer().swap(m_scratch_buffer);
+
+ std::string error;
+
+ // delete the files from disk
+ std::set<std::string> directories;
+ typedef std::set<std::string>::iterator iter_t;
+ for (torrent_info::file_iterator i = m_info->begin_files(true)
+ , end(m_info->end_files(true)); i != end; ++i)
+ {
+ std::string p = (m_save_path / i->path).string();
+ fs::path bp = i->path.branch_path();
+ std::pair<iter_t, bool> ret;
+ ret.second = true;
+ while (ret.second && !bp.empty())
+ {
+ std::pair<iter_t, bool> ret = directories.insert((m_save_path / bp).string());
+ bp = bp.branch_path();
+ }
+ if (std::remove(p.c_str()) != 0 && errno != ENOENT)
+ error = std::strerror(errno);
+ }
+
+ // remove the directories. Reverse order to delete
+ // subdirectories first
+
+ for (std::set<std::string>::reverse_iterator i = directories.rbegin()
+ , end(directories.rend()); i != end; ++i)
+ {
+ if (std::remove(i->c_str()) != 0 && errno != ENOENT)
+ error = std::strerror(errno);
+ }
+
+ if (!error.empty()) throw std::runtime_error(error);
+ }
+
+ void storage::write_resume_data(entry& rd) const
+ {
+ std::vector<std::pair<size_type, std::time_t> > file_sizes
+ = get_filesizes(*m_info, m_save_path);
+
+ rd["file sizes"] = entry::list_type();
+ entry::list_type& fl = rd["file sizes"].list();
+ for (std::vector<std::pair<size_type, std::time_t> >::iterator i
+ = file_sizes.begin(), end(file_sizes.end()); i != end; ++i)
+ {
+ entry::list_type p;
+ p.push_back(entry(i->first));
+ p.push_back(entry(i->second));
+ fl.push_back(entry(p));
+ }
+ }
+
+ bool storage::verify_resume_data(entry& rd, std::string& error)
+ {
+ std::vector<std::pair<size_type, std::time_t> > file_sizes;
+ entry::list_type& l = rd["file sizes"].list();
+
+ for (entry::list_type::iterator i = l.begin();
+ i != l.end(); ++i)
+ {
+ file_sizes.push_back(std::make_pair(
+ i->list().front().integer()
+ , std::time_t(i->list().back().integer())));
+ }
+
+ if (file_sizes.empty())
+ {
+ error = "the number of files in resume data is 0";
+ return false;
+ }
+
+ entry::list_type& slots = rd["slots"].list();
+ bool seed = int(slots.size()) == m_info->num_pieces()
+ && std::find_if(slots.begin(), slots.end()
+ , boost::bind<bool>(std::less<int>()
+ , boost::bind((size_type const& (entry::*)() const)
+ &entry::integer, _1), 0)) == slots.end();
+
+ bool full_allocation_mode = false;
+ try
+ {
+ full_allocation_mode = rd["allocation"].string() == "full";
+ }
+ catch (std::exception&) {}
+
+ if (seed)
+ {
+ if (m_info->num_files(true) != (int)file_sizes.size())
+ {
+ error = "the number of files does not match the torrent (num: "
+ + boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
+ + boost::lexical_cast<std::string>(m_info->num_files(true)) + ")";
+ return false;
+ }
+
+ std::vector<std::pair<size_type, std::time_t> >::iterator
+ fs = file_sizes.begin();
+ // the resume data says we have the entire torrent
+ // make sure the file sizes are the right ones
+ for (torrent_info::file_iterator i = m_info->begin_files(true)
+ , end(m_info->end_files(true)); i != end; ++i, ++fs)
+ {
+ if (i->size != fs->first)
+ {
+ error = "file size for '" + i->path.native_file_string()
+ + "' was expected to be "
+ + boost::lexical_cast<std::string>(i->size) + " bytes";
+ return false;
+ }
+ }
+ }
+
+ return match_filesizes(*m_info, m_save_path, file_sizes
+ , !full_allocation_mode, &error);
+ }
+
+ // returns true on success
+ bool storage::move_storage(fs::path save_path)
+ {
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
+ fs::wpath old_path;
+ fs::wpath new_path;
+#else
+ fs::path old_path;
+ fs::path new_path;
+#endif
+
+ save_path = complete(save_path);
+
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ std::wstring wsave_path(safe_convert(save_path.native_file_string()));
+ if (!exists_win(save_path))
+ CreateDirectory(wsave_path.c_str(), 0);
+ else if ((GetFileAttributes(wsave_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY) == 0)
+ return false;
+#elif defined(_WIN32) && defined(UNICODE)
+ fs::wpath wp = safe_convert(save_path.string());
+ if (!exists(wp))
+ create_directory(wp);
+ else if (!is_directory(wp))
+ return false;
+#else
+ if (!exists(save_path))
+ create_directory(save_path);
+ else if (!is_directory(save_path))
+ return false;
+#endif
+
+ m_files.release(this);
+
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
+ old_path = safe_convert((m_save_path / m_info->name()).string());
+ new_path = safe_convert((save_path / m_info->name()).string());
+#else
+ old_path = m_save_path / m_info->name();
+ new_path = save_path / m_info->name();
+#endif
+
+ try
+ {
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ rename_win(old_path, new_path);
+ rename(old_path, new_path);
+#else
+ rename(old_path, new_path);
+#endif
+ m_save_path = save_path;
+ return true;
+ }
+ catch (std::exception&) {}
+ return false;
+ }
+
+#ifndef NDEBUG
+/*
+ void storage::shuffle()
+ {
+ int num_pieces = m_info->num_pieces();
+
+ std::vector<int> pieces(num_pieces);
+ for (std::vector<int>::iterator i = pieces.begin();
+ i != pieces.end(); ++i)
+ {
+ *i = static_cast<int>(i - pieces.begin());
+ }
+ std::srand((unsigned int)std::time(0));
+ std::vector<int> targets(pieces);
+ std::random_shuffle(pieces.begin(), pieces.end());
+ std::random_shuffle(targets.begin(), targets.end());
+
+ for (int i = 0; i < (std::max)(num_pieces / 50, 1); ++i)
+ {
+ const int slot_index = targets[i];
+ const int piece_index = pieces[i];
+ const int slot_size =static_cast<int>(m_info->piece_size(slot_index));
+ std::vector<char> buf(slot_size);
+ read(&buf[0], piece_index, 0, slot_size);
+ write(&buf[0], slot_index, 0, slot_size);
+ }
+ }
+*/
+#endif
+
+ void storage::move_slot(int src_slot, int dst_slot)
+ {
+ int piece_size = m_info->piece_size(dst_slot);
+ m_scratch_buffer.resize(piece_size);
+ read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true);
+ write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
+ }
+
+ void storage::swap_slots(int slot1, int slot2)
+ {
+ // the size of the target slot is the size of the piece
+ int piece_size = m_info->piece_length();
+ int piece1_size = m_info->piece_size(slot2);
+ int piece2_size = m_info->piece_size(slot1);
+ m_scratch_buffer.resize(piece_size * 2);
+ read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
+ read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
+ write(&m_scratch_buffer[0], slot2, 0, piece1_size);
+ write(&m_scratch_buffer[piece_size], slot1, 0, piece2_size);
+ }
+
+ void storage::swap_slots3(int slot1, int slot2, int slot3)
+ {
+ // the size of the target slot is the size of the piece
+ int piece_size = m_info->piece_length();
+ int piece1_size = m_info->piece_size(slot2);
+ int piece2_size = m_info->piece_size(slot3);
+ int piece3_size = m_info->piece_size(slot1);
+ m_scratch_buffer.resize(piece_size * 2);
+ read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
+ read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
+ write(&m_scratch_buffer[0], slot2, 0, piece1_size);
+ read_impl(&m_scratch_buffer[0], slot3, 0, piece3_size, true);
+ write(&m_scratch_buffer[piece_size], slot3, 0, piece2_size);
+ write(&m_scratch_buffer[0], slot1, 0, piece3_size);
+ }
+
+ size_type storage::read(
+ char* buf
+ , int slot
+ , int offset
+ , int size)
+ {
+ return read_impl(buf, slot, offset, size, false);
+ }
+
+ size_type storage::read_impl(
+ char* buf
+ , int slot
+ , int offset
+ , int size
+ , bool fill_zero)
+ {
+ TORRENT_ASSERT(buf != 0);
+ TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
+ TORRENT_ASSERT(offset >= 0);
+ TORRENT_ASSERT(offset < m_info->piece_size(slot));
+ TORRENT_ASSERT(size > 0);
+
+#ifndef NDEBUG
+ std::vector<file_slice> slices
+ = m_info->map_block(slot, offset, size, true);
+ TORRENT_ASSERT(!slices.empty());
+#endif
+
+ size_type start = slot * (size_type)m_info->piece_length() + offset;
+ TORRENT_ASSERT(start + size <= m_info->total_size());
+
+ // find the file iterator and file offset
+ size_type file_offset = start;
+ std::vector<file_entry>::const_iterator file_iter;
+
+ for (file_iter = m_info->begin_files(true);;)
+ {
+ if (file_offset < file_iter->size)
+ break;
+
+ file_offset -= file_iter->size;
+ ++file_iter;
+ }
+
+ int buf_pos = 0;
+ boost::shared_ptr<file> in(m_files.open_file(
+ this, m_save_path / file_iter->path, file::in));
+
+ TORRENT_ASSERT(file_offset < file_iter->size);
+
+ TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
+
+ size_type new_pos = in->seek(file_offset + file_iter->file_base);
+ if (new_pos != file_offset + file_iter->file_base)
+ {
+ // the file was not big enough
+ if (!fill_zero)
+ throw file_error("slot has no storage");
+ std::memset(buf + buf_pos, 0, size - buf_pos);
+ return size;
+ }
+
+#ifndef NDEBUG
+ size_type in_tell = in->tell();
+ TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base);
+#endif
+
+ int left_to_read = size;
+ int slot_size = static_cast<int>(m_info->piece_size(slot));
+
+ if (offset + left_to_read > slot_size)
+ left_to_read = slot_size - offset;
+
+ TORRENT_ASSERT(left_to_read >= 0);
+
+ size_type result = left_to_read;
+
+#ifndef NDEBUG
+ int counter = 0;
+#endif
+
+ while (left_to_read > 0)
+ {
+ int read_bytes = left_to_read;
+ if (file_offset + read_bytes > file_iter->size)
+ read_bytes = static_cast<int>(file_iter->size - file_offset);
+
+ if (read_bytes > 0)
+ {
+#ifndef NDEBUG
+ TORRENT_ASSERT(int(slices.size()) > counter);
+ size_type slice_size = slices[counter].size;
+ TORRENT_ASSERT(slice_size == read_bytes);
+ TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
+ == file_iter->path);
+#endif
+
+ int actual_read = int(in->read(buf + buf_pos, read_bytes));
+
+ if (read_bytes != actual_read)
+ {
+ // the file was not big enough
+ if (actual_read > 0) buf_pos += actual_read;
+ if (!fill_zero)
+ throw file_error("slot has no storage");
+ std::memset(buf + buf_pos, 0, size - buf_pos);
+ return size;
+ }
+
+ left_to_read -= read_bytes;
+ buf_pos += read_bytes;
+ TORRENT_ASSERT(buf_pos >= 0);
+ file_offset += read_bytes;
+ }
+
+ if (left_to_read > 0)
+ {
+ ++file_iter;
+#ifndef NDEBUG
+ // empty files are not returned by map_block, so if
+ // this file was empty, don't increment the slice counter
+ if (read_bytes > 0) ++counter;
+#endif
+ fs::path path = m_save_path / file_iter->path;
+
+ file_offset = 0;
+ in = m_files.open_file(
+ this, path, file::in);
+ in->seek(file_iter->file_base);
+ }
+ }
+ return result;
+ }
+
+ // throws file_error if it fails to write
+ void storage::write(
+ const char* buf
+ , int slot
+ , int offset
+ , int size)
+ {
+ TORRENT_ASSERT(buf != 0);
+ TORRENT_ASSERT(slot >= 0);
+ TORRENT_ASSERT(slot < m_info->num_pieces());
+ TORRENT_ASSERT(offset >= 0);
+ TORRENT_ASSERT(size > 0);
+
+#ifndef NDEBUG
+ std::vector<file_slice> slices
+ = m_info->map_block(slot, offset, size, true);
+ TORRENT_ASSERT(!slices.empty());
+#endif
+
+ size_type start = slot * (size_type)m_info->piece_length() + offset;
+
+ // find the file iterator and file offset
+ size_type file_offset = start;
+ std::vector<file_entry>::const_iterator file_iter;
+
+ for (file_iter = m_info->begin_files(true);;)
+ {
+ if (file_offset < file_iter->size)
+ break;
+
+ file_offset -= file_iter->size;
+ ++file_iter;
+ TORRENT_ASSERT(file_iter != m_info->end_files(true));
+ }
+
+ fs::path p(m_save_path / file_iter->path);
+ boost::shared_ptr<file> out = m_files.open_file(
+ this, p, file::out | file::in);
+
+ TORRENT_ASSERT(file_offset < file_iter->size);
+ TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
+
+ size_type pos = out->seek(file_offset + file_iter->file_base);
+
+ if (pos != file_offset + file_iter->file_base)
+ {
+ std::stringstream s;
+ s << "no storage for slot " << slot;
+ throw file_error(s.str());
+ }
+
+ int left_to_write = size;
+ int slot_size = static_cast<int>(m_info->piece_size(slot));
+
+ if (offset + left_to_write > slot_size)
+ left_to_write = slot_size - offset;
+
+ TORRENT_ASSERT(left_to_write >= 0);
+
+ int buf_pos = 0;
+#ifndef NDEBUG
+ int counter = 0;
+#endif
+ while (left_to_write > 0)
+ {
+ int write_bytes = left_to_write;
+ if (file_offset + write_bytes > file_iter->size)
+ {
+ TORRENT_ASSERT(file_iter->size >= file_offset);
+ write_bytes = static_cast<int>(file_iter->size - file_offset);
+ }
+
+ if (write_bytes > 0)
+ {
+ TORRENT_ASSERT(int(slices.size()) > counter);
+ TORRENT_ASSERT(slices[counter].size == write_bytes);
+ TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
+ == file_iter->path);
+
+ TORRENT_ASSERT(buf_pos >= 0);
+ TORRENT_ASSERT(write_bytes >= 0);
+ size_type written = out->write(buf + buf_pos, write_bytes);
+
+ if (written != write_bytes)
+ {
+ std::stringstream s;
+ s << "no storage for slot " << slot;
+ throw file_error(s.str());
+ }
+
+ left_to_write -= write_bytes;
+ buf_pos += write_bytes;
+ TORRENT_ASSERT(buf_pos >= 0);
+ file_offset += write_bytes;
+ TORRENT_ASSERT(file_offset <= file_iter->size);
+ }
+
+ if (left_to_write > 0)
+ {
+#ifndef NDEBUG
+ if (write_bytes > 0) ++counter;
+#endif
+ ++file_iter;
+
+ TORRENT_ASSERT(file_iter != m_info->end_files(true));
+ fs::path p = m_save_path / file_iter->path;
+ file_offset = 0;
+ out = m_files.open_file(
+ this, p, file::out | file::in);
+
+ out->seek(file_iter->file_base);
+ }
+ }
+ }
+
+ storage_interface* default_storage_constructor(boost::intrusive_ptr<torrent_info const> ti
+ , fs::path const& path, file_pool& fp)
+ {
+ return new storage(ti, path, fp);
+ }
+
+ // -- piece_manager -----------------------------------------------------
+
+ piece_manager::piece_manager(
+ boost::shared_ptr<void> const& torrent
+ , boost::intrusive_ptr<torrent_info const> ti
+ , fs::path const& save_path
+ , file_pool& fp
+ , disk_io_thread& io
+ , storage_constructor_type sc)
+ : m_storage(sc(ti, save_path, fp))
+ , m_storage_mode(storage_mode_sparse)
+ , m_info(ti)
+ , m_save_path(complete(save_path))
+ , m_state(state_none)
+ , m_current_slot(0)
+ , m_out_of_place(false)
+ , m_scratch_piece(-1)
+ , m_storage_constructor(sc)
+ , m_io_thread(io)
+ , m_torrent(torrent)
+ {
+#ifndef NDEBUG
+ m_resume_data_verified = false;
+#endif
+ }
+
+ piece_manager::~piece_manager()
+ {
+ }
+
+ void piece_manager::write_resume_data(entry& rd) const
+ {
+ m_storage->write_resume_data(rd);
+ }
+
+ bool piece_manager::verify_resume_data(entry& rd, std::string& error)
+ {
+#ifndef NDEBUG
+ m_resume_data_verified = true;
+#endif
+ return m_storage->verify_resume_data(rd, error);
+ }
+
+ void piece_manager::free_buffer(char* buf)
+ {
+ m_io_thread.free_buffer(buf);
+ }
+
+ void piece_manager::async_release_files(
+ boost::function<void(int, disk_io_job const&)> const& handler)
+ {
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::release_files;
+ m_io_thread.add_job(j, handler);
+ }
+
+ void piece_manager::async_delete_files(
+ boost::function<void(int, disk_io_job const&)> const& handler)
+ {
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::delete_files;
+ m_io_thread.add_job(j, handler);
+ }
+
+ void piece_manager::async_move_storage(fs::path const& p
+ , boost::function<void(int, disk_io_job const&)> const& handler)
+ {
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::move_storage;
+ j.str = p.string();
+ m_io_thread.add_job(j, handler);
+ }
+
+ void piece_manager::async_read(
+ peer_request const& r
+ , boost::function<void(int, disk_io_job const&)> const& handler
+ , char* buffer
+ , int priority)
+ {
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::read;
+ j.piece = r.piece;
+ j.offset = r.start;
+ j.buffer_size = r.length;
+ j.buffer = buffer;
+ j.priority = priority;
+ // if a buffer is not specified, only one block can be read
+ // since that is the size of the pool allocator's buffers
+ TORRENT_ASSERT(r.length <= 16 * 1024 || buffer != 0);
+ m_io_thread.add_job(j, handler);
+ }
+
+ void piece_manager::async_write(
+ peer_request const& r
+ , char const* buffer
+ , boost::function<void(int, disk_io_job const&)> const& handler)
+ {
+ TORRENT_ASSERT(r.length <= 16 * 1024);
+
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::write;
+ j.piece = r.piece;
+ j.offset = r.start;
+ j.buffer_size = r.length;
+ j.buffer = m_io_thread.allocate_buffer();
+ if (j.buffer == 0) throw file_error("out of memory");
+ std::memcpy(j.buffer, buffer, j.buffer_size);
+ m_io_thread.add_job(j, handler);
+ }
+
+ void piece_manager::async_hash(int piece
+ , boost::function<void(int, disk_io_job const&)> const& handler)
+ {
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::hash;
+ j.piece = piece;
+
+ m_io_thread.add_job(j, handler);
+ }
+
+ fs::path piece_manager::save_path() const
+ {
+ boost::recursive_mutex::scoped_lock l(m_mutex);
+ return m_save_path;
+ }
+
+ sha1_hash piece_manager::hash_for_piece_impl(int piece)
+ {
+ partial_hash ph;
+
+ std::map<int, partial_hash>::iterator i = m_piece_hasher.find(piece);
+ if (i != m_piece_hasher.end())
+ {
+ ph = i->second;
+ m_piece_hasher.erase(i);
+ }
+
+ int slot = slot_for(piece);
+ TORRENT_ASSERT(slot != has_no_slot);
+ return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece));
+ }
+
+ bool piece_manager::move_storage_impl(fs::path const& save_path)
+ {
+ if (m_storage->move_storage(save_path))
+ {
+ m_save_path = fs::complete(save_path);
+ return true;
+ }
+ return false;
+ }
+
+ void piece_manager::export_piece_map(
+ std::vector<int>& p, std::vector<bool> const& have) const
+ {
+ boost::recursive_mutex::scoped_lock lock(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_storage_mode == storage_mode_compact)
+ {
+ p.clear();
+ p.reserve(m_info->num_pieces());
+ std::vector<int>::const_reverse_iterator last;
+ for (last = m_slot_to_piece.rbegin();
+ last != m_slot_to_piece.rend(); ++last)
+ {
+ if (*last != unallocated) break;
+ }
+
+ for (std::vector<int>::const_iterator i =
+ m_slot_to_piece.begin();
+ i != last.base(); ++i)
+ {
+ p.push_back((*i >= 0) ? *i : unassigned);
+ }
+ }
+ else
+ {
+ p.reserve(m_info->num_pieces());
+ for (int i = 0; i < m_info->num_pieces(); ++i)
+ {
+ p.push_back(have[i] ? i : unassigned);
+ }
+ }
+ }
+
+ void piece_manager::mark_failed(int piece_index)
+ {
+ boost::recursive_mutex::scoped_lock lock(m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_storage_mode != storage_mode_compact) return;
+
+ TORRENT_ASSERT(piece_index >= 0 && piece_index < (int)m_piece_to_slot.size());
+ int slot_index = m_piece_to_slot[piece_index];
+ TORRENT_ASSERT(slot_index >= 0);
+
+ m_slot_to_piece[slot_index] = unassigned;
+ m_piece_to_slot[piece_index] = has_no_slot;
+ m_free_slots.push_back(slot_index);
+ }
+
+ unsigned long piece_manager::piece_crc(
+ int slot_index
+ , int block_size
+ , piece_picker::block_info const* bi)
+ try
+ {
+ TORRENT_ASSERT(slot_index >= 0);
+ TORRENT_ASSERT(slot_index < m_info->num_pieces());
+ TORRENT_ASSERT(block_size > 0);
+
+ adler32_crc crc;
+ std::vector<char> buf(block_size);
+ int num_blocks = static_cast<int>(m_info->piece_size(slot_index)) / block_size;
+ int last_block_size = static_cast<int>(m_info->piece_size(slot_index)) % block_size;
+ if (last_block_size == 0) last_block_size = block_size;
+
+ for (int i = 0; i < num_blocks-1; ++i)
+ {
+ if (bi[i].state != piece_picker::block_info::state_finished) continue;
+ m_storage->read(
+ &buf[0]
+ , slot_index
+ , i * block_size
+ , block_size);
+ crc.update(&buf[0], block_size);
+ }
+ if (num_blocks > 0 && bi[num_blocks - 1].state == piece_picker::block_info::state_finished)
+ {
+ m_storage->read(
+ &buf[0]
+ , slot_index
+ , block_size * (num_blocks - 1)
+ , last_block_size);
+ crc.update(&buf[0], last_block_size);
+ }
+ return crc.final();
+ }
+ catch (std::exception&)
+ {
+ return 0;
+ }
+
+ size_type piece_manager::read_impl(
+ char* buf
+ , int piece_index
+ , int offset
+ , int size)
+ {
+ TORRENT_ASSERT(buf);
+ TORRENT_ASSERT(offset >= 0);
+ TORRENT_ASSERT(size > 0);
+ int slot = slot_for(piece_index);
+ return m_storage->read(buf, slot, offset, size);
+ }
+
+ void piece_manager::write_impl(
+ const char* buf
+ , int piece_index
+ , int offset
+ , int size)
+ {
+ TORRENT_ASSERT(buf);
+ TORRENT_ASSERT(offset >= 0);
+ TORRENT_ASSERT(size > 0);
+ TORRENT_ASSERT(piece_index >= 0 && piece_index < m_info->num_pieces());
+
+ if (offset == 0)
+ {
+ partial_hash& ph = m_piece_hasher[piece_index];
+ TORRENT_ASSERT(ph.offset == 0);
+ ph.offset = size;
+ ph.h.update(buf, size);
+ }
+ else
+ {
+ std::map<int, partial_hash>::iterator i = m_piece_hasher.find(piece_index);
+ if (i != m_piece_hasher.end())
+ {
+ TORRENT_ASSERT(i->second.offset > 0);
+ TORRENT_ASSERT(offset >= i->second.offset);
+ if (offset == i->second.offset)
+ {
+ i->second.offset += size;
+ i->second.h.update(buf, size);
+ }
+ }
+ }
+
+ int slot = allocate_slot_for_piece(piece_index);
+ m_storage->write(buf, slot, offset, size);
+ }
+
+ int piece_manager::identify_data(
+ const std::vector<char>& piece_data
+ , int current_slot
+ , std::vector<bool>& have_pieces
+ , int& num_pieces
+ , const std::multimap<sha1_hash, int>& hash_to_piece
+ , boost::recursive_mutex& mutex)
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT((int)have_pieces.size() == m_info->num_pieces());
+
+ const int piece_size = static_cast<int>(m_info->piece_length());
+ const int last_piece_size = static_cast<int>(m_info->piece_size(
+ m_info->num_pieces() - 1));
+
+ TORRENT_ASSERT((int)piece_data.size() >= last_piece_size);
+
+ // calculate a small digest, with the same
+ // size as the last piece. And a large digest
+ // which has the same size as a normal piece
+ hasher small_digest;
+ small_digest.update(&piece_data[0], last_piece_size);
+ hasher large_digest(small_digest);
+ TORRENT_ASSERT(piece_size - last_piece_size >= 0);
+ if (piece_size - last_piece_size > 0)
+ {
+ large_digest.update(
+ &piece_data[last_piece_size]
+ , piece_size - last_piece_size);
+ }
+ sha1_hash large_hash = large_digest.final();
+ sha1_hash small_hash = small_digest.final();
+
+ typedef std::multimap<sha1_hash, int>::const_iterator map_iter;
+ map_iter begin1;
+ map_iter end1;
+ map_iter begin2;
+ map_iter end2;
+
+ // makes the lookups for the small digest and the large digest
+ boost::tie(begin1, end1) = hash_to_piece.equal_range(small_hash);
+ boost::tie(begin2, end2) = hash_to_piece.equal_range(large_hash);
+
+ // copy all potential piece indices into this vector
+ std::vector<int> matching_pieces;
+ for (map_iter i = begin1; i != end1; ++i)
+ matching_pieces.push_back(i->second);
+ for (map_iter i = begin2; i != end2; ++i)
+ matching_pieces.push_back(i->second);
+
+ // no piece matched the data in the slot
+ if (matching_pieces.empty())
+ return unassigned;
+
+ // ------------------------------------------
+ // CHECK IF THE PIECE IS IN ITS CORRECT PLACE
+ // ------------------------------------------
+
+ if (std::find(
+ matching_pieces.begin()
+ , matching_pieces.end()
+ , current_slot) != matching_pieces.end())
+ {
+ // the current slot is among the matching pieces, so
+ // we will assume that the piece is in the right place
+ const int piece_index = current_slot;
+
+ // lock because we're writing to have_pieces
+ boost::recursive_mutex::scoped_lock l(mutex);
+
+ if (have_pieces[piece_index])
+ {
+ // we have already found a piece with
+ // this index.
+ int other_slot = m_piece_to_slot[piece_index];
+ TORRENT_ASSERT(other_slot >= 0);
+
+ // take one of the other matching pieces
+ // that hasn't already been assigned
+ int other_piece = -1;
+ for (std::vector<int>::iterator i = matching_pieces.begin();
+ i != matching_pieces.end(); ++i)
+ {
+ if (have_pieces[*i] || *i == piece_index) continue;
+ other_piece = *i;
+ break;
+ }
+ if (other_piece >= 0)
+ {
+ // replace the old slot with 'other_piece'
+ TORRENT_ASSERT(have_pieces[other_piece] == false);
+ have_pieces[other_piece] = true;
+ m_slot_to_piece[other_slot] = other_piece;
+ m_piece_to_slot[other_piece] = other_slot;
+ ++num_pieces;
+ }
+ else
+ {
+ // this index is the only piece with this
+ // hash. The previous slot we found with
+ // this hash must be the same piece. Mark
+ // that piece as unassigned, since this slot
+ // is the correct place for the piece.
+ m_slot_to_piece[other_slot] = unassigned;
+ if (m_storage_mode == storage_mode_compact)
+ m_free_slots.push_back(other_slot);
+ }
+ TORRENT_ASSERT(m_piece_to_slot[piece_index] != current_slot);
+ TORRENT_ASSERT(m_piece_to_slot[piece_index] >= 0);
+ m_piece_to_slot[piece_index] = has_no_slot;
+#ifndef NDEBUG
+ // to make the assert happy, a few lines down
+ have_pieces[piece_index] = false;
+#endif
+ }
+ else
+ {
+ ++num_pieces;
+ }
+
+ TORRENT_ASSERT(have_pieces[piece_index] == false);
+ TORRENT_ASSERT(m_piece_to_slot[piece_index] == has_no_slot);
+ have_pieces[piece_index] = true;
+
+ return piece_index;
+ }
+
+ // find a matching piece that hasn't
+ // already been assigned
+ int free_piece = unassigned;
+ for (std::vector<int>::iterator i = matching_pieces.begin();
+ i != matching_pieces.end(); ++i)
+ {
+ if (have_pieces[*i]) continue;
+ free_piece = *i;
+ break;
+ }
+
+ if (free_piece >= 0)
+ {
+ // lock because we're writing to have_pieces
+ boost::recursive_mutex::scoped_lock l(mutex);
+
+ TORRENT_ASSERT(have_pieces[free_piece] == false);
+ TORRENT_ASSERT(m_piece_to_slot[free_piece] == has_no_slot);
+ have_pieces[free_piece] = true;
+ ++num_pieces;
+
+ return free_piece;
+ }
+ else
+ {
+ TORRENT_ASSERT(free_piece == unassigned);
+ return unassigned;
+ }
+ }
+
+ // check if the fastresume data is up to date
+ // if it is, use it and return true. If it
+ // isn't return false and the full check
+ // will be run
+ bool piece_manager::check_fastresume(
+ aux::piece_checker_data& data
+ , std::vector<bool>& pieces
+ , int& num_pieces, storage_mode_t storage_mode
+ , std::string& error_msg)
+ {
+ boost::recursive_mutex::scoped_lock lock(m_mutex);
+
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_info->piece_length() > 0);
+
+ m_storage_mode = storage_mode;
+
+ // This will corrupt the storage
+ // use while debugging to find
+ // states that cannot be scanned
+ // by check_pieces.
+// m_storage->shuffle();
+
+ m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
+ m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
+ TORRENT_ASSERT(m_free_slots.empty());
+ TORRENT_ASSERT(m_unallocated_slots.empty());
+
+ // assume no piece is out of place (i.e. in a slot
+ // other than the one it should be in)
+ bool out_of_place = false;
+
+ pieces.clear();
+ pieces.resize(m_info->num_pieces(), false);
+ num_pieces = 0;
+
+ // if we have fast-resume info
+ // use it instead of doing the actual checking
+ if (!data.piece_map.empty()
+ && int(data.piece_map.size()) <= m_info->num_pieces())
+ {
+ TORRENT_ASSERT(m_resume_data_verified);
+ for (int i = 0; i < (int)data.piece_map.size(); ++i)
+ {
+ m_slot_to_piece[i] = data.piece_map[i];
+ if (data.piece_map[i] >= 0)
+ {
+ if (data.piece_map[i] != i) out_of_place = true;
+ m_piece_to_slot[data.piece_map[i]] = i;
+ int found_piece = data.piece_map[i];
+
+ // if the piece is not in the unfinished list
+ // we have all of it
+ if (std::find_if(
+ data.unfinished_pieces.begin()
+ , data.unfinished_pieces.end()
+ , piece_picker::has_index(found_piece))
+ == data.unfinished_pieces.end())
+ {
+ ++num_pieces;
+ pieces[found_piece] = true;
+ }
+ }
+ else if (data.piece_map[i] == unassigned)
+ {
+ if (m_storage_mode == storage_mode_compact)
+ m_free_slots.push_back(i);
+ }
+ else
+ {
+ TORRENT_ASSERT(data.piece_map[i] == unallocated);
+ if (m_storage_mode == storage_mode_compact)
+ m_unallocated_slots.push_back(i);
+ }
+ }
+
+ if (m_storage_mode == storage_mode_compact)
+ {
+ m_unallocated_slots.reserve(int(m_info->num_pieces() - data.piece_map.size()));
+ for (int i = (int)data.piece_map.size(); i < (int)m_info->num_pieces(); ++i)
+ {
+ m_unallocated_slots.push_back(i);
+ }
+ if (m_unallocated_slots.empty())
+ {
+ switch_to_full_mode();
+ }
+ }
+ else
+ {
+ if (!out_of_place)
+ {
+ // if no piece is out of place
+ // since we're in full allocation mode, we can
+ // forget the piece allocation tables
+
+ std::vector<int>().swap(m_piece_to_slot);
+ std::vector<int>().swap(m_slot_to_piece);
+ m_state = state_create_files;
+ return false;
+ }
+ else
+ {
+ // in this case we're in full allocation mode, but
+ // we're resuming a compact allocated storage
+ m_state = state_expand_pieces;
+ m_current_slot = 0;
+ error_msg = "pieces needs to be reordered";
+ return false;
+ }
+ }
+
+ m_state = state_create_files;
+ return false;
+ }
+
+ m_state = state_full_check;
+ return false;
+ }
+
+/*
+ state chart:
+
+ check_fastresume()
+
+ | |
+ | v
+ | +------------+ +---------------+
+ | | full_check |-->| expand_pieses |
+ | +------------+ +---------------+
+ | | |
+ | v |
+ | +--------------+ |
+ +->| create_files | <------+
+ +--------------+
+ |
+ v
+ +----------+
+ | finished |
+ +----------+
+*/
+
+
+ // performs the full check and full allocation
+ // (if necessary). returns true if finished and
+ // false if it should be called again
+ // the second return value is the progress the
+ // file check is at. 0 is nothing done, and 1
+ // is finished
+ std::pair<bool, float> piece_manager::check_files(
+ std::vector<bool>& pieces, int& num_pieces, boost::recursive_mutex& mutex)
+ {
+#ifndef NDEBUG
+ boost::recursive_mutex::scoped_lock l_(mutex);
+ TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
+ l_.unlock();
+#endif
+
+ if (m_state == state_create_files)
+ {
+ m_storage->initialize(m_storage_mode == storage_mode_allocate);
+ m_state = state_finished;
+ return std::make_pair(true, 1.f);
+ }
+
+ if (m_state == state_expand_pieces)
+ {
+ INVARIANT_CHECK;
+
+ if (m_scratch_piece >= 0)
+ {
+ int piece = m_scratch_piece;
+ int other_piece = m_slot_to_piece[piece];
+ m_scratch_piece = -1;
+
+ if (other_piece >= 0)
+ {
+ if (m_scratch_buffer2.empty())
+ m_scratch_buffer2.resize(m_info->piece_length());
+
+ m_storage->read(&m_scratch_buffer2[0], piece, 0, m_info->piece_size(other_piece));
+ m_scratch_piece = other_piece;
+ m_piece_to_slot[other_piece] = unassigned;
+ }
+
+ // the slot where this piece belongs is
+ // free. Just move the piece there.
+ m_storage->write(&m_scratch_buffer[0], piece, 0, m_info->piece_size(piece));
+ m_piece_to_slot[piece] = piece;
+ m_slot_to_piece[piece] = piece;
+
+ if (other_piece >= 0)
+ m_scratch_buffer.swap(m_scratch_buffer2);
+
+ return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
+ }
+
+ while (m_current_slot < m_info->num_pieces()
+ && (m_slot_to_piece[m_current_slot] == m_current_slot
+ || m_slot_to_piece[m_current_slot] < 0))
+ {
+ ++m_current_slot;
+ }
+
+ if (m_current_slot == m_info->num_pieces())
+ {
+ m_state = state_create_files;
+ buffer().swap(m_scratch_buffer);
+ buffer().swap(m_scratch_buffer2);
+ if (m_storage_mode != storage_mode_compact)
+ {
+ std::vector<int>().swap(m_piece_to_slot);
+ std::vector<int>().swap(m_slot_to_piece);
+ }
+ return std::make_pair(false, 1.f);
+ }
+
+ int piece = m_slot_to_piece[m_current_slot];
+ TORRENT_ASSERT(piece >= 0);
+ int other_piece = m_slot_to_piece[piece];
+ if (other_piece >= 0)
+ {
+ // there is another piece in the slot
+ // where this one goes. Store it in the scratch
+ // buffer until next iteration.
+ if (m_scratch_buffer.empty())
+ m_scratch_buffer.resize(m_info->piece_length());
+
+ m_storage->read(&m_scratch_buffer[0], piece, 0, m_info->piece_size(other_piece));
+ m_scratch_piece = other_piece;
+ m_piece_to_slot[other_piece] = unassigned;
+ }
+
+ // the slot where this piece belongs is
+ // free. Just move the piece there.
+ m_storage->move_slot(m_current_slot, piece);
+ m_piece_to_slot[piece] = piece;
+ m_slot_to_piece[m_current_slot] = unassigned;
+ m_slot_to_piece[piece] = piece;
+
+ return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
+ }
+
+ TORRENT_ASSERT(m_state == state_full_check);
+
+ // ------------------------
+ // DO THE FULL CHECK
+ // ------------------------
+
+ try
+ {
+ // initialization for the full check
+ if (m_hash_to_piece.empty())
+ {
+ for (int i = 0; i < m_info->num_pieces(); ++i)
+ {
+ m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
+ }
+ boost::recursive_mutex::scoped_lock l(mutex);
+ std::fill(pieces.begin(), pieces.end(), false);
+ num_pieces = 0;
+ }
+
+ m_piece_data.resize(int(m_info->piece_length()));
+ int piece_size = int(m_info->piece_size(m_current_slot));
+ int num_read = int(m_storage->read(&m_piece_data[0]
+ , m_current_slot, 0, piece_size));
+
+ // if the file is incomplete, skip the rest of it
+ if (num_read != piece_size)
+ throw file_error("");
+
+ int piece_index = identify_data(m_piece_data, m_current_slot
+ , pieces, num_pieces, m_hash_to_piece, mutex);
+
+ if (piece_index != m_current_slot
+ && piece_index >= 0)
+ m_out_of_place = true;
+
+ TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
+ TORRENT_ASSERT(piece_index == unassigned || piece_index >= 0);
+
+ const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
+ const bool other_should_move = m_piece_to_slot[m_current_slot] != has_no_slot;
+
+ // check if this piece should be swapped with any other slot
+ // this section will ensure that the storage is correctly sorted
+ // libtorrent will never leave the storage in a state that
+ // requires this sorting, but other clients may.
+
+ // example of worst case:
+ // | m_current_slot = 5
+ // V
+ // +---+- - - +---+- - - +---+- -
+ // | x | | 5 | | 3 | <- piece data in slots
+ // +---+- - - +---+- - - +---+- -
+ // 3 y 5 <- slot index
+
+ // in this example, the data in the m_current_slot (5)
+ // is piece 3. It has to be moved into slot 3. The data
+ // in slot y (piece 5) should be moved into the m_current_slot.
+ // and the data in slot 3 (piece x) should be moved to slot y.
+
+ // there are three possible cases.
+ // 1. There's another piece that should be placed into this slot
+ // 2. This piece should be placed into another slot.
+ // 3. There's another piece that should be placed into this slot
+ // and this piece should be placed into another slot
+
+ // swap piece_index with this slot
+
+ // case 1
+ if (this_should_move && !other_should_move)
+ {
+ TORRENT_ASSERT(piece_index != m_current_slot);
+
+ const int other_slot = piece_index;
+ TORRENT_ASSERT(other_slot >= 0);
+ int other_piece = m_slot_to_piece[other_slot];
+
+ m_slot_to_piece[other_slot] = piece_index;
+ m_slot_to_piece[m_current_slot] = other_piece;
+ m_piece_to_slot[piece_index] = piece_index;
+ if (other_piece >= 0) m_piece_to_slot[other_piece] = m_current_slot;
+
+ if (other_piece == unassigned)
+ {
+ std::vector<int>::iterator i =
+ std::find(m_free_slots.begin(), m_free_slots.end(), other_slot);
+ TORRENT_ASSERT(i != m_free_slots.end());
+ if (m_storage_mode == storage_mode_compact)
+ {
+ m_free_slots.erase(i);
+ m_free_slots.push_back(m_current_slot);
+ }
+ }
+
+ if (other_piece >= 0)
+ m_storage->swap_slots(other_slot, m_current_slot);
+ else
+ m_storage->move_slot(m_current_slot, other_slot);
+
+ TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
+ || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
+ }
+ // case 2
+ else if (!this_should_move && other_should_move)
+ {
+ TORRENT_ASSERT(piece_index != m_current_slot);
+
+ const int other_piece = m_current_slot;
+ const int other_slot = m_piece_to_slot[other_piece];
+ TORRENT_ASSERT(other_slot >= 0);
+
+ m_slot_to_piece[m_current_slot] = other_piece;
+ m_slot_to_piece[other_slot] = piece_index;
+ m_piece_to_slot[other_piece] = m_current_slot;
+
+ if (piece_index == unassigned
+ && m_storage_mode == storage_mode_compact)
+ m_free_slots.push_back(other_slot);
+
+ if (piece_index >= 0)
+ {
+ m_piece_to_slot[piece_index] = other_slot;
+ m_storage->swap_slots(other_slot, m_current_slot);
+ }
+ else
+ {
+ m_storage->move_slot(other_slot, m_current_slot);
+ }
+ TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
+ || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
+ }
+ else if (this_should_move && other_should_move)
+ {
+ TORRENT_ASSERT(piece_index != m_current_slot);
+ TORRENT_ASSERT(piece_index >= 0);
+
+ const int piece1 = m_slot_to_piece[piece_index];
+ const int piece2 = m_current_slot;
+ const int slot1 = piece_index;
+ const int slot2 = m_piece_to_slot[piece2];
+
+ TORRENT_ASSERT(slot1 >= 0);
+ TORRENT_ASSERT(slot2 >= 0);
+ TORRENT_ASSERT(piece2 >= 0);
+
+ if (slot1 == slot2)
+ {
+ // this means there are only two pieces involved in the swap
+ TORRENT_ASSERT(piece1 >= 0);
+
+ // movement diagram:
+ // +-------------------------------+
+ // | |
+ // +--> slot1 --> m_current_slot --+
+
+ m_slot_to_piece[slot1] = piece_index;
+ m_slot_to_piece[m_current_slot] = piece1;
+
+ m_piece_to_slot[piece_index] = slot1;
+ m_piece_to_slot[piece1] = m_current_slot;
+
+ TORRENT_ASSERT(piece1 == m_current_slot);
+ TORRENT_ASSERT(piece_index == slot1);
+
+ m_storage->swap_slots(m_current_slot, slot1);
+
+ TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
+ || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
+ }
+ else
+ {
+ TORRENT_ASSERT(slot1 != slot2);
+ TORRENT_ASSERT(piece1 != piece2);
+
+ // movement diagram:
+ // +-----------------------------------------+
+ // | |
+ // +--> slot1 --> slot2 --> m_current_slot --+
+
+ m_slot_to_piece[slot1] = piece_index;
+ m_slot_to_piece[slot2] = piece1;
+ m_slot_to_piece[m_current_slot] = piece2;
+
+ m_piece_to_slot[piece_index] = slot1;
+ m_piece_to_slot[m_current_slot] = piece2;
+
+ if (piece1 == unassigned)
+ {
+ std::vector<int>::iterator i =
+ std::find(m_free_slots.begin(), m_free_slots.end(), slot1);
+ TORRENT_ASSERT(i != m_free_slots.end());
+ if (m_storage_mode == storage_mode_compact)
+ {
+ m_free_slots.erase(i);
+ m_free_slots.push_back(slot2);
+ }
+ }
+
+ if (piece1 >= 0)
+ {
+ m_piece_to_slot[piece1] = slot2;
+ m_storage->swap_slots3(m_current_slot, slot1, slot2);
+ }
+ else
+ {
+ m_storage->move_slot(m_current_slot, slot1);
+ m_storage->move_slot(slot2, m_current_slot);
+ }
+
+ TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
+ || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
+ }
+ }
+ else
+ {
+ TORRENT_ASSERT(m_piece_to_slot[m_current_slot] == has_no_slot || piece_index != m_current_slot);
+ TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unallocated);
+ TORRENT_ASSERT(piece_index == unassigned || m_piece_to_slot[piece_index] == has_no_slot);
+
+ // the slot was identified as piece 'piece_index'
+ if (piece_index != unassigned)
+ m_piece_to_slot[piece_index] = m_current_slot;
+ else if (m_storage_mode == storage_mode_compact)
+ m_free_slots.push_back(m_current_slot);
+
+ m_slot_to_piece[m_current_slot] = piece_index;
+
+ TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
+ || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
+ }
+ }
+ catch (file_error&)
+ {
+ // find the file that failed, and skip all the blocks in that file
+ size_type file_offset = 0;
+ size_type current_offset = m_current_slot * m_info->piece_length();
+ for (torrent_info::file_iterator i = m_info->begin_files(true);
+ i != m_info->end_files(true); ++i)
+ {
+ file_offset += i->size;
+ if (file_offset > current_offset) break;
+ }
+
+ TORRENT_ASSERT(file_offset > current_offset);
+ int skip_blocks = static_cast<int>(
+ (file_offset - current_offset + m_info->piece_length() - 1)
+ / m_info->piece_length());
+
+ if (m_storage_mode == storage_mode_compact)
+ {
+ for (int i = m_current_slot; i < m_current_slot + skip_blocks; ++i)
+ {
+ TORRENT_ASSERT(m_slot_to_piece[i] == unallocated);
+ m_unallocated_slots.push_back(i);
+ }
+ }
+
+ // current slot will increase by one at the end of the for-loop too
+ m_current_slot += skip_blocks - 1;
+ }
+ ++m_current_slot;
+
+ if (m_current_slot >= m_info->num_pieces())
+ {
+ TORRENT_ASSERT(m_current_slot == m_info->num_pieces());
+
+ // clear the memory we've been using
+ std::vector<char>().swap(m_piece_data);
+ std::multimap<sha1_hash, int>().swap(m_hash_to_piece);
+
+ if (m_storage_mode != storage_mode_compact)
+ {
+ if (!m_out_of_place)
+ {
+ // if no piece is out of place
+ // since we're in full allocation mode, we can
+ // forget the piece allocation tables
+
+ std::vector<int>().swap(m_piece_to_slot);
+ std::vector<int>().swap(m_slot_to_piece);
+ m_state = state_create_files;
+ return std::make_pair(false, 1.f);
+ }
+ else
+ {
+ // in this case we're in full allocation mode, but
+ // we're resuming a compact allocated storage
+ m_state = state_expand_pieces;
+ m_current_slot = 0;
+ return std::make_pair(false, 0.f);
+ }
+ }
+ else if (m_unallocated_slots.empty())
+ {
+ switch_to_full_mode();
+ }
+ m_state = state_create_files;
+
+#ifndef NDEBUG
+ boost::recursive_mutex::scoped_lock l(mutex);
+ TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
+#endif
+ return std::make_pair(false, 1.f);
+ }
+
+ TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
+
+ return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
+ }
+
+ void piece_manager::switch_to_full_mode()
+ {
+ TORRENT_ASSERT(m_storage_mode == storage_mode_compact);
+ TORRENT_ASSERT(m_unallocated_slots.empty());
+ // we have allocated all slots, switch to
+ // full allocation mode in order to free
+ // some unnecessary memory.
+ m_storage_mode = storage_mode_sparse;
+ std::vector<int>().swap(m_unallocated_slots);
+ std::vector<int>().swap(m_free_slots);
+ std::vector<int>().swap(m_piece_to_slot);
+ std::vector<int>().swap(m_slot_to_piece);
+ }
+
+ int piece_manager::allocate_slot_for_piece(int piece_index)
+ {
+ boost::recursive_mutex::scoped_lock lock(m_mutex);
+
+ if (m_storage_mode != storage_mode_compact) return piece_index;
+
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(piece_index >= 0);
+ TORRENT_ASSERT(piece_index < (int)m_piece_to_slot.size());
+ TORRENT_ASSERT(m_piece_to_slot.size() == m_slot_to_piece.size());
+
+ int slot_index = m_piece_to_slot[piece_index];
+
+ if (slot_index != has_no_slot)
+ {
+ TORRENT_ASSERT(slot_index >= 0);
+ TORRENT_ASSERT(slot_index < (int)m_slot_to_piece.size());
+ return slot_index;
+ }
+
+ if (m_free_slots.empty())
+ {
+ allocate_slots(1);
+ TORRENT_ASSERT(!m_free_slots.empty());
+ }
+
+ std::vector<int>::iterator iter(
+ std::find(
+ m_free_slots.begin()
+ , m_free_slots.end()
+ , piece_index));
+
+ if (iter == m_free_slots.end())
+ {
+ TORRENT_ASSERT(m_slot_to_piece[piece_index] != unassigned);
+ TORRENT_ASSERT(!m_free_slots.empty());
+ iter = m_free_slots.end() - 1;
+
+ // special case to make sure we don't use the last slot
+ // when we shouldn't, since it's smaller than ordinary slots
+ if (*iter == m_info->num_pieces() - 1 && piece_index != *iter)
+ {
+ if (m_free_slots.size() == 1)
+ allocate_slots(1);
+ TORRENT_ASSERT(m_free_slots.size() > 1);
+ // assumes that all allocated slots
+ // are put at the end of the free_slots vector
+ iter = m_free_slots.end() - 1;
+ }
+ }
+
+ slot_index = *iter;
+ m_free_slots.erase(iter);
+
+ TORRENT_ASSERT(m_slot_to_piece[slot_index] == unassigned);
+
+ m_slot_to_piece[slot_index] = piece_index;
+ m_piece_to_slot[piece_index] = slot_index;
+
+ // there is another piece already assigned to
+ // the slot we are interested in, swap positions
+ if (slot_index != piece_index
+ && m_slot_to_piece[piece_index] >= 0)
+ {
+
+#if !defined(NDEBUG) && defined(TORRENT_STORAGE_DEBUG)
+ std::stringstream s;
+
+ s << "there is another piece at our slot, swapping..";
+
+ s << "\n piece_index: ";
+ s << piece_index;
+ s << "\n slot_index: ";
+ s << slot_index;
+ s << "\n piece at our slot: ";
+ s << m_slot_to_piece[piece_index];
+ s << "\n";
+
+ print_to_log(s.str());
+ debug_log();
+#endif
+
+ int piece_at_our_slot = m_slot_to_piece[piece_index];
+ TORRENT_ASSERT(m_piece_to_slot[piece_at_our_slot] == piece_index);
+
+ std::swap(
+ m_slot_to_piece[piece_index]
+ , m_slot_to_piece[slot_index]);
+
+ std::swap(
+ m_piece_to_slot[piece_index]
+ , m_piece_to_slot[piece_at_our_slot]);
+
+ m_storage->move_slot(piece_index, slot_index);
+
+ TORRENT_ASSERT(m_slot_to_piece[piece_index] == piece_index);
+ TORRENT_ASSERT(m_piece_to_slot[piece_index] == piece_index);
+
+ slot_index = piece_index;
+
+#if !defined(NDEBUG) && defined(TORRENT_STORAGE_DEBUG)
+ debug_log();
+#endif
+ }
+ TORRENT_ASSERT(slot_index >= 0);
+ TORRENT_ASSERT(slot_index < (int)m_slot_to_piece.size());
+
+ if (m_unallocated_slots.empty())
+ {
+ switch_to_full_mode();
+ }
+
+ return slot_index;
+ }
+
+ bool piece_manager::allocate_slots(int num_slots, bool abort_on_disk)
+ {
+ boost::recursive_mutex::scoped_lock lock(m_mutex);
+ TORRENT_ASSERT(num_slots > 0);
+
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_unallocated_slots.empty());
+ TORRENT_ASSERT(m_storage_mode == storage_mode_compact);
+
+ bool written = false;
+
+ for (int i = 0; i < num_slots && !m_unallocated_slots.empty(); ++i)
+ {
+// INVARIANT_CHECK;
+
+ int pos = m_unallocated_slots.front();
+ TORRENT_ASSERT(m_slot_to_piece[pos] == unallocated);
+ TORRENT_ASSERT(m_piece_to_slot[pos] != pos);
+
+ int new_free_slot = pos;
+ if (m_piece_to_slot[pos] != has_no_slot)
+ {
+ new_free_slot = m_piece_to_slot[pos];
+ m_storage->move_slot(new_free_slot, pos);
+ m_slot_to_piece[pos] = pos;
+ m_piece_to_slot[pos] = pos;
+ written = true;
+ }
+ m_unallocated_slots.erase(m_unallocated_slots.begin());
+ m_slot_to_piece[new_free_slot] = unassigned;
+ m_free_slots.push_back(new_free_slot);
+ if (abort_on_disk && written) break;
+ }
+
+ TORRENT_ASSERT(m_free_slots.size() > 0);
+ return written;
+ }
+
+ int piece_manager::slot_for(int piece) const
+ {
+ if (m_storage_mode != storage_mode_compact) return piece;
+ TORRENT_ASSERT(piece < int(m_piece_to_slot.size()));
+ TORRENT_ASSERT(piece >= 0);
+ return m_piece_to_slot[piece];
+ }
+
+ int piece_manager::piece_for(int slot) const
+ {
+ if (m_storage_mode != storage_mode_compact) return slot;
+ TORRENT_ASSERT(slot < int(m_slot_to_piece.size()));
+ TORRENT_ASSERT(slot >= 0);
+ return m_slot_to_piece[slot];
+ }
+
+#ifndef NDEBUG
+ void piece_manager::check_invariant() const
+ {
+ boost::recursive_mutex::scoped_lock lock(m_mutex);
+
+ if (m_unallocated_slots.empty() && m_state == state_finished)
+ {
+ TORRENT_ASSERT(m_storage_mode != storage_mode_compact);
+ }
+
+ if (m_storage_mode != storage_mode_compact)
+ {
+ TORRENT_ASSERT(m_unallocated_slots.empty());
+ TORRENT_ASSERT(m_free_slots.empty());
+ }
+
+ if (m_storage_mode != storage_mode_compact
+ && m_state != state_expand_pieces
+ && m_state != state_full_check)
+ {
+ TORRENT_ASSERT(m_piece_to_slot.empty());
+ TORRENT_ASSERT(m_slot_to_piece.empty());
+ }
+ else
+ {
+ if (m_piece_to_slot.empty()) return;
+
+ TORRENT_ASSERT((int)m_piece_to_slot.size() == m_info->num_pieces());
+ TORRENT_ASSERT((int)m_slot_to_piece.size() == m_info->num_pieces());
+
+ for (std::vector<int>::const_iterator i = m_free_slots.begin();
+ i != m_free_slots.end(); ++i)
+ {
+ TORRENT_ASSERT(*i < (int)m_slot_to_piece.size());
+ TORRENT_ASSERT(*i >= 0);
+ TORRENT_ASSERT(m_slot_to_piece[*i] == unassigned);
+ TORRENT_ASSERT(std::find(i+1, m_free_slots.end(), *i)
+ == m_free_slots.end());
+ }
+
+ for (std::vector<int>::const_iterator i = m_unallocated_slots.begin();
+ i != m_unallocated_slots.end(); ++i)
+ {
+ TORRENT_ASSERT(*i < (int)m_slot_to_piece.size());
+ TORRENT_ASSERT(*i >= 0);
+ TORRENT_ASSERT(m_slot_to_piece[*i] == unallocated);
+ TORRENT_ASSERT(std::find(i+1, m_unallocated_slots.end(), *i)
+ == m_unallocated_slots.end());
+ }
+
+ for (int i = 0; i < m_info->num_pieces(); ++i)
+ {
+ // Check domain of piece_to_slot's elements
+ if (m_piece_to_slot[i] != has_no_slot)
+ {
+ TORRENT_ASSERT(m_piece_to_slot[i] >= 0);
+ TORRENT_ASSERT(m_piece_to_slot[i] < (int)m_slot_to_piece.size());
+ }
+
+ // Check domain of slot_to_piece's elements
+ if (m_slot_to_piece[i] != unallocated
+ && m_slot_to_piece[i] != unassigned)
+ {
+ TORRENT_ASSERT(m_slot_to_piece[i] >= 0);
+ TORRENT_ASSERT(m_slot_to_piece[i] < (int)m_piece_to_slot.size());
+ }
+
+ // do more detailed checks on piece_to_slot
+ if (m_piece_to_slot[i] >= 0)
+ {
+ TORRENT_ASSERT(m_slot_to_piece[m_piece_to_slot[i]] == i);
+ if (m_piece_to_slot[i] != i)
+ {
+ TORRENT_ASSERT(m_slot_to_piece[i] == unallocated);
+ }
+ }
+ else
+ {
+ TORRENT_ASSERT(m_piece_to_slot[i] == has_no_slot);
+ }
+
+ // do more detailed checks on slot_to_piece
+
+ if (m_slot_to_piece[i] >= 0)
+ {
+ TORRENT_ASSERT(m_slot_to_piece[i] < (int)m_piece_to_slot.size());
+ TORRENT_ASSERT(m_piece_to_slot[m_slot_to_piece[i]] == i);
+#ifdef TORRENT_STORAGE_DEBUG
+ TORRENT_ASSERT(
+ std::find(
+ m_unallocated_slots.begin()
+ , m_unallocated_slots.end()
+ , i) == m_unallocated_slots.end()
+ );
+ TORRENT_ASSERT(
+ std::find(
+ m_free_slots.begin()
+ , m_free_slots.end()
+ , i) == m_free_slots.end()
+ );
+#endif
+ }
+ else if (m_slot_to_piece[i] == unallocated)
+ {
+#ifdef TORRENT_STORAGE_DEBUG
+ TORRENT_ASSERT(m_unallocated_slots.empty()
+ || (std::find(
+ m_unallocated_slots.begin()
+ , m_unallocated_slots.end()
+ , i) != m_unallocated_slots.end())
+ );
+#endif
+ }
+ else if (m_slot_to_piece[i] == unassigned)
+ {
+#ifdef TORRENT_STORAGE_DEBUG
+ TORRENT_ASSERT(
+ std::find(
+ m_free_slots.begin()
+ , m_free_slots.end()
+ , i) != m_free_slots.end()
+ );
+#endif
+ }
+ else
+ {
+ TORRENT_ASSERT(false && "m_slot_to_piece[i] is invalid");
+ }
+ }
+ }
+ }
+
+#ifdef TORRENT_STORAGE_DEBUG
+ void piece_manager::debug_log() const
+ {
+ std::stringstream s;
+
+ s << "index\tslot\tpiece\n";
+
+ for (int i = 0; i < m_info->num_pieces(); ++i)
+ {
+ s << i << "\t" << m_slot_to_piece[i] << "\t";
+ s << m_piece_to_slot[i] << "\n";
+ }
+
+ s << "---------------------------------\n";
+
+ print_to_log(s.str());
+ }
+#endif
+#endif
+} // namespace libtorrent
+
diff --git a/src/libtorrent/src/torrent.cpp b/src/libtorrent/src/torrent.cpp
new file mode 100644
index 0000000..a65cf6f
--- /dev/null
+++ b/src/libtorrent/src/torrent.cpp
@@ -0,0 +1,3297 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <iterator>
+#include <algorithm>
+#include <set>
+#include <cctype>
+#include <numeric>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/mutex.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/torrent_handle.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/peer.hpp"
+#include "libtorrent/bt_peer_connection.hpp"
+#include "libtorrent/web_peer_connection.hpp"
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/alert.hpp"
+#include "libtorrent/identify_client.hpp"
+#include "libtorrent/alert_types.hpp"
+#include "libtorrent/extensions.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+#include "libtorrent/instantiate_connection.hpp"
+#include "libtorrent/assert.hpp"
+
+using namespace libtorrent;
+using boost::tuples::tuple;
+using boost::tuples::get;
+using boost::tuples::make_tuple;
+using boost::bind;
+using boost::mutex;
+using libtorrent::aux::session_impl;
+
+namespace
+{
+
+ enum
+ {
+ // wait 60 seconds before retrying a failed tracker
+ tracker_retry_delay_min = 60
+ // when tracker_failed_max trackers
+ // has failed, wait 10 minutes instead
+ , tracker_retry_delay_max = 10 * 60
+ , tracker_failed_max = 5
+ };
+
+ int calculate_block_size(const torrent_info& i, int default_block_size)
+ {
+ if (default_block_size < 1024) default_block_size = 1024;
+
+ // if pieces are too small, adjust the block size
+ if (i.piece_length() < default_block_size)
+ {
+ return i.piece_length();
+ }
+
+ // otherwise, go with the default
+ return default_block_size;
+ }
+
+ struct find_peer_by_ip
+ {
+ find_peer_by_ip(tcp::endpoint const& a, const torrent* t)
+ : ip(a)
+ , tor(t)
+ { TORRENT_ASSERT(t != 0); }
+
+ bool operator()(session_impl::connection_map::value_type const& c) const
+ {
+ tcp::endpoint const& sender = c->remote();
+ if (sender.address() != ip.address()) return false;
+ if (tor != c->associated_torrent().lock().get()) return false;
+ return true;
+ }
+
+ tcp::endpoint const& ip;
+ torrent const* tor;
+ };
+
+ struct peer_by_id
+ {
+ peer_by_id(const peer_id& i): pid(i) {}
+
+ bool operator()(session_impl::connection_map::value_type const& p) const
+ {
+ if (p->pid() != pid) return false;
+ // have a special case for all zeros. We can have any number
+ // of peers with that pid, since it's used to indicate no pid.
+ if (std::count(pid.begin(), pid.end(), 0) == 20) return false;
+ return true;
+ }
+
+ peer_id const& pid;
+ };
+}
+
+namespace libtorrent
+{
+
+ torrent::torrent(
+ session_impl& ses
+ , aux::checker_impl& checker
+ , boost::intrusive_ptr<torrent_info> tf
+ , fs::path const& save_path
+ , tcp::endpoint const& net_interface
+ , storage_mode_t storage_mode
+ , int block_size
+ , storage_constructor_type sc
+ , bool paused)
+ : m_torrent_file(tf)
+ , m_abort(false)
+ , m_paused(paused)
+ , m_just_paused(false)
+ , m_event(tracker_request::started)
+ , m_block_size(0)
+ , m_storage(0)
+ , m_next_request(time_now())
+ , m_duration(1800)
+ , m_complete(-1)
+ , m_incomplete(-1)
+ , m_host_resolver(ses.m_io_service)
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ , m_resolving_country(false)
+ , m_resolve_countries(false)
+#endif
+ , m_announce_timer(ses.m_io_service)
+#ifndef TORRENT_DISABLE_DHT
+ , m_last_dht_announce(time_now() - minutes(15))
+#endif
+ , m_ses(ses)
+ , m_checker(checker)
+ , m_picker(0)
+ , m_trackers(m_torrent_file->trackers())
+ , m_last_working_tracker(-1)
+ , m_currently_trying_tracker(0)
+ , m_failed_trackers(0)
+ , m_time_scaler(0)
+ , m_num_pieces(0)
+ , m_sequenced_download_threshold(0)
+ , m_got_tracker_response(false)
+ , m_ratio(0.f)
+ , m_total_failed_bytes(0)
+ , m_total_redundant_bytes(0)
+ , m_net_interface(net_interface.address(), 0)
+ , m_save_path(complete(save_path))
+ , m_storage_mode(storage_mode)
+ , m_default_block_size(block_size)
+ , m_connections_initialized(true)
+ , m_settings(ses.settings())
+ , m_storage_constructor(sc)
+ , m_max_uploads((std::numeric_limits<int>::max)())
+ , m_num_uploads(0)
+ , m_max_connections((std::numeric_limits<int>::max)())
+ , m_policy(this)
+ {
+#ifndef NDEBUG
+ m_files_checked = false;
+#endif
+ }
+
+ torrent::torrent(
+ session_impl& ses
+ , aux::checker_impl& checker
+ , char const* tracker_url
+ , sha1_hash const& info_hash
+ , char const* name
+ , fs::path const& save_path
+ , tcp::endpoint const& net_interface
+ , storage_mode_t storage_mode
+ , int block_size
+ , storage_constructor_type sc
+ , bool paused)
+ : m_torrent_file(new torrent_info(info_hash))
+ , m_abort(false)
+ , m_paused(paused)
+ , m_just_paused(false)
+ , m_event(tracker_request::started)
+ , m_block_size(0)
+ , m_storage(0)
+ , m_next_request(time_now())
+ , m_duration(1800)
+ , m_complete(-1)
+ , m_incomplete(-1)
+ , m_host_resolver(ses.m_io_service)
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ , m_resolving_country(false)
+ , m_resolve_countries(false)
+#endif
+ , m_announce_timer(ses.m_io_service)
+#ifndef TORRENT_DISABLE_DHT
+ , m_last_dht_announce(time_now() - minutes(15))
+#endif
+ , m_ses(ses)
+ , m_checker(checker)
+ , m_picker(0)
+ , m_last_working_tracker(-1)
+ , m_currently_trying_tracker(0)
+ , m_failed_trackers(0)
+ , m_time_scaler(0)
+ , m_num_pieces(0)
+ , m_sequenced_download_threshold(0)
+ , m_got_tracker_response(false)
+ , m_ratio(0.f)
+ , m_total_failed_bytes(0)
+ , m_total_redundant_bytes(0)
+ , m_net_interface(net_interface.address(), 0)
+ , m_save_path(complete(save_path))
+ , m_storage_mode(storage_mode)
+ , m_default_block_size(block_size)
+ , m_connections_initialized(false)
+ , m_settings(ses.settings())
+ , m_storage_constructor(sc)
+ , m_max_uploads((std::numeric_limits<int>::max)())
+ , m_num_uploads(0)
+ , m_max_connections((std::numeric_limits<int>::max)())
+ , m_policy(this)
+ {
+#ifndef NDEBUG
+ m_files_checked = false;
+#endif
+ INVARIANT_CHECK;
+
+ if (name) m_name.reset(new std::string(name));
+
+ if (tracker_url)
+ {
+ m_trackers.push_back(announce_entry(tracker_url));
+ m_torrent_file->add_tracker(tracker_url);
+ }
+ }
+
+ void torrent::start()
+ {
+ boost::weak_ptr<torrent> self(shared_from_this());
+ if (m_torrent_file->is_valid()) init();
+ if (m_abort) return;
+ m_announce_timer.expires_from_now(seconds(1));
+ m_announce_timer.async_wait(m_ses.m_strand.wrap(
+ bind(&torrent::on_announce_disp, self, _1)));
+ }
+
+#ifndef TORRENT_DISABLE_DHT
+ bool torrent::should_announce_dht() const
+ {
+ if (m_ses.m_listen_sockets.empty()) return false;
+
+ if (!m_ses.m_dht) return false;
+
+ // don't announce private torrents
+ if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
+
+ if (m_trackers.empty()) return true;
+
+ return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback;
+ }
+#endif
+
+ torrent::~torrent()
+ {
+ // The invariant can't be maintained here, since the torrent
+ // is being destructed, all weak references to it have been
+ // reset, which means that all its peers already have an
+ // invalidated torrent pointer (so it cannot be verified to be correct)
+
+ // i.e. the invariant can only be maintained if all connections have
+ // been closed by the time the torrent is destructed. And they are
+ // supposed to be closed. So we can still do the invariant check.
+
+ TORRENT_ASSERT(m_connections.empty());
+
+ INVARIANT_CHECK;
+
+#if defined(TORRENT_VERBOSE_LOGGING)
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ (*(*i)->m_logger) << "*** DESTRUCTING TORRENT\n";
+ }
+#endif
+
+ TORRENT_ASSERT(m_abort);
+ if (!m_connections.empty())
+ disconnect_all();
+ }
+
+ peer_request torrent::to_req(piece_block const& p)
+ {
+ int block_offset = p.block_index * m_block_size;
+ int block_size = (std::min)(torrent_file().piece_size(
+ p.piece_index) - block_offset, m_block_size);
+ TORRENT_ASSERT(block_size > 0);
+ TORRENT_ASSERT(block_size <= m_block_size);
+
+ peer_request r;
+ r.piece = p.piece_index;
+ r.start = block_offset;
+ r.length = block_size;
+ return r;
+ }
+
+ std::string torrent::name() const
+ {
+ if (valid_metadata()) return m_torrent_file->name();
+ if (m_name) return *m_name;
+ return "";
+ }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+
+ void torrent::add_extension(boost::shared_ptr<torrent_plugin> ext)
+ {
+ m_extensions.push_back(ext);
+ }
+
+ void torrent::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
+ , void* userdata)
+ {
+ boost::shared_ptr<torrent_plugin> tp(ext(this, userdata));
+ if (!tp) return;
+
+ add_extension(tp);
+
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ peer_connection* p = *i;
+ boost::shared_ptr<peer_plugin> pp(tp->new_connection(p));
+ if (pp) p->add_extension(pp);
+ }
+
+ // if files are checked for this torrent, call the extension
+ // to let it initialize itself
+ if (m_connections_initialized)
+ tp->on_files_checked();
+ }
+
+#endif
+
+ // this may not be called from a constructor because of the call to
+ // shared_from_this()
+ void torrent::init()
+ {
+ TORRENT_ASSERT(m_torrent_file->is_valid());
+ TORRENT_ASSERT(m_torrent_file->num_files() > 0);
+ TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
+
+ m_have_pieces.resize(m_torrent_file->num_pieces(), false);
+ // the shared_from_this() will create an intentional
+ // cycle of ownership, se the hpp file for description.
+ m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
+ , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor);
+ m_storage = m_owning_storage.get();
+ m_block_size = calculate_block_size(*m_torrent_file, m_default_block_size);
+ m_picker.reset(new piece_picker(
+ m_torrent_file->piece_length() / m_block_size
+ , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size)));
+
+ std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
+ std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
+ , m_web_seeds.begin()));
+ }
+
+ void torrent::use_interface(const char* net_interface)
+ {
+ INVARIANT_CHECK;
+
+ m_net_interface = tcp::endpoint(address::from_string(net_interface), 0);
+ }
+
+ void torrent::on_announce_disp(boost::weak_ptr<torrent> p
+ , asio::error_code const& e)
+ {
+ if (e) return;
+ boost::shared_ptr<torrent> t = p.lock();
+ if (!t) return;
+ t->on_announce();
+ }
+
+ void torrent::on_announce()
+#ifndef NDEBUG
+ try
+#endif
+ {
+ if (m_abort) return;
+
+ boost::weak_ptr<torrent> self(shared_from_this());
+
+ if (!m_torrent_file->priv())
+ {
+ // announce on local network every 5 minutes
+ m_announce_timer.expires_from_now(minutes(5));
+ m_announce_timer.async_wait(m_ses.m_strand.wrap(
+ bind(&torrent::on_announce_disp, self, _1)));
+
+ // announce with the local discovery service
+ if (!m_paused)
+ m_ses.announce_lsd(m_torrent_file->info_hash());
+ }
+ else
+ {
+ m_announce_timer.expires_from_now(minutes(15));
+ m_announce_timer.async_wait(m_ses.m_strand.wrap(
+ bind(&torrent::on_announce_disp, self, _1)));
+ }
+
+#ifndef TORRENT_DISABLE_DHT
+ if (m_paused) return;
+ if (!m_ses.m_dht) return;
+ ptime now = time_now();
+ if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
+ {
+ m_last_dht_announce = now;
+ m_ses.m_dht->announce(m_torrent_file->info_hash()
+ , m_ses.m_listen_sockets.front().external_port
+ , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
+ }
+#endif
+ }
+#ifndef NDEBUG
+ catch (std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ TORRENT_ASSERT(false);
+ };
+#endif
+
+#ifndef TORRENT_DISABLE_DHT
+
+ void torrent::on_dht_announce_response_disp(boost::weak_ptr<libtorrent::torrent> t
+ , std::vector<tcp::endpoint> const& peers)
+ {
+ boost::shared_ptr<libtorrent::torrent> tor = t.lock();
+ if (!tor) return;
+ tor->on_dht_announce_response(peers);
+ }
+
+ void torrent::on_dht_announce_response(std::vector<tcp::endpoint> const& peers)
+ {
+ if (peers.empty()) return;
+
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(tracker_reply_alert(
+ get_handle(), peers.size(), "Got peers from DHT"));
+ }
+ std::for_each(peers.begin(), peers.end(), bind(
+ &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
+ , peer_info::dht, 0));
+ }
+
+#endif
+
+ void torrent::scrape_tracker()
+ {
+ if (m_trackers.empty()) return;
+
+ TORRENT_ASSERT(m_currently_trying_tracker >= 0);
+ TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size()));
+
+ tracker_request req;
+ req.info_hash = m_torrent_file->info_hash();
+ req.kind = tracker_request::scrape_request;
+ req.url = m_trackers[m_currently_trying_tracker].url;
+ m_ses.m_tracker_manager.queue_request(m_ses.m_strand, m_ses.m_half_open, req
+ , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this());
+ }
+
+ // returns true if it is time for this torrent to make another
+ // tracker request
+ bool torrent::should_request()
+ {
+ INVARIANT_CHECK;
+
+ if (m_trackers.empty()) return false;
+
+ if (m_just_paused)
+ {
+ m_just_paused = false;
+ return true;
+ }
+ return !m_paused && m_next_request < time_now();
+ }
+
+ void torrent::tracker_warning(std::string const& msg)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (m_ses.m_alerts.should_post(alert::warning))
+ {
+ m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), msg));
+ }
+ }
+
+ void torrent::tracker_scrape_response(tracker_request const& req
+ , int complete, int incomplete, int downloaded)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(req.kind == tracker_request::scrape_request);
+
+ if (complete >= 0) m_complete = complete;
+ if (incomplete >= 0) m_incomplete = incomplete;
+
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ std::stringstream s;
+ s << "Got scrape response from tracker: " << req.url;
+ m_ses.m_alerts.post_alert(scrape_reply_alert(
+ get_handle(), m_incomplete, m_complete, s.str()));
+ }
+ }
+
+ void torrent::tracker_response(
+ tracker_request const& r
+ , std::vector<peer_entry>& peer_list
+ , int interval
+ , int complete
+ , int incomplete)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(r.kind == tracker_request::announce_request);
+
+ m_failed_trackers = 0;
+ // announce intervals less than 5 minutes
+ // are insane.
+ if (interval < 60 * 5) interval = 60 * 5;
+
+ m_last_working_tracker
+ = prioritize_tracker(m_currently_trying_tracker);
+ m_currently_trying_tracker = 0;
+
+ m_duration = interval;
+ m_next_request = time_now() + seconds(m_duration);
+
+ if (complete >= 0) m_complete = complete;
+ if (incomplete >= 0) m_incomplete = incomplete;
+
+ // connect to random peers from the list
+ std::random_shuffle(peer_list.begin(), peer_list.end());
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ std::stringstream s;
+ s << "TRACKER RESPONSE:\n"
+ "interval: " << m_duration << "\n"
+ "peers:\n";
+ for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
+ i != peer_list.end(); ++i)
+ {
+ s << " " << std::setfill(' ') << std::setw(16) << i->ip
+ << " " << std::setw(5) << std::dec << i->port << " ";
+ if (!i->pid.is_all_zeros()) s << " " << i->pid << " " << identify_client(i->pid);
+ s << "\n";
+ }
+ debug_log(s.str());
+#endif
+ // for each of the peers we got from the tracker
+ for (std::vector<peer_entry>::iterator i = peer_list.begin();
+ i != peer_list.end(); ++i)
+ {
+ // don't make connections to ourself
+ if (i->pid == m_ses.get_peer_id())
+ continue;
+
+ try
+ {
+ tcp::endpoint a(address::from_string(i->ip), i->port);
+
+ if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ debug_log("blocked ip from tracker: " + i->ip);
+#endif
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()
+ , "peer from tracker blocked by IP filter"));
+ }
+
+ continue;
+ }
+
+ m_policy.peer_from_tracker(a, i->pid, peer_info::tracker, 0);
+ }
+ catch (std::exception&)
+ {
+ // assume this is because we got a hostname instead of
+ // an ip address from the tracker
+
+ tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port));
+ m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
+ bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid)));
+ }
+ }
+
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ std::stringstream s;
+ s << "Got response from tracker: " << r.url;
+ m_ses.m_alerts.post_alert(tracker_reply_alert(
+ get_handle(), peer_list.size(), s.str()));
+ }
+ m_got_tracker_response = true;
+ }
+
+ void torrent::on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
+ , peer_id pid) try
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ if (e || host == tcp::resolver::iterator() ||
+ m_ses.is_aborted()) return;
+
+ if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ debug_log("blocked ip from tracker: " + host->endpoint().address().to_string());
+#endif
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(peer_blocked_alert(host->endpoint().address()
+ , "peer from tracker blocked by IP filter"));
+ }
+
+ return;
+ }
+
+ m_policy.peer_from_tracker(*host, pid, peer_info::tracker, 0);
+ }
+ catch (std::exception&)
+ {};
+
+ size_type torrent::bytes_left() const
+ {
+ // if we don't have the metadata yet, we
+ // cannot tell how big the torrent is.
+ if (!valid_metadata()) return -1;
+ return m_torrent_file->total_size()
+ - quantized_bytes_done();
+ }
+
+ size_type torrent::quantized_bytes_done() const
+ {
+// INVARIANT_CHECK;
+
+ if (!valid_metadata()) return 0;
+
+ if (m_torrent_file->num_pieces() == 0)
+ return 0;
+
+ if (is_seed()) return m_torrent_file->total_size();
+
+ const int last_piece = m_torrent_file->num_pieces() - 1;
+
+ size_type total_done
+ = size_type(m_num_pieces) * m_torrent_file->piece_length();
+
+ // if we have the last piece, we have to correct
+ // the amount we have, since the first calculation
+ // assumed all pieces were of equal size
+ if (m_have_pieces[last_piece])
+ {
+ int corr = m_torrent_file->piece_size(last_piece)
+ - m_torrent_file->piece_length();
+ total_done += corr;
+ }
+ return total_done;
+ }
+
+ // the first value is the total number of bytes downloaded
+ // the second value is the number of bytes of those that haven't
+ // been filtered as not wanted we have downloaded
+ tuple<size_type, size_type> torrent::bytes_done() const
+ {
+ INVARIANT_CHECK;
+
+ if (!valid_metadata() || m_torrent_file->num_pieces() == 0)
+ return tuple<size_type, size_type>(0,0);
+
+ const int last_piece = m_torrent_file->num_pieces() - 1;
+ const int piece_size = m_torrent_file->piece_length();
+
+ if (is_seed())
+ return make_tuple(m_torrent_file->total_size()
+ , m_torrent_file->total_size());
+
+ TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered());
+ size_type wanted_done = size_type(m_num_pieces - m_picker->num_have_filtered())
+ * piece_size;
+ TORRENT_ASSERT(wanted_done >= 0);
+
+ size_type total_done
+ = size_type(m_num_pieces) * piece_size;
+ TORRENT_ASSERT(m_num_pieces < m_torrent_file->num_pieces());
+
+ // if we have the last piece, we have to correct
+ // the amount we have, since the first calculation
+ // assumed all pieces were of equal size
+ if (m_have_pieces[last_piece])
+ {
+ TORRENT_ASSERT(total_done >= piece_size);
+ int corr = m_torrent_file->piece_size(last_piece)
+ - piece_size;
+ TORRENT_ASSERT(corr <= 0);
+ TORRENT_ASSERT(corr > -piece_size);
+ total_done += corr;
+ if (m_picker->piece_priority(last_piece) != 0)
+ {
+ TORRENT_ASSERT(wanted_done >= piece_size);
+ wanted_done += corr;
+ }
+ }
+
+ TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
+ TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
+ TORRENT_ASSERT(total_done >= wanted_done);
+
+ const std::vector<piece_picker::downloading_piece>& dl_queue
+ = m_picker->get_download_queue();
+
+ const int blocks_per_piece = piece_size / m_block_size;
+
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i =
+ dl_queue.begin(); i != dl_queue.end(); ++i)
+ {
+ int corr = 0;
+ int index = i->index;
+ if (m_have_pieces[index]) continue;
+ TORRENT_ASSERT(i->finished <= m_picker->blocks_in_piece(index));
+
+#ifndef NDEBUG
+ for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
+ j != dl_queue.end(); ++j)
+ {
+ TORRENT_ASSERT(j->index != index);
+ }
+#endif
+
+ for (int j = 0; j < blocks_per_piece; ++j)
+ {
+ TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
+ corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
+ TORRENT_ASSERT(corr >= 0);
+ TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece()
+ || i->info[j].state != piece_picker::block_info::state_finished);
+ }
+
+ // correction if this was the last piece
+ // and if we have the last block
+ if (i->index == last_piece
+ && i->info[m_picker->blocks_in_last_piece()-1].state
+ == piece_picker::block_info::state_finished)
+ {
+ corr -= m_block_size;
+ corr += m_torrent_file->piece_size(last_piece) % m_block_size;
+ }
+ total_done += corr;
+ if (m_picker->piece_priority(index) != 0)
+ wanted_done += corr;
+ }
+
+ TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
+ TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
+
+ std::map<piece_block, int> downloading_piece;
+ for (const_peer_iterator i = begin(); i != end(); ++i)
+ {
+ peer_connection* pc = *i;
+ boost::optional<piece_block_progress> p
+ = pc->downloading_piece_progress();
+ if (p)
+ {
+ if (m_have_pieces[p->piece_index])
+ continue;
+
+ piece_block block(p->piece_index, p->block_index);
+ if (m_picker->is_finished(block))
+ continue;
+
+ std::map<piece_block, int>::iterator dp
+ = downloading_piece.find(block);
+ if (dp != downloading_piece.end())
+ {
+ if (dp->second < p->bytes_downloaded)
+ dp->second = p->bytes_downloaded;
+ }
+ else
+ {
+ downloading_piece[block] = p->bytes_downloaded;
+ }
+#ifndef NDEBUG
+ TORRENT_ASSERT(p->bytes_downloaded <= p->full_block_bytes);
+ int last_piece = m_torrent_file->num_pieces() - 1;
+ if (p->piece_index == last_piece
+ && p->block_index == m_torrent_file->piece_size(last_piece) / block_size())
+ TORRENT_ASSERT(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size());
+ else
+ TORRENT_ASSERT(p->full_block_bytes == block_size());
+#endif
+ }
+ }
+ for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
+ i != downloading_piece.end(); ++i)
+ {
+ total_done += i->second;
+ if (m_picker->piece_priority(i->first.piece_index) != 0)
+ wanted_done += i->second;
+ }
+
+#ifndef NDEBUG
+
+ if (total_done >= m_torrent_file->total_size())
+ {
+ // Thist happens when a piece has been downloaded completely
+ // but not yet verified against the hash
+ std::copy(m_have_pieces.begin(), m_have_pieces.end()
+ , std::ostream_iterator<bool>(std::cerr, " "));
+ std::cerr << std::endl;
+ std::cerr << "num_pieces: " << m_num_pieces << std::endl;
+
+ std::cerr << "unfinished:" << std::endl;
+
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i =
+ dl_queue.begin(); i != dl_queue.end(); ++i)
+ {
+ std::cerr << " " << i->index << " ";
+ for (int j = 0; j < blocks_per_piece; ++j)
+ {
+ std::cerr << (i->info[j].state == piece_picker::block_info::state_finished ? "1" : "0");
+ }
+ std::cerr << std::endl;
+ }
+
+ std::cerr << "downloading pieces:" << std::endl;
+
+ for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
+ i != downloading_piece.end(); ++i)
+ {
+ std::cerr << " " << i->first.piece_index << ":" << i->first.block_index
+ << " " << i->second << std::endl;
+ }
+
+ }
+
+ TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
+ TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
+
+#endif
+
+ TORRENT_ASSERT(total_done >= wanted_done);
+ return make_tuple(total_done, wanted_done);
+ }
+
+ void torrent::piece_finished(int index, bool passed_hash_check)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << time_now_string() << " *** PIECE_FINISHED [ p: "
+ << index << " chk: " << (passed_hash_check?"passed":"failed") << " ]\n";
+#endif
+
+ bool was_seed = is_seed();
+ bool was_finished = m_picker->num_filtered() + num_pieces()
+ == torrent_file().num_pieces();
+
+ if (passed_hash_check)
+ {
+ if (m_ses.m_alerts.should_post(alert::debug))
+ {
+ m_ses.m_alerts.post_alert(piece_finished_alert(get_handle()
+ , index, "piece finished"));
+ }
+ // the following call may cause picker to become invalid
+ // in case we just became a seed
+ announce_piece(index);
+ TORRENT_ASSERT(valid_metadata());
+ // if we just became a seed, picker is now invalid, since it
+ // is deallocated by the torrent once it starts seeding
+ if (!was_finished
+ && (is_seed()
+ || m_picker->num_filtered() + num_pieces()
+ == torrent_file().num_pieces()))
+ {
+ // torrent finished
+ // i.e. all the pieces we're interested in have
+ // been downloaded. Release the files (they will open
+ // in read only mode if needed)
+ try { finished(); }
+ catch (std::exception& e)
+ {
+#ifndef NDEBUG
+ std::cerr << e.what() << std::endl;
+ TORRENT_ASSERT(false);
+#endif
+ }
+ }
+ }
+ else
+ {
+ piece_failed(index);
+ }
+
+#ifndef NDEBUG
+ try
+ {
+#endif
+
+ m_policy.piece_finished(index, passed_hash_check);
+
+#ifndef NDEBUG
+ }
+ catch (std::exception const& e)
+ {
+ std::cerr << e.what() << std::endl;
+ TORRENT_ASSERT(false);
+ }
+#endif
+
+#ifndef NDEBUG
+ try
+ {
+#endif
+
+ if (!was_seed && is_seed())
+ {
+ TORRENT_ASSERT(passed_hash_check);
+ completed();
+ }
+
+#ifndef NDEBUG
+ }
+ catch (std::exception const& e)
+ {
+ std::cerr << e.what() << std::endl;
+ TORRENT_ASSERT(false);
+ }
+#endif
+
+ }
+
+ void torrent::piece_failed(int index)
+ {
+ // if the last piece fails the peer connection will still
+ // think that it has received all of it until this function
+ // resets the download queue. So, we cannot do the
+ // invariant check here since it assumes:
+ // (total_done == m_torrent_file->total_size()) => is_seed()
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_storage);
+ TORRENT_ASSERT(m_storage->refcount() > 0);
+ TORRENT_ASSERT(m_picker.get());
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < m_torrent_file->num_pieces());
+
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ std::stringstream s;
+ s << "hash for piece " << index << " failed";
+ m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index, s.str()));
+ }
+ // increase the total amount of failed bytes
+ m_total_failed_bytes += m_torrent_file->piece_size(index);
+
+ std::vector<void*> downloaders;
+ m_picker->get_downloaders(downloaders, index);
+
+ // decrease the trust point of all peers that sent
+ // parts of this piece.
+ // first, build a set of all peers that participated
+ std::set<void*> peers;
+ std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { (*i)->on_piece_failed(index); } catch (std::exception&) {}
+ }
+#endif
+
+ for (std::set<void*>::iterator i = peers.begin()
+ , end(peers.end()); i != end; ++i)
+ {
+ policy::peer* p = static_cast<policy::peer*>(*i);
+ if (p == 0) continue;
+ if (p->connection) p->connection->received_invalid_data(index);
+
+ // either, we have received too many failed hashes
+ // or this was the only peer that sent us this piece.
+ // TODO: make this a changable setting
+ if (p->trust_points <= -7
+ || peers.size() == 1)
+ {
+ // we don't trust this peer anymore
+ // ban it.
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(peer_ban_alert(
+ p->ip
+ , get_handle()
+ , "banning peer because of too many corrupt pieces"));
+ }
+
+ // mark the peer as banned
+ p->banned = true;
+
+ if (p->connection)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING)
+ (*p->connection->m_logger) << "*** BANNING PEER [ " << p->ip
+ << " ] 'too many corrupt pieces'\n";
+#endif
+ p->connection->disconnect();
+ }
+ }
+ }
+
+ // we have to let the piece_picker know that
+ // this piece failed the check as it can restore it
+ // and mark it as being interesting for download
+ // TODO: do this more intelligently! and keep track
+ // of how much crap (data that failed hash-check) and
+ // how much redundant data we have downloaded
+ // if some clients has sent more than one piece
+ // start with redownloading the pieces that the client
+ // that has sent the least number of pieces
+ m_picker->restore_piece(index);
+ TORRENT_ASSERT(m_storage);
+ m_storage->mark_failed(index);
+
+ TORRENT_ASSERT(m_have_pieces[index] == false);
+ }
+
+ void torrent::abort()
+ {
+ INVARIANT_CHECK;
+
+ m_abort = true;
+ // if the torrent is paused, it doesn't need
+ // to announce with even=stopped again.
+ if (!m_paused)
+ m_event = tracker_request::stopped;
+ // disconnect all peers and close all
+ // files belonging to the torrents
+
+#if defined(TORRENT_VERBOSE_LOGGING)
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ (*(*i)->m_logger) << "*** ABORTING TORRENT\n";
+ }
+#endif
+
+ disconnect_all();
+ if (m_owning_storage.get())
+ m_storage->async_release_files(
+ bind(&torrent::on_files_released, shared_from_this(), _1, _2));
+
+ m_owning_storage = 0;
+ m_announce_timer.cancel();
+ m_host_resolver.cancel();
+ }
+
+ void torrent::on_files_deleted(int ret, disk_io_job const& j)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ if (alerts().should_post(alert::warning))
+ {
+ if (ret != 0)
+ {
+ alerts().post_alert(torrent_deleted_alert(get_handle(), "delete files failed: " + j.str));
+ }
+ else
+ {
+ alerts().post_alert(torrent_deleted_alert(get_handle(), "files deleted"));
+ }
+ }
+ }
+
+ void torrent::on_files_released(int ret, disk_io_job const& j)
+ {
+/*
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ if (alerts().should_post(alert::warning))
+ {
+ alerts().post_alert(torrent_paused_alert(get_handle(), "torrent paused"));
+ }
+*/
+ }
+
+ void torrent::on_torrent_paused(int ret, disk_io_job const& j)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ if (alerts().should_post(alert::warning))
+ {
+ alerts().post_alert(torrent_paused_alert(get_handle(), "torrent paused"));
+ }
+ }
+
+ void torrent::announce_piece(int index)
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < m_torrent_file->num_pieces());
+
+ std::vector<void*> downloaders;
+ m_picker->get_downloaders(downloaders, index);
+
+ // increase the trust point of all peers that sent
+ // parts of this piece.
+ std::set<void*> peers;
+ std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
+
+ if (!m_have_pieces[index])
+ m_num_pieces++;
+ m_have_pieces[index] = true;
+
+ TORRENT_ASSERT(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
+ == m_num_pieces);
+
+ m_picker->we_have(index);
+ for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
+ try { (*i)->announce_piece(index); } catch (std::exception&) {}
+
+ for (std::set<void*>::iterator i = peers.begin()
+ , end(peers.end()); i != end; ++i)
+ {
+ policy::peer* p = static_cast<policy::peer*>(*i);
+ if (p == 0) continue;
+ p->on_parole = false;
+ ++p->trust_points;
+ // TODO: make this limit user settable
+ if (p->trust_points > 20) p->trust_points = 20;
+ if (p->connection) p->connection->received_valid_data(index);
+ }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
+ }
+#endif
+ if (is_seed())
+ {
+ m_picker.reset();
+ if (m_ses.settings().free_torrent_hashes)
+ m_torrent_file->seed_free();
+ }
+ }
+
+ std::string torrent::tracker_login() const
+ {
+ if (m_username.empty() && m_password.empty()) return "";
+ return m_username + ":" + m_password;
+ }
+
+ void torrent::piece_availability(std::vector<int>& avail) const
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed())
+ {
+ avail.clear();
+ return;
+ }
+
+ m_picker->get_availability(avail);
+ }
+
+ void torrent::set_piece_priority(int index, int priority)
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed()) return;
+
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(m_picker.get());
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < m_torrent_file->num_pieces());
+
+ bool filter_updated = m_picker->set_piece_priority(index, priority);
+ if (filter_updated) update_peer_interest();
+ }
+
+ int torrent::piece_priority(int index) const
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed()) return 1;
+
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(m_picker.get());
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < m_torrent_file->num_pieces());
+
+ return m_picker->piece_priority(index);
+ }
+
+ void torrent::prioritize_pieces(std::vector<int> const& pieces)
+ {
+ INVARIANT_CHECK;
+
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed()) return;
+
+ TORRENT_ASSERT(m_picker.get());
+
+ int index = 0;
+ bool filter_updated = false;
+ for (std::vector<int>::const_iterator i = pieces.begin()
+ , end(pieces.end()); i != end; ++i, ++index)
+ {
+ TORRENT_ASSERT(*i >= 0);
+ TORRENT_ASSERT(*i <= 7);
+ filter_updated |= m_picker->set_piece_priority(index, *i);
+ }
+ if (filter_updated) update_peer_interest();
+ }
+
+ void torrent::piece_priorities(std::vector<int>& pieces) const
+ {
+ INVARIANT_CHECK;
+
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed())
+ {
+ pieces.clear();
+ pieces.resize(m_torrent_file->num_pieces(), 1);
+ return;
+ }
+
+ TORRENT_ASSERT(m_picker.get());
+ m_picker->piece_priorities(pieces);
+ }
+
+ namespace
+ {
+ void set_if_greater(int& piece_prio, int file_prio)
+ {
+ if (file_prio > piece_prio) piece_prio = file_prio;
+ }
+ }
+
+ void torrent::prioritize_files(std::vector<int> const& files)
+ {
+ INVARIANT_CHECK;
+
+ // this call is only valid on torrents with metadata
+ if (!valid_metadata() || is_seed()) return;
+
+ // the bitmask need to have exactly one bit for every file
+ // in the torrent
+ TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files());
+
+ size_type position = 0;
+
+ if (m_torrent_file->num_pieces() == 0) return;
+
+ int piece_length = m_torrent_file->piece_length();
+ // initialize the piece priorities to 0, then only allow
+ // setting higher priorities
+ std::vector<int> pieces(m_torrent_file->num_pieces(), 0);
+ for (int i = 0; i < int(files.size()); ++i)
+ {
+ size_type start = position;
+ size_type size = m_torrent_file->file_at(i).size;
+ if (size == 0) continue;
+ position += size;
+ // mark all pieces of the file with this file's priority
+ // but only if the priority is higher than the pieces
+ // already set (to avoid problems with overlapping pieces)
+ int start_piece = int(start / piece_length);
+ int last_piece = int((position - 1) / piece_length);
+ TORRENT_ASSERT(last_piece <= int(pieces.size()));
+ // if one piece spans several files, we might
+ // come here several times with the same start_piece, end_piece
+ std::for_each(pieces.begin() + start_piece
+ , pieces.begin() + last_piece + 1
+ , bind(&set_if_greater, _1, files[i]));
+ }
+ prioritize_pieces(pieces);
+ update_peer_interest();
+ }
+
+ // updates the interested flag in peers
+ void torrent::update_peer_interest()
+ {
+ for (peer_iterator i = begin(); i != end(); ++i)
+ (*i)->update_interest();
+ }
+
+ void torrent::filter_piece(int index, bool filter)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed()) return;
+
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(m_picker.get());
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < m_torrent_file->num_pieces());
+
+ m_picker->set_piece_priority(index, filter ? 1 : 0);
+ update_peer_interest();
+ }
+
+ void torrent::filter_pieces(std::vector<bool> const& bitmask)
+ {
+ INVARIANT_CHECK;
+
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed()) return;
+
+ TORRENT_ASSERT(m_picker.get());
+
+ int index = 0;
+ for (std::vector<bool>::const_iterator i = bitmask.begin()
+ , end(bitmask.end()); i != end; ++i, ++index)
+ {
+ if ((m_picker->piece_priority(index) == 0) == *i) continue;
+ if (*i)
+ m_picker->set_piece_priority(index, 0);
+ else
+ m_picker->set_piece_priority(index, 1);
+ }
+ update_peer_interest();
+ }
+
+ bool torrent::is_piece_filtered(int index) const
+ {
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed()) return false;
+
+ TORRENT_ASSERT(m_picker.get());
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < m_torrent_file->num_pieces());
+
+ return m_picker->piece_priority(index) == 0;
+ }
+
+ void torrent::filtered_pieces(std::vector<bool>& bitmask) const
+ {
+ INVARIANT_CHECK;
+
+ // this call is only valid on torrents with metadata
+ TORRENT_ASSERT(valid_metadata());
+ if (is_seed())
+ {
+ bitmask.clear();
+ bitmask.resize(m_torrent_file->num_pieces(), false);
+ return;
+ }
+
+ TORRENT_ASSERT(m_picker.get());
+ m_picker->filtered_pieces(bitmask);
+ }
+
+ void torrent::filter_files(std::vector<bool> const& bitmask)
+ {
+ INVARIANT_CHECK;
+
+ // this call is only valid on torrents with metadata
+ if (!valid_metadata() || is_seed()) return;
+
+ // the bitmask need to have exactly one bit for every file
+ // in the torrent
+ TORRENT_ASSERT((int)bitmask.size() == m_torrent_file->num_files());
+
+ size_type position = 0;
+
+ if (m_torrent_file->num_pieces())
+ {
+ int piece_length = m_torrent_file->piece_length();
+ // mark all pieces as filtered, then clear the bits for files
+ // that should be downloaded
+ std::vector<bool> piece_filter(m_torrent_file->num_pieces(), true);
+ for (int i = 0; i < (int)bitmask.size(); ++i)
+ {
+ size_type start = position;
+ position += m_torrent_file->file_at(i).size;
+ // is the file selected for download?
+ if (!bitmask[i])
+ {
+ // mark all pieces of the file as downloadable
+ int start_piece = int(start / piece_length);
+ int last_piece = int(position / piece_length);
+ // if one piece spans several files, we might
+ // come here several times with the same start_piece, end_piece
+ std::fill(piece_filter.begin() + start_piece, piece_filter.begin()
+ + last_piece + 1, false);
+ }
+ }
+ filter_pieces(piece_filter);
+ }
+ }
+
+ void torrent::replace_trackers(std::vector<announce_entry> const& urls)
+ {
+ m_trackers = urls;
+ if (m_currently_trying_tracker >= (int)m_trackers.size())
+ m_currently_trying_tracker = (int)m_trackers.size()-1;
+ m_last_working_tracker = -1;
+ }
+
+ tracker_request torrent::generate_tracker_request()
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_trackers.empty());
+
+ m_next_request = time_now() + seconds(tracker_retry_delay_max);
+
+ tracker_request req;
+ req.info_hash = m_torrent_file->info_hash();
+ req.pid = m_ses.get_peer_id();
+ req.downloaded = m_stat.total_payload_download();
+ req.uploaded = m_stat.total_payload_upload();
+ req.left = bytes_left();
+ if (req.left == -1) req.left = 16*1024;
+ req.event = m_event;
+ tcp::endpoint ep = m_ses.get_ipv6_interface();
+ if (ep != tcp::endpoint())
+ req.ipv6 = ep.address().to_string();
+
+ if (m_event != tracker_request::stopped)
+ m_event = tracker_request::none;
+ req.url = m_trackers[m_currently_trying_tracker].url;
+ req.num_want = m_settings.num_want;
+ // if we are aborting. we don't want any new peers
+ if (req.event == tracker_request::stopped)
+ req.num_want = 0;
+
+ // default initialize, these should be set by caller
+ // before passing the request to the tracker_manager
+ req.listen_port = 0;
+ req.key = 0;
+
+ return req;
+ }
+
+ void torrent::choke_peer(peer_connection& c)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!c.is_choked());
+ TORRENT_ASSERT(m_num_uploads > 0);
+ c.send_choke();
+ --m_num_uploads;
+ }
+
+ bool torrent::unchoke_peer(peer_connection& c)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(c.is_choked());
+ if (m_num_uploads >= m_max_uploads) return false;
+ c.send_unchoke();
+ ++m_num_uploads;
+ return true;
+ }
+
+ void torrent::cancel_block(piece_block block)
+ {
+ INVARIANT_CHECK;
+
+ for (peer_iterator i = m_connections.begin()
+ , end(m_connections.end()); i != end; ++i)
+ {
+ (*i)->cancel_request(block);
+ }
+ }
+
+ void torrent::remove_peer(peer_connection* p) try
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(p != 0);
+
+ peer_iterator i = m_connections.find(p);
+ if (i == m_connections.end())
+ {
+ TORRENT_ASSERT(false);
+ return;
+ }
+
+ if (ready_for_connections())
+ {
+ TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
+
+ if (p->is_seed())
+ {
+ if (m_picker.get())
+ {
+ TORRENT_ASSERT(!is_seed());
+ m_picker->dec_refcount_all();
+ }
+ }
+ else
+ {
+ // if we're a seed, we don't keep track of piece availability
+ if (!is_seed())
+ {
+ const std::vector<bool>& pieces = p->get_bitfield();
+
+ for (std::vector<bool>::const_iterator i = pieces.begin();
+ i != pieces.end(); ++i)
+ {
+ if (*i) peer_lost(static_cast<int>(i - pieces.begin()));
+ }
+ }
+ }
+ }
+
+ if (!p->is_choked())
+ --m_num_uploads;
+
+ m_policy.connection_closed(*p);
+ p->set_peer_info(0);
+ TORRENT_ASSERT(i != m_connections.end());
+ m_connections.erase(i);
+
+ // remove from bandwidth request-queue
+ for (int c = 0; c < 2; ++c)
+ {
+ for (queue_t::iterator i = m_bandwidth_queue[c].begin()
+ , end(m_bandwidth_queue[c].end()); i != end; ++i)
+ {
+ if (i->peer != p) continue;
+ m_bandwidth_queue[c].erase(i);
+ break;
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+#ifndef NDEBUG
+ std::string err = e.what();
+#endif
+ TORRENT_ASSERT(false);
+ };
+
+ void torrent::connect_to_url_seed(std::string const& url)
+ {
+ INVARIANT_CHECK;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << time_now_string() << " resolving web seed: " << url << "\n";
+#endif
+
+ m_resolving_web_seeds.insert(url);
+ proxy_settings const& ps = m_ses.web_seed_proxy();
+ if (ps.type == proxy_settings::http
+ || ps.type == proxy_settings::http_pw)
+ {
+ // use proxy
+ tcp::resolver::query q(ps.hostname
+ , boost::lexical_cast<std::string>(ps.port));
+ m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
+ bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url)));
+ }
+ else
+ {
+ std::string protocol;
+ std::string auth;
+ std::string hostname;
+ int port;
+ std::string path;
+ boost::tie(protocol, auth, hostname, port, path)
+ = parse_url_components(url);
+
+ // TODO: should auth be used here?
+
+ tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
+ m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
+ bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
+ , tcp::endpoint())));
+ }
+
+ }
+
+ void torrent::on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
+ , std::string url) try
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << url << "\n";
+#endif
+
+ if (e || host == tcp::resolver::iterator())
+ {
+ if (m_ses.m_alerts.should_post(alert::warning))
+ {
+ std::stringstream msg;
+ msg << "HTTP seed proxy hostname lookup failed: " << e.message();
+ m_ses.m_alerts.post_alert(
+ url_seed_alert(get_handle(), url, msg.str()));
+ }
+
+ // the name lookup failed for the http host. Don't try
+ // this host again
+ remove_url_seed(url);
+ return;
+ }
+
+ if (m_ses.is_aborted()) return;
+
+ tcp::endpoint a(host->endpoint());
+
+ using boost::tuples::ignore;
+ std::string hostname;
+ int port;
+ boost::tie(ignore, ignore, hostname, port, ignore)
+ = parse_url_components(url);
+
+ if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
+ {
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()
+ , "proxy (" + hostname + ") blocked by IP filter"));
+ }
+ return;
+ }
+
+ tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
+ m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
+ bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a)));
+ }
+ catch (std::exception&)
+ {
+ TORRENT_ASSERT(false);
+ };
+
+ void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
+ , std::string url, tcp::endpoint proxy) try
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << time_now_string() << " completed resolve: " << url << "\n";
+#endif
+
+ std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
+ if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
+
+ if (e || host == tcp::resolver::iterator())
+ {
+ if (m_ses.m_alerts.should_post(alert::warning))
+ {
+ std::stringstream msg;
+ msg << "HTTP seed hostname lookup failed: " << e.message();
+ m_ses.m_alerts.post_alert(
+ url_seed_alert(get_handle(), url, msg.str()));
+ }
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
+#endif
+
+ // the name lookup failed for the http host. Don't try
+ // this host again
+ remove_url_seed(url);
+ return;
+ }
+
+ if (m_ses.is_aborted()) return;
+
+ tcp::endpoint a(host->endpoint());
+
+ if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
+ {
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()
+ , "web seed (" + url + ") blocked by IP filter"));
+ }
+ return;
+ }
+
+ boost::shared_ptr<socket_type> s(new socket_type);
+
+ bool ret = instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy(), *s);
+ TORRENT_ASSERT(ret);
+
+ if (m_ses.web_seed_proxy().type == proxy_settings::http
+ || m_ses.web_seed_proxy().type == proxy_settings::http_pw)
+ {
+ // the web seed connection will talk immediately to
+ // the proxy, without requiring CONNECT support
+ s->get<http_stream>().set_no_connect(true);
+ }
+ boost::intrusive_ptr<peer_connection> c(new web_peer_connection(
+ m_ses, shared_from_this(), s, a, url, 0));
+
+#ifndef NDEBUG
+ c->m_in_constructor = false;
+#endif
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
+ if (pp) c->add_extension(pp);
+ }
+#endif
+
+ try
+ {
+ // add the newly connected peer to this torrent's peer list
+ m_connections.insert(boost::get_pointer(c));
+ m_ses.m_connections.insert(c);
+
+ m_ses.m_half_open.enqueue(
+ bind(&peer_connection::connect, c, _1)
+ , bind(&peer_connection::timed_out, c)
+ , seconds(settings().peer_connect_timeout));
+ }
+ catch (std::exception& e)
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
+#endif
+
+ // TODO: post an error alert!
+// std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
+// if (i != m_connections.end()) m_connections.erase(i);
+ m_ses.connection_failed(c, a, e.what());
+ c->disconnect();
+ }
+ }
+ catch (std::exception& exc)
+ {
+#ifndef NDEBUG
+ std::cerr << exc.what() << std::endl;
+#endif
+ TORRENT_ASSERT(false);
+ };
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ namespace
+ {
+ unsigned long swap_bytes(unsigned long a)
+ {
+ return (a >> 24) | ((a & 0xff0000) >> 8) | ((a & 0xff00) << 8) | (a << 24);
+ }
+ }
+
+ void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
+ {
+ if (m_resolving_country
+ || p->has_country()
+ || p->is_connecting()
+ || p->is_queued()
+ || p->in_handshake()
+ || p->remote().address().is_v6()) return;
+
+ m_resolving_country = true;
+ asio::ip::address_v4 reversed(swap_bytes(p->remote().address().to_v4().to_ulong()));
+ tcp::resolver::query q(reversed.to_string() + ".zz.countries.nerd.dk", "0");
+ m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
+ bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p)));
+ }
+
+ namespace
+ {
+ struct country_entry
+ {
+ int code;
+ char const* name;
+ };
+ }
+
+ void torrent::on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i
+ , intrusive_ptr<peer_connection> p) const
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ m_resolving_country = false;
+
+ // must be ordered in increasing order
+ static const country_entry country_map[] =
+ {
+ { 4, "AF"}, { 8, "AL"}, { 10, "AQ"}, { 12, "DZ"}, { 16, "AS"}
+ , { 20, "AD"}, { 24, "AO"}, { 28, "AG"}, { 31, "AZ"}, { 32, "AR"}
+ , { 36, "AU"}, { 40, "AT"}, { 44, "BS"}, { 48, "BH"}, { 50, "BD"}
+ , { 51, "AM"}, { 52, "BB"}, { 56, "BE"}, { 60, "BM"}, { 64, "BT"}
+ , { 68, "BO"}, { 70, "BA"}, { 72, "BW"}, { 74, "BV"}, { 76, "BR"}
+ , { 84, "BZ"}, { 86, "IO"}, { 90, "SB"}, { 92, "VG"}, { 96, "BN"}
+ , {100, "BG"}, {104, "MM"}, {108, "BI"}, {112, "BY"}, {116, "KH"}
+ , {120, "CM"}, {124, "CA"}, {132, "CV"}, {136, "KY"}, {140, "CF"}
+ , {144, "LK"}, {148, "TD"}, {152, "CL"}, {156, "CN"}, {158, "TW"}
+ , {162, "CX"}, {166, "CC"}, {170, "CO"}, {174, "KM"}, {175, "YT"}
+ , {178, "CG"}, {180, "CD"}, {184, "CK"}, {188, "CR"}, {191, "HR"}
+ , {192, "CU"}, {203, "CZ"}, {204, "BJ"}, {208, "DK"}, {212, "DM"}
+ , {214, "DO"}, {218, "EC"}, {222, "SV"}, {226, "GQ"}, {231, "ET"}
+ , {232, "ER"}, {233, "EE"}, {234, "FO"}, {238, "FK"}, {239, "GS"}
+ , {242, "FJ"}, {246, "FI"}, {248, "AX"}, {250, "FR"}, {254, "GF"}
+ , {258, "PF"}, {260, "TF"}, {262, "DJ"}, {266, "GA"}, {268, "GE"}
+ , {270, "GM"}, {275, "PS"}, {276, "DE"}, {288, "GH"}, {292, "GI"}
+ , {296, "KI"}, {300, "GR"}, {304, "GL"}, {308, "GD"}, {312, "GP"}
+ , {316, "GU"}, {320, "GT"}, {324, "GN"}, {328, "GY"}, {332, "HT"}
+ , {334, "HM"}, {336, "VA"}, {340, "HN"}, {344, "HK"}, {348, "HU"}
+ , {352, "IS"}, {356, "IN"}, {360, "ID"}, {364, "IR"}, {368, "IQ"}
+ , {372, "IE"}, {376, "IL"}, {380, "IT"}, {384, "CI"}, {388, "JM"}
+ , {392, "JP"}, {398, "KZ"}, {400, "JO"}, {404, "KE"}, {408, "KP"}
+ , {410, "KR"}, {414, "KW"}, {417, "KG"}, {418, "LA"}, {422, "LB"}
+ , {426, "LS"}, {428, "LV"}, {430, "LR"}, {434, "LY"}, {438, "LI"}
+ , {440, "LT"}, {442, "LU"}, {446, "MO"}, {450, "MG"}, {454, "MW"}
+ , {458, "MY"}, {462, "MV"}, {466, "ML"}, {470, "MT"}, {474, "MQ"}
+ , {478, "MR"}, {480, "MU"}, {484, "MX"}, {492, "MC"}, {496, "MN"}
+ , {498, "MD"}, {500, "MS"}, {504, "MA"}, {508, "MZ"}, {512, "OM"}
+ , {516, "NA"}, {520, "NR"}, {524, "NP"}, {528, "NL"}, {530, "AN"}
+ , {533, "AW"}, {540, "NC"}, {548, "VU"}, {554, "NZ"}, {558, "NI"}
+ , {562, "NE"}, {566, "NG"}, {570, "NU"}, {574, "NF"}, {578, "NO"}
+ , {580, "MP"}, {581, "UM"}, {583, "FM"}, {584, "MH"}, {585, "PW"}
+ , {586, "PK"}, {591, "PA"}, {598, "PG"}, {600, "PY"}, {604, "PE"}
+ , {608, "PH"}, {612, "PN"}, {616, "PL"}, {620, "PT"}, {624, "GW"}
+ , {626, "TL"}, {630, "PR"}, {634, "QA"}, {634, "QA"}, {638, "RE"}
+ , {642, "RO"}, {643, "RU"}, {646, "RW"}, {654, "SH"}, {659, "KN"}
+ , {660, "AI"}, {662, "LC"}, {666, "PM"}, {670, "VC"}, {674, "SM"}
+ , {678, "ST"}, {682, "SA"}, {686, "SN"}, {690, "SC"}, {694, "SL"}
+ , {702, "SG"}, {703, "SK"}, {704, "VN"}, {705, "SI"}, {706, "SO"}
+ , {710, "ZA"}, {716, "ZW"}, {724, "ES"}, {732, "EH"}, {736, "SD"}
+ , {740, "SR"}, {744, "SJ"}, {748, "SZ"}, {752, "SE"}, {756, "CH"}
+ , {760, "SY"}, {762, "TJ"}, {764, "TH"}, {768, "TG"}, {772, "TK"}
+ , {776, "TO"}, {780, "TT"}, {784, "AE"}, {788, "TN"}, {792, "TR"}
+ , {795, "TM"}, {796, "TC"}, {798, "TV"}, {800, "UG"}, {804, "UA"}
+ , {807, "MK"}, {818, "EG"}, {826, "GB"}, {834, "TZ"}, {840, "US"}
+ , {850, "VI"}, {854, "BF"}, {858, "UY"}, {860, "UZ"}, {862, "VE"}
+ , {876, "WF"}, {882, "WS"}, {887, "YE"}, {891, "CS"}, {894, "ZM"}
+ };
+
+ if (error || i == tcp::resolver::iterator())
+ {
+ // this is used to indicate that we shouldn't
+ // try to resolve it again
+ p->set_country("--");
+ return;
+ }
+
+ while (i != tcp::resolver::iterator()
+ && !i->endpoint().address().is_v4()) ++i;
+ if (i != tcp::resolver::iterator())
+ {
+ // country is an ISO 3166 country code
+ int country = i->endpoint().address().to_v4().to_ulong() & 0xffff;
+
+ // look up the country code in the map
+ const int size = sizeof(country_map)/sizeof(country_map[0]);
+ country_entry tmp = {country, ""};
+ country_entry const* i =
+ std::lower_bound(country_map, country_map + size, tmp
+ , bind(&country_entry::code, _1) < bind(&country_entry::code, _2));
+ if (i == country_map + size
+ || i->code != country)
+ {
+ // unknown country!
+ p->set_country("!!");
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n";
+#endif
+ return;
+ }
+
+ p->set_country(i->name);
+ }
+ }
+#endif
+
+ void torrent::get_peer_info(std::vector<peer_info>& v)
+ {
+ v.clear();
+ for (peer_iterator i = begin();
+ i != end(); ++i)
+ {
+ peer_connection* peer = *i;
+
+ // incoming peers that haven't finished the handshake should
+ // not be included in this list
+ if (peer->associated_torrent().expired()) continue;
+
+ v.push_back(peer_info());
+ peer_info& p = v.back();
+
+ peer->get_peer_info(p);
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ if (resolving_countries())
+ resolve_peer_country(intrusive_ptr<peer_connection>(peer));
+#endif
+ }
+ }
+
+ void torrent::get_download_queue(std::vector<partial_piece_info>& queue)
+ {
+ queue.clear();
+ if (!valid_metadata() || is_seed()) return;
+ piece_picker const& p = picker();
+ std::vector<piece_picker::downloading_piece> const& q
+ = p.get_download_queue();
+
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i
+ = q.begin(); i != q.end(); ++i)
+ {
+ partial_piece_info pi;
+ pi.piece_state = (partial_piece_info::state_t)i->state;
+ pi.blocks_in_piece = p.blocks_in_piece(i->index);
+ pi.finished = (int)i->finished;
+ pi.writing = (int)i->writing;
+ pi.requested = (int)i->requested;
+ int piece_size = int(torrent_file().piece_size(i->index));
+ for (int j = 0; j < pi.blocks_in_piece; ++j)
+ {
+ block_info& bi = pi.blocks[j];
+ bi.state = i->info[j].state;
+ bi.block_size = j < pi.blocks_in_piece - 1 ? m_block_size
+ : piece_size - (j * m_block_size);
+ bool complete = bi.state == block_info::writing
+ || bi.state == block_info::finished;
+ if (i->info[j].peer == 0)
+ {
+ bi.peer = tcp::endpoint();
+ bi.bytes_progress = complete ? bi.block_size : 0;
+ }
+ else
+ {
+ policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
+ if (p->connection)
+ {
+ bi.peer = p->connection->remote();
+ if (bi.state == block_info::requested)
+ {
+ boost::optional<piece_block_progress> pbp
+ = p->connection->downloading_piece_progress();
+ if (pbp && pbp->piece_index == i->index && pbp->block_index == j)
+ {
+ bi.bytes_progress = pbp->bytes_downloaded;
+ TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
+ }
+ else
+ {
+ bi.bytes_progress = 0;
+ }
+ }
+ else
+ {
+ bi.bytes_progress = complete ? bi.block_size : 0;
+ }
+ }
+ else
+ {
+ bi.peer = p->ip;
+ bi.bytes_progress = complete ? bi.block_size : 0;
+ }
+ }
+
+ pi.blocks[j].num_peers = i->info[j].num_peers;
+ }
+ pi.piece_index = i->index;
+ queue.push_back(pi);
+ }
+
+ }
+
+ bool torrent::connect_to_peer(policy::peer* peerinfo)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(peerinfo);
+ TORRENT_ASSERT(peerinfo->connection == 0);
+ peerinfo->connected = time_now();
+#ifndef NDEBUG
+ // this asserts that we don't have duplicates in the policy's peer list
+ peer_iterator i_ = std::find_if(m_connections.begin(), m_connections.end()
+ , bind(&peer_connection::remote, _1) == peerinfo->ip);
+ TORRENT_ASSERT(i_ == m_connections.end()
+ || dynamic_cast<bt_peer_connection*>(*i_) == 0);
+#endif
+
+ TORRENT_ASSERT(want_more_peers());
+ TORRENT_ASSERT(m_ses.num_connections() < m_ses.max_connections());
+
+ tcp::endpoint const& a(peerinfo->ip);
+ TORRENT_ASSERT((m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) == 0);
+
+ boost::shared_ptr<socket_type> s(new socket_type);
+
+ bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
+ TORRENT_ASSERT(ret);
+
+ boost::intrusive_ptr<peer_connection> c(new bt_peer_connection(
+ m_ses, shared_from_this(), s, a, peerinfo));
+
+#ifndef NDEBUG
+ c->m_in_constructor = false;
+#endif
+
+ try
+ {
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
+ if (pp) c->add_extension(pp);
+ }
+#endif
+
+ // add the newly connected peer to this torrent's peer list
+ m_connections.insert(boost::get_pointer(c));
+ m_ses.m_connections.insert(c);
+
+ int timeout = settings().peer_connect_timeout;
+ if (peerinfo) timeout += 3 * peerinfo->failcount;
+
+ m_ses.m_half_open.enqueue(
+ bind(&peer_connection::connect, c, _1)
+ , bind(&peer_connection::timed_out, c)
+ , seconds(timeout));
+ }
+ catch (std::exception& e)
+ {
+ std::set<peer_connection*>::iterator i
+ = m_connections.find(boost::get_pointer(c));
+ if (i != m_connections.end()) m_connections.erase(i);
+ m_ses.connection_failed(c, a, e.what());
+ c->disconnect();
+ return false;
+ }
+ peerinfo->connection = c.get();
+ return true;
+ }
+
+ void torrent::set_metadata(entry const& metadata)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(!m_torrent_file->is_valid());
+ m_torrent_file->parse_info_section(metadata);
+
+ init();
+
+ boost::mutex::scoped_lock(m_checker.m_mutex);
+
+ boost::shared_ptr<aux::piece_checker_data> d(
+ new aux::piece_checker_data);
+ d->torrent_ptr = shared_from_this();
+ d->save_path = m_save_path;
+ d->info_hash = m_torrent_file->info_hash();
+ // add the torrent to the queue to be checked
+ m_checker.m_torrents.push_back(d);
+ typedef session_impl::torrent_map torrent_map;
+ torrent_map::iterator i = m_ses.m_torrents.find(
+ m_torrent_file->info_hash());
+ TORRENT_ASSERT(i != m_ses.m_torrents.end());
+ m_ses.m_torrents.erase(i);
+ // and notify the thread that it got another
+ // job in its queue
+ m_checker.m_cond.notify_one();
+
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(metadata_received_alert(
+ get_handle(), "metadata successfully received from swarm"));
+ }
+ }
+
+ void torrent::attach_peer(peer_connection* p)
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(p != 0);
+ TORRENT_ASSERT(!p->is_local());
+
+ if (m_ses.m_connections.find(p) == m_ses.m_connections.end())
+ {
+ throw protocol_error("peer is not properly constructed");
+ }
+
+ if (m_ses.is_aborted())
+ {
+ throw protocol_error("session is closing");
+ }
+
+ if (int(m_connections.size()) >= m_max_connections)
+ {
+ throw protocol_error("reached connection limit");
+ }
+
+ try
+ {
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
+ if (pp) p->add_extension(pp);
+ }
+#endif
+ m_policy.new_connection(*p);
+ }
+ catch (std::exception&)
+ {
+ throw;
+ }
+ TORRENT_ASSERT(m_connections.find(p) == m_connections.end());
+ peer_iterator ci = m_connections.insert(p).first;
+ TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint());
+
+#ifndef NDEBUG
+ m_policy.check_invariant();
+#endif
+ }
+
+ bool torrent::want_more_peers() const
+ {
+ return int(m_connections.size()) < m_max_connections
+ && m_ses.m_half_open.free_slots()
+ && !m_paused;
+ }
+
+ void torrent::disconnect_all()
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+ while (!m_connections.empty())
+ {
+ peer_connection* p = *m_connections.begin();
+ TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
+
+#if defined(TORRENT_VERBOSE_LOGGING)
+ if (m_abort)
+ (*p->m_logger) << "*** CLOSING CONNECTION 'aborting'\n";
+ else
+ (*p->m_logger) << "*** CLOSING CONNECTION 'pausing'\n";
+#endif
+#ifndef NDEBUG
+ std::size_t size = m_connections.size();
+#endif
+
+ if (p->is_disconnecting())
+ m_connections.erase(m_connections.begin());
+ else
+ p->disconnect();
+ TORRENT_ASSERT(m_connections.size() <= size);
+ }
+ }
+
+ int torrent::bandwidth_throttle(int channel) const
+ {
+ return m_bandwidth_limit[channel].throttle();
+ }
+
+ void torrent::request_bandwidth(int channel
+ , boost::intrusive_ptr<peer_connection> const& p
+ , int priority)
+ {
+ TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0);
+ TORRENT_ASSERT(p->max_assignable_bandwidth(channel) > 0);
+ int block_size = m_bandwidth_limit[channel].throttle() / 10;
+ if (block_size <= 0) block_size = 1;
+
+ if (m_bandwidth_limit[channel].max_assignable() > 0)
+ {
+ perform_bandwidth_request(channel, p, block_size, priority);
+ }
+ else
+ {
+ // skip forward in the queue until we find a prioritized peer
+ // or hit the front of it.
+ queue_t::reverse_iterator i = m_bandwidth_queue[channel].rbegin();
+ while (i != m_bandwidth_queue[channel].rend() && priority > i->priority)
+ {
+ ++i->priority;
+ ++i;
+ }
+ m_bandwidth_queue[channel].insert(i.base(), bw_queue_entry<peer_connection, torrent>(
+ p, block_size, priority));
+ }
+ }
+
+ void torrent::expire_bandwidth(int channel, int amount)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ TORRENT_ASSERT(amount > 0);
+ m_bandwidth_limit[channel].expire(amount);
+ queue_t tmp;
+ while (!m_bandwidth_queue[channel].empty())
+ {
+ bw_queue_entry<peer_connection, torrent> qe = m_bandwidth_queue[channel].front();
+ if (m_bandwidth_limit[channel].max_assignable() == 0)
+ break;
+ m_bandwidth_queue[channel].pop_front();
+ if (qe.peer->max_assignable_bandwidth(channel) <= 0)
+ {
+ TORRENT_ASSERT(m_ses.m_bandwidth_manager[channel]->is_in_history(qe.peer.get()));
+ if (!qe.peer->is_disconnecting()) tmp.push_back(qe);
+ continue;
+ }
+ perform_bandwidth_request(channel, qe.peer
+ , qe.max_block_size, qe.priority);
+ }
+ m_bandwidth_queue[channel].insert(m_bandwidth_queue[channel].begin(), tmp.begin(), tmp.end());
+ }
+
+ void torrent::perform_bandwidth_request(int channel
+ , boost::intrusive_ptr<peer_connection> const& p
+ , int block_size
+ , int priority)
+ {
+ m_ses.m_bandwidth_manager[channel]->request_bandwidth(p
+ , block_size, priority);
+ m_bandwidth_limit[channel].assign(block_size);
+ }
+
+ void torrent::assign_bandwidth(int channel, int amount, int blk)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ TORRENT_ASSERT(amount > 0);
+ TORRENT_ASSERT(amount <= blk);
+ if (amount < blk)
+ expire_bandwidth(channel, blk - amount);
+ }
+
+ // called when torrent is finished (all interesting
+ // pieces have been downloaded)
+ void torrent::finished()
+ {
+ INVARIANT_CHECK;
+
+ if (alerts().should_post(alert::info))
+ {
+ alerts().post_alert(torrent_finished_alert(
+ get_handle()
+ , "torrent has finished downloading"));
+ }
+
+ // disconnect all seeds
+ // TODO: should disconnect all peers that have the pieces we have
+ // not just seeds
+ std::vector<peer_connection*> seeds;
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ peer_connection* p = *i;
+ TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
+ if (p->is_seed())
+ {
+#if defined(TORRENT_VERBOSE_LOGGING)
+ (*p->m_logger) << "*** SEED, CLOSING CONNECTION\n";
+#endif
+ seeds.push_back(p);
+ }
+ }
+ std::for_each(seeds.begin(), seeds.end()
+ , bind(&peer_connection::disconnect, _1));
+
+ TORRENT_ASSERT(m_storage);
+ // we need to keep the object alive during this operation
+ m_storage->async_release_files(
+ bind(&torrent::on_files_released, shared_from_this(), _1, _2));
+ }
+
+ // called when torrent is complete (all pieces downloaded)
+ void torrent::completed()
+ {
+ INVARIANT_CHECK;
+
+ // make the next tracker request
+ // be a completed-event
+ m_event = tracker_request::completed;
+ force_tracker_request();
+ }
+
+ // this will move the tracker with the given index
+ // to a prioritized position in the list (move it towards
+ // the begining) and return the new index to the tracker.
+ int torrent::prioritize_tracker(int index)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(index >= 0);
+ if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
+
+ while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
+ {
+ std::swap(m_trackers[index].url, m_trackers[index-1].url);
+ --index;
+ }
+ return index;
+ }
+
+ void torrent::try_next_tracker()
+ {
+ INVARIANT_CHECK;
+
+ ++m_currently_trying_tracker;
+
+ if ((unsigned)m_currently_trying_tracker >= m_trackers.size())
+ {
+ int delay = tracker_retry_delay_min
+ + (std::min)(m_failed_trackers, (int)tracker_failed_max)
+ * (tracker_retry_delay_max - tracker_retry_delay_min)
+ / tracker_failed_max;
+
+ ++m_failed_trackers;
+ // if we've looped the tracker list, wait a bit before retrying
+ m_currently_trying_tracker = 0;
+ m_next_request = time_now() + seconds(delay);
+
+#ifndef TORRENT_DISABLE_DHT
+ if (m_abort) return;
+
+ // only start the announce if we want to announce with the dht
+ ptime now = time_now();
+ if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
+ {
+ // force the DHT to reannounce
+ m_last_dht_announce = now;
+ boost::weak_ptr<torrent> self(shared_from_this());
+ m_ses.m_dht->announce(m_torrent_file->info_hash()
+ , m_ses.m_listen_sockets.front().external_port
+ , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
+ }
+#endif
+
+ }
+ else
+ {
+ // don't delay before trying the next tracker
+ m_next_request = time_now();
+ }
+
+ }
+
+ bool torrent::check_fastresume(aux::piece_checker_data& data)
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(valid_metadata());
+ bool done = true;
+ try
+ {
+ std::string error_msg;
+ TORRENT_ASSERT(m_storage);
+ TORRENT_ASSERT(m_owning_storage.get());
+ done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
+ , m_storage_mode, error_msg);
+
+ if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
+ {
+ m_ses.m_alerts.post_alert(fastresume_rejected_alert(
+ get_handle(), error_msg));
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ (*m_ses.m_logger) << "fastresume data for "
+ << torrent_file().name() << " rejected: "
+ << error_msg << "\n";
+#endif
+ }
+ }
+ catch (std::exception& e)
+ {
+ // probably means file permission failure or invalid filename
+ std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
+ m_num_pieces = 0;
+
+ if (m_ses.m_alerts.should_post(alert::fatal))
+ {
+ m_ses.m_alerts.post_alert(
+ file_error_alert(
+ get_handle()
+ , e.what()));
+ }
+ pause();
+ }
+ return done;
+ }
+
+ std::pair<bool, float> torrent::check_files()
+ {
+ TORRENT_ASSERT(m_torrent_file->is_valid());
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_owning_storage.get());
+
+ std::pair<bool, float> progress(true, 1.f);
+ try
+ {
+ TORRENT_ASSERT(m_storage);
+ progress = m_storage->check_files(m_have_pieces, m_num_pieces
+ , m_ses.m_mutex);
+ }
+ catch (std::exception& e)
+ {
+ // probably means file permission failure or invalid filename
+ std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
+ m_num_pieces = 0;
+
+ if (m_ses.m_alerts.should_post(alert::fatal))
+ {
+ m_ses.m_alerts.post_alert(
+ file_error_alert(
+ get_handle()
+ , e.what()));
+ }
+ pause();
+ }
+
+ return progress;
+ }
+
+ void torrent::files_checked(std::vector<piece_picker::downloading_piece> const&
+ unfinished_pieces)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ TORRENT_ASSERT(m_torrent_file->is_valid());
+ INVARIANT_CHECK;
+
+ if (!is_seed())
+ {
+ // this is filled in with pieces that needs to be checked
+ // against its hashes.
+ std::vector<int> verify_pieces;
+ m_picker->files_checked(m_have_pieces, unfinished_pieces, verify_pieces);
+ if (m_sequenced_download_threshold > 0)
+ picker().set_sequenced_download_threshold(m_sequenced_download_threshold);
+ while (!verify_pieces.empty())
+ {
+ int piece = verify_pieces.back();
+ verify_pieces.pop_back();
+ async_verify_piece(piece, bind(&torrent::piece_finished
+ , shared_from_this(), piece, _1));
+ }
+ }
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { (*i)->on_files_checked(); } catch (std::exception&) {}
+ }
+#endif
+
+ if (is_seed())
+ {
+ m_picker.reset();
+ if (m_ses.settings().free_torrent_hashes)
+ m_torrent_file->seed_free();
+ }
+
+ if (!m_connections_initialized)
+ {
+ m_connections_initialized = true;
+ // all peer connections have to initialize themselves now that the metadata
+ // is available
+ for (torrent::peer_iterator i = m_connections.begin()
+ , end(m_connections.end()); i != end;)
+ {
+ try
+ {
+ (*i)->on_metadata();
+ (*i)->init();
+ ++i;
+ }
+ catch (std::exception& e)
+ {
+ // the connection failed, close it
+ torrent::peer_iterator j = i;
+ ++j;
+ m_ses.connection_failed(*i, (*i)->remote(), e.what());
+ i = j;
+ }
+ }
+ }
+#ifndef NDEBUG
+ m_files_checked = true;
+#endif
+ }
+
+ alert_manager& torrent::alerts() const
+ {
+ return m_ses.m_alerts;
+ }
+
+ fs::path torrent::save_path() const
+ {
+ if (m_owning_storage.get())
+ return m_owning_storage->save_path();
+ else
+ return m_save_path;
+ }
+
+ void torrent::move_storage(fs::path const& save_path)
+ {
+ INVARIANT_CHECK;
+
+ if (m_owning_storage.get())
+ {
+ m_owning_storage->async_move_storage(save_path
+ , bind(&torrent::on_storage_moved, shared_from_this(), _1, _2));
+ }
+ else
+ {
+ m_save_path = save_path;
+ }
+ }
+
+ void torrent::on_storage_moved(int ret, disk_io_job const& j)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ if (alerts().should_post(alert::warning))
+ {
+ alerts().post_alert(storage_moved_alert(get_handle(), j.str));
+ }
+ }
+
+ piece_manager& torrent::filesystem()
+ {
+ TORRENT_ASSERT(m_owning_storage.get());
+ return *m_owning_storage;
+ }
+
+
+ torrent_handle torrent::get_handle() const
+ {
+ return torrent_handle(&m_ses, &m_checker, m_torrent_file->info_hash());
+ }
+
+ session_settings const& torrent::settings() const
+ {
+ return m_ses.settings();
+ }
+
+#ifndef NDEBUG
+ void torrent::check_invariant() const
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
+ TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
+
+ for (int c = 0; c < 2; ++c)
+ {
+ queue_t::const_iterator j = m_bandwidth_queue[c].begin();
+ if (j == m_bandwidth_queue[c].end()) continue;
+ ++j;
+ for (queue_t::const_iterator i = m_bandwidth_queue[c].begin()
+ , end(m_bandwidth_queue[c].end()); i != end && j != end; ++i, ++j)
+ TORRENT_ASSERT(i->priority >= j->priority);
+ }
+
+ int num_uploads = 0;
+ std::map<piece_block, int> num_requests;
+ for (const_peer_iterator i = begin(); i != end(); ++i)
+ {
+ peer_connection const& p = *(*i);
+ for (std::deque<piece_block>::const_iterator i = p.request_queue().begin()
+ , end(p.request_queue().end()); i != end; ++i)
+ ++num_requests[*i];
+ for (std::deque<piece_block>::const_iterator i = p.download_queue().begin()
+ , end(p.download_queue().end()); i != end; ++i)
+ ++num_requests[*i];
+ if (!p.is_choked()) ++num_uploads;
+ torrent* associated_torrent = p.associated_torrent().lock().get();
+ if (associated_torrent != this)
+ TORRENT_ASSERT(false);
+ }
+ TORRENT_ASSERT(num_uploads == m_num_uploads);
+
+ if (has_picker())
+ {
+ for (std::map<piece_block, int>::iterator i = num_requests.begin()
+ , end(num_requests.end()); i != end; ++i)
+ {
+ if (!m_picker->is_downloaded(i->first))
+ TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second);
+ }
+ }
+
+ if (valid_metadata())
+ {
+ TORRENT_ASSERT(m_abort || int(m_have_pieces.size()) == m_torrent_file->num_pieces());
+ }
+ else
+ {
+ TORRENT_ASSERT(m_abort || m_have_pieces.empty());
+ }
+
+ for (policy::const_iterator i = m_policy.begin_peer()
+ , end(m_policy.end_peer()); i != end; ++i)
+ {
+ TORRENT_ASSERT(i->second.ip.address() == i->first);
+ }
+
+ size_type total_done = quantized_bytes_done();
+ if (m_torrent_file->is_valid())
+ {
+ if (is_seed())
+ TORRENT_ASSERT(total_done == m_torrent_file->total_size());
+ else
+ TORRENT_ASSERT(total_done != m_torrent_file->total_size());
+ }
+ else
+ {
+ TORRENT_ASSERT(total_done == 0);
+ }
+
+ if (m_picker && !m_abort)
+ {
+ // make sure that pieces that have completed the download
+ // of all their blocks are in the disk io thread's queue
+ // to be checked.
+ const std::vector<piece_picker::downloading_piece>& dl_queue
+ = m_picker->get_download_queue();
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i =
+ dl_queue.begin(); i != dl_queue.end(); ++i)
+ {
+ const int blocks_per_piece = m_picker->blocks_in_piece(i->index);
+
+ bool complete = true;
+ for (int j = 0; j < blocks_per_piece; ++j)
+ {
+ if (i->info[j].state == piece_picker::block_info::state_finished)
+ continue;
+ complete = false;
+ break;
+ }
+ if (complete && m_files_checked)
+ {
+ disk_io_job ret = m_ses.m_disk_thread.find_job(
+ m_owning_storage, -1, i->index);
+ TORRENT_ASSERT(ret.action == disk_io_job::hash || ret.action == disk_io_job::write);
+ TORRENT_ASSERT(ret.piece == i->index);
+ }
+ }
+ }
+
+// This check is very expensive.
+ TORRENT_ASSERT(m_num_pieces
+ == std::count(m_have_pieces.begin(), m_have_pieces.end(), true));
+ TORRENT_ASSERT(!valid_metadata() || m_block_size > 0);
+ TORRENT_ASSERT(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0);
+// if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
+ }
+#endif
+
+ void torrent::set_sequenced_download_threshold(int threshold)
+ {
+ if (has_picker())
+ {
+ picker().set_sequenced_download_threshold(threshold);
+ }
+ else
+ {
+ m_sequenced_download_threshold = threshold;
+ }
+ }
+
+
+ void torrent::set_max_uploads(int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ if (limit <= 0) limit = (std::numeric_limits<int>::max)();
+ m_max_uploads = limit;
+ }
+
+ void torrent::set_max_connections(int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ if (limit <= 0) limit = (std::numeric_limits<int>::max)();
+ m_max_connections = limit;
+ }
+
+ void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
+ , bind(&peer_connection::remote, _1) == ip);
+ if (i == m_connections.end()) return;
+ (*i)->set_upload_limit(limit);
+ }
+
+ void torrent::set_peer_download_limit(tcp::endpoint ip, int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
+ , bind(&peer_connection::remote, _1) == ip);
+ if (i == m_connections.end()) return;
+ (*i)->set_download_limit(limit);
+ }
+
+ void torrent::set_upload_limit(int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ if (limit <= 0) limit = (std::numeric_limits<int>::max)();
+ if (limit < num_peers() * 10) limit = num_peers() * 10;
+ m_bandwidth_limit[peer_connection::upload_channel].throttle(limit);
+ }
+
+ int torrent::upload_limit() const
+ {
+ int limit = m_bandwidth_limit[peer_connection::upload_channel].throttle();
+ if (limit == (std::numeric_limits<int>::max)()) limit = -1;
+ return limit;
+ }
+
+ void torrent::set_download_limit(int limit)
+ {
+ TORRENT_ASSERT(limit >= -1);
+ if (limit <= 0) limit = (std::numeric_limits<int>::max)();
+ if (limit < num_peers() * 10) limit = num_peers() * 10;
+ m_bandwidth_limit[peer_connection::download_channel].throttle(limit);
+ }
+
+ int torrent::download_limit() const
+ {
+ int limit = m_bandwidth_limit[peer_connection::download_channel].throttle();
+ if (limit == (std::numeric_limits<int>::max)()) limit = -1;
+ return limit;
+ }
+
+ void torrent::delete_files()
+ {
+#if defined(TORRENT_VERBOSE_LOGGING)
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ (*(*i)->m_logger) << "*** DELETING FILES IN TORRENT\n";
+ }
+#endif
+
+ disconnect_all();
+ if (!m_paused)
+ m_just_paused = true;
+ m_paused = true;
+ // tell the tracker that we stopped
+ m_event = tracker_request::stopped;
+
+ if (m_owning_storage.get())
+ {
+ TORRENT_ASSERT(m_storage);
+ m_storage->async_delete_files(
+ bind(&torrent::on_files_deleted, shared_from_this(), _1, _2));
+ }
+ }
+
+ void torrent::pause()
+ {
+ INVARIANT_CHECK;
+
+ if (m_paused) return;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { if ((*i)->on_pause()) return; } catch (std::exception&) {}
+ }
+#endif
+
+#if defined(TORRENT_VERBOSE_LOGGING)
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ (*(*i)->m_logger) << "*** PAUSING TORRENT\n";
+ }
+#endif
+
+ disconnect_all();
+ m_paused = true;
+ // tell the tracker that we stopped
+ m_event = tracker_request::stopped;
+ m_just_paused = true;
+ // this will make the storage close all
+ // files and flush all cached data
+ if (m_owning_storage.get())
+ {
+ TORRENT_ASSERT(m_storage);
+ m_storage->async_release_files(
+ bind(&torrent::on_torrent_paused, shared_from_this(), _1, _2));
+ }
+ else
+ {
+ if (alerts().should_post(alert::warning))
+ {
+ alerts().post_alert(torrent_paused_alert(get_handle(), "torrent paused"));
+ }
+ }
+ }
+
+ void torrent::resume()
+ {
+ INVARIANT_CHECK;
+
+ if (!m_paused) return;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { if ((*i)->on_resume()) return; } catch (std::exception&) {}
+ }
+#endif
+
+ m_paused = false;
+
+ // tell the tracker that we're back
+ m_event = tracker_request::started;
+ force_tracker_request();
+
+ // make pulse be called as soon as possible
+ m_time_scaler = 0;
+ }
+
+ void torrent::second_tick(stat& accumulator, float tick_interval)
+ {
+ INVARIANT_CHECK;
+
+#ifndef TORRENT_DISABLE_EXTENSIONS
+ for (extension_list_t::iterator i = m_extensions.begin()
+ , end(m_extensions.end()); i != end; ++i)
+ {
+ try { (*i)->tick(); } catch (std::exception&) {}
+ }
+#endif
+
+ if (m_paused)
+ {
+ // let the stats fade out to 0
+ m_stat.second_tick(tick_interval);
+ return;
+ }
+
+ // ---- WEB SEEDS ----
+
+ // re-insert urls that are to be retries into the m_web_seeds
+ typedef std::map<std::string, ptime>::iterator iter_t;
+ for (iter_t i = m_web_seeds_next_retry.begin(); i != m_web_seeds_next_retry.end();)
+ {
+ iter_t erase_element = i++;
+ if (erase_element->second <= time_now())
+ {
+ m_web_seeds.insert(erase_element->first);
+ m_web_seeds_next_retry.erase(erase_element);
+ }
+ }
+
+ // if we have everything we want we don't need to connect to any web-seed
+ if (!is_finished() && !m_web_seeds.empty())
+ {
+ // keep trying web-seeds if there are any
+ // first find out which web seeds we are connected to
+ std::set<std::string> web_seeds;
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end(); ++i)
+ {
+ web_peer_connection* p
+ = dynamic_cast<web_peer_connection*>(*i);
+ if (!p) continue;
+ web_seeds.insert(p->url());
+ }
+
+ for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
+ , end(m_resolving_web_seeds.end()); i != end; ++i)
+ web_seeds.insert(web_seeds.begin(), *i);
+
+ // from the list of available web seeds, subtract the ones we are
+ // already connected to.
+ std::vector<std::string> not_connected_web_seeds;
+ std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
+ , web_seeds.end(), std::back_inserter(not_connected_web_seeds));
+
+ // connect to all of those that we aren't connected to
+ std::for_each(not_connected_web_seeds.begin(), not_connected_web_seeds.end()
+ , bind(&torrent::connect_to_url_seed, this, _1));
+ }
+
+ for (peer_iterator i = m_connections.begin();
+ i != m_connections.end();)
+ {
+ peer_connection* p = *i;
+ ++i;
+ m_stat += p->statistics();
+ // updates the peer connection's ul/dl bandwidth
+ // resource requests
+ try
+ {
+ p->second_tick(tick_interval);
+ }
+ catch (std::exception& e)
+ {
+ (void)e;
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*p->m_logger) << "**ERROR**: " << e.what() << "\n";
+#endif
+ p->set_failed();
+ p->disconnect();
+ }
+ }
+ accumulator += m_stat;
+ m_stat.second_tick(tick_interval);
+
+ m_time_scaler--;
+ if (m_time_scaler <= 0)
+ {
+ m_time_scaler = 10;
+ m_policy.pulse();
+ }
+ }
+
+ void torrent::retry_url_seed(std::string const& url)
+ {
+ m_web_seeds_next_retry[url] = time_now()
+ + seconds(m_ses.settings().urlseed_wait_retry);
+ }
+
+ bool torrent::try_connect_peer()
+ {
+ TORRENT_ASSERT(want_more_peers());
+ return m_policy.connect_one_peer();
+ }
+
+ void torrent::async_verify_piece(int piece_index, boost::function<void(bool)> const& f)
+ {
+// INVARIANT_CHECK;
+
+ TORRENT_ASSERT(m_storage);
+ TORRENT_ASSERT(m_storage->refcount() > 0);
+ TORRENT_ASSERT(piece_index >= 0);
+ TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces());
+ TORRENT_ASSERT(piece_index < (int)m_have_pieces.size());
+
+ m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified
+ , shared_from_this(), _1, _2, f));
+#ifndef NDEBUG
+ check_invariant();
+#endif
+ }
+
+ void torrent::on_piece_verified(int ret, disk_io_job const& j
+ , boost::function<void(bool)> f)
+ {
+ sha1_hash h(j.str);
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ f(m_torrent_file->hash_for_piece(j.piece) == h);
+ }
+
+ const tcp::endpoint& torrent::current_tracker() const
+ {
+ return m_tracker_address;
+ }
+
+ bool torrent::is_allocating() const
+ { return m_owning_storage.get() && m_owning_storage->is_allocating(); }
+
+ void torrent::file_progress(std::vector<float>& fp) const
+ {
+ TORRENT_ASSERT(valid_metadata());
+
+ fp.clear();
+ fp.resize(m_torrent_file->num_files(), 0.f);
+
+ for (int i = 0; i < m_torrent_file->num_files(); ++i)
+ {
+ peer_request ret = m_torrent_file->map_file(i, 0, 0);
+ size_type size = m_torrent_file->file_at(i).size;
+
+// zero sized files are considered
+// 100% done all the time
+ if (size == 0)
+ {
+ fp[i] = 1.f;
+ continue;
+ }
+
+ size_type done = 0;
+ while (size > 0)
+ {
+ size_type bytes_step = (std::min)(size_type(m_torrent_file->piece_size(ret.piece)
+ - ret.start), size);
+ if (m_have_pieces[ret.piece]) done += bytes_step;
+ ++ret.piece;
+ ret.start = 0;
+ size -= bytes_step;
+ }
+ TORRENT_ASSERT(size == 0);
+
+ fp[i] = static_cast<float>(done) / m_torrent_file->file_at(i).size;
+ }
+ }
+
+ torrent_status torrent::status() const
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(std::accumulate(
+ m_have_pieces.begin()
+ , m_have_pieces.end()
+ , 0) == m_num_pieces);
+
+ torrent_status st;
+
+ st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size();
+ st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size();
+
+ st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end()
+ , !boost::bind(&peer_connection::is_connecting, _1));
+
+ st.list_peers = std::distance(m_policy.begin_peer(), m_policy.end_peer());
+ st.list_seeds = (int)std::count_if(m_policy.begin_peer(), m_policy.end_peer()
+ , boost::bind(&policy::peer::seed, bind(&policy::iterator::value_type::second, _1)));
+
+ st.storage_mode = m_storage_mode;
+
+ st.num_complete = m_complete;
+ st.num_incomplete = m_incomplete;
+ st.paused = m_paused;
+ boost::tie(st.total_done, st.total_wanted_done) = bytes_done();
+ TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
+
+ // payload transfer
+ st.total_payload_download = m_stat.total_payload_download();
+ st.total_payload_upload = m_stat.total_payload_upload();
+
+ // total transfer
+ st.total_download = m_stat.total_payload_download()
+ + m_stat.total_protocol_download();
+ st.total_upload = m_stat.total_payload_upload()
+ + m_stat.total_protocol_upload();
+
+ // failed bytes
+ st.total_failed_bytes = m_total_failed_bytes;
+ st.total_redundant_bytes = m_total_redundant_bytes;
+
+ // transfer rate
+ st.download_rate = m_stat.download_rate();
+ st.upload_rate = m_stat.upload_rate();
+ st.download_payload_rate = m_stat.download_payload_rate();
+ st.upload_payload_rate = m_stat.upload_payload_rate();
+
+ st.next_announce = boost::posix_time::seconds(
+ total_seconds(next_announce() - time_now()));
+ if (st.next_announce.is_negative())
+ st.next_announce = boost::posix_time::seconds(0);
+
+ st.announce_interval = boost::posix_time::seconds(m_duration);
+
+ if (m_last_working_tracker >= 0)
+ {
+ st.current_tracker
+ = m_trackers[m_last_working_tracker].url;
+ }
+
+ st.num_uploads = m_num_uploads;
+ st.uploads_limit = m_max_uploads;
+ st.num_connections = int(m_connections.size());
+ st.connections_limit = m_max_connections;
+ // if we don't have any metadata, stop here
+
+ if (!valid_metadata())
+ {
+ if (m_got_tracker_response == false)
+ st.state = torrent_status::connecting_to_tracker;
+ else
+ st.state = torrent_status::downloading_metadata;
+
+// TODO: add a progress member to the torrent that will be used in this case
+// and that may be set by a plugin
+// if (m_metadata_size == 0) st.progress = 0.f;
+// else st.progress = (std::min)(1.f, m_metadata_progress / (float)m_metadata_size);
+ st.progress = 0.f;
+
+ st.block_size = 0;
+
+ return st;
+ }
+
+ st.block_size = block_size();
+
+ // fill in status that depends on metadata
+
+ st.total_wanted = m_torrent_file->total_size();
+
+ if (m_picker.get() && (m_picker->num_filtered() > 0
+ || m_picker->num_have_filtered() > 0))
+ {
+ int filtered_pieces = m_picker->num_filtered()
+ + m_picker->num_have_filtered();
+ int last_piece_index = m_torrent_file->num_pieces() - 1;
+ if (m_picker->piece_priority(last_piece_index) == 0)
+ {
+ st.total_wanted -= m_torrent_file->piece_size(last_piece_index);
+ --filtered_pieces;
+ }
+
+ st.total_wanted -= filtered_pieces * m_torrent_file->piece_length();
+ }
+
+ TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
+
+ if (st.total_wanted == 0) st.progress = 1.f;
+ else st.progress = st.total_wanted_done
+ / static_cast<float>(st.total_wanted);
+
+ st.pieces = &m_have_pieces;
+ st.num_pieces = m_num_pieces;
+
+ if (m_got_tracker_response == false)
+ {
+ st.state = torrent_status::connecting_to_tracker;
+ }
+ else if (is_seed())
+ {
+ TORRENT_ASSERT(st.total_done == m_torrent_file->total_size());
+ st.state = torrent_status::seeding;
+ }
+ else if (st.total_wanted_done == st.total_wanted)
+ {
+ st.state = torrent_status::finished;
+ }
+ else
+ {
+ st.state = torrent_status::downloading;
+ }
+
+ st.num_seeds = num_seeds();
+ if (m_picker.get())
+ st.distributed_copies = m_picker->distributed_copies();
+ else
+ st.distributed_copies = -1;
+ return st;
+ }
+
+ int torrent::num_seeds() const
+ {
+ INVARIANT_CHECK;
+
+ return (int)std::count_if(m_connections.begin(), m_connections.end()
+ , boost::bind(&peer_connection::is_seed, _1));
+ }
+
+ void torrent::tracker_request_timed_out(
+ tracker_request const& r)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ debug_log("*** tracker timed out");
+#endif
+
+ if (m_ses.m_alerts.should_post(alert::warning))
+ {
+ std::stringstream s;
+ s << "tracker: \"" << r.url << "\" timed out";
+ if (r.kind == tracker_request::announce_request)
+ {
+ m_ses.m_alerts.post_alert(tracker_alert(get_handle()
+ , m_failed_trackers + 1, 0, s.str()));
+ }
+ else if (r.kind == tracker_request::scrape_request)
+ {
+ m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str()));
+ }
+ }
+
+ if (r.kind == tracker_request::announce_request)
+ try_next_tracker();
+ }
+
+ // TODO: with some response codes, we should just consider
+ // the tracker as a failure and not retry
+ // it anymore
+ void torrent::tracker_request_error(tracker_request const& r
+ , int response_code, const std::string& str)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ INVARIANT_CHECK;
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ debug_log(std::string("*** tracker error: ") + str);
+#endif
+ if (m_ses.m_alerts.should_post(alert::warning))
+ {
+ std::stringstream s;
+ s << "tracker: \"" << r.url << "\" " << str;
+ if (r.kind == tracker_request::announce_request)
+ {
+ m_ses.m_alerts.post_alert(tracker_alert(get_handle()
+ , m_failed_trackers + 1, response_code, s.str()));
+ }
+ else if (r.kind == tracker_request::scrape_request)
+ {
+ m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str()));
+ }
+ }
+
+ if (r.kind == tracker_request::announce_request)
+ try_next_tracker();
+ }
+
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ void torrent::debug_log(const std::string& line)
+ {
+ (*m_ses.m_logger) << time_now_string() << " " << line << "\n";
+ }
+#endif
+
+}
+
diff --git a/src/libtorrent/src/torrent_handle.cpp b/src/libtorrent/src/torrent_handle.cpp
new file mode 100644
index 0000000..fbfebbf
--- /dev/null
+++ b/src/libtorrent/src/torrent_handle.cpp
@@ -0,0 +1,741 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <iterator>
+#include <algorithm>
+#include <set>
+#include <cctype>
+#include <algorithm>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/optional.hpp>
+#include <boost/bind.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_id.hpp"
+#include "libtorrent/bt_peer_connection.hpp"
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+#include "libtorrent/invariant_check.hpp"
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+namespace std
+{
+ using ::srand;
+ using ::isalnum;
+};
+#endif
+
+using boost::bind;
+using boost::mutex;
+using libtorrent::aux::session_impl;
+
+#ifdef BOOST_NO_EXCEPTIONS
+
+#define TORRENT_FORWARD(call) \
+ if (m_ses == 0) return; \
+ TORRENT_ASSERT(m_chk); \
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
+ mutex::scoped_lock l2(m_chk->m_mutex); \
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
+ if (t == 0) return; \
+ t->call
+
+#define TORRENT_FORWARD_RETURN(call, def) \
+ if (m_ses == 0) return def; \
+ TORRENT_ASSERT(m_chk); \
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
+ mutex::scoped_lock l2(m_chk->m_mutex); \
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
+ if (t == 0) return def; \
+ return t->call
+
+#define TORRENT_FORWARD_RETURN2(call, def) \
+ if (m_ses == 0) return def; \
+ TORRENT_ASSERT(m_chk); \
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
+ mutex::scoped_lock l2(m_chk->m_mutex); \
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
+ if (t == 0) return def; \
+ t->call
+
+#else
+
+#define TORRENT_FORWARD(call) \
+ if (m_ses == 0) throw_invalid_handle(); \
+ TORRENT_ASSERT(m_chk); \
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
+ mutex::scoped_lock l2(m_chk->m_mutex); \
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
+ if (t == 0) throw_invalid_handle(); \
+ t->call
+
+#define TORRENT_FORWARD_RETURN(call, def) \
+ if (m_ses == 0) throw_invalid_handle(); \
+ TORRENT_ASSERT(m_chk); \
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
+ mutex::scoped_lock l2(m_chk->m_mutex); \
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
+ if (t == 0) return def; \
+ return t->call
+
+#define TORRENT_FORWARD_RETURN2(call, def) \
+ if (m_ses == 0) throw_invalid_handle(); \
+ TORRENT_ASSERT(m_chk); \
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
+ mutex::scoped_lock l2(m_chk->m_mutex); \
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
+ if (t == 0) return def; \
+ t->call
+
+#endif
+
+namespace libtorrent
+{
+ namespace fs = boost::filesystem;
+
+ namespace
+ {
+#ifndef BOOST_NO_EXCEPTIONS
+ void throw_invalid_handle()
+ {
+ throw invalid_handle();
+ }
+#endif
+
+ torrent* find_torrent(
+ session_impl* ses
+ , aux::checker_impl* chk
+ , sha1_hash const& hash)
+ {
+ aux::piece_checker_data* d = chk->find_torrent(hash);
+ if (d != 0) return d->torrent_ptr.get();
+
+ boost::shared_ptr<torrent> t = ses->find_torrent(hash).lock();
+ if (t) return t.get();
+ return 0;
+ }
+ }
+
+#ifndef NDEBUG
+
+ void torrent_handle::check_invariant() const
+ {
+ TORRENT_ASSERT((m_ses == 0 && m_chk == 0) || (m_ses != 0 && m_chk != 0));
+ }
+
+#endif
+
+ void torrent_handle::set_max_uploads(int max_uploads) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(max_uploads >= 2 || max_uploads == -1);
+ TORRENT_FORWARD(set_max_uploads(max_uploads));
+ }
+
+ void torrent_handle::use_interface(const char* net_interface) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(use_interface(net_interface));
+ }
+
+ void torrent_handle::set_max_connections(int max_connections) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(max_connections >= 2 || max_connections == -1);
+ TORRENT_FORWARD(set_max_connections(max_connections));
+ }
+
+ void torrent_handle::set_peer_upload_limit(tcp::endpoint ip, int limit) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(limit >= -1);
+ TORRENT_FORWARD(set_peer_upload_limit(ip, limit));
+ }
+
+ void torrent_handle::set_peer_download_limit(tcp::endpoint ip, int limit) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(limit >= -1);
+ TORRENT_FORWARD(set_peer_download_limit(ip, limit));
+ }
+
+ void torrent_handle::set_upload_limit(int limit) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(limit >= -1);
+ TORRENT_FORWARD(set_upload_limit(limit));
+ }
+
+ int torrent_handle::upload_limit() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(upload_limit(), 0);
+ }
+
+ void torrent_handle::set_download_limit(int limit) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_ASSERT(limit >= -1);
+ TORRENT_FORWARD(set_download_limit(limit));
+ }
+
+ int torrent_handle::download_limit() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(download_limit(), 0);
+ }
+
+ void torrent_handle::move_storage(
+ fs::path const& save_path) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(move_storage(save_path));
+ }
+
+ void torrent_handle::add_extension(
+ boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
+ , void* userdata)
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(add_extension(ext, userdata));
+ }
+
+ bool torrent_handle::has_metadata() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(valid_metadata(), false);
+ }
+
+ bool torrent_handle::is_seed() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(is_seed(), false);
+ }
+
+ bool torrent_handle::is_paused() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(is_paused(), false);
+ }
+
+ void torrent_handle::pause() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(pause());
+ }
+
+ void torrent_handle::resume() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(resume());
+ }
+
+ void torrent_handle::set_tracker_login(std::string const& name
+ , std::string const& password) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(set_tracker_login(name, password));
+ }
+
+ void torrent_handle::file_progress(std::vector<float>& progress)
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(file_progress(progress));
+ }
+
+ torrent_status torrent_handle::status() const
+ {
+ INVARIANT_CHECK;
+
+ if (m_ses == 0)
+#ifdef BOOST_NO_EXCEPTIONS
+ return torrent_status();
+#else
+ throw_invalid_handle();
+#endif
+ TORRENT_ASSERT(m_chk);
+
+ session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
+ mutex::scoped_lock l2(m_chk->m_mutex);
+
+ aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
+ if (d != 0)
+ {
+ torrent_status st = d->torrent_ptr->status();
+
+ if (d->processing)
+ {
+ if (d->torrent_ptr->is_allocating())
+ st.state = torrent_status::allocating;
+ else
+ st.state = torrent_status::checking_files;
+ }
+ else
+ st.state = torrent_status::queued_for_checking;
+ st.progress = d->progress;
+ st.paused = d->torrent_ptr->is_paused();
+ return st;
+ }
+
+ boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
+ if (t) return t->status();
+
+#ifndef BOOST_NO_EXCEPTIONS
+ throw_invalid_handle();
+#endif
+ return torrent_status();
+ }
+
+ void torrent_handle::set_sequenced_download_threshold(int threshold) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(set_sequenced_download_threshold(threshold));
+ }
+
+ std::string torrent_handle::name() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(name(), "");
+ }
+
+ void torrent_handle::piece_availability(std::vector<int>& avail) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(piece_availability(avail));
+ }
+
+ void torrent_handle::piece_priority(int index, int priority) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(set_piece_priority(index, priority));
+ }
+
+ int torrent_handle::piece_priority(int index) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(piece_priority(index), 0);
+ }
+
+ void torrent_handle::prioritize_pieces(std::vector<int> const& pieces) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(prioritize_pieces(pieces));
+ }
+
+ std::vector<int> torrent_handle::piece_priorities() const
+ {
+ INVARIANT_CHECK;
+ std::vector<int> ret;
+ TORRENT_FORWARD_RETURN2(piece_priorities(ret), ret);
+ return ret;
+ }
+
+ void torrent_handle::prioritize_files(std::vector<int> const& files) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(prioritize_files(files));
+ }
+
+// ============ start deprecation ===============
+
+ void torrent_handle::filter_piece(int index, bool filter) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(filter_piece(index, filter));
+ }
+
+ void torrent_handle::filter_pieces(std::vector<bool> const& pieces) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(filter_pieces(pieces));
+ }
+
+ bool torrent_handle::is_piece_filtered(int index) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(is_piece_filtered(index), false);
+ }
+
+ std::vector<bool> torrent_handle::filtered_pieces() const
+ {
+ INVARIANT_CHECK;
+ std::vector<bool> ret;
+ TORRENT_FORWARD_RETURN2(filtered_pieces(ret), ret);
+ return ret;
+ }
+
+ void torrent_handle::filter_files(std::vector<bool> const& files) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(filter_files(files));
+ }
+
+// ============ end deprecation ===============
+
+
+ std::vector<announce_entry> const& torrent_handle::trackers() const
+ {
+ INVARIANT_CHECK;
+ const static std::vector<announce_entry> empty;
+ TORRENT_FORWARD_RETURN(trackers(), empty);
+ }
+
+ void torrent_handle::add_url_seed(std::string const& url) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(add_url_seed(url));
+ }
+
+ void torrent_handle::remove_url_seed(std::string const& url) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(remove_url_seed(url));
+ }
+
+ std::set<std::string> torrent_handle::url_seeds() const
+ {
+ INVARIANT_CHECK;
+ const static std::set<std::string> empty;
+ TORRENT_FORWARD_RETURN(url_seeds(), empty);
+ }
+
+ void torrent_handle::replace_trackers(
+ std::vector<announce_entry> const& urls) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(replace_trackers(urls));
+ }
+
+ torrent_info const& torrent_handle::get_torrent_info() const
+ {
+ INVARIANT_CHECK;
+#ifdef BOOST_NO_EXCEPTIONS
+ const static torrent_info empty;
+ if (m_ses == 0) return empty;
+#else
+ if (m_ses == 0) throw_invalid_handle();
+#endif
+ TORRENT_ASSERT(m_chk);
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
+ mutex::scoped_lock l2(m_chk->m_mutex);
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
+ if (t == 0 || !t->valid_metadata())
+#ifdef BOOST_NO_EXCEPTIONS
+ return empty;
+#else
+ throw_invalid_handle();
+#endif
+ return t->torrent_file();
+ }
+
+ bool torrent_handle::is_valid() const
+ {
+ INVARIANT_CHECK;
+ if (m_ses == 0) return false;
+ TORRENT_ASSERT(m_chk);
+ session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
+ mutex::scoped_lock l2(m_chk->m_mutex);
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
+ return t != 0;
+ }
+
+ entry torrent_handle::write_resume_data() const
+ {
+ INVARIANT_CHECK;
+
+ if (m_ses == 0)
+#ifdef BOOST_NO_EXCEPTIONS
+ return entry();
+#else
+ throw_invalid_handle();
+#endif
+ TORRENT_ASSERT(m_chk);
+
+ session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
+ mutex::scoped_lock l2(m_chk->m_mutex);
+
+ torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
+ if (!t || !t->valid_metadata())
+#ifdef BOOST_NO_EXCEPTIONS
+ return entry();
+#else
+ throw_invalid_handle();
+#endif
+
+ std::vector<bool> have_pieces = t->pieces();
+
+ entry ret(entry::dictionary_t);
+
+ ret["file-format"] = "libtorrent resume file";
+ ret["file-version"] = 1;
+
+ ret["allocation"] = t->filesystem().compact_allocation()?"compact":"full";
+
+ const sha1_hash& info_hash = t->torrent_file().info_hash();
+ ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
+
+ // blocks per piece
+ int num_blocks_per_piece =
+ static_cast<int>(t->torrent_file().piece_length()) / t->block_size();
+ ret["blocks per piece"] = num_blocks_per_piece;
+
+ // if this torrent is a seed, we won't have a piece picker
+ // and there will be no half-finished pieces.
+ if (!t->is_seed())
+ {
+ const piece_picker& p = t->picker();
+
+ const std::vector<piece_picker::downloading_piece>& q
+ = p.get_download_queue();
+
+ // unfinished pieces
+ ret["unfinished"] = entry::list_type();
+ entry::list_type& up = ret["unfinished"].list();
+
+ // info for each unfinished piece
+ for (std::vector<piece_picker::downloading_piece>::const_iterator i
+ = q.begin(); i != q.end(); ++i)
+ {
+ if (i->finished == 0) continue;
+
+ entry piece_struct(entry::dictionary_t);
+
+ // the unfinished piece's index
+ piece_struct["piece"] = i->index;
+
+ have_pieces[i->index] = true;
+
+ std::string bitmask;
+ const int num_bitmask_bytes
+ = (std::max)(num_blocks_per_piece / 8, 1);
+
+ for (int j = 0; j < num_bitmask_bytes; ++j)
+ {
+ unsigned char v = 0;
+ int bits = (std::min)(num_blocks_per_piece - j*8, 8);
+ for (int k = 0; k < bits; ++k)
+ v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
+ ? (1 << k) : 0;
+ bitmask.insert(bitmask.end(), v);
+ TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
+ }
+ piece_struct["bitmask"] = bitmask;
+/*
+ TORRENT_ASSERT(t->filesystem().slot_for(i->index) >= 0);
+ unsigned long adler
+ = t->filesystem().piece_crc(
+ t->filesystem().slot_for(i->index)
+ , t->block_size()
+ , i->info);
+
+ piece_struct["adler32"] = adler;
+*/
+ // push the struct onto the unfinished-piece list
+ up.push_back(piece_struct);
+ }
+ }
+
+ std::vector<int> piece_index;
+ t->filesystem().export_piece_map(piece_index, have_pieces);
+ entry::list_type& slots = ret["slots"].list();
+ std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
+
+ // write local peers
+
+ entry::list_type& peer_list = ret["peers"].list();
+ entry::list_type& banned_peer_list = ret["banned_peers"].list();
+
+ policy& pol = t->get_policy();
+
+ int max_failcount = t->settings().max_failcount;
+
+ for (policy::iterator i = pol.begin_peer()
+ , end(pol.end_peer()); i != end; ++i)
+ {
+ asio::error_code ec;
+ if (i->second.banned)
+ {
+ tcp::endpoint ip = i->second.ip;
+ entry peer(entry::dictionary_t);
+ peer["ip"] = ip.address().to_string(ec);
+ if (ec) continue;
+ peer["port"] = ip.port();
+ banned_peer_list.push_back(peer);
+ continue;
+ }
+ // we cannot save remote connection
+ // since we don't know their listen port
+ // unless they gave us their listen port
+ // through the extension handshake
+ // so, if the peer is not connectable (i.e. we
+ // don't know its listen port) or if it has
+ // been banned, don't save it.
+ if (i->second.type == policy::peer::not_connectable) continue;
+
+ // don't save peers that doesn't work
+ if (i->second.failcount >= max_failcount) continue;
+
+ tcp::endpoint ip = i->second.ip;
+ entry peer(entry::dictionary_t);
+ peer["ip"] = ip.address().to_string(ec);
+ if (ec) continue;
+ peer["port"] = ip.port();
+ peer_list.push_back(peer);
+ }
+
+ t->filesystem().write_resume_data(ret);
+
+ return ret;
+ }
+
+
+ fs::path torrent_handle::save_path() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(save_path(), fs::path());
+ }
+
+ void torrent_handle::connect_peer(tcp::endpoint const& adr, int source) const
+ {
+ INVARIANT_CHECK;
+
+ if (m_ses == 0)
+#ifdef BOOST_NO_EXCEPTIONS
+ return;
+#else
+ throw_invalid_handle();
+#endif
+ TORRENT_ASSERT(m_chk);
+
+ session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
+ boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
+
+ if (!t)
+ {
+ // the torrent is being checked. Add the peer to its
+ // peer list. The entries in there will be connected
+ // once the checking is complete.
+ mutex::scoped_lock l2(m_chk->m_mutex);
+
+ aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
+ if (d == 0)
+#ifdef BOOST_NO_EXCEPTIONS
+ return;
+#else
+ throw_invalid_handle();
+#endif
+ d->peers.push_back(adr);
+ return;
+ }
+
+ peer_id id;
+ std::fill(id.begin(), id.end(), 0);
+ t->get_policy().peer_from_tracker(adr, id, source, 0);
+ }
+
+ void torrent_handle::force_reannounce(
+ boost::posix_time::time_duration duration) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(force_tracker_request(time_now() + seconds(duration.total_seconds())));
+ }
+
+ void torrent_handle::force_reannounce() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(force_tracker_request());
+ }
+
+ void torrent_handle::scrape_tracker() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(scrape_tracker());
+ }
+
+ void torrent_handle::set_ratio(float ratio) const
+ {
+ INVARIANT_CHECK;
+
+ TORRENT_ASSERT(ratio >= 0.f);
+ if (ratio < 1.f && ratio > 0.f)
+ ratio = 1.f;
+ TORRENT_FORWARD(set_ratio(ratio));
+ }
+
+#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
+ void torrent_handle::resolve_countries(bool r)
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(resolve_countries(r));
+ }
+
+ bool torrent_handle::resolve_countries() const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD_RETURN(resolving_countries(), false);
+ }
+#endif
+
+ void torrent_handle::get_peer_info(std::vector<peer_info>& v) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(get_peer_info(v));
+ }
+
+ void torrent_handle::get_download_queue(std::vector<partial_piece_info>& queue) const
+ {
+ INVARIANT_CHECK;
+ TORRENT_FORWARD(get_download_queue(queue));
+ }
+
+}
+
diff --git a/src/libtorrent/src/torrent_info.cpp b/src/libtorrent/src/torrent_info.cpp
new file mode 100644
index 0000000..57c8a97
--- /dev/null
+++ b/src/libtorrent/src/torrent_info.cpp
@@ -0,0 +1,936 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <iterator>
+#include <algorithm>
+#include <set>
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/next_prior.hpp>
+#include <boost/bind.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/torrent_info.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/hasher.hpp"
+#include "libtorrent/entry.hpp"
+
+namespace pt = boost::posix_time;
+namespace gr = boost::gregorian;
+
+using namespace libtorrent;
+
+namespace
+{
+
+ namespace fs = boost::filesystem;
+
+ void convert_to_utf8(std::string& str, unsigned char chr)
+ {
+ str += 0xc0 | ((chr & 0xff) >> 6);
+ str += 0x80 | (chr & 0x3f);
+ }
+
+ void verify_encoding(file_entry& target)
+ {
+ std::string tmp_path;
+ std::string file_path = target.path.string();
+ bool valid_encoding = true;
+ for (std::string::iterator i = file_path.begin()
+ , end(file_path.end()); i != end; ++i)
+ {
+ // valid ascii-character
+ if ((*i & 0x80) == 0)
+ {
+ tmp_path += *i;
+ continue;
+ }
+
+ if (std::distance(i, end) < 2)
+ {
+ convert_to_utf8(tmp_path, *i);
+ valid_encoding = false;
+ continue;
+ }
+
+ // valid 2-byte utf-8 character
+ if ((i[0] & 0xe0) == 0xc0
+ && (i[1] & 0xc0) == 0x80)
+ {
+ tmp_path += i[0];
+ tmp_path += i[1];
+ i += 1;
+ continue;
+ }
+
+ if (std::distance(i, end) < 3)
+ {
+ convert_to_utf8(tmp_path, *i);
+ valid_encoding = false;
+ continue;
+ }
+
+ // valid 3-byte utf-8 character
+ if ((i[0] & 0xf0) == 0xe0
+ && (i[1] & 0xc0) == 0x80
+ && (i[2] & 0xc0) == 0x80)
+ {
+ tmp_path += i[0];
+ tmp_path += i[1];
+ tmp_path += i[2];
+ i += 2;
+ continue;
+ }
+
+ if (std::distance(i, end) < 4)
+ {
+ convert_to_utf8(tmp_path, *i);
+ valid_encoding = false;
+ continue;
+ }
+
+ // valid 4-byte utf-8 character
+ if ((i[0] & 0xf0) == 0xe0
+ && (i[1] & 0xc0) == 0x80
+ && (i[2] & 0xc0) == 0x80
+ && (i[3] & 0xc0) == 0x80)
+ {
+ tmp_path += i[0];
+ tmp_path += i[1];
+ tmp_path += i[2];
+ tmp_path += i[3];
+ i += 3;
+ continue;
+ }
+
+ convert_to_utf8(tmp_path, *i);
+ valid_encoding = false;
+ }
+ // the encoding was not valid utf-8
+ // save the original encoding and replace the
+ // commonly used path with the correctly
+ // encoded string
+ if (!valid_encoding)
+ {
+ target.orig_path.reset(new fs::path(target.path));
+ target.path = tmp_path;
+ }
+ }
+
+ void extract_single_file(const entry& dict, file_entry& target
+ , std::string const& root_dir)
+ {
+ target.size = dict["length"].integer();
+ target.path = root_dir;
+ target.file_base = 0;
+
+ // prefer the name.utf-8
+ // because if it exists, it is more
+ // likely to be correctly encoded
+
+ const entry::list_type* list = 0;
+ if (entry const* p = dict.find_key("path.utf-8"))
+ {
+ list = &p->list();
+ }
+ else
+ {
+ list = &dict["path"].list();
+ }
+
+ for (entry::list_type::const_iterator i = list->begin();
+ i != list->end(); ++i)
+ {
+ if (i->string() != "..")
+ target.path /= i->string();
+ }
+ verify_encoding(target);
+ if (target.path.is_complete()) throw std::runtime_error("torrent contains "
+ "a file with an absolute path: '"
+ + target.path.native_file_string() + "'");
+ }
+
+ void extract_files(const entry::list_type& list, std::vector<file_entry>& target
+ , std::string const& root_dir)
+ {
+ size_type offset = 0;
+ for (entry::list_type::const_iterator i = list.begin(); i != list.end(); ++i)
+ {
+ target.push_back(file_entry());
+ extract_single_file(*i, target.back(), root_dir);
+ target.back().offset = offset;
+ offset += target.back().size;
+ }
+ }
+/*
+ void remove_dir(fs::path& p)
+ {
+ TORRENT_ASSERT(p.begin() != p.end());
+ path tmp;
+ for (path::iterator i = boost::next(p.begin()); i != p.end(); ++i)
+ tmp /= *i;
+ p = tmp;
+ }
+*/
+}
+
+namespace libtorrent
+{
+
+ // standard constructor that parses a torrent file
+ torrent_info::torrent_info(const entry& torrent_file)
+ : m_num_pieces(0)
+ , m_creation_date(pt::ptime(pt::not_a_date_time))
+ , m_multifile(false)
+ , m_private(false)
+ , m_extra_info(entry::dictionary_t)
+#ifndef NDEBUG
+ , m_half_metadata(false)
+#endif
+ {
+ try
+ {
+ read_torrent_info(torrent_file);
+ }
+ catch(type_error&)
+ {
+ throw invalid_torrent_file();
+ }
+ }
+
+ // constructor used for creating new torrents
+ // will not contain any hashes, comments, creation date
+ // just the necessary to use it with piece manager
+ // used for torrents with no metadata
+ torrent_info::torrent_info(sha1_hash const& info_hash)
+ : m_piece_length(0)
+ , m_total_size(0)
+ , m_num_pieces(0)
+ , m_info_hash(info_hash)
+ , m_name()
+ , m_creation_date(pt::second_clock::universal_time())
+ , m_multifile(false)
+ , m_private(false)
+ , m_extra_info(entry::dictionary_t)
+#ifndef NDEBUG
+ , m_half_metadata(false)
+#endif
+ {
+ }
+
+ torrent_info::torrent_info()
+ : m_piece_length(0)
+ , m_total_size(0)
+ , m_num_pieces(0)
+ , m_info_hash(0)
+ , m_name()
+ , m_creation_date(pt::second_clock::universal_time())
+ , m_multifile(false)
+ , m_private(false)
+ , m_extra_info(entry::dictionary_t)
+#ifndef NDEBUG
+ , m_half_metadata(false)
+#endif
+ {
+ }
+
+ torrent_info::~torrent_info()
+ {}
+
+ void torrent_info::swap(torrent_info& ti)
+ {
+ using std::swap;
+ m_urls.swap(ti.m_urls);
+ m_url_seeds.swap(ti.m_url_seeds);
+ swap(m_piece_length, ti.m_piece_length);
+ m_piece_hash.swap(ti.m_piece_hash);
+ m_files.swap(ti.m_files);
+ m_nodes.swap(ti.m_nodes);
+ swap(m_num_pieces, ti.m_num_pieces);
+ swap(m_info_hash, ti.m_info_hash);
+ m_name.swap(ti.m_name);
+ swap(m_creation_date, ti.m_creation_date);
+ m_comment.swap(ti.m_comment);
+ m_created_by.swap(ti.m_created_by);
+ swap(m_multifile, ti.m_multifile);
+ swap(m_private, ti.m_private);
+ m_extra_info.swap(ti.m_extra_info);
+#ifndef NDEBUG
+ swap(m_half_metadata, ti.m_half_metadata);
+#endif
+ }
+
+ void torrent_info::set_piece_size(int size)
+ {
+ // make sure the size is an even power of 2
+#ifndef NDEBUG
+ for (int i = 0; i < 32; ++i)
+ {
+ if (size & (1 << i))
+ {
+ TORRENT_ASSERT((size & ~(1 << i)) == 0);
+ break;
+ }
+ }
+#endif
+ TORRENT_ASSERT(!m_half_metadata);
+ m_piece_length = size;
+
+ m_num_pieces = static_cast<int>(
+ (m_total_size + m_piece_length - 1) / m_piece_length);
+ int old_num_pieces = static_cast<int>(m_piece_hash.size());
+
+ m_piece_hash.resize(m_num_pieces);
+ for (int i = old_num_pieces; i < m_num_pieces; ++i)
+ {
+ m_piece_hash[i].clear();
+ }
+ }
+
+ void torrent_info::parse_info_section(entry const& info)
+ {
+ // encode the info-field in order to calculate it's sha1-hash
+ std::vector<char> buf;
+ bencode(std::back_inserter(buf), info);
+ hasher h;
+ h.update(&buf[0], (int)buf.size());
+ m_info_hash = h.final();
+
+ // extract piece length
+ m_piece_length = int(info["piece length"].integer());
+ if (m_piece_length <= 0) throw std::runtime_error("invalid torrent. piece length <= 0");
+
+ // extract file name (or the directory name if it's a multifile libtorrent)
+ if (entry const* e = info.find_key("name.utf-8"))
+ { m_name = e->string(); }
+ else
+ { m_name = info["name"].string(); }
+
+ fs::path tmp = m_name;
+ if (tmp.is_complete())
+ {
+ m_name = tmp.leaf();
+ }
+ else if (tmp.has_branch_path())
+ {
+ fs::path p;
+ for (fs::path::iterator i = tmp.begin()
+ , end(tmp.end()); i != end; ++i)
+ {
+ if (*i == "." || *i == "..") continue;
+ p /= *i;
+ }
+ m_name = p.string();
+ }
+ if (m_name == ".." || m_name == ".")
+ throw std::runtime_error("invalid 'name' of torrent (possible exploit attempt)");
+
+ // extract file list
+ entry const* i = info.find_key("files");
+ if (i == 0)
+ {
+ // if there's no list of files, there has to be a length
+ // field.
+ file_entry e;
+ e.path = m_name;
+ e.offset = 0;
+ e.size = info["length"].integer();
+ m_files.push_back(e);
+ }
+ else
+ {
+ extract_files(i->list(), m_files, m_name);
+ m_multifile = true;
+ }
+
+ // calculate total size of all pieces
+ m_total_size = 0;
+ for (std::vector<file_entry>::iterator i = m_files.begin(); i != m_files.end(); ++i)
+ m_total_size += i->size;
+
+ // extract sha-1 hashes for all pieces
+ // we want this division to round upwards, that's why we have the
+ // extra addition
+
+ m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
+ m_piece_hash.resize(m_num_pieces);
+ const std::string& hash_string = info["pieces"].string();
+
+ if ((int)hash_string.length() != m_num_pieces * 20)
+ throw invalid_torrent_file();
+
+ for (int i = 0; i < m_num_pieces; ++i)
+ std::copy(
+ hash_string.begin() + i*20
+ , hash_string.begin() + (i+1)*20
+ , m_piece_hash[i].begin());
+
+ for (entry::dictionary_type::const_iterator i = info.dict().begin()
+ , end(info.dict().end()); i != end; ++i)
+ {
+ if (i->first == "pieces"
+ || i->first == "piece length"
+ || i->first == "length")
+ continue;
+ m_extra_info[i->first] = i->second;
+ }
+
+ if (entry const* priv = info.find_key("private"))
+ {
+ if (priv->type() != entry::int_t
+ || priv->integer() != 0)
+ {
+ // this key exists and it's not 0.
+ // consider the torrent private
+ m_private = true;
+ }
+ }
+
+#ifndef NDEBUG
+ std::vector<char> info_section_buf;
+ entry gen_info_section = create_info_metadata();
+ bencode(std::back_inserter(info_section_buf), gen_info_section);
+ TORRENT_ASSERT(hasher(&info_section_buf[0], info_section_buf.size()).final()
+ == m_info_hash);
+#endif
+ }
+
+ // extracts information from a libtorrent file and fills in the structures in
+ // the torrent object
+ void torrent_info::read_torrent_info(const entry& torrent_file)
+ {
+ // extract the url of the tracker
+ if (entry const* i = torrent_file.find_key("announce-list"))
+ {
+ const entry::list_type& l = i->list();
+ for (entry::list_type::const_iterator j = l.begin(); j != l.end(); ++j)
+ {
+ const entry::list_type& ll = j->list();
+ for (entry::list_type::const_iterator k = ll.begin(); k != ll.end(); ++k)
+ {
+ announce_entry e(k->string());
+ e.tier = (int)std::distance(l.begin(), j);
+ m_urls.push_back(e);
+ }
+ }
+
+ if (m_urls.size() == 0)
+ {
+ // the announce-list is empty
+ // fall back to look for announce
+ m_urls.push_back(announce_entry(
+ torrent_file["announce"].string()));
+ }
+ // shuffle each tier
+ std::vector<announce_entry>::iterator start = m_urls.begin();
+ std::vector<announce_entry>::iterator stop;
+ int current_tier = m_urls.front().tier;
+ for (stop = m_urls.begin(); stop != m_urls.end(); ++stop)
+ {
+ if (stop->tier != current_tier)
+ {
+ std::random_shuffle(start, stop);
+ start = stop;
+ current_tier = stop->tier;
+ }
+ }
+ std::random_shuffle(start, stop);
+ }
+ else if (entry const* i = torrent_file.find_key("announce"))
+ {
+ m_urls.push_back(announce_entry(i->string()));
+ }
+
+ if (entry const* i = torrent_file.find_key("nodes"))
+ {
+ entry::list_type const& list = i->list();
+ for (entry::list_type::const_iterator i(list.begin())
+ , end(list.end()); i != end; ++i)
+ {
+ if (i->type() != entry::list_t) continue;
+ entry::list_type const& l = i->list();
+ entry::list_type::const_iterator iter = l.begin();
+ if (l.size() < 1) continue;
+ std::string const& hostname = iter->string();
+ ++iter;
+ int port = 6881;
+ if (l.end() != iter) port = int(iter->integer());
+ m_nodes.push_back(std::make_pair(hostname, port));
+ }
+ }
+
+ // extract creation date
+ try
+ {
+ m_creation_date = pt::ptime(gr::date(1970, gr::Jan, 1))
+ + pt::seconds(long(torrent_file["creation date"].integer()));
+ }
+ catch (type_error) {}
+
+ // if there are any url-seeds, extract them
+ try
+ {
+ entry const& url_seeds = torrent_file["url-list"];
+ if (url_seeds.type() == entry::string_t)
+ {
+ m_url_seeds.push_back(url_seeds.string());
+ }
+ else if (url_seeds.type() == entry::list_t)
+ {
+ entry::list_type const& l = url_seeds.list();
+ for (entry::list_type::const_iterator i = l.begin();
+ i != l.end(); ++i)
+ {
+ m_url_seeds.push_back(i->string());
+ }
+ }
+ }
+ catch (type_error&) {}
+
+ // extract comment
+ if (entry const* e = torrent_file.find_key("comment.utf-8"))
+ { m_comment = e->string(); }
+ else if (entry const* e = torrent_file.find_key("comment"))
+ { m_comment = e->string(); }
+
+ if (entry const* e = torrent_file.find_key("created by.utf-8"))
+ { m_created_by = e->string(); }
+ else if (entry const* e = torrent_file.find_key("created by"))
+ { m_created_by = e->string(); }
+
+ parse_info_section(torrent_file["info"]);
+ }
+
+ boost::optional<pt::ptime>
+ torrent_info::creation_date() const
+ {
+ if (m_creation_date != pt::ptime(gr::date(pt::not_a_date_time)))
+ {
+ return boost::optional<pt::ptime>(m_creation_date);
+ }
+ return boost::optional<pt::ptime>();
+ }
+
+ void torrent_info::add_tracker(std::string const& url, int tier)
+ {
+ announce_entry e(url);
+ e.tier = tier;
+ m_urls.push_back(e);
+
+ using boost::bind;
+ std::sort(m_urls.begin(), m_urls.end(), boost::bind<bool>(std::less<int>()
+ , bind(&announce_entry::tier, _1), bind(&announce_entry::tier, _2)));
+ }
+
+ void torrent_info::add_file(fs::path file, size_type size)
+ {
+// TORRENT_ASSERT(file.begin() != file.end());
+
+ if (!file.has_branch_path())
+ {
+ // you have already added at least one file with a
+ // path to the file (branch_path), which means that
+ // all the other files need to be in the same top
+ // directory as the first file.
+ TORRENT_ASSERT(m_files.empty());
+ TORRENT_ASSERT(!m_multifile);
+ m_name = file.string();
+ }
+ else
+ {
+#ifndef NDEBUG
+ if (!m_files.empty())
+ TORRENT_ASSERT(m_name == *file.begin());
+#endif
+ m_multifile = true;
+ m_name = *file.begin();
+ }
+
+ file_entry e;
+ e.path = file;
+ e.size = size;
+ e.offset = m_files.empty() ? 0 : m_files.back().offset
+ + m_files.back().size;
+ m_files.push_back(e);
+
+ m_total_size += size;
+
+ if (m_piece_length == 0)
+ m_piece_length = 256 * 1024;
+
+ m_num_pieces = static_cast<int>(
+ (m_total_size + m_piece_length - 1) / m_piece_length);
+ int old_num_pieces = static_cast<int>(m_piece_hash.size());
+
+ m_piece_hash.resize(m_num_pieces);
+ if (m_num_pieces > old_num_pieces)
+ std::for_each(m_piece_hash.begin() + old_num_pieces
+ , m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1));
+ }
+
+ void torrent_info::add_url_seed(std::string const& url)
+ {
+ m_url_seeds.push_back(url);
+ }
+
+ void torrent_info::set_comment(char const* str)
+ {
+ m_comment = str;
+ }
+
+ void torrent_info::set_creator(char const* str)
+ {
+ m_created_by = str;
+ }
+
+ entry torrent_info::create_info_metadata() const
+ {
+ // you have to add files to the torrent first
+ TORRENT_ASSERT(!m_files.empty());
+
+ entry info(m_extra_info);
+
+ if (!info.find_key("name"))
+ info["name"] = m_name;
+
+ if (!m_multifile)
+ {
+ info["length"] = m_files.front().size;
+ }
+ else
+ {
+ if (!info.find_key("files"))
+ {
+ entry& files = info["files"];
+
+ for (std::vector<file_entry>::const_iterator i = m_files.begin();
+ i != m_files.end(); ++i)
+ {
+ files.list().push_back(entry());
+ entry& file_e = files.list().back();
+ file_e["length"] = i->size;
+ entry& path_e = file_e["path"];
+
+ fs::path const* file_path;
+ if (i->orig_path) file_path = &(*i->orig_path);
+ else file_path = &i->path;
+ TORRENT_ASSERT(file_path->has_branch_path());
+ TORRENT_ASSERT(*file_path->begin() == m_name);
+
+ for (fs::path::iterator j = boost::next(file_path->begin());
+ j != file_path->end(); ++j)
+ {
+ path_e.list().push_back(entry(*j));
+ }
+ }
+ }
+ }
+
+ info["piece length"] = piece_length();
+ entry& pieces = info["pieces"];
+
+ std::string& p = pieces.string();
+
+ for (std::vector<sha1_hash>::const_iterator i = m_piece_hash.begin();
+ i != m_piece_hash.end(); ++i)
+ {
+ p.append((char*)i->begin(), (char*)i->end());
+ }
+
+ return info;
+ }
+
+ entry torrent_info::create_torrent() const
+ {
+ TORRENT_ASSERT(m_piece_length > 0);
+
+ if (m_files.empty())
+ {
+ // TODO: throw something here
+ // throw
+ return entry();
+ }
+
+ entry dict;
+
+ if (m_private) dict["private"] = 1;
+
+ if (!m_urls.empty())
+ dict["announce"] = m_urls.front().url;
+
+ if (!m_nodes.empty())
+ {
+ entry& nodes = dict["nodes"];
+ entry::list_type& nodes_list = nodes.list();
+ for (nodes_t::const_iterator i = m_nodes.begin()
+ , end(m_nodes.end()); i != end; ++i)
+ {
+ entry::list_type node;
+ node.push_back(entry(i->first));
+ node.push_back(entry(i->second));
+ nodes_list.push_back(entry(node));
+ }
+ }
+
+ if (m_urls.size() > 1)
+ {
+ entry trackers(entry::list_t);
+ entry tier(entry::list_t);
+ int current_tier = m_urls.front().tier;
+ for (std::vector<announce_entry>::const_iterator i = m_urls.begin();
+ i != m_urls.end(); ++i)
+ {
+ if (i->tier != current_tier)
+ {
+ current_tier = i->tier;
+ trackers.list().push_back(tier);
+ tier.list().clear();
+ }
+ tier.list().push_back(entry(i->url));
+ }
+ trackers.list().push_back(tier);
+ dict["announce-list"] = trackers;
+ }
+
+ if (!m_comment.empty())
+ dict["comment"] = m_comment;
+
+ dict["creation date"] =
+ (m_creation_date - pt::ptime(gr::date(1970, gr::Jan, 1))).total_seconds();
+
+ if (!m_created_by.empty())
+ dict["created by"] = m_created_by;
+
+ if (!m_url_seeds.empty())
+ {
+ if (m_url_seeds.size() == 1)
+ {
+ dict["url-list"] = m_url_seeds.front();
+ }
+ else
+ {
+ entry& list = dict["url-list"];
+ for (std::vector<std::string>::const_iterator i
+ = m_url_seeds.begin(); i != m_url_seeds.end(); ++i)
+ {
+ list.list().push_back(entry(*i));
+ }
+ }
+ }
+
+ dict["info"] = create_info_metadata();
+
+ entry const& info_section = dict["info"];
+ std::vector<char> buf;
+ bencode(std::back_inserter(buf), info_section);
+ m_info_hash = hasher(&buf[0], buf.size()).final();
+
+ return dict;
+ }
+
+ void torrent_info::set_hash(int index, const sha1_hash& h)
+ {
+ TORRENT_ASSERT(index >= 0);
+ TORRENT_ASSERT(index < (int)m_piece_hash.size());
+ m_piece_hash[index] = h;
+ }
+
+ void torrent_info::convert_file_names()
+ {
+ TORRENT_ASSERT(false);
+ }
+
+ void torrent_info::seed_free()
+ {
+ std::vector<std::string>().swap(m_url_seeds);
+ nodes_t().swap(m_nodes);
+ std::vector<sha1_hash>().swap(m_piece_hash);
+#ifndef NDEBUG
+ m_half_metadata = true;
+#endif
+ }
+
+// ------- start deprecation -------
+
+ void torrent_info::print(std::ostream& os) const
+ {
+ os << "trackers:\n";
+ for (std::vector<announce_entry>::const_iterator i = trackers().begin();
+ i != trackers().end(); ++i)
+ {
+ os << i->tier << ": " << i->url << "\n";
+ }
+ if (!m_comment.empty())
+ os << "comment: " << m_comment << "\n";
+// if (m_creation_date != pt::ptime(gr::date(pt::not_a_date_time)))
+// os << "creation date: " << to_simple_string(m_creation_date) << "\n";
+ os << "private: " << (m_private?"yes":"no") << "\n";
+ os << "number of pieces: " << num_pieces() << "\n";
+ os << "piece length: " << piece_length() << "\n";
+ os << "files:\n";
+ for (file_iterator i = begin_files(); i != end_files(); ++i)
+ os << " " << std::setw(11) << i->size << " " << i->path.string() << "\n";
+ }
+
+// ------- end deprecation -------
+
+ int torrent_info::piece_size(int index) const
+ {
+ TORRENT_ASSERT(index >= 0 && index < num_pieces());
+ if (index == num_pieces()-1)
+ {
+ size_type size = total_size()
+ - (num_pieces() - 1) * piece_length();
+ TORRENT_ASSERT(size > 0);
+ TORRENT_ASSERT(size <= piece_length());
+ return int(size);
+ }
+ else
+ return piece_length();
+ }
+
+ void torrent_info::add_node(std::pair<std::string, int> const& node)
+ {
+ m_nodes.push_back(node);
+ }
+
+ bool torrent_info::remap_files(std::vector<file_entry> const& map)
+ {
+ size_type offset = 0;
+ m_remapped_files.resize(map.size());
+
+ for (int i = 0; i < int(map.size()); ++i)
+ {
+ file_entry& fe = m_remapped_files[i];
+ fe.path = map[i].path;
+ fe.offset = offset;
+ fe.size = map[i].size;
+ fe.file_base = map[i].file_base;
+ fe.orig_path.reset();
+ offset += fe.size;
+ }
+ if (offset != total_size())
+ {
+ m_remapped_files.clear();
+ return false;
+ }
+
+#ifndef NDEBUG
+ std::vector<file_entry> map2(m_remapped_files);
+ std::sort(map2.begin(), map2.end()
+ , bind(&file_entry::file_base, _1) < bind(&file_entry::file_base, _2));
+ std::stable_sort(map2.begin(), map2.end()
+ , bind(&file_entry::path, _1) < bind(&file_entry::path, _2));
+ fs::path last_path;
+ size_type last_end = 0;
+ for (std::vector<file_entry>::iterator i = map2.begin(), end(map2.end());
+ i != end; ++i)
+ {
+ if (last_path == i->path)
+ {
+ assert(last_end <= i->file_base);
+ }
+ last_end = i->file_base + i->size;
+ last_path = i->path;
+ }
+#endif
+
+ return true;
+ }
+
+ std::vector<file_slice> torrent_info::map_block(int piece, size_type offset
+ , int size_, bool storage) const
+ {
+ TORRENT_ASSERT(num_files() > 0);
+ std::vector<file_slice> ret;
+
+ size_type start = piece * (size_type)m_piece_length + offset;
+ size_type size = size_;
+ TORRENT_ASSERT(start + size <= m_total_size);
+
+ // find the file iterator and file offset
+ // TODO: make a vector that can map piece -> file index in O(1)
+ size_type file_offset = start;
+ std::vector<file_entry>::const_iterator file_iter;
+
+ int counter = 0;
+ for (file_iter = begin_files(storage);; ++counter, ++file_iter)
+ {
+ TORRENT_ASSERT(file_iter != end_files(storage));
+ if (file_offset < file_iter->size)
+ {
+ file_slice f;
+ f.file_index = counter;
+ f.offset = file_offset + file_iter->file_base;
+ f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
+ size -= f.size;
+ file_offset += f.size;
+ ret.push_back(f);
+ }
+
+ TORRENT_ASSERT(size >= 0);
+ if (size <= 0) break;
+
+ file_offset -= file_iter->size;
+ }
+ return ret;
+ }
+
+ peer_request torrent_info::map_file(int file_index, size_type file_offset
+ , int size, bool storage) const
+ {
+ TORRENT_ASSERT(file_index < num_files(storage));
+ TORRENT_ASSERT(file_index >= 0);
+ size_type offset = file_offset + file_at(file_index, storage).offset;
+
+ peer_request ret;
+ ret.piece = int(offset / piece_length());
+ ret.start = int(offset - ret.piece * piece_length());
+ ret.length = size;
+ return ret;
+ }
+
+}
diff --git a/src/libtorrent/src/tracker_manager.cpp b/src/libtorrent/src/tracker_manager.cpp
new file mode 100644
index 0000000..eb1f4cf
--- /dev/null
+++ b/src/libtorrent/src/tracker_manager.cpp
@@ -0,0 +1,609 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <iostream>
+#include <cctype>
+#include <iomanip>
+#include <sstream>
+
+#include "zlib.h"
+
+#include <boost/bind.hpp>
+
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/http_tracker_connection.hpp"
+#include "libtorrent/udp_tracker_connection.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/peer_connection.hpp"
+
+using namespace libtorrent;
+using boost::tuples::make_tuple;
+using boost::tuples::tuple;
+using boost::bind;
+
+namespace
+{
+ enum
+ {
+ minimum_tracker_response_length = 3,
+ http_buffer_size = 2048
+ };
+
+
+ enum
+ {
+ FTEXT = 0x01,
+ FHCRC = 0x02,
+ FEXTRA = 0x04,
+ FNAME = 0x08,
+ FCOMMENT = 0x10,
+ FRESERVED = 0xe0,
+
+ GZIP_MAGIC0 = 0x1f,
+ GZIP_MAGIC1 = 0x8b
+ };
+
+}
+
+namespace libtorrent
+{
+ // returns -1 if gzip header is invalid or the header size in bytes
+ int gzip_header(const char* buf, int size)
+ {
+ TORRENT_ASSERT(buf != 0);
+ TORRENT_ASSERT(size > 0);
+
+ const unsigned char* buffer = reinterpret_cast<const unsigned char*>(buf);
+ const int total_size = size;
+
+ // The zip header cannot be shorter than 10 bytes
+ if (size < 10) return -1;
+
+ // check the magic header of gzip
+ if ((buffer[0] != GZIP_MAGIC0) || (buffer[1] != GZIP_MAGIC1)) return -1;
+
+ int method = buffer[2];
+ int flags = buffer[3];
+
+ // check for reserved flag and make sure it's compressed with the correct metod
+ if (method != Z_DEFLATED || (flags & FRESERVED) != 0) return -1;
+
+ // skip time, xflags, OS code
+ size -= 10;
+ buffer += 10;
+
+ if (flags & FEXTRA)
+ {
+ int extra_len;
+
+ if (size < 2) return -1;
+
+ extra_len = (buffer[1] << 8) | buffer[0];
+
+ if (size < (extra_len+2)) return -1;
+ size -= (extra_len + 2);
+ buffer += (extra_len + 2);
+ }
+
+ if (flags & FNAME)
+ {
+ while (size && *buffer)
+ {
+ --size;
+ ++buffer;
+ }
+ if (!size || *buffer) return -1;
+
+ --size;
+ ++buffer;
+ }
+
+ if (flags & FCOMMENT)
+ {
+ while (size && *buffer)
+ {
+ --size;
+ ++buffer;
+ }
+ if (!size || *buffer) return -1;
+
+ --size;
+ ++buffer;
+ }
+
+ if (flags & FHCRC)
+ {
+ if (size < 2) return -1;
+
+ size -= 2;
+ buffer += 2;
+ }
+
+ return total_size - size;
+ }
+
+ bool inflate_gzip(
+ std::vector<char>& buffer
+ , tracker_request const& req
+ , request_callback* requester
+ , int maximum_tracker_response_length)
+ {
+ TORRENT_ASSERT(maximum_tracker_response_length > 0);
+
+ int header_len = gzip_header(&buffer[0], (int)buffer.size());
+ if (header_len < 0)
+ {
+ requester->tracker_request_error(req, 200, "invalid gzip header in tracker response");
+ return true;
+ }
+
+ // start off wth one kilobyte and grow
+ // if needed
+ std::vector<char> inflate_buffer(1024);
+
+ // initialize the zlib-stream
+ z_stream str;
+
+ // subtract 8 from the end of the buffer since that's CRC32 and input size
+ // and those belong to the gzip file
+ str.avail_in = (int)buffer.size() - header_len - 8;
+ str.next_in = reinterpret_cast<Bytef*>(&buffer[header_len]);
+ str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[0]);
+ str.avail_out = (int)inflate_buffer.size();
+ str.zalloc = Z_NULL;
+ str.zfree = Z_NULL;
+ str.opaque = 0;
+ // -15 is really important. It will make inflate() not look for a zlib header
+ // and just deflate the buffer
+ if (inflateInit2(&str, -15) != Z_OK)
+ {
+ requester->tracker_request_error(req, 200, "gzip out of memory");
+ return true;
+ }
+
+ // inflate and grow inflate_buffer as needed
+ int ret = inflate(&str, Z_SYNC_FLUSH);
+ while (ret == Z_OK)
+ {
+ if (str.avail_out == 0)
+ {
+ if (inflate_buffer.size() >= (unsigned)maximum_tracker_response_length)
+ {
+ inflateEnd(&str);
+ requester->tracker_request_error(req, 200
+ , "tracker response too large");
+ return true;
+ }
+ int new_size = (int)inflate_buffer.size() * 2;
+ if (new_size > maximum_tracker_response_length) new_size = maximum_tracker_response_length;
+ int old_size = (int)inflate_buffer.size();
+
+ inflate_buffer.resize(new_size);
+ str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[old_size]);
+ str.avail_out = new_size - old_size;
+ }
+
+ ret = inflate(&str, Z_SYNC_FLUSH);
+ }
+
+ inflate_buffer.resize(inflate_buffer.size() - str.avail_out);
+ inflateEnd(&str);
+
+ if (ret != Z_STREAM_END)
+ {
+ requester->tracker_request_error(req, 200, "gzip error");
+ return true;
+ }
+
+ // commit the resulting buffer
+ std::swap(buffer, inflate_buffer);
+ return false;
+ }
+
+ std::string base64encode(const std::string& s)
+ {
+ static const char base64_table[] =
+ {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'
+ };
+
+ unsigned char inbuf[3];
+ unsigned char outbuf[4];
+
+ std::string ret;
+ for (std::string::const_iterator i = s.begin(); i != s.end();)
+ {
+ // available input is 1,2 or 3 bytes
+ // since we read 3 bytes at a time at most
+ int available_input = (std::min)(3, (int)std::distance(i, s.end()));
+
+ // clear input buffer
+ std::fill(inbuf, inbuf+3, 0);
+
+ // read a chunk of input into inbuf
+ for (int j = 0; j < available_input; ++j)
+ {
+ inbuf[j] = *i;
+ ++i;
+ }
+
+ // encode inbuf to outbuf
+ outbuf[0] = (inbuf[0] & 0xfc) >> 2;
+ outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
+ outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
+ outbuf[3] = inbuf[2] & 0x3f;
+
+ // write output
+ for (int j = 0; j < available_input+1; ++j)
+ {
+ ret += base64_table[outbuf[j]];
+ }
+
+ // write pad
+ for (int j = 0; j < 3 - available_input; ++j)
+ {
+ ret += '=';
+ }
+ }
+ return ret;
+ }
+
+ timeout_handler::timeout_handler(asio::strand& str)
+ : m_strand(str)
+ , m_start_time(time_now())
+ , m_read_time(time_now())
+ , m_timeout(str.io_service())
+ , m_completion_timeout(0)
+ , m_read_timeout(0)
+ , m_abort(false)
+ {}
+
+ void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
+ {
+ m_completion_timeout = completion_timeout;
+ m_read_timeout = read_timeout;
+ m_start_time = m_read_time = time_now();
+
+ if (m_abort) return;
+
+ int timeout = (std::min)(
+ m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout));
+ m_timeout.expires_at(m_read_time + seconds(timeout));
+ m_timeout.async_wait(m_strand.wrap(bind(
+ &timeout_handler::timeout_callback, self(), _1)));
+ }
+
+ void timeout_handler::restart_read_timeout()
+ {
+ m_read_time = time_now();
+ }
+
+ void timeout_handler::cancel()
+ {
+ m_abort = true;
+ m_completion_timeout = 0;
+ m_timeout.cancel();
+ }
+
+ void timeout_handler::timeout_callback(asio::error_code const& error) try
+ {
+ if (error) return;
+ if (m_completion_timeout == 0) return;
+
+ ptime now(time_now());
+ time_duration receive_timeout = now - m_read_time;
+ time_duration completion_timeout = now - m_start_time;
+
+ if (m_read_timeout
+ < total_seconds(receive_timeout)
+ || m_completion_timeout
+ < total_seconds(completion_timeout))
+ {
+ on_timeout();
+ return;
+ }
+
+ if (m_abort) return;
+
+ int timeout = (std::min)(
+ m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout));
+ m_timeout.expires_at(m_read_time + seconds(timeout));
+ m_timeout.async_wait(m_strand.wrap(
+ bind(&timeout_handler::timeout_callback, self(), _1)));
+ }
+ catch (std::exception&)
+ {
+ TORRENT_ASSERT(false);
+ }
+
+ tracker_connection::tracker_connection(
+ tracker_manager& man
+ , tracker_request const& req
+ , asio::strand& str
+ , address bind_interface_
+ , boost::weak_ptr<request_callback> r)
+ : timeout_handler(str)
+ , m_requester(r)
+ , m_bind_interface(bind_interface_)
+ , m_man(man)
+ , m_req(req)
+ {}
+
+ boost::shared_ptr<request_callback> tracker_connection::requester()
+ {
+ return m_requester.lock();
+ }
+
+ void tracker_connection::fail(int code, char const* msg)
+ {
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb) cb->tracker_request_error(m_req, code, msg);
+ close();
+ }
+
+ void tracker_connection::fail_timeout()
+ {
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb) cb->tracker_request_timed_out(m_req);
+ close();
+ }
+
+ void tracker_connection::close()
+ {
+ cancel();
+ m_man.remove_request(this);
+ }
+
+ void tracker_manager::remove_request(tracker_connection const* c)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+
+ tracker_connections_t::iterator i = std::find(m_connections.begin()
+ , m_connections.end(), boost::intrusive_ptr<const tracker_connection>(c));
+ if (i == m_connections.end()) return;
+
+ m_connections.erase(i);
+ }
+
+ // returns protocol, auth, hostname, port, path
+ tuple<std::string, std::string, std::string, int, std::string>
+ parse_url_components(std::string url)
+ {
+ std::string hostname; // hostname only
+ std::string auth; // user:pass
+ std::string protocol; // should be http
+ int port = 80;
+
+ // PARSE URL
+ std::string::iterator start = url.begin();
+ // remove white spaces in front of the url
+ while (start != url.end() && (*start == ' ' || *start == '\t'))
+ ++start;
+ std::string::iterator end
+ = std::find(url.begin(), url.end(), ':');
+ protocol.assign(start, end);
+
+ if (end == url.end()) throw std::runtime_error("invalid url");
+ ++end;
+ if (end == url.end()) throw std::runtime_error("invalid url");
+ if (*end != '/') throw std::runtime_error("invalid url");
+ ++end;
+ if (end == url.end()) throw std::runtime_error("invalid url");
+ if (*end != '/') throw std::runtime_error("invalid url");
+ ++end;
+ start = end;
+
+ std::string::iterator at = std::find(start, url.end(), '@');
+ std::string::iterator colon = std::find(start, url.end(), ':');
+ end = std::find(start, url.end(), '/');
+
+ if (at != url.end()
+ && colon != url.end()
+ && colon < at
+ && at < end)
+ {
+ auth.assign(start, at);
+ start = at;
+ ++start;
+ }
+
+ std::string::iterator port_pos;
+
+ // this is for IPv6 addresses
+ if (start != url.end() && *start == '[')
+ {
+ port_pos = std::find(start, url.end(), ']');
+ if (port_pos == url.end()) throw std::runtime_error("invalid hostname syntax");
+ port_pos = std::find(port_pos, url.end(), ':');
+ }
+ else
+ {
+ port_pos = std::find(start, url.end(), ':');
+ }
+
+ if (port_pos < end)
+ {
+ hostname.assign(start, port_pos);
+ ++port_pos;
+ try
+ {
+ port = boost::lexical_cast<int>(std::string(port_pos, end));
+ }
+ catch(boost::bad_lexical_cast&)
+ {
+ throw std::runtime_error("invalid url: \"" + url
+ + "\", port number expected");
+ }
+ }
+ else
+ {
+ hostname.assign(start, end);
+ }
+
+ start = end;
+ return make_tuple(protocol, auth, hostname, port
+ , std::string(start, url.end()));
+ }
+
+ void tracker_manager::queue_request(
+ asio::strand& str
+ , connection_queue& cc
+ , tracker_request req
+ , std::string const& auth
+ , address bind_infc
+ , boost::weak_ptr<request_callback> c)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ TORRENT_ASSERT(req.num_want >= 0);
+ if (req.event == tracker_request::stopped)
+ req.num_want = 0;
+
+ TORRENT_ASSERT(!m_abort || req.event == tracker_request::stopped);
+ if (m_abort && req.event != tracker_request::stopped)
+ return;
+
+ try
+ {
+ std::string protocol;
+ std::string hostname;
+ int port;
+ std::string request_string;
+
+ using boost::tuples::ignore;
+ // TODO: should auth be used here?
+ boost::tie(protocol, ignore, hostname, port, request_string)
+ = parse_url_components(req.url);
+
+ boost::intrusive_ptr<tracker_connection> con;
+
+ if (protocol == "http")
+ {
+ con = new http_tracker_connection(
+ str
+ , cc
+ , *this
+ , req
+ , hostname
+ , port
+ , request_string
+ , bind_infc
+ , c
+ , m_settings
+ , m_proxy
+ , auth);
+ }
+ else if (protocol == "udp")
+ {
+ con = new udp_tracker_connection(
+ str
+ , *this
+ , req
+ , hostname
+ , port
+ , bind_infc
+ , c
+ , m_settings);
+ }
+ else
+ {
+ throw std::runtime_error("unkown protocol in tracker url");
+ }
+
+ m_connections.push_back(con);
+
+ boost::shared_ptr<request_callback> cb = con->requester();
+ if (cb) cb->m_manager = this;
+ }
+ catch (std::exception& e)
+ {
+ if (boost::shared_ptr<request_callback> r = c.lock())
+ r->tracker_request_error(req, -1, e.what());
+ }
+ }
+
+ void tracker_manager::abort_all_requests()
+ {
+ // removes all connections from m_connections
+ // except those with a requester == 0 (since those are
+ // 'event=stopped'-requests)
+ mutex_t::scoped_lock l(m_mutex);
+
+ m_abort = true;
+ tracker_connections_t keep_connections;
+
+ while (!m_connections.empty())
+ {
+ boost::intrusive_ptr<tracker_connection>& c = m_connections.back();
+ if (!c)
+ {
+ m_connections.pop_back();
+ continue;
+ }
+ tracker_request const& req = c->tracker_req();
+ if (req.event == tracker_request::stopped)
+ {
+ keep_connections.push_back(c);
+ m_connections.pop_back();
+ continue;
+ }
+ // close will remove the entry from m_connections
+ // so no need to pop
+ c->close();
+ }
+
+ std::swap(m_connections, keep_connections);
+ }
+
+ bool tracker_manager::empty() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ return m_connections.empty();
+ }
+
+ int tracker_manager::num_requests() const
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ return m_connections.size();
+ }
+}
diff --git a/src/libtorrent/src/udp_tracker_connection.cpp b/src/libtorrent/src/udp_tracker_connection.cpp
new file mode 100644
index 0000000..0ad38ef
--- /dev/null
+++ b/src/libtorrent/src/udp_tracker_connection.cpp
@@ -0,0 +1,573 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <iostream>
+#include <cctype>
+#include <iomanip>
+#include <sstream>
+
+#include "zlib.h"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/tracker_manager.hpp"
+#include "libtorrent/udp_tracker_connection.hpp"
+#include "libtorrent/io.hpp"
+
+namespace
+{
+ enum
+ {
+ udp_connection_retries = 4,
+ udp_announce_retries = 15,
+ udp_connect_timeout = 15,
+ udp_announce_timeout = 10,
+ udp_buffer_size = 2048
+ };
+}
+
+using boost::bind;
+using boost::lexical_cast;
+
+namespace libtorrent
+{
+
+ udp_tracker_connection::udp_tracker_connection(
+ asio::strand& str
+ , tracker_manager& man
+ , tracker_request const& req
+ , std::string const& hostname
+ , unsigned short port
+ , address bind_infc
+ , boost::weak_ptr<request_callback> c
+ , session_settings const& stn)
+ : tracker_connection(man, req, str, bind_infc, c)
+ , m_man(man)
+ , m_strand(str)
+ , m_name_lookup(m_strand.io_service())
+ , m_socket(m_strand.io_service())
+ , m_transaction_id(0)
+ , m_connection_id(0)
+ , m_settings(stn)
+ , m_attempts(0)
+ {
+ udp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
+ m_name_lookup.async_resolve(q
+ , m_strand.wrap(boost::bind(
+ &udp_tracker_connection::name_lookup, self(), _1, _2)));
+ set_timeout(req.event == tracker_request::stopped
+ ? m_settings.stop_tracker_timeout
+ : m_settings.tracker_completion_timeout
+ , m_settings.tracker_receive_timeout);
+ }
+
+ void udp_tracker_connection::name_lookup(asio::error_code const& error
+ , udp::resolver::iterator i) try
+ {
+ if (error == asio::error::operation_aborted) return;
+ if (error || i == udp::resolver::iterator())
+ {
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+ boost::shared_ptr<request_callback> cb = requester();
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (cb) cb->debug_log("udp tracker name lookup successful");
+#endif
+ restart_read_timeout();
+
+ // look for an address that has the same kind as the one
+ // we're listening on. To make sure the tracker get our
+ // correct listening address.
+ udp::resolver::iterator target = i;
+ udp::resolver::iterator end;
+ udp::endpoint target_address = *i;
+ for (; target != end && target->endpoint().address().is_v4()
+ != bind_interface().is_v4(); ++target);
+ if (target == end)
+ {
+ TORRENT_ASSERT(target_address.address().is_v4() != bind_interface().is_v4());
+ if (cb)
+ {
+ std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
+ std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
+ cb->tracker_warning("the tracker only resolves to an "
+ + tracker_address_type + " address, and you're listening on an "
+ + bind_address_type + " socket. This may prevent you from receiving incoming connections.");
+ }
+ }
+ else
+ {
+ target_address = *target;
+ }
+
+ if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
+ m_target = target_address;
+ m_socket.open(target_address.protocol());
+ m_socket.bind(udp::endpoint(bind_interface(), 0));
+ m_socket.connect(target_address);
+ send_udp_connect();
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ };
+
+ void udp_tracker_connection::on_timeout()
+ {
+ asio::error_code ec;
+ m_socket.close(ec);
+ m_name_lookup.cancel();
+ fail_timeout();
+ }
+
+ void udp_tracker_connection::close()
+ {
+ asio::error_code ec;
+ m_socket.close(ec);
+ m_name_lookup.cancel();
+ tracker_connection::close();
+ }
+
+ void udp_tracker_connection::send_udp_connect()
+ {
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb)
+ {
+ cb->debug_log("==> UDP_TRACKER_CONNECT ["
+ + lexical_cast<std::string>(tracker_req().info_hash) + "]");
+ }
+#endif
+ if (!m_socket.is_open()) return; // the operation was aborted
+
+ char send_buf[16];
+ char* ptr = send_buf;
+
+ if (m_transaction_id == 0)
+ m_transaction_id = rand() ^ (rand() << 16);
+
+ // connection_id
+ detail::write_uint32(0x417, ptr);
+ detail::write_uint32(0x27101980, ptr);
+ // action (connect)
+ detail::write_int32(action_connect, ptr);
+ // transaction_id
+ detail::write_int32(m_transaction_id, ptr);
+
+ m_socket.send(asio::buffer((void*)send_buf, 16), 0);
+ ++m_attempts;
+ m_buffer.resize(udp_buffer_size);
+ m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
+ , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
+ }
+
+ void udp_tracker_connection::connect_response(asio::error_code const& error
+ , std::size_t bytes_transferred) try
+ {
+ if (error == asio::error::operation_aborted) return;
+ if (!m_socket.is_open()) return; // the operation was aborted
+ if (error)
+ {
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+ if (m_target != m_sender)
+ {
+ // this packet was not received from the tracker
+ m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
+ , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
+ return;
+ }
+
+ if (bytes_transferred >= udp_buffer_size)
+ {
+ fail(-1, "udp response too big");
+ return;
+ }
+
+ if (bytes_transferred < 8)
+ {
+ fail(-1, "got a message with size < 8");
+ return;
+ }
+
+ restart_read_timeout();
+
+ const char* ptr = &m_buffer[0];
+ int action = detail::read_int32(ptr);
+ int transaction = detail::read_int32(ptr);
+
+ if (action == action_error)
+ {
+ fail(-1, std::string(ptr, bytes_transferred - 8).c_str());
+ return;
+ }
+
+ if (action != action_connect)
+ {
+ fail(-1, "invalid action in connect reply");
+ return;
+ }
+
+ if (m_transaction_id != transaction)
+ {
+ fail(-1, "incorrect transaction id");
+ return;
+ }
+
+ if (bytes_transferred < 16)
+ {
+ fail(-1, "udp_tracker_connection: "
+ "got a message with size < 16");
+ return;
+ }
+ // reset transaction
+ m_transaction_id = 0;
+ m_attempts = 0;
+ m_connection_id = detail::read_int64(ptr);
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb)
+ {
+ cb->debug_log("<== UDP_TRACKER_CONNECT_RESPONSE ["
+ + lexical_cast<std::string>(m_connection_id) + "]");
+ }
+#endif
+
+ if (tracker_req().kind == tracker_request::announce_request)
+ send_udp_announce();
+ else if (tracker_req().kind == tracker_request::scrape_request)
+ send_udp_scrape();
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ }
+
+ void udp_tracker_connection::send_udp_announce()
+ {
+ if (m_transaction_id == 0)
+ m_transaction_id = rand() ^ (rand() << 16);
+
+ if (!m_socket.is_open()) return; // the operation was aborted
+
+ std::vector<char> buf;
+ std::back_insert_iterator<std::vector<char> > out(buf);
+
+ tracker_request const& req = tracker_req();
+
+ // connection_id
+ detail::write_int64(m_connection_id, out);
+ // action (announce)
+ detail::write_int32(action_announce, out);
+ // transaction_id
+ detail::write_int32(m_transaction_id, out);
+ // info_hash
+ std::copy(req.info_hash.begin(), req.info_hash.end(), out);
+ // peer_id
+ std::copy(req.pid.begin(), req.pid.end(), out);
+ // downloaded
+ detail::write_int64(req.downloaded, out);
+ // left
+ detail::write_int64(req.left, out);
+ // uploaded
+ detail::write_int64(req.uploaded, out);
+ // event
+ detail::write_int32(req.event, out);
+ // ip address
+ if (m_settings.announce_ip != address() && m_settings.announce_ip.is_v4())
+ detail::write_uint32(m_settings.announce_ip.to_v4().to_ulong(), out);
+ else
+ detail::write_int32(0, out);
+ // key
+ detail::write_int32(req.key, out);
+ // num_want
+ detail::write_int32(req.num_want, out);
+ // port
+ detail::write_uint16(req.listen_port, out);
+ // extensions
+ detail::write_uint16(0, out);
+
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ boost::shared_ptr<request_callback> cb = requester();
+ if (cb)
+ {
+ cb->debug_log("==> UDP_TRACKER_ANNOUNCE ["
+ + lexical_cast<std::string>(req.info_hash) + "]");
+ }
+#endif
+
+ m_socket.send(asio::buffer(buf), 0);
+ ++m_attempts;
+
+ m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
+ , bind(&udp_tracker_connection::announce_response, self(), _1, _2));
+ }
+
+ void udp_tracker_connection::send_udp_scrape()
+ {
+ if (m_transaction_id == 0)
+ m_transaction_id = rand() ^ (rand() << 16);
+
+ if (!m_socket.is_open()) return; // the operation was aborted
+
+ std::vector<char> buf;
+ std::back_insert_iterator<std::vector<char> > out(buf);
+
+ // connection_id
+ detail::write_int64(m_connection_id, out);
+ // action (scrape)
+ detail::write_int32(action_scrape, out);
+ // transaction_id
+ detail::write_int32(m_transaction_id, out);
+ // info_hash
+ std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out);
+
+ m_socket.send(asio::buffer(&buf[0], buf.size()), 0);
+ ++m_attempts;
+
+ m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
+ , bind(&udp_tracker_connection::scrape_response, self(), _1, _2));
+ }
+
+ void udp_tracker_connection::announce_response(asio::error_code const& error
+ , std::size_t bytes_transferred) try
+ {
+ if (error == asio::error::operation_aborted) return;
+ if (!m_socket.is_open()) return; // the operation was aborted
+ if (error)
+ {
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+ if (m_target != m_sender)
+ {
+ // this packet was not received from the tracker
+ m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
+ , bind(&udp_tracker_connection::connect_response, self(), _1, _2));
+ return;
+ }
+
+ if (bytes_transferred >= udp_buffer_size)
+ {
+ fail(-1, "udp response too big");
+ return;
+ }
+
+ if (bytes_transferred < 8)
+ {
+ fail(-1, "got a message with size < 8");
+ return;
+ }
+
+ restart_read_timeout();
+ char* buf = &m_buffer[0];
+ int action = detail::read_int32(buf);
+ int transaction = detail::read_int32(buf);
+
+ if (transaction != m_transaction_id)
+ {
+ fail(-1, "incorrect transaction id");
+ return;
+ }
+
+ if (action == action_error)
+ {
+ fail(-1, std::string(buf, bytes_transferred - 8).c_str());
+ return;
+ }
+
+ if (action != action_announce)
+ {
+ fail(-1, "invalid action in announce response");
+ return;
+ }
+
+ if (bytes_transferred < 20)
+ {
+ fail(-1, "got a message with size < 20");
+ return;
+ }
+
+ int interval = detail::read_int32(buf);
+ int incomplete = detail::read_int32(buf);
+ int complete = detail::read_int32(buf);
+ int num_peers = (bytes_transferred - 20) / 6;
+ if ((bytes_transferred - 20) % 6 != 0)
+ {
+ fail(-1, "invalid udp tracker response length");
+ return;
+ }
+
+ boost::shared_ptr<request_callback> cb = requester();
+#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
+ if (cb)
+ {
+ cb->debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
+ }
+#endif
+
+ if (!cb)
+ {
+ m_man.remove_request(this);
+ return;
+ }
+
+ std::vector<peer_entry> peer_list;
+ for (int i = 0; i < num_peers; ++i)
+ {
+ peer_entry e;
+ std::stringstream s;
+ s << (int)detail::read_uint8(buf) << ".";
+ s << (int)detail::read_uint8(buf) << ".";
+ s << (int)detail::read_uint8(buf) << ".";
+ s << (int)detail::read_uint8(buf);
+ e.ip = s.str();
+ e.port = detail::read_uint16(buf);
+ e.pid.clear();
+ peer_list.push_back(e);
+ }
+
+ cb->tracker_response(tracker_req(), peer_list, interval
+ , complete, incomplete);
+
+ m_man.remove_request(this);
+ close();
+ return;
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ }; // msvc 7.1 seems to require this
+
+ void udp_tracker_connection::scrape_response(asio::error_code const& error
+ , std::size_t bytes_transferred) try
+ {
+ if (error == asio::error::operation_aborted) return;
+ if (!m_socket.is_open()) return; // the operation was aborted
+ if (error)
+ {
+ fail(-1, error.message().c_str());
+ return;
+ }
+
+ if (m_target != m_sender)
+ {
+ // this packet was not received from the tracker
+ m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
+ , bind(&udp_tracker_connection::connect_response, self(), _1, _2));
+ return;
+ }
+
+ if (bytes_transferred >= udp_buffer_size)
+ {
+ fail(-1, "udp response too big");
+ return;
+ }
+
+ if (bytes_transferred < 8)
+ {
+ fail(-1, "got a message with size < 8");
+ return;
+ }
+
+ restart_read_timeout();
+ char* buf = &m_buffer[0];
+ int action = detail::read_int32(buf);
+ int transaction = detail::read_int32(buf);
+
+ if (transaction != m_transaction_id)
+ {
+ fail(-1, "incorrect transaction id");
+ return;
+ }
+
+ if (action == action_error)
+ {
+ fail(-1, std::string(buf, bytes_transferred - 8).c_str());
+ return;
+ }
+
+ if (action != action_scrape)
+ {
+ fail(-1, "invalid action in announce response");
+ return;
+ }
+
+ if (bytes_transferred < 20)
+ {
+ fail(-1, "got a message with size < 20");
+ return;
+ }
+
+ int complete = detail::read_int32(buf);
+ int downloaded = detail::read_int32(buf);
+ int incomplete = detail::read_int32(buf);
+
+ boost::shared_ptr<request_callback> cb = requester();
+ if (!cb)
+ {
+ m_man.remove_request(this);
+ close();
+ return;
+ }
+
+ cb->tracker_scrape_response(tracker_req()
+ , complete, incomplete, downloaded);
+
+ m_man.remove_request(this);
+ close();
+ }
+ catch (std::exception& e)
+ {
+ fail(-1, e.what());
+ }
+
+}
+
diff --git a/src/libtorrent/src/upnp.cpp b/src/libtorrent/src/upnp.cpp
new file mode 100644
index 0000000..24cb776
--- /dev/null
+++ b/src/libtorrent/src/upnp.cpp
@@ -0,0 +1,1087 @@
+/*
+
+Copyright (c) 2007, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include "libtorrent/socket.hpp"
+#include "libtorrent/upnp.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/http_tracker_connection.hpp"
+#include "libtorrent/xml_parse.hpp"
+#include "libtorrent/connection_queue.hpp"
+#include "libtorrent/enum_net.hpp"
+
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <asio/ip/host_name.hpp>
+#include <asio/ip/multicast.hpp>
+#include <boost/thread/mutex.hpp>
+#include <cstdlib>
+
+#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) && !defined(TORRENT_UPNP_LOGGING)
+#define TORRENT_UPNP_LOGGING
+#endif
+
+using boost::bind;
+using namespace libtorrent;
+
+namespace libtorrent
+{
+ bool is_local(address const& a);
+ address guess_local_address(asio::io_service&);
+}
+
+upnp::upnp(io_service& ios, connection_queue& cc
+ , address const& listen_interface, std::string const& user_agent
+ , portmap_callback_t const& cb, bool ignore_nonrouters)
+ : m_udp_local_port(0)
+ , m_tcp_local_port(0)
+ , m_user_agent(user_agent)
+ , m_callback(cb)
+ , m_retry_count(0)
+ , m_io_service(ios)
+ , m_strand(ios)
+ , m_socket(ios, udp::endpoint(address_v4::from_string("239.255.255.250"), 1900)
+ , m_strand.wrap(bind(&upnp::on_reply, self(), _1, _2, _3)), false)
+ , m_broadcast_timer(ios)
+ , m_refresh_timer(ios)
+ , m_disabled(false)
+ , m_closing(false)
+ , m_ignore_outside_network(ignore_nonrouters)
+ , m_cc(cc)
+{
+#ifdef TORRENT_UPNP_LOGGING
+ m_log.open("upnp.log", std::ios::in | std::ios::out | std::ios::trunc);
+#endif
+ m_retry_count = 0;
+}
+
+upnp::~upnp()
+{
+}
+
+void upnp::discover_device() try
+{
+ const char msearch[] =
+ "M-SEARCH * HTTP/1.1\r\n"
+ "HOST: 239.255.255.250:1900\r\n"
+ "ST:upnp:rootdevice\r\n"
+ "MAN:\"ssdp:discover\"\r\n"
+ "MX:3\r\n"
+ "\r\n\r\n";
+
+ asio::error_code ec;
+#ifdef TORRENT_DEBUG_UPNP
+ // simulate packet loss
+ if (m_retry_count & 1)
+#endif
+ m_socket.send(msearch, sizeof(msearch) - 1, ec);
+
+ if (ec)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " ==> Broadcast FAILED: " << ec.message() << std::endl
+ << "aborting" << std::endl;
+#endif
+ disable();
+ return;
+ }
+
+ ++m_retry_count;
+ m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
+ m_broadcast_timer.async_wait(m_strand.wrap(bind(&upnp::resend_request
+ , self(), _1)));
+
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " ==> Broadcasting search for rootdevice" << std::endl;
+#endif
+}
+catch (std::exception&)
+{
+ disable();
+};
+
+void upnp::set_mappings(int tcp, int udp)
+{
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " *** set mappings " << tcp << " " << udp;
+ if (m_disabled) m_log << " DISABLED";
+ m_log << std::endl;
+#endif
+
+ if (m_disabled) return;
+ if (udp != 0) m_udp_local_port = udp;
+ if (tcp != 0) m_tcp_local_port = tcp;
+
+ for (std::set<rootdevice>::iterator i = m_devices.begin()
+ , end(m_devices.end()); i != end; ++i)
+ {
+ rootdevice& d = const_cast<rootdevice&>(*i);
+ TORRENT_ASSERT(d.magic == 1337);
+ if (d.mapping[0].local_port != m_tcp_local_port)
+ {
+ if (d.mapping[0].external_port == 0)
+ d.mapping[0].external_port = m_tcp_local_port;
+ d.mapping[0].local_port = m_tcp_local_port;
+ d.mapping[0].need_update = true;
+ }
+ if (d.mapping[1].local_port != m_udp_local_port)
+ {
+ if (d.mapping[1].external_port == 0)
+ d.mapping[1].external_port = m_udp_local_port;
+ d.mapping[1].local_port = m_udp_local_port;
+ d.mapping[1].need_update = true;
+ }
+ if (d.service_namespace
+ && (d.mapping[0].need_update || d.mapping[1].need_update))
+ map_port(d, 0);
+ }
+}
+
+void upnp::resend_request(asio::error_code const& e)
+#ifndef NDEBUG
+try
+#endif
+{
+ if (e) return;
+ if (m_retry_count < 9
+ && (m_devices.empty() || m_retry_count < 4))
+ {
+ discover_device();
+ return;
+ }
+
+ if (m_devices.empty())
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " *** Got no response in 9 retries. Giving up, "
+ "disabling UPnP." << std::endl;
+#endif
+ disable();
+ return;
+ }
+
+ for (std::set<rootdevice>::iterator i = m_devices.begin()
+ , end(m_devices.end()); i != end; ++i)
+ {
+ if (i->control_url.empty() && !i->upnp_connection && !i->disabled)
+ {
+ // we don't have a WANIP or WANPPP url for this device,
+ // ask for it
+ rootdevice& d = const_cast<rootdevice&>(*i);
+ TORRENT_ASSERT(d.magic == 1337);
+ try
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " ==> connecting to " << d.url << std::endl;
+#endif
+ d.upnp_connection.reset(new http_connection(m_io_service
+ , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, self(), _1, _2
+ , boost::ref(d)))));
+ d.upnp_connection->get(d.url);
+ }
+ catch (std::exception& e)
+ {
+ (void)e;
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " *** Connection failed to: " << d.url
+ << " " << e.what() << std::endl;
+#endif
+ d.disabled = true;
+ }
+ }
+ }
+}
+#ifndef NDEBUG
+catch (std::exception&)
+{
+ TORRENT_ASSERT(false);
+};
+#endif
+
+void upnp::on_reply(udp::endpoint const& from, char* buffer
+ , std::size_t bytes_transferred)
+#ifndef NDEBUG
+try
+#endif
+{
+ using namespace libtorrent::detail;
+
+ // parse out the url for the device
+
+/*
+ the response looks like this:
+
+ HTTP/1.1 200 OK
+ ST:upnp:rootdevice
+ USN:uuid:000f-66d6-7296000099dc::upnp:rootdevice
+ Location: http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc
+ Server: Custom/1.0 UPnP/1.0 Proc/Ver
+ EXT:
+ Cache-Control:max-age=180
+ DATE: Fri, 02 Jan 1970 08:10:38 GMT
+
+ a notification looks like this:
+
+ NOTIFY * HTTP/1.1
+ Host:239.255.255.250:1900
+ NT:urn:schemas-upnp-org:device:MediaServer:1
+ NTS:ssdp:alive
+ Location:http://10.0.3.169:2869/upnphost/udhisapi.dll?content=uuid:c17f0c32-d19b-4938-ae94-65f945c3a26e
+ USN:uuid:c17f0c32-d19b-4938-ae94-65f945c3a26e::urn:schemas-upnp-org:device:MediaServer:1
+ Cache-Control:max-age=900
+ Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0
+
+*/
+ asio::error_code ec;
+ if (m_ignore_outside_network && !in_local_network(m_io_service, from.address(), ec))
+ {
+ // this upnp device is filtered because it's not in the
+ // list of configured routers
+#ifdef TORRENT_UPNP_LOGGING
+ if (ec)
+ {
+ m_log << time_now_string() << " <== (" << from << ") error: "
+ << ec.message() << std::endl;
+ }
+ else
+ {
+ std::vector<ip_interface> const& net = enum_net_interfaces(m_io_service, ec);
+ m_log << time_now_string() << " <== (" << from << ") UPnP device "
+ "ignored because it's not on our network ";
+ for (std::vector<ip_interface>::const_iterator i = net.begin()
+ , end(net.end()); i != end; ++i)
+ {
+ m_log << "(" << i->interface_address << ", " << i->netmask << ") ";
+ }
+ m_log << std::endl;
+ }
+#endif
+ return;
+ }
+
+ http_parser p;
+ try
+ {
+ p.incoming(buffer::const_interval(buffer
+ , buffer + bytes_transferred));
+ }
+ catch (std::exception& e)
+ {
+ (void)e;
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << from << ") Rootdevice responded with incorrect HTTP packet. Ignoring device (" << e.what() << ")" << std::endl;
+#endif
+ return;
+ }
+
+ if (p.status_code() != 200 && p.method() != "notify")
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ if (p.method().empty())
+ m_log << time_now_string()
+ << " <== (" << from << ") Device responded with HTTP status: " << p.status_code()
+ << ". Ignoring device" << std::endl;
+ else
+ m_log << time_now_string()
+ << " <== (" << from << ") Device with HTTP method: " << p.method()
+ << ". Ignoring device" << std::endl;
+#endif
+ return;
+ }
+
+ if (!p.header_finished())
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << from << ") Rootdevice responded with incomplete HTTP "
+ "packet. Ignoring device" << std::endl;
+#endif
+ return;
+ }
+
+ std::string url = p.header("location");
+ if (url.empty())
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << from << ") Rootdevice response is missing a location header. "
+ "Ignoring device" << std::endl;
+#endif
+ return;
+ }
+
+ rootdevice d;
+ d.url = url;
+
+ std::set<rootdevice>::iterator i = m_devices.find(d);
+
+ if (i == m_devices.end())
+ {
+
+ std::string protocol;
+ std::string auth;
+ // we don't have this device in our list. Add it
+ boost::tie(protocol, auth, d.hostname, d.port, d.path)
+ = parse_url_components(d.url);
+
+ // ignore the auth here. It will be re-parsed
+ // by the http connection later
+
+ if (protocol != "http")
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << from << ") Rootdevice uses unsupported protocol: '" << protocol
+ << "'. Ignoring device" << std::endl;
+#endif
+ return;
+ }
+
+ if (d.port == 0)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << from << ") Rootdevice responded with a url with port 0. "
+ "Ignoring device" << std::endl;
+#endif
+ return;
+ }
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << from << ") Found rootdevice: " << d.url
+ << " total: " << m_devices.size() << std::endl;
+#endif
+
+ if (m_devices.size() >= 50)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << from << ") Too many devices (" << m_devices.size() << "), "
+ "ignoring: " << d.url << std::endl;
+#endif
+ return;
+ }
+
+ if (m_tcp_local_port != 0)
+ {
+ d.mapping[0].need_update = true;
+ d.mapping[0].local_port = m_tcp_local_port;
+ if (d.mapping[0].external_port == 0)
+ d.mapping[0].external_port = d.mapping[0].local_port;
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string() << " *** Mapping 0 will be updated" << std::endl;
+#endif
+ }
+ if (m_udp_local_port != 0)
+ {
+ d.mapping[1].need_update = true;
+ d.mapping[1].local_port = m_udp_local_port;
+ if (d.mapping[1].external_port == 0)
+ d.mapping[1].external_port = d.mapping[1].local_port;
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string() << " *** Mapping 1 will be updated" << std::endl;
+#endif
+ }
+ boost::tie(i, boost::tuples::ignore) = m_devices.insert(d);
+ }
+
+
+ // since we're using udp, send the query 4 times
+ // just to make sure we find all devices
+ if (m_retry_count >= 4 && !m_devices.empty())
+ {
+ m_broadcast_timer.cancel();
+
+ for (std::set<rootdevice>::iterator i = m_devices.begin()
+ , end(m_devices.end()); i != end; ++i)
+ {
+ if (i->control_url.empty() && !i->upnp_connection && !i->disabled)
+ {
+ // we don't have a WANIP or WANPPP url for this device,
+ // ask for it
+ rootdevice& d = const_cast<rootdevice&>(*i);
+ TORRENT_ASSERT(d.magic == 1337);
+ try
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " ==> connecting to " << d.url << std::endl;
+#endif
+ d.upnp_connection.reset(new http_connection(m_io_service
+ , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, self(), _1, _2
+ , boost::ref(d)))));
+ d.upnp_connection->get(d.url);
+ }
+ catch (std::exception& e)
+ {
+ (void)e;
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " *** Connection failed to: " << d.url
+ << " " << e.what() << std::endl;
+#endif
+ d.disabled = true;
+ }
+ }
+ }
+ }
+}
+#ifndef NDEBUG
+catch (std::exception&)
+{
+ TORRENT_ASSERT(false);
+};
+#endif
+
+void upnp::post(upnp::rootdevice const& d, std::string const& soap
+ , std::string const& soap_action)
+{
+ TORRENT_ASSERT(d.magic == 1337);
+ TORRENT_ASSERT(d.upnp_connection);
+
+ std::stringstream header;
+
+ header << "POST " << d.control_url << " HTTP/1.1\r\n"
+ "Host: " << d.hostname << ":" << d.port << "\r\n"
+ "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+ "Content-Length: " << soap.size() << "\r\n"
+ "Soapaction: \"" << d.service_namespace << "#" << soap_action << "\"\r\n\r\n" << soap;
+
+ d.upnp_connection->sendbuffer = header.str();
+
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " ==> sending: " << header.str() << std::endl;
+#endif
+
+}
+
+void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i)
+{
+ TORRENT_ASSERT(d.magic == 1337);
+
+ if (!d.upnp_connection)
+ {
+ TORRENT_ASSERT(d.disabled);
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string() << " *** mapping (" << i
+ << ") aborted" << std::endl;
+#endif
+ return;
+ }
+
+ std::string soap_action = "AddPortMapping";
+
+ std::stringstream soap;
+
+ soap << "<?xml version=\"1.0\"?>\n"
+ "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<s:Body><u:" << soap_action << " xmlns:u=\"" << d.service_namespace << "\">";
+
+ soap << "<NewRemoteHost></NewRemoteHost>"
+ "<NewExternalPort>" << d.mapping[i].external_port << "</NewExternalPort>"
+ "<NewProtocol>" << (d.mapping[i].protocol ? "UDP" : "TCP") << "</NewProtocol>"
+ "<NewInternalPort>" << d.mapping[i].local_port << "</NewInternalPort>"
+ "<NewInternalClient>" << c.socket().local_endpoint().address().to_string() << "</NewInternalClient>"
+ "<NewEnabled>1</NewEnabled>"
+ "<NewPortMappingDescription>" << m_user_agent << "</NewPortMappingDescription>"
+ "<NewLeaseDuration>" << d.lease_duration << "</NewLeaseDuration>";
+ soap << "</u:" << soap_action << "></s:Body></s:Envelope>";
+
+ post(d, soap.str(), soap_action);
+}
+
+void upnp::map_port(rootdevice& d, int i)
+{
+ TORRENT_ASSERT(d.magic == 1337);
+ if (d.upnp_connection) return;
+
+ if (!d.mapping[i].need_update)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string() << " *** mapping (" << i
+ << ") does not need update, skipping" << std::endl;
+#endif
+ if (i < num_mappings - 1)
+ map_port(d, i + 1);
+ return;
+ }
+ d.mapping[i].need_update = false;
+ TORRENT_ASSERT(!d.upnp_connection);
+ TORRENT_ASSERT(d.service_namespace);
+
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " ==> connecting to " << d.hostname << std::endl;
+#endif
+ d.upnp_connection.reset(new http_connection(m_io_service
+ , m_cc, m_strand.wrap(bind(&upnp::on_upnp_map_response, self(), _1, _2
+ , boost::ref(d), i)), true
+ , bind(&upnp::create_port_mapping, self(), _1, boost::ref(d), i)));
+
+ d.upnp_connection->start(d.hostname, boost::lexical_cast<std::string>(d.port)
+ , seconds(10));
+}
+
+void upnp::delete_port_mapping(rootdevice& d, int i)
+{
+ TORRENT_ASSERT(d.magic == 1337);
+
+ if (!d.upnp_connection)
+ {
+ TORRENT_ASSERT(d.disabled);
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string() << " *** unmapping (" << i
+ << ") aborted" << std::endl;
+#endif
+ return;
+ }
+
+ std::stringstream soap;
+
+ std::string soap_action = "DeletePortMapping";
+
+ soap << "<?xml version=\"1.0\"?>\n"
+ "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<s:Body><u:" << soap_action << " xmlns:u=\"" << d.service_namespace << "\">";
+
+ soap << "<NewRemoteHost></NewRemoteHost>"
+ "<NewExternalPort>" << d.mapping[i].external_port << "</NewExternalPort>"
+ "<NewProtocol>" << (d.mapping[i].protocol ? "UDP" : "TCP") << "</NewProtocol>";
+ soap << "</u:" << soap_action << "></s:Body></s:Envelope>";
+
+ post(d, soap.str(), soap_action);
+}
+
+// requires the mutex to be locked
+void upnp::unmap_port(rootdevice& d, int i)
+{
+ TORRENT_ASSERT(d.magic == 1337);
+ if (d.mapping[i].external_port == 0
+ || d.disabled)
+ {
+ if (i < num_mappings - 1)
+ {
+ unmap_port(d, i + 1);
+ }
+ return;
+ }
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " ==> connecting to " << d.hostname << std::endl;
+#endif
+ d.upnp_connection.reset(new http_connection(m_io_service
+ , m_cc, m_strand.wrap(bind(&upnp::on_upnp_unmap_response, self(), _1, _2
+ , boost::ref(d), i)), true
+ , bind(&upnp::delete_port_mapping, self(), boost::ref(d), i)));
+ d.upnp_connection->start(d.hostname, boost::lexical_cast<std::string>(d.port)
+ , seconds(10));
+}
+
+namespace
+{
+ struct parse_state
+ {
+ parse_state(): found_service(false), exit(false) {}
+ void reset(char const* st)
+ {
+ found_service = false;
+ exit = false;
+ service_type = st;
+ }
+ bool found_service;
+ bool exit;
+ std::string top_tag;
+ std::string control_url;
+ char const* service_type;
+ };
+
+ void find_control_url(int type, char const* string, parse_state& state)
+ {
+ if (state.exit) return;
+
+ if (type == xml_start_tag)
+ {
+ if ((!state.top_tag.empty() && state.top_tag == "service")
+ || !strcmp(string, "service"))
+ {
+ state.top_tag = string;
+ }
+ }
+ else if (type == xml_end_tag)
+ {
+ if (!strcmp(string, "service"))
+ {
+ state.top_tag.clear();
+ if (state.found_service) state.exit = true;
+ }
+ else if (!state.top_tag.empty() && state.top_tag != "service")
+ state.top_tag = "service";
+ }
+ else if (type == xml_string)
+ {
+ if (state.top_tag == "serviceType")
+ {
+ if (!strcmp(string, state.service_type))
+ state.found_service = true;
+ }
+ else if (state.top_tag == "controlURL")
+ {
+ state.control_url = string;
+ if (state.found_service) state.exit = true;
+ }
+ }
+ }
+
+}
+
+void upnp::on_upnp_xml(asio::error_code const& e
+ , libtorrent::http_parser const& p, rootdevice& d) try
+{
+ TORRENT_ASSERT(d.magic == 1337);
+ if (d.upnp_connection)
+ {
+ d.upnp_connection->close();
+ d.upnp_connection.reset();
+ }
+
+ if (e && e != asio::error::eof)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << d.url << ") error while fetching control url: "
+ << e.message() << std::endl;
+#endif
+ d.disabled = true;
+ return;
+ }
+
+ if (!p.header_finished())
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << d.url << ") error while fetching control url: incomplete http message" << std::endl;
+#endif
+ d.disabled = true;
+ return;
+ }
+
+ if (p.status_code() != 200)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << d.url << ") error while fetching control url: " << p.message() << std::endl;
+#endif
+ d.disabled = true;
+ return;
+ }
+
+ parse_state s;
+ s.reset("urn:schemas-upnp-org:service:WANIPConnection:1");
+ xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
+ , bind(&find_control_url, _1, _2, boost::ref(s)));
+ if (s.found_service)
+ {
+ d.service_namespace = s.service_type;
+ }
+ else
+ {
+ // we didn't find the WAN IP connection, look for
+ // a PPP connection
+ s.reset("urn:schemas-upnp-org:service:WANPPPConnection:1");
+ xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
+ , bind(&find_control_url, _1, _2, boost::ref(s)));
+ if (s.found_service)
+ {
+ d.service_namespace = s.service_type;
+ }
+ else
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << d.url << ") Rootdevice response, did not find "
+ "a port mapping interface" << std::endl;
+#endif
+ d.disabled = true;
+ return;
+ }
+ }
+
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== (" << d.url << ") Rootdevice response, found control URL: " << s.control_url
+ << " namespace: " << d.service_namespace << std::endl;
+#endif
+
+ d.control_url = s.control_url;
+
+ map_port(d, 0);
+}
+catch (std::exception&)
+{
+ disable();
+};
+
+void upnp::disable()
+{
+ m_disabled = true;
+ m_devices.clear();
+ m_broadcast_timer.cancel();
+ m_refresh_timer.cancel();
+ m_socket.close();
+}
+
+namespace
+{
+ struct error_code_parse_state
+ {
+ error_code_parse_state(): in_error_code(false), exit(false), error_code(-1) {}
+ bool in_error_code;
+ bool exit;
+ int error_code;
+ };
+
+ void find_error_code(int type, char const* string, error_code_parse_state& state)
+ {
+ if (state.exit) return;
+ if (type == xml_start_tag && !strcmp("errorCode", string))
+ {
+ state.in_error_code = true;
+ }
+ else if (type == xml_string && state.in_error_code)
+ {
+ state.error_code = std::atoi(string);
+ state.exit = true;
+ }
+ }
+}
+
+namespace
+{
+ struct error_code_t
+ {
+ int code;
+ char const* msg;
+ };
+
+ error_code_t error_codes[] =
+ {
+ {402, "Invalid Arguments"}
+ , {501, "Action Failed"}
+ , {714, "The specified value does not exist in the array"}
+ , {715, "The source IP address cannot be wild-carded"}
+ , {716, "The external port cannot be wild-carded"}
+ , {718, "The port mapping entry specified conflicts with "
+ "a mapping assigned previously to another client"}
+ , {724, "Internal and External port values must be the same"}
+ , {725, "The NAT implementation only supports permanent "
+ "lease times on port mappings"}
+ , {726, "RemoteHost must be a wildcard and cannot be a "
+ "specific IP address or DNS name"}
+ , {727, "ExternalPort must be a wildcard and cannot be a specific port "}
+ };
+
+}
+
+void upnp::on_upnp_map_response(asio::error_code const& e
+ , libtorrent::http_parser const& p, rootdevice& d, int mapping) try
+{
+ TORRENT_ASSERT(d.magic == 1337);
+ if (d.upnp_connection)
+ {
+ d.upnp_connection->close();
+ d.upnp_connection.reset();
+ }
+
+ if (e && e != asio::error::eof)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== error while adding portmap: " << e.message() << std::endl;
+#endif
+ d.disabled = true;
+ return;
+ }
+
+ if (m_closing) return;
+
+// error code response may look like this:
+// <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
+// s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+// <s:Body>
+// <s:Fault>
+// <faultcode>s:Client</faultcode>
+// <faultstring>UPnPError</faultstring>
+// <detail>
+// <UPnPErrorxmlns="urn:schemas-upnp-org:control-1-0">
+// <errorCode>402</errorCode>
+// <errorDescription>Invalid Args</errorDescription>
+// </UPnPError>
+// </detail>
+// </s:Fault>
+// </s:Body>
+// </s:Envelope>
+
+ if (!p.header_finished())
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== error while adding portmap: incomplete http message" << std::endl;
+#endif
+ d.disabled = true;
+ return;
+ }
+
+ // We don't want to ignore responses with return codes other than 200
+ // since those might contain valid UPnP error codes
+
+ error_code_parse_state s;
+ xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
+ , bind(&find_error_code, _1, _2, boost::ref(s)));
+
+#ifdef TORRENT_UPNP_LOGGING
+ if (s.error_code != -1)
+ {
+ m_log << time_now_string()
+ << " <== got error message: " << s.error_code << std::endl;
+ }
+#endif
+
+ if (s.error_code == 725)
+ {
+ // only permanent leases supported
+ d.lease_duration = 0;
+ d.mapping[mapping].need_update = true;
+ map_port(d, mapping);
+ return;
+ }
+ else if (s.error_code == 718)
+ {
+ // conflict in mapping, try next external port
+ ++d.mapping[mapping].external_port;
+ d.mapping[mapping].need_update = true;
+ map_port(d, mapping);
+ return;
+ }
+ else if (s.error_code != -1)
+ {
+ int num_errors = sizeof(error_codes) / sizeof(error_codes[0]);
+ error_code_t* end = error_codes + num_errors;
+ error_code_t tmp = {s.error_code, 0};
+ error_code_t* e = std::lower_bound(error_codes, end, tmp
+ , bind(&error_code_t::code, _1) < bind(&error_code_t::code, _2));
+ std::string error_string = "UPnP mapping error ";
+ error_string += boost::lexical_cast<std::string>(s.error_code);
+ if (e != end && e->code == s.error_code)
+ {
+ error_string += ": ";
+ error_string += e->msg;
+ }
+ m_callback(0, 0, error_string);
+ }
+
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== map response: " << std::string(p.get_body().begin, p.get_body().end)
+ << std::endl;
+#endif
+
+ if (s.error_code == -1)
+ {
+ int tcp = 0;
+ int udp = 0;
+
+ if (mapping == 0)
+ tcp = d.mapping[mapping].external_port;
+ else
+ udp = d.mapping[mapping].external_port;
+
+ m_callback(tcp, udp, "");
+ if (d.lease_duration > 0)
+ {
+ d.mapping[mapping].expires = time_now()
+ + seconds(int(d.lease_duration * 0.75f));
+ ptime next_expire = m_refresh_timer.expires_at();
+ if (next_expire < time_now()
+ || next_expire > d.mapping[mapping].expires)
+ {
+ m_refresh_timer.expires_at(d.mapping[mapping].expires);
+ m_refresh_timer.async_wait(m_strand.wrap(bind(&upnp::on_expire, self(), _1)));
+ }
+ }
+ else
+ {
+ d.mapping[mapping].expires = max_time();
+ }
+ }
+
+ for (int i = 0; i < num_mappings; ++i)
+ {
+ if (d.mapping[i].need_update)
+ {
+ map_port(d, i);
+ return;
+ }
+ }
+}
+catch (std::exception&)
+{
+ disable();
+};
+
+void upnp::on_upnp_unmap_response(asio::error_code const& e
+ , libtorrent::http_parser const& p, rootdevice& d, int mapping) try
+{
+ TORRENT_ASSERT(d.magic == 1337);
+ if (d.upnp_connection)
+ {
+ d.upnp_connection->close();
+ d.upnp_connection.reset();
+ }
+
+ if (e && e != asio::error::eof)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== error while deleting portmap: " << e.message() << std::endl;
+#endif
+ }
+
+ if (!p.header_finished())
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== error while deleting portmap: incomplete http message" << std::endl;
+#endif
+ return;
+ }
+
+ if (p.status_code() != 200)
+ {
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== error while deleting portmap: " << p.message() << std::endl;
+#endif
+ d.disabled = true;
+ return;
+ }
+
+#ifdef TORRENT_UPNP_LOGGING
+ m_log << time_now_string()
+ << " <== unmap response: " << std::string(p.get_body().begin, p.get_body().end)
+ << std::endl;
+#endif
+
+ // ignore errors and continue with the next mapping for this device
+ if (mapping < num_mappings - 1)
+ {
+ unmap_port(d, mapping + 1);
+ return;
+ }
+}
+catch (std::exception&)
+{
+ disable();
+};
+
+void upnp::on_expire(asio::error_code const& e) try
+{
+ if (e) return;
+
+ ptime now = time_now();
+ ptime next_expire = max_time();
+
+ for (std::set<rootdevice>::iterator i = m_devices.begin()
+ , end(m_devices.end()); i != end; ++i)
+ {
+ rootdevice& d = const_cast<rootdevice&>(*i);
+ TORRENT_ASSERT(d.magic == 1337);
+ for (int m = 0; m < num_mappings; ++m)
+ {
+ if (d.mapping[m].expires != max_time())
+ continue;
+
+ if (d.mapping[m].expires < now)
+ {
+ d.mapping[m].expires = max_time();
+ map_port(d, m);
+ }
+ else if (d.mapping[m].expires < next_expire)
+ {
+ next_expire = d.mapping[m].expires;
+ }
+ }
+ }
+ if (next_expire != max_time())
+ {
+ m_refresh_timer.expires_at(next_expire);
+ m_refresh_timer.async_wait(m_strand.wrap(bind(&upnp::on_expire, self(), _1)));
+ }
+}
+catch (std::exception&)
+{
+ disable();
+};
+
+void upnp::close()
+{
+ m_refresh_timer.cancel();
+ m_broadcast_timer.cancel();
+ m_closing = true;
+ m_socket.close();
+
+ if (m_disabled)
+ {
+ m_devices.clear();
+ return;
+ }
+
+ for (std::set<rootdevice>::iterator i = m_devices.begin()
+ , end(m_devices.end()); i != end; ++i)
+ {
+ rootdevice& d = const_cast<rootdevice&>(*i);
+ TORRENT_ASSERT(d.magic == 1337);
+ if (d.control_url.empty()) continue;
+ unmap_port(d, 0);
+ }
+}
+
diff --git a/src/libtorrent/src/ut_pex.cpp b/src/libtorrent/src/ut_pex.cpp
new file mode 100644
index 0000000..18c37cd
--- /dev/null
+++ b/src/libtorrent/src/ut_pex.cpp
@@ -0,0 +1,414 @@
+/*
+
+Copyright (c) 2006, MassaRoddel, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <boost/shared_ptr.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include "libtorrent/peer_connection.hpp"
+#include "libtorrent/bt_peer_connection.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/torrent.hpp"
+#include "libtorrent/extensions.hpp"
+
+#include "libtorrent/extensions/ut_pex.hpp"
+
+namespace libtorrent { namespace
+{
+ const char extension_name[] = "ut_pex";
+
+ enum
+ {
+ extension_index = 1,
+ max_peer_entries = 100
+ };
+
+ bool send_peer(peer_connection const& p)
+ {
+ // don't send out peers that we haven't connected to
+ // (that have connected to us)
+ if (!p.is_local()) return false;
+ // don't send out peers that we haven't successfully connected to
+ if (p.is_connecting()) return false;
+ return true;
+ }
+
+ struct ut_pex_plugin: torrent_plugin
+ {
+ ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(55) {}
+
+ virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);
+
+ std::vector<char>& get_ut_pex_msg()
+ {
+ return m_ut_pex_msg;
+ }
+
+ // the second tick of the torrent
+ // each minute the new lists of "added" + "added.f" and "dropped"
+ // are calculated here and the pex message is created
+ // each peer connection will use this message
+ // max_peer_entries limits the packet size
+ virtual void tick()
+ {
+ if (++m_1_minute < 60) return;
+
+ m_1_minute = 0;
+
+ entry pex;
+ std::string& pla = pex["added"].string();
+ std::string& pld = pex["dropped"].string();
+ std::string& plf = pex["added.f"].string();
+ std::string& pla6 = pex["added6"].string();
+ std::string& pld6 = pex["dropped6"].string();
+ std::string& plf6 = pex["added6.f"].string();
+ std::back_insert_iterator<std::string> pla_out(pla);
+ std::back_insert_iterator<std::string> pld_out(pld);
+ std::back_insert_iterator<std::string> plf_out(plf);
+ std::back_insert_iterator<std::string> pla6_out(pla6);
+ std::back_insert_iterator<std::string> pld6_out(pld6);
+ std::back_insert_iterator<std::string> plf6_out(plf6);
+
+ std::set<tcp::endpoint> dropped;
+ m_old_peers.swap(dropped);
+
+ int num_added = 0;
+ for (torrent::peer_iterator i = m_torrent.begin()
+ , end(m_torrent.end()); i != end; ++i)
+ {
+ peer_connection* peer = *i;
+ if (!send_peer(*peer)) continue;
+
+ tcp::endpoint const& remote = peer->remote();
+ m_old_peers.insert(remote);
+
+ std::set<tcp::endpoint>::iterator di = dropped.find(remote);
+ if (di == dropped.end())
+ {
+ // don't write too big of a package
+ if (num_added >= max_peer_entries) break;
+
+ // only send proper bittorrent peers
+ bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
+ if (!p) continue;
+
+ // no supported flags to set yet
+ // 0x01 - peer supports encryption
+ // 0x02 - peer is a seed
+ int flags = p->is_seed() ? 2 : 0;
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ flags |= p->supports_encryption() ? 1 : 0;
+#endif
+ // i->first was added since the last time
+ if (remote.address().is_v4())
+ {
+ detail::write_endpoint(remote, pla_out);
+ detail::write_uint8(flags, plf_out);
+ }
+ else
+ {
+ detail::write_endpoint(remote, pla6_out);
+ detail::write_uint8(flags, plf6_out);
+ }
+ ++num_added;
+ }
+ else
+ {
+ // this was in the previous message
+ // so, it wasn't dropped
+ dropped.erase(di);
+ }
+ }
+
+ for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
+ , end(dropped.end()); i != end; ++i)
+ {
+ if (i->address().is_v4())
+ detail::write_endpoint(*i, pld_out);
+ else
+ detail::write_endpoint(*i, pld6_out);
+ }
+
+ m_ut_pex_msg.clear();
+ bencode(std::back_inserter(m_ut_pex_msg), pex);
+ }
+
+ private:
+ torrent& m_torrent;
+
+ std::set<tcp::endpoint> m_old_peers;
+ int m_1_minute;
+ std::vector<char> m_ut_pex_msg;
+ };
+
+
+ struct ut_pex_peer_plugin : peer_plugin
+ {
+ ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
+ : m_torrent(t)
+ , m_pc(pc)
+ , m_tp(tp)
+ , m_1_minute(55)
+ , m_message_index(0)
+ , m_first_time(true)
+ {}
+
+ virtual void add_handshake(entry& h)
+ {
+ entry& messages = h["m"];
+ messages[extension_name] = extension_index;
+ }
+
+ virtual bool on_extension_handshake(entry const& h)
+ {
+ entry const& messages = h["m"];
+
+ if (entry const* index = messages.find_key(extension_name))
+ {
+ m_message_index = int(index->integer());
+ return true;
+ }
+ else
+ {
+ m_message_index = 0;
+ return false;
+ }
+ }
+
+ virtual bool on_extended(int length, int msg, buffer::const_interval body)
+ {
+ if (msg != extension_index) return false;
+ if (m_message_index == 0) return false;
+
+ if (length > 500 * 1024)
+ throw protocol_error("uT peer exchange message larger than 500 kB");
+
+ if (body.left() < length) return true;
+
+ try
+ {
+ entry pex_msg = bdecode(body.begin, body.end);
+ std::string const& peers = pex_msg["added"].string();
+ std::string const& peer_flags = pex_msg["added.f"].string();
+
+ int num_peers = peers.length() / 6;
+ char const* in = peers.c_str();
+ char const* fin = peer_flags.c_str();
+
+ if (int(peer_flags.size()) != num_peers)
+ return true;
+
+ peer_id pid(0);
+ policy& p = m_torrent.get_policy();
+ for (int i = 0; i < num_peers; ++i)
+ {
+ tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
+ char flags = detail::read_uint8(fin);
+ p.peer_from_tracker(adr, pid, peer_info::pex, flags);
+ }
+
+ if (entry const* p6 = pex_msg.find_key("added6"))
+ {
+ std::string const& peers6 = p6->string();
+ std::string const& peer6_flags = pex_msg["added6.f"].string();
+
+ int num_peers = peers6.length() / 18;
+ char const* in = peers6.c_str();
+ char const* fin = peer6_flags.c_str();
+
+ if (int(peer6_flags.size()) != num_peers)
+ return true;
+
+ peer_id pid(0);
+ policy& p = m_torrent.get_policy();
+ for (int i = 0; i < num_peers; ++i)
+ {
+ tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
+ char flags = detail::read_uint8(fin);
+ p.peer_from_tracker(adr, pid, peer_info::pex, flags);
+ }
+ }
+ }
+ catch (std::exception&)
+ {
+ throw protocol_error("invalid uT peer exchange message");
+ }
+ return true;
+ }
+
+ // the peers second tick
+ // every minute we send a pex message
+ virtual void tick()
+ {
+ if (!m_message_index) return; // no handshake yet
+ if (++m_1_minute <= 60) return;
+
+ if (m_first_time)
+ {
+ send_ut_peer_list();
+ m_first_time = false;
+ }
+ else
+ {
+ send_ut_peer_diff();
+ }
+ m_1_minute = 0;
+ }
+
+ private:
+
+ void send_ut_peer_diff()
+ {
+ std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();
+
+ buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());
+
+ detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
+ detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
+ detail::write_uint8(m_message_index, i.begin);
+ std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
+ i.begin += pex_msg.size();
+
+ TORRENT_ASSERT(i.begin == i.end);
+ m_pc.setup_send();
+ }
+
+ void send_ut_peer_list()
+ {
+ entry pex;
+ // leave the dropped string empty
+ pex["dropped"].string();
+ std::string& pla = pex["added"].string();
+ std::string& plf = pex["added.f"].string();
+ pex["dropped6"].string();
+ std::string& pla6 = pex["added6"].string();
+ std::string& plf6 = pex["added6.f"].string();
+ std::back_insert_iterator<std::string> pla_out(pla);
+ std::back_insert_iterator<std::string> plf_out(plf);
+ std::back_insert_iterator<std::string> pla6_out(pla6);
+ std::back_insert_iterator<std::string> plf6_out(plf6);
+
+ int num_added = 0;
+ for (torrent::peer_iterator i = m_torrent.begin()
+ , end(m_torrent.end()); i != end; ++i)
+ {
+ peer_connection* peer = *i;
+ if (!send_peer(*peer)) continue;
+
+ // don't write too big of a package
+ if (num_added >= max_peer_entries) break;
+
+ // only send proper bittorrent peers
+ bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
+ if (!p) continue;
+
+ // no supported flags to set yet
+ // 0x01 - peer supports encryption
+ // 0x02 - peer is a seed
+ int flags = p->is_seed() ? 2 : 0;
+#ifndef TORRENT_DISABLE_ENCRYPTION
+ flags |= p->supports_encryption() ? 1 : 0;
+#endif
+ tcp::endpoint const& remote = peer->remote();
+ // i->first was added since the last time
+ if (remote.address().is_v4())
+ {
+ detail::write_endpoint(remote, pla_out);
+ detail::write_uint8(flags, plf_out);
+ }
+ else
+ {
+ detail::write_endpoint(remote, pla6_out);
+ detail::write_uint8(flags, plf6_out);
+ }
+ ++num_added;
+ }
+ std::vector<char> pex_msg;
+ bencode(std::back_inserter(pex_msg), pex);
+
+ buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());
+
+ detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
+ detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
+ detail::write_uint8(m_message_index, i.begin);
+ std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
+ i.begin += pex_msg.size();
+
+ TORRENT_ASSERT(i.begin == i.end);
+ m_pc.setup_send();
+ }
+
+ torrent& m_torrent;
+ peer_connection& m_pc;
+ ut_pex_plugin& m_tp;
+ int m_1_minute;
+ int m_message_index;
+
+ // this is initialized to true, and set to
+ // false after the first pex message has been sent.
+ // it is used to know if a diff message or a full
+ // message should be sent.
+ bool m_first_time;
+ };
+
+ boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
+ {
+ bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
+ if (!c) return boost::shared_ptr<peer_plugin>();
+ return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
+ , *pc, *this));
+ }
+}}
+
+namespace libtorrent
+{
+
+ boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
+ {
+ if (t->torrent_file().priv())
+ {
+ return boost::shared_ptr<torrent_plugin>();
+ }
+ return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
+ }
+
+}
+
+
diff --git a/src/libtorrent/src/web_peer_connection.cpp b/src/libtorrent/src/web_peer_connection.cpp
new file mode 100644
index 0000000..3e390ac
--- /dev/null
+++ b/src/libtorrent/src/web_peer_connection.cpp
@@ -0,0 +1,665 @@
+/*
+
+Copyright (c) 2003, Arvid Norberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "libtorrent/pch.hpp"
+
+#include <vector>
+#include <iostream>
+#include <iomanip>
+#include <limits>
+#include <boost/bind.hpp>
+#include <sstream>
+
+#include "libtorrent/web_peer_connection.hpp"
+#include "libtorrent/session.hpp"
+#include "libtorrent/identify_client.hpp"
+#include "libtorrent/entry.hpp"
+#include "libtorrent/bencode.hpp"
+#include "libtorrent/alert_types.hpp"
+#include "libtorrent/invariant_check.hpp"
+#include "libtorrent/io.hpp"
+#include "libtorrent/version.hpp"
+#include "libtorrent/aux_/session_impl.hpp"
+
+using boost::bind;
+using boost::shared_ptr;
+using libtorrent::aux::session_impl;
+
+namespace libtorrent
+{
+ web_peer_connection::web_peer_connection(
+ session_impl& ses
+ , boost::weak_ptr<torrent> t
+ , boost::shared_ptr<socket_type> s
+ , tcp::endpoint const& remote
+ , std::string const& url
+ , policy::peer* peerinfo)
+ : peer_connection(ses, t, s, remote, peerinfo)
+ , m_url(url)
+ , m_first_request(true)
+ {
+ INVARIANT_CHECK;
+
+ // we want large blocks as well, so
+ // we can request more bytes at once
+ request_large_blocks(true);
+ // we only want left-over bandwidth
+ set_priority(0);
+ shared_ptr<torrent> tor = t.lock();
+ TORRENT_ASSERT(tor);
+ int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size();
+
+ // we always prefer downloading 1 MB chunks
+ // from web seeds
+ prefer_whole_pieces((1024 * 1024) / tor->torrent_file().piece_length());
+
+ // multiply with the blocks per piece since that many requests are
+ // merged into one http request
+ m_max_out_request_queue = ses.settings().urlseed_pipeline_size
+ * blocks_per_piece;
+
+ // since this is a web seed, change the timeout
+ // according to the settings.
+ set_timeout(ses.settings().urlseed_timeout);
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "*** web_peer_connection\n";
+#endif
+
+ std::string protocol;
+ boost::tie(protocol, m_auth, m_host, m_port, m_path)
+ = parse_url_components(url);
+
+ if (!m_auth.empty())
+ m_auth = base64encode(m_auth);
+
+ m_server_string = "URL seed @ ";
+ m_server_string += m_host;
+ }
+
+ web_peer_connection::~web_peer_connection()
+ {}
+
+ boost::optional<piece_block_progress>
+ web_peer_connection::downloading_piece_progress() const
+ {
+ if (m_requests.empty())
+ return boost::optional<piece_block_progress>();
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ piece_block_progress ret;
+
+ ret.piece_index = m_requests.front().piece;
+ if (!m_piece.empty())
+ {
+ ret.bytes_downloaded = int(m_piece.size());
+ }
+ else
+ {
+ if (!m_parser.header_finished())
+ {
+ ret.bytes_downloaded = 0;
+ }
+ else
+ {
+ int receive_buffer_size = receive_buffer().left() - m_parser.body_start();
+ ret.bytes_downloaded = receive_buffer_size % t->block_size();
+ }
+ }
+ ret.block_index = (m_requests.front().start + ret.bytes_downloaded) / t->block_size();
+ ret.full_block_bytes = t->block_size();
+ const int last_piece = t->torrent_file().num_pieces() - 1;
+ if (ret.piece_index == last_piece && ret.block_index
+ == t->torrent_file().piece_size(last_piece) / t->block_size())
+ ret.full_block_bytes = t->torrent_file().piece_size(last_piece) % t->block_size();
+ return ret;
+ }
+
+ void web_peer_connection::on_connected()
+ {
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ // this is always a seed
+ incoming_bitfield(std::vector<bool>(
+ t->torrent_file().num_pieces(), true));
+ // it is always possible to request pieces
+ incoming_unchoke();
+
+ reset_recv_buffer(t->block_size() + 1024);
+ }
+
+ void web_peer_connection::write_request(peer_request const& r)
+ {
+ INVARIANT_CHECK;
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ TORRENT_ASSERT(t->valid_metadata());
+
+ bool single_file_request = false;
+ if (!m_path.empty() && m_path[m_path.size() - 1] != '/')
+ single_file_request = true;
+
+ torrent_info const& info = t->torrent_file();
+
+ std::string request;
+ request.reserve(400);
+
+ int size = r.length;
+ const int block_size = t->block_size();
+ const int piece_size = t->torrent_file().piece_length();
+ peer_request pr;
+ while (size > 0)
+ {
+ int request_offset = r.start + r.length - size;
+ pr.start = request_offset % piece_size;
+ pr.length = (std::min)(block_size, size);
+ pr.piece = r.piece + request_offset / piece_size;
+ m_requests.push_back(pr);
+ size -= pr.length;
+ }
+
+ proxy_settings const& ps = m_ses.web_seed_proxy();
+ bool using_proxy = ps.type == proxy_settings::http
+ || ps.type == proxy_settings::http_pw;
+
+ if (single_file_request)
+ {
+ request += "GET ";
+ // do not encode single file paths, they are
+ // assumed to be encoded in the torrent file
+ request += using_proxy ? m_url : m_path;
+ request += " HTTP/1.1\r\n";
+ request += "Host: ";
+ request += m_host;
+ if (m_first_request)
+ {
+ request += "\r\nUser-Agent: ";
+ request += m_ses.settings().user_agent;
+ }
+ if (!m_auth.empty())
+ {
+ request += "\r\nAuthorization: Basic ";
+ request += m_auth;
+ }
+ if (ps.type == proxy_settings::http_pw)
+ {
+ request += "\r\nProxy-Authorization: Basic ";
+ request += base64encode(ps.username + ":" + ps.password);
+ }
+ if (using_proxy)
+ {
+ request += "\r\nProxy-Connection: keep-alive";
+ }
+ request += "\r\nRange: bytes=";
+ request += boost::lexical_cast<std::string>(r.piece
+ * info.piece_length() + r.start);
+ request += "-";
+ request += boost::lexical_cast<std::string>(r.piece
+ * info.piece_length() + r.start + r.length - 1);
+ if (m_first_request || using_proxy)
+ request += "\r\nConnection: keep-alive";
+ request += "\r\n\r\n";
+ m_first_request = false;
+ m_file_requests.push_back(0);
+ }
+ else
+ {
+ std::vector<file_slice> files = info.map_block(r.piece, r.start
+ , r.length);
+
+ for (std::vector<file_slice>::iterator i = files.begin();
+ i != files.end(); ++i)
+ {
+ file_slice const& f = *i;
+
+ request += "GET ";
+ if (using_proxy)
+ {
+ request += m_url;
+ std::string path = info.file_at(f.file_index).path.string();
+ request += escape_path(path.c_str(), path.length());
+ }
+ else
+ {
+ std::string path = m_path;
+ path += info.file_at(f.file_index).path.string();
+ request += escape_path(path.c_str(), path.length());
+ }
+ request += " HTTP/1.1\r\n";
+ request += "Host: ";
+ request += m_host;
+ if (m_first_request)
+ {
+ request += "\r\nUser-Agent: ";
+ request += m_ses.settings().user_agent;
+ }
+ if (!m_auth.empty())
+ {
+ request += "\r\nAuthorization: Basic ";
+ request += m_auth;
+ }
+ if (ps.type == proxy_settings::http_pw)
+ {
+ request += "\r\nProxy-Authorization: Basic ";
+ request += base64encode(ps.username + ":" + ps.password);
+ }
+ if (using_proxy)
+ {
+ request += "\r\nProxy-Connection: keep-alive";
+ }
+ request += "\r\nRange: bytes=";
+ request += boost::lexical_cast<std::string>(f.offset);
+ request += "-";
+ request += boost::lexical_cast<std::string>(f.offset + f.size - 1);
+ if (m_first_request || using_proxy)
+ request += "\r\nConnection: keep-alive";
+ request += "\r\n\r\n";
+ m_first_request = false;
+ TORRENT_ASSERT(f.file_index >= 0);
+ m_file_requests.push_back(f.file_index);
+ }
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << request << "\n";
+#endif
+
+ send_buffer(request.c_str(), request.size());
+ }
+
+ // --------------------------
+ // RECEIVE DATA
+ // --------------------------
+
+ namespace
+ {
+ bool range_contains(peer_request const& range, peer_request const& req, int piece_size)
+ {
+ size_type range_start = size_type(range.piece) * piece_size + range.start;
+ size_type req_start = size_type(req.piece) * piece_size + req.start;
+ return range_start <= req_start
+ && range_start + range.length >= req_start + req.length;
+ }
+ }
+
+ // throws exception when the client should be disconnected
+ void web_peer_connection::on_receive(asio::error_code const& error
+ , std::size_t bytes_transferred)
+ {
+ INVARIANT_CHECK;
+
+ if (error)
+ {
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << "*** web_peer_connection error: "
+ << error.message() << "\n";
+#endif
+ return;
+ }
+
+ boost::shared_ptr<torrent> t = associated_torrent().lock();
+ TORRENT_ASSERT(t);
+
+ incoming_piece_fragment();
+
+ for (;;)
+ {
+ buffer::const_interval recv_buffer = receive_buffer();
+
+ int payload;
+ int protocol;
+ bool header_finished = m_parser.header_finished();
+ if (!header_finished)
+ {
+ boost::tie(payload, protocol) = m_parser.incoming(recv_buffer);
+ m_statistics.received_bytes(payload, protocol);
+
+ TORRENT_ASSERT(recv_buffer.left() == 0 || *recv_buffer.begin == 'H');
+
+ TORRENT_ASSERT(recv_buffer.left() <= packet_size());
+
+ // this means the entire status line hasn't been received yet
+ if (m_parser.status_code() == -1) break;
+
+ // if the status code is not one of the accepted ones, abort
+ if (m_parser.status_code() != 206 // partial content
+ && m_parser.status_code() != 200 // OK
+ && !(m_parser.status_code() >= 300 // redirect
+ && m_parser.status_code() < 400))
+ {
+ if (m_parser.status_code() == 503)
+ {
+ // temporarily unavailable, retry later
+ t->retry_url_seed(m_url);
+ }
+ t->remove_url_seed(m_url);
+ std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code())
+ + " " + m_parser.message();
+ if (m_ses.m_alerts.should_post(alert::warning))
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+ m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url()
+ , error_msg));
+ }
+ throw std::runtime_error(error_msg);
+ }
+ if (!m_parser.header_finished()) break;
+
+ m_body_start = m_parser.body_start();
+ m_received_body = 0;
+ }
+ else
+ {
+ m_statistics.received_bytes(bytes_transferred, 0);
+ }
+
+ // we just completed reading the header
+ if (!header_finished)
+ {
+ if (m_parser.status_code() >= 300 && m_parser.status_code() < 400)
+ {
+ // this means we got a redirection request
+ // look for the location header
+ std::string location = m_parser.header("location");
+
+ if (location.empty())
+ {
+ // we should not try this server again.
+ t->remove_url_seed(m_url);
+ throw std::runtime_error("got HTTP redirection status without location header");
+ }
+
+ bool single_file_request = false;
+ if (!m_path.empty() && m_path[m_path.size() - 1] != '/')
+ single_file_request = true;
+
+ // add the redirected url and remove the current one
+ if (!single_file_request)
+ {
+ TORRENT_ASSERT(!m_file_requests.empty());
+ int file_index = m_file_requests.front();
+
+ torrent_info const& info = t->torrent_file();
+ std::string path = info.file_at(file_index).path.string();
+ path = escape_path(path.c_str(), path.length());
+ size_t i = location.rfind(path);
+ if (i == std::string::npos)
+ {
+ t->remove_url_seed(m_url);
+ throw std::runtime_error("got invalid HTTP redirection location (\"" + location + "\") "
+ "expected it to end with: " + path);
+ }
+ location.resize(i);
+ }
+ t->add_url_seed(location);
+ t->remove_url_seed(m_url);
+ throw std::runtime_error("redirecting to " + location);
+ }
+
+ std::string const& server_version = m_parser.header("server");
+ if (!server_version.empty())
+ {
+ m_server_string = "URL seed @ ";
+ m_server_string += m_host;
+ m_server_string += " (";
+ m_server_string += server_version;
+ m_server_string += ")";
+ }
+
+ m_body_start = m_parser.body_start();
+ m_received_body = 0;
+ }
+
+ recv_buffer.begin += m_body_start;
+ // we only received the header, no data
+ if (recv_buffer.left() == 0) break;
+
+ size_type range_start;
+ size_type range_end;
+ if (m_parser.status_code() == 206)
+ {
+ std::stringstream range_str(m_parser.header("content-range"));
+ char dummy;
+ std::string bytes;
+ range_str >> bytes >> range_start >> dummy >> range_end;
+ if (!range_str)
+ {
+ // we should not try this server again.
+ t->remove_url_seed(m_url);
+ throw std::runtime_error("invalid range in HTTP response: " + range_str.str());
+ }
+ // the http range is inclusive
+ range_end++;
+ }
+ else
+ {
+ range_start = 0;
+ range_end = atol(m_parser.header("content-length").c_str());
+ if (range_end == -1)
+ {
+ // we should not try this server again.
+ t->remove_url_seed(m_url);
+ throw std::runtime_error("no content-length in HTTP response");
+ }
+ }
+
+// std::cerr << "REQUESTS: m_requests: " << m_requests.size()
+// << " file_requests: " << m_file_requests.size() << std::endl;
+
+ torrent_info const& info = t->torrent_file();
+
+ if (m_requests.empty() || m_file_requests.empty())
+ throw std::runtime_error("unexpected HTTP response");
+
+ int file_index = m_file_requests.front();
+ peer_request in_range = info.map_file(file_index, range_start
+ , int(range_end - range_start));
+
+ peer_request front_request = m_requests.front();
+
+ size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start;
+ size_type re = rs + in_range.length;
+ size_type fs = size_type(front_request.piece) * info.piece_length() + front_request.start;
+/*
+ size_type fe = fs + front_request.length;
+
+ std::cerr << "RANGE: r = (" << rs << ", " << re << " ) "
+ "f = (" << fs << ", " << fe << ") "
+ "file_index = " << file_index << " received_body = " << m_received_body << std::endl;
+*/
+
+ // the http response body consists of 3 parts
+ // 1. the middle of a block or the ending of a block
+ // 2. a number of whole blocks
+ // 3. the start of a block
+ // in that order, these parts are parsed.
+
+ bool range_overlaps_request = re > fs + int(m_piece.size());
+
+ if (!range_overlaps_request)
+ {
+ // this means the end of the incoming request ends _before_ the
+ // first expected byte (fs + m_piece.size())
+ throw std::runtime_error("invalid range in HTTP response");
+ }
+
+ // if the request is contained in the range (i.e. the entire request
+ // fits in the range) we should not start a partial piece, since we soon
+ // will receive enough to call incoming_piece() and pass the read buffer
+ // directly (in the next loop below).
+ if (range_overlaps_request && !range_contains(in_range, front_request, info.piece_length()))
+ {
+ // the start of the next block to receive is stored
+ // in m_piece. We need to append the rest of that
+ // block from the http receive buffer and then
+ // (if it completed) call incoming_piece() with
+ // m_piece as buffer.
+
+ int piece_size = int(m_piece.size());
+ int copy_size = (std::min)((std::min)(front_request.length - piece_size
+ , recv_buffer.left()), int(range_end - range_start - m_received_body));
+ m_piece.resize(piece_size + copy_size);
+ TORRENT_ASSERT(copy_size > 0);
+ std::memcpy(&m_piece[0] + piece_size, recv_buffer.begin, copy_size);
+ TORRENT_ASSERT(int(m_piece.size()) <= front_request.length);
+ recv_buffer.begin += copy_size;
+ m_received_body += copy_size;
+ m_body_start += copy_size;
+ TORRENT_ASSERT(m_received_body <= range_end - range_start);
+ TORRENT_ASSERT(int(m_piece.size()) <= front_request.length);
+ if (int(m_piece.size()) == front_request.length)
+ {
+ // each call to incoming_piece() may result in us becoming
+ // a seed. If we become a seed, all seeds we're connected to
+ // will be disconnected, including this web seed. We need to
+ // check for the disconnect condition after the call.
+
+ m_requests.pop_front();
+ incoming_piece(front_request, &m_piece[0]);
+ if (associated_torrent().expired()) return;
+ cut_receive_buffer(m_body_start, t->block_size() + 1024);
+ m_body_start = 0;
+ recv_buffer = receive_buffer();
+ TORRENT_ASSERT(m_received_body <= range_end - range_start);
+ m_piece.clear();
+ TORRENT_ASSERT(m_piece.empty());
+ }
+ }
+
+ // report all received blocks to the bittorrent engine
+ while (!m_requests.empty()
+ && range_contains(in_range, m_requests.front(), info.piece_length())
+ && recv_buffer.left() >= m_requests.front().length)
+ {
+ peer_request r = m_requests.front();
+ m_requests.pop_front();
+ TORRENT_ASSERT(recv_buffer.left() >= r.length);
+
+ incoming_piece(r, recv_buffer.begin);
+ if (associated_torrent().expired()) return;
+ m_received_body += r.length;
+ TORRENT_ASSERT(receive_buffer().begin + m_body_start == recv_buffer.begin);
+ TORRENT_ASSERT(m_received_body <= range_end - range_start);
+ cut_receive_buffer(r.length + m_body_start, t->block_size() + 1024);
+ m_body_start = 0;
+ recv_buffer = receive_buffer();
+ }
+
+ if (!m_requests.empty())
+ {
+ range_overlaps_request = in_range.start + in_range.length
+ > m_requests.front().start + int(m_piece.size());
+
+ if (in_range.start + in_range.length < m_requests.front().start + m_requests.front().length
+ && (m_received_body + recv_buffer.left() >= range_end - range_start))
+ {
+ int piece_size = int(m_piece.size());
+ int copy_size = (std::min)((std::min)(m_requests.front().length - piece_size
+ , recv_buffer.left()), int(range_end - range_start - m_received_body));
+ TORRENT_ASSERT(copy_size >= 0);
+ if (copy_size > 0)
+ {
+ m_piece.resize(piece_size + copy_size);
+ std::memcpy(&m_piece[0] + piece_size, recv_buffer.begin, copy_size);
+ recv_buffer.begin += copy_size;
+ m_received_body += copy_size;
+ m_body_start += copy_size;
+ }
+ TORRENT_ASSERT(m_received_body == range_end - range_start);
+ }
+ }
+
+ TORRENT_ASSERT(m_received_body <= range_end - range_start);
+ if (m_received_body == range_end - range_start)
+ {
+ cut_receive_buffer(recv_buffer.begin - receive_buffer().begin
+ , t->block_size() + 1024);
+ recv_buffer = receive_buffer();
+ m_file_requests.pop_front();
+ m_parser.reset();
+ m_body_start = 0;
+ m_received_body = 0;
+ continue;
+ }
+ break;
+ }
+ }
+
+ void web_peer_connection::get_specific_peer_info(peer_info& p) const
+ {
+ if (is_interesting()) p.flags |= peer_info::interesting;
+ if (is_choked()) p.flags |= peer_info::choked;
+ if (is_peer_interested()) p.flags |= peer_info::remote_interested;
+ if (has_peer_choked()) p.flags |= peer_info::remote_choked;
+ if (is_local()) p.flags |= peer_info::local_connection;
+ if (!is_connecting() && m_server_string.empty())
+ p.flags |= peer_info::handshake;
+ if (is_connecting() && !is_queued()) p.flags |= peer_info::connecting;
+ if (is_queued()) p.flags |= peer_info::queued;
+
+ p.client = m_server_string;
+ p.connection_type = peer_info::web_seed;
+ }
+
+ bool web_peer_connection::in_handshake() const
+ {
+ return m_server_string.empty();
+ }
+
+ // throws exception when the client should be disconnected
+ void web_peer_connection::on_sent(asio::error_code const& error
+ , std::size_t bytes_transferred)
+ {
+ INVARIANT_CHECK;
+
+ if (error) return;
+ m_statistics.sent_bytes(0, bytes_transferred);
+ }
+
+
+#ifndef NDEBUG
+ void web_peer_connection::check_invariant() const
+ {
+/*
+ TORRENT_ASSERT(m_num_pieces == std::count(
+ m_have_piece.begin()
+ , m_have_piece.end()
+ , true));
+*/ }
+#endif
+
+}
+
diff --git a/src/libtorrent/zlib/adler32.c b/src/libtorrent/zlib/adler32.c
new file mode 100644
index 0000000..84f011b
--- /dev/null
+++ b/src/libtorrent/zlib/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 > BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
diff --git a/src/libtorrent/zlib/compress.c b/src/libtorrent/zlib/compress.c
new file mode 100644
index 0000000..45ae0cb
--- /dev/null
+++ b/src/libtorrent/zlib/compress.c
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: compress.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/src/libtorrent/zlib/crc32.c b/src/libtorrent/zlib/crc32.c
new file mode 100644
index 0000000..e0de932
--- /dev/null
+++ b/src/libtorrent/zlib/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64 at csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id: crc32.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case */
+ if (len2 == 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320L; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
diff --git a/src/libtorrent/zlib/crc32.h b/src/libtorrent/zlib/crc32.h
new file mode 100644
index 0000000..8053b61
--- /dev/null
+++ b/src/libtorrent/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/src/libtorrent/zlib/deflate.c b/src/libtorrent/zlib/deflate.c
new file mode 100644
index 0000000..8fa2fe2
--- /dev/null
+++ b/src/libtorrent/zlib/deflate.c
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id: deflate.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong destLen;
+
+ /* conservative upper bound */
+ destLen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+ /* if can't get parameters, return conservative bound */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return destLen;
+
+ /* if not default parameters, return conservative bound */
+ s = strm->state;
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return destLen;
+
+ /* default settings: return tight bound for that case */
+ return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ /* %%% avoid this when Z_RLE */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifdef FASTEST
+ if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+ (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#else
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#endif
+ /* longest_match() or longest_match_fast() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+ /* longest_match() or longest_match_fast() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt run; /* length of run */
+ uInt max; /* maximum length of run */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan; /* scan for end of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ run = 0;
+ if (s->strstart > 0) { /* if there is a previous byte, that is */
+ max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+ scan = s->window + s->strstart - 1;
+ prev = *scan++;
+ do {
+ if (*scan++ != prev)
+ break;
+ } while (++run < max);
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (run >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, run);
+ _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+ s->lookahead -= run;
+ s->strstart += run;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/src/libtorrent/zlib/deflate.h b/src/libtorrent/zlib/deflate.h
new file mode 100644
index 0000000..66c4524
--- /dev/null
+++ b/src/libtorrent/zlib/deflate.h
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: deflate.h 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/src/libtorrent/zlib/gzio.c b/src/libtorrent/zlib/gzio.c
new file mode 100644
index 0000000..d304cac
--- /dev/null
+++ b/src/libtorrent/zlib/gzio.c
@@ -0,0 +1,1026 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id: gzio.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE /* for compatibility with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+# pragma map (fdopen , "\174\174FDOPEN")
+ FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ z_off_t start; /* start of compressed data in file (header skipped) */
+ z_off_t in; /* bytes into deflate or inflate */
+ z_off_t out; /* bytes out of deflate or inflate */
+ int back; /* one character push-back */
+ int last; /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->in = 0;
+ s->out = 0;
+ s->back = EOF;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else if (*p == 'R') {
+ strategy = Z_RLE;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->start = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * start anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->start = ftell(s->file) - s->stream.avail_in;
+ }
+
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[46]; /* allow for up to 128-bit integers */
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Assure two bytes in the buffer so we can peek ahead -- handle case
+ where first byte of header is at the end of the buffer after the last
+ gzip segment */
+ len = s->stream.avail_in;
+ if (len < 2) {
+ if (len) s->inbuf[0] = s->stream.next_in[0];
+ errno = 0;
+ len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+ if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+ s->stream.avail_in += len;
+ s->stream.next_in = s->inbuf;
+ if (s->stream.avail_in < 2) {
+ s->transparent = s->stream.avail_in;
+ return;
+ }
+ }
+
+ /* Peek ahead to check the gzip magic header */
+ if (s->stream.next_in[0] != gz_magic[0] ||
+ s->stream.next_in[1] != gz_magic[1]) {
+ s->transparent = 1;
+ return;
+ }
+ s->stream.avail_in -= 2;
+ s->stream.next_in += 2;
+
+ /* Check the rest of the gzip header */
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ if (s->stream.avail_out && s->back != EOF) {
+ *next_out++ = s->back;
+ s->stream.next_out++;
+ s->stream.avail_out--;
+ s->back = EOF;
+ s->out++;
+ start++;
+ if (s->last) {
+ s->z_err = Z_STREAM_END;
+ return 1;
+ }
+ }
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -=
+ (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+ }
+ len -= s->stream.avail_out;
+ s->in += len;
+ s->out += len;
+ if (len == 0) s->z_eof = 1;
+ return (int)len;
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may be
+ * different from s->out in case of concatenated .gz files.
+ * Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ inflateReset(&(s->stream));
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ if (len == s->stream.avail_out &&
+ (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+ return -1;
+ return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+ s->back = c;
+ s->out--;
+ s->last = (s->z_err == Z_STREAM_END);
+ if (s->last) s->z_err = Z_OK;
+ s->z_eof = 0;
+ return c;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+ va_start(va, format);
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf(buf, format, va);
+ va_end(va);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = vsprintf(buf, format, va);
+ va_end(va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+ len = strlen(buf);
+# else
+ len = vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+# endif
+#endif
+ if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen(buf);
+# else
+ len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#endif
+ if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), flush);
+ s->out -= s->stream.avail_out;
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->in;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ if (s->inbuf == Z_NULL) return -1L;
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return s->in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->in = s->out = offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if (offset >= s->out) {
+ offset -= s->out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ if (s->outbuf == Z_NULL) return -1L;
+ }
+ if (offset && s->back != EOF) {
+ s->back = EOF;
+ s->out++;
+ offset--;
+ if (s->last) s->z_err = Z_STREAM_END;
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return s->out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+ if (!s->transparent) (void)inflateReset(&s->stream);
+ s->in = 0;
+ s->out = 0;
+ return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ /* With concatenated compressed files that can have embedded
+ * crc trailers, z_eof is no longer the only/best indicator of EOF
+ * on a gz_stream. Handle end-of-stream error explicitly here.
+ */
+ if (s == NULL || s->mode != 'r') return 0;
+ if (s->z_eof) return 1;
+ return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+ Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return 0;
+ return s->transparent;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return Z_STREAM_ERROR;
+#else
+ if (do_flush (file, Z_FINISH) != Z_OK)
+ return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
+
+/* ===========================================================================
+ Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return;
+ if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+ s->z_eof = 0;
+ clearerr(s->file);
+}
diff --git a/src/libtorrent/zlib/infback.c b/src/libtorrent/zlib/infback.c
new file mode 100644
index 0000000..455dbc9
--- /dev/null
+++ b/src/libtorrent/zlib/infback.c
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->write = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/src/libtorrent/zlib/inffast.c b/src/libtorrent/zlib/inffast.c
new file mode 100644
index 0000000..bbee92e
--- /dev/null
+++ b/src/libtorrent/zlib/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/src/libtorrent/zlib/inffast.h b/src/libtorrent/zlib/inffast.h
new file mode 100644
index 0000000..1e88d2d
--- /dev/null
+++ b/src/libtorrent/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/src/libtorrent/zlib/inflate.c b/src/libtorrent/zlib/inflate.c
new file mode 100644
index 0000000..792fdee
--- /dev/null
+++ b/src/libtorrent/zlib/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->write = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
diff --git a/src/libtorrent/zlib/inflate.h b/src/libtorrent/zlib/inflate.h
new file mode 100644
index 0000000..07bd3e7
--- /dev/null
+++ b/src/libtorrent/zlib/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/src/libtorrent/zlib/inftrees.c b/src/libtorrent/zlib/inftrees.c
new file mode 100644
index 0000000..8a9c13f
--- /dev/null
+++ b/src/libtorrent/zlib/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/src/libtorrent/zlib/inftrees.h b/src/libtorrent/zlib/inftrees.h
new file mode 100644
index 0000000..b1104c8
--- /dev/null
+++ b/src/libtorrent/zlib/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/src/libtorrent/zlib/trees.c b/src/libtorrent/zlib/trees.c
new file mode 100644
index 0000000..772a4a0
--- /dev/null
+++ b/src/libtorrent/zlib/trees.c
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id: trees.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+ set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n;
+
+ for (n = 0; n < 9; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ if (n == 9)
+ for (n = 14; n < 32; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/src/libtorrent/zlib/trees.h b/src/libtorrent/zlib/trees.h
new file mode 100644
index 0000000..72facf9
--- /dev/null
+++ b/src/libtorrent/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/src/libtorrent/zlib/uncompr.c b/src/libtorrent/zlib/uncompr.c
new file mode 100644
index 0000000..45d6e53
--- /dev/null
+++ b/src/libtorrent/zlib/uncompr.c
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: uncompr.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/src/libtorrent/zlib/zconf.h b/src/libtorrent/zlib/zconf.h
new file mode 100644
index 0000000..9de3e06
--- /dev/null
+++ b/src/libtorrent/zlib/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.h 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/src/libtorrent/zlib/zlib.h b/src/libtorrent/zlib/zlib.h
new file mode 100644
index 0000000..0228179
--- /dev/null
+++ b/src/libtorrent/zlib/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.3, July 18th, 2005
+
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup at gzip.org madler at alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumualte before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately. Z_FIXED prevents the
+ use of dynamic Huffman codes, allowing for a simpler decoder for special
+ applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front. In addition, the
+ current implementation of deflate will use at most the window size minus
+ 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK can be used to
+ force inflate() to return immediately after header processing is complete
+ and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When
+ any of extra, name, or comment are not Z_NULL and the respective field is
+ not present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns 1 if file is being read directly without decompression, otherwise
+ zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+/*
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is NULL, this function returns the required initial
+ value for the for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/src/libtorrent/zlib/zutil.c b/src/libtorrent/zlib/zutil.c
new file mode 100644
index 0000000..4ec1a84
--- /dev/null
+++ b/src/libtorrent/zlib/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/src/libtorrent/zlib/zutil.h b/src/libtorrent/zlib/zutil.h
new file mode 100644
index 0000000..0a0c202
--- /dev/null
+++ b/src/libtorrent/zlib/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h 1788 2007-11-28 05:16:36Z arvidn $ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+# ifdef _WIN32_WCE
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used. We rename it to
+ * avoid conflict with other libraries that use the same workaround.
+ */
+# define errno z_errno
+# endif
+ extern int errno;
+#else
+# ifndef _WIN32_WCE
+# include <errno.h>
+# endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+ #include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */
diff --git a/src/lobbyoptionstab.cpp b/src/lobbyoptionstab.cpp
new file mode 100644
index 0000000..aeb65f8
--- /dev/null
+++ b/src/lobbyoptionstab.cpp
@@ -0,0 +1,256 @@
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/intl.h>
+#include <wx/stattext.h>
+#include <wx/checkbox.h>
+#include <wx/tooltip.h>
+#include <wx/radiobut.h>
+#include <wx/textctrl.h>
+#include <wx/button.h>
+#include <wx/filedlg.h>
+#include <wx/choice.h>
+
+#include "lobbyoptionstab.h"
+#include "nonportable.h"
+#include "settings.h"
+#include "springlobbyapp.h"
+#include "settings++/custom_dialogs.h"
+#include "utils/controls.h"
+#include "aui/auimanager.h"
+#include "ui.h"
+#include "mainwindow.h"
+
+
+BEGIN_EVENT_TABLE(LobbyOptionsTab, wxPanel)
+
+ EVT_BUTTON ( SPRING_WEBBROWSE, LobbyOptionsTab::OnBrowseWeb )
+ EVT_BUTTON ( ID_BUT_EDITOR, LobbyOptionsTab::OnBrowseEditor )
+ EVT_RADIOBUTTON( SPRING_DEFWEB, LobbyOptionsTab::OnDefaultWeb )
+
+END_EVENT_TABLE()
+
+LobbyOptionsTab::LobbyOptionsTab(wxWindow* parent)
+ : wxScrolledWindow( parent, -1 ),
+ m_show_tooltips_label( 0 )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("lobbyoptionstab") );
+
+ m_main_sizer = new wxBoxSizer ( wxVERTICAL );
+
+/* ================================
+ * Web browser
+ */
+
+ wxStaticBox* m_web_box = new wxStaticBox( this , -1, _("Web Browser") );
+ m_web_loc_text = new wxStaticText( this, -1, _("Web Browser") );
+
+ m_web_def_radio = new wxRadioButton( this, SPRING_DEFWEB, _("Default Browser."),
+ wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
+ m_web_def_radio->SetToolTip(TE(_("Use your system-wide browser preference")));
+
+ m_web_spec_radio = new wxRadioButton( this, SPRING_DEFWEB, _("Specify:") );
+ m_web_spec_radio->SetToolTip(TE(_("Specify the web browser you want to use")));
+
+ m_web_edit = new wxTextCtrl( this, -1, sett().GetWebBrowserPath() );
+
+ m_web_browse_btn = new wxButton( this, SPRING_WEBBROWSE, _("Browse") );
+ m_web_browse_btn->SetToolTip(TE(_("Use a file dialog to find the web browser")));
+
+ if ( sett().GetWebBrowserUseDefault() ) m_web_def_radio->SetValue( true );
+ else m_web_spec_radio->SetValue( true );
+
+ m_web_loc_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_web_loc_sizer->Add( m_web_loc_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2 );
+ m_web_loc_sizer->Add( m_web_edit, 1, wxEXPAND );
+ m_web_loc_sizer->Add( m_web_browse_btn );
+
+ wxStaticBoxSizer* m_web_box_sizer = new wxStaticBoxSizer( m_web_box, wxVERTICAL );
+
+ m_web_box_sizer->Add( m_web_def_radio, 0, wxALL, 2 );
+ m_web_box_sizer->Add( m_web_spec_radio, 0, wxALL, 2 );
+ m_web_box_sizer->Add( m_web_loc_sizer, 0, wxEXPAND | wxALL, 2 );
+/////
+ wxStaticBox* m_editor_box = new wxStaticBox( this , -1, _("External text editor") );
+ m_editor_loc_text = new wxStaticText( this, -1, _("Path") );
+
+ m_editor_edit = new wxTextCtrl( this, -1, sett().GetEditorPath() );
+
+ m_editor_browse_btn = new wxButton( this, ID_BUT_EDITOR, _("Browse") );
+ m_editor_browse_btn->SetToolTip(TE(_("Use a file dialog to find the editor binary")));
+
+ m_editor_loc_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_editor_loc_sizer->Add( m_editor_loc_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2 );
+ m_editor_loc_sizer->Add( m_editor_edit, 1, wxEXPAND );
+ m_editor_loc_sizer->Add( m_editor_browse_btn );
+
+ wxStaticBoxSizer* m_editor_box_sizer = new wxStaticBoxSizer( m_editor_box, wxVERTICAL );
+
+ m_editor_box_sizer->Add( m_editor_loc_sizer, 0, wxEXPAND | wxALL, 2 );
+////////
+ wxStaticBoxSizer* m_autojoin_sizer= new wxStaticBoxSizer ( wxVERTICAL, this, _("Autoconnect") );
+ m_autoconnect_label = new wxStaticText ( this, -1, _("If checked, SpringLobby will automatically log on to the last used server") );
+ m_autojoin = new wxCheckBox( this, -1, _("Autoconnect on lobby start"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_autojoin->SetValue( sett().GetAutoConnect() );
+ m_autojoin_sizer->Add( m_autoconnect_label, 1, wxEXPAND | wxALL, 5 );
+ m_autojoin_sizer->Add( m_autojoin, 0, wxEXPAND | wxALL, 5 );
+
+ wxStaticBoxSizer* m_reportstats_sizer = new wxStaticBoxSizer ( wxVERTICAL, this, _("Report statistics") );
+ m_reportstats_label = new wxStaticText ( this, -1, _("By default SpringLobby will send some statistics (OS,SpringLobby version) to server,\nto both make helping you in case of problems easier and inform of critical updates.\nUncheck to disable.") );
+ m_reportstats = new wxCheckBox( this, -1, _("report statistics"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_reportstats->SetValue( sett().GetReportStats() );
+ m_reportstats_sizer->Add( m_reportstats_label, 1, wxEXPAND|wxALL, 5);
+ m_reportstats_sizer->Add( m_reportstats, 0, wxEXPAND|wxALL, 5);
+
+ m_main_sizer->Add( m_web_box_sizer, 0, wxEXPAND | wxALL, 5 );
+ m_main_sizer->Add( m_editor_box_sizer, 0, wxEXPAND | wxALL, 5 );
+ m_main_sizer->Add( m_autojoin_sizer, 0, wxALL, 5 );
+ m_main_sizer->Add( m_reportstats_sizer, 0, wxALL, 5 );
+
+#ifdef __WXMSW__
+ wxStaticBoxSizer* m_updater_sizer = new wxStaticBoxSizer ( wxVERTICAL, this, _("Automatic updates") );
+ m_updater_label = new wxStaticText ( this, -1, _("SpringLobby can check at startup if a newer version is available and automatically download it for you.") );
+ m_updater = new wxCheckBox( this, -1, _("automatically check for updates"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_updater->SetValue( sett().GetAutoUpdate() );
+ m_updater_sizer->Add( m_updater_label, 1, wxEXPAND|wxALL, 5);
+ m_updater_sizer->Add( m_updater, 0, wxEXPAND|wxALL, 5);
+
+ m_main_sizer->Add( m_updater_sizer, 0, wxALL, 5 );
+#endif
+
+ wxStaticBoxSizer* m_show_tooltips_sizer = new wxStaticBoxSizer ( wxVERTICAL, this, _("Tooltips") );
+ m_show_tooltips = new wxCheckBox( this, -1, _("Show Tooltips?"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_show_tooltips->SetValue( sett().GetShowTooltips() );
+#ifndef __WXMSW__ // on windows this change is immediate
+ m_show_tooltips_label = new wxStaticText ( this, -1, _("Requires SpringLobby restart to take effect.") );
+ m_show_tooltips_sizer->Add( m_show_tooltips_label, 1, wxEXPAND|wxALL, 5);
+#endif
+ m_show_tooltips_sizer->Add( m_show_tooltips, 0, wxEXPAND|wxALL, 5);
+
+ m_main_sizer->Add( m_show_tooltips_sizer, 0, wxALL, 5 );
+
+ wxStaticBoxSizer* m_complete_method_sizer = new wxStaticBoxSizer ( wxVERTICAL, this, _("Tab completion method") );
+ m_complete_method_label = new wxStaticText ( this, -1, _("\"Match exact\" will complete a word if there is one and only one match.\n"
+ "\"Match nearest\" will select the (first) match that has closest Levenshtein distance") );
+ m_complete_method_old = new wxRadioButton( this, -1, _("Match exact"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
+ m_complete_method_new = new wxRadioButton( this, -1, _("Match nearest"), wxDefaultPosition, wxDefaultSize );
+ m_complete_method_old->SetValue( sett().GetCompletionMethod() == Settings::MatchExact );
+ m_complete_method_new->SetValue( sett().GetCompletionMethod() == Settings::MatchNearest );
+ m_complete_method_sizer->Add( m_complete_method_label, 1, wxEXPAND|wxALL, 5);
+ m_complete_method_sizer->Add( m_complete_method_old, 0, wxEXPAND|wxALL, 5);
+ m_complete_method_sizer->Add( m_complete_method_new, 0, wxEXPAND|wxALL, 5);
+
+ m_main_sizer->Add( m_complete_method_sizer, 0, wxALL, 5 );
+
+ wxStaticBoxSizer* m_misc_gui_sizer = new wxStaticBoxSizer ( wxVERTICAL, this, _("Misc GUI") );
+ m_use_tabicons = new wxCheckBox( this, -1, _("Show big icons in mainwindow tabs?"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_use_tabicons->SetValue( sett().GetUseTabIcons() );
+ m_misc_gui_sizer->Add( m_use_tabicons , 0, wxEXPAND | wxALL, 5 );
+
+
+ m_x_on_all_tabs = new wxCheckBox( this, -1, _("Show close button on all tabs? (needs restart to take effect)"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_x_on_all_tabs->SetValue( sett().GetShowXallTabs() );
+ m_misc_gui_sizer->Add( m_x_on_all_tabs , 1, wxEXPAND | wxALL, 5 );
+ m_main_sizer->Add( m_misc_gui_sizer , 0, wxALL, 5 );
+
+ wxStaticBoxSizer* m_start_tab_sizer = new wxStaticBoxSizer ( wxHORIZONTAL, this, _("Start tab") );
+ m_start_tab = new wxChoice( this, -1, wxDefaultPosition, wxDefaultSize, MainWindow::GetTabNames() );
+ m_start_tab->SetSelection( sett().GetStartTab() );
+ wxStaticText* m_start_tab_label = new wxStaticText ( this, -1, _("Select which tab to show at startup") );
+ m_start_tab_sizer->Add( m_start_tab_label , 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5 );
+ m_start_tab_sizer->Add( m_start_tab , 0, wxALIGN_CENTER_VERTICAL , 5 );
+ m_main_sizer->Add( m_start_tab_sizer, 0, wxALL, 5 );
+
+ SetScrollRate( 10, 10 );
+ SetSizer( m_main_sizer );
+}
+
+LobbyOptionsTab::~LobbyOptionsTab()
+{
+ //dtor
+}
+
+void LobbyOptionsTab::OnApply(wxCommandEvent& /*unused*/)
+{
+ if ( !m_web_def_radio->GetValue() ) sett().SetWebBrowserPath( m_web_edit->GetValue() );
+ sett().SetWebBrowserUseDefault( m_web_def_radio->GetValue() );
+
+ sett().SetAutoConnect( m_autojoin->IsChecked() );
+ sett().SetReportStats( m_reportstats->GetValue() );
+#ifdef __WXMSW__
+ sett().SetAutoUpdate( m_updater->IsChecked() );
+#endif
+ bool show = m_show_tooltips->IsChecked();
+ wxToolTip::Enable(show);
+ sett().SetShowTooltips(show);
+
+ sett().SetCompletionMethod( m_complete_method_new->GetValue() ? Settings::MatchNearest: Settings::MatchExact );
+
+ sett().SetUseTabIcons( m_use_tabicons->IsChecked() );
+ ui().mw().SetTabIcons();
+ sett().SetStartTab( m_start_tab->GetSelection() );
+
+ sett().SetEditorPath( m_editor_edit->GetValue() );
+
+ sett().SetShowXallTabs( m_x_on_all_tabs->IsChecked() );
+}
+
+
+void LobbyOptionsTab::OnRestore(wxCommandEvent& /*unused*/)
+{
+ m_autojoin->SetValue( sett().GetAutoConnect() );
+ m_reportstats->SetValue( sett().GetReportStats() );
+#ifdef __WXMSW__
+ m_updater->SetValue( sett().GetAutoUpdate() );
+#endif
+ bool show = sett().GetShowTooltips();
+ m_show_tooltips->SetValue(show);
+ wxToolTip::Enable(show);
+
+ m_complete_method_old->SetValue( sett().GetCompletionMethod() == Settings::MatchExact );
+ m_complete_method_new->SetValue( sett().GetCompletionMethod() == Settings::MatchNearest );
+
+ HandleWebloc( sett().GetWebBrowserUseDefault() );
+ m_use_tabicons->SetValue( sett().GetUseTabIcons() );
+
+ m_start_tab->SetSelection( sett().GetStartTab() );
+
+ m_editor_edit->SetValue( sett().GetEditorPath() );
+
+ m_x_on_all_tabs->SetValue( sett().GetShowXallTabs() );
+}
+
+void LobbyOptionsTab::HandleWebloc( bool defloc )
+{
+ m_web_def_radio->SetValue( defloc );
+ m_web_spec_radio->SetValue( !defloc );
+ if ( defloc ) {
+ m_web_edit->Enable( false );
+ m_web_browse_btn->Enable( false );
+ //m_sync_find_btn->Enable( false );
+ m_web_edit->SetValue( _T("") );
+ } else {
+ m_web_edit->Enable( true );
+ m_web_browse_btn->Enable( true );
+ //m_sync_find_btn->Enable( true );
+ m_web_edit->SetValue( sett().GetWebBrowserPath() );
+ }
+}
+
+void LobbyOptionsTab::OnBrowseWeb( wxCommandEvent& /*unused*/ )
+{
+ wxFileDialog pick( this, _("Choose a web browser executable"), _T(""), _T("*"), CHOOSE_EXE );
+ if ( pick.ShowModal() == wxID_OK ) m_web_edit->SetValue( pick.GetPath() );
+}
+
+void LobbyOptionsTab::OnBrowseEditor( wxCommandEvent& /*unused*/ )
+{
+ wxFileDialog pick( this, _("Choose a editor browser executable"), _T(""), _T("*"), CHOOSE_EXE );
+ if ( pick.ShowModal() == wxID_OK ) m_editor_edit->SetValue( pick.GetPath() );
+}
+
+void LobbyOptionsTab::OnDefaultWeb( wxCommandEvent& /*unused*/ )
+{
+ HandleWebloc( m_web_def_radio->GetValue() );
+}
+
+
diff --git a/src/lobbyoptionstab.h b/src/lobbyoptionstab.h
new file mode 100644
index 0000000..7c6693b
--- /dev/null
+++ b/src/lobbyoptionstab.h
@@ -0,0 +1,94 @@
+#ifndef LOBBYOPTIONSTAB_H
+#define LOBBYOPTIONSTAB_H
+
+#include <wx/scrolwin.h>
+
+class wxCheckBox;
+class wxBoxSizer;
+class wxStaticText;
+class wxRadioButton;
+class wxTextCtrl;
+class wxButton;
+class wxStaticBoxSizer;
+class wxChoice;
+
+class LobbyOptionsTab : public wxScrolledWindow
+{
+ public:
+ LobbyOptionsTab(wxWindow* parent);
+ virtual ~LobbyOptionsTab();
+
+ void OnApply( wxCommandEvent& event );
+ void OnRestore( wxCommandEvent& event );
+
+ void OnBrowseWeb( wxCommandEvent& event );
+ void OnBrowseEditor( wxCommandEvent& event );
+ void OnDefaultWeb( wxCommandEvent& event );
+ void HandleWebloc( bool defloc );
+
+ protected:
+
+ wxCheckBox* m_autojoin;
+ wxCheckBox* m_reportstats;
+ wxCheckBox* m_updater;
+ wxCheckBox* m_show_tooltips;
+ wxCheckBox* m_use_tabicons;
+ wxCheckBox* m_x_on_all_tabs;
+
+ wxStaticText* m_autoconnect_label;
+ wxStaticText* m_reportstats_label;
+ wxStaticText* m_updater_label;
+ wxStaticText* m_show_tooltips_label;
+ wxStaticText* m_web_loc_text;
+ wxStaticText* m_editor_loc_text;
+ wxTextCtrl* m_web_edit;
+ wxTextCtrl* m_editor_edit;
+
+ wxStaticText* m_complete_method_label;
+ wxRadioButton* m_complete_method_old;
+ wxRadioButton* m_complete_method_new;
+ wxButton* m_web_browse_btn;
+ wxButton* m_editor_browse_btn;
+ wxButton* m_select_locale;
+ wxRadioButton* m_web_def_radio;
+ wxRadioButton* m_web_spec_radio;
+
+
+ wxBoxSizer* m_main_sizer;
+ wxStaticBoxSizer* m_web_box_sizer;
+ wxStaticBoxSizer* m_editor_box_sizer;
+ wxBoxSizer* m_web_loc_sizer;
+ wxBoxSizer* m_editor_loc_sizer;
+
+ wxChoice* m_start_tab;
+
+ enum
+ {
+ SPRING_WEBBROWSE = wxID_HIGHEST,
+ SPRING_DEFWEB,
+ ID_BUT_EDITOR
+ };
+
+
+ DECLARE_EVENT_TABLE();
+};
+
+#endif // LOBBYOPTIONSTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mainchattab.cpp b/src/mainchattab.cpp
new file mode 100644
index 0000000..e9ecf9c
--- /dev/null
+++ b/src/mainchattab.cpp
@@ -0,0 +1,361 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: MainChatTab
+//
+
+#include <stdexcept>
+#include <wx/intl.h>
+#include <wx/imaglist.h>
+#include <wx/sizer.h>
+#include <wx/notebook.h>
+#include <wx/image.h>
+#include <wx/log.h>
+
+#include "aui/auimanager.h"
+#include "mainchattab.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "utils/math.h"
+#include "mainwindow.h"
+#include "channel/channel.h"
+#include "user.h"
+#include "chatpanel.h"
+#include "ui.h"
+#include "server.h"
+#include "settings.h"
+#include "aui/artprovider.h"
+#include "aui/slbook.h"
+
+#include "images/close.xpm"
+#include "images/server.xpm"
+#include "images/channel.xpm"
+#include "images/userchat.xpm"
+
+BEGIN_EVENT_TABLE( MainChatTab, wxPanel )
+
+ EVT_AUINOTEBOOK_PAGE_CHANGED ( CHAT_TABS, MainChatTab::OnTabsChanged )
+ EVT_AUINOTEBOOK_PAGE_CLOSE ( CHAT_TABS, MainChatTab::OnTabClose )
+
+END_EVENT_TABLE()
+
+
+MainChatTab::MainChatTab( wxWindow* parent, Ui& ui )
+ : wxScrolledWindow( parent, -1, wxDefaultPosition, wxDefaultSize, 0, wxPanelNameStr ),
+ m_ui( ui )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "mainchattab" ) );
+
+ m_newtab_sel = -1;
+ m_server_chat = 0;
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_chat_tabs = new SLNotebook( this, CHAT_TABS, wxDefaultPosition, wxDefaultSize, wxAUI_NB_DEFAULT_STYLE | wxAUI_NB_TOP | wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_WINDOWLIST_BUTTON );
+ m_chat_tabs ->SetArtProvider( new SLArtProvider );
+
+ wxBitmap userchat ( userchat_xpm ); //*charArr2wxBitmap(userchat_png, sizeof(userchat_png) );
+ m_imagelist = new wxImageList( 12, 12 );
+ m_imagelist->Add( wxBitmap( close_xpm ) );
+ m_imagelist->Add( wxBitmap( server_xpm ) );
+ m_imagelist->Add( wxBitmap( channel_xpm ) );
+ m_imagelist->Add( wxBitmap( userchat_xpm ) );
+
+ m_imagelist->Add( wxBitmap ( ReplaceChannelStatusColour( wxBitmap( channel_xpm ), sett().GetChatColorJoinPart() ) ) );
+ m_imagelist->Add( wxBitmap ( ReplaceChannelStatusColour( wxBitmap( userchat_xpm ), sett().GetChatColorJoinPart() ) ) );
+
+ m_imagelist->Add( wxBitmap ( ReplaceChannelStatusColour( wxBitmap( channel_xpm ), sett().GetChatColorMine() ) ) );
+ m_imagelist->Add( wxBitmap ( ReplaceChannelStatusColour( wxBitmap( userchat_xpm ), sett().GetChatColorMine() ) ) );
+
+ m_imagelist->Add( wxBitmap ( ReplaceChannelStatusColour( wxBitmap( channel_xpm ), sett().GetChatColorHighlight() ) ) );
+ m_imagelist->Add( wxBitmap ( ReplaceChannelStatusColour( wxBitmap( userchat_xpm ), sett().GetChatColorHighlight() ) ) );
+
+ m_imagelist->Add( wxBitmap ( ReplaceChannelStatusColour( wxBitmap( server_xpm ), sett().GetChatColorError() ) ) );
+
+ m_main_sizer->Add( m_chat_tabs, 1, wxEXPAND );
+
+ SetSizer( m_main_sizer );
+ m_main_sizer->SetSizeHints( this );
+ SetScrollRate( 3, 3 );
+ Layout();
+}
+
+
+MainChatTab::~MainChatTab()
+{
+
+}
+
+ChatPanel& MainChatTab::ServerChat()
+{
+ ASSERT_LOGIC( m_server_chat != 0, _T( "m_server_chat = 0" ) );
+ return *m_server_chat;
+}
+
+
+ChatPanel* MainChatTab::GetActiveChatPanel()
+{
+ return ( ChatPanel* )m_chat_tabs->GetPage( m_chat_tabs->GetSelection() );
+}
+
+
+ChatPanel* MainChatTab::GetChannelChatPanel( const wxString& channel )
+{
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_Channel ) {
+ wxString name = m_chat_tabs->GetPageText( i );
+ if ( name.Lower() == channel.Lower() ) return ( ChatPanel* )m_chat_tabs->GetPage( i );
+ }
+ }
+ return 0;
+}
+
+void MainChatTab::UpdateNicklistHighlights()
+{
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_Channel ) {
+ tmp->UpdateNicklistHighlights();
+ }
+ }
+}
+
+ChatPanel* MainChatTab::GetUserChatPanel( const wxString& user )
+{
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_User ) {
+ wxString name = m_chat_tabs->GetPageText( i );
+ if ( name.Lower() == user.Lower() ) return ( ChatPanel* )m_chat_tabs->GetPage( i );
+ }
+ }
+ return 0;
+}
+
+
+void MainChatTab::OnUserConnected( User& user )
+{
+ ChatPanel* panel = GetUserChatPanel( user.GetNick() );
+ if ( panel != 0 ) {
+ panel->SetUser( &user );
+ panel->OnUserConnected();
+ //TODO enable send button (koshi)
+ }
+}
+
+
+void MainChatTab::OnUserDisconnected( User& user )
+{
+ ChatPanel* panel = GetUserChatPanel( user.GetNick() );
+ if ( panel != 0 ) {
+ panel->OnUserDisconnected();
+ panel->SetUser( 0 );
+ //TODO disable send button (koshi)
+ }
+}
+
+void MainChatTab::LeaveChannels()
+{
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_Channel )
+ {
+ tmp->StatusMessage( _( "Disconnected from server, chat closed." ) );
+ tmp->SetChannel( 0 );
+ } else if ( tmp->GetPanelType() == CPT_User )
+ {
+ tmp->StatusMessage( _( "Disconnected from server, chat closed." ) );
+ tmp->SetUser( 0 );
+ }
+ }
+}
+
+void MainChatTab::RejoinChannels()
+{
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ )
+ {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_Channel )
+ {
+
+ // TODO: This will not rejoin passworded channels.
+ wxString name = m_chat_tabs->GetPageText( i );
+ bool alreadyin = false;
+ try
+ {
+ ui().GetServer().GetChannel( name ).GetMe();
+ alreadyin = true;
+ }
+ catch ( ... ) {}
+ if ( !alreadyin )
+ {
+ m_ui.GetServer().JoinChannel( name, _T( "" ) );
+ tmp->SetChannel( &m_ui.GetServer().GetChannel( name ) );
+ }
+
+ } else if ( tmp->GetPanelType() == CPT_User )
+ {
+
+ wxString name = m_chat_tabs->GetPageText( i );
+ if ( m_ui.GetServer().UserExists( name ) ) tmp->SetUser( &m_ui.GetServer().GetUser( name ) );
+
+ }
+ }
+}
+
+
+ChatPanel* MainChatTab::AddChatPanel( Channel& channel )
+{
+
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ if ( m_chat_tabs->GetPageText( i ) == channel.GetName() ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_Channel ) {
+ m_chat_tabs->SetSelection( i );
+ tmp->SetChannel( &channel );
+ return tmp;
+ }
+ }
+ }
+
+ ChatPanel* chat = new ChatPanel( m_chat_tabs, m_ui, channel, m_imagelist );
+ m_chat_tabs->InsertPage( m_chat_tabs->GetPageCount() - 1, chat, channel.GetName(), true, wxBitmap( channel_xpm ) );
+ chat->FocusInputBox();
+ return chat;
+}
+
+ChatPanel* MainChatTab::AddChatPanel( Server& server, const wxString& name )
+{
+
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ if ( m_chat_tabs->GetPageText( i ) == name ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_Server ) {
+ m_chat_tabs->SetSelection( i );
+ tmp->SetServer( &server );
+ return tmp;
+ }
+ }
+ }
+
+ ChatPanel* chat = new ChatPanel( m_chat_tabs, m_ui, server, m_imagelist );
+ m_chat_tabs->InsertPage( m_chat_tabs->GetPageCount() - 1, chat, name, true, wxBitmap( server_xpm ) );
+ return chat;
+}
+
+ChatPanel* MainChatTab::AddChatPanel( const User& user )
+{
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ if ( m_chat_tabs->GetPageText( i ) == user.GetNick() ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp->GetPanelType() == CPT_User ) {
+ m_chat_tabs->SetSelection( i );
+ tmp->SetUser( &user );
+ return tmp;
+ }
+ }
+ }
+ int selection = m_chat_tabs->GetSelection();
+ ChatPanel* chat = new ChatPanel( m_chat_tabs, m_ui, user, m_imagelist );
+ m_chat_tabs->InsertPage( m_chat_tabs->GetPageCount() - 1, chat, user.GetNick(), true, wxBitmap( userchat_xpm ) );
+ if ( selection > 0 ) m_chat_tabs->SetSelection( selection );
+ return chat;
+}
+
+void MainChatTab::OnTabClose( wxAuiNotebookEvent& event )
+{
+ int selection = event.GetSelection();
+ ChatPanel* panel = ( ChatPanel* )m_chat_tabs->GetPage( selection );
+ if ( panel )
+ {
+ panel->Part();
+ }
+}
+
+void MainChatTab::OnTabsChanged( wxAuiNotebookEvent& event )
+{
+ wxLogDebugFunc( _T( "" ) );
+
+ int oldsel = event.GetOldSelection();
+ if ( oldsel < 0 ) return;
+ int newsel = event.GetSelection();
+ if ( newsel < 0 ) return;
+
+ // change icon to default the icon to show that no new events happened
+ size_t ImageIndex = ( ( ChatPanel* )m_chat_tabs->GetPage( newsel ) )->GetIconIndex();
+ if ( ImageIndex == 4 || ImageIndex == 6 || ImageIndex == 8 )
+ {
+ GetActiveChatPanel()->SetIconIndex( 2 );
+ m_chat_tabs->SetPageBitmap( newsel, wxBitmap( channel_xpm ) );
+ }
+ else if ( ImageIndex == 5 || ImageIndex == 7 || ImageIndex == 9 )
+ {
+ GetActiveChatPanel()->SetIconIndex( 3 );
+ m_chat_tabs->SetPageBitmap( newsel, wxBitmap( userchat_xpm ) );
+ }
+ else if ( ImageIndex == 10 )
+ {
+ GetActiveChatPanel()->SetIconIndex( 1 );
+ m_chat_tabs->SetPageBitmap( newsel, wxBitmap( server_xpm ) );
+ }
+
+ wxWindow* newpage = m_chat_tabs->GetPage( newsel );
+ if ( newpage == 0 ) { // Not sure what to do here
+ wxLogError( _T( "Newpage NULL." ) );
+ return;
+ }
+
+ GetActiveChatPanel()->FocusInputBox();
+
+}
+
+
+wxImage MainChatTab::ReplaceChannelStatusColour( wxBitmap img, const wxColour& colour )
+{
+ wxImage ret = img.ConvertToImage();
+ wxImage::HSVValue origcolour = wxImage::RGBtoHSV( wxImage::RGBValue::RGBValue( colour.Red(), colour.Green(), colour.Blue() ) );
+
+ double bright = origcolour.value - 0.1 * origcolour.value;
+ bright = clamp( bright, 0.0, 1.0 );
+ wxImage::HSVValue hsvdarker1( origcolour.hue, origcolour.saturation, bright );
+ bright = origcolour.value - 0.5 * origcolour.value;
+ bright = clamp( bright, 0.0, 1.0 );
+ wxImage::HSVValue hsvdarker2( origcolour.hue, origcolour.saturation, bright );
+
+ wxImage::RGBValue rgbdarker1 = wxImage::HSVtoRGB( hsvdarker1 );
+ wxImage::RGBValue rgbdarker2 = wxImage::HSVtoRGB( hsvdarker2 );
+
+
+ ret.Replace( 164, 147, 0, rgbdarker2.red, rgbdarker2.green, rgbdarker2.blue );
+
+ ret.Replace( 255, 228, 0, rgbdarker1.red, rgbdarker1.green, rgbdarker1.blue );
+
+ ret.Replace( 255, 253, 234, colour.Red(), colour.Green(), colour.Blue() );
+
+ ret.Replace( 255, 228, 0, rgbdarker1.red, rgbdarker1.green, rgbdarker1.blue );
+
+ // server icon
+
+ ret.Replace( 211, 211, 211, rgbdarker2.red, rgbdarker2.green, rgbdarker2.blue );
+
+ ret.Replace( 249, 249, 249, rgbdarker1.red, rgbdarker1.green, rgbdarker1.blue );
+
+ ret.Replace( 0, 180, 255, colour.Red(), colour.Green(), colour.Blue() );
+
+
+ return ret;
+}
+
+bool MainChatTab::RemoveChatPanel( ChatPanel* panel )
+{
+ for ( unsigned int i = 0; i < m_chat_tabs->GetPageCount(); i++ ) {
+ ChatPanel* tmp = ( ChatPanel* )m_chat_tabs->GetPage( i );
+ if ( tmp == panel && panel != 0 )
+ {
+ m_chat_tabs->DeletePage( i );
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/src/mainchattab.h b/src/mainchattab.h
new file mode 100644
index 0000000..242a363
--- /dev/null
+++ b/src/mainchattab.h
@@ -0,0 +1,90 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MAINCHATTAB_H
+#define SPRINGLOBBY_HEADERGUARD_MAINCHATTAB_H
+
+#include <wx/scrolwin.h>
+
+class Ui;
+class ChatPanel;
+class Server;
+class Channel;
+class User;
+class wxAuiNotebookEvent;
+class SLNotebook;
+class wxBoxSizer;
+class wxImageList;
+class wxString;
+
+//! @brief The main chat tab.
+class MainChatTab : public wxScrolledWindow
+{
+ public:
+ MainChatTab( wxWindow* parent, Ui& ui );
+ ~MainChatTab();
+
+ ChatPanel* GetActiveChatPanel();
+ ChatPanel* GetChannelChatPanel( const wxString& channel );
+ ChatPanel* GetUserChatPanel( const wxString& user );
+
+ ChatPanel& ServerChat();
+
+ ChatPanel* AddChatPanel( Channel& channel );
+ ChatPanel* AddChatPanel( Server& server, const wxString& name );
+ ChatPanel* AddChatPanel( const User& user );
+ /** \brief this is only used if channel is left via raw command in server tab */
+ bool RemoveChatPanel( ChatPanel* panel );
+
+ void RejoinChannels();
+ void LeaveChannels();
+
+ void OnTabsChanged( wxAuiNotebookEvent& event );
+ void OnTabClose( wxAuiNotebookEvent& event );
+ void OnUserConnected( User& user );
+ void OnUserDisconnected( User& user );
+
+ void ChangeUnreadChannelColour( const wxColour& colour );
+ void ChangeUnreadPMColour( const wxColour& colour );
+
+ void UpdateNicklistHighlights();
+
+ wxImage ReplaceChannelStatusColour( wxBitmap img, const wxColour& colour );
+
+ protected:
+
+ Ui& m_ui;
+
+ wxWindow* m_close_window;
+ SLNotebook* m_chat_tabs;
+ wxBoxSizer* m_main_sizer;
+ wxImageList* m_imagelist;
+ ChatPanel* m_server_chat;
+ ChatPanel* m_main_chat;
+ int m_newtab_sel;
+
+ enum {
+ CHAT_TABS = wxID_HIGHEST
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_MAINCHATTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mainjoinbattletab.cpp b/src/mainjoinbattletab.cpp
new file mode 100644
index 0000000..bcd97d7
--- /dev/null
+++ b/src/mainjoinbattletab.cpp
@@ -0,0 +1,264 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: MainJoinBattleTab
+//
+
+#include <wx/icon.h>
+#include <wx/intl.h>
+#include <wx/notebook.h>
+#include <wx/imaglist.h>
+#include <wx/sizer.h>
+#include <wx/wupdlock.h>
+#include <wx/log.h>
+
+#include "ui.h"
+#include "settings.h"
+#include "battle.h"
+#include "mainjoinbattletab.h"
+#include "battlelisttab.h"
+#include "battleroomtab.h"
+#include "battlemaptab.h"
+#include "battleoptionstab.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "battleroommmoptionstab.h"
+#include "aui/auimanager.h"
+#include "aui/artprovider.h"
+#include "aui/slbook.h"
+
+#include "images/battle_list.xpm"
+#include "images/battle.xpm"
+#include "images/battle_map.xpm"
+#include "images/battle_settings.xpm"
+
+#include <stdexcept>
+
+MainJoinBattleTab::MainJoinBattleTab( wxWindow* parent, Ui& ui )
+ : wxScrolledWindow( parent, -1 ),
+ m_battle_tab( 0 ),
+ m_map_tab( 0 ),
+ m_opts_tab( 0 ),
+ m_mm_opts_tab( 0 ),
+ m_ui( ui )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "mainjoinbattletab" ) );
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_tabs = new SLNotebook( this, BATTLE_TABS, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_TOP | wxAUI_NB_TAB_EXTERNAL_MOVE );
+ m_tabs->SetArtProvider( new SLArtProvider );
+
+ m_imagelist = new wxImageList( 12, 12 );
+ m_imagelist->Add( wxIcon( battle_list_xpm ) );
+ m_imagelist->Add( wxIcon( battle_xpm ) );
+ m_imagelist->Add( wxIcon( battle_map_xpm ) );
+ m_imagelist->Add( wxIcon( battle_settings_xpm ) );
+
+ m_list_tab = new BattleListTab( m_tabs, m_ui );
+ m_tabs->AddPage( m_list_tab, _( "Battle list" ), true, wxIcon( battle_list_xpm ) );
+
+ m_main_sizer->Add( m_tabs, 1, wxEXPAND );
+
+ SetScrollRate( 3, 3 );
+ SetSizer( m_main_sizer );
+ Layout();
+}
+
+
+MainJoinBattleTab::~MainJoinBattleTab()
+{
+
+}
+
+
+Battle* MainJoinBattleTab::GetCurrentBattle()
+{
+ if ( m_battle_tab )
+ return &m_battle_tab->GetBattle();
+
+ return 0;
+}
+
+
+ChatPanel* MainJoinBattleTab::GetActiveChatPanel()
+{
+ if ( m_tabs->GetSelection() == 1 ) {
+ if ( m_battle_tab != 0 ) return &m_battle_tab->GetChatPanel();
+ }
+ return 0;
+}
+
+//void MainJoinBattleTab::UpdateCurrentBattle()
+void MainJoinBattleTab::UpdateCurrentBattle()
+{
+ try
+ {
+ GetBattleRoomTab().UpdateBattleInfo();
+ } catch ( ... ) {}
+ try
+ {
+ GetBattleMapTab().Update();
+ } catch ( ... ) {}
+}
+
+void MainJoinBattleTab::UpdateCurrentBattle( const wxString& Tag )
+{
+ try
+ {
+ GetBattleRoomTab().UpdateBattleInfo( Tag );
+ } catch ( ... ) {}
+
+ try
+ {
+ GetBattleMapTab().Update( Tag );
+ } catch ( ... ) {}
+
+ try
+ {
+ GetOptionsTab().UpdateBattle( Tag );
+ } catch ( ... ) {}
+
+ try
+ {
+ GetMMOptionsTab().UpdateOptControls( Tag );
+ } catch ( ... ) {}
+}
+
+
+BattleListTab& MainJoinBattleTab::GetBattleListTab()
+{
+ ASSERT_LOGIC( m_list_tab != 0, _T( "m_list_tab = 0" ) );
+ return *m_list_tab;
+}
+
+
+void MainJoinBattleTab::JoinBattle( Battle& battle )
+{
+ LeaveCurrentBattle();
+
+ m_battle_tab = new BattleRoomTab( m_tabs, m_ui, battle );
+ m_tabs->InsertPage( 1, m_battle_tab, _( "Battleroom" ), true, wxIcon( battle_xpm ) );
+
+ m_map_tab = new BattleMapTab( m_tabs, m_ui, battle );
+ m_tabs->InsertPage( 2, m_map_tab, _( "Map" ), false, wxIcon( battle_map_xpm ) );
+
+ m_mm_opts_tab = new BattleroomMMOptionsTab<Battle>( battle, m_tabs );
+ m_tabs->InsertPage( 3, m_mm_opts_tab, _( "Options" ), false, wxIcon( battle_settings_xpm ) );
+
+ m_opts_tab = new BattleOptionsTab( m_tabs, m_ui, battle );
+ m_tabs->InsertPage( 4, m_opts_tab, _( "Unit Restrictions" ), false, wxIcon( battle_settings_xpm ) );
+
+#ifdef __WXMSW__
+ Refresh(); // this is needed to avoid a weird frame overlay glitch in windows
+#endif
+}
+
+
+void MainJoinBattleTab::HostBattle( Battle& battle )
+{
+ JoinBattle( battle );
+}
+
+
+void MainJoinBattleTab::LeaveCurrentBattle()
+{
+ if ( m_mm_opts_tab ) {
+ m_tabs->DeletePage( 4 );
+ m_mm_opts_tab = 0;
+ }
+ if ( m_opts_tab ) {
+ m_tabs->DeletePage( 3 );
+ m_opts_tab = 0;
+ }
+ if ( m_map_tab ) {
+ m_tabs->DeletePage( 2 );
+ m_map_tab = 0;
+ }
+ if ( m_battle_tab ) {
+ m_tabs->DeletePage( 1 );
+ m_battle_tab = 0;
+ }
+
+
+}
+
+
+void MainJoinBattleTab::BattleUserUpdated( User& user )
+{
+ try
+ {
+ GetBattleRoomTab().UpdateUser( user );
+ } catch ( ... ) {}
+ try
+ {
+ GetBattleMapTab().UpdateUser( user );
+ } catch ( ... ) {}
+}
+
+
+void MainJoinBattleTab::OnUnitSyncReloaded()
+{
+ wxLogDebugFunc( _T( "" ) );
+ GetBattleListTab().OnUnitSyncReloaded();
+ wxLogMessage( _T( "Battle list tab reloaded" ) );
+ try
+ {
+ GetBattleRoomTab().OnUnitSyncReloaded();
+ } catch ( ... ) {}
+ try
+ {
+ GetBattleMapTab().OnUnitSyncReloaded();
+ } catch ( ... ) {}
+ wxLogMessage( _T( "Battle list tab reloaded" ) );
+}
+
+void MainJoinBattleTab::OnConnected()
+{
+ if ( m_list_tab ) {
+ bool filter = sett().GetBattleFilterActivState();
+ m_list_tab->SetFilterActiv( filter );
+ //
+ }
+}
+
+void MainJoinBattleTab::ReloadPresetList()
+{
+ try
+ {
+ GetBattleRoomTab().UpdatePresetList();
+ } catch ( ... ) {}
+ try
+ {
+ GetMMOptionsTab().UpdatePresetList();
+ } catch ( ... ) {}
+
+}
+
+
+BattleRoomTab& MainJoinBattleTab::GetBattleRoomTab()
+{
+ ASSERT_EXCEPTION( m_battle_tab, _T( "m_battle_tab == 0" ) );
+ return *m_battle_tab;
+}
+
+
+BattleMapTab& MainJoinBattleTab::GetBattleMapTab()
+{
+ ASSERT_EXCEPTION( m_map_tab, _T( "m_map_tab == 0" ) );
+ return *m_map_tab;
+}
+
+
+BattleOptionsTab& MainJoinBattleTab::GetOptionsTab()
+{
+ ASSERT_EXCEPTION( m_opts_tab, _T( "m_opts_tab == 0" ) );
+ return *m_opts_tab;
+}
+
+
+BattleroomMMOptionsTab<Battle>& MainJoinBattleTab::GetMMOptionsTab()
+{
+ ASSERT_EXCEPTION( m_mm_opts_tab, _T( "m_mm_opts_tab == 0" ) );
+ return *m_mm_opts_tab;
+}
+
diff --git a/src/mainjoinbattletab.h b/src/mainjoinbattletab.h
new file mode 100644
index 0000000..02ac712
--- /dev/null
+++ b/src/mainjoinbattletab.h
@@ -0,0 +1,89 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MAINJOINBATTLETAB_H
+#define SPRINGLOBBY_HEADERGUARD_MAINJOINBATTLETAB_H
+
+#include <wx/scrolwin.h>
+#include "battleroommmoptionstab.h"
+
+class Ui;
+class BattleListTab;
+class Battle;
+class User;
+class BattleRoomTab;
+class BattleMapTab;
+class BattleOptionsTab;
+class wxBoxSizer;
+class wxImageList;
+class SLNotebook;
+class wxNotebook;
+
+class MainJoinBattleTab : public wxScrolledWindow
+{
+ public:
+ MainJoinBattleTab( wxWindow* parent, Ui& ui );
+ ~MainJoinBattleTab();
+
+ BattleListTab& GetBattleListTab();
+
+ void HostBattle( Battle& battle );
+ void JoinBattle( Battle& battle );
+ //void UpdateCurrentBattle();
+ void UpdateCurrentBattle();
+ void UpdateCurrentBattle( const wxString& Tag );
+ void LeaveCurrentBattle();
+ Battle* GetCurrentBattle();
+ ChatPanel* GetActiveChatPanel();
+
+ void BattleUserUpdated( User& user );
+ BattleRoomTab& GetBattleRoomTab();
+ BattleMapTab& GetBattleMapTab();
+ BattleOptionsTab& GetOptionsTab();
+ BattleroomMMOptionsTab<Battle>& GetMMOptionsTab();
+
+ void ReloadPresetList();
+
+ void OnUnitSyncReloaded();
+
+ void OnConnected();
+
+ protected:
+ wxBoxSizer* m_main_sizer;
+
+ wxImageList* m_imagelist;
+
+ SLNotebook* m_tabs;
+
+ BattleListTab* m_list_tab;
+
+ BattleRoomTab* m_battle_tab;
+ BattleMapTab* m_map_tab;
+ BattleOptionsTab* m_opts_tab;
+ BattleroomMMOptionsTab<Battle>* m_mm_opts_tab;
+ Ui& m_ui;
+
+ enum {
+ BATTLE_TABS = wxID_HIGHEST
+ };
+
+};
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_MAINJOINBATTLETAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mainoptionstab.cpp b/src/mainoptionstab.cpp
new file mode 100644
index 0000000..c57fbda
--- /dev/null
+++ b/src/mainoptionstab.cpp
@@ -0,0 +1,151 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: MainOptionsTab
+//
+
+#include "mainoptionstab.h"
+
+#include <wx/icon.h>
+#include <wx/intl.h>
+#include <wx/notebook.h>
+#include <wx/imaglist.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/log.h>
+
+#include "aui/auimanager.h"
+#include "aui/artprovider.h"
+#include "aui/slbook.h"
+#include "ui.h"
+#include "springoptionstab.h"
+#include "chatoptionstab.h"
+#include "settings.h"
+#include "uiutils.h"
+#include "groupoptionspanel.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+
+#ifndef NO_TORRENT_SYSTEM
+#include "torrentoptionspanel.h"
+#endif
+
+#include "lobbyoptionstab.h"
+#include "images/torrentoptionspanel_icon.png.h"
+#include "images/spring.xpm"
+#include "images/userchat.xpm"
+#include "images/springlobby.xpm"
+
+
+BEGIN_EVENT_TABLE( MainOptionsTab, wxPanel )
+
+ EVT_BUTTON ( wxID_APPLY, MainOptionsTab::OnApply )
+ EVT_BUTTON ( wxID_REVERT, MainOptionsTab::OnRestore )
+
+END_EVENT_TABLE()
+
+/** \brief A container for the various option panels
+ * Contains a notebook holding the real option panels as pages. Handles "apply" and "restore" events for those pages,
+ * rather then those having to implement (and duplicate) this functionality. \n
+ * See SpringOptionsTab, TorrentOptionsPanel, ChatOptionsTab
+ */
+MainOptionsTab::MainOptionsTab( wxWindow* parent, Ui& ui ) : wxScrolledWindow( parent, -1 ), m_ui( ui )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "mainoptionstab" ) );
+ m_tabs = new SLNotebook( this, OPTIONS_TABS, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_TOP | wxAUI_NB_TAB_EXTERNAL_MOVE );
+ m_tabs->SetArtProvider( new SLArtProvider );
+ m_imagelist = new wxImageList( 12, 12 );
+ m_imagelist->Add( wxIcon( spring_xpm ) );
+ m_imagelist->Add( charArr2wxBitmap( torrentoptionspanel_icon_png, sizeof( torrentoptionspanel_icon_png ) ) );
+ m_imagelist->Add( wxIcon( userchat_xpm ) );
+ m_imagelist->Add( wxIcon( userchat_xpm ) );
+ m_imagelist->Add( wxIcon( springlobby_xpm ) );
+
+ m_spring_opts = new SpringOptionsTab( m_tabs, m_ui );
+ m_tabs->AddPage( m_spring_opts, _( "Spring" ), true, wxIcon( spring_xpm ) );
+
+#ifndef NO_TORRENT_SYSTEM
+ m_torrent_opts = new TorrentOptionsPanel( m_tabs, m_ui );
+ m_tabs->AddPage( m_torrent_opts, _( "P2P" ), true, charArr2wxBitmap( torrentoptionspanel_icon_png, sizeof( torrentoptionspanel_icon_png ) ) );
+#endif
+
+ m_chat_opts = new ChatOptionsTab( m_tabs, m_ui );
+ m_tabs->AddPage( m_chat_opts, _( "Chat" ), true, wxIcon( userchat_xpm ) );
+
+ m_lobby_opts = new LobbyOptionsTab( m_tabs );
+ m_tabs->AddPage ( m_lobby_opts, _( "General" ), true, wxIcon( springlobby_xpm ) );
+
+ m_groups_opts = new GroupOptionsPanel( m_tabs );
+ m_tabs->AddPage ( m_groups_opts, _( "Groups" ), true, wxIcon( userchat_xpm ) );
+
+ m_restore_btn = new wxButton( this, wxID_REVERT, _( "Restore" ) );
+ m_apply_btn = new wxButton( this, wxID_APPLY, _( "Apply" ) );
+
+ m_button_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_button_sizer->AddStretchSpacer();
+ m_button_sizer->Add( m_restore_btn, 0, wxALL, 2 );
+ m_button_sizer->Add( m_apply_btn, 0, wxALL, 2 );
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+ m_main_sizer->Add( m_tabs, 1, wxEXPAND );
+ m_main_sizer->Add( m_button_sizer, 0, wxEXPAND );
+
+ SetSizer( m_main_sizer );
+ SetScrollRate( 3, 3 );
+ Layout();
+ Refresh();
+}
+
+
+MainOptionsTab::~MainOptionsTab()
+{
+
+}
+
+
+GroupOptionsPanel& MainOptionsTab::GetGroupOptionsPanel()
+{
+ ASSERT_EXCEPTION( m_groups_opts != 0, _T( "m_groups_opts == 0" ) );
+ return *m_groups_opts;
+}
+
+
+void MainOptionsTab::OnApply( wxCommandEvent& event )
+{
+ m_spring_opts->OnApply( event );
+ m_chat_opts->OnApply( event );
+#ifndef NO_TORRENT_SYSTEM
+ m_torrent_opts->OnApply( event );
+#endif
+ m_lobby_opts->OnApply( event );
+
+ sett().SaveSettings();
+}
+
+
+void MainOptionsTab::OnRestore( wxCommandEvent& event )
+{
+ m_spring_opts->OnRestore( event );
+ m_chat_opts->OnRestore( event );
+#ifndef NO_TORRENT_SYSTEM
+ m_torrent_opts->OnRestore( event );
+#endif
+
+ m_lobby_opts->OnRestore ( event );
+}
+
+void MainOptionsTab::OnOpenGroupsTab()
+{
+ //m_groups_opts->ReloadGroupSizer();
+}
+
+void MainOptionsTab::SetSelection( const unsigned int page )
+{
+ if ( page < m_tabs->GetPageCount() ) {
+ m_tabs->SetSelection( page );
+ //m_groups_opts->ReloadGroupSizer();
+ }
+ else
+ m_tabs->SetSelection( 0 );
+}
+
+
diff --git a/src/mainoptionstab.h b/src/mainoptionstab.h
new file mode 100644
index 0000000..87fe82b
--- /dev/null
+++ b/src/mainoptionstab.h
@@ -0,0 +1,87 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MAINOPTIONSTAB_H
+#define SPRINGLOBBY_HEADERGUARD_MAINOPTIONSTAB_H
+
+#include <wx/scrolwin.h>
+
+class Ui;
+class wxCommandEvent;
+class wxBoxSizer;
+class wxImageList;
+class wxNotebook;
+class SLNotebook;
+class SpringOptionsTab;
+class ChatOptionsTab;
+class wxButton;
+class wxBoxSizer;
+class TorrentOptionsPanel;
+class GroupOptionsPanel;
+class LobbyOptionsTab;
+
+/** \brief A container for the various option panels
+ * Contains a notebook holding the real option panels as pages. Handles "apply" and "restore" events for those pages,
+ * rather then those having to implement (and duplicate) this functionality. \n
+ * See SpringOptionsTab, TorrentOptionsPanel, ChatOptionsTab
+ */
+class MainOptionsTab : public wxScrolledWindow
+{
+ public:
+ MainOptionsTab( wxWindow* parent, Ui& ui );
+ ~MainOptionsTab();
+
+ /** \brief delegate the data setting to memeber panels */
+ void OnApply( wxCommandEvent& event );
+ void OnRestore( wxCommandEvent& event );
+
+ void OnOpenGroupsTab();
+ void SetSelection( const unsigned int page );
+ GroupOptionsPanel& GetGroupOptionsPanel();
+
+
+ protected:
+ wxBoxSizer* m_main_sizer;
+
+ wxImageList* m_imagelist;
+
+ SLNotebook* m_tabs;
+
+ SpringOptionsTab* m_spring_opts;
+ ChatOptionsTab* m_chat_opts;
+ TorrentOptionsPanel* m_torrent_opts;
+ GroupOptionsPanel* m_groups_opts;
+ LobbyOptionsTab* m_lobby_opts;
+
+ wxButton* m_restore_btn;
+ wxButton* m_apply_btn;
+
+ wxBoxSizer* m_button_sizer;
+
+ Ui& m_ui;
+
+ enum {
+ OPTIONS_TABS = wxID_HIGHEST,
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_MAINOPTIONSTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mainsingleplayertab.cpp b/src/mainsingleplayertab.cpp
new file mode 100644
index 0000000..7a5a8b1
--- /dev/null
+++ b/src/mainsingleplayertab.cpp
@@ -0,0 +1,160 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include <wx/intl.h>
+#include <wx/window.h>
+#include <wx/sizer.h>
+#include <wx/imaglist.h>
+#include <wx/icon.h>
+#include <wx/log.h>
+
+#include <stdexcept>
+
+#include "aui/auimanager.h"
+#include "aui/artprovider.h"
+#include "aui/slbook.h"
+#include "singleplayertab.h"
+#include "battleoptionstab.h"
+#include "mainsingleplayertab.h"
+#include "battleroommmoptionstab.h"
+#include "ui.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+
+#include "images/battle.xpm"
+#include "images/battle_settings.xpm"
+
+
+MainSinglePlayerTab::MainSinglePlayerTab( wxWindow* parent, Ui& ui )
+ : wxScrolledWindow( parent, -1 ),
+ m_ui( ui )
+{
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+ GetAui().manager->AddPane( this, wxLEFT, _T( "mainsingleplayertab" ) );
+ m_tabs = new SLNotebook( this, -1, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_TOP | wxAUI_NB_TAB_EXTERNAL_MOVE );
+ m_tabs->SetArtProvider( new SLArtProvider );
+
+ m_imagelist = new wxImageList( 12, 12 );
+ m_imagelist->Add( wxIcon( battle_xpm ) );
+ m_imagelist->Add( wxIcon( battle_settings_xpm ) );
+
+ m_sp_tab = new SinglePlayerTab( m_tabs, m_ui, *this );
+ m_tabs->AddPage( m_sp_tab, _( "Game" ), true, 0 );
+ m_mm_opts_tab = new BattleroomMMOptionsTab<SinglePlayerBattle>( m_sp_tab->GetBattle(), m_tabs );
+ m_tabs->InsertPage( 1, m_mm_opts_tab, _( "Options" ), false, wxIcon( battle_settings_xpm ) );
+ m_opts_tab = new BattleOptionsTab( m_tabs, m_ui, m_sp_tab->GetBattle() );
+ m_tabs->InsertPage( 2, m_opts_tab, _( "Unit Restrictions" ), false, wxIcon( battle_settings_xpm ) );
+
+ m_main_sizer->Add( m_tabs, 1, wxEXPAND );
+
+ SetScrollRate( 3, 3 );
+ SetSizer( m_main_sizer );
+ Layout();
+}
+
+
+MainSinglePlayerTab::~MainSinglePlayerTab()
+{
+
+}
+
+
+void MainSinglePlayerTab::UpdateMinimap()
+{
+ try
+ {
+ GetSinglePlayerTab().UpdateMinimap();
+ } catch ( ... ) {}
+}
+
+
+void MainSinglePlayerTab::OnUnitSyncReloaded()
+{
+ wxLogDebugFunc( _T( "" ) );
+ try
+ {
+ GetSinglePlayerTab().ResetUsername();
+ wxLogMessage( _T( "Reloading map list" ) );
+ GetSinglePlayerTab().ReloadMaplist();
+ wxLogMessage( _T( "Reloading mod list" ) );
+ GetSinglePlayerTab().ReloadModlist();
+ wxLogMessage( _T( "Reloading minimap" ) );
+ GetSinglePlayerTab().UpdateMinimap();
+ } catch ( ... ) {}
+
+}
+
+
+void MainSinglePlayerTab::ReloadRestrictions()
+{
+ try
+ {
+ GetOptionsTab().ReloadRestrictions();
+ } catch ( ... ) {}
+}
+
+
+void MainSinglePlayerTab::ReloadMapOptContrls()
+{
+ try
+ {
+ GetMMOptionsTab().OnReloadControls( OptionsWrapper::MapOption );
+ } catch ( ... ) {}
+}
+
+
+void MainSinglePlayerTab::ReloadModOptContrls()
+{
+ try
+ {
+ GetMMOptionsTab().OnReloadControls( OptionsWrapper::ModOption );
+ } catch ( ... ) {}
+
+}
+
+SinglePlayerTab& MainSinglePlayerTab::GetSinglePlayerTab()
+{
+ ASSERT_EXCEPTION( m_sp_tab, _T( "m_sp_tab == 0" ) );
+ return *m_sp_tab;
+}
+
+BattleOptionsTab& MainSinglePlayerTab::GetOptionsTab()
+{
+ ASSERT_EXCEPTION( m_opts_tab, _T( "m_opts_tab == 0" ) );
+ return *m_opts_tab;
+}
+
+
+BattleroomMMOptionsTab<SinglePlayerBattle>& MainSinglePlayerTab::GetMMOptionsTab()
+{
+ ASSERT_EXCEPTION( m_mm_opts_tab, _T( "m_mm_opts_tab == 0" ) );
+ return *m_mm_opts_tab;
+}
+
+
+void MainSinglePlayerTab::ReloadPresetList()
+{
+ try
+ {
+ GetSinglePlayerTab().UpdatePresetList();
+ } catch ( ... ) {}
+ try
+ {
+ GetMMOptionsTab().UpdatePresetList();
+ } catch ( ... ) {}
+}
+
+
+void MainSinglePlayerTab::Update( const wxString& Tag )
+{
+
+ try
+ {
+ GetSinglePlayerTab().Update( Tag );
+ } catch ( ... ) {}
+
+ try
+ {
+ GetOptionsTab().UpdateBattle( Tag );
+ } catch ( ... ) {}
+
+}
diff --git a/src/mainsingleplayertab.h b/src/mainsingleplayertab.h
new file mode 100644
index 0000000..501dae2
--- /dev/null
+++ b/src/mainsingleplayertab.h
@@ -0,0 +1,66 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MAINSINGLEPLAYERTAB_H
+#define SPRINGLOBBY_HEADERGUARD_MAINSINGLEPLAYERTAB_H
+
+#include <wx/scrolwin.h>
+#include "battleroommmoptionstab.h"
+
+class Ui;
+class SLNotebook;
+class wxImageList;
+class wxBoxSizer;
+class SinglePlayerTab;
+class BattleOptionsTab;
+
+class MainSinglePlayerTab : public wxScrolledWindow
+{
+ public:
+ MainSinglePlayerTab( wxWindow* parent, Ui& ui );
+ ~MainSinglePlayerTab();
+
+ void UpdateMinimap();
+ void OnUnitSyncReloaded();
+ void Update( const wxString& Tag );
+
+ void ReloadRestrictions();
+ void ReloadMapOptContrls();
+ void ReloadModOptContrls();
+ void ReloadPresetList();
+
+ SinglePlayerTab& GetSinglePlayerTab();
+ BattleOptionsTab& GetOptionsTab();
+ BattleroomMMOptionsTab<SinglePlayerBattle>& GetMMOptionsTab();
+
+ protected:
+
+ Ui& m_ui;
+
+ wxBoxSizer* m_main_sizer;
+ wxImageList* m_imagelist;
+ SLNotebook* m_tabs;
+
+ SinglePlayerTab* m_sp_tab;
+ BattleOptionsTab* m_opts_tab;
+ BattleroomMMOptionsTab<SinglePlayerBattle>* m_mm_opts_tab;
+
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_MAINSINGLEPLAYERTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/maintorrenttab.cpp b/src/maintorrenttab.cpp
new file mode 100644
index 0000000..86d9e78
--- /dev/null
+++ b/src/maintorrenttab.cpp
@@ -0,0 +1,248 @@
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include "maintorrenttab.h"
+
+#ifndef NO_TORRENT_SYSTEM
+
+#include <wx/intl.h>
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/button.h>
+#include <wx/msgdlg.h>
+
+#include "torrentlistctrl.h"
+#include "torrentwrapper.h"
+#include "ui.h"
+#include "utils/conversion.h"
+#include "Helper/colorbutton.h"
+#include "filelister/filelistdialog.h"
+#include "widgets/downloaddialog.h"
+#include "aui/auimanager.h"
+
+BEGIN_EVENT_TABLE( MainTorrentTab, wxPanel )
+ //(*EventTable(MainTorrentTab)
+ //*)
+ EVT_BUTTON ( ID_BUTTON_CANCEL, MainTorrentTab::OnCancelButton )
+ EVT_BUTTON ( ID_DOWNLOAD_DIALOG, MainTorrentTab::OnDownloadDialog )
+ EVT_BUTTON ( ID_BUTTON_WIDGETS, MainTorrentTab::OnDLWidgets )
+
+END_EVENT_TABLE()
+
+MainTorrentTab::MainTorrentTab( wxWindow* parent, Ui& ui )
+ : wxScrolledWindow( parent ),
+ m_widgets_dialog( NULL ),
+ m_ui( ui )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T( "maintorrenttab" ) );
+
+ m_mainbox = new wxBoxSizer ( wxVERTICAL );
+
+ wxBoxSizer* m_listbox = new wxBoxSizer ( wxVERTICAL );
+ wxBoxSizer* m_totalbox = new wxBoxSizer ( wxHORIZONTAL );
+ wxBoxSizer* m_buttonbox = new wxBoxSizer ( wxHORIZONTAL );
+ wxBoxSizer* m_status_box = new wxBoxSizer( wxHORIZONTAL );
+ wxBoxSizer* m_firstrow_box = new wxBoxSizer( wxHORIZONTAL );
+
+ wxStaticText* m_list_lbl = new wxStaticText( this, ID_OUTGOING_LBL, _( "Transfers in progress: " ) );
+ m_listbox->Add( m_list_lbl, 0, wxALL, 5 );
+ m_torrent_list = new TorrentListCtrl( this, m_ui );
+ m_listbox->Add( m_torrent_list, 2, wxALL | wxEXPAND | wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_mainbox->Add( m_listbox, 2, wxALL | wxEXPAND | wxALIGN_CENTER_HORIZONTAL, 0 );
+
+ m_outgoing_lbl = new wxStaticText( this, ID_OUTGOING_LBL, _( "Total Outgoing: " ) );
+ m_incoming_lbl = new wxStaticText( this, ID_INCOMING_LBL, _( "Total Incoming: " ) );
+ m_totalbox->Add( m_outgoing_lbl, 1, wxALL | wxALIGN_CENTER_HORIZONTAL, 10 );
+ m_totalbox->Add( m_incoming_lbl, 1, wxALL | wxALIGN_CENTER_HORIZONTAL, 10 );
+
+ m_firstrow_box->Add( m_totalbox, 0, wxALL, 5 );
+
+ m_status_color = new ColorButton( this, wxID_ANY, wxBitmap(), wxDefaultPosition, wxSize( 20, 20 ), 0 );
+ m_status_color_text = new wxStaticText( this, wxID_ANY, _( "unknown" ) );
+ m_status_box->Add( m_status_color , 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 10 );
+ m_status_box->Add( m_status_color_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 10 );
+ m_firstrow_box->Add( m_status_box, 1, wxALL, 5 );
+
+ m_mainbox->Add( m_firstrow_box, 0, wxALL, 5 );
+
+ m_but_cancel = new wxButton( this, ID_BUTTON_CANCEL, _( "Cancel Download" ) );
+ //m_but_cancel->Disable();
+ m_buttonbox->Add( m_but_cancel, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM, 5 );
+ m_but_publish = new wxButton( this, ID_BUTTON_PUB, _( "Publish new file" ) );
+ m_buttonbox->Add( m_but_publish, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM, 5 );
+ m_but_download = new wxButton( this, ID_DOWNLOAD_DIALOG, _( "Search file" ) );
+ m_buttonbox->Add( m_but_download, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM, 5 );
+ m_but_widgets = new wxButton( this, ID_BUTTON_WIDGETS, _( "Download Lua widgets" ) );
+ m_buttonbox->Add( m_but_widgets, 1, wxALL | wxALIGN_RIGHT | wxALIGN_BOTTOM, 5 );
+
+ m_mainbox->Add( m_buttonbox, 0, wxALL, 5 );
+
+ SetSizer( m_mainbox );
+ m_mainbox->SetSizeHints( this );
+ Layout();
+
+ info_map = torrent().CollectGuiInfos();
+ m_torrent_list->SetInfoMap( &info_map );
+// m_torrent_list->SetSizeHints(this);
+ m_torrent_list->Layout();
+
+ for ( map_infos_iter iter = info_map.begin(); iter != info_map.end(); ++iter )
+ {
+ AddTorrentInfo( iter->second );
+ }
+ m_download_dialog = 0;
+}
+
+MainTorrentTab::~MainTorrentTab()
+{
+ if ( m_download_dialog )
+ {
+ delete m_download_dialog;
+ m_download_dialog = 0;
+ }
+}
+
+void MainTorrentTab::OnDLWidgets( wxCommandEvent& /*unused*/ )
+{
+ if ( m_widgets_dialog && m_widgets_dialog->IsShown() ) {
+ m_widgets_dialog->SetFocus();
+ }
+ else {
+ m_widgets_dialog = new WidgetDownloadDialog( this, wxID_ANY, _( "Lua widget downloader" ) );
+ m_widgets_dialog->Show( true );
+ }
+}
+
+void MainTorrentTab::UpdateInfo( TorrentInfos& info )
+{
+ int index = -1;
+ for ( int i = 0; i < m_torrent_list->GetItemCount() ; i++ ) {
+ if ( info.hash == TowxString( ( int )m_torrent_list->GetItemData( i ) ) ) {
+ index = i;
+ break;
+ }
+ }
+
+ //ASSERT_LOGIC( index != -1, _T("index = -1") );
+ if ( index > 0 ) {
+ SetInfo( index, info );
+ }
+ else {
+ AddTorrentInfo( info );
+ }
+}
+
+void MainTorrentTab::SetInfo( int index, TorrentInfos& info )
+{
+
+ float kfactor = 1 / float( 1024 );
+ float mfactor = 1 / float( 1024 * 1024 );
+
+ int eta_seconds = -1;
+ if ( info.progress > 0 && info.inspeed > 0 )
+ eta_seconds = int ( ( info.filesize - info.downloaded ) / info.inspeed );
+
+ info.eta = eta_seconds;
+
+// m_torrent_list->SetItemImage( index, icons().GetBattleStatusIcon( battle ) );
+ m_torrent_list->SetItem( index, 0, info.name );
+ m_torrent_list->SetItem( index, 1, info.numcopies > 0 ? TowxString( info.numcopies ) : wxString( _( "not available" ) ) );
+ m_torrent_list->SetItem( index, 2, TowxString( info.downloaded*mfactor ) );
+ m_torrent_list->SetItem( index, 3, TowxString( info.uploaded*mfactor ) );
+ if ( info.downloadstatus == P2P::seeding ) m_torrent_list->SetItem( index, 4, _( "seeding" ) );
+ else if ( info.downloadstatus == P2P::leeching ) m_torrent_list->SetItem( index, 4, _( "leeching" ) );
+ else if ( info.downloadstatus == P2P::queued ) m_torrent_list->SetItem( index, 4, _( "queued" ) );
+ m_torrent_list->SetItem( index, 5, TowxString( info.progress * 100 ) );
+ m_torrent_list->SetItem( index, 6, TowxString( info.outspeed*kfactor ) );
+ m_torrent_list->SetItem( index, 7, TowxString( info.inspeed*kfactor ) );
+ m_torrent_list->SetItem( index, 8, ( eta_seconds > -1 ? TowxString( eta_seconds ) : _T( "inf." ) ) + _T( " s" ) );
+ m_torrent_list->SetItem( index, 9, wxString::Format( _T( "%.3f" ), info.filesize*mfactor ) );
+
+ m_torrent_list->Sort();
+}
+
+void MainTorrentTab::AddTorrentInfo( TorrentInfos& info )
+{
+ int index = m_torrent_list->InsertItem( m_torrent_list->GetItemCount(), info.name );
+
+// ASSERT_LOGIC( index != -1, _T("index = -1") );
+ m_torrent_list->SetItemData( index, FromwxString<long>( info.hash ) );
+
+
+ //ASSERT_LOGIC( index != -1, _T("index = -1") );
+
+// ASSERT_LOGIC( m_torrent_list->GetItem( item ), _T("!GetItem") );
+
+ SetInfo( index, info );
+
+}
+
+void MainTorrentTab::OnUpdate()
+{
+
+ if ( torrent().IsConnectedToP2PSystem() )
+ {
+ m_but_cancel->Enable();
+ m_but_publish->Enable();
+ m_but_download->Enable();
+ }
+ else
+ {
+ m_but_cancel->Disable();
+ m_but_publish->Disable();
+ m_but_download->Disable();
+ }
+
+ switch ( torrent().GetTorrentSystemStatus() )
+ {
+ case 0:
+ m_status_color->SetColor( wxColour( 255, 0, 0 ) ); //not connected
+ m_status_color_text->SetLabel( _( "Status: not connected" ) );
+ break;
+ case 1:
+ m_status_color->SetColor( wxColour( 0, 255, 0 ) ); //connected
+ m_status_color_text->SetLabel( _( "Status: connected" ) );
+ break;
+ case 2:
+ m_status_color->SetColor( wxColour( 0, 0, 255 ) ); //ingame
+ m_status_color_text->SetLabel( _( "Status: throttled or paused (ingame)" ) );
+ break;
+ default:
+ m_status_color->SetColor( wxColour( 255, 255, 255 ) ); //unknown
+ m_status_color_text->SetLabel( _( "Status: unknown" ) );
+ break;
+ }
+
+ m_torrent_list->SetSelectionRestorePoint();
+ info_map = torrent().CollectGuiInfos();
+ m_outgoing_lbl->SetLabel( wxString::Format( _( "Total Outgoing: %.2f KB/s" ), ( info_map[0].outspeed / float( 1024 ) ) ) );
+ m_incoming_lbl->SetLabel( wxString::Format( _( "Total Incoming: %.2f KB/s" ), ( info_map[0].inspeed / float( 1024 ) ) ) );
+ m_torrent_list->DeleteAllItems();
+ for ( map_infos_iter iter = info_map.begin(); iter != info_map.end(); ++iter )
+ {
+ if ( iter->first == 0 ) continue; //skip global torrent stats
+ AddTorrentInfo( iter->second );
+
+ }
+ Layout();
+ m_torrent_list->RestoreSelection();
+
+}
+
+
+void MainTorrentTab::OnCancelButton( wxCommandEvent& /*unused*/ )
+{
+ torrent().RemoveTorrentByHash( TowxString( m_torrent_list->GetSelectedData() ) );
+}
+
+void MainTorrentTab::OnDownloadDialog( wxCommandEvent& /*unused*/ )
+{
+ m_download_dialog = new FileListDialog( this );
+ m_download_dialog->Show();
+}
+
+#endif
diff --git a/src/maintorrenttab.h b/src/maintorrenttab.h
new file mode 100644
index 0000000..d461a64
--- /dev/null
+++ b/src/maintorrenttab.h
@@ -0,0 +1,101 @@
+#ifndef MAINTORRENTTAB_H
+#define MAINTORRENTTAB_H
+
+#ifndef NO_TORRENT_SYSTEM
+
+#include <wx/scrolwin.h>
+#include <map>
+
+class wxStaticText;
+class wxButton;
+class TorrentListCtrl;
+class Ui;
+struct TorrentInfos;
+class wxBoxSizer;
+class FileListDialog;
+class ColorButton;
+class WidgetDownloadDialog;
+
+typedef std::map<int,TorrentInfos> map_infos;
+typedef map_infos::iterator map_infos_iter;
+
+class MainTorrentTab: public wxScrolledWindow
+{
+ public:
+
+ MainTorrentTab(wxWindow* parent,Ui& ui);
+ ~MainTorrentTab();
+
+ wxStaticText* m_incoming;
+ wxStaticText* m_outgoing;
+ wxStaticText* m_incoming_lbl;
+ wxStaticText* m_outgoing_lbl;
+ wxStaticText* m_status_color_text;
+
+ wxButton* m_but_cancel;
+ wxButton* m_but_publish;
+ wxButton* m_but_download;
+ wxButton* m_but_widgets;
+ ColorButton* m_status_color;
+ TorrentListCtrl* m_torrent_list;
+ WidgetDownloadDialog* m_widgets_dialog;
+
+ Ui& m_ui;
+ void OnUpdate();
+
+ protected:
+
+ enum
+ {
+ ID_LIST = wxID_HIGHEST,
+ ID_BUTTON_CANCEL,
+ ID_BUTTON_PUB,
+ ID_OUTGOING,
+ ID_INCOMING,
+ ID_OUTGOING_LBL,
+ ID_INCOMING_LBL,
+ ID_DOWNLOAD_DIALOG,
+ ID_BUTTON_WIDGETS
+
+ };
+
+ map_infos info_map;
+ void AddTorrentInfo( TorrentInfos& info );
+ void UpdateInfo( TorrentInfos& info );
+ void SetInfo(int index, TorrentInfos& info );
+ void OnCancelButton( wxCommandEvent& event );
+ void OnDownloadDialog( wxCommandEvent& event );
+ void OnDLWidgets( wxCommandEvent& event );
+
+ wxBoxSizer* m_mainbox;
+ FileListDialog* m_download_dialog;
+
+ private:
+
+ //(*Handlers(MainTorrentTab)
+ //*)
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
+
+#endif
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
new file mode 100644
index 0000000..b0acbaa
--- /dev/null
+++ b/src/mainwindow.cpp
@@ -0,0 +1,686 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+//
+// Class: MainWindow
+//
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/frame.h>
+#include <wx/intl.h>
+#include <wx/textdlg.h>
+#include <wx/imaglist.h>
+#include <wx/image.h>
+#include <wx/icon.h>
+#include <wx/sizer.h>
+#include <wx/menu.h>
+#include <wx/log.h>
+#include <wx/dcmemory.h>
+#include <wx/choicdlg.h>
+#include <wx/aui/auibook.h>
+#include <wx/tooltip.h>
+#include <wx/aboutdlg.h>
+
+#include <stdexcept>
+#include <iostream>
+
+#include "aui/auimanager.h"
+#include "aui/slbook.h"
+#include "aui/artprovider.h"
+#include "springlobbyapp.h"
+#include "mainwindow.h"
+#include "settings.h"
+#include "ui.h"
+#include "server.h"
+#include "utils/debug.h"
+#include "utils/platform.h"
+#include "battlelisttab.h"
+#include "mainchattab.h"
+#include "mainjoinbattletab.h"
+#include "mainsingleplayertab.h"
+#include "mainoptionstab.h"
+#include "iunitsync.h"
+#include "uiutils.h"
+#include "chatpanel.h"
+#include "playback/playbacktraits.h"
+#include "playback/playbacktab.h"
+#ifndef NO_TORRENT_SYSTEM
+ #include "maintorrenttab.h"
+ #include "torrentwrapper.h"
+#endif
+#include "user.h"
+
+
+#include "images/springlobby.xpm"
+#include "images/chat_icon.png.h"
+#include "images/chat_icon_text.png.h"
+#include "images/join_icon.png.h"
+#include "images/join_icon_text.png.h"
+#include "images/single_player_icon.png.h"
+#include "images/single_player_icon_text.png.h"
+#include "images/options_icon.png.h"
+#include "images/options_icon_text.png.h"
+#include "images/downloads_icon.png.h"
+#include "images/downloads_icon_text.png.h"
+#include "images/replay_icon.png.h"
+#include "images/replay_icon_text.png.h"
+#include "images/floppy_icon.png.h"
+
+#include "settings++/frame.h"
+#include "settings++/custom_dialogs.h"
+
+#include "updater/updater.h"
+#include "channel/autojoinchanneldialog.h"
+#include "channel/channelchooserdialog.h"
+#include "Helper/imageviewer.h"
+
+#if defined(__WXMSW__)
+ #include <wx/msw/winundef.h>
+#endif
+#include <wx/aboutdlg.h>
+
+BEGIN_EVENT_TABLE(MainWindow, wxFrame)
+
+ EVT_MENU( MENU_JOIN, MainWindow::OnMenuJoin )
+ EVT_MENU( MENU_CHAT, MainWindow::OnMenuChat )
+ EVT_MENU( MENU_CONNECT, MainWindow::OnMenuConnect )
+ EVT_MENU( MENU_DISCONNECT, MainWindow::OnMenuDisconnect )
+ EVT_MENU( MENU_SAVE_OPTIONS, MainWindow::OnMenuSaveOptions )
+ EVT_MENU( MENU_QUIT, MainWindow::OnMenuQuit )
+ EVT_MENU( MENU_USYNC, MainWindow::OnUnitSyncReload )
+ EVT_MENU( MENU_TRAC, MainWindow::OnReportBug )
+ EVT_MENU( MENU_DOC, MainWindow::OnShowDocs )
+ EVT_MENU( MENU_SETTINGSPP, MainWindow::OnShowSettingsPP )
+ EVT_MENU( MENU_VERSION, MainWindow::OnMenuVersion )
+ EVT_MENU( MENU_ABOUT, MainWindow::OnMenuAbout )
+ EVT_MENU( MENU_START_TORRENT, MainWindow::OnMenuStartTorrent )
+ EVT_MENU( MENU_STOP_TORRENT, MainWindow::OnMenuStopTorrent )
+ EVT_MENU( MENU_SAVE_LAYOUT, MainWindow::OnMenuSaveLayout )
+ EVT_MENU( MENU_LOAD_LAYOUT, MainWindow::OnMenuLoadLayout )
+ EVT_MENU( MENU_DEFAULT_LAYOUT, MainWindow::OnMenuDefaultLayout )
+// EVT_MENU( MENU_SHOW_TOOLTIPS, MainWindow::OnShowToolTips )
+ EVT_MENU( MENU_AUTOJOIN_CHANNELS, MainWindow::OnMenuAutojoinChannels )
+ EVT_MENU( MENU_SELECT_LOCALE, MainWindow::OnMenuSelectLocale )
+ EVT_MENU( MENU_CHANNELCHOOSER, MainWindow::OnShowChannelChooser )
+ EVT_MENU( MENU_SCREENSHOTS, MainWindow::OnShowScreenshots )
+ EVT_MENU_OPEN( MainWindow::OnMenuOpen )
+ EVT_AUINOTEBOOK_PAGE_CHANGED( MAIN_TABS, MainWindow::OnTabsChanged )
+ EVT_CLOSE( MainWindow::OnClose )
+END_EVENT_TABLE()
+
+MainWindow::TabNames MainWindow::m_tab_names;
+
+MainWindow::MainWindow( Ui& ui )
+ : wxFrame( (wxFrame*)0, -1, _("SpringLobby"), wxPoint(50, 50), wxSize(450, 340) ),
+ m_ui(ui),
+ m_autojoin_dialog(NULL),
+ m_channel_chooser(NULL),
+ m_log_win(NULL)
+{
+ SetIcon( wxIcon(springlobby_xpm) );
+
+ GetAui().manager = new AuiManagerContainer::ManagerType( this );
+
+ wxMenu *menuFile = new wxMenu;
+ menuFile->Append(MENU_CONNECT, _("&Connect..."));
+ menuFile->Append(MENU_DISCONNECT, _("&Disconnect"));
+ menuFile->AppendSeparator();
+#ifndef NDEBUG
+ menuFile->Append(MENU_SAVE_OPTIONS, _("&Save options"));
+ menuFile->AppendSeparator();
+#endif
+ menuFile->Append(MENU_QUIT, _("&Quit"));
+
+ //m_menuEdit = new wxMenu;
+ //TODO doesn't work atm
+
+
+ /* loading layouts currently borked
+ wxMenu* menuView = new wxMenu;
+ menuView->Append( MENU_SAVE_LAYOUT, _("&Save Layout") );
+ menuView->Append( MENU_LOAD_LAYOUT, _("&Load layout") );
+ menuView->Append( MENU_DEFAULT_LAYOUT, _("&Set &Laoyut as default") );
+ */
+
+ m_menuTools = new wxMenu;
+ m_menuTools->Append(MENU_JOIN, _("&Join channel..."));
+ m_menuTools->Append(MENU_CHANNELCHOOSER, _("Channel &list"));
+ m_menuTools->Append(MENU_CHAT, _("Open private &chat..."));
+ m_menuTools->Append(MENU_AUTOJOIN_CHANNELS, _("&Autojoin channels..."));
+ m_menuTools->Append(MENU_SCREENSHOTS, _("&View screenshots"));
+ m_menuTools->AppendSeparator();
+ m_menuTools->Append(MENU_USYNC, _("&Reload maps/mods"));
+
+
+ #ifndef NO_TORRENT_SYSTEM
+ m_menuTools->AppendSeparator();
+ #endif
+ m_menuTools->Append(MENU_VERSION, _("Check for new Version"));
+ m_settings_menu = new wxMenuItem( m_menuTools, MENU_SETTINGSPP, _("SpringSettings"), wxEmptyString, wxITEM_NORMAL );
+ m_menuTools->Append (m_settings_menu);
+
+ wxMenu *menuHelp = new wxMenu;
+ menuHelp->Append(MENU_ABOUT, _("&About"));
+ menuHelp->Append(MENU_SELECT_LOCALE, _("&Change language"));
+ menuHelp->Append(MENU_TRAC, _("&Report a bug..."));
+ menuHelp->Append(MENU_DOC, _("&Documentation"));
+
+ m_menubar = new wxMenuBar;
+ m_menubar->Append(menuFile, _("&File"));
+ //m_menubar->Append(m_menuEdit, _("&Edit"));
+
+ //m_menubar->Append(menuView, _("&View")); //layout stuff --> disabled
+
+ m_menubar->Append(m_menuTools, _("&Tools"));
+ m_menubar->Append(menuHelp, _("&Help"));
+ SetMenuBar(m_menubar);
+
+ m_main_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_func_tabs = new SLNotebook( this, MAIN_TABS, wxDefaultPosition, wxDefaultSize,
+ wxAUI_NB_WINDOWLIST_BUTTON | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_LEFT );
+ m_func_tabs->SetArtProvider(new SLArtProvider);
+
+
+ m_chat_tab = new MainChatTab( m_func_tabs, m_ui );
+ m_join_tab = new MainJoinBattleTab( m_func_tabs, m_ui );
+ m_sp_tab = new MainSinglePlayerTab( m_func_tabs, m_ui );
+ m_replay_tab = new ReplayTab ( m_func_tabs, m_ui );
+ m_savegame_tab = new SavegameTab( m_func_tabs, m_ui );
+#ifndef NO_TORRENT_SYSTEM
+ m_torrent_tab = new MainTorrentTab( m_func_tabs, m_ui);
+#endif
+ m_opts_tab = new MainOptionsTab( m_func_tabs, m_ui );
+
+ m_func_tabs->AddPage( m_chat_tab, m_tab_names[0], true );
+ m_func_tabs->AddPage( m_join_tab, m_tab_names[1], false );
+ m_func_tabs->AddPage( m_sp_tab, m_tab_names[2], false );
+ m_func_tabs->AddPage( m_savegame_tab, m_tab_names[3], false );
+ m_func_tabs->AddPage( m_replay_tab, m_tab_names[4], false );
+#ifndef NO_TORRENT_SYSTEM
+ m_func_tabs->AddPage( m_torrent_tab, m_tab_names[5], false );
+ m_func_tabs->AddPage( m_opts_tab, m_tab_names[6], false );
+#else
+ m_func_tabs->AddPage( m_opts_tab, m_tab_names[5], false );
+#endif
+
+
+
+ SetTabIcons();
+ m_main_sizer->Add( m_func_tabs, 1, wxEXPAND | wxALL, 0 );
+
+ SetSizer( m_main_sizer );
+ wxString name = _T("MAINWINDOW");
+ wxPoint pos = sett().GetWindowPos( name, wxPoint( DEFSETT_MW_LEFT, DEFSETT_MW_TOP ) );
+ wxSize size = sett().GetWindowSize( name, wxSize( DEFSETT_MW_WIDTH, DEFSETT_MW_HEIGHT ) );
+ SetSize( pos.x , pos.y, size.GetWidth(), size.GetHeight() );
+ Layout();
+
+ se_frame_active = false;
+
+ wxToolTip::Enable(sett().GetShowTooltips());
+
+ m_channel_chooser = new ChannelChooserDialog( this, -1, _("Choose channels to join") );
+
+}
+
+wxBitmap MainWindow::GetTabIcon( const unsigned char* data, size_t size )
+{
+ if ( sett().GetUseTabIcons() )
+ return charArr2wxBitmap( data , size );
+ else
+ return wxNullBitmap;
+}
+
+void MainWindow::SetTabIcons()
+{
+ unsigned int count = 0;
+ m_func_tabs->SetPageBitmap( count++, GetTabIcon( chat_icon_png, sizeof(chat_icon_png) ) );
+ m_func_tabs->SetPageBitmap( count++, GetTabIcon( join_icon_png, sizeof(join_icon_png) ) );
+ m_func_tabs->SetPageBitmap( count++, GetTabIcon( single_player_icon_png , sizeof (single_player_icon_png) ) );
+ m_func_tabs->SetPageBitmap( count++, GetTabIcon( floppy_icon_png , sizeof (floppy_icon_png) ) );
+ m_func_tabs->SetPageBitmap( count++, GetTabIcon( replay_icon_png , sizeof (replay_icon_png) ) );
+#ifndef NO_TORRENT_SYSTEM
+ m_func_tabs->SetPageBitmap( count++, GetTabIcon( downloads_icon_png , sizeof (downloads_icon_png) ) );
+#endif
+ m_func_tabs->SetPageBitmap( count++, GetTabIcon( options_icon_png , sizeof (options_icon_png) ) );
+ Refresh();
+}
+
+void MainWindow::forceSettingsFrameClose()
+{
+ if (se_frame_active && se_frame != 0)
+ se_frame->handleExternExit();
+}
+
+void MainWindow::SetLogWin( wxLogWindow* log, wxLogChain* logchain )
+{
+ m_log_win = log;
+ m_log_chain = logchain;
+ if ( m_log_win )
+ m_log_win->GetFrame()->SetParent( this );
+}
+
+MainWindow::~MainWindow()
+{
+}
+
+void MainWindow::OnClose( wxCloseEvent& /*unused*/ )
+{
+ AuiManagerContainer::ManagerType* manager=GetAui().manager;
+ if(manager){
+ GetAui().manager=NULL;
+ manager->UnInit();
+ delete manager;
+ }
+
+ wxString name = _T("MAINWINDOW");
+ sett().SetWindowSize( name, GetSize() );
+ sett().SetWindowPos( name, GetPosition() );
+
+ m_ui.Quit();
+ m_ui.OnMainWindowDestruct();
+ forceSettingsFrameClose();
+ freeStaticBox();
+
+ if ( m_autojoin_dialog != 0 )
+ {
+ delete m_autojoin_dialog;
+ m_autojoin_dialog = 0;
+ }
+
+ sett().SaveSettings();
+ if ( m_log_win ) {
+ m_log_win->GetFrame()->Destroy();
+ if ( m_log_chain ) // if logwin was created, it's the current "top" log
+ m_log_chain->DetachOldLog(); //so we need to tellwx not to delete it on its own
+ //since we absolutely need to destroy the logwin here, set a fallback for the time until app cleanup
+#if(wxUSE_STD_IOSTREAM)
+ wxLog::SetActiveTarget( new wxLogStream( &std::cout ) );
+#endif
+ }
+
+ Destroy();
+
+}
+
+void DrawBmpOnBmp( wxBitmap& canvas, wxBitmap& object, int x, int y )
+{
+ wxMemoryDC dc;
+ dc.SelectObject( canvas );
+ dc.DrawBitmap( object, x, y, true );
+ dc.SelectObject( wxNullBitmap );
+}
+
+//void MainWindow::DrawTxtOnBmp( wxBitmap& canvas, wxString text, int x, int y )
+//{
+// wxMemoryDC dc;
+// dc.SelectObject( canvas );
+//
+// dc.DrawText( text, x, y);
+// dc.SelectObject( wxNullBitmap );
+//}
+
+
+/*
+//! @brief Get the ChatPanel dedicated to server output and input
+ChatPanel& servwin()
+{
+ return m_ui.mw().GetChatTab().ServerChat();
+}
+*/
+
+//! @brief Returns the curent MainChatTab object
+MainChatTab& MainWindow::GetChatTab()
+{
+ ASSERT_EXCEPTION( m_chat_tab != 0, _T("m_chat_tab = 0") );
+ return *m_chat_tab;
+}
+
+MainJoinBattleTab& MainWindow::GetJoinTab()
+{
+ ASSERT_EXCEPTION( m_join_tab != 0, _T("m_join_tab = 0") );
+ return *m_join_tab;
+}
+
+
+MainSinglePlayerTab& MainWindow::GetSPTab()
+{
+ ASSERT_EXCEPTION( m_sp_tab != 0, _T("m_sp_tab = 0") );
+ return *m_sp_tab;
+}
+
+MainWindow::ReplayTab& MainWindow::GetReplayTab()
+{
+ ASSERT_EXCEPTION( m_replay_tab != 0, _T("m_replay_tab = 0") );
+ return *m_replay_tab;
+}
+
+MainWindow::SavegameTab& MainWindow::GetSavegameTab()
+{
+ ASSERT_EXCEPTION( m_replay_tab != 0, _T("m_replay_tab = 0") );
+ return *m_savegame_tab;
+}
+
+#ifndef NO_TORRENT_SYSTEM
+MainTorrentTab& MainWindow::GetTorrentTab()
+{
+ ASSERT_EXCEPTION( m_torrent_tab != 0, _T("m_torrent_tab = 0") );
+ return *m_torrent_tab ;
+}
+#endif
+ChatPanel* MainWindow::GetActiveChatPanel()
+{
+ unsigned int index = m_func_tabs->GetSelection();
+ if ( index == PAGE_CHAT ) return m_chat_tab->GetActiveChatPanel();
+ if ( index == PAGE_JOIN ) return m_join_tab->GetActiveChatPanel();
+ return 0;
+}
+
+
+ChatPanel* MainWindow::GetChannelChatPanel( const wxString& channel )
+{
+ return m_chat_tab->GetChannelChatPanel( channel );
+}
+
+MainOptionsTab& MainWindow::GetOptionsTab()
+{
+ ASSERT_EXCEPTION(m_opts_tab != 0, _T("m_opts_tab == 0"));
+ return *m_opts_tab;
+}
+
+//! @brief Open a new chat tab with a channel chat
+//!
+//! @param channel The channel name
+//! @note This does NOT join the chatt.
+//! @sa Server::JoinChannel OpenPrivateChat
+void MainWindow::OpenChannelChat( Channel& channel, bool doFocus )
+{
+ ASSERT_LOGIC( m_chat_tab != 0, _T("m_chat_tab") );
+ if ( doFocus )
+ m_func_tabs->SetSelection( PAGE_CHAT );
+ m_chat_tab->AddChatPanel( channel );
+}
+
+
+//! @brief Open a new chat tab with a private chat
+//!
+//! @param nick The user to whom the chatwindow should be opened to
+void MainWindow::OpenPrivateChat( const User& user, bool doFocus )
+{
+ ASSERT_LOGIC( m_chat_tab != 0, _T("m_chat_tab") );
+ m_func_tabs->SetSelection( PAGE_CHAT );
+ ChatPanel* cp = m_chat_tab->AddChatPanel( user );
+ if ( doFocus )
+ cp->FocusInputBox();
+
+}
+
+//! @brief Displays the lobby singleplayer tab.
+void MainWindow::ShowSingleplayer()
+{
+ ShowTab( PAGE_SINGLE );
+}
+
+void MainWindow::ShowTab( const int idx )
+{
+ if ( -1 < idx && idx <m_tab_names.GetCount() )
+ m_func_tabs->SetSelection( idx );
+ else
+ wxLogError( _T("tab selection oob: %d"), idx );
+}
+
+//! @brief Displays the lobby configuration.
+void MainWindow::ShowConfigure( const unsigned int page )
+{
+ m_func_tabs->SetSelection( PAGE_OPTOS );
+ //possibly out of bounds is captured by m_opts_tab itslef
+ m_opts_tab->SetSelection( page );
+}
+
+void MainWindow::ShowChannelChooser()
+{
+ if ( m_channel_chooser && m_channel_chooser->IsShown() )
+ return;
+
+ if ( !ui().IsConnected() )
+ customMessageBox( SL_MAIN_ICON, _("You need to be connected to server to view channel list"), _("Not connected") );
+ else {
+ m_channel_chooser->ClearChannels();
+ ui().GetServer().RequestChannels();
+ m_channel_chooser->Show( true );
+ }
+}
+
+//! @brief Called when join channel menuitem is clicked
+void MainWindow::OnMenuJoin( wxCommandEvent& /*unused*/ )
+{
+
+ if ( !m_ui.IsConnected() ) return;
+ wxString answer;
+ if ( m_ui.AskText( _("Join channel..."), _("Name of channel to join"), answer ) ) {
+ m_ui.JoinChannel( answer, _T("") );
+ }
+
+}
+
+
+void MainWindow::OnMenuChat( wxCommandEvent& /*unused*/ )
+{
+
+ if ( !m_ui.IsConnected() ) return;
+ wxString answer;
+ if ( m_ui.AskText( _("Open Private Chat..."), _("Name of user"), answer ) ) {
+ if (m_ui.GetServer().UserExists( answer ) ) {
+ //true puts focus on new tab
+ OpenPrivateChat( m_ui.GetServer().GetUser( answer ), true );
+ }
+ }
+
+}
+
+void MainWindow::OnMenuAbout( wxCommandEvent& /*unused*/ )
+{
+ wxAboutDialogInfo info;
+ info.SetName(_T("SpringLobby"));
+ info.SetVersion (GetSpringLobbyVersion());
+ info.SetDescription(_("SpringLobby is a cross-plattform lobby client for the RTS Spring engine"));
+ //info.SetCopyright(_T("");
+ info.SetLicence(_T("GPL"));
+ info.AddDeveloper(_T("BrainDamage"));
+ info.AddDeveloper(_T("dizekat"));
+ info.AddDeveloper(_T("insaneinside"));
+ info.AddDeveloper(_T("Kaot"));
+ info.AddDeveloper(_T("koshi"));
+ info.AddDeveloper(_T("semi_"));
+ info.AddDeveloper(_T("tc-"));
+ info.AddTranslator(_T("chaosch (simplified chinese)"));
+ info.AddTranslator(_T("lejocelyn (french)"));
+ info.AddTranslator(_T("Suprano (german)"));
+ info.AddTranslator(_T("tc- (swedish)"));
+ info.SetIcon(wxIcon(springlobby_xpm));
+ wxAboutBox(info);
+}
+
+void MainWindow::OnMenuConnect( wxCommandEvent& /*unused*/ )
+{
+ m_ui.ShowConnectWindow();
+}
+
+
+void MainWindow::OnMenuDisconnect( wxCommandEvent& /*unused*/ )
+{
+ m_ui.Disconnect();
+}
+
+void MainWindow::OnMenuSaveOptions( wxCommandEvent& /*unused*/ )
+{
+ sett().SaveSettings();
+}
+
+void MainWindow::OnMenuQuit( wxCommandEvent& /*unused*/ )
+{
+ Close();
+}
+
+
+void MainWindow::OnMenuVersion( wxCommandEvent& /*unused*/ )
+{
+ Updater().CheckForUpdates();
+}
+
+void MainWindow::OnUnitSyncReload( wxCommandEvent& /*unused*/ )
+{
+ m_ui.ReloadUnitSync();
+}
+
+void MainWindow::OnShowScreenshots( wxCommandEvent& /*unused*/ )
+{
+ wxSortedArrayString ar = usync().GetScreenshotFilenames();
+ if ( ar.Count() == 0 ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("There were no screenshots found in your spring data directory."), _("No files found") );
+ return;
+ }
+ ImageViewerDialog* img = new ImageViewerDialog( ar, true, this, -1, _T("Screenshots") );
+ img->Show( true );
+}
+
+void MainWindow::OnMenuStartTorrent( wxCommandEvent& /*unused*/ )
+{
+ #ifndef NO_TORRENT_SYSTEM
+ sett().SetTorrentSystemAutoStartMode( 2 ); // switch operation to manual mode
+ torrent().ConnectToP2PSystem();
+ #endif
+}
+
+
+void MainWindow::OnMenuStopTorrent( wxCommandEvent& /*unused*/ )
+{
+ #ifndef NO_TORRENT_SYSTEM
+ sett().SetTorrentSystemAutoStartMode( 2 ); // switch operation to manual mode
+ torrent().DisconnectFromP2PSystem();
+ #endif
+}
+
+
+void MainWindow::OnMenuOpen( wxMenuEvent& /*unused*/ )
+{
+ #ifndef NO_TORRENT_SYSTEM
+ m_menuTools->Delete(MENU_STOP_TORRENT);
+ m_menuTools->Delete(MENU_START_TORRENT);
+ if ( !torrent().IsConnectedToP2PSystem() )
+ {
+ m_menuTools->Insert( 5, MENU_START_TORRENT, _("Manually &Start Torrent System") );
+ }
+ else
+ {
+ m_menuTools->Insert( 5, MENU_STOP_TORRENT, _("Manually &Stop Torrent System") );
+ }
+ #endif
+}
+
+
+void MainWindow::OnReportBug( wxCommandEvent& /*unused*/ )
+{
+ wxString reporter = wxEmptyString;
+ if (m_ui.IsConnected() )
+ reporter = _T("?reporter=") + m_ui.GetServer().GetMe().GetNick();
+ m_ui.OpenWebBrowser( _T("http://trac.springlobby.info/newticket") + reporter);
+}
+
+
+void MainWindow::OnShowDocs( wxCommandEvent& /*unused*/ )
+{
+ m_ui.OpenWebBrowser( _T("http://springlobby.info") );
+}
+
+void MainWindow::OnTabsChanged( wxAuiNotebookEvent& event )
+{
+ int newsel = event.GetSelection();
+
+ if ( newsel == 0 || newsel == 1 )
+ {
+ if ( !m_ui.IsConnected() && m_ui.IsMainWindowCreated() ) m_ui.Connect();
+ }
+}
+
+void MainWindow::OnUnitSyncReloaded()
+{
+ wxLogDebugFunc( _T("") );
+ wxLogMessage( _T("Reloading join tab") );
+ GetJoinTab().OnUnitSyncReloaded();
+ wxLogMessage( _T("Join tab updated") );
+ wxLogMessage( _T("Reloading Singleplayer tab") );
+ GetSPTab().OnUnitSyncReloaded();
+ wxLogMessage( _T("Singleplayer tab updated") );
+}
+
+void MainWindow::OnShowSettingsPP( wxCommandEvent& /*unused*/ )
+{
+ se_frame = new settings_frame(this,wxID_ANY,wxT("Settings++"),wxDefaultPosition,
+ wxDefaultSize);
+ se_frame_active = true;
+ se_frame->Show();
+}
+
+void MainWindow::OnMenuAutojoinChannels( wxCommandEvent& /*unused*/ )
+{
+ m_autojoin_dialog = new AutojoinChannelDialog (this);
+ m_autojoin_dialog->Show();
+}
+
+void MainWindow::OnMenuSelectLocale( wxCommandEvent& /*unused*/ )
+{
+ if ( wxGetApp().SelectLanguage() ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("You need to restart SpringLobby for the language change to take effect."),
+ _("Restart required"), wxICON_EXCLAMATION | wxOK );
+ }
+}
+
+void MainWindow::OnShowChannelChooser( wxCommandEvent& /*unused*/ )
+{
+ ShowChannelChooser();
+}
+
+void MainWindow::OnChannelList( const wxString& channel, const int& numusers, const wxString& topic )
+{
+ m_channel_chooser->AddChannel( channel, numusers, topic );
+}
+
+void MainWindow::OnChannelListStart( )
+{
+ m_channel_chooser->ClearChannels();
+}
+
+void MainWindow::OnMenuSaveLayout( wxCommandEvent& /*unused*/ )
+{
+ wxString answer;
+ if ( !ui().AskText( _("Layout manager"),_("Enter a profile name"), answer ) ) return;
+ wxString layout = GetAui().manager->SavePerspective();
+ sett().SaveLayout( answer, layout );
+}
+
+void MainWindow::OnMenuLoadLayout( wxCommandEvent& /*unused*/ )
+{
+ wxArrayString layouts = sett().GetLayoutList();
+ unsigned int result = wxGetSingleChoiceIndex( _("Which profile fo you want to load?"), _("Layout manager"), layouts );
+ if ( ( result < 0 ) || ( result > layouts.GetCount() ) ) return;
+ GetAui().manager->LoadPerspective( sett().GetLayout( layouts[result] ) );
+}
+
+
+void MainWindow::OnMenuDefaultLayout( wxCommandEvent& /*unused*/ )
+{
+ wxArrayString layouts = sett().GetLayoutList();
+ unsigned int result = wxGetSingleChoiceIndex( _("Which profile do you want to be default?"), _("Layout manager"), layouts );
+ if ( ( result < 0 ) || ( result > layouts.GetCount() ) ) return;
+ sett().SetDefaultLayout( layouts[result] );
+}
+
+const MainWindow::TabNames& MainWindow::GetTabNames()
+{
+ return m_tab_names;
+}
diff --git a/src/mainwindow.h b/src/mainwindow.h
new file mode 100644
index 0000000..9e841fe
--- /dev/null
+++ b/src/mainwindow.h
@@ -0,0 +1,250 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MAINWINDOW_H
+#define SPRINGLOBBY_HEADERGUARD_MAINWINDOW_H
+
+#include <wx/frame.h>
+
+class Ui;
+class Channel;
+class User;
+class wxCommandEvent;
+class wxListbookEvent;
+class wxAuiNotebookEvent;
+class MainChatTab;
+class MainJoinBattleTab;
+class MainSinglePlayerTab;
+#ifndef NO_TORRENT_SYSTEM
+class MainTorrentTab;
+#endif
+class wxBoxSizer;
+class SLNotebook;
+class wxListbook;
+class MainOptionsTab;
+class wxBitmap;
+class wxImageList;
+class ChatPanel;
+class settings_frame;
+class wxMenuItem;
+class wxMenuBar;
+class wxMenu;
+class ChannelChooserDialog;
+class ReplayTab;
+class AutojoinChannelDialog;
+class WidgetDownloadDialog;
+class wxLogWindow;
+class wxLogChain;
+class wxCloseEvent;
+
+class ReplayTraits;
+template < class Traits >
+class PlaybackTab;
+
+class SavegameTraits;
+template < class Traits >
+class SavegameTab;
+
+
+
+//! @brief wxFrame that contains the main window of the client.
+class MainWindow : public wxFrame
+{
+ public:
+ MainWindow( Ui& ui );
+ virtual ~MainWindow();
+
+ typedef PlaybackTab<ReplayTraits>
+ ReplayTab;
+ typedef PlaybackTab<SavegameTraits>
+ SavegameTab;
+
+ // MainWindow interface
+ void OpenChannelChat( Channel& channel, bool doFocus = true );
+ void OpenPrivateChat( const User& user, bool doFocus = false );
+
+ void ShowConfigure( const unsigned int page = OPT_PAGE_SPRING );
+ void ShowTab( const int idx );
+ void ShowSingleplayer();
+
+ /** Show the channel list dialog. */
+ void ShowChannelChooser();
+
+ void OnMenuAbout( wxCommandEvent& event );
+ void OnMenuJoin( wxCommandEvent& event );
+ void OnMenuChat( wxCommandEvent& event );
+ void OnMenuConnect( wxCommandEvent& event );
+ void OnMenuDisconnect( wxCommandEvent& event );
+ void OnMenuSaveOptions( wxCommandEvent& event );
+ void OnMenuQuit( wxCommandEvent& event );
+ void OnMenuVersion ( wxCommandEvent& event );
+ void OnMenuSaveLayout( wxCommandEvent& event );
+ void OnMenuLoadLayout( wxCommandEvent& event );
+ void OnMenuDefaultLayout( wxCommandEvent& event );
+ void OnUnitSyncReload( wxCommandEvent& event );
+ void OnMenuStartTorrent( wxCommandEvent& event );
+ void OnMenuStopTorrent( wxCommandEvent& event );
+ void OnMenuOpen( wxMenuEvent& event );
+ void OnMenuAutojoinChannels( wxCommandEvent& event );
+ void OnReportBug( wxCommandEvent& event );
+ void OnShowDocs( wxCommandEvent& event );
+ void OnShowSettingsPP( wxCommandEvent& event );
+ void OnMenuSelectLocale( wxCommandEvent& event );
+ void OnShowChannelChooser( wxCommandEvent& event );
+ void OnShowScreenshots( wxCommandEvent& event );
+ void forceSettingsFrameClose();
+ void OnUnitSyncReloaded();
+ void OnChannelList( const wxString& channel, const int& numusers, const wxString& topic );
+ void OnChannelListStart( );
+ void OnClose( wxCloseEvent& evt );
+
+
+
+ void OnTabsChanged( wxAuiNotebookEvent& event );
+ MainChatTab& GetChatTab();
+ MainJoinBattleTab& GetJoinTab();
+ MainSinglePlayerTab& GetSPTab();
+ ReplayTab& GetReplayTab();
+ SavegameTab& GetSavegameTab();
+ #ifndef NO_TORRENT_SYSTEM
+ MainTorrentTab& GetTorrentTab();
+ #endif
+ ChatPanel* GetActiveChatPanel();
+ ChatPanel* GetChannelChatPanel( const wxString& channel );
+ MainOptionsTab& GetOptionsTab();
+
+ void SetTabIcons();
+
+ void SetLogWin( wxLogWindow* log, wxLogChain* logchain );
+
+ protected:
+ // MainWindow variables
+ Ui& m_ui;
+
+ wxMenuItem* m_settings_menu;
+ wxMenuBar* m_menubar;
+ wxMenu* m_menuTools;
+
+ wxBoxSizer* m_main_sizer;
+ SLNotebook* m_func_tabs;
+
+ MainChatTab* m_chat_tab;
+ MainJoinBattleTab* m_join_tab;
+ MainSinglePlayerTab* m_sp_tab;
+ MainOptionsTab* m_opts_tab;
+ #ifndef NO_TORRENT_SYSTEM
+ MainTorrentTab* m_torrent_tab;
+ #endif
+
+ AutojoinChannelDialog* m_autojoin_dialog;
+ settings_frame* se_frame;
+ bool se_frame_active;
+ ChannelChooserDialog* m_channel_chooser;
+
+ ReplayTab* m_replay_tab;
+ SavegameTab* m_savegame_tab;
+
+ wxBitmap GetTabIcon( const unsigned char* data, size_t size );
+
+ wxLogWindow* m_log_win;
+ wxLogChain* m_log_chain;
+
+ enum {
+ MENU_SETTINGSPP,
+ MENU_ABOUT = wxID_ABOUT,
+ MENU_QUIT = wxID_EXIT,
+
+ MENU_CONNECT = wxID_HIGHEST,
+ MENU_DISCONNECT,
+ MENU_SAVE_OPTIONS,
+ MENU_JOIN,
+ MENU_USYNC,
+ MENU_TRAC,
+ MENU_DOC,
+ MENU_CHAT,
+ MAIN_TABS,
+ MENU_VERSION,
+ MENU_START_TORRENT,
+ MENU_STOP_TORRENT,
+ MENU_AUTOJOIN_CHANNELS,
+ MENU_SELECT_LOCALE,
+ MENU_CHANNELCHOOSER,
+ MENU_SAVE_LAYOUT,
+ MENU_LOAD_LAYOUT,
+ MENU_DEFAULT_LAYOUT,
+ MENU_SCREENSHOTS
+ };
+
+ class TabNames : public wxArrayString
+ {
+ public:
+ TabNames ()
+ {
+ Add( _("Chat") );
+ Add( _("Multiplayer") );
+ Add( _("Singleplayer") );
+ Add( _("Savegames") );
+ Add( _("Replays") );
+ #ifndef NO_TORRENT_SYSTEM
+ Add( _("Downloads") );
+ #endif
+ Add( _("Options") );
+ }
+ };
+ static TabNames m_tab_names;
+
+ public:
+ // Page indexes
+ static const unsigned int PAGE_CHAT = 0;
+ static const unsigned int PAGE_JOIN = 1;
+ static const unsigned int PAGE_SINGLE = 2;
+ static const unsigned int PAGE_REPLAY = 3;
+ static const unsigned int PAGE_SAVEGAME = 4;
+
+ #ifndef NO_TORRENT_SYSTEM
+ static const unsigned int PAGE_TORRENT = 5;
+ static const unsigned int PAGE_OPTOS = 6;
+ #else
+ static const unsigned int PAGE_OPTOS = 5;
+ #endif
+
+ static const unsigned int OPT_PAGE_SPRING = 0;
+ static const unsigned int OPT_PAGE_CHAT = 1;
+ #ifndef NO_TORRENT_SYSTEN
+ static const unsigned int OPT_PAGE_TORRENT = 2;
+ static const unsigned int OPT_PAGE_GENERAL = 3;
+ static const unsigned int OPT_PAGE_GROUPS = 4;
+ #else
+ static const unsigned int OPT_PAGE_GENERAL = 2;
+ static const unsigned int OPT_PAGE_GROUPS = 3;
+ #endif
+
+ static const TabNames& GetTabNames();
+
+ protected:
+
+
+ DECLARE_EVENT_TABLE()
+};
+
+//ChatPanel& servwin();
+
+// wxWidget IDs
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_MAINWINDOW_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mapctrl.cpp b/src/mapctrl.cpp
new file mode 100644
index 0000000..6adf3dc
--- /dev/null
+++ b/src/mapctrl.cpp
@@ -0,0 +1,1579 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+
+#include <wx/panel.h>
+#include <wx/dcclient.h>
+#include <wx/bitmap.h>
+#include <wx/image.h>
+#include <wx/intl.h>
+#include <cmath>
+#include <stdexcept>
+#include <wx/log.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "utils/math.h"
+#include "uiutils.h"
+#include "mapctrl.h"
+#include "iunitsync.h"
+#include "user.h"
+#include "ui.h"
+#include "server.h"
+#include "ibattle.h"
+#include "settings.h"
+#include "iconimagelist.h"
+
+#include "images/close.xpm"
+#include "images/close_hi.xpm"
+#include "images/start_ally.xpm"
+#include "images/start_enemy.xpm"
+#include "images/start_unused.xpm"
+#include "images/player.xpm"
+#include "images/bot.xpm"
+#include "images/no1_icon.png.h"
+#include "images/no2_icon.png.h"
+#include "images/up_down.xpm"
+#include "images/upsel_down.xpm"
+#include "images/up_downsel.xpm"
+#include "images/not_found_icon.xpm"
+#include "images/download_map.xpm"
+#include "images/reload_map.xpm"
+
+#define USER_BOX_EXPANDED_HEIGHT 70
+#define USER_BOX_EXPANDED_WIDTH 75
+
+/** How much padding to place around the icon of a user box.
+ */
+#define USER_BOX_ICON_PADDING 2
+
+
+/** Width of the e.g. player or bot images that mark a player/bot's
+ * chosen start position.
+ */
+#define USER_BOX_ICON_WIDTH 16
+
+/** Height of the e.g. player or bot images that mark a player/bot's
+ * chosen start position.
+ */
+#define USER_BOX_ICON_HEIGHT 16
+
+#define USER_BOX_ICON_HALFWIDTH (USER_BOX_ICON_WIDTH / 2)
+#define USER_BOX_ICON_HALFHEIGHT (USER_BOX_ICON_HEIGHT / 2)
+
+
+const wxSize user_box_icon_size ( USER_BOX_ICON_WIDTH + 2 * USER_BOX_ICON_PADDING,
+ USER_BOX_ICON_HEIGHT + 2 * USER_BOX_ICON_PADDING );
+
+const wxSize user_box_expanded_size ( USER_BOX_EXPANDED_WIDTH, USER_BOX_EXPANDED_HEIGHT );
+
+BEGIN_EVENT_TABLE( MapCtrl, wxPanel )
+ EVT_PAINT( MapCtrl::OnPaint )
+ EVT_SIZE( MapCtrl::OnResize )
+ EVT_MOTION( MapCtrl::OnMouseMove )
+ EVT_LEFT_DOWN( MapCtrl::OnLeftDown )
+ EVT_LEFT_UP( MapCtrl::OnLeftUp )
+ // EVT_MOUSEWHEEL( MapCtrl::OnMouseWheel )
+ EVT_COMMAND( wxID_ANY, UnitSyncAsyncOperationCompletedEvt, MapCtrl::OnGetMapImageAsyncCompleted )
+END_EVENT_TABLE()
+
+/* Something to do with start box sizes. */
+const int boxsize = 8;
+const int minboxsize = 40;
+
+static inline void WriteInt24(unsigned char* p, int i)
+{
+ p[0] = i & 0xFF;
+ p[1] = (i >> 8) & 0xFF;
+ p[2] = (i >> 16) & 0xFF;
+}
+
+static inline int ReadInt24(const unsigned char* p)
+{
+ return p[0] | (p[1] << 8) | (p[2] << 16);
+}
+
+MapCtrl::MapCtrl( wxWindow* parent, int size, IBattle* battle, Ui& ui, bool readonly, bool fixed_size, bool draw_start_types, bool singleplayer ):
+ wxPanel( parent, -1, wxDefaultPosition, wxSize(size, size), wxSIMPLE_BORDER|wxFULL_REPAINT_ON_RESIZE ),
+ m_async(this),
+ m_minimap(0),
+ m_metalmap(0),
+ m_heightmap(0),
+ m_battle(battle),
+ m_ui(ui),
+ m_mapname(_T("")),
+ m_draw_start_types(draw_start_types),
+ m_fixed_size(fixed_size),
+ m_ro(readonly),
+ m_sp(singleplayer),
+ m_mover_rect(-2),
+ m_rect_area(Main),
+ m_last_rect_area(Main),
+ m_maction(None),
+ m_lastsize(-1,-1),
+ m_close_img(0),
+ m_close_hi_img(0),
+ m_start_ally(0),
+ m_start_enemy(0),
+ m_start_unused(0),
+ m_player_img(0),
+ m_bot_img(0),
+ m_nfound_img(0),
+ m_reload_img(0),
+ m_dl_img(0),
+ m_user_expanded(0),
+ m_current_infomap(IM_Minimap)
+{
+ SetBackgroundStyle( wxBG_STYLE_CUSTOM );
+ SetBackgroundColour( *wxLIGHT_GREY );
+ if ( !m_ro )
+ {
+ m_close_img = new wxBitmap( close_xpm );
+ m_close_hi_img = new wxBitmap( close_hi_xpm );
+ }
+ m_tmp_brect.ally = -1;
+}
+
+
+MapCtrl::~MapCtrl()
+{
+ FreeMinimap();
+ delete m_close_img;
+ delete m_close_hi_img;
+ delete m_start_ally;
+ delete m_start_enemy;
+ delete m_start_unused;
+ delete m_nfound_img;
+ delete m_reload_img;
+ delete m_dl_img;
+}
+
+
+void MapCtrl::SetBattle( IBattle* battle )
+{
+ m_battle = battle;
+ UpdateMinimap();
+}
+
+
+wxRect
+MapCtrl::GetDrawableRect() const
+{
+ int w ( 0 ), h ( 0 );
+ GetClientSize(&w, &h);
+ return wxRect(0, 0, w, h);
+}
+
+wxRect MapCtrl::GetMinimapRect() const
+{
+ if ( m_minimap == 0 ) return wxRect();
+
+ int cwidth, cheight, top = 0, left = 0;
+ GetClientSize( &cwidth, &cheight );
+
+ if ( m_minimap->GetWidth() < cwidth )
+ {
+ left = (cwidth - m_minimap->GetWidth()) / 2;
+ }
+ else
+ {
+ top = (cheight - m_minimap->GetHeight()) / 2;
+ }
+ return wxRect( left, top, m_minimap->GetWidth(), m_minimap->GetHeight() );
+}
+
+
+wxRect MapCtrl::GetStartRect( int index )
+{
+ BattleStartRect sr = m_battle->GetStartRect( index );
+ if ( !sr.IsOk() ) return wxRect();
+ return GetStartRect( sr );
+}
+
+
+wxRect MapCtrl::GetStartRect( const BattleStartRect& sr )
+{
+ int x1,y1,x2,y2;
+ if ( !sr.exist || sr.todelete ) return wxRect();
+ wxRect mr = GetMinimapRect();
+
+ x1 = int( (mr.x + sr.left * mr.width / 200.0) + 0.5 );
+ y1 = int( (mr.y + sr.top * mr.height / 200.0) + 0.5 );
+ x2 = int( (mr.x + sr.right * mr.width / 200.0) + 0.5 );
+ y2 = int( (mr.y + sr.bottom * mr.height / 200.0) + 0.5 );
+
+ return wxRect( x1, y1, x2-x1, y2-y1 );
+}
+
+
+void MapCtrl::Accumulate( wxImage& image )
+{
+ if (!image.IsOk()) return;
+
+ // Even tho GetData() returns a non-const pointer,
+ // it does not unshare the reference counted data,
+ // so we have to make a copy of the image..
+ image = image.Copy();
+
+ const int w = image.GetWidth();
+ const int h = image.GetHeight();
+ unsigned char* data = image.GetData();
+
+ // sum in vertical direction
+ unsigned char* p = data;
+ for (int x = 0; x < w; ++x, p += 3)
+ {
+ WriteInt24(p, p[0] + p[1] + p[2]);
+ }
+ for (int y = 1; y < h; ++y)
+ {
+ const unsigned char* prev = data + 3*((y-1)*w);
+ unsigned char* curr = data + 3*(y*w);
+ for (int x = 0; x < w; ++x, prev += 3, curr += 3)
+ {
+ WriteInt24(curr, ReadInt24(prev) + curr[0] + curr[1] + curr[2]);
+ }
+ }
+
+ // sum in horizontal direction
+ for (int x = 1; x < w; ++x)
+ {
+ for (int y = 0; y < h; ++y)
+ {
+ p = data + 3*(y*w+x);
+ WriteInt24(p, ReadInt24(p) + ReadInt24(p - 3));
+ }
+ }
+}
+
+
+double MapCtrl::GetStartRectMetalFraction( int index )
+{
+ BattleStartRect sr = m_battle->GetStartRect( index );
+ if ( !sr.IsOk() ) return 0.0;
+ return GetStartRectMetalFraction( sr );
+}
+
+
+double MapCtrl::GetStartRectMetalFraction( const BattleStartRect& sr )
+{
+ // todo: this really is *logic*, not rendering code, so it
+ // should go in some other layer sometime (SpringUnitSync?).
+ if (!m_metalmap_cumulative.IsOk()) return 0.0;
+
+ int x1,y1,x2,y2,w,h;
+
+ w = m_metalmap_cumulative.GetWidth();
+ h = m_metalmap_cumulative.GetHeight();
+ x1 = std::max(0, std::min(w-1, int( (sr.left * w / 200.0) + 0.5 )));
+ y1 = std::max(0, std::min(h-1, int( (sr.top * h / 200.0) + 0.5 )));
+ x2 = std::max(0, std::min(w-1, int( (sr.right * w / 200.0) + 0.5 )));
+ y2 = std::max(0, std::min(h-1, int( (sr.bottom * h / 200.0) + 0.5 )));
+
+ const unsigned char* metalmap = m_metalmap_cumulative.GetData();
+ const int lefttop = ReadInt24(&metalmap[3*(y1*w+x1)]);
+ const int righttop = ReadInt24(&metalmap[3*(y1*w+x2)]);
+ const int leftbot = ReadInt24(&metalmap[3*(y2*w+x1)]);
+ const int rightbot = ReadInt24(&metalmap[3*(y2*w+x2)]);
+ // in 2d cumulative distribution total is value at bottom right corner
+ const int total = ReadInt24(&metalmap[3*(w*h-1)]);
+
+ return (double) (lefttop + rightbot - righttop - leftbot) / total;
+}
+
+
+unsigned int MapCtrl::GetNewRectIndex()
+{
+ ASSERT_LOGIC ( m_battle, _T("getting a rectangle index not in a battle"));
+ return m_battle->GetNextFreeRectIdx();
+}
+
+
+BattleStartRect MapCtrl::GetBattleRect( int x1, int y1, int x2, int y2, int ally )
+{
+ BattleStartRect br;
+ wxRect mr = GetMinimapRect();
+
+ br.ally = ally;
+ br.left = int( (200.0 * ( x1 - mr.x ) / mr.width) + 0.5 );
+ br.top = int( (200.0 * ( y1 - mr.y ) / mr.height) + 0.5 );
+ br.right = int( (200.0 * ( x2 - mr.x ) / mr.width) + 0.5 );
+ br.bottom = int( (200.0 * ( y2 - mr.y ) / mr.height) + 0.5 );
+ br.exist = true;
+ br.toadd = false;
+ br.toresize = true;
+
+ int max_sz = 200;
+
+ if ( br.left < 0 ) br.left = 0;
+ if ( br.left > max_sz ) br.left = max_sz;
+ if ( br.top < 0 ) br.top = 0;
+ if ( br.top > max_sz ) br.top = max_sz;
+ if ( br.right < 0 ) br.right = 0;
+ if ( br.right > max_sz ) br.right = max_sz;
+ if ( br.bottom < 0 ) br.bottom = 0;
+ if ( br.bottom > max_sz ) br.bottom = max_sz;
+
+ return br;
+}
+
+
+void MapCtrl::SetMouseOverRect( int index )
+{
+ int oldindex = m_mover_rect;
+ m_mover_rect = index;
+ _SetCursor();
+
+ if ( (index != oldindex) || (m_rect_area != m_last_rect_area) ) UpdateMinimap();
+ m_last_rect_area = m_rect_area;
+}
+
+
+void MapCtrl::_SetCursor()
+{
+ if ( !m_minimap )
+ {
+ if ( m_rect_area != Main ) SetCursor( wxCursor( wxCURSOR_HAND ) );
+ else SetCursor( wxCursor( wxCURSOR_ARROW ) );
+ return;
+ }
+
+ if ( m_battle != 0 )
+ {
+ long longval;
+ m_battle->CustomBattleOptions().getSingleValue( _T("startpostype") , OptionsWrapper::EngineOption ).ToLong( &longval );
+ if ( longval != IBattle::ST_Choose )
+ {
+ SetCursor( wxCursor( wxCURSOR_ARROW ) );
+ return;
+ }
+ else
+ {
+ if ( !m_ro ) SetCursor( wxCursor( wxCURSOR_CROSS ) );
+ else SetCursor( wxCursor( wxCURSOR_ARROW ) );
+ return;
+ }
+ }
+
+ if ( !m_ro )
+ {
+ if ( m_mover_rect >= 0 )
+ {
+ if ( m_rect_area == UpLeft ) SetCursor( wxCursor( wxCURSOR_SIZENWSE ) );
+ else if ( m_rect_area == UpRight ) SetCursor( wxCursor( wxCURSOR_ARROW ) );
+ else if ( m_rect_area == DownLeft ) SetCursor( wxCursor( wxCURSOR_SIZENESW ) );
+ else if ( m_rect_area == DownRight ) SetCursor( wxCursor( wxCURSOR_SIZENWSE ) );
+ else SetCursor( wxCursor( wxCURSOR_SIZING ) );
+ }
+ else if ( m_mover_rect == -1 )
+ {
+ SetCursor( wxCursor( wxCURSOR_CROSS ) );
+ }
+ else
+ {
+ SetCursor( wxCursor( wxCURSOR_ARROW ) );
+ }
+ }
+ else
+ {
+ if ( m_mover_rect >= 0 ) SetCursor( wxCursor( wxCURSOR_HAND ) );
+ else SetCursor( wxCursor( wxCURSOR_ARROW ) );
+ }
+
+}
+
+
+void MapCtrl::RelocateUsers()
+{
+ if ( m_battle == 0 ) return;
+
+ for ( unsigned int i = 0; i < m_battle->GetNumUsers(); i++ )
+ {
+ try
+ {
+ User& user = m_battle->GetUser( i );
+ UserPosition& pos = user.BattleStatus().pos;
+ pos = m_battle->GetFreePosition();
+ if ( user.BattleStatus().pos.x == -1 ) m_battle->KickPlayer( user );
+ }
+ catch (...) {}
+ }
+}
+
+
+void MapCtrl::GetClosestStartPos( int fromx, int fromy, int& index, int& x, int& y, int& range )
+{
+ if ( m_battle == 0 ) return;
+ UnitSyncMap map = m_battle->LoadMap();
+
+ int newrange;
+ range = -1;
+ index = -1;
+
+ for ( int i = 0; i < map.info.posCount; i++ )
+ {
+ double dx = fromx - map.info.positions[i].x;
+ double dy = fromy - map.info.positions[i].y;
+ newrange = (int)sqrt( dx*dx + dy*dy );
+ if ( ( range == -1 ) || ( range > newrange ))
+ {
+ range = newrange;
+ index = i;
+ }
+ }
+
+ if ( index != -1 )
+ {
+ x = map.info.positions[index].x;
+ y = map.info.positions[index].y;
+ }
+}
+
+
+int MapCtrl::LoadMinimap()
+{
+ wxLogDebugFunc( _T("") );
+ if ( m_battle == 0 ) return -1;
+ if ( m_minimap ) return -1;
+ if ( !m_battle->MapExists() ) return -1;
+
+ wxString map = m_battle->GetHostMapName();
+
+ try
+ {
+ int w, h;
+ GetClientSize( &w, &h );
+ if ( w * h == 0 )
+ {
+ m_mapname = _T("");
+ m_lastsize = wxSize( -1, -1 );
+ return -2;
+ }
+
+ // start chain of asynchronous map image fetches
+ // first minimap, then metalmap and heightmap
+ m_async.GetMinimap( map, w, h );
+
+ m_mapname = map;
+ m_lastsize = wxSize( w, h );
+ Refresh();
+ Update();
+ }
+ catch (...)
+ {
+ FreeMinimap();
+ return -3;
+ }
+ return 0;
+}
+
+
+void MapCtrl::FreeMinimap()
+{
+ delete m_minimap;
+ m_minimap = 0;
+ delete m_metalmap;
+ m_metalmap = 0;
+ delete m_heightmap;
+ m_heightmap = 0;
+ m_mapname = _T("");
+}
+
+
+void MapCtrl::UpdateMinimap()
+{
+ int w, h;
+ _SetCursor();
+ if ( m_battle == 0 ) return;
+ GetClientSize( &w, &h );
+ if ( m_battle ) //needs to be looked into, crahses with replaytab (koshi)
+ {
+ bool just_resize = ( m_lastsize != wxSize(-1,-1) && m_lastsize != wxSize(w, h) );
+ if ( (m_mapname != m_battle->GetHostMapName() ) || just_resize )
+ {
+ FreeMinimap();
+ int loaded_ok = LoadMinimap();
+
+ if(!just_resize && loaded_ok == 0) // if a new map is loaded, reset start positions
+ {
+ long longval;
+ m_battle->CustomBattleOptions().getSingleValue( _T("startpostype") , OptionsWrapper::EngineOption ).ToLong( &longval );
+ if ( longval == IBattle::ST_Pick ) RelocateUsers();
+ }
+ }
+ }
+ Refresh();
+ Update();
+}
+
+
+void MapCtrl::RequireImages()
+{
+ if ( !m_start_ally ) m_start_ally = new wxBitmap( start_ally_xpm );
+ if ( !m_start_enemy ) m_start_enemy = new wxBitmap( start_enemy_xpm );
+ if ( !m_start_unused ) m_start_unused = new wxBitmap( start_unused_xpm );
+ if ( !m_player_img ) m_player_img = new wxBitmap( player_xpm );
+ if ( !m_bot_img ) m_bot_img = new wxBitmap( bot_xpm );
+}
+
+
+void MapCtrl::DrawStartRect( wxDC& dc, int index, wxRect& sr, const wxColour& col, bool mouseover, int alphalevel, bool forceInsideMinimap )
+{
+ int x1 = sr.x;
+ int y1 = sr.y;
+ int x2 = sr.x + sr.width;
+ int y2 = sr.y + sr.height;
+ wxRect mr = GetMinimapRect();
+ if ( forceInsideMinimap )
+ {
+ x1 = std::max( mr.x, x1 );
+ y1 = std::max( mr.y, y1 );
+ x2 = std::min( mr.x+mr.width, x2 );
+ y2 = std::min( mr.y+mr.height, y2 );
+ }
+ sr.x = x1;
+ sr.y = y1;
+ sr.width = x2 - x1;
+ sr.height = y2 - y1;
+ if ( sr.width < 0 )
+ {
+ sr.width = 0;
+ }
+ if ( sr.height < 0 )
+ {
+ sr.height = 0;
+ }
+ if ( sr.width * sr.height <= 0 ) return;
+
+ dc.SetBrush( wxBrush( *wxLIGHT_GREY, wxTRANSPARENT ) );
+
+ wxImage img( sr.width, sr.height );
+ wxColour light;
+ light.Set( ( ( col.Red() + 100 ) > 200 ) ? 200 : (col.Red() + 100 ), ( ( col.Green() + 100 ) > 200 ) ? 200 : ( col.Green() + 100 ), ( ( col.Blue() + 100 ) > 200 ) ? 200 : ( col.Blue() + 100 ) );
+ img.SetRGB( wxRect( 0, 0, sr.width, sr.height ), light.Red(), light.Green(), light.Blue() );
+ img.InitAlpha();
+ unsigned char *alpha = img.GetAlpha();
+ for ( int y = 0; y < sr.height; y++ )
+ {
+ int a;
+ if ( ( y % 3 ) == 0 ) a = alphalevel;
+ else a = ( ( alphalevel - 40 ) < 0 ) ? 0 : ( alphalevel - 40 );
+ for ( int x = 0; x < sr.width; x++ )
+ {
+ alpha[ ( y* sr.width )+ x ] = a;
+ }
+ }
+ wxBitmap bmpimg( img );
+ dc.DrawBitmap( bmpimg, sr.x, sr.y, false );
+
+ /* wxFont f( 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL|wxFONTFLAG_ANTIALIASED, wxFONTWEIGHT_LIGHT );
+ dc.SetFont( f );*/
+ if ( index != -1 )
+ {
+ int twidth, theight, tx, ty;
+ wxString strIndex = wxString::Format( _T("%d"), index + 1 );
+ dc.GetTextExtent( strIndex, &twidth, &theight );
+ dc.SetTextForeground( col );
+ tx = sr.x + sr.width / 2 - twidth / 2;
+ ty = sr.y + sr.height / 2 - theight / 2 - 1;
+ DrawOutlinedText( dc, strIndex, tx, ty, wxColour( 50, 50, 50), *wxWHITE );
+ //dc.DrawText( wxString::Format( _T("%d"), index+1), sr.x + sr.width / 2 - twidth / 2, sr.y + sr.height / 2 - theight / 2 - 1 );
+
+ const double metal = GetStartRectMetalFraction( index );
+ if ( metal != 0.0 )
+ {
+ wxString strMetal = wxString::Format( _("Metal: %.1f%%"), metal * 100.0 );
+ dc.GetTextExtent( strMetal, &twidth, &theight );
+ // don't cramp it in rect, but only display it if it actually fits
+ if (sr.height >= 6 * theight && sr.width > twidth)
+ {
+ tx = sr.x + sr.width / 2 - twidth / 2;
+ ty = sr.y + sr.height / 2 + theight / 2 + theight - 1;
+ DrawOutlinedText( dc, strMetal, tx, ty, wxColour( 50, 50, 50 ), *wxWHITE );
+ }
+ }
+ }
+
+ dc.SetPen( wxPen( col ) );
+
+ if ( mouseover && !m_ro )
+ {
+
+ dc.DrawRectangle( sr.x + 1, sr.y + 1, sr.width - 2, sr.height - 2 );
+ dc.SetPen( wxPen( *wxBLACK ) );
+ dc.DrawRectangle( sr.x, sr.y, sr.width, sr.height );
+
+ dc.SetBrush( wxBrush( *wxBLACK, wxSOLID ) );
+ dc.DrawRectangle( sr.x, sr.y, boxsize, boxsize );
+ dc.DrawRectangle( sr.x + sr.width - boxsize, sr.y + sr.height - boxsize, boxsize, boxsize );
+ //dc.DrawRectangle( sr.x + sr.width - boxsize, sr.y + 1, boxsize, boxsize );
+ //dc.DrawRectangle( sr.x, sr.y + sr.height - boxsize, boxsize, boxsize );
+
+ if ( m_rect_area != UpRight ) dc.DrawBitmap( *m_close_img, sr.x + sr.width - 16, sr.y + 2, true );
+ else dc.DrawBitmap( *m_close_hi_img, sr.x + sr.width - 16, sr.y + 2, true );
+
+ }
+ else
+ {
+ dc.DrawRectangle( sr.x, sr.y, sr.width, sr.height );
+ }
+}
+
+
+wxRect MapCtrl::GetRefreshRect()
+{
+ int width, height;
+ GetClientSize( &width, &height );
+ return wxRect( 5, height - 27, 72, 22 );
+}
+
+
+wxRect MapCtrl::GetDownloadRect()
+{
+ int width, height;
+ GetClientSize( &width, &height );
+ return wxRect( 5, height - 52, 87, 22 );
+}
+
+
+void MapCtrl::DrawBackground( wxDC& dc )
+{
+ int width, height;
+ GetClientSize( &width, &height );
+
+ dc.SetPen( wxPen( *wxLIGHT_GREY ) );
+ dc.SetBrush( wxBrush( *wxLIGHT_GREY, wxSOLID ) );
+
+ if ( m_battle == 0 )
+ {
+ dc.DrawRectangle( 0, 0, width, height );
+ return;
+ }
+
+ wxBitmap* img = 0;
+ switch (m_current_infomap)
+ {
+ case IM_Minimap:
+ img = m_minimap;
+ break;
+ case IM_Metalmap:
+ img = m_metalmap;
+ break;
+ case IM_Heightmap:
+ img = m_heightmap;
+ break;
+ default:
+ ASSERT_LOGIC( false, _T("missing InfoMap IM_* enumeration constant in switch") );
+ break;
+ }
+
+ // Draw minimap.
+ if ( !img )
+ {
+
+ // Draw background.
+ dc.DrawRectangle( 0, 0, width, height );
+
+ if ( m_sp ) return;
+
+ if ( !m_nfound_img ) m_nfound_img = new wxBitmap( not_found_icon_xpm );
+ if ( !m_reload_img ) m_reload_img = new wxBitmap( reload_map_xpm );
+ if ( !m_dl_img ) m_dl_img = new wxBitmap( download_map_xpm );
+
+ dc.DrawBitmap( *m_nfound_img, width/2 - 32, height/2 - 32, true );
+ if ( (m_rect_area == Refreshing) && (m_mdown_area != Refreshing) ) dc.DrawBitmap( *m_reload_img, 6, height - 28, true );
+ else dc.DrawBitmap( *m_reload_img, 5, height - 27, true );
+ if ( (m_rect_area == Download) && (m_mdown_area != Download) ) dc.DrawBitmap( *m_dl_img, 6, height - 53, true );
+ else dc.DrawBitmap( *m_dl_img, 5, height - 52, true );
+
+ dc.SetFont( wxFont( 9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL ) );
+ if ( m_rect_area == Refreshing ) DrawOutlinedText( dc, _("Refresh"), 28, height - 25, wxColour(50,50,50), *wxWHITE );
+ else DrawOutlinedText( dc, _("Refresh"), 28, height - 25, *wxWHITE, wxColour(50,50,50) );
+ if ( m_rect_area == Download ) DrawOutlinedText( dc, _("Download"), 28, height - 50, wxColour(50,50,50), *wxWHITE );
+ else DrawOutlinedText( dc, _("Download"), 28, height - 50, *wxWHITE, wxColour(50,50,50) );
+
+ }
+ else
+ {
+
+ wxRect r = GetMinimapRect();
+
+ // Draw background where the minimap is not drawn(to avoid flickering).
+ if ( r.y > 0 )
+ {
+ dc.DrawRectangle( 0, 0, width, (height - r.height) / 2 );
+ dc.DrawRectangle( 0, r.y+r.height, width, (height - r.height) / 2 + 1 );
+ }
+ if ( r.x > 0 )
+ {
+ dc.DrawRectangle( 0, 0, (width - r.width) / 2, height );
+ dc.DrawRectangle( r.x+r.width, 0, (width - r.width) / 2 + 1, height );
+ }
+
+ // Draw minimap
+ dc.DrawBitmap( *img, r.x, r.y, false );
+ }
+}
+
+
+void MapCtrl::DrawStartRects( wxDC& dc )
+{
+ for ( int i = 0; i <= int(m_battle->GetLastRectIdx()); i++ )
+ {
+ wxRect sr = GetStartRect( i );
+ if ( sr.IsEmpty() ) continue;
+ wxColour col;
+ if ( i == m_battle->GetMe().BattleStatus().ally )
+ {
+ col.Set( 0, 200, 0 );
+ }
+ else
+ {
+ col.Set( 200, 0, 0 );
+ }
+ DrawStartRect( dc, i, sr, col, m_mover_rect == i );
+ }
+}
+
+
+void MapCtrl::DrawStartPositions( wxDC& dc )
+{
+ wxRect mr = GetMinimapRect();
+ m_map = m_battle->LoadMap();
+ RequireImages();
+ long longval;
+ m_battle->CustomBattleOptions().getSingleValue( _T("startpostype") , OptionsWrapper::EngineOption ).ToLong( &longval );
+ if ( longval == IBattle::ST_Fixed )
+ {
+
+ wxFont f( 7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT );
+ dc.SetFont( f );
+ for ( int i = 0; i < m_map.info.posCount; i++ )
+ {
+ int x = (int)( (double)((double)m_map.info.positions[i].x / (double)m_map.info.width) * (double)mr.width ) - 8;
+ int y = (int)( (double)(m_map.info.positions[i].y / (double)m_map.info.height) * (double)mr.height ) - 8;
+ dc.DrawBitmap( *m_start_ally, x+mr.x, y+mr.y, true );
+ wxCoord w, h;
+ dc.GetTextExtent( wxString::Format(_T("%d"), i+1 ), &w, &h );
+ dc.DrawText( wxString::Format(_T("%d"), i+1 ), x+mr.x+(8-w/2), y+mr.y+(8-h/2) );
+ }
+ }
+ else
+ {
+ // Draw startpositions
+ for ( int i = 0; i < m_map.info.posCount; i++ )
+ {
+ int x = (int)( (double)((double)m_map.info.positions[i].x / (double)m_map.info.width) * (double)mr.width ) - 8;
+ int y = (int)( (double)(m_map.info.positions[i].y / (double)m_map.info.height) * (double)mr.height ) - 8;
+ dc.DrawBitmap( *m_start_unused, x+mr.x, y+mr.y, true );
+ }
+ }
+}
+
+wxRealPoint
+MapCtrl::GetUserMapPositionAsReal(const User& user) const
+{
+ return wxRealPoint(static_cast<double>(user.BattleStatus().pos.x) / static_cast<double>(m_map.info.width),
+ static_cast<double>(user.BattleStatus().pos.y) / static_cast<double>(m_map.info.height));
+}
+
+wxPoint
+MapCtrl::GetTranslatedScaledUserMapPosition(const User& user) const
+{
+ wxRealPoint rmp ( GetUserMapPositionAsReal(user) );
+ wxRect mr ( GetMinimapRect() );
+
+ return wxPoint(mr.x + static_cast<int>(rmp.x * mr.width),
+ mr.y + static_cast<int>(rmp.y * mr.height));
+}
+
+/** Try to fit @p what inside @p container.
+ *
+ * @return a wxPoint that can be used with wxRect::Offset.
+ */
+inline wxPoint
+FitInside(const wxRect& what, const wxRect& container)
+{
+ ASSERT_LOGIC ( what.width <= container.width && what.height <= container.height,
+ _T("Can't fit rect inside target container") );
+
+ wxPoint offset ( 0, 0 );
+
+ if ( what.x < container.x )
+ offset.x += container.x - what.x;
+ else if ( what.GetRight() > container.GetRight() )
+ offset.x += container.GetRight() - what.GetRight();
+
+ if ( what.y < container.y )
+ offset.y += container.y - what.y;
+ else if ( what.GetBottom() > container.GetBottom() )
+ offset.y += container.GetBottom() - what.GetBottom();
+
+ return offset;
+}
+
+wxRect MapCtrl::GetUserRect( const User& user, bool selected )
+{
+ ASSERT_LOGIC( m_battle != 0, _T("Bot == 0") );
+ m_map = m_battle->LoadMap();
+
+ wxPoint absolute_position ( GetTranslatedScaledUserMapPosition(user) );
+ wxPoint box_start ( absolute_position.x - USER_BOX_ICON_HALFWIDTH - USER_BOX_ICON_PADDING,
+ absolute_position.y - USER_BOX_ICON_HALFWIDTH - USER_BOX_ICON_PADDING );
+ wxRect user_box ( box_start, ( selected && m_sp ) ? user_box_expanded_size : user_box_icon_size );
+ wxRect cram_into_box ( GetDrawableRect() );
+ wxPoint offset ( ::FitInside(user_box, cram_into_box) );
+ user_box.Offset(offset);
+
+ return user_box;
+}
+
+
+MapCtrl::RectangleArea MapCtrl::GetUserRectArea( const wxRect& userrect, int x, int y )
+{
+ x = x - userrect.x;
+ y = y - userrect.y;
+ wxRect close = GetUserCloseRect();
+
+ if ( close.Contains( x, y ) ) return Close;
+ wxRect side = GetUserSideRect();
+ if ( side.Contains( x, y ) ) return Side;
+ wxRect AllyUp = GetUserUpAllyButtonRect();
+ if ( AllyUp.Contains( x, y ) ) return UpAllyButton;
+ wxRect AllyDown = GetUserDownAllyButtonRect();
+ if ( AllyDown.Contains( x, y ) ) return DownAllyButton;
+ wxRect handicap = GetUserHandicapRect();
+ if ( handicap.Contains( x, y ) ) return Handicap;
+ wxRect HandicapUp = GetUserUpHandicapButtonRect();
+ if ( HandicapUp.Contains( x, y ) ) return UpHandicapButton;
+ wxRect HandicapDown = GetUserDownHandicapButtonRect();
+ if ( HandicapDown.Contains( x, y ) ) return DownHandicapButton;
+
+ wxRect bot( 0, 0, USER_BOX_ICON_WIDTH, USER_BOX_ICON_HEIGHT );
+ if ( bot.Contains( x, y ) ) return Move;
+
+ return Main;
+}
+
+
+void MapCtrl::DrawOutlinedText( wxDC& dc, const wxString& str, int x, int y, const wxColour& outline, const wxColour& font )
+{
+ dc.SetTextForeground( outline );
+ dc.DrawText( str, x, y );
+ dc.DrawText( str, x, y+1 );
+ dc.DrawText( str, x+1, y );
+ dc.DrawText( str, x+2, y );
+ dc.DrawText( str, x, y+2 ); // Hack to get font outline
+ dc.DrawText( str, x+2, y+2 );
+ dc.SetTextForeground( font );
+ dc.DrawText( str, x+1, y+1 );
+
+}
+
+void MapCtrl::DrawUser( wxDC& dc, User& user, bool selected, bool /*unused*/ )
+{
+ wxBitmap* img;
+ if ( !user.BattleStatus().IsBot() ) img = m_player_img;
+ else img = m_bot_img;
+
+ wxFont f( 9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT );
+ dc.SetFont( f );
+ dc.SetTextForeground( *wxWHITE );
+
+ wxRect r = GetUserRect( user, selected );
+ wxColour col = user.BattleStatus().colour;
+
+ if ( selected )
+ {
+ /* Drawing the whole user-battle-settings-box deal */
+ DrawStartRect( dc, -1, r,ColourDelta( col, -40 ) , false, 180 , false); /* box background */
+
+ /* Side selector */
+ wxRect siderect = GetUserSideRect();
+ DrawOutlinedText( dc, _("side:"), r.x+3, r.y+siderect.y-1, wxColour(50,50,50), *wxWHITE );
+
+ if ( m_rect_area == Side )
+ {
+ wxRect tmp( r.x+siderect.x-1, r.y+siderect.y-1, siderect.width+2, siderect.height+2 );
+ DrawStartRect( dc, -1, tmp, col, false );
+ }
+
+ wxBitmap bmp = icons().GetBitmap( icons().GetSideIcon( m_battle->GetHostModName(), user.BattleStatus().side ) );
+ dc.DrawBitmap( bmp, r.x+siderect.x, r.y+siderect.y, true );
+
+ /* Draw the Ally Number numeric select */
+ wxRect updownallyrect = GetUserUpAllyButtonRect();
+ DrawOutlinedText( dc, wxString::Format( _("ally: %d"), user.BattleStatus().ally + 1 ), r.x+3, r.y+updownallyrect.y, wxColour(50,50,50), *wxWHITE );
+ //dc.DrawText( wxString::Format( _("ally: %d"), bot.BattleStatus().ally + 1 ), r.x+4, r.y+40 );
+
+ if ( m_rect_area == UpAllyButton ) dc.DrawBitmap( wxBitmap(upsel_down_xpm), r.x+updownallyrect.x, r.y+updownallyrect.y, true );
+ else if ( m_rect_area == DownAllyButton ) dc.DrawBitmap( wxBitmap(up_downsel_xpm), r.x+updownallyrect.x, r.y+updownallyrect.y, true );
+ else dc.DrawBitmap( wxBitmap(up_down_xpm), r.x+updownallyrect.x, r.y+updownallyrect.y, true );
+
+ /* Draw the Handicap numeric select */
+ wxRect updownhandicaprect = GetUserUpHandicapButtonRect();
+ wxFont b( 6, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT );
+ dc.SetFont( b );
+ DrawOutlinedText( dc, wxString::Format( _("bonus: %d%%"), user.BattleStatus().handicap ), r.x+3, r.y+updownhandicaprect.y+2, wxColour(50,50,50), *wxWHITE );
+ dc.SetFont( f );
+
+ if ( m_rect_area == UpHandicapButton ) dc.DrawBitmap( wxBitmap(upsel_down_xpm), r.x+updownhandicaprect.x, r.y+updownhandicaprect.y, true );
+ else if ( m_rect_area == DownHandicapButton ) dc.DrawBitmap( wxBitmap(up_downsel_xpm), r.x+updownhandicaprect.x, r.y+updownhandicaprect.y, true );
+ else dc.DrawBitmap( wxBitmap(up_down_xpm), r.x+updownhandicaprect.x, r.y+updownhandicaprect.y, true );
+
+ dc.SetPen( wxPen( col ) );
+ dc.SetBrush( wxBrush( col, wxSOLID ) );
+
+ dc.DrawRectangle( r.x+1, r.y+1, r.width-2, 18 );
+
+ /* Draw the little 'X' (close button) in the corner... */
+ if ( &user != &(m_battle->GetMe()) )
+ {
+ wxRect closerect = GetUserCloseRect();
+ if ( m_rect_area == Close ) dc.DrawBitmap( *m_close_hi_img, r.x+closerect.x, r.y+closerect.y, true );
+ else dc.DrawBitmap( *m_close_img, r.x+closerect.x, r.y+closerect.y, true );
+ }
+ dc.DrawBitmap( *img, r.x+2, r.y+2, true );
+ }
+ else
+ {
+ /* Just drawing an icon */
+ dc.SetPen( wxPen( ColourDelta( col, -40 ) ) );
+ dc.SetBrush( wxBrush( col, wxSOLID ) );
+ dc.DrawRectangle( r.x, r.y, r.width, r.height );
+ dc.DrawBitmap( *img, r.x+ USER_BOX_ICON_PADDING, r.y+USER_BOX_ICON_PADDING, true );
+
+ int w, h;
+ wxString allystr = wxString::Format( _T("%d"), user.BattleStatus().ally + 1 );
+ dc.GetTextExtent( allystr, &w, &h );
+
+ DrawOutlinedText( dc, allystr, r.width - w - 3 + r.x, r.height - h - 1 + r.y, wxColour(50,50,50), *wxWHITE );
+ }
+
+}
+
+
+void MapCtrl::DrawUserPositions( wxDC& dc )
+{
+ wxLogDebugFunc(_T("") );
+ if ( m_battle == 0 ) return;
+ if ( !m_battle->MapExists() ) return;
+
+ wxRect mr = GetMinimapRect();
+ m_map = m_battle->LoadMap();
+ RequireImages();
+
+ for ( int i = 0; i < m_map.info.posCount; i++ )
+ {
+
+ int x = (int)( (double)((double)m_map.info.positions[i].x / (double)m_map.info.width) * (double)mr.width ) - 8;
+ int y = (int)( (double)(m_map.info.positions[i].y / (double)m_map.info.height) * (double)mr.height ) - 8;
+
+ User* bot = 0;
+ for ( unsigned int bi = 0; bi < m_battle->GetNumUsers(); bi++ )
+ {
+ User& tbot = m_battle->GetUser(bi);
+ if ( &tbot == 0 ) continue;
+ if ( (tbot.BattleStatus().pos.x == m_map.info.positions[i].x) && (tbot.BattleStatus().pos.y == m_map.info.positions[i].y) )
+ {
+ bot = &tbot;
+ break;
+ }
+ }
+
+ if ( bot != 0 ) continue;
+
+ dc.DrawBitmap( *m_start_ally, x+mr.x, y+mr.y, true );
+ }
+ int previousteam = -1;
+ for ( unsigned int i = 0; i < m_battle->GetNumUsers(); i++ )
+ {
+ User& usr = m_battle->GetUser(i);
+ if ( &usr == 0 ) continue;
+ if ( usr.BattleStatus().spectator ) continue;
+ int currentteam = usr.BattleStatus().team;
+ if ( currentteam == previousteam ) continue;
+ else previousteam = currentteam;
+
+ bool expanded = m_user_expanded;
+ if ( !m_sp ) expanded = false;
+ DrawUser( dc, usr, (m_maction != Moved) && expanded, (m_maction == Moved) && expanded );
+
+ }
+
+}
+
+
+void MapCtrl::OnPaint( wxPaintEvent& WXUNUSED(event) )
+{
+ wxLogDebugFunc( _T("") );
+ wxPaintDC dc( this );
+
+ DrawBackground( dc );
+
+ if ( m_battle == 0 ) return;
+
+ if ( !m_minimap ) return;
+ long longval;
+ m_battle->CustomBattleOptions().getSingleValue( _T("startpostype") , OptionsWrapper::EngineOption ).ToLong( &longval );
+
+
+ if ( m_draw_start_types )
+ {
+ if ( longval == IBattle::ST_Choose )
+ {
+ DrawStartRects( dc );
+ // Draw add rect.
+ if ( m_tmp_brect.ally != -1 )
+ {
+ wxRect tmp=GetStartRect(m_tmp_brect);
+ DrawStartRect( dc, m_tmp_brect.ally, tmp, *wxWHITE, false );
+ }
+ }
+ else if ( longval == IBattle::ST_Pick )
+ {
+ DrawUserPositions( dc );
+ }
+ else
+ {
+ DrawStartPositions( dc );
+ }
+ }
+
+}
+
+
+void MapCtrl::OnResize( wxSizeEvent& /*unused*/ )
+{
+ UpdateMinimap();
+}
+
+
+void MapCtrl::OnMouseMove( wxMouseEvent& event )
+{
+ wxPoint p = event.GetPosition();
+ if ( m_battle == 0 ) return;
+ if ( p == wxDefaultPosition ) return;
+ long longval;
+ m_battle->CustomBattleOptions().getSingleValue( _T("startpostype") , OptionsWrapper::EngineOption ).ToLong( &longval );
+
+ if ( longval == IBattle::ST_Pick )
+ {
+
+ if ( !m_battle->MapExists() ) return;
+ if ( m_maction == Moved )
+ {
+ User& user = *m_user_expanded;
+ try
+ {
+ ASSERT_LOGIC( &user != 0, _T("MapCtrl::OnMouseMove(): user = 0") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ m_map = m_battle->LoadMap();
+
+ wxRect mr = GetMinimapRect();
+ wxRect r = GetUserRect( user, false );
+
+ user.BattleStatus().pos.x = (int)( ( (double)(event.GetX() - mr.x) / (double)mr.width ) * (double)m_map.info.width );
+ user.BattleStatus().pos.y = (int)( ( (double)(event.GetY() - mr.y) / (double)mr.height ) * (double)m_map.info.height );
+ user.BattleStatus().pos.x = clamp( user.BattleStatus().pos.x, 0, m_map.info.width );
+ user.BattleStatus().pos.y = clamp( user.BattleStatus().pos.y, 0, m_map.info.height );
+
+ int x, y, index, range;
+ GetClosestStartPos( user.BattleStatus().pos.x, user.BattleStatus().pos.y, index, x, y, range );
+ if ( index != -1 )
+ {
+ if ( range < (10.0 / (double)mr.width) * (double)m_map.info.width )
+ {
+ user.BattleStatus().pos.x = x;
+ user.BattleStatus().pos.y = y;
+ }
+ }
+ RefreshRect( r.Union( GetUserRect( user, false ) ), false );
+ return;
+ }
+
+ if ( !m_user_expanded || !m_battle->UserExists( m_user_expanded->GetNick() ) ) m_user_expanded = 0;
+
+ if ( m_user_expanded )
+ {
+ User& user = *m_user_expanded;
+ try
+ {
+ ASSERT_LOGIC( &user != 0, _T("MapCtrl::OnMouseMove(): user = 0") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ wxRect r = GetUserRect( user, true );
+ if ( r.Contains( event.GetX(), event.GetY() ) )
+ {
+ RectangleArea last = m_rect_area;
+ m_rect_area = GetUserRectArea( r, event.GetX(), event.GetY() );
+ if ( last != m_rect_area ) RefreshRect( r, false );
+ }
+ else
+ {
+ m_user_expanded = 0;
+ RefreshRect( r, false );
+ }
+ }
+ else
+ {
+ for ( unsigned int i = 0; i < m_battle->GetNumUsers(); i++ )
+ {
+ User& user = m_battle->GetUser(i);
+ if ( &user == 0 ) continue;
+ wxRect r = GetUserRect( user, false );
+ if ( r.Contains( event.GetX(), event.GetY() ) )
+ {
+ m_rect_area = GetUserRectArea( r, event.GetX(), event.GetY() );
+ m_user_expanded = &user;
+ RefreshRect( GetUserRect( user, true ), false );
+ break;
+ }
+ }
+ }
+ return;
+ }
+
+ if ( !m_minimap )
+ {
+ wxRect r = GetRefreshRect();
+ wxRect d = GetDownloadRect();
+ RectangleArea old = m_rect_area;
+ if ( r.Contains( event.GetX(), event.GetY() ) )
+ {
+ m_rect_area = Refreshing;
+ }
+ else if ( d.Contains( event.GetX(), event.GetY() ) )
+ {
+ m_rect_area = Download;
+ }
+ else
+ {
+ m_rect_area = Main;
+ }
+ _SetCursor();
+ if ( m_rect_area != old )
+ {
+ Refresh();
+ Update();
+ }
+ return;
+ }
+
+ if ( !m_draw_start_types ) return;
+
+ if ( longval != IBattle::ST_Choose ) return;
+
+ if ( m_maction == Add )
+ { // We are currently adding a rect.
+
+ wxRect oldr = GetStartRect( m_tmp_brect );
+
+ m_tmp_brect = GetBattleRect(m_mdown_x<event.GetX()?m_mdown_x:event.GetX(),
+ m_mdown_y<event.GetY()?m_mdown_y:event.GetY(),
+ m_mdown_x>event.GetX()?m_mdown_x:event.GetX(),
+ m_mdown_y>event.GetY()?m_mdown_y:event.GetY(),
+ m_tmp_brect.ally );
+
+ wxRect newr = GetStartRect( m_tmp_brect );
+ if ( newr != oldr ) RefreshRect( newr.Union( oldr ), false );
+ return;
+
+ }
+ else if ( m_maction == ResizeDownRight )
+ {
+
+ wxRect sr = GetStartRect( m_mdown_rect );
+
+ wxRect nsr( sr.x, sr.y, event.GetX() - sr.x, event.GetY() - sr.y );
+ if ( nsr.width < minboxsize ) nsr.SetWidth( minboxsize );
+ if ( nsr.height < minboxsize ) nsr.SetHeight( minboxsize );
+ BattleStartRect bsr = GetBattleRect( nsr.x, nsr.y, nsr.x + nsr.width, nsr.y + nsr.height, m_mdown_rect );
+ m_battle->AddStartRect( m_mdown_rect, bsr.left, bsr.top, bsr.right, bsr.bottom );
+ m_battle->StartRectAdded( m_mdown_rect );
+ m_battle->ResizeStartRect( m_mdown_rect );
+
+ // ugly fix.
+ nsr = GetStartRect(bsr);
+
+ if ( sr != nsr ) RefreshRect( sr.Union( nsr ), false );
+ return;
+
+ }
+ else if ( m_maction == ResizeUpLeft )
+ {
+
+ wxRect sr = GetStartRect( m_mdown_rect );
+
+ wxRect nsr( event.GetX(), event.GetY(), (sr.x - event.GetX()) + sr.width, (sr.y - event.GetY()) + sr.height );
+ if ( nsr.width < minboxsize )
+ {
+ nsr.SetLeft( event.GetX() - minboxsize + nsr.width );
+ nsr.SetWidth( minboxsize );
+ }
+ if ( nsr.height < minboxsize )
+ {
+ nsr.SetTop( event.GetY() - minboxsize + nsr.height );
+ nsr.SetHeight( minboxsize );
+ }
+ BattleStartRect bsr = GetBattleRect( nsr.x, nsr.y, nsr.x + nsr.width, nsr.y + nsr.height, m_mdown_rect );
+ m_battle->AddStartRect( m_mdown_rect, bsr.left, bsr.top, bsr.right, bsr.bottom );
+ m_battle->StartRectAdded( m_mdown_rect );
+ m_battle->ResizeStartRect( m_mdown_rect );
+
+ // ugly fix.
+ nsr = GetStartRect(bsr);
+
+ if ( sr != nsr ) RefreshRect( sr.Union( nsr ), false );
+ return;
+
+ }
+
+ // Make sure point is inside minimap
+ if ( GetMinimapRect().Contains( p ) )
+ {
+
+ // Check if point is in a startrect.
+ for ( int i = m_battle->GetLastRectIdx(); i >= 0; i-- )
+ {
+
+ wxRect r = GetStartRect( i );
+ if ( r.IsEmpty() ) continue;
+
+ if ( r.Contains( p ) )
+ {
+
+ if ( !m_ro )
+ {
+ if ( (wxRect( r.x + r.width - m_close_img->GetWidth(), r.y + 1, m_close_img->GetWidth(), m_close_img->GetWidth() )).Contains( p ) ) m_rect_area = UpRight;
+ else if ( (wxRect( r.x, r.y, boxsize, boxsize )).Contains( p ) ) m_rect_area = UpLeft;
+ else if ( (wxRect( r.x + r.width - boxsize, r.y + r.height - boxsize, boxsize, boxsize )).Contains( p ) ) m_rect_area = DownRight;
+ //else if ( (wxRect( r.x, r.y + r.height - boxsize, boxsize, boxsize )).Contains( p ) ) m_rect_area = DownLeft;
+ else m_rect_area = Main;
+ }
+ SetMouseOverRect( i );
+
+ return;
+
+ }
+
+ }
+ if ( m_mover_rect != -1 ) SetMouseOverRect( -1 );
+
+ }
+ else
+ {
+ if ( m_mover_rect != -2 ) SetMouseOverRect( -2 );
+ }
+
+}
+
+
+void MapCtrl::OnLeftDown( wxMouseEvent& event )
+{
+ if ( m_battle == 0 ) return;
+
+ long longval;
+ m_battle->CustomBattleOptions().getSingleValue( _T("startpostype") , OptionsWrapper::EngineOption ).ToLong( &longval );
+
+ if ( !m_ro )
+ {
+ if ( longval == IBattle::ST_Pick )
+ {
+ if ( m_user_expanded ) m_mdown_area = m_rect_area;
+ else return;
+ if ( m_mdown_area == Move ) m_maction = Moved;
+ else m_maction = None;
+ User& user = *m_user_expanded;
+ try
+ {
+ ASSERT_LOGIC( &user != 0, _T("MapCtrl::OnLeftDown(): user = 0") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ RefreshRect( GetUserRect( user, true ), false );
+ return;
+ }
+ }
+
+ if ( !m_minimap )
+ {
+ if ( m_rect_area != Main )
+ {
+ m_mdown_area = m_rect_area;
+ Refresh();
+ Update();
+ }
+ return;
+ }
+
+ if ( !m_draw_start_types ) return;
+
+ if ( longval != IBattle::ST_Choose ) return;
+ if ( !m_ro )
+ {
+ // In edit mode
+ if ( m_mover_rect >= 0 )
+ { // We are over an existing rect.
+
+ m_mdown_area = m_rect_area;
+ m_mdown_rect = m_mover_rect;
+ m_mdown_x = event.GetX();
+ m_mdown_y = event.GetY();
+
+ if ( m_mdown_area == UpLeft )
+ {
+ m_maction = ResizeUpLeft;
+ }
+ else if ( m_mdown_area == UpRight )
+ {
+ m_maction = Delete;
+ }
+ else if ( m_mdown_area == DownLeft )
+ {
+// m_maction = ResizeDownLeft;
+ }
+ else if ( m_mdown_area == DownRight )
+ {
+ m_maction = ResizeDownRight;
+ }
+ else if ( m_mdown_area == Main )
+ {
+ m_maction = Moved;
+ }
+
+ }
+ else if ( m_mover_rect == -1 )
+ { // We are over empty minimap area.
+
+ m_maction = Add; // Add new start rect.
+ m_mdown_x = event.GetX();
+ m_mdown_y = event.GetY();
+ m_tmp_brect.ally = GetNewRectIndex();
+
+ }
+ else if ( m_mover_rect == -2 )
+ { // We are outside the minimap.
+
+ }
+ }
+ else
+ {
+ // Readonly.
+ if ( m_mover_rect >= 0 )
+ {
+ // Join ally rect that user clicked on
+ m_battle->GetMe().BattleStatus().ally = m_mover_rect;
+
+ }
+ m_maction = None;
+ }
+}
+
+
+void MapCtrl::OnLeftUp( wxMouseEvent& event )
+{
+ if ( m_battle == 0 ) return;
+
+ long longval;
+ m_battle->CustomBattleOptions().getSingleValue( _T("startpostype") , OptionsWrapper::EngineOption ).ToLong( &longval );
+ if ( longval == IBattle::ST_Pick )
+ {
+ if ( !m_user_expanded ) return;
+ if ( m_rect_area != m_mdown_area ) return;
+ User& user = *m_user_expanded;
+ try
+ {
+ ASSERT_LOGIC( &user != 0, _T("MapCtrl::OnLeftUp(): user == 0") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ if ( ( m_mdown_area == Move ) && ( m_maction == Moved ) )
+ {
+ m_battle->UserPositionChanged( user );
+ }
+ else if ( m_mdown_area == UpAllyButton )
+ {
+ user.BattleStatus().ally = ( user.BattleStatus().ally + 1 ) % SPRING_MAX_ALLIES;
+ RefreshRect( GetUserRect( user, true ), false );
+
+ }
+ else if ( m_mdown_area == DownAllyButton )
+ {
+ user.BattleStatus().ally = (user.BattleStatus().ally - 1) >= 0 ? (user.BattleStatus().ally - 1) : ( SPRING_MAX_ALLIES -1 );
+ RefreshRect( GetUserRect( user, true ), false );
+
+ }
+ else if ( m_mdown_area == UpHandicapButton )
+ {
+ if ( user.BattleStatus().handicap == 100 ) user.BattleStatus().handicap = 0;
+ else user.BattleStatus().handicap = ( user.BattleStatus().handicap + 5 );
+ RefreshRect( GetUserRect( user, true ), false );
+
+ }
+ else if ( m_mdown_area == DownHandicapButton )
+ {
+ user.BattleStatus().handicap = (user.BattleStatus().handicap - 5) >= 0 ? (user.BattleStatus().handicap - 5) : 100;
+ RefreshRect( GetUserRect( user, true ), false );
+
+ }
+ else if ( m_mdown_area == Side )
+ {
+ try
+ {
+ wxArrayString sides = usync().GetSides( m_battle->GetHostModName() );
+ unsigned int sidecount = sides.GetCount();
+ if ( sidecount > 0 ) user.BattleStatus().side = (user.BattleStatus().side + 1) % sidecount;
+ else user.BattleStatus().side = 0;
+ }
+ catch (...) {}
+ RefreshRect( GetUserRect( user, true ), false );
+
+ }
+ else if ( m_mdown_area == Close && m_user_expanded != &m_battle->GetMe() )
+ {
+ wxRect r = GetUserRect( user, true );
+ m_battle->KickPlayer( user );
+ RefreshRect( r, false );
+ m_user_expanded = 0;
+ }
+ m_mdown_area = Main;
+ m_maction = None;
+ return;
+ }
+
+ if ( !m_minimap )
+ {
+ if ( m_mdown_area == m_rect_area )
+ {
+ if ( m_mdown_area == Refreshing )
+ {
+ m_ui.ReloadUnitSync();
+ m_battle->Update( wxString::Format( _T("%d_mapname"), OptionsWrapper::PrivateOptions ) );
+ UpdateMinimap();
+ }
+ else if ( m_mdown_area == Download )
+ {
+ m_ui.DownloadMap( m_battle->GetHostMapHash(), m_battle->GetHostMapName() );
+ }
+ }
+ m_mdown_area = Main;
+ Refresh();
+ Update();
+ return;
+ }
+
+ if ( !m_draw_start_types ) return;
+
+ if ( longval != IBattle::ST_Choose ) return;
+
+ if ( m_maction == Add )
+ {
+
+ m_tmp_brect.ally = -1;
+ if ( ( abs( m_mdown_x - event.GetX() ) >= minboxsize ) && ( abs( m_mdown_y - event.GetY() ) >= minboxsize ) )
+ {
+ BattleStartRect r = GetBattleRect( m_mdown_x<event.GetX()?m_mdown_x:event.GetX(), m_mdown_y<event.GetY()?m_mdown_y:event.GetY(), m_mdown_x>event.GetX()?m_mdown_x:event.GetX(), m_mdown_y>event.GetY()?m_mdown_y:event.GetY() );
+ m_battle->AddStartRect( GetNewRectIndex(), r.left, r.top, r.right, r.bottom );
+ }
+ else
+ {
+ BattleStartRect r = GetBattleRect( m_mdown_x, m_mdown_y, m_mdown_x + minboxsize, m_mdown_y + minboxsize );
+ m_battle->AddStartRect( GetNewRectIndex(), r.left, r.top, r.right, r.bottom );
+ }
+ m_battle->SendHostInfo( IBattle::HI_StartRects );
+ UpdateMinimap();
+ }
+ else if ( m_maction == Delete )
+ {
+
+ if ( (m_mdown_area == m_rect_area) && (m_mover_rect == m_mdown_rect) )
+ {
+ m_battle->RemoveStartRect( m_mdown_rect );
+ UpdateMinimap();
+ m_battle->SendHostInfo( IBattle::HI_StartRects );
+ }
+
+ }
+ else if ( (m_maction == ResizeDownRight)||(m_maction == ResizeUpLeft) )
+ {
+ m_battle->ResizeStartRect( m_mdown_rect );
+ m_battle->SendHostInfo( IBattle::HI_StartRects );
+ }
+
+ m_maction = None;
+
+}
+
+
+void MapCtrl::OnMouseWheel( wxMouseEvent& event )
+{
+ if (m_metalmap)
+ {
+ int idx = (int) m_current_infomap;
+ if (event.m_wheelRotation > 0)
+ {
+ ++idx;
+ if (idx >= IM_Count)
+ idx = IM_Minimap;
+ }
+ else
+ {
+ --idx;
+ if (idx < IM_Minimap)
+ idx = IM_Count - 1;
+ }
+ m_current_infomap = (InfoMap) idx;
+ Refresh();
+ Update();
+ }
+}
+
+
+void MapCtrl::OnGetMapImageAsyncCompleted( wxCommandEvent& event )
+{
+ wxLogDebugFunc( _T("") );
+
+ wxString mapname = event.GetString();
+
+ if ( mapname != m_mapname ) return;
+
+ const int w = m_lastsize.GetWidth();
+ const int h = m_lastsize.GetHeight();
+
+ if ( m_minimap == NULL )
+ {
+ m_minimap = new wxBitmap( usync().GetMinimap( m_mapname, w, h ) );
+ // this ensures metalmap and heightmap aren't loaded in battlelist
+ if (m_draw_start_types && usync().VersionSupports(IUnitSync::USYNC_GetInfoMap))
+ m_async.GetMetalmap( m_mapname, w, h );
+ }
+ else if ( m_metalmap == NULL )
+ {
+ m_metalmap = new wxBitmap( usync().GetMetalmap( m_mapname, w, h ) );
+ // singleplayer mode doesn't allow startboxes anyway
+ m_metalmap_cumulative = usync().GetMetalmap( m_mapname );
+ Accumulate( m_metalmap_cumulative );
+ m_async.GetHeightmap( m_mapname, w, h );
+ }
+ else if ( m_heightmap == NULL )
+ {
+ m_heightmap = new wxBitmap( usync().GetHeightmap( m_mapname, w, h ) );
+ }
+
+ Refresh();
+ Update();
+}
diff --git a/src/mapctrl.h b/src/mapctrl.h
new file mode 100644
index 0000000..9529b57
--- /dev/null
+++ b/src/mapctrl.h
@@ -0,0 +1,238 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MAPCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_MAPCTRL_H
+
+#include <wx/image.h>
+#include <wx/string.h>
+
+#include "ibattle.h"
+#include "iunitsync.h"
+
+class wxPanel;
+class wxBitmap;
+class wxDC;
+
+class Battle;
+struct BattleStartRect;
+class SinglePlayerBattle;
+class Ui;
+struct UnitSyncMap;
+class BattleRoomTab;
+
+class MapCtrl : public wxPanel
+{
+
+ enum RectangleArea
+ {
+ Main = -1,
+ UpLeft,
+ UpRight,
+ DownRight,
+ DownLeft,
+ UpAllyButton,
+ DownAllyButton,
+ Side,
+ UpHandicapButton,
+ DownHandicapButton,
+ Handicap,
+ Close,
+ Move,
+ Download,
+ Refreshing
+ };
+
+ enum MouseAction
+ {
+ None,
+ Add,
+ Delete,
+ Moved,
+ ResizeUpLeft,
+ ResizeUpRight,
+ ResizeDownLeft,
+ ResizeDownRight
+ };
+
+ enum UserRectOrientation
+ {
+ TopLeft,
+ BottomLeft,
+ TopRight,
+ BottomRight
+ };
+
+
+ public:
+ MapCtrl( wxWindow* parent, int size, IBattle* battle, Ui& ui, bool readonly, bool fixed_size, bool draw_start_types, bool singleplayer );
+ ~MapCtrl();
+
+ void SetBattle( IBattle* battle );
+
+ void UpdateMinimap();
+
+ void OnPaint( wxPaintEvent& event );
+ void OnResize( wxSizeEvent& event );
+
+ void OnMouseMove( wxMouseEvent& event );
+ void OnLeftDown( wxMouseEvent& event );
+ void OnLeftUp( wxMouseEvent& event );
+ void OnMouseWheel( wxMouseEvent& event );
+
+ void OnGetMapImageAsyncCompleted( wxCommandEvent& event );
+
+ protected:
+
+ int LoadMinimap();
+ void FreeMinimap();
+
+ BattleStartRect GetBattleRect( int x1, int y1, int x2, int y2, int ally = -1 );
+
+ /** Get the rect occupied by the minimap.
+ *
+ * @see GetDrawableRect
+ */
+ wxRect GetMinimapRect() const;
+
+ /** Get the widget-drawable area as a wxRect. This is similar to
+ * GetMinimapRect, but includes the area not filled by the minimap.
+ *
+ * @return The wxRect corresponding {0, 0, ClientWidth, ClientHeight}.
+ *
+ * @see GetMinimapRect, wxWindow::GetClientSize
+ */
+ wxRect GetDrawableRect() const;
+
+ wxRect GetStartRect( int index );
+ wxRect GetStartRect( const BattleStartRect& sr );
+ void Accumulate( wxImage& image );
+ double GetStartRectMetalFraction( int index );
+ double GetStartRectMetalFraction( const BattleStartRect& sr );
+
+ void DrawOutlinedText( wxDC& dc, const wxString& str, int x, int y, const wxColour& outline, const wxColour& font );
+
+ /** Get the relative (range: [0.0,1.0]) x- and y- coordinates of
+ * the user's start position.
+ */
+ wxRealPoint GetUserMapPositionAsReal(const User& user) const;
+
+ /** Get an absolute (relative to the client's [*this* MapCtrl
+ * widget's] drawable area) user map position.
+ *
+ * The returned point is as would be used with wxDC methods.
+ */
+ wxPoint GetTranslatedScaledUserMapPosition(const User& user) const;
+
+ wxRect GetUserRect( const User& user, bool selected );
+ RectangleArea GetUserRectArea( const wxRect& userrect, int x, int y );
+
+ wxRect GetUserSideRect() { return wxRect( 37, 20, 16, 16 ); }
+ wxRect GetUserHandicapRect() { return wxRect( 40, 55, 16, 16 ); }
+ wxRect GetUserCloseRect() { return wxRect( 59, 4, 14, 14 ); }
+ wxRect GetUserUpAllyButtonRect() { return wxRect( 61, 35, 12, 8 ); }
+ wxRect GetUserDownAllyButtonRect() { return wxRect( 61, 43, 12, 8 ); }
+ wxRect GetUserUpHandicapButtonRect() { return wxRect( 61, 52, 12, 8 ); }
+ wxRect GetUserDownHandicapButtonRect() { return wxRect( 61, 60, 12, 8 ); }
+
+ wxRect GetRefreshRect();
+ wxRect GetDownloadRect();
+
+ unsigned int GetNewRectIndex();
+
+ void RequireImages();
+
+ void RelocateUsers();
+
+ void GetClosestStartPos( int fromx, int fromy, int& index, int& x, int& y, int& range );
+
+ void DrawUser( wxDC& dc, User& user, bool selected, bool moving );
+ void DrawUserPositions( wxDC& dc );
+ void DrawBackground( wxDC& dc );
+ void DrawStartRects( wxDC& dc );
+ void DrawStartPositions( wxDC& dc );
+ void DrawStartRect( wxDC& dc, int index, wxRect& sr, const wxColour& col, bool mouseover, int alphalevel = 70, bool forceInsideMinimap = true );
+
+ void SetMouseOverRect( int index );
+
+ void _SetCursor();
+
+ UnitSyncAsyncOps m_async;
+
+ wxBitmap* m_minimap;
+ wxBitmap* m_metalmap;
+ wxBitmap* m_heightmap;
+ wxImage m_metalmap_cumulative;
+
+ IBattle* m_battle;
+
+ Ui& m_ui;
+ wxString m_mapname;
+
+ bool m_draw_start_types;
+ bool m_fixed_size;
+ bool m_ro;
+ bool m_sp;
+
+ int m_mover_rect;
+ int m_mdown_rect;
+
+ RectangleArea m_rect_area;
+ RectangleArea m_last_rect_area;
+
+ RectangleArea m_mdown_area;
+ BattleStartRect m_tmp_brect;
+
+ MouseAction m_maction;
+ int m_mdown_x;
+ int m_mdown_y;
+
+ wxSize m_lastsize;
+
+ wxBitmap* m_close_img;
+ wxBitmap* m_close_hi_img;
+
+ wxBitmap* m_start_ally;
+ wxBitmap* m_start_enemy;
+ wxBitmap* m_start_unused;
+
+ wxBitmap* m_player_img;
+ wxBitmap* m_bot_img;
+
+ wxBitmap* m_nfound_img;
+ wxBitmap* m_reload_img;
+ wxBitmap* m_dl_img;
+
+ UnitSyncMap m_map;
+
+ User* m_user_expanded;
+
+ enum InfoMap
+ {
+ IM_Minimap, // must be first one
+ IM_Metalmap, // entries must be consecutively numbered (without gaps)
+ IM_Heightmap,
+ IM_Count, // must be last one
+ };
+
+ InfoMap m_current_infomap;
+
+ DECLARE_EVENT_TABLE();
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_MAPCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mapgridctrl.cpp b/src/mapgridctrl.cpp
new file mode 100644
index 0000000..1867679
--- /dev/null
+++ b/src/mapgridctrl.cpp
@@ -0,0 +1,571 @@
+/* Copyright (C) 2008 The SpringLobby Team. All rights reserved. */
+/* Author: Tobi Vollebregt */
+
+#include "mapgridctrl.h"
+
+#include "settings.h"
+#include "uiutils.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include <wx/dcbuffer.h>
+#include <wx/geometry.h>
+#include <wx/settings.h>
+#include <algorithm>
+#include <wx/log.h>
+
+#include "images/map_select_1.png.h"
+#include "images/map_select_2.png.h"
+
+/// Size of the map previews. This should be same as size of map previews in
+/// battle list and as prefetch size in SpringUnitSync for performance reasons.
+#define MINIMAP_SIZE 98
+
+/// Margin between the map previews, in pixels.
+#define MINIMAP_MARGIN 1
+
+/// Maximum minimap fetches in WorkerThread queue
+/// (these will still be executed after control is destroyed)
+#define MAX_MINIMAP_FETCHES 2
+/// Maximum mapinfo fetches in WorkerThread queue
+#define MAX_MAPINFO_FETCHES 5
+
+
+BEGIN_EVENT_TABLE( MapGridCtrl, wxPanel )
+ EVT_PAINT( MapGridCtrl::OnPaint )
+ EVT_SIZE( MapGridCtrl::OnResize )
+ EVT_MOTION( MapGridCtrl::OnMouseMove )
+ EVT_LEFT_DOWN( MapGridCtrl::OnLeftDown )
+ EVT_LEFT_UP( MapGridCtrl::OnLeftUp )
+ EVT_COMMAND( 2, UnitSyncAsyncOperationCompletedEvt, MapGridCtrl::OnGetMapImageAsyncCompleted )
+ EVT_COMMAND( 3, UnitSyncAsyncOperationCompletedEvt, MapGridCtrl::OnGetMapExAsyncCompleted )
+END_EVENT_TABLE()
+
+
+const wxEventType MapGridCtrl::MapSelectedEvt = wxNewEventType();
+const wxEventType MapGridCtrl::LoadingCompletedEvt = wxNewEventType();
+
+
+MapGridCtrl::MapGridCtrl( wxWindow* parent, Ui& ui, wxSize size, wxWindowID id )
+ : wxPanel( parent, id, wxDefaultPosition, size, wxSIMPLE_BORDER|wxFULL_REPAINT_ON_RESIZE )
+ , m_ui( ui )
+ , m_async( this )
+ , m_selection_follows_mouse( sett().GetMapSelectorFollowsMouse() )
+ , m_size( 0, 0 )
+ , m_pos( 0, 0 )
+ , m_in_mouse_drag( false )
+ , m_async_mapinfo_fetches( 0 )
+ , m_async_minimap_fetches( 0 )
+ , m_mouseover_map( NULL )
+ , m_selected_map( NULL )
+{
+ SetBackgroundStyle( wxBG_STYLE_CUSTOM );
+ SetBackgroundColour( *wxLIGHT_GREY );
+
+ m_img_background.Create( MINIMAP_SIZE, MINIMAP_SIZE, false /*don't clear*/ );
+ wxRect rect( 0, 0, MINIMAP_SIZE, MINIMAP_SIZE );
+ wxColour color( GetBackgroundColour() );
+ m_img_background.SetRGB( rect, color.Red(), color.Green(), color.Blue() );
+
+ m_img_minimap_alpha = charArr2wxImage( map_select_1_png, sizeof(map_select_1_png) );
+ m_img_foreground = charArr2wxImage( map_select_2_png, sizeof(map_select_2_png) );
+
+ ASSERT_EXCEPTION( m_img_minimap_alpha.HasAlpha(), _T("map_select_1_png must have an alpha channel") );
+ ASSERT_EXCEPTION( m_img_foreground.HasAlpha(), _T("map_select_2_png must have an alpha channel") );
+
+ m_img_minimap_loading = wxBitmap( BlendImage( m_img_foreground, m_img_background, false ) );
+}
+
+
+MapGridCtrl::~MapGridCtrl()
+{
+
+}
+
+
+#define CMP( var ) \
+ if ( a->info.var < b->info.var ) return -1; \
+ if ( a->info.var > b->info.var ) return 1; \
+ return 0
+
+#define CMP2( a, b ) \
+ if ( (a) < (b) ) return -1; \
+ if ( (a) > (b) ) return 1; \
+ return 0
+
+inline int MapGridCtrl::CompareName( const MapData* a, const MapData* b )
+{
+ return a->name.CmpNoCase( b->name );
+}
+inline int MapGridCtrl::CompareTidalStrength( const MapData* a, const MapData* b )
+{
+ CMP( tidalStrength );
+}
+inline int MapGridCtrl::CompareGravity( const MapData* a, const MapData* b )
+{
+ CMP( gravity );
+}
+inline int MapGridCtrl::CompareMaxMetal( const MapData* a, const MapData* b )
+{
+ CMP( maxMetal );
+}
+inline int MapGridCtrl::CompareExtractorRadius( const MapData* a, const MapData* b )
+{
+ CMP( extractorRadius );
+}
+inline int MapGridCtrl::CompareMinWind( const MapData* a, const MapData* b )
+{
+ CMP( minWind );
+}
+inline int MapGridCtrl::CompareMaxWind( const MapData* a, const MapData* b )
+{
+ CMP( maxWind );
+}
+inline int MapGridCtrl::CompareWind( const MapData* a, const MapData* b )
+{
+ CMP2( (a->info.minWind + a->info.maxWind), (b->info.minWind + b->info.maxWind) );
+}
+inline int MapGridCtrl::CompareArea( const MapData* a, const MapData* b )
+{
+ CMP2( (a->info.width * a->info.height), (b->info.width * b->info.height) );
+}
+static inline double AspectRatio( const MapInfo& x )
+{
+ const int max = std::max( x.width, x.height );
+ const int min = std::min( x.width, x.height );
+ return (double) max / (min != 0 ? min : 1);
+}
+inline int MapGridCtrl::CompareAspectRatio( const MapData* a, const MapData* b )
+{
+ CMP2( AspectRatio( a->info ), AspectRatio( b->info ) );
+}
+inline int MapGridCtrl::ComparePosCount( const MapData* a, const MapData* b )
+{
+ CMP( posCount );
+}
+
+#undef CMP2
+#undef CMP
+
+template< class Compare > inline void MapGridCtrl::_Sort( int dimension, Compare cmp )
+{
+ if ( dimension <= 1 ) {
+ // vertical sort (ie. sort entire dataset)
+ std::stable_sort( m_grid.begin(), m_grid.end(), cmp );
+ }
+ else /*if ( dimension == 2 )*/ {
+ // horizontal sort (ie. sort each row individually)
+ for ( int y = 0; y < m_size.y; ++y ) {
+ const int idx1 = y * m_size.x;
+ const int idx2 = std::min( int(m_grid.size()), idx1 + m_size.x );
+ std::stable_sort( m_grid.begin() + idx1, m_grid.begin() + idx2, cmp );
+ }
+ }
+}
+
+
+void MapGridCtrl::Sort( SortKey vertical, SortKey horizontal, bool vertical_direction, bool horizontal_direction )
+{
+ if ( m_maps.empty() ) return;
+
+ // Always start by sorting on name, to get duplicate maps together.
+ SortKey keys[3] = { SortKey_Name, vertical, horizontal };
+ bool dirs[3] = { false, vertical_direction, horizontal_direction };
+
+ // This looks like common antipattern 'loop switch sequence', however here
+ // it's the best way I found to prevent duplication of the switch statement,
+ // which will probably require most (all?) changes and possibly grow big.
+
+ for (int i = 0; i < 3; ++i) {
+ // Do nothing if current sortkey is same as previous one.
+ if ( i > 0 && keys[i] == keys[i - 1] && dirs[i] == dirs[i - 1] ) continue;
+ // Sort dimension i on sortkey keys[i].
+ const bool d = dirs[i];
+ switch ( keys[i] ) {
+ case SortKey_Name: _Sort( i, _Compare( d, CompareName ) ); break;
+ case SortKey_TidalStrength: _Sort( i, _Compare( d, CompareTidalStrength ) ); break;
+ case SortKey_Gravity: _Sort( i, _Compare( d, CompareGravity ) ); break;
+ case SortKey_MaxMetal: _Sort( i, _Compare( d, CompareMaxMetal ) ); break;
+ case SortKey_ExtractorRadius: _Sort( i, _Compare( d, CompareExtractorRadius ) ); break;
+ case SortKey_MinWind: _Sort( i, _Compare( d, CompareMinWind ) ); break;
+ case SortKey_MaxWind: _Sort( i, _Compare( d, CompareMaxWind ) ); break;
+ case SortKey_Wind: _Sort( i, _Compare( d, CompareWind ) ); break;
+ case SortKey_Area: _Sort( i, _Compare( d, CompareArea ) ); break;
+ case SortKey_AspectRatio: _Sort( i, _Compare( d, CompareAspectRatio ) ); break;
+ case SortKey_PosCount: _Sort( i, _Compare( d, ComparePosCount ) ); break;
+ default:
+ ASSERT_EXCEPTION( false, _T("unimplemented SortKey in MapGridCtrl::Sort") );
+ break;
+ }
+ }
+}
+
+
+void MapGridCtrl::Clear()
+{
+ m_maps_unused.insert( m_maps.begin(), m_maps.end() );
+ m_maps_unused.insert( m_maps_filtered.begin(), m_maps_filtered.end() );
+ m_pending_maps.clear();
+ m_maps.clear();
+ m_maps_filtered.clear();
+ m_grid.clear();
+ m_mouseover_map = NULL; // can't be sure pointer will stay valid
+ m_selected_map = NULL;
+}
+
+
+void MapGridCtrl::AddMap( const wxString& mapname )
+{
+ // no duplicates (would crash because of dangling MapData pointers in m_grid)
+ if ( m_maps.find( mapname ) != m_maps.end() ) return;
+
+ // check if we still have it in m_maps_unused..
+ MapMap::iterator it = m_maps_unused.find( mapname );
+ if ( it != m_maps_unused.end() ) {
+ m_maps.insert( *it );
+ m_grid.push_back( &m_maps[mapname] );
+ m_maps_unused.erase( it );
+ UpdateGridSize();
+ return;
+ }
+
+ // if not, get it from unitsync
+ FetchMapInfo( mapname );
+}
+
+
+void MapGridCtrl::AddMap( const UnitSyncMap& map )
+{
+ // no duplicates (would crash because of dangling MapData pointers in m_grid)
+ if ( m_maps.find( map.name ) != m_maps.end() ) return;
+ // don't want map to exist in both m_maps and m_maps_unused.
+ m_maps_unused.erase( map.name );
+
+ m_maps[map.name] = map;
+ m_grid.push_back( &m_maps[map.name] );
+ UpdateGridSize();
+}
+
+
+void MapGridCtrl::UpdateGridSize()
+{
+ // recalculate grid size (keep it approximately square)
+ const int width = int(sqrt( double(m_maps.size()) ) + 0.5);
+ m_size.x = width;
+ m_size.y = (m_maps.size() + width - 1) / width;
+ CheckInBounds();
+}
+
+
+void MapGridCtrl::CheckInBounds()
+{
+ const int size = MINIMAP_SIZE + MINIMAP_MARGIN;
+
+ int width, height;
+ GetClientSize( &width, &height );
+
+ // this ensures always at least a quarter of the client area contains minimaps
+ //m_pos.x = std::max( -width / 2, std::min( size * m_size.x - width / 2, m_pos.x ) );
+ //m_pos.y = std::max( -height / 2, std::min( size * m_size.y - height / 2, m_pos.y ) );
+
+ // this ensures the maps are centered when they fit on the screen,
+ // otherwise it ensures the entire client area contains minimaps.
+ if ( width / size >= m_size.x )
+ m_pos.x = -(width - m_size.x * size) / 2;
+ else
+ m_pos.x = std::max( -1, std::min( size * m_size.x - width, m_pos.x ) );
+
+ if ( height / size >= m_size.y )
+ m_pos.y = -(height - m_size.y * size) / 2;
+ else
+ m_pos.y = std::max( -1, std::min( size * m_size.y - height, m_pos.y ) );
+}
+
+
+void MapGridCtrl::UpdateAsyncFetches()
+{
+ while ( m_async_mapinfo_fetches < MAX_MAPINFO_FETCHES && !m_pending_maps.empty() ) {
+ wxString mapname = m_pending_maps.back();
+ m_pending_maps.pop_back();
+ FetchMapInfo( mapname );
+ }
+
+ // no minimap fetches until all mapinfo fetches are finished
+ if ( m_async_mapinfo_fetches == 0 && m_async_minimap_fetches == 0 ) {
+ for (int y = 0; y < m_size.y; ++y) {
+ for (int x = 0; x < m_size.x; ++x) {
+ const int idx = y * m_size.x + x;
+ if ( idx >= int(m_grid.size()) ) break;
+ if ( m_grid[idx]->state == MapState_NoMinimap ) {
+ FetchMinimap( *m_grid[idx] );
+ return;
+ }
+ }
+ }
+ }
+}
+
+
+void MapGridCtrl::FetchMapInfo( const wxString& mapname )
+{
+ if ( m_async_mapinfo_fetches < MAX_MAPINFO_FETCHES ) {
+ m_async.GetMapEx( mapname );
+ ++m_async_mapinfo_fetches;
+ }
+ else {
+ m_pending_maps.push_back( mapname );
+ }
+}
+
+
+void MapGridCtrl::FetchMinimap( MapData& map )
+{
+ // must be finished fetching mapinfos
+ if ( m_async_mapinfo_fetches == 0 && m_async_minimap_fetches < MAX_MINIMAP_FETCHES ) {
+ m_async.GetMinimap( map.name, MINIMAP_SIZE, MINIMAP_SIZE );
+ map.state = MapState_GetMinimap;
+ ++m_async_minimap_fetches;
+ }
+}
+
+
+void MapGridCtrl::DrawMap( wxDC& dc, MapData& map, int x, int y )
+{
+ switch ( map.state ) {
+ case MapState_NoMinimap:
+ FetchMinimap( map );
+ // fall through, both when starting fetch and when waiting
+ // for it to finish, we want to show temporary image
+ case MapState_GetMinimap:
+ // draw temporary image while waiting for async fetch of minimap
+ dc.DrawBitmap( m_img_minimap_loading, x, y );
+ break;
+ case MapState_GotMinimap:
+ x += (MINIMAP_SIZE - map.minimap.GetWidth()) / 2;
+ y += (MINIMAP_SIZE - map.minimap.GetHeight()) / 2;
+ dc.DrawBitmap( map.minimap, x, y, false );
+ // draw selection
+ if ( &map == m_selected_map ) {
+ dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) ) );
+ dc.SetBrush( wxBrush( wxColour(0, 0, 0), wxTRANSPARENT ) );
+ dc.DrawRectangle( x - 1, y - 1, map.minimap.GetWidth() + 2, map.minimap.GetHeight() + 2 );
+ }
+ break;
+ default:
+ wxLogError( _T("unknonw map.state in MapGridCtrl::DrawMap") );
+ break;
+ }
+}
+
+
+void MapGridCtrl::DrawBackground( wxDC& dc )
+{
+ int width, height;
+ GetClientSize( &width, &height );
+
+ dc.SetPen( wxPen( *wxLIGHT_GREY ) );
+ dc.SetBrush( wxBrush( *wxLIGHT_GREY, wxSOLID ) );
+
+ dc.DrawRectangle( 0, 0, width, height );
+}
+
+
+void MapGridCtrl::OnPaint( wxPaintEvent& /*unused*/ )
+{
+ // This line must come first, to avoid an endless succession of paint messages.
+ // OnPaint handlers must always create a wxPaintDC.
+
+ wxAutoBufferedPaintDC dc( this );
+
+ DrawBackground( dc );
+
+ if ( m_maps.empty() ) return;
+
+ int width, height;
+ GetClientSize( &width, &height );
+
+ const int size = MINIMAP_SIZE + MINIMAP_MARGIN;
+
+ // simple tile mapping algorithm
+ int start_scrn_x = -(m_pos.x % size);
+ int start_scrn_y = -(m_pos.y % size);
+ int start_grid_x = m_pos.x / size;
+ int start_grid_y = m_pos.y / size;
+ int end_grid_x = std::min(start_grid_x + (width + 2 * size - 1) / size, m_size.x);
+ int end_grid_y = std::min(start_grid_y + (height + 2 * size - 1) / size, m_size.y);
+
+ if ( start_grid_x < 0 ) {
+ start_scrn_x += size * -start_grid_x;
+ start_grid_x = 0;
+ }
+
+ if ( start_grid_y < 0 ) {
+ start_scrn_y += size * -start_grid_y;
+ start_grid_y = 0;
+ }
+
+ for (int y = start_grid_y, scrn_y = start_scrn_y; y < end_grid_y; ++y, scrn_y += size) {
+ for (int x = start_grid_x, scrn_x = start_scrn_x; x < end_grid_x; ++x, scrn_x += size) {
+ const int idx = y * m_size.x + x;
+ if ( idx >= int(m_grid.size()) ) break;
+ DrawMap( dc, *m_grid[idx], scrn_x, scrn_y );
+ }
+ }
+}
+
+
+void MapGridCtrl::OnResize( wxSizeEvent& event )
+{
+ CheckInBounds();
+}
+
+
+void MapGridCtrl::OnMouseMove( wxMouseEvent& event )
+{
+ SetCursor( wxCursor( wxCURSOR_HAND ) );
+ if ( m_in_mouse_drag ) {
+ // Fix for for not receiving LeftUp event when left button
+ // is released outside the control (happens on Windows.)
+ if ( !event.LeftIsDown() ) {
+ OnLeftUp( event );
+ return;
+ }
+
+ m_pos -= (event.GetPosition() - m_last_mouse_pos);
+ m_last_mouse_pos = event.GetPosition();
+
+ CheckInBounds();
+ Refresh();
+ }
+ else {
+ const wxPoint pos_unscaled = event.GetPosition() + m_pos;
+ const wxPoint pos = wxPoint2DInt(pos_unscaled) / (MINIMAP_SIZE + MINIMAP_MARGIN);
+ const int idx = pos.y * m_size.x + pos.x;
+ MapData* old_mouseover_map = m_mouseover_map;
+
+ // use pos_unscaled for tests against 0 because negative values lower
+ // than MINIMAP_SIZE get rounded up to 0 when diviving by MINIMAP_SIZE..
+ if ( pos_unscaled.x >= 0 && pos.x < m_size.x && pos_unscaled.y >= 0 && pos.y <= m_size.y && idx < (int)m_grid.size() ) {
+ m_mouseover_map = m_grid[idx];
+ }
+ else {
+ m_mouseover_map = NULL;
+ }
+
+ if ( m_mouseover_map != old_mouseover_map ) {
+ if ( m_selection_follows_mouse && m_mouseover_map != NULL ) {
+ SelectMap( m_mouseover_map );
+ }
+ }
+ }
+}
+
+
+void MapGridCtrl::OnLeftDown( wxMouseEvent& event )
+{
+ SetCursor( wxCursor( wxCURSOR_HAND ) );
+ m_first_mouse_pos = event.GetPosition();
+ m_last_mouse_pos = event.GetPosition();
+ m_in_mouse_drag = true;
+}
+
+
+void MapGridCtrl::OnLeftUp( wxMouseEvent& event )
+{
+ SetCursor( wxCursor( wxCURSOR_ARROW ) );
+ m_in_mouse_drag = false;
+
+ if ( wxPoint2DInt(event.GetPosition() - m_first_mouse_pos).GetVectorLength() <= 3 ) {
+ SelectMap( m_mouseover_map );
+ }
+}
+
+
+void MapGridCtrl::SelectMap( MapData* map )
+{
+ m_selected_map = map;
+
+ if ( m_selected_map != NULL ) {
+ wxLogMessage( _T("MapGridCtrl: Selected map: ") + m_selected_map->name );
+
+ wxCommandEvent evt( MapSelectedEvt, GetId() );
+ evt.SetEventObject( this );
+ evt.SetString( m_selected_map->name );
+ wxPostEvent( this, evt );
+ }
+
+ Refresh();
+}
+
+
+void MapGridCtrl::SetMinimap( MapMap& maps, const wxString& mapname, const wxBitmap& minimap )
+{
+ MapMap::iterator it = maps.find( mapname );
+
+ if ( it != maps.end() ) {
+ it->second.minimap = minimap;
+ it->second.state = MapState_GotMinimap;
+ }
+}
+
+
+void MapGridCtrl::OnGetMapImageAsyncCompleted( wxCommandEvent& event )
+{
+ wxString mapname = event.GetString();
+
+ wxLogDebugFunc( mapname );
+
+ // if mapname is empty, some error occurred in usync().GetMinimap...
+ if ( !mapname.empty() ) {
+ wxImage minimap( usync().GetMinimap( mapname, MINIMAP_SIZE, MINIMAP_SIZE ) );
+
+ const int w = minimap.GetWidth();
+ const int h = minimap.GetHeight();
+ wxImage background( BorderInvariantResizeImage( m_img_background, w, h ) );
+ wxImage minimap_alpha( BorderInvariantResizeImage( m_img_minimap_alpha, w, h ) );
+ wxImage foreground( BorderInvariantResizeImage( m_img_foreground, w, h ) );
+
+ minimap.SetAlpha( minimap_alpha.GetAlpha(), true /* "static data" */ );
+ minimap = BlendImage( minimap, background, false );
+ minimap = BlendImage( foreground, minimap, false );
+
+ // set the minimap in all MapMaps
+ wxBitmap minimap_bmp( minimap );
+ SetMinimap( m_maps, mapname, minimap_bmp );
+ SetMinimap( m_maps_unused, mapname, minimap_bmp );
+ SetMinimap( m_maps_filtered, mapname, minimap_bmp );
+
+ Refresh(); // TODO: use RefreshRect ?
+ }
+
+ --m_async_minimap_fetches;
+ UpdateAsyncFetches();
+}
+
+
+void MapGridCtrl::OnGetMapExAsyncCompleted( wxCommandEvent& event )
+{
+ wxString mapname = event.GetString();
+
+ wxLogDebugFunc( mapname );
+
+ // if mapname is empty, some error occurred in usync().GetMapEx...
+ if ( !mapname.empty() ) {
+ try {
+ AddMap( usync().GetMapEx( mapname ) );
+ }
+ catch (...) {}
+
+ Refresh();
+ }
+
+ --m_async_mapinfo_fetches;
+ UpdateAsyncFetches();
+
+ // UpdateAsyncFetches didn't start a new one, so we finished
+ // and can raise the LoadingCompletedEvt
+ if ( m_async_mapinfo_fetches == 0 ) {
+ wxCommandEvent evt( LoadingCompletedEvt, GetId() );
+ evt.SetEventObject( this );
+ wxPostEvent( this, evt );
+ }
+}
diff --git a/src/mapgridctrl.h b/src/mapgridctrl.h
new file mode 100644
index 0000000..12b4ac5
--- /dev/null
+++ b/src/mapgridctrl.h
@@ -0,0 +1,213 @@
+/* Author: Tobi Vollebregt */
+
+#ifndef SPRINGLOBBY_HEADERGUARD_MAPGRIDCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_MAPGRIDCTRL_H
+
+#include "iunitsync.h"
+#include <wx/bitmap.h>
+#include <wx/image.h>
+#include <wx/panel.h>
+
+class Ui;
+
+
+class MapGridCtrl : public wxPanel
+{
+ public:
+
+ /// this event is raised each time when a new map is selected
+ static const wxEventType MapSelectedEvt;
+ /// this event is raised after the loading of map infos finished
+ static const wxEventType LoadingCompletedEvt;
+
+ enum SortKey
+ {
+ SortKey_Name,
+ SortKey_TidalStrength,
+ SortKey_Gravity,
+ SortKey_MaxMetal,
+ SortKey_ExtractorRadius,
+ SortKey_MinWind,
+ SortKey_MaxWind,
+ SortKey_Wind, // minWind + maxWind
+ SortKey_Area, // width * height
+ SortKey_AspectRatio, // max(width/height, height/width)
+ SortKey_PosCount,
+ };
+
+ MapGridCtrl( wxWindow* parent, Ui& ui, wxSize size = wxDefaultSize, wxWindowID id = -1 );
+ ~MapGridCtrl();
+
+ void Clear();
+ void AddMap( const wxString& mapname );
+ void AddMap( const UnitSyncMap& map );
+
+ void CheckInBounds();
+
+ /* ===== sorting ===== */
+ void Sort( SortKey vertical, SortKey horizontal, bool vertical_direction = false, bool horizontal_direction = false );
+
+ /* ===== filtering ===== */
+ template< class Predicate > int Filter( Predicate pred )
+ {
+ std::vector< wxString > maps;
+
+ m_maps_filtered.insert( m_maps.begin(), m_maps.end() );
+ m_maps_unused.insert( m_maps.begin(), m_maps.end() );
+ m_maps.clear();
+ m_grid.clear();
+ m_mouseover_map = NULL; // can't be sure pointer will stay valid
+ m_selected_map = NULL;
+
+ for (MapMap::iterator it = m_maps_filtered.begin(); it != m_maps_filtered.end(); ++it) {
+ if ( pred( it->second ) ) maps.push_back( it->first );
+ }
+
+ for (std::vector< wxString >::iterator it = maps.begin(); it != maps.end(); ++it) {
+ AddMap( *it );
+ m_maps_filtered.erase( *it );
+ }
+
+ return m_maps.size();
+ }
+
+ UnitSyncMap* GetSelectedMap() const { return m_selected_map; }
+
+ void OnPaint( wxPaintEvent& event );
+ void OnResize( wxSizeEvent& event );
+
+ void OnMouseMove( wxMouseEvent& event );
+ void OnLeftDown( wxMouseEvent& event );
+ void OnLeftUp( wxMouseEvent& event );
+
+ void OnGetMapImageAsyncCompleted( wxCommandEvent& event );
+ void OnGetMapExAsyncCompleted( wxCommandEvent& event );
+
+ protected:
+
+ enum MapState
+ {
+ MapState_NoMinimap,
+ MapState_GetMinimap,
+ MapState_GotMinimap
+ };
+
+ struct MapData : UnitSyncMap
+ {
+ MapData() : state( MapState_NoMinimap ) {}
+ void operator=( const UnitSyncMap& other ) { UnitSyncMap::operator=( other ); }
+
+ wxBitmap minimap;
+ MapState state;
+ };
+
+ typedef std::map< wxString, MapData > MapMap;
+
+ // wrapper around the Compare*() methods below to allow changing sort direction
+ template< class Compare > class _Compare2
+ {
+ public:
+ _Compare2( bool direction, Compare cmp )
+ : m_cmp( cmp ), m_direction( direction ? -1 : 1 ) {}
+ bool operator()( const MapData* a, const MapData* b ) {
+ return (m_direction * m_cmp( a, b )) < 0;
+ }
+ private:
+ Compare m_cmp;
+ int m_direction;
+ };
+
+ // allow a _Compare2 to be constructed with implicit template arguments
+ template< class Compare > _Compare2< Compare > _Compare( bool direction, Compare cmp ) {
+ return _Compare2< Compare >( direction, cmp );
+ }
+
+ // comparison methods returning -1 if a < b, 1 if a > b and 0 if !(a < b) && !(a > b)
+ static int CompareName( const MapData* a, const MapData* b );
+ static int CompareTidalStrength( const MapData* a, const MapData* b );
+ static int CompareGravity( const MapData* a, const MapData* b );
+ static int CompareMaxMetal( const MapData* a, const MapData* b );
+ static int CompareExtractorRadius( const MapData* a, const MapData* b );
+ static int CompareMinWind( const MapData* a, const MapData* b );
+ static int CompareMaxWind( const MapData* a, const MapData* b );
+ static int CompareWind( const MapData* a, const MapData* b );
+ static int CompareArea( const MapData* a, const MapData* b );
+ static int CompareAspectRatio( const MapData* a, const MapData* b );
+ static int ComparePosCount( const MapData* a, const MapData* b );
+ template< class Compare > void _Sort( int dimension, Compare cmp );
+
+ void UpdateGridSize();
+ void UpdateAsyncFetches();
+ void FetchMapInfo( const wxString& mapname );
+ void FetchMinimap( MapData& map );
+ void DrawMap( wxDC& dc, MapData& map, int x, int y );
+ void DrawBackground( wxDC& dc );
+ void SetMinimap( MapMap& maps, const wxString& mapname, const wxBitmap& minimap );
+ void SelectMap( MapData* map );
+
+ Ui& m_ui;
+ UnitSyncAsyncOps m_async;
+
+ const bool m_selection_follows_mouse;
+
+ /// Set of maps which are queued to be fetched asynchronously.
+ std::vector< wxString > m_pending_maps;
+
+ MapMap m_maps;
+ MapMap m_maps_unused;
+ MapMap m_maps_filtered;
+ std::vector< MapData* > m_grid;
+ wxSize m_size;
+
+ wxPoint m_pos;
+ wxPoint m_first_mouse_pos;
+ wxPoint m_last_mouse_pos;
+ bool m_in_mouse_drag;
+
+ /// Number of async minimap fetches still running on behalf of this control.
+ /// This number is limited so SL doesn't keep fetching maps after this
+ /// control is destroyed.
+ int m_async_mapinfo_fetches;
+
+ /// Number of async minimap fetches still running on behalf of this control.
+ /// This number is limited so the control can adapt (faster) to changes in
+ /// the set of visible maps. (it fetches only visible maps)
+ int m_async_minimap_fetches;
+
+ /// Map which is currently under the mouse pointer.
+ MapData* m_mouseover_map;
+ /// Map which was last clicked.
+ MapData* m_selected_map;
+
+ /// solid color background
+ wxImage m_img_background;
+ /// map_select_1_png, alpha channel of this is attached to minimap before
+ /// blending it over m_img_background
+ wxImage m_img_minimap_alpha;
+ /// map_select_2_png, this is alpha blended on top of the minimap
+ wxImage m_img_foreground;
+ /// this is displayed for maps whose minimap has not yet been loaded
+ wxBitmap m_img_minimap_loading;
+
+ DECLARE_EVENT_TABLE();
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_MAPGRIDCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mapselectdialog.cpp b/src/mapselectdialog.cpp
new file mode 100644
index 0000000..2436825
--- /dev/null
+++ b/src/mapselectdialog.cpp
@@ -0,0 +1,439 @@
+/* Author: Tobi Vollebregt */
+
+#include "mapselectdialog.h"
+
+#include "battle.h"
+#include "server.h"
+#include "settings.h"
+#include "ui.h"
+#include "uiutils.h"
+#include "utils/controls.h"
+#include "utils/debug.h"
+#include "settings.h"
+#include <wx/settings.h>
+
+//(*InternalHeaders(MapSelectDialog)
+#include <wx/listctrl.h>
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/textctrl.h>
+#include <wx/radiobut.h>
+#include "mapgridctrl.h"
+#include <wx/choice.h>
+#include <wx/intl.h>
+#include <wx/button.h>
+#include <wx/string.h>
+//*)
+
+//(*IdInit(MapSelectDialog)
+const long MapSelectDialog::ID_STATICTEXT2 = wxNewId();
+const long MapSelectDialog::ID_VERTICAL_CHOICE = wxNewId();
+const long MapSelectDialog::ID_STATICTEXT1 = wxNewId();
+const long MapSelectDialog::ID_HORIZONTAL_CHOICE = wxNewId();
+const long MapSelectDialog::ID_FILTER_ALL = wxNewId();
+const long MapSelectDialog::ID_FILTER_POPULAR = wxNewId();
+const long MapSelectDialog::ID_FILTER_RECENT = wxNewId();
+const long MapSelectDialog::ID_FILTER_TEXT = wxNewId();
+const long MapSelectDialog::ID_MAP_NAME = wxNewId();
+const long MapSelectDialog::ID_MAP_OPTS_LIST = wxNewId();
+const long MapSelectDialog::ID_MAPGRID = wxNewId();
+//*)
+const long MapSelectDialog::ID_VERTICAL_DIRECTION = wxNewId();
+const long MapSelectDialog::ID_HORIZONTAL_DIRECTION = wxNewId();
+
+const wxString MapSelectDialog::m_dialog_name = _T("MapSelector");
+
+BEGIN_EVENT_TABLE(MapSelectDialog,wxDialog)
+ //(*EventTable(MapSelectDialog)
+ //*)
+END_EVENT_TABLE()
+
+MapSelectDialog::MapSelectDialog(wxWindow* parent,Ui& ui)
+ : m_ui(ui)
+ , m_horizontal_direction( sett().GetHorizontalSortorder() )
+ , m_vertical_direction( sett().GetVerticalSortorder() )
+{
+ //(*Initialize(MapSelectDialog)
+ wxStaticBoxSizer* StaticBoxSizer2;
+ wxStaticText* StaticText2;
+ wxStaticText* StaticText1;
+ wxBoxSizer* BoxSizer2;
+ wxBoxSizer* boxSizerHorizontal;
+ wxBoxSizer* BoxSizer1;
+ wxStaticBoxSizer* StaticBoxSizer1;
+ wxBoxSizer* boxSizerVertical;
+ wxStdDialogButtonSizer* StdDialogButtonSizer1;
+
+ Create(parent, wxID_ANY, _("Select map (click and drag to scroll)"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX, _T("wxID_ANY"));
+ BoxSizer1 = new wxBoxSizer(wxHORIZONTAL);
+ BoxSizer2 = new wxBoxSizer(wxVERTICAL);
+ StaticText2 = new wxStaticText(this, ID_STATICTEXT2, _("Vertical sort key"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT2"));
+ BoxSizer2->Add(StaticText2, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
+ boxSizerVertical = new wxBoxSizer(wxHORIZONTAL);
+ m_vertical_choice = new wxChoice(this, ID_VERTICAL_CHOICE, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_VERTICAL_CHOICE"));
+ boxSizerVertical->Add(m_vertical_choice, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ BoxSizer2->Add(boxSizerVertical, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ StaticText1 = new wxStaticText(this, ID_STATICTEXT1, _("Horizontal sort key"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT1"));
+ BoxSizer2->Add(StaticText1, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
+ boxSizerHorizontal = new wxBoxSizer(wxHORIZONTAL);
+ m_horizontal_choice = new wxChoice(this, ID_HORIZONTAL_CHOICE, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_HORIZONTAL_CHOICE"));
+ boxSizerHorizontal->Add(m_horizontal_choice, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ BoxSizer2->Add(boxSizerHorizontal, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ StaticBoxSizer1 = new wxStaticBoxSizer(wxVERTICAL, this, _("Show"));
+ m_filter_all = new wxRadioButton(this, ID_FILTER_ALL, _("All maps"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_FILTER_ALL"));
+ m_filter_all->SetToolTip(_("Shows all available maps"));
+ StaticBoxSizer1->Add(m_filter_all, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ m_filter_popular = new wxRadioButton(this, ID_FILTER_POPULAR, _("Popular maps"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_FILTER_POPULAR"));
+ m_filter_popular->SetToolTip(_("Shows only maps which are currently being player on the server. You must be online to use this."));
+ StaticBoxSizer1->Add(m_filter_popular, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ m_filter_recent = new wxRadioButton(this, ID_FILTER_RECENT, _("Recently played maps"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_FILTER_RECENT"));
+ m_filter_recent->SetValue(true);
+ m_filter_recent->SetToolTip(_("Shows only maps you played recently. (Based on your replays.)"));
+ StaticBoxSizer1->Add(m_filter_recent, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ BoxSizer2->Add(StaticBoxSizer1, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ StaticBoxSizer2 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Filter"));
+ m_filter_text = new wxTextCtrl(this, ID_FILTER_TEXT, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_FILTER_TEXT"));
+ m_filter_text->SetToolTip(_("Shows only maps which contain this text in their name or description."));
+ StaticBoxSizer2->Add(m_filter_text, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
+ BoxSizer2->Add(StaticBoxSizer2, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ m_map_details = new wxStaticBoxSizer(wxVERTICAL, this, _("Map details"));
+ m_map_name = new wxStaticText(this, ID_MAP_NAME, wxEmptyString, wxDefaultPosition, wxSize(170,90), wxST_NO_AUTORESIZE, _T("ID_MAP_NAME"));
+ m_map_name->SetLabel( wxEmptyString );
+ m_map_details->Add(m_map_name, 0, wxTOP|wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ m_map_opts_list = new wxListCtrl(this, ID_MAP_OPTS_LIST, wxDefaultPosition, wxSize(170,120), wxLC_REPORT|wxLC_NO_HEADER|wxNO_BORDER, wxDefaultValidator, _T("ID_MAP_OPTS_LIST"));
+ m_map_details->Add(m_map_opts_list, 1, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ BoxSizer2->Add(m_map_details, 1, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ StdDialogButtonSizer1 = new wxStdDialogButtonSizer();
+ StdDialogButtonSizer1->AddButton(new wxButton(this, wxID_OK, wxEmptyString));
+ StdDialogButtonSizer1->AddButton(new wxButton(this, wxID_CANCEL, wxEmptyString));
+ StdDialogButtonSizer1->Realize();
+ BoxSizer2->Add(StdDialogButtonSizer1, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ BoxSizer1->Add(BoxSizer2, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ m_mapgrid = new MapGridCtrl(this, m_ui, wxSize(600,400), ID_MAPGRID);
+ BoxSizer1->Add(m_mapgrid, 1, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ SetSizer(BoxSizer1);
+ BoxSizer1->Fit(this);
+ BoxSizer1->SetSizeHints(this);
+ Center();
+
+ Connect(ID_VERTICAL_CHOICE,wxEVT_COMMAND_CHOICE_SELECTED,(wxObjectEventFunction)&MapSelectDialog::OnSortKeySelect);
+ Connect(ID_HORIZONTAL_CHOICE,wxEVT_COMMAND_CHOICE_SELECTED,(wxObjectEventFunction)&MapSelectDialog::OnSortKeySelect);
+ Connect(ID_FILTER_ALL,wxEVT_COMMAND_RADIOBUTTON_SELECTED,(wxObjectEventFunction)&MapSelectDialog::OnFilterAllSelect);
+ Connect(ID_FILTER_POPULAR,wxEVT_COMMAND_RADIOBUTTON_SELECTED,(wxObjectEventFunction)&MapSelectDialog::OnFilterPopularSelect);
+ Connect(ID_FILTER_RECENT,wxEVT_COMMAND_RADIOBUTTON_SELECTED,(wxObjectEventFunction)&MapSelectDialog::OnFilterRecentSelect);
+ Connect(ID_FILTER_TEXT,wxEVT_COMMAND_TEXT_UPDATED,(wxObjectEventFunction)&MapSelectDialog::OnFilterTextChanged);
+ m_mapgrid->Connect(ID_MAPGRID,wxEVT_LEFT_DCLICK,(wxObjectEventFunction)&MapSelectDialog::OnMapGridLeftDClick,0,this);
+ Connect(wxID_ANY,wxEVT_INIT_DIALOG,(wxObjectEventFunction)&MapSelectDialog::OnInit);
+ //*)
+
+ Connect(ID_MAPGRID,MapGridCtrl::MapSelectedEvt,(wxObjectEventFunction)&MapSelectDialog::OnMapSelected,0,this);
+ Connect(ID_MAPGRID,MapGridCtrl::LoadingCompletedEvt,(wxObjectEventFunction)&MapSelectDialog::OnMapLoadingCompleted,0,this);
+
+ // Ugh.. Can not have these created by generated code because wxSmith doesn't accept a symbolic size,
+ // (ie. wxSize(CONTROL_HEIGHT,CONTROL_HEIGHT)) and all Set*Size() methods don't seem to have any effect.
+ m_vertical_direction_button = new wxButton(this, ID_VERTICAL_DIRECTION, _T("á´ "), wxDefaultPosition, wxSize(CONTROL_HEIGHT,CONTROL_HEIGHT), 0, wxDefaultValidator, _T("ID_VERTICAL_DIRECTION"));
+ boxSizerVertical->Add(m_vertical_direction_button, 0, wxALL|wxEXPAND|wxSHAPED|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ m_horizontal_direction_button = new wxButton(this, ID_HORIZONTAL_DIRECTION, _T(">"), wxDefaultPosition, wxSize(CONTROL_HEIGHT,CONTROL_HEIGHT), 0, wxDefaultValidator, _T("ID_HORIZONTAL_DIRECTION"));
+ boxSizerHorizontal->Add(m_horizontal_direction_button, 0, wxALL|wxEXPAND|wxSHAPED|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
+ //<>á´ á´§
+
+ Connect(ID_VERTICAL_DIRECTION, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&MapSelectDialog::OnVerticalDirectionClicked);
+ Connect(ID_HORIZONTAL_DIRECTION, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&MapSelectDialog::OnHorizontalDirectionClicked);
+
+ // TODO: refactor, this is copied from battlemaptab.cpp
+ m_map_opts_list->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
+ m_map_opts_list->SetFont( wxFont( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT ) );
+
+ wxListItem col;
+
+ col.SetText( _("Option") );
+ m_map_opts_list->InsertColumn( 0, col );
+ col.SetText( _("Value") );
+ m_map_opts_list->InsertColumn( 1, col );
+ m_map_opts_list->SetColumnWidth( 0, 90 );
+ m_map_opts_list->SetColumnWidth( 1, 80 );
+
+ m_map_opts_list->InsertItem( 0, _("Size") );
+ m_map_opts_list->InsertItem( 1, _("Windspeed") );
+ m_map_opts_list->InsertItem( 2, _("Tidal strength") );
+ m_map_opts_list->InsertItem( 3, _("Gravity") );
+ m_map_opts_list->InsertItem( 4, _("Extractor radius") );
+ m_map_opts_list->InsertItem( 5, _("Max metal") );
+ m_map_opts_list->InsertItem( 6, _("Start positions") );
+
+ //could prolly go into Create() params, dunno how tho w/o meddling w wxsmith
+
+ wxPoint pos = sett().GetWindowPos( m_dialog_name , wxPoint( DEFSETT_MW_LEFT, DEFSETT_MW_TOP ) );
+ wxSize size = sett().GetWindowSize( m_dialog_name , wxSize( DEFSETT_MW_WIDTH, DEFSETT_MW_HEIGHT ) );
+ SetSize( pos.x , pos.y, size.GetWidth(), size.GetHeight() );
+ Layout();
+}
+
+MapSelectDialog::~MapSelectDialog()
+{
+ //(*Destroy(MapSelectDialog)
+ //*)
+ sett().SetHorizontalSortkeyIndex( m_horizontal_choice->GetSelection() );
+ sett().SetVerticalSortkeyIndex( m_vertical_choice->GetSelection() );
+ sett().SetHorizontalSortorder( m_horizontal_direction );
+ sett().SetVerticalSortorder( m_vertical_direction );
+ sett().SetWindowSize( m_dialog_name , GetSize() );
+ sett().SetWindowPos( m_dialog_name , GetPosition() );
+ if ( m_filter_all->GetValue() )
+ sett().SetMapSelectorFilterRadio( m_filter_all_sett );
+ else if ( m_filter_recent->GetValue() )
+ sett().SetMapSelectorFilterRadio( m_filter_recent_sett );
+ else
+ sett().SetMapSelectorFilterRadio( m_filter_popular_sett );
+}
+
+
+void MapSelectDialog::OnInit( wxInitDialogEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+
+ AppendSortKeys( m_horizontal_choice );
+ AppendSortKeys( m_vertical_choice );
+
+ m_horizontal_choice->SetSelection( sett().GetHorizontalSortkeyIndex() );
+ m_vertical_choice->SetSelection( sett().GetVerticalSortkeyIndex() );
+
+ m_horizontal_direction_button->SetLabel( m_horizontal_direction ? _T("<") : _T(">") );
+ m_vertical_direction_button->SetLabel( m_vertical_direction ? _T("á´§") : _T("á´ ") );
+
+ m_maps = usync().GetMapList();
+ m_replays = usync().GetPlaybackList( true ); //true meaning replays, flase meaning savegames
+
+ const unsigned int lastFilter = sett().GetMapSelectorFilterRadio();
+ m_filter_popular->Enable( m_ui.IsConnected() );
+
+ // due to a bug / crappy design in SpringUnitSync / unitsync itself we
+ // get a replay list with one empty item when there are no replays..
+ bool no_replays = m_replays.empty() || ( m_replays.size() == 1 && m_replays[0] == wxEmptyString );
+ if ( no_replays ) {
+ m_filter_all->SetValue( true );
+ m_filter_recent->Enable( false );
+ }
+
+ if ( lastFilter == m_filter_popular_sett ) {
+ if ( m_ui.IsConnected() ) {
+ m_filter_popular->SetValue( true );
+ LoadPopular();
+ }
+ else {
+ m_filter_all->SetValue( true );
+ LoadAll();
+ }
+ }
+ else if ( lastFilter == m_filter_recent_sett ) {
+ if ( !no_replays ) {
+ m_filter_recent->Enable( true );
+ m_filter_recent->SetValue( true );
+ LoadRecent();
+ }
+ else {
+ m_filter_all->SetValue( true );
+ LoadAll();
+ }
+ }
+ else {
+ m_filter_all->SetValue( true );
+ LoadAll();
+ }
+
+ UpdateSortAndFilter();
+
+ m_filter_text->SetFocus();
+}
+
+
+void MapSelectDialog::OnSortKeySelect( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ UpdateSortAndFilter();
+}
+
+
+void MapSelectDialog::AppendSortKeys( wxChoice* choice )
+{
+ // see MapGridCtrl for available SortKeys
+ choice->Append( _("Name"), (void*) MapGridCtrl::SortKey_Name );
+ choice->Append( _("Tidal strength"), (void*) MapGridCtrl::SortKey_TidalStrength );
+ choice->Append( _("Gravity"), (void*) MapGridCtrl::SortKey_Gravity );
+ choice->Append( _("Max metal"), (void*) MapGridCtrl::SortKey_MaxMetal );
+ choice->Append( _("Extractor radius"), (void*) MapGridCtrl::SortKey_ExtractorRadius );
+ choice->Append( _("Minimum wind"), (void*) MapGridCtrl::SortKey_MinWind );
+ choice->Append( _("Maximum wind"), (void*) MapGridCtrl::SortKey_MaxWind );
+ choice->Append( _("Average wind"), (void*) MapGridCtrl::SortKey_Wind );
+ choice->Append( _("Size (map area)"), (void*) MapGridCtrl::SortKey_Area );
+ choice->Append( _("Aspect ratio"), (void*) MapGridCtrl::SortKey_AspectRatio );
+ choice->Append( _("Number of start positions"), (void*) MapGridCtrl::SortKey_PosCount );
+}
+
+static MapGridCtrl::SortKey GetSelectedSortKey( wxChoice* choice )
+{
+ return (MapGridCtrl::SortKey) (int) (long) choice->GetClientData( choice->GetSelection() );
+}
+
+namespace {
+struct FilterPredicate
+{
+ FilterPredicate( const wxString& searchText ) : searchText(searchText.Lower()) {}
+ bool operator () ( const UnitSyncMap& map ) const
+ {
+ return map.name.Lower().Contains( searchText )
+ || map.info.description.Lower().Contains( searchText )
+ || map.info.author.Lower().Contains( searchText );
+ }
+ wxString searchText;
+};
+}
+
+void MapSelectDialog::UpdateSortAndFilter()
+{
+ FilterPredicate predicate( m_filter_text->GetValue() );
+ m_mapgrid->Filter( predicate );
+ m_mapgrid->Sort( GetSelectedSortKey( m_vertical_choice ), GetSelectedSortKey( m_horizontal_choice ), m_vertical_direction, m_horizontal_direction );
+ m_mapgrid->CheckInBounds();
+ m_mapgrid->Refresh();
+}
+
+UnitSyncMap* MapSelectDialog::GetSelectedMap() const
+{
+ wxLogDebugFunc( _T("") );
+ return m_mapgrid->GetSelectedMap();
+}
+
+void MapSelectDialog::OnMapSelected( wxCommandEvent& event )
+{
+ const wxString& mapname = event.GetString();
+
+ wxLogDebugFunc( mapname );
+
+ const UnitSyncMap* pMap = m_mapgrid->GetSelectedMap();
+ if ( pMap == NULL) return;
+ const UnitSyncMap& map = *pMap;
+
+ m_map_name->SetLabel( RefineMapname( map.name ) + _T("\n\n") + map.info.description );
+
+ // TODO: refactor, this is copied from battlemaptab.cpp
+ m_map_opts_list->SetItem( 0, 1, wxString::Format( _T("%dx%d"), map.info.width/512, map.info.height/512 ) );
+ m_map_opts_list->SetItem( 1, 1, wxString::Format( _T("%d-%d"), map.info.minWind, map.info.maxWind ) );
+ m_map_opts_list->SetItem( 2, 1, wxString::Format( _T("%d"), map.info.tidalStrength ) );
+ m_map_opts_list->SetItem( 3, 1, wxString::Format( _T("%d"), map.info.gravity ) );
+ m_map_opts_list->SetItem( 4, 1, wxString::Format( _T("%d"), map.info.extractorRadius ) );
+ m_map_opts_list->SetItem( 5, 1, wxString::Format( _T("%.3f"), map.info.maxMetal ) );
+ m_map_opts_list->SetItem( 6, 1, wxString::Format( _T("%d"), map.info.posCount ) );
+}
+
+void MapSelectDialog::OnMapLoadingCompleted( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ // to apply stored sorting settings we need to re-apply sorting after loading finished
+ UpdateSortAndFilter();
+}
+
+void MapSelectDialog::OnVerticalDirectionClicked( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ m_vertical_direction = !m_vertical_direction;
+ m_vertical_direction_button->SetLabel( m_vertical_direction ? _T("á´§") : _T("á´ ") );
+ UpdateSortAndFilter();
+}
+
+void MapSelectDialog::OnHorizontalDirectionClicked( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ m_horizontal_direction = !m_horizontal_direction;
+ m_horizontal_direction_button->SetLabel( m_horizontal_direction ? _T("<") : _T(">") );
+ UpdateSortAndFilter();
+}
+
+void MapSelectDialog::OnMapGridLeftDClick(wxMouseEvent& /*unused*/)
+{
+ wxLogDebugFunc( _T("") );
+
+ if ( m_mapgrid->GetSelectedMap() ) {
+ EndModal( wxID_OK );
+ }
+}
+
+void MapSelectDialog::LoadAll()
+{
+ wxLogDebugFunc( _T("") );
+ const int count = m_maps.size();
+
+ m_mapgrid->Clear();
+
+ for ( int i = 0; i < count; ++i ) {
+ m_mapgrid->AddMap( m_maps[i] );
+ }
+
+ m_mapgrid->Refresh();
+}
+
+void MapSelectDialog::LoadPopular()
+{
+ wxLogDebugFunc( _T("") );
+
+ m_mapgrid->Clear();
+
+ try {
+ m_ui.GetServer().battles_iter->IteratorBegin();
+ while ( !m_ui.GetServer().battles_iter->EOL() ) {
+ Battle* b = m_ui.GetServer().battles_iter->GetBattle();
+ if ( b != NULL ) m_mapgrid->AddMap( b->GetHostMapName() );
+ }
+ }
+ catch (...) {} // m_ui.GetServer may throw when disconnected...
+
+ m_mapgrid->Refresh();
+}
+
+void MapSelectDialog::LoadRecent()
+{
+ wxLogDebugFunc( _T("") );
+ const int count = m_maps.size();
+
+ m_mapgrid->Clear();
+
+ // just check whether map names are contained in replay names
+ // not the most elegant solution but, hey, it works
+ for ( int i = 0; i < count; ++i ) {
+ // prefix and suffix with underscore to prevent most common partial matches
+ const wxString mapname = _T("_") + m_maps[i].BeforeLast( '.' ) + _T("_");
+ unsigned int replaycount = m_replays.GetCount();
+ for ( int replaynum = 0; replaynum < replaycount; replaynum++ ) {
+ if ( m_replays[replaynum].Contains( mapname ) )
+ m_mapgrid->AddMap( m_maps[i] );
+ }
+ }
+
+ m_mapgrid->Refresh();
+}
+
+// filter event handlers
+
+void MapSelectDialog::OnFilterAllSelect(wxCommandEvent& /*unused*/)
+{
+ wxLogDebugFunc( _T("") );
+ LoadAll();
+}
+
+void MapSelectDialog::OnFilterPopularSelect(wxCommandEvent& /*unused*/)
+{
+ wxLogDebugFunc( _T("") );
+ LoadPopular();
+}
+
+void MapSelectDialog::OnFilterRecentSelect(wxCommandEvent& /*unused*/)
+{
+ wxLogDebugFunc( _T("") );
+ LoadRecent();
+}
+
+void MapSelectDialog::OnFilterTextChanged(wxCommandEvent& /*unused*/)
+{
+ wxLogDebugFunc( _T("") );
+ UpdateSortAndFilter();
+}
diff --git a/src/mapselectdialog.h b/src/mapselectdialog.h
new file mode 100644
index 0000000..27f2325
--- /dev/null
+++ b/src/mapselectdialog.h
@@ -0,0 +1,122 @@
+/* Author: Tobi Vollebregt */
+
+#ifndef MAPSELECTDIALOG_H
+#define MAPSELECTDIALOG_H
+
+#include <vector>
+
+//(*Headers(MapSelectDialog)
+#include <wx/dialog.h>
+class wxStdDialogButtonSizer;
+class wxTextCtrl;
+class MapGridCtrl;
+class wxRadioButton;
+class wxStaticText;
+class wxListCtrl;
+class wxBoxSizer;
+class wxStaticBoxSizer;
+class wxChoice;
+//*)
+class wxButton;
+
+class Ui;
+struct UnitSyncMap;
+
+
+class MapSelectDialog: public wxDialog
+{
+ public:
+
+ MapSelectDialog( wxWindow* parent, Ui& ui );
+ virtual ~MapSelectDialog();
+
+ UnitSyncMap* GetSelectedMap() const;
+
+ protected:
+
+ //(*Declarations(MapSelectDialog)
+ wxRadioButton* m_filter_recent;
+ wxStaticText* m_map_name;
+ wxRadioButton* m_filter_all;
+ MapGridCtrl* m_mapgrid;
+ wxChoice* m_vertical_choice;
+ wxChoice* m_horizontal_choice;
+ wxTextCtrl* m_filter_text;
+ wxListCtrl* m_map_opts_list;
+ wxRadioButton* m_filter_popular;
+ wxStaticBoxSizer* m_map_details;
+ //*)
+ wxButton* m_vertical_direction_button;
+ wxButton* m_horizontal_direction_button;
+
+ //(*Identifiers(MapSelectDialog)
+ static const long ID_STATICTEXT2;
+ static const long ID_VERTICAL_CHOICE;
+ static const long ID_STATICTEXT1;
+ static const long ID_HORIZONTAL_CHOICE;
+ static const long ID_FILTER_ALL;
+ static const long ID_FILTER_POPULAR;
+ static const long ID_FILTER_RECENT;
+ static const long ID_FILTER_TEXT;
+ static const long ID_MAP_NAME;
+ static const long ID_MAP_OPTS_LIST;
+ static const long ID_MAPGRID;
+ //*)
+ static const long ID_VERTICAL_DIRECTION;
+ static const long ID_HORIZONTAL_DIRECTION;
+
+ //(*Handlers(MapSelectDialog)
+ void OnInit(wxInitDialogEvent& event);
+ void OnSortKeySelect(wxCommandEvent& event);
+ void OnMapGridLeftDClick(wxMouseEvent& event);
+ void OnFilterAllSelect(wxCommandEvent& event);
+ void OnFilterPopularSelect(wxCommandEvent& event);
+ void OnFilterRecentSelect(wxCommandEvent& event);
+ void OnFilterTextChanged(wxCommandEvent& event);
+ //*)
+
+ void OnMapSelected( wxCommandEvent& event );
+ void OnMapLoadingCompleted( wxCommandEvent& event );
+ void OnVerticalDirectionClicked( wxCommandEvent& event );
+ void OnHorizontalDirectionClicked( wxCommandEvent& event );
+
+ void AppendSortKeys( wxChoice* choice );
+ void UpdateSortAndFilter();
+
+ void LoadAll();
+ void LoadPopular();
+ void LoadRecent();
+
+ Ui& m_ui;
+ bool m_horizontal_direction;
+ bool m_vertical_direction;
+ wxArrayString m_maps;
+ wxArrayString m_replays;
+
+ static const wxString m_dialog_name;
+ static const unsigned int m_filter_all_sett = 0;
+ static const unsigned int m_filter_recent_sett = 1;
+ static const unsigned int m_filter_popular_sett = 2;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mmoptionmodel.cpp b/src/mmoptionmodel.cpp
new file mode 100644
index 0000000..7812faa
--- /dev/null
+++ b/src/mmoptionmodel.cpp
@@ -0,0 +1,121 @@
+#include "mmoptionmodel.h"
+
+mmOptionModel::mmOptionModel(wxString name_, wxString key_, wxString description_, OptionType type_,
+ wxString section_ , wxString style_ )
+ : name(name_),key(key_),description(description_),type(type_),
+ section(section_),ct_type_string(style_)
+{
+ //set style according to input string
+ if ( style_= _T("yaadda") )
+ ct_type = ct_someothers;
+ else
+ ct_type = ct_undefined; //lobby will chooose best fit
+
+ if ( section == wxEmptyString )
+ section = SLGlobals::nosection_name;
+
+ if ( ct_type_string == wxEmptyString )
+ ct_type_string = SLGlobals::nostyle_name;
+
+}
+
+mmOptionModel::mmOptionModel(wxString name_, wxString key_, wxString description_, OptionType type_,
+ wxString section_ , ControlType style_ )
+ : name(name_),key(key_),description(description_),type(type_),
+ ct_type(style_), section(section_)
+{
+}
+
+mmOptionModel::~mmOptionModel()
+{}
+
+mmOptionModel::mmOptionModel()
+{
+ type = opt_undefined;
+ name = _T("");
+ key = name;
+ description = name;
+ section = SLGlobals::nosection_name;
+ ct_type = ct_undefined;
+}
+
+mmOptionBool::mmOptionBool(wxString name_, wxString key_, wxString description_, bool def_,
+ wxString section_ , wxString style_):
+ mmOptionModel(name_,key_,description_,opt_bool,section_,style_),
+ def(def_),value(def_)
+{}
+
+mmOptionBool::mmOptionBool():mmOptionModel()
+{
+ value = false;
+ def = value;
+}
+
+mmOptionFloat::mmOptionFloat(wxString name_, wxString key_, wxString description_, float def_, float stepping_, float min_, float max_,
+ wxString section_ , wxString style_):
+ mmOptionModel(name_,key_,description_,opt_float,section_,style_),
+ def(def_),value(def_),stepping(stepping_),min(min_),max(max_)
+{}
+
+mmOptionFloat::mmOptionFloat():mmOptionModel()
+{
+ value = 0.0;
+ min = value;
+ max = value;
+ stepping = value;
+}
+
+mmOptionString::mmOptionString(wxString name_, wxString key_, wxString description_, wxString def_, unsigned int max_len_,
+ wxString section_ , wxString style_):
+ mmOptionModel(name_,key_,description_,opt_string,section_,style_),
+ def(def_),value(def_),max_len(max_len_)
+{}
+
+mmOptionString::mmOptionString():mmOptionModel()
+{
+ def = _T("");
+ value = def;
+ max_len = 0;
+}
+
+mmOptionList::mmOptionList(wxString name_, wxString key_, wxString description_, wxString def_,
+ wxString section_ , wxString style_):
+ mmOptionModel(name_,key_,description_,opt_list,section_,style_),
+ def(def_),value(def_)
+{
+ cur_choice_index = 0;
+}
+
+mmOptionList::mmOptionList():mmOptionModel()
+{
+ value = _T("");
+ def = _T("");
+}
+
+void mmOptionList::addItem(wxString key_, wxString name_, wxString desc_)
+{
+ listitems.push_back(listItem(key_,name_,desc_));
+ //make sure current choice is set to default
+ if ( this->def == key_ )
+ this->cur_choice_index = listitems.size() - 1;
+ cbx_choices.Add(name_);
+}
+
+listItem::listItem(wxString key_, wxString name_,wxString desc_):
+ key(key_),name(name_),desc(desc_)
+{
+
+}
+
+
+ mmOptionSection::mmOptionSection():mmOptionModel()
+{
+ key = SLGlobals::nosection_name;
+}
+
+ mmOptionSection::mmOptionSection(wxString name_, wxString key_, wxString description_,wxString section_, wxString style_ )
+ :mmOptionModel( name_, key_, description_, opt_section,section_, style_ )
+{
+
+}
+
diff --git a/src/mmoptionmodel.h b/src/mmoptionmodel.h
new file mode 100644
index 0000000..1fa7c7c
--- /dev/null
+++ b/src/mmoptionmodel.h
@@ -0,0 +1,175 @@
+#ifndef MMOPTIONMODEL_H_
+#define MMOPTIONMODEL_H_
+
+#include <wx/string.h>
+#include <wx/arrstr.h>
+#include <vector>
+
+namespace SLGlobals {
+ const wxString nosection_name = _T("none");
+ const wxString nostyle_name = _T("none");
+};
+
+//! enum that lets us differentiate option types at runtime
+/*! opt_undefined will be returned/set if the type could not be determined, others respectively */
+enum OptionType {
+ opt_undefined = 0,
+ opt_bool = 1,
+ opt_list = 2,
+ opt_float = 3,
+ opt_string = 4,
+ opt_section = 5
+};
+
+//! used to hold an item in an option list
+/*! An option list is made of a variable number of theses items.
+ * Each item itself (should) contain a key, name and description.
+ */
+struct listItem
+{
+ listItem(wxString key_, wxString name_,wxString desc_);
+
+ wxString key;
+ wxString name;
+ wxString desc;
+};
+
+//! Used in option list
+typedef std::vector<listItem> ListItemVec;
+
+//! The base class for all option types
+/*! All members and functions are public (also in derived classes).
+ * Therefore no sanity checks whatsoever are performed when changing a member.
+ * Default constructors are mostly provided for compability with stl containers.
+ */
+struct mmOptionModel
+{
+ enum ControlType{
+ ct_undefined,
+ ct_someothers
+ };
+
+
+ //! sets members accordingly
+ ///* this ctor sets controltype enum according to string *///
+ mmOptionModel(wxString name_, wxString key_, wxString description_, OptionType type_ = opt_undefined,
+ wxString section_ = SLGlobals::nosection_name, wxString style_ = SLGlobals::nostyle_name);
+ mmOptionModel(wxString name_, wxString key_, wxString description_, OptionType type_ = opt_undefined,
+ wxString section_ = SLGlobals::nosection_name, ControlType style_ = ct_undefined);
+
+ virtual ~mmOptionModel();
+ //! all members are set to empty strings, type to opt_undefined
+ mmOptionModel();
+
+ wxString name, key, description;
+ OptionType type;
+ ControlType ct_type;
+ wxString section;
+ //! control style string, as of yet undefined
+ wxString ct_type_string;
+};
+
+//! Holds a bool option
+/*! difference from parent: members def and value are bool */
+struct mmOptionBool : public mmOptionModel
+{
+ //! sets members accordingly
+ mmOptionBool(wxString name_, wxString key_, wxString description_, bool def_,
+ wxString section_ = SLGlobals::nosection_name, wxString style_ = SLGlobals::nostyle_name);
+ //! sets wxstring member to "" and bool members to false
+ mmOptionBool();
+ bool def;
+ //! this will always represent the current value, also the only member that should change after creation
+ bool value;
+};
+
+//! Holds a float option
+struct mmOptionFloat : public mmOptionModel
+{
+ //! sets members accordingly
+ mmOptionFloat(wxString name_, wxString key_, wxString description_, float def_, float stepping_, float min_, float max_,
+ wxString section_ = SLGlobals::nosection_name, wxString style_ = SLGlobals::nostyle_name);
+ //! sets wxstring member to "" and float members to 0.0
+ mmOptionFloat();
+
+ float def;
+ //! this will always represent the current value, also the only member that should change after creation
+ float value;
+
+ //! the increment with that value may change in min,max boundaries
+ float stepping;
+ float min, max;
+};
+
+//! Holds a string option
+struct mmOptionString : public mmOptionModel
+{
+ //! sets members accordingly
+ mmOptionString(wxString name_, wxString key_, wxString description_, wxString def_, unsigned int max_len_,
+ wxString section_ = SLGlobals::nosection_name, wxString style_ = SLGlobals::nostyle_name);
+ //! sets wxstring member to "" and max_len to 0
+ mmOptionString();
+
+ //! should not exceed max length (not ensured)
+ wxString def;
+ //! this will always represent the current value,
+ /*! the only member that should change after creation, before set check if new value exceeds max_len*/
+ wxString value;
+ //! the maximum lentgh the value string may have
+ unsigned int max_len;
+};
+
+//! Holds a an option list (a vector of listItems)
+/*! Most complex of option types. A convenience method for adding new Listitems is provided,
+ * as well as a wxArrayString that contains the names of the added Listitems (useful for comboboxes)
+ */
+struct mmOptionList : public mmOptionModel
+{
+ //! sets members accordingly; listitems,cbx_choices remain empty
+ mmOptionList(wxString name_, wxString key_, wxString description_, wxString def_,
+ wxString section_ = SLGlobals::nosection_name, wxString style_ = SLGlobals::nostyle_name);
+ //! def, value are set to ""; listitems,cbx_choices remain empty
+ mmOptionList();
+
+ //! creates a new listitem from params, pushes it on the vector and adds name_ to cbx_choices
+ void addItem(wxString key_, wxString name_, wxString desc_);
+
+ wxString def;
+ //! will always reflect the name of the currently "selected" listitem
+ wxString value;
+ //! index of current value in cbx_choices, so one can assign new combox value
+ int cur_choice_index;
+ //! holds a variable amount of ListItems
+ ListItemVec listitems;
+ //! for easy mapping to a combobox
+ wxArrayString cbx_choices;
+
+};
+
+
+struct mmOptionSection : public mmOptionModel{
+ mmOptionSection (wxString name_, wxString key_, wxString description_,
+ wxString section_ = SLGlobals::nosection_name, wxString style_ = SLGlobals::nostyle_name );
+ mmOptionSection ();
+};
+
+
+#endif /*MMOPTIONMODEL_H_*/
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mmoptionswrapper.cpp b/src/mmoptionswrapper.cpp
new file mode 100644
index 0000000..d0f63b5
--- /dev/null
+++ b/src/mmoptionswrapper.cpp
@@ -0,0 +1,657 @@
+#include "mmoptionswrapper.h"
+
+#include "iunitsync.h"
+#include "utils/conversion.h"
+#include "settings++/custom_dialogs.h"
+#include "utils/debug.h"
+
+#include <stdexcept>
+#include <wx/intl.h>
+#include <wx/log.h>
+#include <wx/fileconf.h>
+#include <wx/filename.h>
+
+OptionsWrapper::OptionsWrapper()
+{
+ unLoadOptions();
+ loadOptions( EngineOption, _T("") );
+ loadOptions( PrivateOptions,_T("") );
+}
+
+void OptionsWrapper::unLoadOptions()
+{
+ for (int i = 0; i < LastOption; ++i)
+ {
+ unLoadOptions( (GameOption)i );
+ }
+}
+
+void OptionsWrapper::unLoadOptions(GameOption i)
+{
+ GameOptions empty;
+ m_opts[i] = empty;
+
+ mmSectionTreeMap::iterator itor = m_sections.find( i );
+ if ( itor != m_sections.end() ) m_sections.erase( itor );
+}
+
+OptionsWrapper::~OptionsWrapper()
+{
+}
+
+bool OptionsWrapper::loadMapOptions(wxString mapname)
+{
+ return loadOptions(MapOption,mapname);
+}
+
+OptionType OptionsWrapper::GetSingleOptionType (wxString key) const
+{
+ OptionType type = opt_undefined;
+ for ( int g = 0; g < LastOption; g++ )
+ {
+ if (keyExists(key,(GameOption)g,false,type))
+ return type;
+ }
+ return opt_undefined;
+}
+
+bool OptionsWrapper::loadAIOptions( const wxString& modname, int aiindex,const wxString& ainame )
+{
+ int mapindex = m_ais_indexes[ainame];
+ if ( mapindex == 0 ) mapindex = m_ais_indexes.size() + LastOption;
+ m_ais_indexes[ainame] = mapindex;
+ wxLogDebugFunc( _T("bot name: ") + ainame + _T(" option index: ") + TowxString( mapindex ) );
+ unLoadOptions((GameOption)mapindex);
+ try
+ {
+ GameOptions opt = usync().GetAIOptions( modname, aiindex );
+ ParseSectionMap( m_sections[mapindex], opt.section_map );
+ m_opts[mapindex] = opt;
+ } catch (...)
+ {
+ return false;
+ }
+ return true;
+}
+
+int OptionsWrapper::GetAIOptionIndex( const wxString& nick )
+{
+ std::map<wxString,int>::iterator itor = m_ais_indexes.find(nick);
+ int pos = -1;
+ if ( itor != m_ais_indexes.end() ) pos = itor->second;
+ wxLogDebugFunc( _T("bot name: ") + nick + _T(" option index: ") + TowxString( pos ) );
+ return pos;
+}
+
+bool OptionsWrapper::loadOptions(GameOption modmapFlag, const wxString& name)
+{
+ unLoadOptions(modmapFlag);
+ GameOptions opt;
+ switch (modmapFlag)
+ {
+ default:
+ break;
+ case MapOption:
+ try
+ {
+ opt = usync().GetMapOptions(name);
+ ParseSectionMap( m_sections[modmapFlag], opt.section_map );
+ }
+ catch(...)
+ {
+ wxLogError(_T("Could not load map Options"));
+ return false;
+ }
+ break;
+ case ModOption:
+ try
+ {
+ opt = usync().GetModOptions(name);
+ ParseSectionMap( m_sections[modmapFlag], opt.section_map );
+ }
+ catch(...)
+ {
+ wxLogError(_T("Could not load mod Options"));
+ return false;
+ }
+ break;
+ case EngineOption:
+ {
+
+ mmOptionList startpos( _("Start Position Type"),_T("startpostype"), _("How players will select where to be spawned in the map\n0: fixed map positions\n1: random map positions\n2: choose in game\n3: choose in the lobby before starting"), _T("0") );
+ startpos.addItem( _T("0"), _("Fixed"), _T("Use the start positions defined in the map, the positions will be assigned incrementally from the team with lowest number to highest") );
+ startpos.addItem( _T("1"), _("Random"), _T("Use the start positions defined in the map, the positions will be assigned randomly") );
+ startpos.addItem( _T("2"), _("Choose in-game"), _T("Players will be able to pick their own starting point right before the game starts, optionally limited by a bounding box defined by the host") );
+ startpos.addItem( _T("3"), _("Choose before game"), _T("The host will place each player's start position in the map preview before the game is launched") );
+ opt.list_map[_T("startpostype")] = startpos;
+ break;
+ }
+ case PrivateOptions:
+ {
+ opt.string_map[_T("restrictions")] = mmOptionString(_("List of restricted units"), _T("restrictedunits"), _T("Units in this list won't be available in game"), _T(""), 0 ); // tab separated list
+ opt.string_map[_T("mapname")] = mmOptionString(_("Map name"), _T("mapname"), _T("Map name"), _T(""), 0 );
+ break;
+ }
+ }
+ m_opts[modmapFlag] = opt;
+ return true;
+}
+
+OptionsWrapper::GameOption OptionsWrapper::GetSection( wxString& key ) const
+{
+ GameOption ret = LastOption;
+ bool found = false;
+ for ( int flag = 0; flag < PrivateOptions; flag++ )
+ {
+ OptionType optType = opt_undefined;
+ found = keyExists( key, (GameOption)flag, false, optType );
+ if ( found )
+ {
+ ret = (GameOption)flag;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool OptionsWrapper::keyExists(wxString key ) const
+{
+ bool found = false;
+ for ( int flag = 0; flag < PrivateOptions; flag++ )
+ {
+ OptionType optType = opt_undefined;
+ found = keyExists( key, (GameOption)flag, false, optType );
+ if ( found ) break;
+ }
+ return found;
+}
+
+bool OptionsWrapper::keyExists(wxString key, GameOption modmapFlag, bool showError, OptionType& optType) const
+{
+ wxString duplicateKeyError = _T("Please contact the mod's author and tell him\n"
+ "to use unique keys in his ModOptions.lua");
+ bool exists = false;
+ optType = opt_undefined;
+ GameOptionsMap::const_iterator optIt = m_opts.find((int)modmapFlag);
+ if ( optIt == m_opts.end() )
+ return false;
+ const GameOptions& gameoptions = optIt->second;
+ if ( gameoptions.list_map.find(key) != gameoptions.list_map.end())
+ {
+ optType = opt_list;
+ exists = true;
+ }
+ else if ( gameoptions.string_map.find(key) != gameoptions.string_map.end())
+ {
+ optType = opt_string;
+ exists = true;
+ }
+ else if ( gameoptions.bool_map.find(key) != gameoptions.bool_map.end())
+ {
+ optType = opt_bool;
+ exists = true;
+ }
+ else if ( gameoptions.float_map.find(key)!= gameoptions.float_map.end())
+ {
+ optType = opt_float;
+ exists = true;
+ }
+ else if ( gameoptions.section_map.find(key)!= gameoptions.section_map.end())
+ {
+ optType = opt_section;
+ exists = true;
+ }
+ if (exists && showError)
+ {
+ customMessageBoxNoModal(SL_MAIN_ICON,duplicateKeyError,_T("Mod/map option error"),wxOK);
+ wxLogWarning(_T("duplicate key in mapmodoptions"));
+ return false;
+ }
+ else if ( exists && !showError )
+ {
+ return true;
+ }
+ else
+ return false;
+}
+
+bool OptionsWrapper::setOptions(wxStringPairVec* options, GameOption modmapFlag)
+{
+ for (wxStringPairVec::iterator it = options->begin(); it != options->end(); ++it)
+ {
+ wxString key = it->first;
+ wxString value = it->second;
+
+ //we don't want to add a key that doesn't already exists
+ OptionType optType = opt_undefined;
+ if(!keyExists(key,modmapFlag,false,optType))
+ return false;
+ else
+ {
+ if ( !setSingleOptionTypeSwitch( key, value, modmapFlag, optType) )
+ return false;
+ }
+ }
+ return true;
+}
+
+OptionsWrapper::wxStringTripleVec OptionsWrapper::getOptions( GameOption modmapFlag) const
+{
+ wxStringTripleVec list;
+ GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
+ if ( optIt != m_opts.end() ) {
+ const GameOptions& gameoptions = optIt->second;
+ for (IUnitSync::OptionMapBoolConstIter it = gameoptions.bool_map.begin(); it != gameoptions.bool_map.end(); ++it) {
+ list.push_back( wxStringTriple( (*it).first, wxStringPair ( it->second.name , TowxString(it->second.value) ) ) );
+ }
+
+ for (IUnitSync::OptionMapStringConstIter it = gameoptions.string_map.begin(); it != gameoptions.string_map.end(); ++it) {
+ list.push_back( wxStringTriple( (*it).first, wxStringPair ( it->second.name, it->second.value) ) );
+ }
+
+ for (IUnitSync::OptionMapFloatConstIter it = gameoptions.float_map.begin(); it != gameoptions.float_map.end(); ++it) {
+ list.push_back( wxStringTriple( (*it).first, wxStringPair ( it->second.name, TowxString(it->second.value) ) ) );
+ }
+
+ for (IUnitSync::OptionMapListConstIter it = gameoptions.list_map.begin(); it != gameoptions.list_map.end(); ++it) {
+ list.push_back( wxStringTriple( (*it).first, wxStringPair ( it->second.name, it->second.value ) ) );
+ }
+ }
+ return list;
+}
+
+std::map<wxString,wxString> OptionsWrapper::getOptionsMap( GameOption modmapFlag ) const
+{
+ std::map<wxString,wxString> map;
+ GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
+ if ( optIt != m_opts.end() ) {
+ const GameOptions& gameoptions = optIt->second;
+ for (IUnitSync::OptionMapBoolConstIter it = gameoptions.bool_map.begin(); it != gameoptions.bool_map.end(); ++it) {
+ map[it->first] = TowxString(it->second.value);
+ }
+
+ for (IUnitSync::OptionMapStringConstIter it = gameoptions.string_map.begin(); it != gameoptions.string_map.end(); ++it) {
+ map[it->first] = it->second.value;
+ }
+
+ for (IUnitSync::OptionMapFloatConstIter it = gameoptions.float_map.begin(); it != gameoptions.float_map.end(); ++it) {
+ map[it->first] = TowxString(it->second.value);
+ }
+
+ for (IUnitSync::OptionMapListConstIter it = gameoptions.list_map.begin(); it != gameoptions.list_map.end(); ++it) {
+ map[it->first] = it->second.value;
+ }
+ }
+ return map;
+}
+
+bool OptionsWrapper::setSingleOption(wxString key,wxString value,GameOption modmapFlag)
+{
+ OptionType optType = opt_undefined;
+ keyExists( key, modmapFlag, false, optType );
+ return setSingleOptionTypeSwitch(key,value,modmapFlag,optType);
+}
+
+bool OptionsWrapper::setSingleOption(wxString key,wxString value)
+{
+ OptionType optType = opt_undefined;
+ if (keyExists(key,ModOption,false,optType))
+ return setSingleOptionTypeSwitch(key,value,ModOption,optType);
+ else if (keyExists(key,MapOption,false,optType))
+ return setSingleOptionTypeSwitch(key,value,MapOption,optType);
+ else
+ return false;
+}
+
+wxString OptionsWrapper::getSingleValue(wxString key) const
+{
+ for ( int g = 0; g < LastOption; g++ )
+ {
+ const wxString tmp = getSingleValue(key, (GameOption)g);
+ if (tmp != wxEmptyString)
+ return tmp;
+ }
+ return wxEmptyString;
+}
+template < class MapType >
+static inline typename MapType::mapped_type GetItem( const MapType& map, const typename MapType::key_type& key )
+{
+ typename MapType::const_iterator mapIt = map.find(key);
+ if ( mapIt != map.end() )
+ return mapIt->second;
+ else
+ return typename MapType::mapped_type();
+}
+
+wxString OptionsWrapper::getSingleValue(wxString key, GameOption modmapFlag) const
+{
+ OptionType optType = opt_undefined;
+
+ if ( keyExists(key,modmapFlag,false,optType) )
+ {
+ GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
+ if ( optIt == m_opts.end() )
+ return wxEmptyString;
+
+ const GameOptions& tempOpt = optIt->second;
+ switch (optType)
+ {
+ case opt_float:
+ return TowxString( GetItem( tempOpt.float_map, key ).value );
+ case opt_bool:
+ return TowxString( GetItem( tempOpt.bool_map, key ).value );
+ case opt_string:
+ return GetItem( tempOpt.string_map, key ).value ;
+ case opt_list:
+ return GetItem( tempOpt.list_map, key ).value;
+ case opt_undefined:
+ default:
+ return wxEmptyString;
+ }
+ }
+
+ return wxEmptyString;
+}
+
+wxString OptionsWrapper::getDefaultValue(wxString key, GameOption modmapFlag) const
+{
+ OptionType optType = opt_undefined;
+ wxString ret;
+ if ( keyExists(key,modmapFlag,false,optType) )
+ {
+ //purposefully create a copy, no better idea
+ GameOptionsMapCIter optIt = m_opts.find((int)modmapFlag);
+ if ( optIt == m_opts.end() )
+ return wxEmptyString;
+
+ const GameOptions& tempOpt = optIt->second;
+ switch ( optType )
+ {
+ {
+ case opt_bool:
+ ret = TowxString( GetItem( tempOpt.bool_map, key ).def );
+ break;
+ }
+ case opt_float:
+ {
+ ret = TowxString( GetItem( tempOpt.float_map, key ).def );
+ break;
+ }
+ case opt_string:
+ {
+ ret = GetItem( tempOpt.string_map, key ).def;
+ break;
+ }
+ case opt_list:
+ {
+ ret = GetItem( tempOpt.list_map, key ).def;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+bool OptionsWrapper::setSingleOptionTypeSwitch(wxString key, wxString value, GameOption modmapFlag, OptionType optType)
+{
+ GameOptions& gameoptions = m_opts[modmapFlag];
+ switch (optType)
+ {
+ case opt_float :
+ {
+ //test if min < val < max
+ double d_val;
+ bool d_conv_ok = value.ToDouble(&d_val);
+ if( !d_conv_ok || d_val < (gameoptions.float_map)[key].min || d_val > (gameoptions.float_map)[key].max )
+ {
+ wxLogWarning(_T("recieved number option exceeds boundaries"));
+ return false;
+ }
+ else
+ (gameoptions.float_map)[key].value = d_val;
+ break;
+ }
+ case opt_bool :
+ {
+ long l_val;
+ bool l_conv_ok = value.ToLong(&l_val);
+ if( !l_conv_ok || ( l_val != 1 && l_val != 0 ) )
+ {
+ wxLogWarning(_T("recieved bool option that is neither 0 or 1"));
+ return false;
+ }
+ else
+ (gameoptions.bool_map)[key].value = bool(l_val);
+ break;
+ }
+ case opt_string :
+ {
+ // test if maxlength isn't exceeded
+ unsigned int max_lenght = (gameoptions.string_map)[key].max_len;
+ if ( ( max_lenght != 0 ) && ( value.Len() > max_lenght ) )
+ {
+ wxLogWarning(_T("recieved string option exceeds max_len"));
+ return false;
+ }
+ else
+ (gameoptions.string_map)[key].value = value;
+ break;
+ }
+ case opt_list :
+ {
+ // test if valid value, aka is in list
+ int listitemcount = (gameoptions.list_map)[key].listitems.size();
+ bool valid_string = false;
+ int j = 0;
+ for (; j < listitemcount; ++j)
+ {
+ if ( (gameoptions.list_map)[key].listitems[j].key == value)
+ {
+ valid_string = true;
+ break;
+ }
+ }
+
+ if (valid_string)
+ {
+ //LOOKATME (koshi) if there's a problem with list modoption look here first
+ (gameoptions.list_map)[key].value = (gameoptions.list_map)[key].listitems[j].key;
+ (gameoptions.list_map)[key].cur_choice_index = j;
+ }
+ else
+ {
+ wxLogWarning(_T("recieved list option is not valid"));
+ return false;
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+ //if we made it here, all is good
+ return true;
+}
+
+wxString OptionsWrapper::GetNameListOptValue(wxString key, GameOption flag) const
+{
+ OptionType optType;
+ if ( keyExists(key,flag,false, optType) )
+ {
+ if ( optType == opt_list)
+ {
+ GameOptionsMapCIter optIt = m_opts.find((int)flag);
+ if ( optIt == m_opts.end() )
+ return wxEmptyString;
+
+ GameOptions tempOpt = optIt->second;
+ return ( (tempOpt.list_map)[key].cbx_choices[ (tempOpt.list_map)[key].cur_choice_index ] );
+ }
+ }
+
+ // at this point retrieval failed
+ return wxEmptyString;
+}
+
+wxString OptionsWrapper::GetNameListOptItemKey(wxString optkey, wxString itemname, GameOption flag) const
+{
+ OptionType optType;
+ if ( keyExists(optkey,flag,false, optType) )
+ {
+ if ( optType == opt_list)
+ {
+ GameOptionsMapCIter optIt = m_opts.find((int)flag);
+ if ( optIt == m_opts.end() )
+ return wxEmptyString;
+
+ GameOptions tempOpt = optIt->second;
+ for (ListItemVec::iterator it = (tempOpt.list_map)[optkey].listitems.begin(); it != (tempOpt.list_map)[optkey].listitems.end(); ++it)
+ {
+ if (it->name == itemname)
+ return it->key;
+ }
+ }
+ }
+
+ // at this point retrieval failed
+ return wxEmptyString;
+}
+
+void OptionsWrapper::ParseSectionMap( mmSectionTree& section_tree, const IUnitSync::OptionMapSection& section_map )
+{
+
+ // map child-key <-> parent-key
+ typedef std::map<wxString,wxString> RelationMap;
+ typedef std::map<wxString,wxString>::iterator RelationMapIter;
+ RelationMap relation_map;
+
+ //setup relation map
+ for ( IUnitSync::OptionMapSectionConstIter it = section_map.begin(); it != section_map.end(); ++it )
+ {
+ relation_map[it->second.key] = it->second.section;
+ }
+
+ RelationMapIter rit = relation_map.begin();
+ // no more items in the map means we've added them all
+ while ( relation_map.size() > 0 )
+ {
+ RelationMapIter rit_next = rit; // in case we need to delete
+ ++rit_next;
+
+ if ( relation_map.find(rit->second) == relation_map.end() )
+ {
+ //either we already added this sections parent or it's a root section
+ IUnitSync::OptionMapSectionConstIter section = section_map.find(rit->first);
+ assert ( section != section_map.end() );
+ section_tree.AddSection( section->second );
+
+
+ //we're done with this section, so remove it
+ relation_map.erase(rit);
+ }
+
+ rit = rit_next;
+
+ //we've reached the end of the map, restart at beginning
+ if ( rit == relation_map.end() )
+ rit = relation_map.begin();
+ }
+
+}
+
+mmSectionTree::mmSectionTree()
+ : m_tree ( 0 )
+{
+ m_tree = new ConfigType( _T("SL-temp"), wxEmptyString, wxFileName::CreateTempFileName( _T("springlobby-") ) );
+}
+
+mmSectionTree::~mmSectionTree()
+{
+ //! \todo wth does this segfault?
+// if ( m_tree ) {
+// delete m_tree;
+// m_tree = 0;
+// }
+ #ifndef NDEBUG
+ m_tree->Flush();
+ #else //no need to clutter tempfile directory if we're not debugging
+ m_tree->DeleteAll();
+ #endif
+}
+
+void mmSectionTree::AddSection ( const wxString& parentpath, const mmOptionSection& section )
+{
+ wxString fullpath = parentpath + _T("/") + section.key + _T("/");
+ m_tree->Write( fullpath + _T("key") ,section.key );
+ #ifndef NDEBUG
+ m_tree->Flush();
+ #endif
+}
+
+bool mmSectionTree::FindRecursive( const wxString& parent_key, wxString& path )
+{
+ wxString current;
+ long cur_index;
+
+ //search current level first before recursing
+ bool cont = m_tree->GetFirstGroup( current, cur_index );
+ while ( cont )
+ {
+ if ( current.EndsWith( parent_key ) ) {
+ path = current;
+ return true;
+ }
+ cont = m_tree->GetNextGroup( current, cur_index );
+ }
+
+ //we need to recurse into sub-paths
+ cont = m_tree->GetFirstGroup( current, cur_index );
+ while ( cont )
+ {
+ wxString old_path = m_tree->GetPath();
+ m_tree->SetPath( old_path + _T("/") + current );
+ if ( FindRecursive( parent_key, path ) )
+ return true;
+ m_tree->SetPath( old_path );
+ cont = m_tree->GetNextGroup( current, cur_index );
+ }
+ return false;
+}
+
+wxString mmSectionTree::FindParentpath ( const wxString& parent_key )
+{
+ wxString path = _T("/");
+ if ( FindRecursive( parent_key, path ) )
+ return path;
+ else
+ return _T("");
+}
+
+void mmSectionTree::AddSection( const mmOptionSection section)
+{
+ m_section_map[section.key] = section;
+ wxString name = section.section;
+ if ( section.section == SLGlobals::nosection_name )
+ {
+ AddSection( _T("/"), section );
+ }
+ else
+ {
+ wxString parent = FindParentpath( section.section );
+ AddSection( parent , section );
+ }
+}
+
+//mmSectionTree::SectionVector mmSectionTree::GetSectionVector()
+//{
+//
+//}
+
+void mmSectionTree::Clear()
+{
+ m_section_map.clear();
+ m_tree->DeleteAll();
+}
diff --git a/src/mmoptionswrapper.h b/src/mmoptionswrapper.h
new file mode 100644
index 0000000..3c589f2
--- /dev/null
+++ b/src/mmoptionswrapper.h
@@ -0,0 +1,189 @@
+#ifndef MMOPTIONSORAPPER_H_
+#define MMOPTIONSORAPPER_H_
+
+#include "iunitsync.h"
+
+#include <vector>
+#include <utility>
+#include <wx/string.h>
+
+struct GameOptions;
+
+class wxFileConfig;
+
+class mmSectionTree {
+
+ public:
+ mmSectionTree();
+ ~mmSectionTree();
+
+ void AddSection( const mmOptionSection );
+ mmOptionSection GetSection( const wxString& key );
+
+ typedef std::vector< mmOptionSection > SectionVector;
+
+// SectionVector GetSectionVector();
+
+ void Clear();
+
+ protected:
+ //map key -> option
+ typedef std::map< wxString, mmOptionSection > SectionMap;
+ SectionMap m_section_map;
+ typedef wxFileConfig ConfigType;
+ ConfigType* m_tree;
+
+ void AddSection ( const wxString& path, const mmOptionSection& section );
+ wxString FindParentpath ( const wxString& parent_key );
+ bool FindRecursive( const wxString& parent_key, wxString& path );
+
+};
+
+class OptionsWrapper
+{
+public:
+ //! public types
+ typedef std::pair < wxString,wxString> wxStringPair;
+ typedef std::pair < wxString, wxStringPair> wxStringTriple;
+ typedef std::vector<wxStringPair> wxStringPairVec;
+ typedef std::vector<wxStringTriple> wxStringTripleVec;
+ typedef std::map<wxString,wxString> wxStringMap;
+ typedef std::map<int, GameOptions> GameOptionsMap;
+ typedef std::map<int, mmSectionTree> mmSectionTreeMap;
+
+ //! enum to differentiate option category easily at runtime
+ enum GameOption{
+ PrivateOptions = 3,
+ EngineOption = 2,
+ MapOption = 1,
+ ModOption = 0,
+ LastOption = 4
+ };// should reflect: optionCategoriesCount
+
+ //does nothing
+ OptionsWrapper();
+ virtual ~OptionsWrapper();
+ //! just calls loadOptions(MapOption,mapname)
+ bool loadMapOptions(wxString mapname);
+
+ bool loadAIOptions( const wxString& modname, int aiindex, const wxString& ainick );
+
+ int GetAIOptionIndex( const wxString& nick );
+
+ //! load corresponding options through unitsync calls
+ /*!
+ * the containers for corresponding flag are recreated and then gets the number of options from unitsync
+ * and adds them one by one to the appropiate container
+ * \param flag decides which type of option to load
+ * \return true if load successful, false otherwise
+ */
+ bool loadOptions(GameOption flag, const wxString& name );
+ //! checks if given key can be found in specified container
+ /*!
+ * \param key the key that should be checked for existance in containers
+ * \param flag which GameOption conatiner should be searched
+ * \param showError if true displays a messagebox if duplicate key is found
+ * \param optType will contain the corresponding OptionType if key is found, opt_undefined otherwise
+ * \return true if key is found, false otherwise
+ */
+ bool keyExists(wxString key,GameOption flag,bool showError, OptionType& optType) const;
+ //! checks if given key can be found in all containers
+ /*!
+ * \param key the key that should be checked for existance in containers
+ * \return true if key is found, false otherwise
+ */
+ bool keyExists(wxString key ) const;
+ //! checks which container this key belongs to
+ /*!
+ * \param key the key that should be checked for existance in containers
+ * \return they container section
+ */
+ GameOption GetSection( wxString& key ) const;
+ //! given a vector of key/value pairs sets the appropiate options to new values
+ /*! Every new value is tested for meeting boundary conditions, type, etc.
+ * If test fails error is logged and false is returned.
+ * \param values the wxStringPairVec containing key / new value pairs
+ * \param flag which OptionType is to be processed
+ * \return false if ANY error occured, true otherwise
+ */
+ bool setOptions(wxStringPairVec* values,GameOption flag);
+ //! get all options of one GameOption
+ /*! the output has the following format: < wxString , Pair < wxString , wxString > >
+ * meaning < key , < name , value > >
+ * \param triples this will contain the options after the function
+ * \param flag which OptionType is to be processed
+ */
+ wxStringTripleVec getOptions( GameOption flag ) const;
+ //! similar to getOptions, instead of vector a map is used and the name is not stored
+ std::map<wxString,wxString> getOptionsMap(GameOption) const;
+ //! recreates ALL containers
+ void unLoadOptions();
+ //! recreates the containers of corresponding flag
+ void unLoadOptions(GameOption flag);
+
+ //! returns value of specified key
+ /*! searches all containers for key
+ * \return value of key if key found, "" otherwise
+ */
+ wxString getSingleValue(wxString key) const;
+ //! returns value of specified key
+ /*! searches containers of type flag for key
+ * \return value of key if key found, "" otherwise
+ */
+
+ wxString getSingleValue(wxString key, GameOption flag) const;
+
+ wxString getDefaultValue(wxString key, GameOption flag) const;
+
+ //! sets a single option in specified container
+ /*! \return true if success, false otherwise */
+ bool setSingleOption(wxString key, wxString value, GameOption modmapFlag);
+ //! same as before, but tries all containers
+ bool setSingleOption(wxString key, wxString value);
+
+ //! returns the option type of specified key (all containers are tried)
+ OptionType GetSingleOptionType (wxString key) const;
+
+ //!returns the cbx_choice associated w current listoption
+ wxString GetNameListOptValue(wxString key, GameOption flag) const;
+
+ //! returns the listitem key associated with listitem name
+ wxString GetNameListOptItemKey(wxString optkey, wxString itemname, GameOption flag) const;
+
+ GameOptionsMap m_opts;
+
+ //! after loading sections into map, parse them into tree
+ void ParseSectionMap( mmSectionTree& section_tree, const IUnitSync::OptionMapSection& section_map );
+protected:
+ //! used for code clarity in setOptions()
+ bool setSingleOptionTypeSwitch(wxString key, wxString value, GameOption modmapFlag, OptionType optType);
+
+ mmSectionTreeMap m_sections;
+
+ //! a map that connects the ai nick with it's set of options
+ std::map<wxString, int> m_ais_indexes;
+
+ typedef GameOptionsMap::const_iterator
+ GameOptionsMapCIter;
+
+};
+
+#endif /*MMOPTIONSORAPPER_H_*/
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mmoptionwindows.cpp b/src/mmoptionwindows.cpp
new file mode 100644
index 0000000..0d43f03
--- /dev/null
+++ b/src/mmoptionwindows.cpp
@@ -0,0 +1,141 @@
+#include "mmoptionwindows.h"
+
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/statline.h>
+#include <wx/choice.h>
+#include <wx/button.h>
+#include <wx/intl.h>
+#include <wx/checkbox.h>
+#include <wx/slider.h>
+#include <wx/combobox.h>
+#include <wx/tipwin.h>
+#include <wx/tooltip.h>
+
+#include "mmoptionswrapper.h"
+#include "ui.h"
+#include "battle.h"
+#include "utils/controls.h"
+#include "utils/math.h"
+#include "utils/conversion.h"
+#include "spinctld.h"
+
+BEGIN_EVENT_TABLE( SingleOptionDialog, wxDialog )
+
+END_EVENT_TABLE()
+
+SingleOptionDialog::SingleOptionDialog( IBattle& battle, const wxString& optiontag )
+ : m_battle( battle ),
+ m_tag( optiontag ),
+ m_checkbox( 0 ),
+ m_combobox( 0 ),
+ m_spinctrl( 0 ),
+ m_textctrl( 0 )
+{
+ OptionsWrapper& optWrap = m_battle.CustomBattleOptions();
+ OptionsWrapper::GameOption optFlag = ( OptionsWrapper::GameOption )s2l( optiontag.BeforeFirst( '_' ) );
+ wxString key = optiontag.AfterFirst( '_' );
+ OptionType type = optWrap.GetSingleOptionType( key );
+ Create( ( wxWindow* )&ui().mw(), wxID_ANY, _( "Change option" ), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, _T( "OptionDialog" ) );
+ if ( !optWrap.keyExists( key, optFlag, false, type ) )
+ {
+ EndModal( wxID_CANCEL );
+ return;
+ }
+
+ wxBoxSizer* m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ // wxStaticText* m_labelctrl = wxStaticText();
+
+ switch ( type )
+ {
+ case opt_bool:
+ {
+ mmOptionBool opt = optWrap.m_opts[optFlag].bool_map[key];
+ m_checkbox = new wxCheckBox( this, wxID_ANY, opt.name );
+ m_checkbox->SetToolTip( TE( opt.description ) );
+ m_checkbox->SetValue( opt.value );
+ m_main_sizer->Add( m_checkbox, 0, wxEXPAND );
+ break;
+ }
+ case opt_float:
+ {
+ mmOptionFloat opt = optWrap.m_opts[optFlag].float_map[key];
+ m_spinctrl = new wxSpinCtrlDbl();
+ m_spinctrl->Create( this, wxID_ANY, _T( "" ), wxDefaultPosition, wxDefaultSize, 0, double( opt.min ), double( opt.max ), double( opt.value ), double( opt.stepping ), wxSPINCTRLDBL_AUTODIGITS, opt.key );
+ m_spinctrl->SetToolTip( TE( opt.description ) );
+ m_main_sizer->Add( m_spinctrl, 0, wxEXPAND );
+ break;
+ }
+ case opt_string:
+ {
+ mmOptionString opt = optWrap.m_opts[optFlag].string_map[key];
+ m_textctrl = new wxTextCtrl( this, wxID_ANY, opt.value, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, opt.key );
+ m_textctrl->SetToolTip( TE( opt.description ) );
+ m_main_sizer->Add( m_textctrl, 0, wxEXPAND );
+ break;
+ }
+ case opt_list:
+ {
+ mmOptionList opt = optWrap.m_opts[optFlag].list_map[key];
+ int temp = int( opt.cbx_choices.GetCount() - 1 );
+ int index = clamp( opt.cur_choice_index, 0, temp );
+ m_combobox = new wxComboBox( this, wxID_ANY, opt.cbx_choices[index], wxDefaultPosition, wxDefaultSize, opt.cbx_choices, wxCB_READONLY, wxDefaultValidator );
+ wxString tooltip = opt.description + _T( "\n" );
+ for ( ListItemVec::iterator itor = opt.listitems.begin(); itor != opt.listitems.end(); itor++ )
+ {
+ tooltip += _T( "\n" ) + itor->name + _T( ": " ) + itor->desc;
+ }
+ m_combobox->SetToolTip( TE( tooltip ) );
+ m_main_sizer->Add( m_combobox, 0, wxEXPAND );
+ break;
+ }
+ default:
+ {
+ EndModal( wxID_CANCEL );
+ return;
+ break;
+ }
+ }
+
+ wxSize __SpacerSize_1 = wxDLG_UNIT( this, wxSize( 0, 0 ) );
+ m_main_sizer->Add( __SpacerSize_1.GetWidth(), __SpacerSize_1.GetHeight(), 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5 );
+ wxStaticLine* m_separator1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxSize( 10, -1 ), wxLI_HORIZONTAL, _T( "ID_STATICLINE1" ) );
+ m_main_sizer->Add( m_separator1, 0, wxALL | wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5 );
+ wxBoxSizer* m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_cancel_button = new wxButton( this, ID_CANCEL, _( "Cancel" ), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T( "ID_CANCEL" ) );
+ m_buttons_sizer->Add( m_cancel_button, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5 );
+ m_buttons_sizer->Add( 0, 0, 1, wxALL | wxEXPAND | wxSHAPED | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 0 );
+ m_ok_button = new wxButton( this, ID_OK, _( "Ok" ), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T( "ID_OK" ) );
+ m_buttons_sizer->Add( m_ok_button, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5 );
+ m_main_sizer->Add( m_buttons_sizer, 0, wxALL | wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 0 );
+
+
+ m_main_sizer->Fit( this );
+ m_main_sizer->SetSizeHints( this );
+
+ SetSizer( m_main_sizer );
+ Layout();
+
+ Connect( ID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED, ( wxObjectEventFunction )&SingleOptionDialog::OnCancel );
+ Connect( ID_OK, wxEVT_COMMAND_BUTTON_CLICKED, ( wxObjectEventFunction )&SingleOptionDialog::OnOk );
+}
+
+void SingleOptionDialog::OnCancel( wxCommandEvent& /*unused*/ )
+{
+ EndModal( wxID_CANCEL );
+}
+
+void SingleOptionDialog::OnOk( wxCommandEvent& /*unused*/ )
+{
+ OptionsWrapper::GameOption optFlag = ( OptionsWrapper::GameOption )s2l( m_tag.BeforeFirst( '_' ) );
+ wxString key = m_tag.AfterFirst( '_' );
+ wxString value;
+ if ( m_textctrl ) value = m_textctrl->GetValue();
+ else if ( m_combobox ) value = m_battle.CustomBattleOptions().GetNameListOptItemKey( key, m_combobox->GetValue(), optFlag );
+ else if ( m_spinctrl ) value = TowxString( m_spinctrl->GetValue() );
+ else if ( m_checkbox ) value = TowxString( m_checkbox->GetValue() );
+ m_battle.CustomBattleOptions().setSingleOption( key, value, optFlag );
+ m_battle.SendHostInfo( m_tag );
+ EndModal( wxID_OK );
+}
diff --git a/src/mmoptionwindows.h b/src/mmoptionwindows.h
new file mode 100644
index 0000000..4d0bf84
--- /dev/null
+++ b/src/mmoptionwindows.h
@@ -0,0 +1,62 @@
+#ifndef MMOPTIONWINDOWS_H_INCLUDED
+#define MMOPTIONWINDOWS_H_INCLUDED
+
+#include <wx/dialog.h>
+
+class wxCheckBox;
+class wxComboBox;
+class wxCommandEvent;
+class IBattle;
+class wxSpinCtrlDbl;
+class wxTextCtrl;
+class wxStaticText;
+class wxButton;
+
+class SingleOptionDialog: public wxDialog
+{
+
+ public:
+ SingleOptionDialog( IBattle& battle, const wxString& optiontag );
+
+ void OnOk(wxCommandEvent& event);
+ void OnCancel(wxCommandEvent& event);
+
+ protected:
+ IBattle& m_battle;
+ wxString m_tag;
+
+ wxCheckBox* m_checkbox;
+ wxComboBox* m_combobox;
+ wxSpinCtrlDbl* m_spinctrl;
+ wxTextCtrl* m_textctrl;
+ wxButton* m_cancel_button;
+ wxButton* m_ok_button;
+
+ DECLARE_EVENT_TABLE();
+};
+
+enum
+{
+ ID_CANCEL = wxID_HIGHEST,
+ ID_OK
+};
+
+#endif // MMOPTIONWINDOWS_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/mutexwrapper.h b/src/mutexwrapper.h
new file mode 100644
index 0000000..b1102c2
--- /dev/null
+++ b/src/mutexwrapper.h
@@ -0,0 +1,96 @@
+#ifndef MUTEXWRAPPER_H
+#define MUTEXWRAPPER_H
+#include <wx/thread.h>
+#include <wx/log.h>
+
+template<class T>
+class MutexWrapper;
+
+class AbstractMutexWrapper{
+ public:
+ virtual ~AbstractMutexWrapper(){};
+ virtual void Lock()=0;
+ virtual void UnLock()=0;
+};
+
+template<class T>
+class ScopedLocker
+{
+ private:
+ MutexWrapper<T> &mw;
+ ScopedLocker(const ScopedLocker<T> &other){}/// prevent copying
+ ScopedLocker& operator= (const ScopedLocker& other){}/// and assignment
+ public:
+ explicit ScopedLocker(MutexWrapper<T> &mw_):mw(mw_){
+ mw.Lock();
+ }
+ ~ScopedLocker(){
+ mw.UnLock();
+ }
+ T &Get(){
+ return mw.GetData();
+ }
+};
+/*
+class ScopedLocker
+{
+ private:
+ AbstractMutexWrapper *mw;
+ ScopedLocker(const ScopedLocker<T> &other){}/// prevent copying
+ ScopedLocker& operator= (const ScopedLocker& other){}/// and assignment
+ public:
+ explicit ScopedLocker(AbstractMutexWrapper &mw_):mw(*mw_){
+ mw.Lock();
+ }
+ ~ScopedLocker(){
+ mw.UnLock();
+ }
+};*/
+
+
+template<class T>
+class MutexWrapper: public AbstractMutexWrapper
+{
+ wxCriticalSection mutex;/// critical section is same as mutex except on windows it only works within one process (i.e. program). I'm gonna call it mutex.
+ T data;
+ bool locked;
+ public:
+ MutexWrapper():locked(false){
+ }
+ virtual ~MutexWrapper(){
+ }
+ virtual void Lock(){
+ mutex.Enter();
+ locked=true;
+ }
+ virtual void UnLock(){
+ locked=false;
+ mutex.Leave();
+ }
+ protected:
+ T &GetData(){
+ if(!locked)wxLogError(_T("serious error in MutexWrapper usage : not locked, but Get() is called!"));
+ return data;
+ }
+ friend class ScopedLocker<T>;
+};
+
+#endif // MUTEXWRAPPER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/nicklistctrl.cpp b/src/nicklistctrl.cpp
new file mode 100644
index 0000000..f8e665d
--- /dev/null
+++ b/src/nicklistctrl.cpp
@@ -0,0 +1,331 @@
+/* Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: NickListCtrl
+//
+
+#include <wx/platform.h>
+#include <wx/imaglist.h>
+#include <wx/menu.h>
+#include <wx/string.h>
+#include <wx/intl.h>
+#include <stdexcept>
+#include <wx/log.h>
+#include <algorithm>
+
+#include "nicklistctrl.h"
+#include "utils/math.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "iconimagelist.h"
+#include "user.h"
+#include "settings.h"
+#include "ui.h"
+#include "mainwindow.h"
+#include "countrycodes.h"
+#include "chatpanel.h"
+#include "userlist.h"
+#include "usermenu.h"
+#include "Helper/sortutil.h"
+
+
+
+BEGIN_EVENT_TABLE( NickListCtrl, NickListCtrl::BaseType )
+ EVT_LIST_ITEM_ACTIVATED ( NICK_LIST, NickListCtrl::OnActivateItem )
+ EVT_CONTEXT_MENU ( NickListCtrl::OnShowMenu )
+ #if wxUSE_TIPWINDOW
+ #ifndef __WXMSW__ //disables tooltips on win and mac
+ EVT_MOTION ( NickListCtrl::OnMouseMotion )
+ #endif
+ #endif
+END_EVENT_TABLE()
+
+template<> SortOrder NickListCtrl::BaseType::m_sortorder = SortOrder( ) ;
+
+NickListCtrl::NickListCtrl( wxWindow* parent, bool show_header, NickListCtrl::UserMenu* popup, bool singleSelectList,
+ const wxString& name, bool highlight )
+ : NickListCtrl::BaseType( parent, NICK_LIST, wxDefaultPosition, wxDefaultSize,
+ wxLC_VIRTUAL | wxSUNKEN_BORDER | wxLC_REPORT | ( int )( !show_header ) * wxLC_NO_HEADER | ( int )( singleSelectList ) * wxLC_SINGLE_SEL,
+ name, 4, 3, &CompareOneCrit, highlight, UserActions::ActHighlight, true /*periodic sort*/ ),
+ m_menu( popup )
+{
+
+#if defined(__WXMAC__)
+ const int widths [4] = { 20, 20, 20, 120 };
+#else
+ const int widths [4] = { 20, 20, 20, 120 };
+#endif
+
+ AddColumn( 0, widths[0], _( "s" ), _T( "Status" ) );
+ AddColumn( 1, widths[1], _( "c" ), _T( "Country" ) );
+ AddColumn( 2, widths[2], _( "r" ), _T( "Rank" ) );
+ AddColumn( 3, widths[3], _( "Nickname" ), _T( "Nickname" ) );
+
+ if ( m_sortorder.size() == 0 ) {
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = -1;
+ m_sortorder[1].col = 3;
+ m_sortorder[1].direction = 1;
+ m_sortorder[2].col = 2;
+ m_sortorder[2].direction = 1;
+ m_sortorder[3].col = 1;
+ m_sortorder[3].direction = 1;
+ }
+}
+
+NickListCtrl::~NickListCtrl()
+{
+
+}
+
+void NickListCtrl::AddUser( const User& user )
+{
+ if ( AddItem( &user ) )
+ return;
+
+ wxLogWarning( _T( "Useralready in list." ) );
+}
+
+void NickListCtrl::RemoveUser( const User& user )
+{
+ if ( RemoveItem( &user ) )
+ return;
+
+ wxLogError( _T( "Didn't find the user to remove." ) );
+}
+
+
+void NickListCtrl::UserUpdated( const User& user )
+{
+ int index = GetIndexFromData( &user );
+ if ( index != -1 ) {
+ m_data[index] = &user;
+ MarkDirtySort();
+ RefreshItem( index );
+ }
+ else {
+ wxLogWarning( _T( "NickListCtrl::UserUpdated error, index == -1 ." ) );
+ }
+}
+
+void NickListCtrl::ClearUsers()
+{
+ Clear();
+}
+
+void NickListCtrl::OnActivateItem( wxListEvent& event )
+{
+ int index = event.GetIndex();
+ if ( index == -1 )
+ return;
+
+ const User* user = m_data[index];
+ if ( user ) {
+ ui().mw().OpenPrivateChat( *user, true ); //true --> setfoucs
+ }
+ SetSelectedIndex( index );
+}
+
+
+void NickListCtrl::OnShowMenu( wxContextMenuEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T( "" ) );
+ if ( m_menu != 0 )
+ {
+ //no need to popup the menu when there's no user selected
+ int selected = GetSelectedIndex();
+ if ( selected != -1 && m_data[selected] ) {
+ const User& user = *m_data[selected];
+ wxString nick = user.GetNick();
+ m_menu->EnableItems( ( selected != -1 ), nick );
+ PopupMenu( m_menu );
+ }
+ }
+}
+
+void NickListCtrl::SetTipWindowText( const long item_hit, const wxPoint& position )
+{
+
+ int column = getColumnFromPosition( position );
+ if ( column > ( int )m_colinfovec.size() || column < 0 || item_hit < 0 || item_hit > ( long ) m_data.size() || m_data[item_hit] == NULL )
+ {
+ m_tiptext = _T( "" );
+ }
+ else
+ {
+ const User& user = *m_data[item_hit];
+ {
+ switch ( column )
+ {
+ case 0: // status
+ m_tiptext = _T( "This " );
+ if ( user.GetStatus().bot )
+ m_tiptext << _T( "bot " );
+ else if ( user.GetStatus().moderator )
+ m_tiptext << _T( "moderator " );
+ else
+ m_tiptext << _T( "player " );
+
+ if ( user.GetStatus().in_game )
+ m_tiptext << _T( "is ingame" );
+ else if ( user.GetStatus().away )
+ m_tiptext << _T( "is away" );
+ else
+ m_tiptext << _T( "is available" );
+ break;
+
+ case 1: // country
+ m_tiptext = GetFlagNameFromCountryCode( user.GetCountry().Upper() );
+ break;
+
+ case 2: // rank
+ m_tiptext = user.GetRankName( user.GetStatus().rank );
+ break;
+
+ case 3: // nickname
+ m_tiptext = user.GetNick();
+ break;
+
+ default:
+ m_tiptext = m_colinfovec[column].tip;
+ break;
+ }
+ }
+ }
+}
+
+wxListItemAttr* NickListCtrl::GetItemAttr( long item ) const
+{
+ if ( item < ( long ) m_data.size() && item > -1 ) {
+ const User& u = *m_data[item];
+ wxString name = u.GetNick();
+ return HighlightItemUser( name );
+ }
+ return NULL;
+}
+
+void NickListCtrl::HighlightItem( long /*unused*/ )
+{
+
+}
+
+int NickListCtrl::GetIndexFromData( const DataType& data ) const
+{
+ const User* user = data;
+ static long seekpos;
+ seekpos = clamp( seekpos, 0l , ( long )m_data.size() );
+ int index = seekpos;
+
+ for ( DataCIter f_idx = m_data.begin() + seekpos; f_idx != m_data.end() ; ++f_idx )
+ {
+ if ( user == *f_idx )
+ {
+ seekpos = index;
+ return seekpos;
+ }
+ index++;
+ }
+ //it's ok to init with seekpos, if it had changed this would not be reached
+ int r_index = seekpos - 1;
+ for ( DataRevCIter r_idx = m_data.rbegin() + ( m_data.size() - seekpos ); r_idx != m_data.rend() ; ++r_idx )
+ {
+ if ( user == *r_idx )
+ {
+ seekpos = r_index;
+ return seekpos;
+ }
+ r_index--;
+ }
+
+ return -1;
+}
+
+void NickListCtrl::Sort()
+{
+ if ( m_data.size() > 0 )
+ {
+ SaveSelection();
+ SLInsertionSort( m_data, m_comparator );
+ RestoreSelection();
+ }
+}
+
+wxString NickListCtrl::GetItemText( long item, long column ) const
+{
+ switch ( column ) {
+ case 0:
+ case 1:
+ case 2:
+ default:
+ return wxEmptyString;
+
+ case 3:
+ return ( m_data[item] ? m_data[item]->GetNick() : wxString() );
+ }
+}
+
+int NickListCtrl::GetItemColumnImage( long item, long column ) const
+{
+ if ( m_data[item] ) {
+ const User& user = *m_data[item];
+ switch ( column ) {
+ case 0:
+ return user.GetStatusIconIndex();
+ case 1:
+ return user.GetFlagIconIndex();
+ case 2:
+ return user.GetRankIconIndex();
+
+ case 3:
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+int NickListCtrl::CompareOneCrit( DataType u1, DataType u2, int col, int dir )
+{
+ switch ( col ) {
+ case 0:
+ return dir * CompareUserStatus( u1, u2 );
+ case 1:
+ return dir * u2->GetCountry().CmpNoCase( u1->GetCountry() );
+ case 2:
+ return dir * compareSimple( u2->GetStatus().rank, u1->GetStatus().rank );
+ case 3:
+ return dir * u2->GetNick().CmpNoCase( u1->GetNick() ) ;
+ default:
+ return 0;
+ }
+}
+
+int NickListCtrl::CompareUserStatus( DataType user1, DataType user2 )
+{
+
+ ASSERT_LOGIC( user1 != 0, _T( "user1 = 0" ) );
+ ASSERT_LOGIC( user2 != 0, _T( "user2 = 0" ) );
+
+ int u1 = 0, u2 = 0;
+
+ if ( user1->GetStatus().bot )
+ u1 += 1000;
+ if ( user2->GetStatus().bot )
+ u2 += 1000;
+ if ( user1->GetStatus().moderator )
+ u1 += 100;
+ if ( user2->GetStatus().moderator )
+ u2 += 100;
+ if ( user1->GetStatus().in_game )
+ u1 += -10;
+ if ( user2->GetStatus().in_game )
+ u2 += -10;
+
+ // inverse the order
+ if ( u1 < u2 )
+ return -1;
+ if ( u1 > u2 )
+ return 1;
+
+ return 0;
+}
+
diff --git a/src/nicklistctrl.h b/src/nicklistctrl.h
new file mode 100644
index 0000000..5c28be3
--- /dev/null
+++ b/src/nicklistctrl.h
@@ -0,0 +1,82 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_NICKLISTCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_NICKLISTCTRL_H
+
+#include "customvirtlistctrl.h"
+#include "usermenu.h"
+
+class User;
+class UserList;
+class Ui;
+class ChatPanel;
+class UserMenu;
+
+class NickListCtrl : public CustomVirtListCtrl< const User* ,NickListCtrl >
+{
+ protected:
+ typedef SL_GENERIC::UserMenu<ChatPanel> UserMenu;
+
+ public:
+ NickListCtrl( wxWindow* parent, bool show_header = true, UserMenu* popup = 0,
+ bool singleSelectList = true, const wxString& name = _T("NickListCtrl"), bool highlight = true );
+ virtual ~NickListCtrl();
+
+ virtual void AddUser( const User& user );
+ void RemoveUser( const User& user );
+
+ void UserUpdated( const User& user );
+
+ void ClearUsers();
+
+ void OnActivateItem( wxListEvent& event );
+ void OnShowMenu( wxContextMenuEvent& event );
+ virtual void SetTipWindowText( const long item_hit, const wxPoint& position);
+
+ void HighlightItem( long item );
+
+ //these are overloaded to use list in virtual style
+ wxString GetItemText(long item, long column) const;
+ int GetItemColumnImage(long item, long column) const;
+ wxListItemAttr * GetItemAttr(long item) const;
+
+ protected:
+
+ //! passed as callback to generic ItemComparator, returns -1,0,1 as per defined ordering
+ static int CompareOneCrit( DataType u1, DataType u2, int col, int dir );
+ //! utils func for comparing user status, so the CompareOneCrit doesn't get too crowded
+ static int CompareUserStatus( DataType u1, DataType u2 );
+ //! required per base clase
+ virtual void Sort( );
+
+ int GetIndexFromData( const DataType& data ) const;
+
+ UserMenu* m_menu;
+
+ enum {
+ NICK_LIST = 31765 //wxID_HIGHEST
+ //wxID_HIGHEST is used by BattleListCTRL. The cant be in the same Tab like BattleTab
+ };
+
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_NICKLISTCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/nonportable.h b/src/nonportable.h
new file mode 100644
index 0000000..469570b
--- /dev/null
+++ b/src/nonportable.h
@@ -0,0 +1,43 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_NONPORTABLE_H
+#define SPRINGLOBBY_HEADERGUARD_NONPORTABLE_H
+
+#if defined(__WXMSW__)
+ #define SPRING_VERSION_PARAM _T("/V")
+ #define CHOOSE_EXE _("Executables (*.exe)|*.exe|Any File (*.*)|*.*")
+ #define USYNC_CALL_CONV __stdcall
+ #define SPRING_BIN _T("spring.exe")
+ #define DOS_TXT true
+ #define SL_DUMMY_COL //for custom virt listctrls
+#elif defined(__WXGTK__) || defined(__WXX11__)
+ #define SPRING_VERSION_PARAM _T("-V")
+ #define CHOOSE_EXE _("Any file (*)|*")
+ #define USYNC_CALL_CONV
+ #define SPRING_BIN _T("spring")
+ #define DOS_TXT false
+#elif defined(__WXMAC__)
+ #define SPRING_VERSION_PARAM _T("-V")
+ #define CHOOSE_EXE _("App Bundles (*.app)|*.app|Any File (*.*)|*.*")
+ #define USYNC_CALL_CONV
+ #define SPRING_BIN _T("Spring.app")
+ #define DOS_TXT false
+#endif
+
+#endif // SPRINGLOBBY_HEADERGUARD_NONPORTABLE_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/offlinebattle.cpp b/src/offlinebattle.cpp
new file mode 100644
index 0000000..cc8f6ae
--- /dev/null
+++ b/src/offlinebattle.cpp
@@ -0,0 +1,72 @@
+#include "offlinebattle.h"
+#include "spring.h"
+#include "ui.h"
+
+#include <wx/timer.h>
+
+OfflineBattle::OfflineBattle( const int id ):
+m_id( id ),
+m_me( User(_T("Spectator")) )
+{
+ m_opts.founder = m_me.GetNick();
+ OnUserAdded( m_me );
+ UserBattleStatus& newstatus = m_me.BattleStatus();
+ newstatus.spectator = true;
+ newstatus.sync = true;
+}
+
+OfflineBattle::OfflineBattle():
+m_id( 0 ),
+m_me( User(_T("Spectator")) )
+{
+ m_opts.founder = m_me.GetNick();
+ OnUserAdded( m_me );
+ UserBattleStatus& newstatus = m_me.BattleStatus();
+ newstatus.spectator = true;
+ newstatus.sync = true;
+}
+
+void OfflineBattle::StartSpring()
+{
+ spring().Run(*this);
+ ui().OnSpringStarting();
+}
+
+OfflineBattle::OfflineBattle ( const OfflineBattle& other )
+{
+ *this = other;
+}
+
+OfflineBattle& OfflineBattle::operator = ( const OfflineBattle& other )
+{
+ m_map_loaded = other.m_map_loaded;
+ m_map_loaded = other.m_map_loaded;
+ m_mod_loaded = other.m_mod_loaded;
+ m_map_exists = other.m_map_exists;
+ m_mod_exists = other.m_mod_exists;
+ m_local_map = other.m_local_map;
+ m_local_mod = other.m_local_mod;
+ m_host_map = other.m_host_map;
+ m_host_mod = other.m_host_mod;
+ m_restricted_units = other.m_restricted_units;
+ m_opt_wrap = other.m_opt_wrap;
+ m_opts = other.m_opts;
+ m_ingame = other.m_ingame;
+ m_generating_script = other.m_generating_script;
+ m_rects = other.m_rects;
+ m_ready_up_map = other.m_ready_up_map; // player name -> time counting from join/unspect
+ m_players_ready = other.m_players_ready;
+ m_players_sync = other.m_players_sync;
+ m_teams_sizes = other.m_teams_sizes; // controlteam -> number of people in
+ m_ally_sizes = other.m_ally_sizes; // allyteam -> number of people in
+ m_preset = other.m_preset;
+ m_is_self_in = other.m_is_self_in;
+ m_internal_bot_list = other.m_internal_bot_list;
+ m_script = other.m_script;
+ m_playback_file_path = other.m_playback_file_path;
+ m_parsed_teams = other.m_parsed_teams;
+ m_parsed_allies = other.m_parsed_allies;
+ m_internal_user_list = other.m_internal_user_list;
+ m_timer = new wxTimer( other.m_timer ); //!no idea if this is proper
+ return *this;
+}
diff --git a/src/offlinebattle.h b/src/offlinebattle.h
new file mode 100644
index 0000000..5af2b87
--- /dev/null
+++ b/src/offlinebattle.h
@@ -0,0 +1,41 @@
+#ifndef OFFLINEBATTLE_H_INCLUDED
+#define OFFLINEBATTLE_H_INCLUDED
+
+#include "ibattle.h"
+
+class OfflineBattle : public IBattle
+{
+ public:
+ OfflineBattle ( const int id );
+ OfflineBattle ( );
+ OfflineBattle ( const OfflineBattle& );
+ OfflineBattle& operator = ( const OfflineBattle& );
+ ~OfflineBattle (){};
+ User& GetMe() { return m_me; }
+ bool IsFounderMe() { return true; }
+ void StartSpring();
+
+ protected:
+ int m_id;
+ User m_me;
+};
+
+#endif // OFFLINEBATTLE_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/playback/playbackfilter.cpp b/src/playback/playbackfilter.cpp
new file mode 100644
index 0000000..8bc7e40
--- /dev/null
+++ b/src/playback/playbackfilter.cpp
@@ -0,0 +1,441 @@
+
+#if wxUSE_TOGGLEBTN
+#include <wx/tglbtn.h>
+#endif
+#include <wx/stattext.h>
+#include <wx/checkbox.h>
+#include <wx/sizer.h>
+#include <wx/textctrl.h>
+#include <wx/intl.h>
+#include <wx/choice.h>
+#include <wx/button.h>
+#include <wx/string.h>
+#include <wx/statbox.h>
+#include <wx/event.h>
+#include <wx/regex.h>
+
+#include "playbacktab.h"
+#include "replaylist.h"
+//#include "PlaybackListFiltervalues.h"
+#include "playbackfiltervalues.h"
+#include "../battlelistctrl.h"
+#include "../battle.h"
+#include "../uiutils.h"
+#include "../utils/tasutil.h"
+#include "../utils/conversion.h"
+#include "../settings.h"
+
+
+///////////////////////////////////////////////////////////////////////////
+
+BEGIN_EVENT_TABLE_TEMPLATE1(PlaybackListFilter, wxPanel, PlaybackTabType)
+
+ EVT_BUTTON ( PLAYBACK_FILTER_PLAYER_BUTTON , PlaybackListFilter::OnPlayerButton )
+ EVT_BUTTON ( PLAYBACK_FILTER_DURATION_BUTTON , PlaybackListFilter::OnDurationButton )
+ EVT_BUTTON ( PLAYBACK_FILTER_FILESIZE_BUTTON , PlaybackListFilter::OnFilesizeButton )
+ EVT_CHOICE ( PLAYBACK_FILTER_PLAYER_CHOICE , PlaybackListFilter::OnPlayerChange )
+ EVT_TEXT ( PLAYBACK_FILTER_DURATION_EDIT , PlaybackListFilter::OnChangeDuration )
+ EVT_TEXT ( PLAYBACK_FILTER_FILESIZE_EDIT , PlaybackListFilter::OnChangeFilesize )
+ EVT_TEXT ( PLAYBACK_FILTER_MAP_EDIT , PlaybackListFilter::OnChangeMap )
+ EVT_TEXT ( PLAYBACK_FILTER_MOD_EDIT , PlaybackListFilter::OnChangeMod )
+ EVT_CHECKBOX ( PLAYBACK_FILTER_MAP_SHOW , PlaybackListFilter::OnChange )
+ EVT_CHECKBOX ( PLAYBACK_FILTER_MOD_SHOW , PlaybackListFilter::OnChange )
+
+END_EVENT_TABLE()
+
+template <class PlaybackTabType>
+PlaybackListFilter<PlaybackTabType>::PlaybackListFilter( wxWindow* parent, wxWindowID id, PlaybackTabType* parentTab,
+ const wxPoint& pos, const wxSize& size, long style )
+ : wxPanel( parent, id, pos, size, style ),
+ m_parent_tab( parentTab ), m_filter_map_edit(0),
+ m_filter_map_expression(0), m_filter_mod_edit(0),m_filter_mod_expression(0)
+
+{
+ PlaybackListFilterValues f_values = sett().GetReplayFilterValues( sett().GetLastReplayFilterProfileName() );
+
+ wxBoxSizer* m_filter_sizer;
+ m_filter_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxStaticBoxSizer* m_filter_body_sizer;
+ m_filter_body_sizer = new wxStaticBoxSizer( new wxStaticBox( this, -1, _("Filter settings") ), wxVERTICAL );
+
+ wxBoxSizer* m_filter_body_row2_sizer;
+ m_filter_body_row2_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+// wxBoxSizer* m_filter_player_sizer;
+// m_filter_player_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_player_text = new wxStaticText( this, wxID_ANY, _("Player:"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_player_text->Wrap( -1 );
+ m_filter_player_text->SetMinSize( wxSize( 90,-1 ) );
+ m_filter_body_row2_sizer ->Add( m_filter_player_text, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxArrayString m_filter_player_choiceChoices;
+
+ m_filter_player_choiceChoices.Add( _("All") );
+ for (wxLongLong i = 0;i <= 32;i++) m_filter_player_choiceChoices.Add( i.ToString() );
+
+ m_filter_player_choice = new wxChoice( this, PLAYBACK_FILTER_PLAYER_CHOICE, wxDefaultPosition, wxSize( -1,-1 ), m_filter_player_choiceChoices, 0 );
+ m_filter_player_choice->SetSelection( GetIntParam( f_values.player_num ) );
+ m_filter_player_choice->SetMinSize( wxSize( 140,-1 ) );
+
+ m_filter_body_row2_sizer ->Add( m_filter_player_choice, 0, wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_player_button = new wxButton( this, PLAYBACK_FILTER_PLAYER_BUTTON, f_values.player_mode, wxDefaultPosition, wxSize( 25, 25 ), 0 );
+ m_filter_body_row2_sizer ->Add( m_filter_player_button, 0, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+
+
+////map
+ wxBoxSizer* m_filter_body_row3_sizer;
+ m_filter_body_row3_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_map_sizer;
+ m_filter_map_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_map_text = new wxStaticText( this, wxID_ANY, _("Map:"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_map_text->Wrap( -1 );
+ m_filter_map_text->SetMinSize( wxSize( 90,-1 ) );
+
+ m_filter_map_sizer->Add( m_filter_map_text, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_map_edit = new wxTextCtrl( this, PLAYBACK_FILTER_MAP_EDIT, f_values.map, wxDefaultPosition, wxSize( -1,-1 ), 0|wxSIMPLE_BORDER );
+ m_filter_map_edit->SetMinSize( wxSize( 140,-1 ) );
+ m_filter_map_expression = new wxRegEx(m_filter_map_edit->GetValue(),wxRE_ICASE);
+
+ m_filter_map_sizer->Add( m_filter_map_edit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row3_sizer->Add( m_filter_map_sizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_only_map_sizer;
+ m_filter_only_map_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_map_show = new wxCheckBox( this, PLAYBACK_FILTER_MAP_SHOW, _("Only maps i have"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_map_show->SetValue(f_values.map_show);
+ m_filter_map_show->SetMinSize( wxSize( 140,-1 ) );
+
+ m_filter_only_map_sizer->Add( m_filter_map_show, 0, wxEXPAND|wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row3_sizer->Add( m_filter_only_map_sizer, 0, wxEXPAND, 5 );
+
+
+//// mod
+ wxBoxSizer* m_filter_body_row4_sizer;
+ m_filter_body_row4_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_mod_sizer;
+ m_filter_mod_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_mod_text = new wxStaticText( this, wxID_ANY, _("Mod:"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_mod_text->Wrap( -1 );
+ m_filter_mod_text->SetMinSize( wxSize( 90,-1 ) );
+
+ m_filter_mod_sizer->Add( m_filter_mod_text, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_mod_edit = new wxTextCtrl( this, PLAYBACK_FILTER_MOD_EDIT, f_values.mod, wxDefaultPosition, wxSize( -1,-1 ), 0|wxSIMPLE_BORDER );
+ m_filter_mod_edit->SetMinSize( wxSize( 140,-1 ) );
+ m_filter_mod_expression = new wxRegEx(m_filter_mod_edit->GetValue(), wxRE_ICASE);
+
+ m_filter_mod_sizer->Add( m_filter_mod_edit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row4_sizer->Add( m_filter_mod_sizer, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* m_filter_only_mod_sizer;
+ m_filter_only_mod_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_mod_show = new wxCheckBox( this, PLAYBACK_FILTER_MOD_SHOW, _("Only mods i have"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_mod_show->SetValue(f_values.mod_show);
+ m_filter_mod_show->SetMinSize( wxSize( 140,-1 ) );
+
+ m_filter_only_mod_sizer->Add( m_filter_mod_show, 0, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+
+ m_filter_body_row4_sizer->Add( m_filter_only_mod_sizer, 0, wxALIGN_LEFT|wxEXPAND, 5 );
+
+
+/////
+
+///// filesize
+ wxBoxSizer* m_filter_body_row5_sizer;
+ m_filter_body_row5_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_filesize_sizer;
+ m_filter_filesize_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_filesize_text = new wxStaticText( this, wxID_ANY, _("Filesize in KB:"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_filesize_text->Wrap( -1 );
+ m_filter_filesize_text->SetMinSize( wxSize( 90,-1 ) );
+
+ m_filter_filesize_sizer->Add( m_filter_filesize_text, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_filesize_edit = new wxTextCtrl( this, PLAYBACK_FILTER_FILESIZE_EDIT, f_values.filesize, wxDefaultPosition, wxSize( -1,-1 ), 0|wxSIMPLE_BORDER );
+ m_filter_filesize_edit->SetMinSize( wxSize( 140,-1 ) );
+
+ m_filter_filesize_sizer->Add( m_filter_filesize_edit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row5_sizer->Add( m_filter_filesize_sizer, 0, wxEXPAND, 5 );
+
+ //button here
+ m_filter_filesize_button= new wxButton( this, PLAYBACK_FILTER_FILESIZE_BUTTON, f_values.filesize_mode, wxDefaultPosition, wxSize( 25, 25 ), 0 );
+ m_filter_body_row5_sizer->Add( m_filter_filesize_button, 0, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+/////
+
+///// duration
+ wxBoxSizer* m_filter_body_row6_sizer;
+ m_filter_body_row6_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ wxBoxSizer* m_filter_duration_sizer;
+ m_filter_duration_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_duration_text = new wxStaticText( this, wxID_ANY, _("Duration (hh:mm:ss):"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_filter_duration_text->Wrap( -1 );
+ m_filter_duration_text->SetMinSize( wxSize( 90,-1 ) );
+
+ m_filter_duration_sizer->Add( m_filter_duration_text, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_duration_edit = new wxTextCtrl( this, PLAYBACK_FILTER_DURATION_EDIT, f_values.duration, wxDefaultPosition, wxSize( -1,-1 ), 0|wxSIMPLE_BORDER );
+ m_filter_duration_edit->SetMinSize( wxSize( 140,-1 ) );
+
+ m_filter_duration_sizer->Add( m_filter_duration_edit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_filter_body_row6_sizer->Add( m_filter_duration_sizer, 0, wxEXPAND, 5 );
+
+ m_filter_duration_button = new wxButton( this, PLAYBACK_FILTER_DURATION_BUTTON, f_values.duration_mode, wxDefaultPosition, wxSize( 25, 25 ), 0 );
+ m_filter_body_row6_sizer->Add( m_filter_duration_button, 0, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+/////
+
+ //bring all sizers together
+
+ wxBoxSizer* m_col1_sizer = new wxBoxSizer( wxVERTICAL );
+ wxBoxSizer* m_col2_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_col1_sizer->Add( m_filter_body_row2_sizer, 1, wxEXPAND, 5 );
+ m_col1_sizer->Add( m_filter_body_row3_sizer, 1, wxEXPAND, 5 );
+ m_col1_sizer->Add( m_filter_body_row4_sizer, 1, wxEXPAND, 5 );
+ m_col2_sizer->Add( m_filter_body_row5_sizer, 1, wxEXPAND, 5 );
+ m_col2_sizer->Add( m_filter_body_row6_sizer, 1, wxEXPAND, 5 );
+
+
+
+ m_filter_sizer->Add( m_col1_sizer, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_filter_sizer->Add( m_col2_sizer, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ m_activ = false;
+ m_filter_player_mode = _GetButtonMode(f_values.player_mode);
+ m_filter_duration_mode = _GetButtonMode(f_values.duration_mode);
+ m_filter_filesize_mode = _GetButtonMode(f_values.filesize_mode);
+ m_filter_player_choice_value = m_filter_player_choice->GetSelection()-1;
+
+ m_filter_body_sizer->Add( m_filter_sizer );
+ this->SetSizer( m_filter_body_sizer );
+ this->Layout();
+ m_filter_sizer->Fit( this );
+
+ if (m_filter_map_expression != NULL) { delete m_filter_map_expression; }
+ m_filter_map_expression = new wxRegEx(m_filter_map_edit->GetValue(),wxRE_ICASE);
+ if (m_filter_mod_expression != NULL) { delete m_filter_mod_expression; }
+ m_filter_mod_expression = new wxRegEx(m_filter_mod_edit->GetValue(),wxRE_ICASE);
+
+ wxCommandEvent dummy;
+ OnChange(dummy);
+
+}
+
+template <class PlaybackTabType>
+typename PlaybackListFilter<PlaybackTabType>::m_button_mode PlaybackListFilter<PlaybackTabType>::_GetButtonMode(wxString sign)
+{
+ if ( sign == _T("<") )
+ return m_smaller;
+ if ( sign == _T(">") )
+ return m_bigger;
+ return m_equal;
+}
+
+template <class PlaybackTabType>
+wxString PlaybackListFilter<PlaybackTabType>::_GetButtonSign(m_button_mode value)
+{
+ switch (value) {
+ case m_equal : return _T("=");
+ case m_smaller : return _T("<");
+ case m_bigger :
+ default : return _T(">");
+ }
+}
+
+template <class PlaybackTabType>
+typename PlaybackListFilter<PlaybackTabType>::m_button_mode PlaybackListFilter<PlaybackTabType>::_GetNextMode(m_button_mode value)
+{
+ switch (value) {
+ case m_equal : return m_smaller;
+ case m_smaller : return m_bigger;
+ case m_bigger :
+ default : return m_equal;
+ }
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnPlayerButton ( wxCommandEvent& event )
+{
+ m_filter_player_mode = _GetNextMode(m_filter_player_mode);
+ m_filter_player_button->SetLabel( _GetButtonSign( m_filter_player_mode ) );
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::SetActiv( bool state )
+{
+ m_activ = state;
+ if (m_parent_tab != 0) {
+ m_parent_tab->UpdateList();
+ }
+}
+template <class PlaybackTabType>
+bool PlaybackListFilter<PlaybackTabType>::_IntCompare(int a,int b,m_button_mode mode)
+{
+ switch (mode) {
+ case m_equal : return (a == b);
+ case m_smaller : return (a < b);
+ case m_bigger : return (a > b);
+ default : return false;
+ }
+}
+
+template <class PlaybackTabType>
+bool PlaybackListFilter<PlaybackTabType>::FilterPlayback( const typename PlaybackListFilter<PlaybackTabType>::PlaybackType& playback )
+{
+
+ if (!m_activ) return true;
+
+ const OfflineBattle& battle = playback.battle;
+ //Player Check
+ if ( (m_filter_player_choice_value != -1) && !_IntCompare( battle.GetNumUsers() - battle.GetSpectators() , m_filter_player_choice_value , m_filter_player_mode ) ) return false;
+
+ //Only Maps i have Check
+ if (m_filter_map_show->GetValue() && !battle.MapExists()) return false;
+
+ //Only Mods i have Check
+ if (m_filter_mod_show->GetValue() && !battle.ModExists()) return false;
+
+ //Strings Plain Text & RegEx Check (Case insensitiv)
+
+ //Map:
+ if ( !RefineMapname(battle.GetHostMapName() ).Upper().Contains( m_filter_map_edit->GetValue().Upper() ) && !m_filter_map_expression->Matches(RefineMapname(battle.GetHostMapName() )) ) return false;
+
+ //Mod:
+ if ( !battle.GetHostModName().Upper().Contains( m_filter_mod_edit->GetValue().Upper() ) && !RefineModname( battle.GetHostModName() ).Upper().Contains( m_filter_mod_edit->GetValue().Upper() ) && !m_filter_mod_expression->Matches(RefineModname(battle.GetHostModName())) ) return false;
+
+ if ( (!m_filter_filesize_edit->GetValue().IsEmpty() ) && !_IntCompare( playback.size , 1024 * s2l( m_filter_filesize_edit->GetValue()) , m_filter_filesize_mode) ) return false;
+
+ //duration
+ if ( (!m_filter_duration_edit->GetValue().IsEmpty() ) && !_IntCompare( playback.duration , m_duration_value , m_filter_duration_mode) ) return false;
+
+ return true;
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnChange ( wxCommandEvent& /*unused*/ )
+{
+ if (!m_activ) return;
+ m_parent_tab->UpdateList();
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnChangeMap ( wxCommandEvent& event )
+{
+ if ( m_filter_map_edit == NULL ) return;
+ if (m_filter_map_expression != NULL) { delete m_filter_map_expression; }
+ m_filter_map_expression = new wxRegEx(m_filter_map_edit->GetValue(),wxRE_ICASE);
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnChangeMod ( wxCommandEvent& event )
+{
+ if ( m_filter_mod_edit == NULL ) return;
+ if (m_filter_mod_expression != NULL) { delete m_filter_mod_expression; }
+ m_filter_mod_expression = new wxRegEx(m_filter_mod_edit->GetValue(),wxRE_ICASE);
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnPlayerChange( wxCommandEvent& event )
+{
+ m_filter_player_choice_value = m_filter_player_choice->GetSelection()-1;
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnChangeDuration(wxCommandEvent& event)
+{
+ SetDurationValue();
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnChangeFilesize(wxCommandEvent& event)
+{
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnDurationButton(wxCommandEvent& event)
+{
+ m_filter_duration_mode = _GetNextMode(m_filter_duration_mode);
+ m_filter_duration_button->SetLabel( _GetButtonSign( m_filter_duration_mode ) );
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::OnFilesizeButton(wxCommandEvent& event)
+{
+ m_filter_filesize_mode = _GetNextMode(m_filter_filesize_mode);
+ m_filter_filesize_button->SetLabel( _GetButtonSign( m_filter_filesize_mode ) );
+ OnChange(event);
+}
+
+template <class PlaybackTabType>
+bool PlaybackListFilter<PlaybackTabType>::GetActiv() const
+{
+ return m_activ;
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::SaveFilterValues()
+{
+ PlaybackListFilterValues filtervalues;
+ filtervalues.duration = m_filter_duration_edit->GetValue() ;
+ filtervalues.map = m_filter_map_edit->GetValue();
+ filtervalues.map_show = m_filter_map_show->GetValue();
+ filtervalues.map = m_filter_map_edit->GetValue();
+ filtervalues.mod = m_filter_mod_edit->GetValue();
+ filtervalues.mod_show = m_filter_mod_show->GetValue();
+ filtervalues.player_mode = _GetButtonSign(m_filter_player_mode);
+ filtervalues.player_num = wxString::Format(_("%d"),m_filter_player_choice->GetSelection());
+ filtervalues.duration_mode = _GetButtonSign(m_filter_duration_mode);
+ filtervalues.filesize = m_filter_filesize_edit->GetValue();
+ filtervalues.filesize_mode= _GetButtonSign(m_filter_filesize_mode);
+ sett().SetReplayFilterValues(filtervalues);
+}
+
+template <class PlaybackTabType>
+void PlaybackListFilter<PlaybackTabType>::SetDurationValue()
+{
+
+ wxString dur = m_filter_duration_edit->GetValue();
+ const wxChar* sep = _T(":");
+ int sep_count = dur.Replace(sep,sep); //i know, i know
+ switch ( sep_count ) {
+ default:
+ break;
+
+ case 0: m_duration_value = s2l( dur );
+ break;
+ case 1: m_duration_value = s2l( dur.AfterFirst(*sep) ) + ( s2l( dur.BeforeFirst(*sep) ) * 60 );
+ break;
+ case 2: m_duration_value = s2l( dur.AfterLast(*sep) ) + ( s2l( dur.AfterFirst(*sep).BeforeFirst(*sep) ) * 60 )
+ + ( s2l( dur.BeforeFirst(*sep) ) * 3600 );
+ break;
+
+ }
+}
diff --git a/src/playback/playbackfilter.h b/src/playback/playbackfilter.h
new file mode 100644
index 0000000..5ed1951
--- /dev/null
+++ b/src/playback/playbackfilter.h
@@ -0,0 +1,144 @@
+#ifndef SPRINGLOBBY_PLAYBACKFILTER_H_INCLUDED
+#define SPRINGLOBBY_PLAYBACKFILTER_H_INCLUDED
+
+#include <wx/panel.h>
+
+///////////////////////////////////////////////////////////////////////////
+
+class ReplayTab;
+class wxToggleButton;
+class wxCheckBox;
+class wxStaticText;
+class wxTextCtrl;
+class wxChoice;
+class wxButton;
+class wxRegEx;
+class wxStaticText;
+
+
+/** \brief The panel contained in BattleListTab used to filter for diff info of battles
+ * \todo DOCMEMORE */
+template <class PlaybackTabType>
+class PlaybackListFilter : public wxPanel
+{
+ protected:
+ typedef typename PlaybackTabType::PlaybackType
+ PlaybackType;
+
+ public:
+ PlaybackListFilter ( wxWindow* parent, wxWindowID id, PlaybackTabType* parentTab, const wxPoint& pos, const wxSize& size, long style );
+
+ void OnPlayerButton ( wxCommandEvent& event );
+ void OnFilesizeButton ( wxCommandEvent& event );
+ void OnDurationButton ( wxCommandEvent& event );
+
+ void OnActivate ( wxCommandEvent& event );
+
+ void SetActiv ( bool state );
+
+ void OnChange ( wxCommandEvent& event );
+ void OnChangeMap ( wxCommandEvent& event );
+ void OnChangeMod ( wxCommandEvent& event );
+ void OnChangeFilesize ( wxCommandEvent& event );
+ void OnChangeDuration ( wxCommandEvent& event );
+
+ void OnPlayerChange ( wxCommandEvent& event );
+
+ bool FilterPlayback( const PlaybackType& playback );
+ bool GetActiv() const;
+
+ void SetFilterHighlighted( bool state );
+
+ void SaveFilterValues();
+
+ protected:
+ enum m_button_mode {m_equal,m_bigger,m_smaller};
+
+ wxString _GetButtonSign(m_button_mode value);
+ m_button_mode _GetNextMode(m_button_mode value);
+ m_button_mode _GetButtonMode(wxString sign);
+ bool _IntCompare(int a,int b,m_button_mode mode);
+
+ bool m_activ;
+
+ PlaybackTabType* m_parent_tab;
+#if wxUSE_TOGGLEBTN
+ wxToggleButton* m_filter_show;
+#else
+ wxCheckBox* m_filter_show;
+#endif
+ wxStaticText* m_filter_text;
+
+ wxCheckBox* m_filter_activ;
+
+ //Player
+ wxStaticText* m_filter_player_text;
+ wxButton* m_filter_player_button;
+ m_button_mode m_filter_player_mode;
+ wxChoice* m_filter_player_choice;
+ int m_filter_player_choice_value;
+
+ //Filesize
+ wxStaticText* m_filter_filesize_text;
+ wxButton* m_filter_filesize_button;
+ m_button_mode m_filter_filesize_mode;
+ wxTextCtrl* m_filter_filesize_edit;
+
+ //Duration
+ wxStaticText* m_filter_duration_text;
+ wxButton* m_filter_duration_button;
+ m_button_mode m_filter_duration_mode;
+ wxTextCtrl* m_filter_duration_edit;
+ long m_duration_value;
+ void SetDurationValue();
+
+ //Map
+ wxStaticText* m_filter_map_text;
+ wxTextCtrl* m_filter_map_edit;
+ wxCheckBox* m_filter_map_show;
+ wxRegEx* m_filter_map_expression;
+
+ //Mod
+ wxStaticText* m_filter_mod_text;
+ wxTextCtrl* m_filter_mod_edit;
+ wxCheckBox* m_filter_mod_show;
+ wxRegEx* m_filter_mod_expression;
+
+
+ DECLARE_EVENT_TABLE();
+};
+
+enum
+{
+ PLAYBACK_FILTER_MAP_EDIT,
+ PLAYBACK_FILTER_MOD_EDIT,
+ PLAYBACK_FILTER_FILESIZE_EDIT,
+ PLAYBACK_FILTER_DURATION_EDIT,
+ PLAYBACK_FILTER_PLAYER_CHOICE,
+ PLAYBACK_FILTER_MAP_SHOW,
+ PLAYBACK_FILTER_MOD_SHOW,
+ PLAYBACK_FILTER_PLAYER_BUTTON,
+ PLAYBACK_FILTER_DURATION_BUTTON,
+ PLAYBACK_FILTER_FILESIZE_BUTTON
+};
+
+#include "playbackfilter.cpp"
+#endif // SPRINGLOBBY_PLAYBACKFILTER_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/playback/playbackfiltervalues.h b/src/playback/playbackfiltervalues.h
new file mode 100644
index 0000000..8acb2b1
--- /dev/null
+++ b/src/playback/playbackfiltervalues.h
@@ -0,0 +1,43 @@
+#ifndef PlaybackListFilterValues_H_INCLUDED
+#define PlaybackListFilterValues_H_INCLUDED
+
+struct PlaybackListFilterValues
+{
+ // checkboxes
+ bool map_show;
+ bool mod_show;
+
+ //text fields
+ wxString map;
+ wxString mod;
+ wxString filesize;
+ wxString duration;
+ //choices
+ wxString player_num;
+
+
+ //modifiers
+ wxString player_mode;
+ wxString filesize_mode;
+ wxString duration_mode;
+};
+
+#endif // PlaybackListFilterValues_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/playback/playbacklist.cpp b/src/playback/playbacklist.cpp
new file mode 100644
index 0000000..4c63570
--- /dev/null
+++ b/src/playback/playbacklist.cpp
@@ -0,0 +1,78 @@
+
+#include "../tdfcontainer.h"
+#include "../offlinebattle.h"
+#include "../globalsmanager.h"
+
+template <class ListImp>
+ListImp& playbacklist()
+{
+ static GlobalObjectHolder<ListImp> m_replay_list;
+ return m_replay_list;
+}
+
+template <class PlaybackImp>
+typename PlaybackList<PlaybackImp>::PlaybackType&
+ PlaybackList<PlaybackImp>::AddPlayback( const PlaybackType& replay )
+{
+ m_replays[replay.id] = replay;
+ return m_replays[replay.id];
+}
+
+template <class PlaybackImp>
+void PlaybackList<PlaybackImp>::RemovePlayback( playback_id_t const& id )
+{
+ m_replays.erase(id);
+}
+
+template <class PlaybackImp>
+typename PlaybackList<PlaybackImp>::playback_map_t::size_type PlaybackList<PlaybackImp>::GetNumPlaybacks()
+{
+ return m_replays.size();
+}
+
+template <class PlaybackImp>
+typename PlaybackList<PlaybackImp>::PlaybackType&
+ PlaybackList<PlaybackImp>::GetPlaybackById( playback_id_t const& id )
+{
+//TODO catch
+ playback_iter_t b = m_replays.find(id);
+ if (b == m_replays.end())
+ throw std::runtime_error("PlaybackList_Iter::GetPlayback(): no such replay");
+
+ return b->second;
+}
+
+template <class PlaybackImp>
+bool PlaybackList<PlaybackImp>::PlaybackExists( playback_id_t const& id )
+{
+ return m_replays.find(id) != m_replays.end();
+}
+
+template <class PlaybackImp>
+bool PlaybackList<PlaybackImp>::DeletePlayback( playback_id_t const& id )
+{
+ PlaybackType rep = m_replays[id];
+ if ( wxRemoveFile( rep.Filename ) ) {
+
+ //m_filenames.resize(std::remove(m_filenames.begin(), m_filenames.end(), rep.Filename)-m_filenames.begin());
+
+ m_replays.erase(id);
+ return true;
+ }
+ return false;
+}
+
+template <class PlaybackImp>
+void PlaybackList<PlaybackImp>::RemoveAll()
+{
+// m_filenames.clear();
+ m_replays.clear();
+ m_fails = 0;
+}
+
+template <class PlaybackImp>
+const typename PlaybackList<PlaybackImp>::playback_map_t& PlaybackList<PlaybackImp>::GetPlaybacksMap() const {
+ return m_replays;
+}
+
+
diff --git a/src/playback/playbacklist.h b/src/playback/playbacklist.h
new file mode 100644
index 0000000..5bccff2
--- /dev/null
+++ b/src/playback/playbacklist.h
@@ -0,0 +1,60 @@
+#ifndef SL_PLAYBACKLIST_H_INCLUDED
+#define SL_PLAYBACKLIST_H_INCLUDED
+
+#include <map>
+#include <wx/event.h>
+
+class wxArrayString;
+
+template <class PlaybackImp>
+class PlaybackList : public wxEvtHandler
+{
+ public:
+ typedef PlaybackImp
+ PlaybackType;
+
+ typedef unsigned int playback_id_t;
+
+ //! @brief mapping from playback id number to playback object
+ typedef std::map<playback_id_t, PlaybackType> playback_map_t;
+ //! @brief iterator for playback map
+ typedef typename playback_map_t::iterator playback_iter_t;
+ //! @brief const iterator for playback map
+ typedef typename playback_map_t::const_iterator playback_const_iter_t;
+
+ virtual void LoadPlaybacks( const wxArrayString& filenames ) = 0;
+ //!loads replays between two indices
+// virtual void LoadPlaybacks( const unsigned int from, const unsigned int to) = 0;
+
+ PlaybackType& AddPlayback( const PlaybackType& replay );
+ void AddPlayback( PlaybackType* replay );
+ void RemovePlayback( playback_id_t const& id );
+
+ PlaybackType &GetPlaybackById( playback_id_t const& id );
+
+ ///Playback& GetPlayback( int const index ) ;
+
+ bool PlaybackExists( playback_id_t const& id );
+ bool DeletePlayback( playback_id_t const& id );
+ typename playback_map_t::size_type GetNumPlaybacks();
+
+ void RemoveAll();
+
+ const playback_map_t& GetPlaybacksMap() const;
+
+
+ protected:
+ PlaybackList() {};
+
+ playback_map_t m_replays;
+
+ unsigned long m_fails;
+
+};
+
+template <class ListImp>
+ListImp& playbacklist();
+
+#include "playbacklist.cpp"
+
+#endif // SL_PLAYBACKLIST_H_INCLUDED
diff --git a/src/playback/playbacklistctrl.cpp b/src/playback/playbacklistctrl.cpp
new file mode 100644
index 0000000..471ebda
--- /dev/null
+++ b/src/playback/playbacklistctrl.cpp
@@ -0,0 +1,305 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include <wx/intl.h>
+#include <wx/menu.h>
+#include <wx/filename.h>
+#include <wx/log.h>
+
+#include "playbackstructs.h"
+//#include "../utils.h"
+#include "../user.h"
+#include "../iconimagelist.h"
+#include "../uiutils.h"
+#include "../ui.h"
+
+
+BEGIN_EVENT_TABLE_TEMPLATE1(PlaybackListCtrl, PlaybackListCtrl::BaseType, PlaybackType )
+
+ EVT_LIST_ITEM_RIGHT_CLICK( RLIST_LIST, PlaybackListCtrl::OnListRightClick )
+ EVT_MENU ( RLIST_DLMAP, PlaybackListCtrl::OnDLMap )
+ EVT_MENU ( RLIST_DLMOD, PlaybackListCtrl::OnDLMod )
+ EVT_LIST_COL_CLICK ( RLIST_LIST, ParentType::OnColClick )
+
+END_EVENT_TABLE()
+
+template<class T,class L> SortOrder CustomVirtListCtrl<T,L>::m_sortorder = SortOrder();
+
+template <class PlaybackType>
+PlaybackListCtrl<PlaybackType>::PlaybackListCtrl( wxWindow* parent ):
+ PlaybackListCtrl::BaseType(parent, RLIST_LIST, wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_ALIGN_LEFT,
+ _T("PlaybackListCtrl"), 8, 4, &CompareOneCrit )
+{
+#ifdef __WXMSW__
+ const int hd = wxLIST_AUTOSIZE_USEHEADER;
+ const int widths[8] = {80,140,141,hd,160,hd,70,180};
+#else
+ const int widths[8] = {80,140,141,50,160,50,70,180};
+
+#endif
+
+ AddColumn( 0, widths[0], _("Date"), _("Date of recording") );
+ AddColumn( 1, widths[1], _("Mod"), _("Modname") );
+ AddColumn( 2, widths[2], _("Map"), _("Mapname") );
+ AddColumn( 3, widths[3], _("Players"), _("Number of players") );
+ AddColumn( 4, widths[4], _("Duration"), _T("Duration") );
+ AddColumn( 5, widths[5], _("Spring Version"), _("Spring Version") );
+ AddColumn( 6, widths[6], _("Filesize"), _("Filesize in kilobyte") );
+ AddColumn( 7, widths[7], _("File"), _T("Filename") );
+
+ if ( m_sortorder.size() == 0 ) {
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = true;
+ m_sortorder[1].col = 1;
+ m_sortorder[1].direction = true;
+ m_sortorder[2].col = 2;
+ m_sortorder[2].direction = true;
+ m_sortorder[3].col = 3;
+ m_sortorder[3].direction = true;
+ Sort( );
+ }
+
+
+ m_popup = new wxMenu( _T("") );
+ // &m enables shortcout "alt + m" and underlines m
+ m_popup->Append( RLIST_DLMAP, _("Download &map") );
+ m_popup->Append( RLIST_DLMOD, _("Download m&od") );
+}
+
+template <class PlaybackType>
+PlaybackListCtrl<PlaybackType>::~PlaybackListCtrl()
+{
+ delete m_popup;
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::OnListRightClick( wxListEvent& /*unused*/ )
+{
+ PopupMenu( m_popup );
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::AddPlayback( const PlaybackType& replay )
+{
+ if ( AddItem( &replay ) )
+ return;
+
+ wxLogWarning( _T("Replay already in list.") );
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::RemovePlayback( const PlaybackType& replay )
+{
+ if ( RemoveItem( &replay) )
+ return;
+
+ wxLogError( _T("Didn't find the replay to remove.") );
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::OnDLMap( wxCommandEvent& /*unused*/ )
+{
+ if ( m_selected_index > 0 && (long)m_data.size() > m_selected_index ) {
+ OfflineBattle battle = m_data[m_selected_index]->battle;
+ ui().DownloadMap( battle.GetHostMapHash(), battle.GetHostMapName() );
+ }
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::OnDLMod( wxCommandEvent& /*unused*/ )
+{
+ if ( m_selected_index > 0 && (long)m_data.size() > m_selected_index ) {
+ OfflineBattle battle = m_data[m_selected_index]->battle;
+ ui().DownloadMod( battle.GetHostModHash(), battle.GetHostModName() );
+ }
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::Sort()
+{
+ if ( m_data.size() > 0 ) {
+ SaveSelection();
+ SLInsertionSort( m_data, m_comparator );
+ RestoreSelection();
+ }
+}
+
+template <class PlaybackType>
+int PlaybackListCtrl<PlaybackType>::CompareOneCrit( DataType u1, DataType u2, int col, int dir )
+{
+ switch ( col ) {
+ case 0: return dir * compareSimple( u1->date, u2->date );
+ case 1: return dir * u1->battle.GetHostModName().CmpNoCase( u2->battle.GetHostModName() );
+ case 2: return dir * u1->battle.GetHostMapName().CmpNoCase( u2->battle.GetHostMapName() );
+ case 3: return dir * compareSimple( u1->battle.GetNumUsers() - u1->battle.GetSpectators(), u2->battle.GetNumUsers() - u2->battle.GetSpectators() );
+ case 4: return dir * compareSimple( u1->duration,u2->duration );
+ case 5: return dir * u1->SpringVersion.CmpNoCase( u2->SpringVersion ) ;
+ case 6: return dir * compareSimple( u1->size, u2->size ) ;
+ case 7: return dir * u1->Filename.AfterLast( wxFileName::GetPathSeparator() ).CmpNoCase( u2->Filename.AfterLast( wxFileName::GetPathSeparator() ) );
+ default: return 0;
+ }
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::SetTipWindowText( const long item_hit, const wxPoint position)
+{
+ if ( item_hit < 0 || item_hit >= (long)m_data.size() )
+ return;
+
+ const PlaybackType& replay = *GetDataFromIndex( item_hit );
+
+ int column = getColumnFromPosition( position );
+ if (column > (int)m_colinfovec.size() || column < 0)
+ {
+ m_tiptext = _T("");
+ }
+ else
+ {
+ switch (column) {
+ case 0: // date
+ m_tiptext = replay.date;
+ break;
+ case 1: // modname
+ m_tiptext = replay.ModName;
+ break;
+ case 2: // mapname
+ m_tiptext = replay.MapName;
+ break;
+ case 3: //playernum
+ m_tiptext = RefineModname(replay.ModName);
+ break;
+ case 4: // spring version
+ m_tiptext = replay.SpringVersion;
+ break;
+ case 5: // filenam
+ m_tiptext = replay.Filename;
+ break;
+
+ default: m_tiptext = _T("");
+ break;
+ }
+ }
+}
+
+template <class PlaybackType>
+wxString PlaybackListCtrl<PlaybackType>::GetItemText(long item, long column) const
+{
+ if ( m_data[item] == NULL )
+ return wxEmptyString;
+
+ const PlaybackType& replay = *m_data[item];
+ wxString duration = wxString::Format(_T("%02ld:%02ld:%02ld"), replay.duration / 3600,
+ (replay.duration%3600)/60, (replay.duration%60)/60 ) ;
+
+ switch ( column ) {
+ case 0: return replay.date;
+ case 1: return replay.battle.GetHostModName();
+ case 2: return replay.battle.GetHostMapName();
+ case 3: return wxString::Format(_T("%d"),replay.battle.GetNumUsers() - replay.battle.GetSpectators() );
+ case 4: return duration;
+ case 5: return replay.SpringVersion;
+ case 6: return wxString::Format( _T("%d KB"),replay.size/1024 );
+ case 7: return replay.Filename.AfterLast( wxFileName::GetPathSeparator() );
+
+ default: return wxEmptyString;
+ }
+}
+
+template <class PlaybackType>
+int PlaybackListCtrl<PlaybackType>::GetItemImage(long item) const
+{
+ if ( m_data[item] == NULL )
+ return -1;
+
+ return -1;//icons().GetBattleStatusIcon( *m_data[item] );
+}
+
+template <class PlaybackType>
+int PlaybackListCtrl<PlaybackType>::GetItemColumnImage(long item, long column) const
+{
+ //nothing's been done here atm
+ return -1;
+
+// if ( m_data[item] == NULL )
+// return -1;
+//
+// const PlaybackType& replay = *m_data[item];
+//
+// switch ( column ) {
+// default: return -1;
+// }
+}
+
+template <class PlaybackType>
+wxListItemAttr* PlaybackListCtrl<PlaybackType>::GetItemAttr(long /*unused*/) const
+{
+ //not neded atm
+// if ( item < m_data.size() && item > -1 ) {
+// const Replay& replay = *m_data[item];
+// }
+ return NULL;
+}
+
+template <class PlaybackType>
+void PlaybackListCtrl<PlaybackType>::RemovePlayback( const int index )
+{
+ if ( index != -1 && index < m_data.size() ) {
+ m_data.erase( m_data.begin() + index );
+ SetItemCount( m_data.size() );
+ RefreshVisibleItems( );
+ return;
+ }
+ wxLogError( _T("Didn't find the replay to remove.") );
+}
+
+template <class PlaybackType>
+int PlaybackListCtrl<PlaybackType>::GetIndexFromData( const DataType& data ) const
+{
+ DataCIter it = m_data.begin();
+ for ( int i = 0; it != m_data.end(); ++it, ++i ) {
+ if ( *it != 0 && data->Equals( *(*it) ) )
+ return i;
+ }
+ wxLogError( _T("didn't find the battle.") );
+ return -1;
+}
+
+/////!TODO get rid of this in favor of the functionality in base class
+//template <class PlaybackType>
+//void PlaybackListCtrl::OnColClick( wxListEvent& event )
+//{
+// int click_col=event.GetColumn();
+// wxLogMessage(_T("click col: %d"),click_col);
+// if ( click_col == -1 ) return;
+// wxListItem col;
+// GetColumn( m_sortorder[0].col, col );
+// col.SetImage( icons().ICON_NONE );
+// SetColumn( m_sortorder[0].col, col );
+//
+// if(click_col==m_sortorder[0].col){
+// m_sortorder[0].direction *= -1;
+// }
+// else{
+// int order_remove=3;
+// for(int i=0;i<4;++i){
+// if(m_sortorder[i].col==click_col){
+// order_remove=i;
+// }
+// }
+// for(int i=order_remove;i>0;--i){
+// m_sortorder[i]=m_sortorder[i-1];
+// }
+// m_sortorder[0].col=click_col;
+// m_sortorder[0].direction=true;
+// }
+//
+// for(int i=0;i<4;++i){
+// wxLogMessage(_T("sorting level%d by %d direction %d"),i,m_sortorder[i].col,m_sortorder[i].direction);
+// }
+//
+// GetColumn( m_sortorder[0].col, col );
+// col.SetImage( ( m_sortorder[0].direction > 0 )?icons().ICON_UP:icons().ICON_DOWN );
+// SetColumn( m_sortorder[0].col, col );
+//
+// SortList( true );
+//}
diff --git a/src/playback/playbacklistctrl.h b/src/playback/playbacklistctrl.h
new file mode 100644
index 0000000..6612049
--- /dev/null
+++ b/src/playback/playbacklistctrl.h
@@ -0,0 +1,105 @@
+#ifndef SPRINGLOBBY_PlaybackListCtrl_H_INCLUDED
+#define SPRINGLOBBY_PlaybackListCtrl_H_INCLUDED
+
+#include "../customvirtlistctrl.h"
+
+class wxMenu;
+class wxListEvent;
+class wxCommandEvent;
+
+template <class PlaybackImp>
+class PlaybackListCtrl : public CustomVirtListCtrl< const PlaybackImp*, PlaybackListCtrl<PlaybackImp> >
+{
+ protected:
+ typedef PlaybackListCtrl<PlaybackImp>
+ ThisType;
+ typedef CustomVirtListCtrl< const PlaybackImp*,PlaybackListCtrl<PlaybackImp> >
+ ParentType;
+ typedef typename ParentType::DataType
+ DataType;
+ typedef PlaybackImp
+ PlaybackType;
+
+ using ParentType::AddColumn;
+ using ParentType::m_sortorder;
+ using ParentType::PopupMenu;
+ using ParentType::m_data;
+ using ParentType::m_selected_data;
+ using ParentType::m_selected_index;
+ using ParentType::SaveSelection;
+ using ParentType::RestoreSelection;
+ using ParentType::HitTest;
+ using ParentType::m_comparator;
+ using ParentType::m_tiptimer;
+ using ParentType::m_tiptext;
+ using ParentType::m_colinfovec;
+ using ParentType::m_tooltip_delay;
+ using ParentType::m_tooltip_duration;
+ using ParentType::DataVector;
+ typedef typename ParentType::DataVector::const_iterator
+ DataCIter; //! TODO (koshi) i'd be mighty thankful if some could explain to me why the import with using ParentType::DataCIter doesn't work here;
+ using ParentType::getColumnFromPosition;
+
+ public:
+ PlaybackListCtrl( wxWindow* parent );
+ ~PlaybackListCtrl();
+
+ void AddPlayback( const PlaybackType& replay );
+ void RemovePlayback( const PlaybackType& replay );
+ void RemovePlayback( const int index );
+ void OnListRightClick( wxListEvent& event );
+ void OnDLMap( wxCommandEvent& event );
+ void OnDLMod( wxCommandEvent& event );
+ void OnColClick( wxListEvent& event );
+
+ virtual void SetTipWindowText( const long item_hit, const wxPoint position);
+
+ virtual void HighlightItem( long /*unused*/ ){};
+
+ //these are overloaded to use list in virtual style
+ wxString GetItemText(long item, long column) const;
+ int GetItemImage(long item) const;
+ int GetItemColumnImage(long item, long column) const;
+ wxListItemAttr * GetItemAttr(long item) const;
+ int GetIndexFromData( const DataType& data ) const;
+
+ using ParentType::RefreshVisibleItems;
+ using ParentType::GetDataFromIndex;
+
+ protected:
+ static int CompareOneCrit( DataType u1, DataType u2, int col, int dir ) ;
+
+ virtual void Sort();
+
+ wxMenu* m_popup;
+
+ DECLARE_EVENT_TABLE()
+};
+
+enum
+{
+ RLIST_LIST,
+ RLIST_DLMOD,
+ RLIST_DLMAP
+};
+
+#include "playbacklistctrl.cpp"
+#endif // SPRINGLOBBY_PlaybackListCtrl_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/playback/playbackstructs.h b/src/playback/playbackstructs.h
new file mode 100644
index 0000000..689f8df
--- /dev/null
+++ b/src/playback/playbackstructs.h
@@ -0,0 +1,44 @@
+#ifndef PLAYBACKSTRUCTS_H_INCLUDED
+#define PLAYBACKSTRUCTS_H_INCLUDED
+
+#include "../offlinebattle.h"
+
+struct Replay
+{
+ int id;
+ int playernum;
+ bool can_watch;
+ int duration; //in seconds
+ int size; //in bytes
+ wxString MapName;
+ wxString ModName;
+ wxString SpringVersion;
+ wxString Filename;
+ wxString date;
+ OfflineBattle battle;
+ Replay():id(0),playernum(0),can_watch(false),duration(0),size(0){};
+
+ bool Equals( const Replay& other ) const { return Filename == other.Filename; }
+};
+
+struct Savegame
+{
+ int id;
+ int playernum;
+ bool can_watch;
+ int duration; //in seconds
+ int size; //in bytes
+ wxString MapName;
+ wxString ModName;
+ wxString SpringVersion;
+ wxString Filename;
+ wxString date;
+ OfflineBattle battle;
+ Savegame():id(0),playernum(0),can_watch(false),duration(0),size(0){};
+
+ bool Equals( const Savegame& other ) const { return Filename == other.Filename; }
+};
+
+
+
+#endif // PLAYBACKSTRUCTS_H_INCLUDED
diff --git a/src/playback/playbacktab.cpp b/src/playback/playbacktab.cpp
new file mode 100644
index 0000000..7260011
--- /dev/null
+++ b/src/playback/playbacktab.cpp
@@ -0,0 +1,488 @@
+#include <wx/intl.h>
+#include <wx/stattext.h>
+#include <wx/statline.h>
+#include <wx/textdlg.h>
+#include <wx/combobox.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/checkbox.h>
+#include <wx/filename.h>
+#include <wx/log.h>
+#if wxUSE_TOGGLEBTN
+ #include <wx/tglbtn.h>
+#endif
+
+#include "playbacklistctrl.h"
+#include "replaylist.h"
+#include "playbackthread.h"
+#include "../ui.h"
+#include "../chatpanel.h"
+#include "../utils/debug.h"
+#include "../uiutils.h"
+#include "../settings.h"
+#include "../iunitsync.h"
+#include "../mapctrl.h"
+#include "../battleroomlistctrl.h"
+
+#include "playbackfilter.h"
+#include "../iconimagelist.h"
+
+#include "../settings++/custom_dialogs.h"
+
+
+BEGIN_EVENT_TABLE_TEMPLATE1( PlaybackTab, wxPanel, PlaybackTraits )
+
+ EVT_BUTTON ( PLAYBACK_WATCH , PlaybackTab::OnWatch )
+ EVT_BUTTON ( PLAYBACK_RELOAD , PlaybackTab::OnReload )
+ EVT_BUTTON ( PLAYBACK_DELETE , PlaybackTab::OnDelete )
+ EVT_LIST_ITEM_SELECTED ( RLIST_LIST , PlaybackTab::OnSelect )
+ // this doesn't get triggered (?)
+ EVT_LIST_ITEM_DESELECTED( wxID_ANY , PlaybackTab::OnDeselect )
+ EVT_CHECKBOX ( PLAYBACK_LIST_FILTER_ACTIV , PlaybackTab::OnFilterActiv )
+ EVT_COMMAND ( wxID_ANY, PlaybacksLoadedEvt , PlaybackTab::AddAllPlaybacks )
+ #if wxUSE_TOGGLEBTN
+ EVT_TOGGLEBUTTON ( PLAYBACK_LIST_FILTER_BUTTON , PlaybackTab::OnFilter )
+ #else
+ EVT_CHECKBOX ( PLAYBACK_LIST_FILTER_BUTTON , PlaybackTab::OnFilter )
+ #endif
+
+END_EVENT_TABLE()
+
+template < class PlaybackTraits >
+PlaybackTab<PlaybackTraits>::PlaybackTab( wxWindow* parent, Ui& ui ) :
+ wxPanel( parent, -1 ),
+ m_replay_loader ( 0 ),
+ m_ui( ui )
+{
+ wxLogMessage( _T( "PlaybackTab::PlaybackTab()" ) );
+
+ m_replay_loader = new LoaderType( this );
+
+ wxBoxSizer* m_main_sizer;
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* m_filter_sizer;
+ m_filter_sizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* m_replaylist_sizer;
+ m_replaylist_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_replay_listctrl = new ListCtrlType( this );
+ m_replaylist_sizer->Add( m_replay_listctrl, 1, wxALL | wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_replaylist_sizer, 1, wxEXPAND, 5 );;
+
+ wxBoxSizer* m_info_sizer;
+ m_info_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_minimap = new MapCtrl( this, 100, 0, m_ui, true, true, false, false );
+ m_info_sizer->Add( m_minimap, 0, wxALL, 5 );
+
+ wxFlexGridSizer* m_data_sizer;
+ m_data_sizer = new wxFlexGridSizer( 4, 2, 0, 0 );
+
+ m_map_lbl = new wxStaticText( this, wxID_ANY, _( "Map:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_map_lbl, 1, wxALL | wxEXPAND, 5 );
+
+ m_map_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_map_text, 1, wxALL | wxEXPAND, 5 );
+
+ m_mod_lbl = new wxStaticText( this, wxID_ANY, _( "Mod:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_mod_lbl, 1, wxALL | wxEXPAND, 5 );
+
+ m_mod_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_mod_text, 1, wxALL | wxEXPAND, 5 );
+
+ m_players_lbl = new wxStaticText( this, wxID_ANY, _( "Players:" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_players_lbl, 1, wxALL | wxEXPAND, 5 );
+
+ m_players_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_data_sizer->Add( m_players_text, 1, wxALL | wxEXPAND, 5 );
+
+ m_info_sizer->Add( m_data_sizer, 1, wxEXPAND | wxALL, 0 );
+
+ m_players = new BattleroomListCtrl( this, 0, m_ui, true );
+ m_info_sizer->Add( m_players , 2, wxALL | wxEXPAND, 0 );
+
+ m_main_sizer->Add( m_info_sizer, 0, wxEXPAND, 5 );
+
+
+ m_filter = new PlaybackListFilter<ThisType>( this , wxID_ANY, this , wxDefaultPosition, wxSize( -1, -1 ), wxEXPAND );
+ m_filter_sizer->Add( m_filter, 0, wxEXPAND, 5 );
+
+ m_main_sizer->Add( m_filter_sizer, 0, wxEXPAND, 5 );
+
+ m_buttons_sep = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ m_main_sizer->Add( m_buttons_sep, 0, wxALL | wxEXPAND, 5 );
+
+ wxBoxSizer* m_buttons_sizer;
+ m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+#if wxUSE_TOGGLEBTN
+ m_filter_show = new wxToggleButton( this, PLAYBACK_LIST_FILTER_BUTTON , wxT( " Filter " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
+#else
+ m_filter_show = new wxCheckBox( this, PLAYBACK_LIST_FILTER_BUTTON , wxT( " Filter " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
+#endif
+
+ m_buttons_sizer->Add( m_filter_show, 0, 0, 5 );
+
+ m_filter_activ = new wxCheckBox( this, PLAYBACK_LIST_FILTER_ACTIV , wxT( "Activated" ), wxDefaultPosition, wxDefaultSize, 0 );
+ m_buttons_sizer->Add( m_filter_activ, 1, wxALL | wxEXPAND, 5 );
+
+ m_buttons_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+ m_watch_btn = new wxButton( this, PLAYBACK_WATCH, PlaybackTraits::IsReplayType ? _( "Watch" ) : _( "Load" ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
+ m_buttons_sizer->Add( m_watch_btn, 0, wxBOTTOM | wxLEFT | wxRIGHT, 5 );
+
+ m_delete_btn = new wxButton( this, PLAYBACK_DELETE, _( "Delete" ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
+ m_buttons_sizer->Add( m_delete_btn, 0, wxBOTTOM | wxRIGHT, 5 );
+
+ m_reload_btn = new wxButton( this, PLAYBACK_RELOAD, _( "Reload list" ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
+ m_buttons_sizer->Add( m_reload_btn, 0, wxBOTTOM | wxRIGHT, 5 );
+
+ m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND, 5 );
+
+ m_filter->Hide();
+
+ this->SetSizer( m_main_sizer );
+ this->Layout();
+
+ ReloadList();
+
+ //none selected --> shouldn't watch/delete that
+ Deselect();
+}
+
+template < class PlaybackTraits >
+PlaybackTab<PlaybackTraits>::~PlaybackTab()
+{
+ m_minimap->SetBattle( NULL );
+ if ( m_filter != 0 )
+ m_filter->SaveFilterValues();
+
+ wxLogDebugFunc( _T( "" ) );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::AddAllPlaybacks( wxCommandEvent& /*unused*/ )
+{
+ const typename ListType::playback_map_t& replays =
+ playbacklist<ListType>().GetPlaybacksMap();
+
+ for ( typename ListType::playback_const_iter_t i = replays.begin();i != replays.end();++i ) {
+ AddPlayback( i->second );
+ }
+ m_replay_listctrl->RefreshVisibleItems();
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::AddPlayback( const PlaybackType& replay ) {
+
+ if ( m_filter->GetActiv() && !m_filter->FilterPlayback( replay ) ) {
+ return;
+ }
+
+ m_replay_listctrl->AddPlayback( replay );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::RemovePlayback( const PlaybackType& replay )
+{
+ int index = m_replay_listctrl->GetIndexFromData( &replay );
+
+ if ( index == -1 )
+ return;
+
+ if ( index == m_replay_listctrl->GetSelectedIndex() )
+ Deselect();
+
+ m_replay_listctrl->RemovePlayback( replay );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::RemovePlayback( const int index )
+{
+ if ( index == -1 )
+ return;
+
+ if ( index == m_replay_listctrl->GetSelectedIndex() )
+ Deselect();
+
+ m_replay_listctrl->RemovePlayback( index );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::UpdatePlayback( const PlaybackType& replay )
+{
+ if ( m_filter->GetActiv() && !m_filter->FilterPlayback( replay ) ) {
+ RemovePlayback( replay );
+ return;
+ }
+
+ int index = m_replay_listctrl->GetIndexFromData( &replay );
+
+ if ( index != -1 )
+ m_replay_listctrl->RefreshItem( index );
+ else
+ AddPlayback( replay );
+
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::RemoveAllPlaybacks()
+{
+ m_replay_listctrl->Clear();
+ //shouldn't list be cleared too here? (koshi)
+}
+
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::UpdateList()
+{
+ const typename ListType::playback_map_t& replays =
+ playbacklist<ListType>().GetPlaybacksMap();
+
+ for ( typename ListType::playback_const_iter_t i = replays.begin(); i != replays.end(); ++i ) {
+ UpdatePlayback( i->second );
+ }
+ m_replay_listctrl->RefreshVisibleItems();
+}
+
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::SetFilterActiv( bool activ )
+{
+ m_filter->SetActiv( activ );
+ m_filter_activ->SetValue( activ );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::OnFilter( wxCommandEvent& /*unused*/ )
+{
+ if ( m_filter_show->GetValue() ) {
+ m_filter->Show( );
+ this->Layout();
+ }
+ else {
+ m_filter->Hide( );
+ this->Layout();
+ }
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::OnWatch( wxCommandEvent& /*unused*/ )
+{
+ if ( m_replay_listctrl->GetSelectedIndex() != -1 ) {
+ int m_sel_replay_id = m_replay_listctrl->GetSelectedData()->id;
+
+ wxString type = PlaybackTraits::IsReplayType ? _( "replay" ) : _( "savegame" ) ;
+ wxLogMessage( _T( "Watching %s %d " ), type.c_str(), m_sel_replay_id );
+ try {
+ PlaybackType& rep = playbacklist<ListType>().GetPlaybackById( m_sel_replay_id );
+
+ std::map<wxString, wxString> versionlist = sett().GetSpringVersionList();
+ if ( versionlist.size() == 0 ) {
+ wxLogWarning( _T( "can't get spring version from any unitsync" ) );
+ customMessageBox( SL_MAIN_ICON, _( "Couldn't get your spring versions from any unitsync library." ), _( "Spring error" ), wxICON_EXCLAMATION | wxOK );
+ AskForceWatch( rep );
+ return;
+ }
+ bool versionfound = false;
+ for ( std::map<wxString, wxString>::iterator itor = versionlist.begin(); itor != versionlist.end(); itor++ ) {
+ if ( itor->second == rep.SpringVersion ) {
+ if ( sett().GetCurrentUsedSpringIndex() != itor->first ) {
+ wxLogMessage( _T( "%s requires version: %s, switching to profile: %s" ), type.c_str(), rep.SpringVersion.c_str(), itor->first.c_str() );
+ sett().SetUsedSpringIndex( itor->first );
+ ui().ReloadUnitSync();
+ }
+ versionfound = true;
+ }
+ }
+ if ( !ReplayTraits::IsReplayType )
+ versionfound = true; // quick hack to bypass spring version check
+ if ( !versionfound ) {
+ wxString message = wxString::Format( _( "No compatible installed spring version has been found, this %s requires version: %s\n" ), type.c_str(), rep.SpringVersion.c_str() );
+ message << _( "Your current installed versions are:" );
+ for ( std::map<wxString, wxString>::iterator itor = versionlist.begin(); itor != versionlist.end(); itor++ ) message << _T( " " ) << itor->second;
+ customMessageBox( SL_MAIN_ICON, message, _( "Spring error" ), wxICON_EXCLAMATION | wxOK );
+ wxLogWarning ( _T( "no spring version supported by this replay found" ) );
+ AskForceWatch( rep );
+ return;
+ }
+ rep.battle.GetMe().SetNick( usync().GetDefaultNick() );
+ bool watchable = rep.battle.MapExists() && rep.battle.ModExists();
+ if ( watchable )
+ rep.battle.StartSpring();
+ else {
+#ifdef NO_TORRENT_SYSTEM
+ wxString downloadProc = _( "Do you want me to take you to the download page?" );
+#else
+ wxString downloadProc = _( "Should i try to download it for you?\nYou can see the progress in the \"Download Manager\" tab." );
+#endif
+
+ OfflineBattle& battle = rep.battle;
+
+ if ( !battle.ModExists() ) {
+ if ( customMessageBox( SL_MAIN_ICON, _( "You need to download the mod before you can watch this replay.\n\n" ) + downloadProc, _( "Mod not available" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
+ wxString modhash = battle.GetHostModHash();
+ wxString modname = battle.GetHostModName();
+ m_ui.DownloadMod ( modhash, modname );
+ }
+ else {
+ AskForceWatch( rep );
+ }
+ return;
+ }
+
+ if ( !battle.MapExists() ) {
+ if ( customMessageBox( SL_MAIN_ICON, _( " I couldn't find the map to be able to watch this replay\nThis can be caused by tasclient writing broken map hash value\nIf you're sure you have the map, press no\nYou need to download the map to be able to watch this replay.\n\n" ) + downloadProc, _( "Map not available" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
+ wxString maphash = battle.GetHostMapHash();
+ wxString mapname = battle.GetHostMapName();
+ m_ui.DownloadMap ( maphash, mapname );
+ }
+ else {
+ AskForceWatch( rep );
+ }
+ }
+ }
+ } catch ( std::runtime_error ) {
+ return;
+ }
+ } else {
+ Deselected();
+ }
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::AskForceWatch( typename PlaybackTab<PlaybackTraits>::PlaybackType& rep ) const
+{
+ if ( customMessageBox( SL_MAIN_ICON, _( "I don't think you will be able to watch this replay.\nTry anyways? (MIGHT CRASH!)" ) , _( "Invalid replay" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
+ rep.battle.StartSpring();
+ }
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::OnDelete( wxCommandEvent& /*unused*/ )
+{
+ int sel_index = m_replay_listctrl->GetSelectedIndex();
+ if ( sel_index >= 0 ) {
+ try {
+ const PlaybackType& rep = *m_replay_listctrl->GetSelectedData();
+ int m_sel_replay_id = rep.id;
+ int index = m_replay_listctrl->GetIndexFromData( &rep );
+ wxLogMessage( _T( "Deleting replay %d " ), m_sel_replay_id );
+ wxString fn = rep.Filename;
+ if ( !playbacklist<ListType>().DeletePlayback( m_sel_replay_id ) )
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "Could not delete Replay: " ) + fn,
+ _( "Error" ) );
+ else {
+ RemovePlayback( index ); // Deselect is called in there too
+ }
+ } catch ( std::runtime_error ) {
+ return;
+ }
+ } else {
+ Deselected();
+ }
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::OnFilterActiv( wxCommandEvent& /*unused*/ )
+{
+ m_filter->SetActiv( m_filter_activ->GetValue() );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::OnSelect( wxListEvent& event )
+{
+ wxLogDebugFunc( _T( "" ) );
+ if ( event.GetIndex() == -1 ) {
+ Deselect();
+ }
+ else
+ {
+ try
+ {
+ m_watch_btn->Enable( true );
+ m_delete_btn->Enable( true );
+ int index = event.GetIndex();
+ m_replay_listctrl->SetSelectedIndex( index );
+
+ //this might seem a bit backwards, but it's currently the only way that doesn't involve casting away constness
+ int m_sel_replay_id = m_replay_listctrl->GetDataFromIndex( index )->id;
+ PlaybackType& rep = playbacklist<ListType>().GetPlaybackById( m_sel_replay_id );
+
+
+ wxLogMessage( _T( "Selected replay %d " ), m_sel_replay_id );
+
+ m_players_text->SetLabel( _T( "" ) );
+ m_map_text->SetLabel( rep.battle.GetHostMapName() );
+ m_mod_text->SetLabel( rep.battle.GetHostModName() );
+ m_minimap->SetBattle( &( rep.battle ) );
+ m_minimap->UpdateMinimap();
+
+ m_players->Clear();
+ m_players->SetBattle( ( IBattle* )&rep.battle );
+ for ( size_t i = 0; i < rep.battle.GetNumUsers(); ++i ) {
+ try {
+ User& usr = rep.battle.GetUser( i );
+ m_players->AddUser( usr );
+ }
+ catch ( ... )
+ {}
+ }
+ }
+ catch ( ... ) {
+ Deselect();
+ }
+ event.Skip();
+ }
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::OnDeselect( wxListEvent& /*unused*/ )
+{
+ Deselected();
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::Deselect()
+{
+ m_replay_listctrl->SelectNone();
+ Deselected();
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::Deselected()
+{
+ m_watch_btn->Enable( false );
+ m_delete_btn->Enable( false );
+ m_players_text->SetLabel( _T( "" ) );
+ m_map_text->SetLabel( _T( "" ) );
+ m_mod_text->SetLabel( _T( "" ) );
+ m_minimap->SetBattle( NULL );
+ m_minimap->UpdateMinimap();
+ m_minimap->Refresh();
+ m_players->Clear();
+ m_players->SetBattle( NULL );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::ReloadList()
+{
+ wxDateTime dt = wxDateTime::UNow();
+ Deselect();
+ m_replay_listctrl->Clear();
+ m_replay_loader->Run();
+
+
+// long sec = (wxDateTime::UNow() - dt).GetMilliseconds().ToLong();
+// if ( sec > 0 )
+// customMessageBoxNoModal(SL_MAIN_ICON, wxString::Format( _T("List reloaded in %d milli seconds"),sec ) );
+}
+
+template < class PlaybackTraits >
+void PlaybackTab<PlaybackTraits>::OnReload( wxCommandEvent& /*unused*/ )
+{
+ ReloadList();
+}
diff --git a/src/playback/playbacktab.h b/src/playback/playbacktab.h
new file mode 100644
index 0000000..82beed4
--- /dev/null
+++ b/src/playback/playbacktab.h
@@ -0,0 +1,154 @@
+#ifndef SPRINGLOBBY_PlaybackTab_H_INCLUDED
+#define SPRINGLOBBY_PlaybackTab_H_INCLUDED
+
+#include <wx/panel.h>
+#include <vector>
+
+class Ui;
+class MapCtrl;
+class BattleroomListCtrl;
+class wxCommandEvent;
+class wxListEvent;
+class wxStaticText;
+class wxComboBox;
+class wxButton;
+class wxBoxSizer;
+class wxStaticText;
+class wxStaticLine;
+class wxCheckBox;
+class wxToggleButton;
+
+template <class PlaybackTabType>
+class PlaybackListFilter;
+
+template <class PlaybackType>
+class PlaybackListCtrl;
+
+template <class PlaybackType>
+class PlaybackLoader;
+
+template <class PlaybackTraitsImp>
+class PlaybackTab : public wxPanel
+{
+ protected:
+ friend class BattleListFilter; //! WTF?
+
+ public:
+ typedef PlaybackTraitsImp
+ PlaybackTraits;
+ typedef typename PlaybackTraits::PlaybackType
+ PlaybackType;
+ typedef PlaybackTab<PlaybackTraits>
+ ThisType;
+ typedef typename PlaybackTraits::ListType
+ ListType;
+ typedef PlaybackListCtrl<PlaybackType>
+ ListCtrlType;
+ typedef PlaybackLoader<ThisType>
+ LoaderType;
+
+ static const bool IsReplayType = PlaybackTraits::IsReplayType;
+
+ public:
+ //! loads all replays into list and adds them to listctrl
+ PlaybackTab( wxWindow* parent, Ui& ui );
+ ~PlaybackTab();
+
+ //! adds a single replay to listctrl
+ void AddPlayback( const PlaybackType& Replay );
+ void RemovePlayback( const PlaybackType& Replay );
+ void RemovePlayback( const int index );
+ void UpdatePlayback( const PlaybackType& Replay );
+
+ //! add all replays in m_replays to listctrl
+ void AddAllPlaybacks( wxCommandEvent& evt );
+ void RemoveAllPlaybacks();
+ void ReloadList();
+
+ void UpdateList();
+
+ //! calls ui::watch which executes spring
+ void OnWatch( wxCommandEvent& event );
+ //! clears list and parses all replays anew
+ void OnReload( wxCommandEvent& event );
+ //! does nothing yet
+ void OnDelete( wxCommandEvent& event );
+ //! does nothing yet
+ void OnFilter( wxCommandEvent& event );
+ //! does nothing yet
+ void OnFilterActiv( wxCommandEvent& event );
+
+ //! sets m_sel_replay_id according to selected listitem
+ void OnSelect( wxListEvent& event );
+ //! does nothing yet
+ void SetFilterActiv(bool activ);
+
+ void Deselect();
+ void Deselected();
+ void OnDeselect( wxListEvent& event );
+
+ protected:
+ PlaybackListFilter<ThisType>* m_filter;
+ ListCtrlType* m_replay_listctrl;
+ LoaderType* m_replay_loader;
+ MapCtrl* m_minimap;
+ wxStaticText* m_map_lbl;
+ wxStaticText* m_map_text;
+ wxStaticText* m_mod_lbl;
+ wxStaticText* m_mod_text;
+ wxStaticText* m_players_lbl;
+ wxStaticText* m_players_text;
+
+ wxStaticLine* m_buttons_sep;
+ wxButton* m_watch_btn;
+ wxButton* m_delete_btn;
+ wxButton* m_reload_btn;
+
+ BattleroomListCtrl* m_players;
+
+ wxCheckBox* m_filter_activ;
+#if wxUSE_TOGGLEBTN
+ wxToggleButton* m_filter_show;
+#else
+ wxCheckBox* m_filter_show;
+#endif
+
+ Ui& m_ui;
+
+ void AskForceWatch( PlaybackType& rep ) const;
+
+ DECLARE_EVENT_TABLE();
+};
+
+enum
+{
+ PLAYBACK_WATCH = wxID_HIGHEST,
+ PLAYBACK_DELETE,
+ PLAYBACK_RELOAD,
+ PLAYBACK_LIST,
+ PLAYBACK_LIST_FILTER_BUTTON,
+ PLAYBACK_LIST_FILTER_ACTIV,
+ PLAYBACK_TIMER,
+ PLAYBACK_USER_LIST
+};
+
+#include "playbacktab.cpp"
+#endif // SPRINGLOBBY_PlaybackTab_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/playback/playbackthread.cpp b/src/playback/playbackthread.cpp
new file mode 100644
index 0000000..06e20c2
--- /dev/null
+++ b/src/playback/playbackthread.cpp
@@ -0,0 +1,75 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+//
+
+#include <wx/app.h>
+#include <wx/log.h>
+
+//#include "../utils.h"
+#include "replaylist.h"
+#include "savegamelist.h"
+#include "../iunitsync.h"
+
+template <class PlaybackTabImp >
+PlaybackLoader<PlaybackTabImp>::PlaybackLoader( ParentType* parent )
+ : m_parent( parent ),
+ m_thread_loader( 0 )
+{
+}
+
+template <class PlaybackTabImp >
+PlaybackLoader<PlaybackTabImp>::~PlaybackLoader()
+{
+}
+
+template <class PlaybackTabImp >
+void PlaybackLoader<PlaybackTabImp>::Run()
+{
+ if ( !usync().IsLoaded() ) return;
+ if ( m_thread_loader ) return; // a thread is already running
+ m_filenames = usync().GetPlaybackList( IsReplayType );
+ playbacklist<ListType>().RemoveAll();
+ m_thread_loader = new ThreadType();
+ m_thread_loader->SetParent( this );
+ m_thread_loader->Create();
+ m_thread_loader->Run();
+}
+
+template <class PlaybackTabImp >
+void PlaybackLoader<PlaybackTabImp>::OnComplete()
+{
+ if ( !m_parent ) return;
+ wxCommandEvent notice( PlaybacksLoadedEvt, 1 );
+ m_parent->ProcessEvent( notice );
+ m_thread_loader = 0; // the thread object deleted itself
+}
+
+template <class PlaybackTabImp >
+wxArrayString PlaybackLoader<PlaybackTabImp>::GetPlaybackFilenames()
+{
+ return m_filenames;
+}
+
+template <class PlaybackTabImp >
+PlaybackLoader<PlaybackTabImp>::PlaybackLoaderThread::PlaybackLoaderThread():
+m_parent(0)
+{
+}
+
+template <class PlaybackTabImp >
+void* PlaybackLoader<PlaybackTabImp>::ThreadType::Entry()
+{
+ if( m_parent )
+ {
+ playbacklist<ListType>().LoadPlaybacks( m_parent->GetPlaybackFilenames() );
+ m_parent->OnComplete();
+ }
+
+ return NULL;
+}
+
+template <class PlaybackTabImp >
+void PlaybackLoader<PlaybackTabImp>::PlaybackLoaderThread::SetParent( ParentType* parent )
+{
+ m_parent = parent;
+}
diff --git a/src/playback/playbackthread.h b/src/playback/playbackthread.h
new file mode 100644
index 0000000..c5c07e0
--- /dev/null
+++ b/src/playback/playbackthread.h
@@ -0,0 +1,74 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_PLAYBACKTHREAD
+#define SPRINGLOBBY_HEADERGUARD_PLAYBACKTHREAD
+
+#include <wx/string.h>
+
+static const wxEventType PlaybacksLoadedEvt = wxNewEventType();
+
+template <class PlaybackTabImp >
+class PlaybackLoader
+{
+protected:
+
+ class PlaybackLoaderThread : public wxThread
+ {
+ private:
+ typedef PlaybackLoader<PlaybackTabImp>
+ ParentType;
+
+ public:
+ PlaybackLoaderThread();
+ void SetParent( ParentType* parent );
+ void* Entry();
+
+ private:
+ ParentType* m_parent;
+ };
+
+public:
+ typedef PlaybackTabImp
+ ParentType;
+ typedef typename ParentType::PlaybackType
+ PlaybackType;
+ typedef typename ParentType::ListType
+ ListType;
+ typedef PlaybackLoader<PlaybackTabImp>
+ ThisType;
+ typedef PlaybackLoaderThread
+ ThreadType;
+
+ static const bool IsReplayType = ParentType::IsReplayType;
+
+ PlaybackLoader( ParentType* parent );
+ ~PlaybackLoader();
+ void OnComplete();
+ void Run();
+ wxArrayString GetPlaybackFilenames();
+
+protected:
+ wxArrayString m_filenames;
+ ParentType* m_parent;
+ ThreadType* m_thread_loader;
+
+};
+
+#include "playbackthread.cpp"
+#endif // SPRINGLOBBY_HEADERGUARD_PLAYBACKTHREAD
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/playback/playbacktraits.h b/src/playback/playbacktraits.h
new file mode 100644
index 0000000..f3972e3
--- /dev/null
+++ b/src/playback/playbacktraits.h
@@ -0,0 +1,32 @@
+#ifndef PLAYBACKTRAITS_H_INCLUDED
+#define PLAYBACKTRAITS_H_INCLUDED
+
+class Replay;
+class ReplayList;
+
+class ReplayTraits {
+ public:
+ typedef Replay
+ PlaybackType;
+
+ typedef ReplayList
+ ListType;
+
+ static const bool IsReplayType = true;
+};
+
+class Savegame;
+class SavegameList;
+
+class SavegameTraits {
+ public:
+ typedef Savegame
+ PlaybackType;
+
+ typedef SavegameList
+ ListType;
+
+ static const bool IsReplayType = false;
+};
+
+#endif // PLAYBACKTRAITS_H_INCLUDED
diff --git a/src/playback/replaylist.cpp b/src/playback/replaylist.cpp
new file mode 100644
index 0000000..3de1dcc
--- /dev/null
+++ b/src/playback/replaylist.cpp
@@ -0,0 +1,120 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+#include <iterator>
+#include <algorithm>
+#include <wx/file.h>
+#include <wx/filefn.h>
+
+#include "replaylist.h"
+#include "../utils/math.h"
+#include "../utils/conversion.h"
+#include "../settings++/custom_dialogs.h"
+#include "playbacktab.h"
+#include "playbackstructs.h"
+#include "../uiutils.h"
+#include "../globalsmanager.h"
+
+
+ReplayList::ReplayList()
+{
+}
+
+void ReplayList::LoadPlaybacks( const wxArrayString& filenames )
+{
+ m_fails = 0;
+
+ m_replays.clear();
+ size_t size = filenames.GetCount();
+ for ( size_t i = 0; i < size; ++i)
+ {
+ Replay rep;
+ rep.id = i;
+ Replay& rep_ref = AddPlayback( rep ); // don't touch this reference, since elements inside this data structure are filled using pointers, adding & not fecthing the new addresses would screw up references when rep gets destroyed
+ if ( !GetReplayInfos( filenames[i] , rep_ref ) )
+ {
+ RemovePlayback( rep.id );
+ m_fails++;
+ }
+ }
+}
+
+bool ReplayList::GetReplayInfos ( const wxString& ReplayPath, Replay& ret )
+{
+ //wxLogMessage(_T("GetReplayInfos %s"), ReplayPath.c_str());
+ //wxLOG_Info ( STD_STRING( ReplayPath ) );
+ //TODO extract moar info
+ ret.Filename = ReplayPath;
+ ret.battle.SetPlayBackFilePath( ReplayPath );
+
+ wxString FileName = ReplayPath.AfterLast( '/' ); // strips file path
+ FileName = FileName.BeforeLast( _T('.') ); //strips the file extension;
+
+ ret.date = FileName.BeforeFirst(_T('_'));
+ FileName = FileName.AfterFirst(_T('_'));
+
+ FileName = FileName.AfterFirst(_T('_')); // strips hours minutes seconds informatiom
+
+ ret.SpringVersion = FileName.AfterLast(_T('_'));
+
+ ret.MapName = FileName.BeforeLast(_T('_'));
+
+ ret.battle.SetScript( GetScriptFromReplay( ReplayPath ) );
+ //wxLogMessage(_T("Script: %s"), script.c_str());
+
+ if ( ret.battle.GetScript().IsEmpty() ) return false;
+
+ GetHeaderInfo( ret, ReplayPath );
+ ret.battle.GetBattleFromScript( false );
+ ret.ModName = ret.battle.GetHostModName();
+ ret.battle.SetBattleType( BT_Replay );
+
+ return true;
+}
+
+wxString ReplayList::GetScriptFromReplay ( const wxString& ReplayPath )
+{
+ wxString script;
+ try
+ {
+ wxFile replay( ReplayPath, wxFile::read );
+ if ( !replay.IsOpened() ) return script;
+ replay.Seek( 20 );
+ int headerSize=0 ;
+ replay.Read( &headerSize, 4);
+ replay.Seek( 64 );
+ int scriptSize=0;
+ replay.Read( &scriptSize, 4);
+ replay.Seek( headerSize );
+ std::string script_a(scriptSize,0);
+ replay.Read( &script_a[0], scriptSize );
+ script = TowxString( script_a ) ;//(script_a,scriptSize);
+
+ }
+ catch (...)
+ {
+ }
+ return script;
+}
+
+
+void ReplayList::GetHeaderInfo( Replay& rep, const wxString& ReplayPath )
+{
+ try
+ {
+ wxFile replay( ReplayPath, wxFile::read );
+ replay.Seek( 72 );
+ int gametime = 0 ;
+ replay.Read( &gametime, 4);
+ rep.duration = gametime;
+ rep.size = replay.Length();
+ wxLongLong_t unixtime = 0;
+ replay.Seek( 56 );
+ replay.Read( &unixtime, 8 );
+ wxDateTime dt;
+ dt.Set( (time_t) unixtime );
+ // todo: add 2 strings one for date other for time?
+ wxString date = dt.FormatISODate()+_T(" ")+dt.FormatISOTime();
+ rep.date = date;
+ }
+ catch (...){ }
+}
+
diff --git a/src/playback/replaylist.h b/src/playback/replaylist.h
new file mode 100644
index 0000000..03e8843
--- /dev/null
+++ b/src/playback/replaylist.h
@@ -0,0 +1,87 @@
+#ifndef SPRINGLOBBY_REPLAYLIST_H_INCLUDED
+#define SPRINGLOBBY_REPLAYLIST_H_INCLUDED
+
+
+#include <wx/string.h>
+#include <wx/timer.h>
+#include <wx/arrstr.h>
+
+#include "playbacklist.h"
+#include "playbacktraits.h"
+//copied from spring sources for reference
+//struct DemoFileHeader
+//{
+// char magic[16]; ///< DEMOFILE_MAGIC
+// int version; ///< DEMOFILE_VERSION
+// int headerSize; ///< Size of the DemoFileHeader, minor version number.
+// char versionString[16]; ///< Spring version string, e.g. "0.75b2", "0.75b2+svn4123"
+// Uint8 gameID[16]; ///< Unique game identifier. Identical for each player of the game.
+// Uint64 unixTime; ///< Unix time when game was started.
+// int scriptSize; ///< Size of startscript.
+// int demoStreamSize; ///< Size of the demo stream.
+// int gameTime; ///< Total number of seconds game time.
+// int wallclockTime; ///< Total number of seconds wallclock time.
+// int maxPlayerNum; ///< Maximum player number which was used in this game.
+// int numPlayers; ///< Number of players for which stats are saved.
+// int playerStatSize; ///< Size of the entire player statistics chunk.
+// int playerStatElemSize; ///< sizeof(CPlayer::Statistics)
+// int numTeams; ///< Number of teams for which stats are saved.
+// int teamStatSize; ///< Size of the entire team statistics chunk.
+// int teamStatElemSize; ///< sizeof(CTeam::Statistics)
+// int teamStatPeriod; ///< Interval (in seconds) between team stats.
+// int winningAllyTeam; ///< The ally team that won the game, -1 if unknown.
+//};
+
+class Replay;
+
+template <class PB>
+class GlobalObjectHolder;
+
+class ReplayList : public PlaybackList<Replay>
+{
+ public:
+
+ typedef Replay
+ PlaybackType;
+
+ virtual void LoadPlaybacks( const wxArrayString& filenames );
+
+ protected:
+ ReplayList();
+
+ template <class PB>
+ friend class GlobalObjectHolder;
+
+ bool GetReplayInfos ( const wxString& ReplayPath, Replay& ret );
+ wxString GetScriptFromReplay ( const wxString& ReplayPath );
+ BattleOptions GetBattleOptsFromScript( const wxString& script_ );
+
+ //! load mod/map options
+ void LoadMMOpts( const wxString& sectionname, IBattle& battle, const PDataList& node );
+ //! load engine options
+ void LoadMMOpts( IBattle& battle, const PDataList& node );
+
+ //! saves relevant infos from header into replay struct
+ void GetHeaderInfo( Replay& rep, const wxString& ReplayPath );
+
+};
+
+#endif // SPRINGLOBBY_REPLAYLIST_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/playback/savegamelist.cpp b/src/playback/savegamelist.cpp
new file mode 100644
index 0000000..852eb0b
--- /dev/null
+++ b/src/playback/savegamelist.cpp
@@ -0,0 +1,80 @@
+#include "savegamelist.h"
+
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+#include <iterator>
+#include <algorithm>
+#include <fstream>
+#include <wx/file.h>
+#include <wx/filefn.h>
+
+#include "replaylist.h"
+//#include "../utils/.h"
+#include "../settings++/custom_dialogs.h"
+#include "playbacktab.h"
+#include "playbackstructs.h"
+#include "../uiutils.h"
+#include "../globalsmanager.h"
+
+
+SavegameList::SavegameList()
+{
+}
+
+
+void SavegameList::LoadPlaybacks( const wxArrayString& filenames )
+{
+ m_fails = 0;
+
+ m_replays.clear();
+ size_t size = filenames.GetCount();
+ for ( size_t i = 0; i < size; ++i)
+ {
+ Savegame rep;
+ rep.id = i;
+ wxString fn = filenames[i];
+ Savegame& rep_ref = AddPlayback( rep ); // don't touch this reference, since elements inside this data structure are filled using pointers, adding & not fecthing the new addresses would screw up references when rep gets destroyed
+
+ if ( !GetSavegameInfos( filenames[i] , rep_ref ) )
+ {
+ RemovePlayback( rep.id );
+ m_fails++;
+ }
+ }
+}
+
+bool SavegameList::GetSavegameInfos ( const wxString& SavegamePath, Savegame& ret )
+{
+ //wxLogMessage(_T("GetSavegameInfos %s"), SavegamePath.c_str());
+ //wxLOG_Info ( STD_STRING( SavegamePath ) );
+ //TODO extract moar info
+ ret.Filename = SavegamePath;
+ ret.battle.SetPlayBackFilePath( SavegamePath );
+ if ( SavegamePath.IsEmpty() ) return false;
+ ret.battle.SetScript( GetScriptFromSavegame( SavegamePath ) );
+ //wxLogMessage(_T("Script: %s"), script.c_str());
+
+ if ( ret.battle.GetScript().IsEmpty() ) return false;
+
+ ret.battle.GetBattleFromScript( true );
+ ret.ModName = ret.battle.GetHostModName();
+ ret.battle.SetBattleType( BT_Savegame );
+
+ return true;
+}
+
+wxString SavegameList::GetScriptFromSavegame ( const wxString& SavegamePath )
+{
+ // blatantly copied from spring source
+ std::ifstream file(SavegamePath.mb_str(), std::ios::in|std::ios::binary);
+ std::string script;
+ char c;
+ if ( file.is_open() )
+ {
+ do
+ {
+ file.read(&c,sizeof(char));
+ if (c) script += c;
+ } while ( ( c != 0 ) && !file.eof() );
+ }
+ return TowxString( script );
+}
diff --git a/src/playback/savegamelist.h b/src/playback/savegamelist.h
new file mode 100644
index 0000000..ed365b5
--- /dev/null
+++ b/src/playback/savegamelist.h
@@ -0,0 +1,57 @@
+#ifndef SAVEGAMELIST_H
+#define SAVEGAMELIST_H
+
+#include "playbacklist.h"
+
+class Savegame;
+
+template <class PB>
+class GlobalObjectHolder;
+
+class SavegameList : public PlaybackList<Savegame>
+{
+ public:
+
+ typedef Savegame
+ PlaybackType;
+
+ virtual void LoadPlaybacks( const wxArrayString& filenames );
+
+ protected:
+ SavegameList();
+
+ template <class PB>
+ friend class GlobalObjectHolder;
+
+ bool GetSavegameInfos ( const wxString& SavegamePath, Savegame& ret );
+ wxString GetScriptFromSavegame ( const wxString& SavegamePath );
+ BattleOptions GetBattleOptsFromScript( const wxString& script_ );
+
+ //! load mod/map options
+ void LoadMMOpts( const wxString& sectionname, OfflineBattle& battle, const PDataList& node );
+ //! load engine options
+ void LoadMMOpts( OfflineBattle& battle, const PDataList& node );
+
+ //! saves relevant infos from header into replay struct
+ void GetHeaderInfo( Savegame& rep, const wxString& SavegamePath );
+
+};
+
+#endif // SAVEGAMELIST_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/sdlsound.cpp b/src/sdlsound.cpp
new file mode 100644
index 0000000..ac44d9d
--- /dev/null
+++ b/src/sdlsound.cpp
@@ -0,0 +1,63 @@
+#ifndef DISABLE_SOUND
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+
+#include "sounds/ring_sound.h"
+#include "sounds/pm_sound.h"
+
+#include "sdlsound.h"
+
+
+SDLSound& sound()
+{
+ static SDLSound m_sound;
+ return m_sound;
+}
+
+SDLSound::SDLSound()
+{
+ //Initialise SDL, mixer subsystem and load sound sample
+ //Fails are treated silently
+ SDL_RWops *ringwave = SDL_RWFromConstMem(ring_sound_data, sizeof(ring_sound_data));
+ SDL_RWops *pmwave = SDL_RWFromConstMem(pm_sound_data, sizeof(pm_sound_data));
+
+ if(SDL_Init(SDL_INIT_AUDIO) < 0) {
+ return;
+ }
+
+ if (Mix_OpenAudio(11025, AUDIO_S16SYS, 1, 1024) < 0)
+ {
+ return;
+ }
+
+
+
+ ring_sound = Mix_LoadWAV_RW(ringwave, 0);
+ pm_sound = Mix_LoadWAV_RW( pmwave, 0);
+
+}
+
+SDLSound::~SDLSound()
+{
+ if ( ring_sound ) Mix_FreeChunk(ring_sound);
+ if ( pm_sound ) Mix_FreeChunk(pm_sound);
+
+
+ Mix_CloseAudio();
+
+ SDL_Quit();
+}
+
+void SDLSound::ring() const
+{
+ if ( ring_sound ) Mix_PlayChannel(-1, ring_sound, 0);
+}
+
+
+void SDLSound::pm() const
+{
+ if ( pm_sound ) Mix_PlayChannel(-1, pm_sound, 0);
+}
+
+#endif
diff --git a/src/sdlsound.h b/src/sdlsound.h
new file mode 100644
index 0000000..fa32596
--- /dev/null
+++ b/src/sdlsound.h
@@ -0,0 +1,47 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SDLSOUND_H
+#define SPRINGLOBBY_HEADERGUARD_SDLSOUND_H
+
+#ifndef DISABLE_SOUND
+
+//struct Mix_Chunk;
+#include <SDL_mixer.h>
+
+class SDLSound
+{
+ public:
+ SDLSound();
+ ~SDLSound();
+
+ void ring() const;
+ void pm() const;
+
+ private:
+
+ Mix_Chunk *ring_sound;
+ Mix_Chunk *pm_sound;
+
+};
+
+SDLSound& sound();
+
+#endif
+
+#endif // SPRINGLOBBY_HEADERGUARD_SDLSOUND_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/selectusersdialog.cpp b/src/selectusersdialog.cpp
new file mode 100644
index 0000000..952f2ed
--- /dev/null
+++ b/src/selectusersdialog.cpp
@@ -0,0 +1,329 @@
+
+#include "selectusersdialog.h"
+
+#include <wx/string.h>
+#include <wx/stattext.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+#include <wx/colour.h>
+#include <wx/settings.h>
+#include <wx/textctrl.h>
+#include <wx/sizer.h>
+#include <wx/listctrl.h>
+#include <wx/panel.h>
+#include <wx/statline.h>
+#include <wx/button.h>
+#include <wx/tokenzr.h>
+#include <wx/wupdlock.h>
+
+#include "iconimagelist.h"
+#include "ui.h"
+#include "userlist.h"
+#include "server.h"
+#include "user.h"
+#include "utils/conversion.h"
+#include "useractions.h"
+
+
+BEGIN_EVENT_TABLE( SelectUsersDialog, wxDialog )
+ EVT_TEXT( FILTER_TEXT, SelectUsersDialog::OnNameFilterChange )
+ EVT_LIST_ITEM_ACTIVATED( NICK_LIST, SelectUsersDialog::OnNameActivated )
+ EVT_LIST_ITEM_DESELECTED( NICK_LIST, SelectUsersDialog::OnNameDeselected )
+ EVT_LIST_ITEM_SELECTED( NICK_LIST, SelectUsersDialog::OnNameSelected )
+ EVT_BUTTON( wxID_CANCEL, SelectUsersDialog::OnCancel )
+ EVT_BUTTON( wxID_OK, SelectUsersDialog::OnOk )
+END_EVENT_TABLE()
+
+SelectUsersDialog::SelectUsersDialog( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
+{
+ this->SetSizeHints( wxDefaultSize, wxDefaultSize );
+
+ wxBoxSizer* mainSizer;
+ mainSizer = new wxBoxSizer( wxVERTICAL );
+
+ m_users_panel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxTAB_TRAVERSAL );
+ wxBoxSizer* bUsersListSizer;
+ bUsersListSizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* filterSizer;
+ filterSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_filter_names_staticText = new wxStaticText( m_users_panel, wxID_ANY, _("Filter names"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_filter_names_staticText->Wrap( -1 );
+ filterSizer->Add( m_filter_names_staticText, 0, wxALL|wxALIGN_BOTTOM, 5 );
+
+ m_name_filter_text = new wxTextCtrl( m_users_panel, FILTER_TEXT, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ m_name_filter_text->SetToolTip( _("Enter text filter to filter the online users list") );
+
+ filterSizer->Add( m_name_filter_text, 1, wxLEFT|wxRIGHT|wxTOP, 5 );
+
+ bUsersListSizer->Add( filterSizer, 0, wxEXPAND, 5 );
+
+ m_user_list = new wxListCtrl( m_users_panel, NICK_LIST, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER|wxLC_SORT_ASCENDING );
+ bUsersListSizer->Add( m_user_list, 1, wxALL|wxEXPAND, 5 );
+
+ m_users_panel->SetSizer( bUsersListSizer );
+ m_users_panel->Layout();
+ bUsersListSizer->Fit( m_users_panel );
+ mainSizer->Add( m_users_panel, 1, wxEXPAND, 5 );
+
+ wxBoxSizer* bNameSizer;
+ bNameSizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_name_staticText = new wxStaticText( this, wxID_ANY, _("Name"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_name_staticText->Wrap( -1 );
+ bNameSizer->Add( m_name_staticText, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+
+ m_selection_text = new wxTextCtrl( this, NAME_TEXT, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ bNameSizer->Add( m_selection_text, 1, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+
+ mainSizer->Add( bNameSizer, 0, wxEXPAND, 5 );
+
+ m_buttons_hr = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ mainSizer->Add( m_buttons_hr, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+
+ m_dialog_buttons = new wxStdDialogButtonSizer();
+ m_dialog_buttonsOK = new wxButton( this, wxID_OK );
+ m_dialog_buttons->AddButton( m_dialog_buttonsOK );
+ m_dialog_buttonsCancel = new wxButton( this, wxID_CANCEL );
+ m_dialog_buttons->AddButton( m_dialog_buttonsCancel );
+ m_dialog_buttons->Realize();
+ mainSizer->Add( m_dialog_buttons, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
+
+ this->SetSizer( mainSizer );
+ this->Layout();
+
+ Initialize();
+}
+
+SelectUsersDialog::~SelectUsersDialog()
+{
+ ClearList();
+}
+
+void SelectUsersDialog::Initialize()
+{
+ m_user_list->InsertColumn(0, _("Nickname"), wxLIST_FORMAT_LEFT, 300);
+ m_user_list->SetImageList( &icons(), wxIMAGE_LIST_SMALL );
+ m_user_list->SetImageList( &icons(), wxIMAGE_LIST_NORMAL );
+ m_user_list->SetImageList( &icons(), wxIMAGE_LIST_STATE );
+ PopulateUsersList();
+}
+
+void SelectUsersDialog::PopulateUsersList()
+{
+ ClearList();
+ if ( ui().IsConnected() ) {
+ const UserList& userlist = ui().GetServer().GetUserList();
+
+ wxWindowUpdateLocker noUpdates(m_user_list);
+ for ( unsigned int i = 0; i < userlist.GetNumUsers(); ++i) {
+ wxString name = userlist.GetUser( i ).GetNick();
+ if ( !useractions().IsKnown( name ) && !ui().IsThisMe( name ) ) {
+ wxString country = userlist.GetUser( i ).GetCountry();
+ AddUserToList( name, country );
+ }
+ }
+ Sort();
+ }
+}
+
+void SelectUsersDialog::ClearList()
+{
+ wxWindowUpdateLocker noUpdates(m_user_list);
+ long item = -1;
+ while ( true ) {
+ item = m_user_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_DONTCARE);
+ if ( item == -1 )
+ break;
+ RemoveUserFromList( item );
+ item = -1;
+ }
+}
+
+long SelectUsersDialog::AddUserToList( const wxString& nick, const wxString& flag )
+{
+ return AddUserToList(nick, icons().GetFlagIcon(flag) );
+}
+
+long SelectUsersDialog::AddUserToList( const wxString& nick, const int& flag )
+{
+ long item = m_user_list->InsertItem(0, nick, flag );
+ m_user_list->SetItemData(item, (wxUIntPtr)(new wxString(nick)));
+ return item;
+}
+
+void SelectUsersDialog::RemoveUserFromList( long item )
+{
+ delete (wxString*)m_user_list->GetItemData(item);
+ m_user_list->DeleteItem(item);
+}
+
+void SelectUsersDialog::UpdateUsersList()
+{
+}
+
+void SelectUsersDialog::UpdateSelection()
+{
+ wxSortedArrayString text = GetSelectionFromText();
+ for ( unsigned int i = 0; i < m_selection.Count(); i++ ) {
+ if ( text.Index(m_selection[i], false) == wxNOT_FOUND ) text.Insert( m_selection[i], 0 );
+ }
+
+ m_selection_text->SetValue(BuildSelectionText( text ));
+}
+
+wxString SelectUsersDialog::BuildSelectionText( const wxSortedArrayString& sel )
+{
+ wxString str;
+ for ( unsigned int i = 0; i < sel.Count(); i++ ) {
+ if ( str != wxEmptyString ) str += _T(";");
+ str += sel[i];
+ }
+ return str;
+}
+
+wxSortedArrayString SelectUsersDialog::GetSelectionFromText()
+{
+ wxSortedArrayString s;
+ wxStringTokenizer st(m_selection_text->GetValue(), _T(";, "), wxTOKEN_DEFAULT);
+ while ( st.HasMoreTokens() ) {
+ s.Add(st.GetNextToken());
+ }
+ return s;
+}
+
+wxSortedArrayString SelectUsersDialog::GetUsers(wxWindow* parent)
+{
+ SelectUsersDialog dlg(parent);
+ if ( dlg.ShowModal() == wxID_OK ) {
+ return dlg.GetSelection();
+ } else {
+ wxSortedArrayString s;
+ return s;
+ }
+}
+
+int SelectUsersDialog::ShowModal()
+{
+ m_selection.Clear();
+ return wxDialog::ShowModal();
+}
+
+void SelectUsersDialog::OnNameFilterChange( wxCommandEvent& /*unused*/ )
+{
+ long item = -1;
+ wxString filter = m_name_filter_text->GetValue();
+
+ wxArrayString del;
+
+wxWindowUpdateLocker noUpdates(m_user_list);
+ while ( true ) {
+ item = m_user_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_DONTCARE);
+ if ( item == -1 )
+ break;
+
+ wxString name = m_user_list->GetItemText(item);
+ if ( name == wxEmptyString ) continue;
+
+ filter.MakeLower();
+ name.MakeLower();
+
+ if ( (filter != wxEmptyString) && (!name.Contains(filter)) ) {
+ wxListItem listItem;
+ listItem.SetId(item);
+ m_user_list->GetItem(listItem);
+ int flag = listItem.GetImage();
+ name = m_user_list->GetItemText(item); // Preserve case
+ del.Add(name);
+ m_filtered_users.Add( name +_T(" ") + TowxString(flag) );
+ }
+
+ }
+
+ if ( del.Count() == (size_t)m_user_list->GetItemCount() ) {
+ m_user_list->DeleteAllItems();
+ } else {
+ for ( unsigned int i = 0; i < del.Count(); i++ ) {
+ long item = m_user_list->FindItem(-1, del[i]);
+ RemoveUserFromList(item);
+ }
+ }
+
+ wxSortedArrayString sel = GetSelection();
+
+ for ( int i = m_filtered_users.Count() - 1; i >= 0; i-- )
+ {
+ wxString line = m_filtered_users[i];
+ int sep = line.Find(' ');
+ wxString name = line.Mid(0, sep);
+ if ( name.Contains(filter) || (filter == wxEmptyString) ) {
+ int flag = (int)FromwxString<long>( line.Mid(sep+1) ); // Flag is never < 0 or > intmax
+ AddUserToList( name, flag );
+ m_filtered_users.RemoveAt(i);
+ }
+ }
+ Sort();
+
+ for ( unsigned int i = 0; i < sel.Count(); i++ ) {
+ long item = m_user_list->FindItem(-1, sel[i]);
+ if ( item != -1 )
+ m_user_list->SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
+ }
+
+}
+
+void SelectUsersDialog::OnNameActivated( wxListEvent& event )
+{
+ m_selection.Clear();
+ m_selection.Add(event.GetText());
+ EndModal(wxID_OK);
+}
+
+void SelectUsersDialog::OnNameDeselected( wxListEvent& event )
+{
+ m_selection.Remove(event.GetText());
+
+ wxSortedArrayString text = GetSelectionFromText();
+ text.Remove(event.GetText());
+
+ m_selection_text->SetValue(BuildSelectionText( text ));
+ UpdateSelection();
+}
+
+void SelectUsersDialog::OnNameSelected( wxListEvent& event )
+{
+ m_selection.Remove(event.GetText());
+ m_selection.Add(event.GetText());
+ UpdateSelection();
+}
+
+void SelectUsersDialog::OnCancel( wxCommandEvent& /*unused*/ )
+{
+ EndModal(wxID_CANCEL);
+}
+
+void SelectUsersDialog::OnOk( wxCommandEvent& /*unused*/ )
+{
+ EndModal(wxID_OK);
+}
+
+
+wxSortedArrayString SelectUsersDialog::GetSelection()
+{
+ return GetSelectionFromText();
+}
+
+int wxCALLBACK SelectUsersDialog::CompareName(long item1, long item2, long /*unused*/ )
+{
+ //wxListCtrl* user_list = (wxListCtrl*)sortData;
+ wxString* s1 = (wxString*)item1;
+ wxString* s2 = (wxString*)item2;
+ return (*s1).CmpNoCase(*s2);
+}
+
+void SelectUsersDialog::Sort()
+{
+ wxWindowUpdateLocker noUpdates(m_user_list);
+ m_user_list->SortItems(CompareName, (wxUIntPtr)m_user_list);
+}
diff --git a/src/selectusersdialog.h b/src/selectusersdialog.h
new file mode 100644
index 0000000..d44996e
--- /dev/null
+++ b/src/selectusersdialog.h
@@ -0,0 +1,94 @@
+
+#ifndef SPRINGLOBBY_HEADERGUARD_SELECTUSERSDIALOG_H
+#define SPRINGLOBBY_HEADERGUARD_SELECTUSERSDIALOG_H
+
+
+#include <wx/dialog.h>
+
+class wxPanel;
+class wxStaticText;
+class wxTextCtrl;
+class wxListCtrl;
+class wxStaticLine;
+class wxStdDialogButtonSizer;
+class wxButton;
+class wxListEvent;
+
+class SelectUsersDialog : public wxDialog
+{
+ DECLARE_EVENT_TABLE()
+
+ protected:
+ enum
+ {
+ FILTER_TEXT = 1000,
+ NICK_LIST,
+ NAME_TEXT,
+ };
+
+ wxPanel* m_users_panel;
+ wxStaticText* m_filter_names_staticText;
+ wxTextCtrl* m_name_filter_text;
+ wxListCtrl* m_user_list;
+ wxStaticText* m_name_staticText;
+ wxTextCtrl* m_selection_text;
+ wxStaticLine* m_buttons_hr;
+ wxStdDialogButtonSizer* m_dialog_buttons;
+ wxButton* m_dialog_buttonsOK;
+ wxButton* m_dialog_buttonsCancel;
+
+ void OnNameFilterChange( wxCommandEvent& event );
+ void OnNameActivated( wxListEvent& event );
+ void OnNameDeselected( wxListEvent& event );
+ void OnNameSelected( wxListEvent& event );
+ void OnCancel( wxCommandEvent& event );
+ void OnOk( wxCommandEvent& event );
+
+ wxSortedArrayString m_selection;
+ wxSortedArrayString m_filtered_users;
+
+ void Initialize();
+ void PopulateUsersList();
+ void ClearList();
+ void UpdateUsersList();
+ void UpdateSelection();
+ wxSortedArrayString GetSelectionFromText();
+ wxString BuildSelectionText( const wxSortedArrayString& sel );
+
+ long AddUserToList( const wxString& nick, const wxString& flag );
+ long AddUserToList( const wxString& nick, const int& flag );
+ void RemoveUserFromList( long item );
+
+ static int wxCALLBACK CompareName(long item1, long item2, long sortData );
+
+ void Sort();
+
+ public:
+ SelectUsersDialog( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Select Users"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 358,518 ), long style = wxDEFAULT_DIALOG_STYLE );
+ ~SelectUsersDialog();
+
+ static wxSortedArrayString GetUsers(wxWindow* parent = 0);
+
+ int ShowModal();
+ wxSortedArrayString GetSelection();
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_SELECTUSERSDIALOG_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/server.cpp b/src/server.cpp
new file mode 100644
index 0000000..03c8eb6
--- /dev/null
+++ b/src/server.cpp
@@ -0,0 +1,199 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: Server
+//
+
+#include <stdexcept>
+#include <wx/log.h>
+
+#include "server.h"
+#include "socket.h"
+#include "battle.h"
+#include "channel/channel.h"
+#include "user.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "chatpanel.h"
+
+Server::Server():
+battles_iter(new BattleList_Iter(&m_battles)),
+m_sock(0),
+m_keepalive(15)
+{
+ m_sock = new Socket( *this, false );
+}
+
+Server::~Server()
+{
+ delete battles_iter;
+ if(uidata.panel)uidata.panel->SetServer(NULL);
+ delete m_sock;
+}
+
+
+User& Server::GetUser( const wxString& nickname ) const
+{
+ return m_users.GetUser( nickname );
+}
+
+
+bool Server::UserExists( const wxString& nickname ) const
+{
+ return m_users.UserExists( nickname );
+}
+
+
+Channel& Server::GetChannel( const wxString& name )
+{
+ return m_channels.GetChannel( name );
+}
+
+
+int Server::GetNumChannels()
+{
+ return m_channels.GetNumChannels();
+}
+
+
+Channel& Server::GetChannel( const int& index )
+{
+ return m_channels.GetChannel( index );
+}
+
+
+bool Server::ChannelExists( const wxString& name )
+{
+ return m_channels.ChannelExists( name );
+}
+
+
+Battle& Server::GetBattle( const int& battleid )
+{
+ return battles_iter->GetBattle( battleid );
+}
+
+
+bool Server::BattleExists( const int& battleid )
+{
+ return battles_iter->BattleExists( battleid );
+}
+
+
+
+User& Server::_AddUser( const wxString& user )
+{
+ if ( m_users.UserExists( user ) ) return m_users.GetUser( user );
+ User* u = new User( user, *this );
+ m_users.AddUser( *u );
+ return *u;
+}
+
+
+void Server::_RemoveUser( const wxString& nickname )
+{
+ try{
+ User* u = &m_users.GetUser( nickname );
+ m_users.RemoveUser( nickname );
+ int numchannels = m_channels.GetNumChannels();
+ for ( int i = 0; i < numchannels; i++ )
+ {
+ Channel& chan = m_channels.GetChannel( i );
+ if ( chan.UserExists( nickname ) ) chan.Left( *u, _T("server idiocy") );
+ }
+ delete u;
+ }catch(std::runtime_error){
+ }
+}
+
+
+Channel& Server::_AddChannel( const wxString& chan )
+{
+ if ( m_channels.ChannelExists( chan ) ) return m_channels.GetChannel( chan );
+ Channel* c = new Channel( *this, ui() );
+ c->SetName( chan );
+
+ m_channels.AddChannel( *c );
+ return *c;
+}
+
+
+void Server::_RemoveChannel( const wxString& name )
+{
+ Channel* c = &m_channels.GetChannel( name );
+ m_channels.RemoveChannel( name );
+ ASSERT_LOGIC( c != 0, _T("Server::_RemoveChannel(\"") + name + _T("\"): GetChannel returned NULL pointer"));
+ delete c;
+}
+
+Battle& Server::_AddBattle( const int& id )
+{
+ if ( battles_iter->BattleExists( id ) ) return battles_iter->GetBattle( id );
+ Battle* b = new Battle( *this, id );
+
+ m_battles.AddBattle( *b );
+ return *b;
+}
+
+
+void Server::_RemoveBattle( const int& id )
+{
+ Battle* b = &battles_iter->GetBattle( id );
+ m_battles.RemoveBattle( id );
+ ASSERT_LOGIC( b != 0, _T("Server::_RemoveBattle(): GetBattle returned NULL pointer"));
+ delete b;
+}
+
+
+void Server::OnDisconnected()
+{
+ while ( battles_iter->GetNumBattles() > 0 )
+ {
+ battles_iter->IteratorBegin();
+ Battle* b = battles_iter->GetBattle();
+ if (b!=0)
+ {
+ m_battles.RemoveBattle( b->GetBattleId() );
+ delete b;
+ }
+ }
+ while ( m_users.GetNumUsers() > 0 )
+ {
+ try
+ {
+ User* u = &m_users.GetUser( 0 );
+ m_users.RemoveUser( u->GetNick() );
+ delete u;
+ }
+ catch(std::runtime_error)
+ {
+ }
+ }
+ while ( m_channels.GetNumChannels() > 0 )
+ {
+ Channel* c = &m_channels.GetChannel( 0 );
+ m_channels.RemoveChannel( c->GetName() );
+ delete c;
+ }
+
+}
+
+void Server::RequestSpringUpdate()
+{
+}
+
+wxArrayString Server::GetRelayHostList()
+{
+ wxArrayString ret;
+ for ( unsigned int i = 0; i < m_relay_host_manager_list.GetCount(); i++ )
+ {
+ try
+ {
+ User& manager = GetUser( m_relay_host_manager_list[i] );
+ if ( manager.Status().in_game ) continue; // skip the manager is not connected or reports it's ingame ( no slots available ), or it's away ( functionality disabled )
+ if ( manager.Status().away ) continue;
+ ret.Add( m_relay_host_manager_list[i] );
+ }
+ catch(...){}
+ }
+ return ret;
+}
diff --git a/src/server.h b/src/server.h
new file mode 100644
index 0000000..47a607a
--- /dev/null
+++ b/src/server.h
@@ -0,0 +1,237 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SERVER_H
+#define SPRINGLOBBY_HEADERGUARD_SERVER_H
+
+#include <wx/string.h>
+#include <wx/arrstr.h>
+
+#include "channel/channellist.h"
+#include "userlist.h"
+#include "battlelist.h"
+#include "inetclass.h"
+
+class ServerEvents;
+class Channel;
+class Ui;
+struct BattleOptions;
+class User;
+struct UserBattleStatus;
+class ChatPanel;
+class wxString;
+typedef int ServerError;
+class wxColour;
+
+
+typedef int HostInfo;
+
+
+//! @brief Abstract baseclass that is used to implement a server protocol.
+class Server : public iNetClass
+{
+ public:
+ friend class ServerEvents;
+
+ enum PortTestCode {
+ porttest_pass_WX26 = 0,
+ porttest_pass = 1,
+ porttest_timeout = 2,
+ porttest_socketNotOk = 3,
+ porttest_socketError = 4,
+ porttest_unreachable = 5
+ };
+
+ struct UiServerData {
+ UiServerData(): panel(0) {}
+ ChatPanel* panel;
+ };
+
+ UiServerData uidata;
+
+
+ Server();
+ virtual ~Server( );
+
+ // Server interface
+
+ virtual bool ExecuteSayCommand( const wxString& cmd ) = 0;
+
+ virtual bool Register( const wxString& addr, const int port, const wxString& nick, const wxString& password,wxString& reason ) = 0;
+ virtual void AcceptAgreement() = 0;
+
+ virtual void Connect( const wxString& servername, const wxString& addr, const int port ) = 0;
+ virtual void Disconnect() = 0;
+ virtual bool IsConnected() = 0;
+
+ virtual void Login() = 0;
+ virtual void Logout() = 0;
+ virtual bool IsOnline() const = 0;
+
+ virtual void Update( int mselapsed ) = 0;
+
+ virtual void JoinChannel( const wxString& channel, const wxString& key ) = 0;
+ virtual void PartChannel( const wxString& channel ) = 0;
+
+ virtual void DoActionChannel( const wxString& channel, const wxString& msg ) = 0;
+ virtual void SayChannel( const wxString& channel, const wxString& msg ) = 0;
+
+ virtual void SayPrivate( const wxString& nick, const wxString& msg ) = 0;
+ virtual void DoActionPrivate( const wxString& nick, const wxString& msg ) = 0;
+
+ virtual void SayBattle( int battleid, const wxString& msg ) = 0;
+ virtual void DoActionBattle( int battleid, const wxString& msg ) = 0;
+
+ virtual void Ring( const wxString& nick ) = 0;
+
+ virtual void ModeratorSetChannelTopic( const wxString& channel, const wxString& topic ) = 0;
+ virtual void ModeratorSetChannelKey( const wxString& channel, const wxString& key ) = 0;
+ virtual void ModeratorMute( const wxString& channel, const wxString& nick, int duration, bool byip ) = 0;
+ virtual void ModeratorUnmute( const wxString& channel, const wxString& nick ) = 0;
+ virtual void ModeratorKick( const wxString& channel, const wxString& reason ) = 0;
+ virtual void ModeratorBan( const wxString& nick, bool byip ) = 0;
+ virtual void ModeratorUnban( const wxString& nick ) = 0;
+ virtual void ModeratorGetIP( const wxString& nick ) = 0;
+ virtual void ModeratorGetLastLogin( const wxString& nick ) = 0;
+ virtual void ModeratorGetLastIP( const wxString& nick ) = 0;
+ virtual void ModeratorFindByIP( const wxString& ipadress ) = 0;
+
+ virtual void AdminGetAccountAccess( const wxString& nick ) = 0;
+ virtual void AdminChangeAccountAccess( const wxString& nick, const wxString& accesscode ) = 0;
+ virtual void AdminSetBotMode( const wxString& nick, bool isbot ) = 0;
+
+ virtual void HostBattle( BattleOptions bo, const wxString& password = _T("") ) = 0;
+ virtual void JoinBattle( const int& battleid, const wxString& password = _T("") ) = 0;
+ virtual void LeaveBattle( const int& battleid ) = 0;
+ virtual void StartHostedBattle() = 0;
+
+ virtual void ForceSide( int battleid, User& user, int side ) = 0;
+ virtual void ForceTeam( int battleid, User& user, int team ) = 0;
+ virtual void ForceAlly( int battleid, User& user, int ally ) = 0;
+ virtual void ForceColour( int battleid, User& user, const wxColour& col ) = 0;
+ virtual void ForceSpectator( int battleid, User& user, bool spectator ) = 0;
+ virtual void BattleKickPlayer( int battleid, User& user ) = 0;
+ virtual void SetHandicap( int battleid, User& user, int handicap) = 0;
+
+
+ virtual void AddBot( int battleid, const wxString& nick, UserBattleStatus& status ) = 0;
+ virtual void RemoveBot( int battleid, User& user ) = 0;
+ virtual void UpdateBot( int battleid, User& user, UserBattleStatus& status ) = 0;
+
+ virtual void SendHostInfo( HostInfo update ) = 0;
+ virtual void SendHostInfo( const wxString& Tag ) = 0;
+ virtual void SendRaw( const wxString& raw ) = 0;
+ virtual void SendUserPosition( const User& usr ) = 0;
+
+ virtual void RequestInGameTime( const wxString& nick ) = 0;
+
+ virtual Battle* GetCurrentBattle() = 0;
+
+ virtual void RequestChannels() = 0;
+
+ virtual void SendMyBattleStatus( UserBattleStatus& bs ) = 0;
+ virtual void SendMyUserStatus() = 0;
+
+ virtual void SetKeepaliveInterval( int seconds ) { m_keepalive = seconds; }
+ virtual int GetKeepaliveInterval() { return m_keepalive; }
+
+ virtual void SetUsername( const wxString& username ) { m_user = username; }
+ virtual void SetPassword( const wxString& password ) { m_pass = password; }
+ virtual bool IsPasswordHash( const wxString& pass ) const = 0;
+ virtual wxString GetPasswordHash( const wxString& pass ) const = 0;
+
+ wxString GetRequiredSpring() const { return m_required_spring_ver; }
+
+ void SetRequiredSpring( const wxString& version ) { m_required_spring_ver = version; }
+
+ virtual void Ping() = 0;
+
+ virtual void OnConnected( Socket* sock ) = 0;
+ virtual void OnDisconnected( Socket* sock ) = 0;
+ virtual void OnDataReceived( Socket* sock ) = 0;
+
+ virtual void OnDisconnected();
+
+ BattleList_Iter* const battles_iter;
+
+ virtual User& GetMe() const = 0;
+ User& GetUser( const wxString& nickname ) const;
+ bool UserExists( const wxString& nickname ) const;
+
+ Channel& GetChannel( const wxString& name );
+ int GetNumChannels();
+ Channel& GetChannel( const int& index );
+ bool ChannelExists( const wxString& name );
+
+ Battle& GetBattle( const int& battleid );
+ bool BattleExists( const int& battleid );
+
+ virtual int TestOpenPort( unsigned int port ) = 0;
+
+ virtual void SendScriptToProxy( const wxString& script ) = 0;
+
+ virtual void SendScriptToClients( const wxString& script ) = 0;
+
+ std::map<wxString,wxString> m_channel_pw; /// channel name -> password, filled on channel join
+
+ ///used to fill userlist in groupuserdialog
+ const UserList& GetUserList(){return m_users;}
+
+ wxString GetServerName() { return m_server_name; }
+
+ virtual void RequestSpringUpdate();
+
+ virtual wxArrayString GetRelayHostList();
+
+ protected:
+ Socket* m_sock;
+ int m_keepalive;
+ wxString m_user;
+ wxString m_pass;
+ wxString m_server_name;
+ bool m_pass_hash;
+ wxString m_required_spring_ver;
+
+ ChannelList m_channels;
+ UserList m_users;
+ BattleList m_battles;
+
+ wxString m_relay_host_bot;
+ wxString m_relay_host_manager;
+
+ wxArrayString m_relay_host_manager_list;
+
+ User& _AddUser( const wxString& user );
+ void _RemoveUser( const wxString& nickname );
+
+ Channel& _AddChannel( const wxString& chan );
+ void _RemoveChannel( const wxString& name );
+
+ Battle& _AddBattle( const int& id );
+ void _RemoveBattle( const int& id );
+
+ static const unsigned int PING_TIMEOUT = 40;
+
+ virtual void SendCmd( const wxString& command, const wxString& param ) = 0;
+ virtual void RelayCmd( const wxString& command, const wxString& param ) = 0;
+
+ private:
+ Server( const Server& );
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_SERVER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/serverevents.cpp b/src/serverevents.cpp
new file mode 100644
index 0000000..27a8e7b
--- /dev/null
+++ b/src/serverevents.cpp
@@ -0,0 +1,1025 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: ServerEvents
+//
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/intl.h>
+#include <stdexcept>
+
+#include "serverevents.h"
+#include "mainwindow.h"
+#include "ui.h"
+#include "channel/channel.h"
+#include "user.h"
+#include "utils/debug.h"
+#include "server.h"
+#include "battle.h"
+#include "httpdownloader.h"
+#include "settings.h"
+#include "utils/tasutil.h"
+#include "settings++/custom_dialogs.h"
+#ifndef NO_TORRENT_SYSTEM
+#include "torrentwrapper.h"
+#endif
+#include "globalsmanager.h"
+
+BEGIN_EVENT_TABLE(ServerEvents, wxEvtHandler)
+ EVT_COMMAND(wxID_ANY, httpDownloadEvtComplete, ServerEvents::OnSpringDownloadEvent)
+ EVT_COMMAND(wxID_ANY, httpDownloadEvtFailed, ServerEvents::OnSpringDownloadEvent)
+END_EVENT_TABLE()
+
+void ServerEvents::OnConnected( const wxString& server_name, const wxString& server_ver, bool supported, const wxString& server_spring_ver, bool /*unused*/ )
+{
+ wxLogDebugFunc( server_ver + _T(" ") + server_spring_ver );
+ m_serv.SetRequiredSpring( server_spring_ver );
+ ui().OnConnected( m_serv, server_name, server_ver, supported );
+ m_serv.Login();
+}
+
+
+void ServerEvents::OnDisconnected( bool wasonline )
+{
+ wxLogDebugFunc( _T("") );
+ m_serv.SetRequiredSpring (_T(""));
+ ui().OnDisconnected( m_serv, wasonline );
+#ifndef NO_TORRENT_SYSTEM
+ try // settings may be already destroyed
+ {
+ if ( sett().GetTorrentSystemAutoStartMode() == 0 ) torrent().DisconnectFromP2PSystem();
+ }
+ catch (GlobalDestroyedError e)
+ {
+ }
+#endif
+}
+
+
+void ServerEvents::OnLogin()
+{
+ wxString nick = m_serv.GetMe().GetNick();
+ wxArrayString highlights = sett().GetHighlightedWords();
+ if ( highlights.Index( nick ) == -1 )
+ {
+ highlights.Add( nick );
+ sett().SetHighlightedWords( highlights );
+ }
+}
+
+
+void ServerEvents::OnLoginInfoComplete()
+{
+ wxLogDebugFunc( _T("") );
+ //m_serv.RequestChannels();
+ std::vector<ChannelJoinInfo> autojoin = sett().GetChannelsJoin();
+ for ( std::vector<ChannelJoinInfo>::iterator itor = autojoin.begin(); itor != autojoin.end(); itor++ )
+ {
+ m_serv.JoinChannel( itor->name, itor->password );
+ }
+#ifndef NO_TORRENT_SYSTEM
+ if ( sett().GetTorrentSystemAutoStartMode() == 0 ) torrent().ConnectToP2PSystem();
+#endif
+ ui().OnLoggedIn( );
+}
+
+
+void ServerEvents::OnLogout()
+{
+ //wxLogDebugFunc( _T("") );
+}
+
+
+void ServerEvents::OnUnknownCommand( const wxString& command, const wxString& params )
+{
+ wxLogDebugFunc( _T("") );
+ ui().OnUnknownCommand( m_serv, command, params );
+}
+
+
+void ServerEvents::OnSocketError( const Sockerror& /*unused*/ )
+{
+ //wxLogDebugFunc( _T("") );
+}
+
+
+void ServerEvents::OnProtocolError( const Protocolerror /*unused*/ )
+{
+ //wxLogDebugFunc( _T("") );
+}
+
+
+void ServerEvents::OnMotd( const wxString& msg )
+{
+ wxLogDebugFunc( _T("") );
+ ui().OnMotd( m_serv, msg );
+}
+
+
+void ServerEvents::OnPong( wxLongLong ping_time )
+{
+ //wxLongLong is non-POD and cannot be passed to wxFormat as such. use c-string rep instead. converting to long might loose precision
+ ui().OnServerMessage( m_serv, wxString::Format( _("ping reply took %s ms"), ping_time.ToString().c_str() ) );
+}
+
+
+void ServerEvents::OnNewUser( const wxString& nick, const wxString& country, int cpu, const wxString& id )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( !m_serv.UserExists( nick ), _T("New user from server, but already exists!") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ User& user = m_serv._AddUser( nick );
+ if ( useractions().DoActionOnUser( UserActions::ActNotifLogin, nick ) )
+ actNotifBox( SL_MAIN_ICON, nick + _(" is online") );
+ user.SetCountry( country );
+ user.SetCpu( cpu );
+ user.SetID( id );
+ ui().OnUserOnline( user );
+}
+
+
+void ServerEvents::OnUserStatus( const wxString& nick, UserStatus status )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ wxLogMessage( _T("calling m_serv.GetUser( nick ) ") );
+ User& user = m_serv.GetUser( nick );
+ wxLogMessage( _T("calling user.SetStatus( status ) ") );
+
+ UserStatus oldStatus = user.GetStatus();
+ user.SetStatus( status );
+ if ( useractions().DoActionOnUser( UserActions::ActNotifStatus, nick ) )
+ {
+ wxString diffString = status.GetDiffString( oldStatus ) ;
+ if ( diffString != wxEmptyString )
+ actNotifBox( SL_MAIN_ICON, nick + _(" is now ") + diffString );
+ }
+
+ wxLogMessage( _T("calling ui().OnUserStatusChanged( user ) ") );
+ ui().OnUserStatusChanged( user );
+ wxLogMessage( _T("updating battles ") );
+
+ if ( user.GetBattle() != 0 )
+ {
+ Battle& battle = *user.GetBattle();
+ try
+ {
+ if ( battle.GetFounder().GetNick() == user.GetNick() )
+ {
+ if ( status.in_game != battle.GetInGame() )
+ {
+ battle.SetInGame( status.in_game );
+ if ( status.in_game ) battle.StartSpring();
+ else ui().OnBattleInfoUpdated( battle );
+ }
+ }
+ }catch(...){}
+ }
+ }
+ catch (...)
+ {
+ wxLogWarning( _("OnUserStatus() failed ! (exception)") );
+ }
+}
+
+
+void ServerEvents::OnUserQuit( const wxString& nick )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ User &user=m_serv.GetUser( nick );
+ Battle* userbattle = user.GetBattle();
+ if ( userbattle )
+ {
+ int battleid = userbattle->GetID();
+ try
+ {
+ if ( &userbattle->GetFounder() == &user )
+ {
+ for ( int i = 0; i < userbattle->GetNumUsers(); i ++ )
+ {
+ User& battleuser = userbattle->GetUser( i );
+ OnUserLeftBattle( battleid, battleuser.GetNick() );
+ }
+ OnBattleClosed( battleid );
+ }
+ else OnUserLeftBattle( battleid, user.GetNick() );
+ }catch(...){}
+ }
+ ui().OnUserOffline( user );
+ m_serv._RemoveUser( nick );
+ if ( useractions().DoActionOnUser( UserActions::ActNotifLogin, nick ) )
+ actNotifBox( SL_MAIN_ICON, nick + _(" just went offline") );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnBattleOpened( int id, BattleType type, NatType nat, const wxString& nick,
+ const wxString& host, int port, int maxplayers,
+ bool haspass, int rank, const wxString& maphash, const wxString& map,
+ const wxString& title, const wxString& mod )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_EXCEPTION( !m_serv.BattleExists( id ), _T("New battle from server, but already exists!") );
+ Battle& battle = m_serv._AddBattle( id );
+
+ User& user = m_serv.GetUser( nick );
+ battle.OnUserAdded( user );
+
+ battle.SetBattleType( type );
+ battle.SetNatType( nat );
+ battle.SetFounder( nick );
+ battle.SetHostIp( host );
+ battle.SetHostPort( port );
+ battle.SetMaxPlayers( maxplayers );
+ battle.SetIsPassworded( haspass );
+ battle.SetRankNeeded( rank );
+ battle.SetHostMap( map, maphash );
+ battle.SetDescription( title );
+ battle.SetHostMod( mod, wxEmptyString );
+
+ if ( useractions().DoActionOnUser( UserActions::ActNotifBattle, user.GetNick() ) )
+ actNotifBox( SL_MAIN_ICON, user.GetNick() + _(" opened battle ") + title );
+
+ ui().OnBattleOpened( battle );
+ if ( user.Status().in_game )
+ {
+ battle.SetInGame( true );
+ battle.StartSpring();
+ }
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnJoinedBattle( int battleid, const wxString& hash )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+
+ battle.SetHostMod( battle.GetHostModName(), hash );
+
+ UserBattleStatus& bs = m_serv.GetMe().BattleStatus();
+ bs.spectator = false;
+
+ if ( !battle.IsFounderMe() || battle.IsProxy() )
+ {
+ battle.CustomBattleOptions().loadOptions( OptionsWrapper::MapOption, battle.GetHostMapName() );
+ battle.CustomBattleOptions().loadOptions( OptionsWrapper::ModOption, battle.GetHostModName() );
+ }
+
+ ui().OnJoinedBattle( battle );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnHostedBattle( int battleid )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+
+ if ( battle.GetBattleType() == BT_Played )
+ {
+ battle.CustomBattleOptions().loadOptions( OptionsWrapper::MapOption, battle.GetHostMapName() );
+ battle.CustomBattleOptions().loadOptions( OptionsWrapper::ModOption, battle.GetHostModName() );
+ }
+ else
+ {
+ battle.GetBattleFromScript( true );
+ }
+
+
+ wxString presetname = sett().GetModDefaultPresetName( battle.GetHostModName() );
+ if ( !presetname.IsEmpty() )
+ {
+ battle.LoadOptionsPreset( presetname );
+ }
+
+ battle.LoadMapDefaults( battle.GetHostMapName() );
+
+ m_serv.SendHostInfo( IBattle::HI_Send_All_opts );
+
+ ui().OnHostedBattle( battle );
+ }
+ catch (assert_exception) {}
+}
+
+
+void ServerEvents::OnStartHostedBattle( int battleid )
+{
+ wxLogDebugFunc( _T("") );
+ Battle& battle = m_serv.GetBattle( battleid );
+ battle.SetInGame( true );
+ battle.StartSpring();
+}
+
+
+void ServerEvents::OnClientBattleStatus( int battleid, const wxString& nick, UserBattleStatus status )
+{
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ User& user = battle.GetUser( nick );
+
+ if ( battle.IsFounderMe() ) AutoCheckCommandSpam( battle, user );
+
+ status.color_index = user.BattleStatus().color_index;
+ battle.OnUserBattleStatusUpdated( user, status );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnUserJoinedBattle( int battleid, const wxString& nick )
+{
+ try
+ {
+ wxLogDebugFunc( _T("") );
+ User& user = m_serv.GetUser( nick );
+ Battle& battle = m_serv.GetBattle( battleid );
+
+ battle.OnUserAdded( user );
+ ui().OnUserJoinedBattle( battle, user );
+ try
+ {
+ if ( &user == &battle.GetFounder() )
+ {
+ if ( user.Status().in_game )
+ {
+ battle.SetInGame( true );
+ battle.StartSpring();
+ }
+ }
+ }catch(...){}
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnUserLeftBattle( int battleid, const wxString& nick )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ User& user = battle.GetUser( nick );
+ battle.OnUserRemoved( user );
+ ui().OnUserLeftBattle( battle, user );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+
+}
+
+
+void ServerEvents::OnBattleInfoUpdated( int battleid, int spectators, bool locked, const wxString& maphash, const wxString& map )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+
+ battle.SetSpectators( spectators );
+ battle.SetIsLocked( locked );
+
+ wxString oldmap = battle.GetHostMapName();
+
+ battle.SetHostMap( map, maphash );
+
+ if ( (oldmap != map) && (battle.UserExists( m_serv.GetMe().GetNick())) )
+ {
+ battle.SendMyBattleStatus();
+ battle.CustomBattleOptions().loadOptions( OptionsWrapper::MapOption, map );
+ battle.Update( wxString::Format( _T("%d_mapname"), OptionsWrapper::PrivateOptions ) );
+ }
+
+ ui().OnBattleInfoUpdated( battle );
+ }
+ catch (assert_exception) {}
+}
+
+void ServerEvents::OnSetBattleInfo( int battleid, const wxString& param, const wxString& value )
+{
+ wxLogDebugFunc( param + _T(", ") + value );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+
+ wxString key = param;
+ if ( key.Left( 5 ) == _T("game/") )
+ {
+ key = key.AfterFirst( '/' );
+ if ( key.Left( 11 ) == _T( "mapoptions/" ) )
+ {
+ key = key.AfterFirst( '/' );
+ battle.CustomBattleOptions().setSingleOption( key, value, OptionsWrapper::MapOption );
+ battle.Update( wxString::Format(_T("%d_%s"), OptionsWrapper::MapOption, key.c_str() ) );
+ }
+ else if ( key.Left( 11 ) == _T( "modoptions/" ) )
+ {
+ key = key.AfterFirst( '/' );
+ battle.CustomBattleOptions().setSingleOption( key, value, OptionsWrapper::ModOption );
+ battle.Update( wxString::Format(_T("%d_%s"), OptionsWrapper::ModOption, key.c_str() ) );
+ }
+ else if ( key.Left( 8 ) == _T( "restrict" ) )
+ {
+ OnBattleDisableUnit( battleid, key.AfterFirst(_T('/')), s2l(value) );
+ }
+ else if ( key.Left( 4 ) == _T( "team" ) && key.Contains( _T("startpos") ) )
+ {
+ int team = s2l( key.BeforeFirst(_T('/')).Mid( 4 ) );
+ if ( key.Contains( _T("startposx") ) )
+ {
+ int numusers = battle.GetNumUsers();
+ for ( int i = 0; i < numusers; i++ )
+ {
+ User& usr = battle.GetUser( i );
+ UserBattleStatus& status = usr.BattleStatus();
+ if ( status.team == team )
+ {
+ status.pos.x = s2l( value );
+ battle.OnUserBattleStatusUpdated( usr, status );
+ }
+ }
+ }
+ else if ( key.Contains( _T("startposy") ) )
+ {
+ int numusers = battle.GetNumUsers();
+ for ( int i = 0; i < numusers; i++ )
+ {
+ User& usr = battle.GetUser( i );
+ UserBattleStatus& status = usr.BattleStatus();
+ if ( status.team == team )
+ {
+ status.pos.y = s2l( value );
+ battle.OnUserBattleStatusUpdated( usr, status );
+ }
+ }
+ }
+ }
+ else
+ {
+ battle.CustomBattleOptions().setSingleOption( key, value, OptionsWrapper::EngineOption );
+ battle.Update( wxString::Format(_T("%d_%s"), OptionsWrapper::EngineOption, key.c_str() ) );
+ }
+ }
+ }
+ catch (assert_exception) {}
+}
+
+
+void ServerEvents::OnBattleInfoUpdated( int battleid )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ ui().OnBattleInfoUpdated( battle );
+ }
+ catch ( assert_exception ) {}
+}
+
+
+void ServerEvents::OnBattleClosed( int battleid )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+
+ ui().OnBattleClosed( battle );
+
+ m_serv._RemoveBattle( battleid );
+ }
+ catch ( assert_exception ) {}
+}
+
+
+void ServerEvents::OnBattleDisableUnit( int battleid, const wxString& unitname, int count )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ battle.RestrictUnit( unitname, count );
+ battle.Update( wxString::Format( _T("%d_restrictions"), OptionsWrapper::PrivateOptions ) );
+ }
+ catch ( assert_exception ) {}
+}
+
+
+void ServerEvents::OnBattleEnableUnit( int battleid, const wxString& unitname )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ battle.UnrestrictUnit( unitname );
+ battle.Update( wxString::Format( _T("%d_restrictions"), OptionsWrapper::PrivateOptions ) );
+ }
+ catch ( assert_exception ) {}
+}
+
+
+void ServerEvents::OnBattleEnableAllUnits( int battleid )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ battle.UnrestrictAllUnits();
+ battle.Update( wxString::Format( _T("%d_restrictions"), OptionsWrapper::PrivateOptions ) );
+ }
+ catch ( assert_exception ) {}
+}
+
+
+void ServerEvents::OnJoinChannelResult( bool success, const wxString& channel, const wxString& reason )
+{
+ wxLogDebugFunc( _T("") );
+ if ( success )
+ {
+
+ Channel& chan = m_serv._AddChannel( channel );
+ chan.SetPassword( m_serv.m_channel_pw[channel] );
+ ui().OnJoinedChannelSuccessful( chan );
+
+ }
+ else
+ {
+ ui().ShowMessage( _("Join channel failed"), _("Could not join channel ") + channel + _(" because: ") + reason );
+ }
+}
+
+
+void ServerEvents::OnChannelSaid( const wxString& channel, const wxString& who, const wxString& message )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ if ( ( m_serv.GetMe().GetNick() == who ) || !useractions().DoActionOnUser( UserActions::ActIgnoreChat, who ) )
+ m_serv.GetChannel( channel ).Said( m_serv.GetUser( who ), message );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnChannelJoin( const wxString& channel, const wxString& who )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ m_serv.GetChannel( channel ).OnChannelJoin( m_serv.GetUser( who ) );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnChannelPart( const wxString& channel, const wxString& who, const wxString& message )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ m_serv.GetChannel( channel ).Left( m_serv.GetUser( who ), message );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnChannelTopic( const wxString& channel, const wxString& who, const wxString& message, int /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ m_serv.GetChannel( channel ).SetTopic( message, who );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnChannelAction( const wxString& channel, const wxString& who, const wxString& action )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ m_serv.GetChannel( channel ).DidAction( m_serv.GetUser( who ), action );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnPrivateMessage( const wxString& user, const wxString& message, bool fromme )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ User& who = m_serv.GetUser( user );
+ if (!useractions().DoActionOnUser( UserActions::ActIgnorePM, who.GetNick() ) )
+ ui().OnUserSaid( who, message, fromme );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+void ServerEvents::OnChannelList( const wxString& channel, const int& numusers, const wxString& topic )
+{
+ ui().mw().OnChannelList( channel, numusers, topic );
+}
+
+
+void ServerEvents::OnUserJoinChannel( const wxString& channel, const wxString& who )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ m_serv.GetChannel( channel ).Joined( m_serv.GetUser( who ) );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnRequestBattleStatus( int battleid )
+{
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ ui().OnRequestBattleStatus( battle );
+ }
+ catch (assert_exception) {}
+}
+
+
+void ServerEvents::OnSaidBattle( int battleid, const wxString& nick, const wxString& msg )
+{
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ ui().OnSaidBattle( battle, nick, msg );
+ battle.GetAutoHost().OnSaidBattle( nick, msg );
+ }
+ catch (assert_exception) {}
+}
+
+void ServerEvents::OnBattleAction( int battleid, const wxString& nick, const wxString& msg )
+{
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ ui().OnBattleAction( battle, nick, msg );
+ }
+ catch (assert_exception) {}
+}
+
+
+void ServerEvents::OnBattleStartRectAdd( int battleid, int allyno, int left, int top, int right, int bottom )
+{
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ battle.AddStartRect( allyno, left, top, right, bottom );
+ battle.StartRectAdded( allyno );
+ battle.Update( wxString::Format( _T("%d_mapname"), OptionsWrapper::PrivateOptions ) );
+ }
+ catch (assert_exception) {}
+}
+
+
+void ServerEvents::OnBattleStartRectRemove( int battleid, int allyno )
+{
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ battle.RemoveStartRect( allyno );
+ battle.StartRectRemoved( allyno );
+ battle.Update( wxString::Format( _T("%d_mapname"), OptionsWrapper::PrivateOptions ) );
+ }
+ catch (assert_exception) {}
+}
+
+
+void ServerEvents::OnBattleAddBot( int battleid, const wxString& nick, UserBattleStatus status )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ battle.OnBotAdded( nick, status );
+ User& bot = battle.GetUser( nick );
+ ASSERT_LOGIC( &bot != 0, _T("Bot null after add.") );
+ ui().OnUserJoinedBattle( battle, bot );
+ }
+ catch (assert_exception) {}
+}
+
+void ServerEvents::OnBattleUpdateBot( int battleid, const wxString& nick, UserBattleStatus status )
+{
+ OnClientBattleStatus( battleid, nick, status );
+}
+
+
+void ServerEvents::OnBattleRemoveBot( int battleid, const wxString& nick )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ Battle& battle = m_serv.GetBattle( battleid );
+ User& user = battle.GetUser( nick );
+ ui().OnUserLeftBattle( battle, user );
+ battle.OnUserRemoved( user );
+ }
+ catch (std::runtime_error &except)
+ {
+ }
+}
+
+
+void ServerEvents::OnAcceptAgreement( const wxString& agreement )
+{
+ ui().OnAcceptAgreement( agreement );
+}
+
+
+void ServerEvents::OnRing( const wxString& from )
+{
+ ui().OnRing( from );
+}
+
+
+void ServerEvents::OnServerMessage( const wxString& message )
+{
+ ui().OnServerMessage( m_serv, message );
+}
+
+
+void ServerEvents::OnServerMessageBox( const wxString& message )
+{
+ ui().ShowMessage( _("Server Message"), message );
+}
+
+
+void ServerEvents::OnChannelMessage( const wxString& channel, const wxString& msg )
+{
+ ui().OnChannelMessage( channel, msg );
+}
+
+
+void ServerEvents::OnHostExternalUdpPort( const unsigned int udpport )
+{
+ if ( !m_serv.GetCurrentBattle() ) return;
+ if ( m_serv.GetCurrentBattle()->GetNatType() == NAT_Hole_punching || m_serv.GetCurrentBattle()->GetNatType() == NAT_Fixed_source_ports ) m_serv.GetCurrentBattle()->SetHostPort( udpport );
+}
+
+
+void ServerEvents::OnMyInternalUdpSourcePort( const unsigned int udpport )
+{
+ if ( !m_serv.GetCurrentBattle() ) return;
+ m_serv.GetCurrentBattle()->SetMyInternalUdpSourcePort(udpport);
+}
+
+
+void ServerEvents::OnMyExternalUdpSourcePort( const unsigned int udpport )
+{
+ if ( !m_serv.GetCurrentBattle() ) return;
+ m_serv.GetCurrentBattle()->SetMyExternalUdpSourcePort(udpport);
+}
+
+void ServerEvents::OnClientIPPort( const wxString &username, const wxString &ip, unsigned int udpport )
+{
+ wxLogMessage(_T("OnClientIPPort(%s,%s,%d)"),username.c_str(),ip.c_str(),udpport);
+ if ( !m_serv.GetCurrentBattle() )
+ {
+ wxLogMessage(_T("GetCurrentBattle() returned null"));
+ return;
+ }
+ try
+ {
+ User &user=m_serv.GetCurrentBattle()->GetUser( username );
+
+ user.BattleStatus().ip=ip;
+ user.BattleStatus().udpport=udpport;
+ wxLogMessage(_T("set to %s %d "),user.BattleStatus().ip.c_str(),user.BattleStatus().udpport);
+
+ if (sett().GetShowIPAddresses())ui().OnBattleAction(*m_serv.GetCurrentBattle(),username,wxString::Format(_(" has ip=%s"),ip.c_str()));
+
+ if (m_serv.GetCurrentBattle()->GetNatType() != NAT_None && (udpport==0))
+ {
+ // todo: better warning message
+ //something.OutputLine( _T(" ** ") + who.GetNick() + _(" does not support nat traversal! ") + GetChatTypeStr() + _T("."), sett().GetChatColorJoinPart(), sett().GetChatFont() );
+ ui().OnBattleAction(*m_serv.GetCurrentBattle(),username,_(" does not really support nat traversal"));
+ }
+ m_serv.GetCurrentBattle()->CheckBan(user);
+ }
+ catch (std::runtime_error)
+ {
+ wxLogMessage(_T("runtime_error inside OnClientIPPort()"));
+ }
+}
+
+
+void ServerEvents::OnKickedFromBattle()
+{
+ customMessageBoxNoModal(SL_MAIN_ICON,_("You were kicked from the battle!"),_("Kicked by Host"));
+}
+
+
+void ServerEvents::OnRedirect( const wxString& address, unsigned int port, const wxString& CurrentNick, const wxString& CurrentPassword )
+{
+ wxString name = address + _T(":") + TowxString(port);
+ sett().SetServer( name, address, port );
+ ui().DoConnect( name, CurrentNick, CurrentPassword );
+}
+
+
+void ServerEvents::AutoCheckCommandSpam( Battle& battle, User& user )
+{
+ wxString nick = user.GetNick();
+ MessageSpamCheck info = m_spam_check[nick];
+ time_t now = time( 0 );
+ if ( info.lastmessage == now ) info.count++;
+ else info.count = 0;
+ info.lastmessage = now;
+ m_spam_check[nick] = info;
+ if ( info.count == 7 )
+ {
+ battle.DoAction( _T("is autokicking ") + nick + _T(" due to command spam.") );
+ battle.KickPlayer( user );
+ }
+}
+
+void ServerEvents::OnMutelistBegin( const wxString& channel )
+{
+ mutelistWindow( _("Begin mutelist for ") + channel, wxString::Format( _("%s mutelist"), channel.c_str() ) );
+}
+
+void ServerEvents::OnMutelistItem( const wxString& /*unused*/, const wxString& mutee, const wxString& description )
+{
+ wxString message = mutee;
+ wxString desc = description;
+ wxString mutetime = GetWordParam( desc );
+ long time;
+ if ( mutetime == _T("indefinite") ) message << _(" indefinite time remaining");
+ else if ( mutetime.ToLong(&time) ) message << wxString::Format( _(" %d minutes remaining"), time/60 + 1 );
+ else message << mutetime;
+ if ( !desc.IsEmpty() ) message << _T(", ") << desc;
+ mutelistWindow( message );
+}
+
+void ServerEvents::OnMutelistEnd( const wxString& channel )
+{
+ mutelistWindow( _("End mutelist for ") + channel );
+}
+
+void ServerEvents::OnScriptStart( int battleid )
+{
+ if ( !m_serv.BattleExists( battleid ) )
+ {
+ return;
+ }
+ m_serv.GetBattle( battleid ).ClearScript();
+}
+
+void ServerEvents::OnScriptLine( int battleid, const wxString& line )
+{
+ if ( !m_serv.BattleExists( battleid ) )
+ {
+ return;
+ }
+ m_serv.GetBattle( battleid ).AppendScriptLine( line );
+}
+
+void ServerEvents::OnScriptEnd( int battleid )
+{
+ if ( !m_serv.BattleExists( battleid ) )
+ {
+ return;
+ }
+ m_serv.GetBattle( battleid ).GetBattleFromScript( true );
+}
+
+
+void ServerEvents::OnFileDownload( bool autolaunch, bool autoclose, bool disconnectonrefuse, const wxString& FileName, const wxString& url, const wxString& description )
+{
+ wxString refinedurl;
+ if ( url.Contains(_T("http://")) ) refinedurl = url.AfterFirst(_T('/')).AfterFirst(_T('/'));
+ else refinedurl = url;
+ bool result = ui().Ask( _("Download update"), wxString::Format( _("Would you like to download %s ? The file offers the following updates:\n\n%s\n\nThe download will be started in the background, you will be notified on operation completed."), url.c_str(), description.c_str() ) );
+ if ( result )
+ {
+ m_autoclose = autoclose;
+ m_autolaunch = autolaunch;
+ wxString filename;
+ if ( FileName != _T("*") ) filename = FileName;
+ else filename = _T("Spring installer.exe");
+ m_savepath = sett().GetCurrentUsedDataDir() + filename;
+ wxLogMessage(_T("downloading update in: %s, from: %s"),m_savepath.c_str(),refinedurl.c_str());
+ ui().OpenWebBrowser( url );
+ //new HttpDownloaderThread<ServerEvents>( refinedurl, m_savepath, *this, wxID_HIGHEST + 100, true, false );
+ }
+}
+void ServerEvents::OnSpringDownloadEvent( wxCommandEvent& event )
+{
+ int code = event.GetInt();
+ wxLogMessage(event.GetString());
+ if ( code != 0)
+ {
+ customMessageBox(SL_MAIN_ICON, _("There was an error downloading for the latest version.\n"), _("Error"));
+ wxString err;
+ switch (code)
+ {
+ case wxPROTO_NETERR:
+ err = _("Network Error");
+ break;
+ case wxPROTO_PROTERR:
+ err = _("Negotiation error");
+ break;
+ case wxPROTO_CONNERR:
+ err = _T("Failed to connect to server");
+ break;
+ case wxPROTO_INVVAL:
+ err = _("Invalid Value");
+ break;
+ case wxPROTO_NOHNDLR:
+ err = _("No Handler");
+ break;
+ case wxPROTO_NOFILE:
+ err = _("File doesn't exit");
+ break;
+ case wxPROTO_ABRT:
+ err = _("Action Aborted");
+ break;
+ case wxPROTO_RCNCT:
+ err = _("Reconnection Error");
+ break;
+ default:
+ err = _("Unknown Error");
+ break;
+ }
+
+ wxLogDebugFunc(_T("Error connecting! Error is: ") + err);
+ customMessageBoxNoModal(SL_MAIN_ICON, _T("Error connecting! (") + err + _T(")\nPlease update manually from http://springrts.com"), _T(""));
+
+ }
+ else
+ {
+ wxString text = _("Download complete, location is: ") + m_savepath;
+ if ( m_autoclose ) text += _("\nlobby will get closed now.");
+ customMessageBox(SL_MAIN_ICON, text, _("Download complete.") );
+ if ( m_autolaunch )
+ {
+ if ( !wxExecute( _T("\"") + m_savepath + _T("\""), wxEXEC_ASYNC ) )
+ {
+ customMessageBoxNoModal(SL_MAIN_ICON, _("Couldn't launch installer. File location is: ") + m_savepath, _("Couldn't launch installer.") );
+ }
+ }
+ if ( m_autoclose )
+ {
+ ui().mw().Close();
+ }
+
+ }
+}
diff --git a/src/serverevents.h b/src/serverevents.h
new file mode 100644
index 0000000..1067c23
--- /dev/null
+++ b/src/serverevents.h
@@ -0,0 +1,161 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SERVEREVENTS_H
+#define SPRINGLOBBY_HEADERGUARD_SERVEREVENTS_H
+
+//almost only needed for NAtType enum def
+#include "battle.h"
+#include <wx/event.h>
+#include <wx/longlong.h>
+
+class Ui;
+struct UserStatus;
+struct UserBattleStatus;
+class Server;
+
+// FIXME this is defined elsewhere, should use a different kind of type so we could use forward decl
+typedef int Sockerror;
+
+typedef int Protocolerror;
+
+struct MessageSpamCheck
+{
+ time_t lastmessage;
+ unsigned int count;
+};
+
+class Battle;
+
+//! @brief Class that implements server event behaviour.
+class ServerEvents : public wxEvtHandler
+{
+ public:
+ ServerEvents( Server& serv) : m_serv(serv) {}
+ ~ServerEvents() {}
+
+ // Uicontrol interface
+
+ void OnConnected( const wxString& server_name, const wxString& server_ver, bool supported, const wxString& server_spring_ver, bool lanmode );
+ void OnDisconnected( bool wasonline );
+
+ void OnLogin();
+ void OnLoginInfoComplete();
+ void OnLogout();
+
+ void OnUnknownCommand( const wxString& command, const wxString& params );
+ void OnSocketError( const Sockerror& error );
+ void OnProtocolError( const Protocolerror error );
+ void OnMotd( const wxString& msg );
+ void OnPong( wxLongLong ping_time );
+
+ void OnNewUser( const wxString& nick, const wxString& conutry, int cpu, const wxString& id );
+ void OnUserStatus( const wxString& nick, UserStatus status );
+ void OnUserQuit( const wxString& nick );
+
+ void OnBattleOpened( int id, BattleType type, NatType nat, const wxString& nick,
+ const wxString& host, int port, int maxplayers,
+ bool haspass, int rank, const wxString& maphash, const wxString& map,
+ const wxString& title, const wxString& mod );
+
+ void OnUserJoinedBattle( int battleid, const wxString& nick );
+ void OnUserLeftBattle( int battleid, const wxString& nick );
+ void OnBattleInfoUpdated( int battleid, int spectators, bool locked, const wxString& maphash, const wxString& map );
+ void OnSetBattleInfo( int battleid, const wxString& param, const wxString& value );
+ void OnBattleInfoUpdated( int battleid );
+ void OnBattleClosed( int battleid );
+
+ void OnJoinedBattle( int battleid, const wxString& hash );
+ void OnHostedBattle( int battleid );
+
+ void OnStartHostedBattle( int battleid );
+ void OnClientBattleStatus( int battleid, const wxString& nick, UserBattleStatus status );
+
+ void OnBattleStartRectAdd( int battleid, int allyno, int left, int top, int right, int bottom );
+ void OnBattleStartRectRemove( int battleid, int allyno );
+
+ void OnBattleAddBot( int battleid, const wxString& nick, UserBattleStatus status );
+ void OnBattleUpdateBot( int battleid, const wxString& nick, UserBattleStatus status );
+ void OnBattleRemoveBot( int battleid, const wxString& nick );
+
+ void OnBattleDisableUnit( int battleid, const wxString& unitname, int count = 0 );
+ void OnBattleEnableUnit( int battleid, const wxString& unitname );
+ void OnBattleEnableAllUnits( int battleid );
+
+ void OnJoinChannelResult( bool success, const wxString& channel, const wxString& reason );
+
+ void OnChannelSaid( const wxString& channel, const wxString& who, const wxString& message );
+ void OnChannelJoin( const wxString& channel, const wxString& who );
+ void OnChannelPart( const wxString& channel, const wxString& who, const wxString& message );
+ void OnChannelTopic( const wxString& channel, const wxString& who, const wxString& message, int when );
+ void OnChannelAction( const wxString& channel, const wxString& who, const wxString& action );
+ void OnChannelList( const wxString& channel, const int& numusers, const wxString& topic );
+ void OnUserJoinChannel( const wxString& channel, const wxString& who );
+
+ void OnPrivateMessage( const wxString& user, const wxString& message, bool fromme = false );
+
+ void OnRequestBattleStatus( int battleid );
+ void OnSaidBattle( int battleid, const wxString& nick, const wxString& msg );
+ void OnBattleAction( int battleid, const wxString& nick, const wxString& msg );
+
+ void OnAcceptAgreement( const wxString& agreement );
+
+ void OnRing( const wxString& from );
+
+ void OnServerMessage( const wxString& message );
+ void OnServerMessageBox( const wxString& message );
+ void OnChannelMessage( const wxString& channel, const wxString& msg );
+
+ void OnHostExternalUdpPort( const unsigned int udpport );
+
+ void OnMyExternalUdpSourcePort( const unsigned int udpport );
+ void OnMyInternalUdpSourcePort( const unsigned int udpport );
+
+ void OnClientIPPort( const wxString &username, const wxString &ip, unsigned int udpport );
+
+ void OnKickedFromBattle();
+
+ void OnRedirect( const wxString& address, unsigned int port, const wxString& CurrentNick, const wxString& CurrentPassword );
+
+ /// use this function to check spam from clients and autokick from the battle
+ void AutoCheckCommandSpam( Battle& battle, User& nick );
+
+ void OnMutelistBegin( const wxString& channel );
+ void OnMutelistItem( const wxString& channel, const wxString& mutee, const wxString& description );
+ void OnMutelistEnd( const wxString& channel );
+
+ void OnScriptStart( int battleid );
+ void OnScriptLine( int battleid, const wxString& line );
+ void OnScriptEnd( int battleid );
+
+ void OnFileDownload( bool autolaunch, bool autoclose, bool disconnectonrefuse, const wxString& FileName, const wxString& url, const wxString& description );
+ void OnSpringDownloadEvent( wxCommandEvent& event );
+
+ protected:
+ Server& m_serv;
+ std::map<wxString,MessageSpamCheck> m_spam_check;
+
+ DECLARE_EVENT_TABLE()
+
+ /// spring autoupdate stuff
+ bool m_autolaunch;
+ bool m_autoclose;
+ wxString m_savepath;
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_SERVEREVENTS_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/settings++/Defs.hpp b/src/settings++/Defs.hpp
new file mode 100644
index 0000000..f6d892a
--- /dev/null
+++ b/src/settings++/Defs.hpp
@@ -0,0 +1,544 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+// Autohost
+// LODScale=1.000
+// LODScaleReflection=1.000
+// LODScaleRefraction=1.000
+// LODScaleShadow=1.000
+// MapArchives=1 // multiple maps per archive?
+// MetalMapPalette=0
+//
+// FIXME: VSync Off=-1?
+
+
+
+#ifndef DEFS_HPP
+#define DEFS_HPP
+
+#define PWIN_SIZE_X 895
+#define PWIN_SIZE_Y 830
+#define CWIN_SIZE_X 580
+#define CWIN_SIZE_Y 360
+
+// ParentWin menu-item IDs
+#define ID_MENUITEM_SAVE 50
+#define ID_MENUITEM_RESET 51
+#define ID_MENUITEM_QUIT 52
+#define ID_MENUITEM_DISABLE_WARN 53
+#define ID_MENUITEM_MODE 60
+#define ID_MENUITEM_EXPERT 62
+#define ID_MENUITEM_SIMPLE 61
+
+#define ID_MENUITEM_HELP 70
+#define ID_MENUITEM_ABOUT 71
+#define ID_MENUITEM_CONTACT 72
+#define ID_MENUITEM_CREDITS 73
+#define ID_MENUITEM_BUGREPORT 74
+
+// ParentWin TextInput IDs
+#define ID_RES_CHOICES_LBOX_X 1111
+#define ID_RES_CHOICES_LBOX_Y 1112
+
+
+// ParentWin Rendering Options slider IDs
+#define ID_RO_SLI_0 100
+#define ID_RO_SLI_1 101
+#define ID_RO_SLI_2 102
+#define ID_RO_SLI_3 103
+#define ID_RO_SLI_4 104
+#define ID_RO_SLI_5 105
+#define ID_RO_SLI_6 106
+#define ID_RO_SLI_7 107
+#define ID_RO_SLI_8 108
+
+// ParentWin Video Options checkbox IDs
+#define ID_WINDOWP_VO_CBOX_0 250
+#define ID_WINDOWP_VO_CBOX_1 251
+#define ID_WINDOWP_VO_CBOX_2 252
+
+// ParentWin Video Options radiobutton IDs
+#define ID_WINDOWP_VO_RBUT_0 280
+#define ID_WINDOWP_VO_RBUT_1 281
+
+// ParentWin Video Options slider IDs
+#define ID_VO_SLI_0 200
+
+// tab_simple controls
+#define ID_SIMPLE_QUAL_CBX 390
+#define ID_SIMPLE_DETAIL_CBX 391
+#define ID_SIMPLE_MODE_CBX 392
+#define ID_SIMPLE_GOEXPERT_BUT 393
+
+
+// UI Options checkbox IDs
+#define ID_WINDOWP_UI_CBOX_1 360
+#define ID_WINDOWP_UI_CBOX_2 361
+#define ID_WINDOWP_UI_CBOX_3 362
+#define ID_WINDOWP_UI_CBOX_4 363
+#define ID_WINDOWP_UI_CBOX_5 364
+#define ID_WINDOWP_UI_CBOX_6 365
+#define ID_WINDOWP_UI_CBOX_7 366
+#define ID_WINDOWP_UI_CBOX_8 367
+#define ID_WINDOWP_UI_CBOX_9 368
+#define ID_WINDOWP_UI_CBOX_10 369
+#define ID_WINDOWP_UI_CBOX_11 370
+#define ID_WINDOWP_UI_CBOX_12 371
+#define ID_WINDOWP_UI_CBOX_13 372
+#define ID_WINDOWP_UI_CBOX_14 373
+#define ID_WINDOWP_UI_CBOX_15 374
+#define ID_WINDOWP_UI_CBOX_16 375
+#define ID_WINDOWP_UI_CBOX_17 376
+#define ID_WINDOWP_UI_CBOX_18 377
+
+//Zoom opt
+#define ID_WINDOWP_UI_MW_SPD 385
+
+//QUALITY OPTIONS checkbox IDs
+#define ID_WINDOWP_QA_CBOX_0 300
+#define ID_WINDOWP_QA_CBOX_1 301
+#define ID_WINDOWP_QA_CBOX_2 302
+#define ID_WINDOWP_QA_CBOX_3 303
+#define ID_WINDOWP_QA_CBOX_4 304
+#define ID_WINDOWP_QA_CBOX_5 305
+#define ID_WINDOWP_QA_CBOX_6 306
+#define ID_WINDOWP_QA_CBOX_7 307
+#define ID_WINDOWP_QA_CBOX_8 308
+#define ID_WINDOWP_QA_CBOX_9 309
+#define ID_WINDOWP_QA_CBOX_10 310
+#define ID_WINDOWP_QA_CBOX_11 311
+
+#define ID_WINDOWP_WR_COMBOX 320
+
+// ParentWin Audio Options slider IDs
+#define ID_AO_SLI_0 400
+#define ID_AO_SLI_1 401
+#define ID_AO_SLI_2 402
+#define ID_AO_SLI_3 403
+#define ID_AO_SLI_4 404
+#define ID_AO_SLI_5 405
+
+// ParentWin Debug Options checkbox IDs
+#define ID_WINDOWP_DO_CBOX_0 540
+
+
+// ParentWin Debug Options slider IDs
+#define ID_DO_SLI_0 500
+
+// ParentWin Water Rendering radiobutton IDs
+#define ID_WINDOWP_WR_RBUT_0 550
+#define ID_WINDOWP_WR_RBUT_1 551
+#define ID_WINDOWP_WR_RBUT_2 552
+#define ID_WINDOWP_WR_RBUT_3 553
+
+// ChildWin Mouse Options checkbox IDs
+#define ID_WINDOWC_MO_CBOX_0 650
+#define ID_WINDOWC_MO_CBOX_1 651
+
+// ChildWin Mouse Options radiobutton IDs
+#define ID_WINDOWC_MO_RBUT_0 680
+#define ID_WINDOWC_MO_RBUT_1 681
+#define ID_WINDOWC_MO_RBUT_2 682
+#define ID_WINDOWC_MO_RBUT_3 683
+#define ID_WINDOWC_MO_RBUT_4 684
+
+// ChildWin Mouse Options slider IDs
+#define ID_MO_SLI_0 660
+#define ID_MO_SLI_1 661
+#define ID_MO_SLI_2 662
+#define ID_MO_SLI_3 663
+#define ID_MO_SLI_4 664
+
+// panel_paths ids
+#define ID_PATH_USYNC_BTN 701
+#define ID_PATH_OK_BTN 702
+
+//water 4 specific options
+#define ID_W4_BumpWaterBlurReflection 720
+#define ID_W4_BumpWaterUseDepthTexture 721
+#define ID_W4_BumpWaterShoreWaves 722
+#define ID_W4_BumpWaterReflection 723
+#define ID_W4_BumpWaterTexSizeReflection 724
+#define ID_W4_BumpWaterRefraction 725
+#define ID_W4_BumpWaterAnisotropy 726
+
+#define SLI_STYLE (wxSL_LABELS )
+#define WX_DEF_V wxDefaultValidator
+#define WX_DEF_P wxPoint(-1, -1)
+#define WX_DEF_S wxSize(-1, -1)
+#define WX_SLI_S wxSize(200, -1)
+
+#define configHandler (susynclib())
+#define TAB_SIZE wxSize(700,500)
+#define UPDATE_W4_CONTROLS 2003
+#define UPDATE_VIDEO_MODE 2002
+#define UPDATE_QA_BOXES 2001
+#define UPDATE_ALL 2000
+#define UPDATE_EXPERTMODE_WARNING_ON_SIMPLETAB 2003
+
+//#include <wx/string.h>
+#include <wx/intl.h>
+//#include <string>
+#include <map>
+
+struct Control {
+ const wxString lbl;
+ const wxString key;
+ int id;
+ const wxString def; //default value for confighandler, not control
+ const wxString tTip [1];
+};
+
+const int Control_size = sizeof(Control);
+
+typedef std::map<const wxString,const int> category_sizes_map ;
+typedef category_sizes_map::value_type category_sizes_map_type;
+
+const Control UI_ZOOM[] = {
+ {_("Scrollwheel speed"), _T("ScrollWheelSpeed"), ID_WINDOWP_UI_MW_SPD, _T("25"),
+ {_("Higher values mean faster zoom with mouse wheel.\n"
+ "Negative values will invert zoom direction.\n"
+ "Results may vary depending on camera mode!")} }
+
+};
+
+const category_sizes_map_type UI_ZOOM_entry ( _T("UI_ZOOM"), sizeof(UI_ZOOM) / Control_size );
+
+//TODO is max_texture stages obsolte?
+const Control RO_SLI[] = {
+ {_("Shadow-map size"), _T("ShadowMapSize"), ID_RO_SLI_0, _T("2048"), {_("higher value = better looking shadows\n"
+ "possible values: 1024, 2048, 4096, 8192")} },
+ {_("Tree view-distance"), _T("TreeRadius"), ID_RO_SLI_1, _T("1000"), {_("sets the maximum distance at which trees will still be rendered")} },
+ {_("Terrain detail"), _T("GroundDetail"), ID_RO_SLI_2, _T("80"), {_("higher value = more terrain details")} },
+ {_("Unit LOD distance"), _T("UnitLodDist"), ID_RO_SLI_3, _T("300"), {_("higher value = units will remain detailed even when zooming out")} },
+ {_("Grass detail"), _T("GrassDetail"), ID_RO_SLI_4, _T("3"), {_("higher value = more detailed grass")} },
+ {_("Ground decals"), _T("GroundDecals"), ID_RO_SLI_5, _T("0"), {_("settings higher than 1 might have unwelcome side-effects / be very resource hungry")} },
+ {_("Unit icon distance"), _T("UnitIconDist"), ID_RO_SLI_6, _T("350"), {_("determines at which range units are still fully rendered\n"
+ "higher value = greater range = more units rendered at the same time")} },
+ {_("Max simultaneous particles"), _T("MaxParticles"), ID_RO_SLI_7, _T("4000") , {_("limits how many particles are displayed at the same time")}},
+ {_("Max nano simultaneous particles"), _T("MaxNanoParticles"), ID_RO_SLI_8, _T("10000") , {_("limits how many particles are displayed at the same time")}}
+ //{_("Max texture stages (SM3)"), _T("SM3MaxTextureStages"), ID_RO_SLI_8, "6" , {_("Decrease this if you are having bad perfomance on maps in sm3 format,\n"
+ // not needed atm "increase if sm3 maps look ugly.")}}
+};
+
+const category_sizes_map_type RO_SLI_entry ( _T("RO_SLI"), sizeof(RO_SLI) / Control_size );
+
+const Control VO_CBOX[] = {
+ {_("Run full-screen"), _T("Fullscreen"), ID_WINDOWP_VO_CBOX_0, _T("1"), {_("run fullscreen or in a window?")}},
+ {_("Dual-screen mode"), _T("DualScreenMode"), ID_WINDOWP_VO_CBOX_1, _T("0"), {_("if you have two monitors you can use both")}},
+ {_("Enable v-sync"), _T("VSync"), ID_WINDOWP_VO_CBOX_2, _T("0"), {_("V-Sync on/off")}}
+};
+
+const category_sizes_map_type VO_CBOX_entry ( _T("VO_BOX"), sizeof(VO_CBOX) / Control_size );
+
+const Control VO_RBUT[] = {
+ {_("16-bit Z-buffer"), _T("DepthBufferBits"), ID_WINDOWP_VO_RBUT_0, _T("24"), {_("placeholder")}},
+ {_("24-bit Z-buffer"), _T("DepthBufferBits"), ID_WINDOWP_VO_RBUT_1, _T("24"), {_("placeholder")}}
+};
+
+const category_sizes_map_type VO_RBUT_entry ( _T("VO_RBUT"), sizeof(VO_RBUT) / Control_size );
+
+
+const Control VO_SLI[] = {
+ {_("Full-scene anti-aliasing samples"), _T("FSAALevel"), ID_VO_SLI_0, _T("0"), {_("how much anti-aliasing should be applied")}}
+};
+
+const category_sizes_map_type VO_SLI_entry ( _T("VO_SLI"), sizeof(VO_SLI) / Control_size );
+
+const Control VO_SLI_EXT[] = {
+ {_(""), _T("FSAA"), -1, _T("0"), {_("")}}
+};
+
+const category_sizes_map_type VO_SLI_EXT_entry ( _T("VO_SLI_EXT"), sizeof(VO_SLI_EXT) / Control_size );
+
+const Control AO_SLI[] = {
+ {_("Maximum simultaneous sounds"), _T("MaxSounds"), ID_AO_SLI_0, _T("32") , {_("maximum different sounds played at the same time\n"
+ "Set this to zero to disable sound completely.")}},
+ {_("Master sound volume"), _T("snd_volmaster"), ID_AO_SLI_1, _T("60"), {_("master sound volume")}},
+ {_("General sound volume"), _T("snd_general"), ID_AO_SLI_2, _T("100"), {_("general volume relative to master volume")}},
+ {_("Unit reply volume"), _T("snd_volunitreply"), ID_AO_SLI_3, _T("100") , {_("reply volume relative to master volume")}},
+ {_("Battle volume"), _T("snd_volbattle"), ID_AO_SLI_4, _T("100") , {_("battle volume relative to global volume")}},
+ {_("User interface volume"), _T("snd_volui"), ID_AO_SLI_5, _T("100") , {_("ui volume relative to global volume")}}
+
+};
+
+const category_sizes_map_type AO_SLI_entry ( _T("AO_SLI"), sizeof(AO_SLI) / Control_size );
+
+const Control QA_CBOX[] = {
+ {_("Shadows (slow)"), _T("Shadows"), ID_WINDOWP_QA_CBOX_0, _T("0"), {_("enable shadows?")}},
+ {_("3D trees"), _T("3DTrees"), ID_WINDOWP_QA_CBOX_1, _T("1"), {_("want better looking trees?\n"
+ "needs Geforce 2/Radeon 8500/Intel 830 or later class graphic card")}},
+ {_("High-resolution clouds"), _T("AdvSky"), ID_WINDOWP_QA_CBOX_2, _T("0"), {_("want better looking sky?\n"
+ "needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card")}},
+ {_("Dynamic clouds (slow)"), _T("DynamicSky"), ID_WINDOWP_QA_CBOX_3, _T("0"), {_("want moving clouds in the sky?")}},
+ {_("Reflective units"), _T("AdvUnitShading"), ID_WINDOWP_QA_CBOX_4, _T("0"), {_("shiny units?\n"
+ "needs Geforce 5/Radeon 9500/Intel 915 or later class graphic card")}},
+ {_("Never use shaders when rendering SM3 maps"), _T("SM3ForceFallbackTex"), ID_WINDOWP_QA_CBOX_5, _T("0"), {_("problems with sm3 maps? enable this")}},
+ {_("Enable LuaShaders support"), _T("LuaShaders"), ID_WINDOWP_QA_CBOX_6, _T("1"), {_("makes for some cool effects")}},
+ {_("Use Pixelbuffer objects"), _T("UsePBO"), ID_WINDOWP_QA_CBOX_7, _T("0"), {_("If supported, it speeds up the dynamic loading of terrain textures -> smoother camera movement")}},
+ {_("Compress textures"), _T("CompressTextures"),ID_WINDOWP_QA_CBOX_8, _T("0"), {_("Runtime texture compression. (Ideal for graphic cards with small amount of vram)")}},
+ {_("High-resolution LOS textures"), _T("HighResLos"), ID_WINDOWP_QA_CBOX_9, _T("1"), {_("smoother Line of Sight overlays")}},
+ {_("Draw smooth points"), _T("SmoothPoints"), ID_WINDOWP_QA_CBOX_10, _T("0"), {_("should points be anti-aliased")}},
+ {_("Draw smooth lines"), _T("SmoothLines"), ID_WINDOWP_QA_CBOX_11, _T("0"), {_("should lines be anti-aliased")}},
+};
+
+const category_sizes_map_type QA_CBOX_entry ( _T("QA_CBOX"), sizeof(QA_CBOX) / Control_size );
+
+const Control UI_CBOX[] = {
+
+ {_("Issue commands on mini-map"), _T("MiniMapFullProxy"), ID_WINDOWP_UI_CBOX_2, _T("1"), {_("Issue orders on the mini-map like you would ")}},
+ {_("Show commands on mini-map"), _T("MiniMapDrawCommands"), ID_WINDOWP_UI_CBOX_3, _T("1"), {_("default value is \"on\"")}},
+ {_("Draw icons on mini-map"), _T("MiniMapIcons"), ID_WINDOWP_UI_CBOX_4, _T("1"), {_("default value is \"on\"")}},
+ {_("Draw markers on mini-map"), _T("MiniMapMarker"), ID_WINDOWP_UI_CBOX_5, _T("1"), {_("default value is \"on\"")}},
+ {_("Mini-map on left (single screen)"), _T("MinimapOnLeft"), ID_WINDOWP_UI_CBOX_6, _T("1"), {_("left is the default")}},
+ {_("Mini-map on left (dual screen)"), _T("DualScreenMiniMapOnLeft"), ID_WINDOWP_UI_CBOX_7,_T("1"), {_("left is the default")}},
+ {_("Simplified mini-map colors"), _T("SimpleMiniMapColors"), ID_WINDOWP_UI_CBOX_8, _T("0"), {_("Use less colors")}},
+
+ {_("Team-colored nanospray"), _T("TeamNanoSpray"), ID_WINDOWP_UI_CBOX_9, _T("0"),
+ {_("Should nano particels be the color of your team?")}},
+ {_("Colorized elevation map"), _T("ColorElev"), ID_WINDOWP_UI_CBOX_10, _T("1"), {_("makes differences in height clearer")}},
+
+ {_("Show in-game clock"), _T("ShowClock"), ID_WINDOWP_UI_CBOX_11, _T("0"),
+ {_("requires \"Enable LuaWidgets\" to be set.\nWill be displayed in the bottom right corner")}},
+ {_("Show in-game player information"), _T("ShowPlayerInfo"), ID_WINDOWP_UI_CBOX_12, _T("0"),
+ {_("requires \"Enable LuaWidgets\" to be set.\nWill be displayed in the bottom right corner")}},
+ {_("Show in-game framerate"), _T("ShowFPS"), ID_WINDOWP_UI_CBOX_13, _T("0"),
+ {_("requires \"Enable LuaWidgets\" to be set.\nWill be displayed in the bottom right corner")}},
+//TODO is there even a reason that it should be disabled?
+ {_("Fix rendering on alt-tab"), _T("FixAltTab"), ID_WINDOWP_UI_CBOX_14, _T("1"), {_("Do not change if not needed")}},
+ {_("Disallow helper AI's"), _T("NoHelperAIs"), ID_WINDOWP_UI_CBOX_15, _T("0"), {_("Disables Economy AI, etc.\n"
+ "If enabled might screw with LuaUi.")}},
+ {_("Enable scroll on window edge"), _T("WindowedEdgeMove"), ID_WINDOWP_UI_CBOX_16, _T("1"), {_("Scroll the screen when mouse reaches the screen's edge.")}},
+ {_("Invert Mouse"), _T("InvertMouse"), ID_WINDOWP_UI_CBOX_17, _T("0"), {_("Inverts the Mouse Y-axis in FPS mode")}},
+ {_("Use Hardware Cursor"), _T("HardwareCursor"), ID_WINDOWP_UI_CBOX_18, _T("0"), {_("Use native OS mouse cursor (hardware accelerated)")}},
+
+
+};
+
+const category_sizes_map_type UI_CBOX_entry ( _T("UI_CBOX"), sizeof(UI_CBOX) / Control_size );
+
+const Control MO_SLI[] = {
+ {_("Overhead camera"), _T("OverheadScrollSpeed"), ID_MO_SLI_0, _T("10"), {_("set the scroll speed (mouse + keyboard) for this mode")}},
+ {_("Rotatable overhead camera"), _T("RotOverheadScrollSpeed"), ID_MO_SLI_1, _T("10") , {_("set the scroll speed (mouse + keyboard) for this mode")}},
+ {_("Total war camera"), _T("TWScrollSpeed"), ID_MO_SLI_2, _T("10") , {_("set the scroll speed (mouse + keyboard) for this mode")}},
+ {_("First person camera"), _T("FPSScrollSpeed"), ID_MO_SLI_3, _T("10") , {_("set the scroll speed (mouse + keyboard) for this mode")}},
+ {_("Free camera"), _T("CamFreeScrollSpeed"), ID_MO_SLI_4, _T("100") , {_("set the scroll speed (mouse + keyboard) for this mode")}}
+};
+
+const category_sizes_map_type MO_SLI_entry ( _T("MO_SLI"), sizeof(MO_SLI) / Control_size );
+
+const Control MO_SLI_EXT[] = {
+ {_(""), _T("OverheadEnabled"), -1, _T("1"), {_("Make this the default view when startins Spring.\n"
+ "Can be changed ingame.")}},
+ {_(""), _T("RotOverheadEnabled"), -1, _T("1"), {_("Make this the default view when startins Spring.\n"
+ "Can be changed ingame.")}},
+ {_(""), _T("TWEnabled"), -1, _T("1"), {_("Make this the default view when startins Spring.\n"
+ "Can be changed ingame.")}},
+ {_(""), _T("FPSEnabled"), -1, _T("1"), {_("Make this the default view when startins Spring.\n"
+ "Can be changed ingame.")}},
+ {_(""), _T("CamFreeEnabled"), -1, _T("1"), {_("Make this the default view when startins Spring.\n"
+ "Can be changed ingame.")}},
+};
+
+const category_sizes_map_type MO_SLI_EXT_entry ( _T("MO_SLI_EXT"), sizeof(MO_SLI_EXT) / Control_size );
+
+const Control DO_SLI[] = {
+ {_("Console verbose level (0=min,10=max)"), _T("VerboseLevel"), ID_DO_SLI_0, _T("10"), {_("How much information should be outputted?")}}
+};
+
+const category_sizes_map_type DO_SLI_entry ( _T("DO_SLI"), sizeof(DO_SLI) / Control_size );
+
+const Control DO_CBOX[] = {
+ {_("Catch AI exceptions"), _T("CatchAIExceptions"), ID_WINDOWP_DO_CBOX_0, _T("1"), {_("disable for AI debugging")}}
+};
+
+const category_sizes_map_type DO_CBOX_entry ( _T("DO_CBOX"), sizeof(DO_CBOX) / Control_size );
+
+const Control WR_COMBOX[] = {
+ {_("Basic"), _T("ReflectiveWater"), ID_WINDOWP_WR_COMBOX, _T("1"), {_("Depending on the power of your graphics card,\n"
+ "selecting higher quality than basic can have a\n"
+ "major impact on Spring's performance.\n")}}
+ /*{_("reflective", "ReflectiveWater", ID_WINDOWP_WR_COMBOX_1, "1"},
+ {_("reflective + refractive", "ReflectiveWater", ID_WINDOWP_WR_COMBOX_2, "1"},
+ {_("dynamic", "ReflectiveWater", ID_WINDOWP_WR_COMBOX_3, "1"}*/
+};
+
+const category_sizes_map_type WR_COMBOX_entry ( _T("WR_COMBOX"), sizeof(WR_COMBOX) / Control_size );
+
+const wxString WR_COMBOX_CHOICES[] = {
+ _("Basic"), _("Reflective"), _("Reflective + refractive"), _("Dynamic"), _("Bump-mapped")
+};
+
+const Control MO_CBOX[] = {
+ {_("Invert mouse y-axis"), _T("InvertMouse"), ID_WINDOWC_MO_CBOX_0, _T("1"), {_("swap up/down with down/up")}},
+ {_("Mini-map 3-button mouse support"), _T("MiniMapFullProxy"), ID_WINDOWC_MO_CBOX_1, _T("1"), {_("if you don't want to able to use that button, disable it here")}}
+};
+
+const category_sizes_map_type MO_CBOX_entry ( _T("MO_CBOX"), sizeof(MO_CBOX) / Control_size );
+
+const Control MO_RBUT[] = {
+ {_("Overhead"), _T("CamMode"), ID_WINDOWC_MO_RBUT_0, _T("1"), {_("Static bird's eye view")}},
+ {_("Rotatable overhead"), _T("CamMode"), ID_WINDOWC_MO_RBUT_1, _T("1"), {_("Same as overhead, but you can rotate around the z-axis")}},
+ {_("Total war"), _T("CamMode"), ID_WINDOWC_MO_RBUT_2, _T("1"), {_("top-view camera, which can be tilted on the X axis")}},
+ {_("First person"), _T("CamMode"), ID_WINDOWC_MO_RBUT_3, _T("1"), {_("Camera from unit's point of view")}},
+ {_("Free camera"), _T("CamMode"), ID_WINDOWC_MO_RBUT_4, _T("1"), {_("Modify the view anyway you want")}}
+};
+
+const category_sizes_map_type MO_RBUT_entry ( _T("MO_RBUT"), sizeof(MO_RBUT) / Control_size );
+
+const Control RC_TEXT[] = {
+ {_(""), _T("XResolution"), -1, _T("1024"), {_("screen width")}},
+ {_(""), _T("YResolution"), -1, _T("768") , {_("screen height")}}
+};
+
+const category_sizes_map_type RC_TEXT_entry ( _T("RC_TEXT"), sizeof(RC_TEXT) / Control_size );
+
+
+const Control W4_CONTROLS[] = {
+ //booleans = checkboxes
+ {_("Blur reflection"), _T("BumpWaterBlurReflection"), ID_W4_BumpWaterBlurReflection , _T("1"), {_("")}},
+ {_("Use depth texture"), _T("BumpWaterUseDepthTexture"), ID_W4_BumpWaterUseDepthTexture , _T("1"), {_("enables smoother blending on coastlines")}},
+ {_("Shore waves"), _T("BumpWaterShoreWaves"), ID_W4_BumpWaterShoreWaves , _T("0"), {_("Enables shorewaves")}},
+ {_("Reflection"), _T("BumpWaterReflection"), ID_W4_BumpWaterReflection , _T("1"), {_("Turn on water reflections")}},
+ // select boxes
+ {_("Reflection texture size"), _T("BumpWaterTexSizeReflection"), ID_W4_BumpWaterTexSizeReflection , _T("128"), {_("")}},
+ {_("Refraction"), _T("BumpWaterRefraction"), ID_W4_BumpWaterRefraction , _T("1"), {_("Turn on water refractions.\n(0:=off, 1:=screencopy(fast), 2:=own rendering pass(slow)).")}},
+ // spin control
+ {_("Anisotropy"), _T("BumpWaterAnisotropy"), ID_W4_BumpWaterAnisotropy , _T("0"), {_("")}},
+ // {_(""), _T(""), ID_W4_ , _T(""), {_("")}},
+ // {_(""), _T(""), ID_W4_ , _T(""), {_("")}},
+ // {_(""), _T(""), ID_W4_ , _T(""), {_("")}},
+ // {_(""), _T(""), ID_W4_ , _T(""), {_("")}},
+
+};
+
+const wxString W4_REFRACTION_CHOICES[] = { _("off"), _("screencopy(fast)"), _("own rendering pass(slow)") };
+const wxString W4_TEXSIZE_CHOICES[] = { _("128"), _("256"), _("512"), _T("1024") };
+
+const category_sizes_map_type W4_CONTROLS_entry ( _T("W4_CONTROLS"), sizeof(W4_CONTROLS) / Control_size );
+
+const category_sizes_map_type entries_[] = { RC_TEXT_entry, MO_RBUT_entry, MO_CBOX_entry, WR_COMBOX_entry, DO_CBOX_entry, DO_SLI_entry, MO_SLI_EXT_entry,
+ MO_SLI_entry, UI_CBOX_entry, QA_CBOX_entry, AO_SLI_entry, AO_SLI_entry, VO_SLI_EXT_entry, VO_SLI_entry,
+ VO_RBUT_entry, VO_CBOX_entry, RO_SLI_entry, UI_ZOOM_entry, W4_CONTROLS_entry};
+
+static category_sizes_map s_category_sizes ( entries_ , entries_ + sizeof(entries_) / sizeof(entries_[0]) );
+
+
+/** not used
+#define NUM_DEFAULTS 88
+const char DEFAULTS[NUM_DEFAULTS][64] = {
+ "3DTrees=1",
+ "AdvSky=0",
+ "AdvUnitShading=0",
+ "FSAA=0",
+ "FSAALevel=0",
+ "ReflectiveWater=1",
+ "MaxParticles=20000",
+ "DynamicSky=0",
+ "DepthBufferBits=16",
+ "StencilBufferBits=1",
+ "GrassDetail=10",
+ "GroundDecals=100",
+ "GroundDetail=120",
+ "Shadows=0",
+ "ShadowMapSize=2048",
+ "SM3MaxTextureStages=20",
+ "SM3ForceFallbackTex=1",
+ "TreeRadius=3000",
+ "UnitIconDist=1000",
+ "UnitLodDist=600",
+ "VSync=1",
+ "XResolution=1024",
+ "YResolution=768",
+
+ "BuildIconsFirst=0",
+ "ColorElev=1",
+ "DualScreenMode=0",
+ "FixAltTab=1",
+ "Fullscreen=0",
+ "HighResLos=1",
+ "NoHelperAIs=0",
+ "TeamNanoSpray=1",
+ "SmoothLines=0",
+ "SmoothPoints=0",
+ "ShowClock=1",
+ "ShowPlayerInfo=1",
+ "ShowFPS=0",
+
+ "StdoutDebug=0",
+ "CatchAIExceptions=0",
+ "VerboseLevel=0",
+
+ "CamMode=1",
+ "CamTimeExponent=4.0",
+ "CamTimeFactor=1.0",
+ "DoubleClickTime=200",
+
+ "FontCharFirst=32",
+ "FontCharLast=223",
+ "FontFile=Luxi.ttf",
+
+ "InfoConsoleGeometry=0.25 0.95 0.40 0.20",
+ "TooltipGeometry=0.00 0.00 0.40 0.1",
+ "TooltipOutlineFont=0",
+ "InfoMessageTime=400",
+ "InvertMouse=1",
+ "InvertQueueKey=0",
+ "WindowedEdgeMove=1",
+
+ "LuaGaia=1",
+ "LuaRules=1",
+ "LuaShaders=1",
+ "LuaUI=1",
+
+ "MapArchives=1",
+ "MetalMapPalette=0",
+
+ "MiniMapButtonSize=16",
+ "MiniMapCursorScale=-0.5",
+ "MiniMapDrawCommands=1",
+ "MiniMapFullProxy=1",
+ "MiniMapGeometry=2 2 200 200",
+ "MiniMapIcons=1",
+ "MiniMapMarker=1",
+ "MiniMapUnitExp=0.25",
+ "MiniMapUnitSize=2.5",
+ "MinimapOnLeft=1",
+ "DualScreenMiniMapOnLeft=1",
+ "SimpleMiniMapColors=0",
+
+ "OverheadEnabled=1",
+ "OverheadScrollSpeed=10",
+ "RotOverheadEnabled=0",
+ "RotOverheadScrollSpeed=0",
+ "RotOverheadMouseScale=0.002",
+ "TWEnabled=0",
+ "TWScrollSpeed=0",
+ "FPSEnabled=0",
+ "FPSScrollSpeed=0",
+ "FPSMouseScale=0.002",
+ "CamFreeEnabled=0",
+ "CamFreeScrollSpeed=0",
+ "ScrollWheelSpeed=25",
+
+ "MaxSounds=16",
+ "SoundVolume=100",
+ "UnitReplySoundVolume=80"
+};
+**/
+
+#endif
diff --git a/src/settings++/Main.cpp b/src/settings++/Main.cpp
new file mode 100644
index 0000000..841a2c4
--- /dev/null
+++ b/src/settings++/Main.cpp
@@ -0,0 +1,137 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+#include "main.h"
+#include "frame.h"
+
+#include "../crashreport.h"
+#include "../utils/conversion.h"
+#include "../utils/platform.h"
+#include "../settings.h"
+#include "se_utils.h"
+
+#include <iostream>
+#include <wx/msgdlg.h>
+#include <wx/intl.h>
+#include <wx/log.h>
+#include <wx/cmdline.h>
+#include <wx/frame.h>
+
+#include "../springunitsynclib.h"
+
+IMPLEMENT_APP(Springsettings)
+
+Springsettings::Springsettings()
+ : m_log_verbosity( 3 ),
+ m_log_console( true ),
+ m_log_window_show( false ),
+ m_crash_handle_disable( false )
+{
+ SetAppName( _T("springsettings") );
+}
+
+bool Springsettings::OnInit()
+{
+ //this triggers the Cli Parser amongst other stuff
+ if (!wxApp::OnInit())
+ return false;
+
+ #if wxUSE_ON_FATAL_EXCEPTION
+ if (!m_crash_handle_disable) wxHandleFatalExceptions( true );
+ #endif
+
+ //initialize all loggers
+ //TODO non-constant parameters
+ wxLogChain* logchain = 0;
+ wxLogWindow* loggerwin = InitializeLoggingTargets( 0, m_log_console, m_log_window_show, !m_crash_handle_disable, m_log_verbosity, logchain );
+
+ SetSettingsStandAlone( true );
+ settings_frame* frame = new settings_frame(NULL,wxID_ANY,wxT("SpringSettings"),wxDefaultPosition,
+ wxDefaultSize);
+ SetTopWindow(frame);
+ frame->Show();
+
+ if ( loggerwin ) { // we got a logwindow, lets set proper parent win
+ loggerwin->GetFrame()->SetParent( frame );
+ }
+
+ return true;
+}
+
+int Springsettings::OnExit()
+{
+ susynclib().Unload();
+ return 0;
+}
+
+//! @brief is called when the app crashes
+void Springsettings::OnFatalException()
+{
+ #if wxUSE_DEBUGREPORT && defined(HAVE_WX28) && defined(ENABLE_DEBUG_REPORT)
+ crashreport().GenerateReport(wxDebugReport::Context_Exception);
+ #else
+ wxMessageBox( _("The application has generated a fatal error and will be terminated\nGenerating a bug report is not possible\n\nplease enable wxUSE_DEBUGREPORT"),_("Critical error"), wxICON_ERROR );
+ #endif
+}
+
+void Springsettings::OnInitCmdLine(wxCmdLineParser& parser)
+{
+ wxCmdLineEntryDesc cmdLineDesc[] =
+ {
+ { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _("show this help message"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
+ { wxCMD_LINE_SWITCH, _T("nc"), _T("no-crash-handler"), _("don't use the crash handler (useful for debugging)"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+ { wxCMD_LINE_SWITCH, _T("cl"), _T("console-logging"), _("shows application log to the console(if available)"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+ { wxCMD_LINE_SWITCH, _T("gl"), _T("gui-logging"), _("enables application log window"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+ { wxCMD_LINE_OPTION, _T("l"), _T("log-verbosity"), _("overrides default logging verbosity, can be:\n 0: no log\n 1: critical errors\n 2: errors\n 3: warnings (default)\n 4: messages\n 5: function trace"), wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL },
+ { wxCMD_LINE_NONE }
+
+ };
+
+ parser.SetDesc( cmdLineDesc );
+ parser.SetSwitchChars (wxT("-"));
+}
+
+//! @brief parses the command line and sets global app options like log verbosity or log target
+bool Springsettings::OnCmdLineParsed(wxCmdLineParser& parser)
+{
+ #if wxUSE_CMDLINE_PARSER
+ if ( !parser.Parse(true) )
+ {
+ m_log_console = parser.Found(_T("console-logging"));
+ m_log_window_show = parser.Found(_T("gui-logging"));
+ m_crash_handle_disable = parser.Found(_T("no-crash-handler"));
+
+ if ( !parser.Found(_T("log-verbosity"), &m_log_verbosity ) )
+ m_log_verbosity = 3;
+
+ if ( parser.Found(_T("help")) )
+ return false; // not a syntax error, but program should stop if user asked for command line usage
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ #else // wxUSE_CMDLINE_PARSER
+ return true;
+ #endif
+}
diff --git a/src/settings++/custom_dialogs.cpp b/src/settings++/custom_dialogs.cpp
new file mode 100644
index 0000000..0e46fdc
--- /dev/null
+++ b/src/settings++/custom_dialogs.cpp
@@ -0,0 +1,437 @@
+#include "custom_dialogs.h"
+
+#include <wx/icon.h>
+#include <wx/string.h>
+#include <wx/frame.h>
+#include <wx/defs.h>
+#include <wx/textctrl.h>
+#include <wx/sizer.h>
+#include <wx/button.h>
+#include <wx/font.h>
+#include <wx/event.h>
+#include <wx/stattext.h>
+#include <wx/artprov.h>
+#include <wx/statbmp.h>
+#include <wx/listctrl.h>
+#include <wx/dialog.h>
+#include <wx/choicdlg.h>
+
+
+#include "../images/springsettings.xpm"
+#include "../images/springlobby.xpm"
+#include "../utils/conversion.h"
+
+BEGIN_EVENT_TABLE(CustomMessageBox ,wxDialog)
+ EVT_BUTTON(wxID_NO, CustomMessageBox::OnOptionsNo)
+END_EVENT_TABLE()
+
+wxWindow* CustomMessageBoxBase::m_settingsWindow = 0;
+wxWindow* CustomMessageBoxBase::m_lobbyWindow = 0;
+static CustomMessageBox* s_nonmodbox = 0;
+static ServerMessageBox* s_serverMsgBox = 0;
+static ActNotifBox* s_actNotifBox = 0;
+static MutelistWindow* s_mutelistWindow = 0;
+
+CustomMessageBox::CustomMessageBox(wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption ,
+ long style, const wxPoint& pos )
+ : wxDialog(parent,-1,caption,pos,wxDefaultSize,style|wxFRAME_FLOAT_ON_PARENT|wxDEFAULT_DIALOG_STYLE)
+{
+ SetIcon(*icon);
+
+//******** copied from wxsource/generic/msgdlgg.cpp with small modifications***********************************************************
+
+
+ wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer *icon_text = new wxBoxSizer( wxHORIZONTAL );
+
+
+ // 1) icon
+
+ wxBitmap bitmap;
+ switch ( style & wxICON_MASK )
+ {
+ default:
+ bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX);
+ break;
+
+ case wxICON_ERROR:
+ bitmap = wxArtProvider::GetIcon(wxART_ERROR, wxART_MESSAGE_BOX);
+ break;
+
+ case wxICON_INFORMATION:
+ bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX);
+ break;
+
+ case wxICON_WARNING:
+ bitmap = wxArtProvider::GetIcon(wxART_WARNING, wxART_MESSAGE_BOX);
+ break;
+
+ case wxICON_QUESTION:
+ bitmap = wxArtProvider::GetIcon(wxART_QUESTION, wxART_MESSAGE_BOX);
+ break;
+ }
+
+ wxStaticBitmap *info_icon = new wxStaticBitmap(this, wxID_ANY, bitmap);
+ icon_text->Add( info_icon, 0, wxCENTER );
+
+ // 2) text
+ icon_text->Add( CreateTextSizer( message ), 0, wxALIGN_TOP| wxLEFT, 10 );
+
+ topsizer->Add( icon_text, 1, wxCENTER | wxLEFT|wxRIGHT|wxTOP, 10 );
+ topsizer->Add(0,10);
+
+ // 3) buttons
+ int center_flag = wxEXPAND;
+ if (style & wxYES_NO)
+ center_flag = wxALIGN_CENTRE;
+ wxSizer *sizerBtn = CreateButtonSizer(style & ButtonSizerFlags);
+ if ( sizerBtn )
+ topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10 );
+
+
+ SetAutoLayout( true );
+ SetSizer( topsizer );
+
+ topsizer->SetSizeHints( this );
+ topsizer->Fit( this );
+ /*
+ wxSize size( GetSize() );
+ if (size.x > size.y*3/2)
+ {
+ size.x = size.y*3/2;
+ SetSize( size );
+ }
+ */
+ Centre( wxBOTH | wxCENTER_FRAME);
+/***************************************************************************************************/
+}
+
+CustomMessageBox::~CustomMessageBox()
+{
+}
+
+
+void CustomMessageBox::OnOptionsNo(wxCommandEvent& /*unused*/)
+{
+ EndModal(wxID_NO);
+}
+
+void CustomMessageBoxBase::setLobbypointer(wxWindow* arg)
+{
+ m_lobbyWindow = arg;
+}
+
+ void CustomMessageBoxBase::setSettingspointer(wxWindow* arg)
+{
+ m_settingsWindow = arg;
+}
+
+ wxWindow* CustomMessageBoxBase::getLobbypointer()
+{
+// if (m_lobbyWindow==0)
+// wxLogWarning(_T("null parent window in custom message dialog"));
+ return m_lobbyWindow;
+}
+
+ wxWindow* CustomMessageBoxBase::getSettingspointer()
+{
+// if (m_settingsWindow==0)
+// wxLogWarning(_T("null parent window in custom message dialog"));
+ return m_settingsWindow;
+}
+
+int customMessageBox( int whichIcon , const wxString& message,const wxString& caption,
+ long style , int x, int y )
+{
+ wxWindow* parent;
+ wxIcon* icon;
+ switch (whichIcon)
+ {
+ case SL_MAIN_ICON:
+ icon = new wxIcon(springlobby_xpm);
+ parent = CustomMessageBoxBase::getLobbypointer();
+ break;
+ case SS_MAIN_ICON:
+ icon = new wxIcon(springsettings_xpm);
+ parent = CustomMessageBoxBase::getSettingspointer();
+ break;
+ default:
+ icon = new wxIcon(wxNullIcon);
+ parent = 0;
+ break;
+
+ }
+ CustomMessageBox dlg(icon,parent,message,caption,style,wxPoint(x,y));
+ int re = dlg.ShowModal();
+ switch (re)
+ {
+ case wxID_OK: return wxOK;
+ case wxID_CANCEL: return wxCANCEL;
+ case wxID_YES: return wxYES;
+ case wxID_NO: return wxNO;
+ default: return -1;
+ }
+}
+
+void customMessageBoxNoModal( int whichIcon , const wxString& message,const wxString& caption,
+ long style , int x, int y )
+{
+ wxWindow* parent;
+ wxIcon* icon;
+ switch (whichIcon)
+ {
+ case SL_MAIN_ICON:
+ icon = new wxIcon(springlobby_xpm);
+ parent = CustomMessageBoxBase::getLobbypointer();
+ break;
+ case SS_MAIN_ICON:
+ icon = new wxIcon(springsettings_xpm);
+ parent = CustomMessageBoxBase::getSettingspointer();
+ break;
+ default:
+ icon = new wxIcon(wxNullIcon);
+ parent = 0;
+ break;
+
+ }
+ s_nonmodbox = new CustomMessageBox (icon,parent,message,caption,style,wxPoint(x,y));
+
+ s_nonmodbox->Show(true);
+}
+
+void freeStaticBox()
+{
+ if (s_nonmodbox!=0)
+ {
+ s_nonmodbox->Show(false);
+ s_nonmodbox->Destroy();
+ s_nonmodbox = 0;
+ }
+ if (s_serverMsgBox!=0)
+ {
+ s_serverMsgBox->Show(false);
+ s_serverMsgBox->Destroy();
+ s_serverMsgBox = 0;
+ }
+ if (s_actNotifBox!=0)
+ {
+ s_actNotifBox->Show(false);
+ s_actNotifBox->Destroy();
+ s_actNotifBox = 0;
+ }
+
+}
+
+CreditsDialog::CreditsDialog(wxWindow* parent,wxString title,int whichIcon) : wxDialog(parent,-1,title,wxDefaultPosition,
+ wxDefaultSize,wxDEFAULT_DIALOG_STYLE|wxFRAME_FLOAT_ON_PARENT)
+{
+ wxBoxSizer* container = new wxBoxSizer(wxVERTICAL);
+ text_ctrl = new wxTextCtrl(this,-1,wxT(""),wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH);
+ container->Add(text_ctrl,1,wxEXPAND);
+
+ container->Add(wxDialog::CreateButtonSizer(wxOK));
+ SetSizer(container);
+ wxIcon* icon;
+ switch (whichIcon)
+ {
+ case SL_MAIN_ICON:
+ icon = new wxIcon(springlobby_xpm);
+ break;
+ case SS_MAIN_ICON:
+ icon = new wxIcon(springsettings_xpm);
+ break;
+ default:
+ icon = new wxIcon(wxNullIcon);
+ break;
+
+ }
+ SetIcon(*icon);
+}
+
+void CreditsDialog::AddCredit(wxString person,wxString message)
+{
+ wxFont* heavyFont = new wxFont(10, wxDEFAULT, wxNORMAL, wxBOLD);
+ text_ctrl->SetDefaultStyle(wxTextAttr(wxNullColour,wxNullColour,*heavyFont));
+ text_ctrl->AppendText(person + _T(": "));
+ text_ctrl->SetDefaultStyle(wxTextAttr(wxNullColour,wxNullColour,*wxNORMAL_FONT));
+ text_ctrl->AppendText(message + _T("\n\n"));
+}
+
+CreditsDialog::~CreditsDialog()
+{
+}
+
+ServerMessageBox::~ServerMessageBox()
+{
+}
+
+ServerMessageBox::ServerMessageBox(wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption ,
+ long style, const wxPoint& pos )
+ : wxDialog(parent,-1,caption,pos,wxDefaultSize,style|wxFRAME_FLOAT_ON_PARENT|wxDEFAULT_DIALOG_STYLE|wxEXPAND)
+{
+ SetIcon(*icon);
+
+ m_messages = new wxListCtrl(this,-1,wxDefaultPosition,wxDefaultSize,wxLC_NO_HEADER|wxLC_REPORT);
+ m_messages->InsertColumn(0,_T(""));
+ topsizer = new wxBoxSizer( wxVERTICAL );
+
+ AppendMessage(message);
+
+ topsizer->Add( m_messages, 1, wxALL|wxEXPAND|wxALIGN_CENTRE, 10 );
+ topsizer->Add(0,10);
+
+ wxSizer *sizerBtn = CreateButtonSizer(wxOK);
+ topsizer->Add(sizerBtn, 0, wxALL|wxALIGN_CENTRE, 10 );
+
+ SetSizer( topsizer );
+ Centre( wxBOTH | wxCENTER_FRAME);
+
+}
+
+void ServerMessageBox::AppendMessage(const wxString& message)
+{
+ if ( message == wxEmptyString )
+ return;
+ m_messages->InsertItem(m_messages->GetItemCount(),message);
+ m_messages->SetColumnWidth(0, wxLIST_AUTOSIZE);
+
+ SetSize(m_messages->GetColumnWidth(0)+25,-1);
+ Layout();
+}
+
+ActNotifBox::ActNotifBox(wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption ,
+ long style, const wxPoint& pos)
+ : ServerMessageBox( icon , parent, message, caption, style, pos)
+{}
+
+ActNotifBox::~ActNotifBox(){}
+
+void ActNotifBox::AppendMessage( const wxString& message )
+{
+ wxDateTime now = wxDateTime::Now();
+ wxString msg = now.Format( _T("%H:%M: ") ) + message;
+ ServerMessageBox::AppendMessage( msg );
+}
+
+void serverMessageBox( int whichIcon , const wxString& message,const wxString& caption,
+ long style , int x, int y )
+{
+ wxWindow* parent;
+ wxIcon* icon;
+ switch (whichIcon)
+ {
+ case SL_MAIN_ICON:
+ icon = new wxIcon(springlobby_xpm);
+ parent = CustomMessageBoxBase::getLobbypointer();
+ break;
+ case SS_MAIN_ICON:
+ icon = new wxIcon(springsettings_xpm);
+ parent = CustomMessageBoxBase::getSettingspointer();
+ break;
+ default:
+ icon = new wxIcon(wxNullIcon);
+ parent = 0;
+ break;
+
+ }
+ if ( s_serverMsgBox != 0 && s_serverMsgBox->IsShown() )
+ {
+ s_serverMsgBox->AppendMessage(message);
+ }
+ else
+ {
+ s_serverMsgBox = new ServerMessageBox (icon,parent,message,caption,style,wxPoint(x,y));
+ s_serverMsgBox->Show(true);
+ }
+}
+
+void actNotifBox( int whichIcon , const wxString& message,const wxString& caption,
+ long style , int x, int y )
+{
+ wxWindow* parent;
+ wxIcon* icon;
+ switch (whichIcon)
+ {
+ case SL_MAIN_ICON:
+ icon = new wxIcon(springlobby_xpm);
+ parent = CustomMessageBoxBase::getLobbypointer();
+ break;
+ case SS_MAIN_ICON:
+ icon = new wxIcon(springsettings_xpm);
+ parent = CustomMessageBoxBase::getSettingspointer();
+ break;
+ default:
+ icon = new wxIcon(wxNullIcon);
+ parent = 0;
+ break;
+
+ }
+ if ( s_actNotifBox != 0 && s_actNotifBox->IsShown() )
+ {
+ s_actNotifBox->AppendMessage(message);
+ }
+ else
+ {
+ s_actNotifBox = new ActNotifBox(icon,parent,wxEmptyString,caption,style,wxPoint(x,y));
+ s_actNotifBox->AppendMessage(message);
+ s_actNotifBox->Show(true);
+ }
+}
+
+int GetSingleChoiceIndex( const wxString& message,
+ const wxString& caption,
+ const wxArrayString& aChoices,
+ const int selected,
+ wxWindow *parent ,
+ int /*unused*/ ,
+ int /*unused*/ ,
+ bool /*unused*/ )
+{
+ wxString *choices;
+ int n = ConvertWXArrayToC(aChoices, &choices);
+
+ wxSingleChoiceDialog dialog(parent, message, caption, n, choices);
+ dialog.SetSelection( selected );
+
+ int choice;
+ if ( dialog.ShowModal() == wxID_OK )
+ choice = dialog.GetSelection();
+ else
+ choice = -1;
+
+ delete [] choices;
+
+ return choice;
+}
+
+void mutelistWindow( const wxString& message, const wxString& caption,
+ long style, const int x, const int y )
+{
+ wxWindow* parent = CustomMessageBoxBase::getLobbypointer();
+ wxIcon* icon = new wxIcon(springlobby_xpm);
+
+ if ( s_mutelistWindow != 0 && s_mutelistWindow->IsShown() )
+ {
+ s_mutelistWindow->AppendMessage(message);
+ }
+ else
+ {
+ s_mutelistWindow = new MutelistWindow(icon,parent,wxEmptyString,caption,style,wxPoint(x,y));
+ s_mutelistWindow->AppendMessage(message);
+ s_mutelistWindow->Show(true);
+ }
+}
+
+MutelistWindow::MutelistWindow(wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption ,
+ long style, const wxPoint& pos)
+ : ServerMessageBox( icon , parent, message, caption, style, pos)
+{}
+
+MutelistWindow::~MutelistWindow ()
+{}
+
diff --git a/src/settings++/custom_dialogs.h b/src/settings++/custom_dialogs.h
new file mode 100644
index 0000000..4161ccc
--- /dev/null
+++ b/src/settings++/custom_dialogs.h
@@ -0,0 +1,196 @@
+#ifndef CUSTOM_MSG_BOX_H_
+#define CUSTOM_MSG_BOX_H_
+
+#include <wx/msgdlg.h>
+
+const unsigned SL_MAIN_ICON = 1;
+const unsigned SS_MAIN_ICON = 2;
+
+
+class wxIcon;
+class wxWindow;
+class wxPoint;
+class wxString;
+class wxTextCtrl;
+class wxCommandEvent;
+class wxCloseEvent;
+class wxBoxSizer;
+class wxListCtrl;
+
+#define SL_MAIN_WINDOW_PTR CustomMessageBox::getLobbypointer()
+#define SE_FRAME_PTR CustomMessageBox::getSettingspointer()
+
+/** \brief utlity function to display modal messagebox
+ * \return wxOK|wxCANCEL|wxYES|wxNO according to option chosen
+ */
+int customMessageBox(int whichIcon , const wxString& message,
+ const wxString& caption = wxMessageBoxCaptionStr,
+ long style = wxOK|wxICON_INFORMATION, const int x = -1, const int y = -1 );
+
+/** \brief utlity function to display modal messagebox
+ * the dialog itself is statically allocated, therefore only one
+ * one of these may exist at any given time. \n
+ * It is possible to use this with other styles than wxOK|wxICON_INFORMATION,
+ * but since it's displayed non-modal nothing would come of it
+ */
+void customMessageBoxNoModal(int whichIcon , const wxString& message,
+ const wxString& caption = wxMessageBoxCaptionStr,
+ long style = wxOK|wxICON_INFORMATION, const int x = -1, const int y = -1 );
+
+/** \brief displays server messages when no chat window has focus
+ * If dialog currently isn't shown, it's brought up. If dialog already is shown (not necessarily having focus)
+ * message is appended, rather than old box replaced with new.
+ */
+void serverMessageBox(int whichIcon , const wxString& message,
+ const wxString& caption = wxMessageBoxCaptionStr,
+ long style = wxOK|wxICON_INFORMATION, const int x = -1, const int y = -1 );
+
+/** \brief displays user action notifications
+ * If dialog currently isn't shown, it's brought up. If dialog already is shown (not necessarily having focus)
+ * message is appended, rather than old box replaced with new.
+ */
+void actNotifBox(int whichIcon , const wxString& message,
+ const wxString& caption = _T("User action notification"),
+ long style = wxOK|wxICON_INFORMATION, const int x = -1, const int y = -1 );
+
+/** \brief show mutelist for a specific channel
+ *
+ */
+void mutelistWindow( const wxString& message,
+ const wxString& caption = _T("Mutelist"),
+ long style = wxOK|wxICON_INFORMATION, const int x = -1, const int y = -1 );
+
+//! cleanup
+void freeStaticBox();
+
+
+/** \brief used to display information throughout the app
+ * almost identical to wx's own dialog except for the possibility
+ * to set a custom icon
+ */
+class CustomMessageBox : public wxDialog
+{
+public:
+ CustomMessageBox(wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption = wxMessageBoxCaptionStr,
+ long style = wxOK|wxICON_INFORMATION, const wxPoint& pos = wxDefaultPosition);
+ virtual ~CustomMessageBox();
+
+ void OnOptionsNo(wxCommandEvent& event);
+
+protected:
+
+ DECLARE_EVENT_TABLE()
+
+};
+
+/** \brief used to display server messages when no chatwindow has focus
+ */
+class ServerMessageBox : public wxDialog
+{
+public:
+ ServerMessageBox(wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption = wxMessageBoxCaptionStr,
+ long style = wxOK, const wxPoint& pos = wxDefaultPosition);
+ virtual ~ServerMessageBox();
+
+ virtual void AppendMessage(const wxString& message);
+
+protected:
+
+ wxBoxSizer* topsizer;
+ wxListCtrl* m_messages;
+
+ ServerMessageBox( const ServerMessageBox& );
+
+};
+
+/** \brief displays user action notifications */
+class ActNotifBox : public ServerMessageBox
+{
+public:
+ ActNotifBox (wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption = _T("User action notification") ,
+ long style = wxOK, const wxPoint& pos = wxDefaultPosition);
+ virtual ~ActNotifBox ();
+
+ virtual void AppendMessage(const wxString& message);
+};
+
+/** \brief displays channel mutelist */
+class MutelistWindow : public ServerMessageBox
+{
+public:
+ MutelistWindow (wxIcon* icon ,wxWindow *parent, const wxString& message,
+ const wxString& caption = _T("User action notification") ,
+ long style = wxOK, const wxPoint& pos = wxDefaultPosition);
+ virtual ~MutelistWindow ();
+
+ //virtual void AppendMessage(const wxString& message);
+};
+
+/** \brief encapsulates pointers common to ServerMessageBox and CustomMessageBox
+ * \todo this isn't really that well designed, make a real base class of this?
+ */
+class CustomMessageBoxBase
+{
+public:
+ static void setLobbypointer(wxWindow*);
+ static void setSettingspointer(wxWindow*);
+ static wxWindow* getLobbypointer();
+ static wxWindow* getSettingspointer();
+ void AppendMessage(const wxString& message);
+
+protected:
+ static wxWindow* m_settingsWindow;
+ static wxWindow* m_lobbyWindow;
+ wxListCtrl* m_messages;
+
+};
+
+/** \brief A generic Credits dialog
+ * See showCredits() for modal use
+ */
+class CreditsDialog: public wxDialog
+{
+public:
+ CreditsDialog(wxWindow* parent,wxString title, int whichIcon);
+ virtual ~CreditsDialog();
+ /** \brief add a Name|Reason line to the dialog */
+ void AddCredit(wxString,wxString);
+
+private:
+ wxTextCtrl* text_ctrl;
+
+ CreditsDialog( const CreditsDialog& );
+};
+
+//! extends the wx method by allowing to set selection
+int GetSingleChoiceIndex( const wxString& message,
+ const wxString& caption,
+ const wxArrayString& aChoices,
+ const int selected,
+ wxWindow *parent = NULL,
+ int x = wxDefaultCoord,
+ int y = wxDefaultCoord,
+ bool centre = true );
+
+#endif /*CUSTOM_MSG_DLG_H_*/
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/settings++/frame.cpp b/src/settings++/frame.cpp
new file mode 100644
index 0000000..2ac41de
--- /dev/null
+++ b/src/settings++/frame.cpp
@@ -0,0 +1,355 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#include <wx/notebook.h>
+#include <wx/menu.h>
+#include <wx/icon.h>
+
+#include "frame.h"
+#include "../settings.h"
+#include "../springunitsync.h"
+#include "tab_render_detail.h"
+#include "tab_quality_video.h"
+#include "tab_abstract.h"
+#include "tab_audio.h"
+#include "tab_ui.h"
+#include "tab_simple.h"
+#include "Defs.hpp"
+#include "panel_pathoption.h"
+#include "custom_dialogs.h"
+#include "../images/springsettings.xpm"
+#include "helpmenufunctions.h"
+#include "se_utils.h"
+
+const wxString simpleTabCap= _("Combined Options");
+const wxString qualityTabCap= _("Render quality / Video mode");
+const wxString detailTabCap = _("Render detail");
+const wxString uiTabCap= _("UI options");
+const wxString audioTabCap = _("Audio");
+const wxString expertModeWarning = _("Changes made on Quality/Detail tab in expert mode"
+ "\n will be lost if you change simple options again.\n"
+ "Also these changes WILL NOT be reflected by the \n"
+ "selected choices on the Combined options tab.\n"
+ "(this message can be disabled in the \"File\" menu)");
+
+BEGIN_EVENT_TABLE(settings_frame,wxFrame)
+ EVT_CLOSE(settings_frame::OnClose)
+ EVT_MENU(wxID_ANY,settings_frame::OnMenuChoice)
+END_EVENT_TABLE()
+
+settings_frame::settings_frame(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& pa_size)
+: wxFrame(parent, id, title, position, pa_size)
+{
+ alreadyCalled = false;
+ parentWindow = parent;
+
+ if ( !usync().IsLoaded() )
+ usync().ReloadUnitSyncLib();
+
+ notebook = new wxNotebook(this, ID_OPTIONS, wxPoint(0,0),TAB_SIZE, wxNB_TOP|wxNB_NOPAGETHEME);
+ notebook->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, _T("Tahoma")));
+
+ settingsIcon = new wxIcon(springsettings_xpm);
+
+ if (abstract_panel::loadValuesIntoMap())
+ {
+ CreateGUIControls();
+ initMenuBar();
+ }
+ else
+ {
+ notebook->AddPage(new PathOptionPanel(notebook,this),_("Error!"));
+ SetTitle(_T("SpringSettings"));
+ }
+
+ SetIcon(*settingsIcon);
+ wxString name = _T("SETTINGSFRAME");
+ wxPoint pos = sett().GetWindowPos( name, wxPoint( DEFSETT_SW_LEFT, DEFSETT_SW_TOP ) );
+ wxSize size = sett().GetWindowSize( name, wxSize( DEFSETT_SW_WIDTH, DEFSETT_SW_HEIGHT ) );
+ SetSize( pos.x , pos.y, size.GetWidth(), size.GetHeight() );
+ Layout();
+ Center();
+}
+
+void settings_frame::buildGuiFromErrorPanel()
+{
+ notebook->DeletePage(0);
+
+ //to be safe we'll try again
+ if (abstract_panel::loadValuesIntoMap())
+ {
+ CreateGUIControls();
+ initMenuBar();
+ }
+ else
+ {
+ notebook->AddPage(new PathOptionPanel(notebook,this),_("Error!"));
+ }
+}
+
+settings_frame::~settings_frame()
+{
+
+}
+
+void settings_frame::handleExternExit()
+{
+ if ( !alreadyCalled){
+ alreadyCalled = true;
+ if (abstract_panel::settingsChanged)
+ {
+ int choice = customMessageBox(SS_MAIN_ICON,_("Save Spring settings before exiting?"), _("Confirmation needed"), wxYES|wxNO |wxICON_QUESTION);
+ if ( choice == wxYES)
+ {
+ abstract_panel::saveSettings();
+ if (simpleTab!=0)
+ simpleTab->saveCbxChoices();
+ }
+ }
+ }
+
+ sett().SaveSettings();
+}
+
+void settings_frame::handleExit() {
+ if (abstract_panel::settingsChanged)
+ {
+ int action = customMessageBox(SS_MAIN_ICON,_("Save Spring settings before exiting?"), _("Confirmation needed"),wxYES_NO|wxCANCEL|wxICON_QUESTION );
+ switch (action) {
+ case wxYES:
+ if (abstract_panel::saveSettings())
+ (abstract_panel::settingsChanged) = false;
+ if (simpleTab!=0)
+ simpleTab->saveCbxChoices();
+ case wxNO:
+ sett().SaveSettings();
+ Destroy();
+ break;
+
+ case wxCANCEL:
+ default:
+ break;
+ }
+ }
+ else
+ {
+ sett().SaveSettings();
+ Destroy();
+ }
+}
+
+void settings_frame::CreateGUIControls()
+{
+ switch(sett().getMode()){
+ case SET_MODE_EXPERT:
+
+ qualityTab = new tab_quality_video(notebook,ID_QUALITY_VIDEO);
+ detailTab = new tab_render_detail(notebook,ID_RENDER_DETAIL);
+ uiTab = new tab_ui(notebook,ID_UI);
+ audioTab = new audio_panel(notebook,ID_AUDIO);
+ simpleTab = 0;
+ notebook->AddPage(uiTab, uiTabCap);
+ notebook->AddPage(qualityTab, qualityTabCap);
+ notebook->AddPage(detailTab, detailTabCap);
+ notebook->AddPage(audioTab,audioTabCap);
+
+ break;
+ default:
+ case SET_MODE_SIMPLE:
+ simpleTab = new tab_simple(this,notebook,ID_SIMPLE);
+ uiTab = new tab_ui(notebook,ID_UI);
+ notebook->AddPage(simpleTab,simpleTabCap);
+ notebook->AddPage(uiTab, uiTabCap);
+ break;
+ }
+ notebook->SetSelection(0);
+
+ if (sett().getMode()==SET_MODE_EXPERT)
+ SetTitle(_("SpringSettings (expert mode)"));
+ else
+ SetTitle(_("SpringSettings (simple mode)"));
+
+ abstract_panel::settingsChanged = false;
+
+}
+
+void settings_frame::initMenuBar() {
+ menuFile = new wxMenu();
+
+ menuFile->Append(ID_MENUITEM_SAVE, _("Save settings"));
+ menuFile->Append(ID_MENUITEM_RESET, _("Reset settings to default values"));
+ menuFile->AppendCheckItem(ID_MENUITEM_DISABLE_WARN, _("Disable expert mode warning"));
+ menuFile->AppendSeparator();
+ menuFile->Append(ID_MENUITEM_QUIT, _("Quit"));
+
+ menuFile->Check(ID_MENUITEM_DISABLE_WARN,sett().getDisableWarning());
+
+ menuMode = new wxMenu();
+ menuMode->AppendRadioItem(ID_MENUITEM_SIMPLE,_("Simple (few options)"));
+ menuMode->AppendRadioItem(ID_MENUITEM_EXPERT,_("Expert (all options"));
+
+ menuHelp = new wxMenu();
+ menuHelp->Append(ID_MENUITEM_ABOUT,_("About"));
+ menuHelp->Append(ID_MENUITEM_CONTACT, _("Contact"));
+ menuHelp->Append(ID_MENUITEM_CREDITS, _("Credits"));
+ menuHelp->Append(ID_MENUITEM_BUGREPORT, _("Report a bug"));
+
+ switch(sett().getMode()){
+ case SET_MODE_EXPERT: {
+ menuMode->Check(ID_MENUITEM_EXPERT,true);
+ }
+ break;
+ default:
+ case SET_MODE_SIMPLE: {
+ menuMode->Check(ID_MENUITEM_SIMPLE,true);
+ }
+ break;
+ }
+ wxMenuBar* menuBar = new wxMenuBar();
+ menuBar->Append(menuFile, _("File"));
+ menuBar->Append(menuMode, _("Mode"));
+ menuBar->Append(menuHelp, _("Info/Help"));
+
+ //TODO PROFILES!!!
+
+ SetMenuBar(menuBar);
+}
+
+void settings_frame::OnMenuChoice(wxCommandEvent& event) {
+ switch (event.GetId()) {
+ case ID_MENUITEM_SAVE:
+ if (abstract_panel::saveSettings())
+ (abstract_panel::settingsChanged) = false;
+ if (simpleTab!=0)
+ simpleTab->saveCbxChoices();
+ break;
+
+ case ID_MENUITEM_QUIT:
+ handleExit();
+ break;
+
+ case ID_MENUITEM_RESET:
+ if ((customMessageBox(SS_MAIN_ICON,_("Reset ALL settings to default values?"), _("Confirmation needed"), wxYES_NO)) == wxYES) {
+ resetSettings();
+ }
+ break;
+
+ case ID_MENUITEM_SIMPLE:
+ if (sett().getMode()==SET_MODE_EXPERT)
+ sett().setMode(SET_MODE_SIMPLE);
+
+ simpleTab = new tab_simple(this,notebook,ID_SIMPLE);
+ notebook->InsertPage(0,simpleTab,simpleTabCap);
+ simpleTab->updateControls(UPDATE_ALL);
+
+ //if not on ui page goto simple
+ if (notebook->GetSelection()!=1)
+ notebook->SetSelection(0);
+
+ notebook->DeletePage(4);
+ notebook->DeletePage(3);
+ notebook->DeletePage(2);
+ qualityTab = 0;
+ detailTab = 0;
+ audioTab = 0;
+
+ SetTitle(_("SpringSettings (simple mode)"));
+ if (!sett().getDisableWarning()){
+ customMessageBox(SS_MAIN_ICON,expertModeWarning, _("Hint"), wxOK);
+ }
+ break;
+
+ case ID_MENUITEM_EXPERT:
+ if (sett().getMode()==SET_MODE_SIMPLE) {
+ switchToExpertMode();
+ }
+ break;
+ case ID_MENUITEM_DISABLE_WARN:
+ sett().setDisableWarning(menuFile->IsChecked(ID_MENUITEM_DISABLE_WARN));
+ break;
+
+ case ID_MENUITEM_ABOUT:
+ showAbout();
+ break;
+ case ID_MENUITEM_CREDITS:
+ showCredits();
+ break;
+ case ID_MENUITEM_CONTACT:
+ openContactPage();
+ break;
+ case ID_MENUITEM_BUGREPORT:
+ openNewTicket();
+ break;
+ }
+}
+void settings_frame::resetSettings()
+{
+ abstract_panel::loadDefaults();
+ updateAllControls();
+}
+
+void settings_frame::switchToExpertMode()
+{
+ sett().setMode(SET_MODE_EXPERT);
+ menuMode->Check(ID_MENUITEM_EXPERT,true);
+
+ qualityTab = new tab_quality_video(notebook,ID_QUALITY_VIDEO);
+ detailTab = new tab_render_detail(notebook,ID_RENDER_DETAIL);
+ audioTab = new audio_panel(notebook,ID_AUDIO);
+ notebook->AddPage(qualityTab, qualityTabCap);
+ notebook->AddPage(detailTab, detailTabCap);
+ notebook->AddPage(audioTab,audioTabCap);
+
+ notebook->DeletePage(0);
+ simpleTab = 0;
+ SetTitle(_("SpringSettings (expert mode)"));
+ uiTab->updateControls(UPDATE_ALL);
+ detailTab->updateControls(UPDATE_ALL);
+ qualityTab->updateControls(UPDATE_ALL);
+ audioTab->updateControls(UPDATE_ALL);
+}
+
+void settings_frame::updateAllControls()
+{
+ if (uiTab)
+ uiTab->updateControls(UPDATE_ALL);
+ if (simpleTab!=0)
+ simpleTab->updateControls(UPDATE_ALL);
+ if (detailTab)
+ detailTab->updateControls(UPDATE_ALL);
+ if (qualityTab)
+ qualityTab->updateControls(UPDATE_ALL);
+ if (audioTab)
+ audioTab->updateControls(UPDATE_ALL);
+}
+void settings_frame::OnClose(wxCloseEvent& /*unused*/)
+{
+ if ( !alreadyCalled ){
+ wxString name = _T("SETTINGSFRAME");
+ sett().SetWindowSize( name, GetSize() );
+ sett().SetWindowPos( name, GetPosition() );
+ sett().SaveSettings();
+ handleExit();
+ }
+}
+
+
diff --git a/src/settings++/frame.h b/src/settings++/frame.h
new file mode 100644
index 0000000..df76db3
--- /dev/null
+++ b/src/settings++/frame.h
@@ -0,0 +1,104 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef __SETTINGS_FRAME_h__
+#define __SETTINGS_FRAME_h__
+
+
+#include <wx/frame.h>
+class wxNotebook;
+class tab_simple;
+class tab_ui;
+class tab_render_detail;
+class tab_quality_video;
+class audio_panel;
+class abstract_panel;
+class wxMenu;
+class wxCommanEvent;
+class wxCloseEvent;
+class wxString;
+class wxWindow;
+class wxPoint;
+class wxSize;
+class wxFlexGridSizer;
+class wxNotebookEvent;
+class PathOptionPanel;
+class wxIcon;
+
+class settings_frame : public wxFrame
+{
+ private:
+ DECLARE_EVENT_TABLE();
+
+ public:
+ settings_frame(wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("Project2"), const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize);
+ virtual ~settings_frame();
+ void handleExternExit();
+ void switchToExpertMode();
+ void buildGuiFromErrorPanel();
+
+ private:
+ tab_simple* simpleTab;
+ tab_ui* uiTab;
+ audio_panel* audioTab;
+ tab_render_detail* detailTab;
+ tab_quality_video* qualityTab;
+
+ wxMenu* menuFile;
+ wxMenu* menuMode;
+ wxMenu* menuHelp;
+ wxWindow* parentWindow;
+ wxNotebook *notebook;
+ wxFlexGridSizer *book_sizer;
+ wxFlexGridSizer* book_sizer2;
+ PathOptionPanel* pathOpt_panel;
+
+ wxIcon* settingsIcon;
+
+ void OnNBchange(wxNotebookEvent&);
+ void initMenuBar();
+ void handleExit();
+ bool alreadyCalled;
+
+ enum
+ {
+ ////GUI Enum Control ID Start
+ ID_UI = 1013,
+ ID_QUALITY_VIDEO = 1012,
+ ID_RENDER_DETAIL = 1011,
+ ID_SIMPLE = 1010,
+ //ID_DEBUG = 1009,
+ ID_MOUSE = 1008,
+ ID_AUDIO = 1007,
+ ID_GENERAL = 1006,
+ ID_VIDEO = 1005,
+ ID_RENDERING = 1004,
+ ID_OPTIONS = 1003,
+ ////GUI Enum Control ID End
+ ID_DUMMY_VALUE_ //don't remove this value unless you have other enum values
+ };
+ void OnClose(wxCloseEvent& event);
+ void OnMenuChoice(wxCommandEvent& event);
+ void CreateGUIControls();
+ void resetSettings();
+ void updateAllControls();
+
+};
+
+
+#endif
diff --git a/src/settings++/helpmenufunctions.cpp b/src/settings++/helpmenufunctions.cpp
new file mode 100644
index 0000000..02bd976
--- /dev/null
+++ b/src/settings++/helpmenufunctions.cpp
@@ -0,0 +1,51 @@
+#include "helpmenufunctions.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif //HAVE_CONFIG_H
+
+#ifndef VERSION
+ #define VERSION "unknown"
+#endif //VERSION
+
+
+#include <wx/icon.h>
+#include "../images/springsettings.xpm"
+
+#include "custom_dialogs.h"
+#include <wx/intl.h>
+#include "se_utils.h"
+#include <string>
+
+#include <wx/aboutdlg.h>
+
+void showAbout()
+{
+ std::string ver = std::string("0.2.1 revision ") + VERSION;
+ wxAboutDialogInfo info;
+ info.SetName(_T("SpringSettings"));
+ info.SetVersion(_T("0.2.1"));//WX_STRING(ver));
+ info.SetDescription(_("SpringSettings is a graphical frontend to the Settings of the Spring engine"));
+ info.SetCopyright(_T("(C) 2007-2008 koshi <koshi at springlobby.info>"));
+ info.SetIcon(wxIcon(springsettings_xpm));
+ wxAboutBox(info);
+}
+
+void showCredits()
+{
+ CreditsDialog dlg(CustomMessageBoxBase::getSettingspointer(),_T("Credits"),SS_MAIN_ICON);
+ dlg.AddCredit(_("Kloot"),_T("wrote Settings++ from which SpringSettings originated"));
+ dlg.AddCredit(_("The SpringLobby team"),_("thanks for inviting me in, code to re-use, infrastructure and help in general"));
+ dlg.AddCredit(_("everyone reporting bugs/suggestions"),_T(""));
+ dlg.ShowModal();
+}
+
+void openNewTicket()
+{
+ openUrl(_T("http://trac.springlobby.info/newticket?component=springsettings%2Fsettings%2B%2B&owner=koshi"));
+}
+
+void openContactPage()
+{
+ openUrl(_T("http://trac.springlobby.info/wiki/Contact"));
+}
diff --git a/src/settings++/helpmenufunctions.h b/src/settings++/helpmenufunctions.h
new file mode 100644
index 0000000..0149326
--- /dev/null
+++ b/src/settings++/helpmenufunctions.h
@@ -0,0 +1,31 @@
+#ifndef HELPMENUFUNCTIONS_H_
+#define HELPMENUFUNCTIONS_H_
+
+/** \brief shows the about dialog in non-modal mode */
+void showAbout();
+/** \brief shows the credits dialog in modal mode */
+void showCredits();
+/** \brief opens trac in browser, presets owner and component */
+void openNewTicket();
+/** \brief opens http://trac.springlobby.info/wiki/Contact in browser */
+void openContactPage();
+
+#endif /*HELPMENUFUNCTIONS_H_*/
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/settings++/main.h b/src/settings++/main.h
new file mode 100644
index 0000000..9d5060b
--- /dev/null
+++ b/src/settings++/main.h
@@ -0,0 +1,48 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef SPRINGSETTINGS_MAIN_h
+#define SPRINGSETTINGS_MAIN_h
+
+#include <wx/app.h>
+
+class Springsettings : public wxApp
+{
+ public:
+ Springsettings();
+ bool OnInit();
+ int OnExit();
+ virtual void OnFatalException();
+
+ virtual void OnInitCmdLine(wxCmdLineParser& parser);
+ virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
+
+ protected:
+
+ long m_log_verbosity;
+ bool m_log_console;
+ bool m_log_window_show;
+ bool m_crash_handle_disable;
+
+};
+
+#endif
diff --git a/src/settings++/panel_pathoption.cpp b/src/settings++/panel_pathoption.cpp
new file mode 100644
index 0000000..f4c7ddb
--- /dev/null
+++ b/src/settings++/panel_pathoption.cpp
@@ -0,0 +1,112 @@
+#include "panel_pathoption.h"
+
+#include <wx/filedlg.h>
+#include <wx/dirdlg.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/intl.h>
+#include <wx/textctrl.h>
+#include <wx/radiobut.h>
+#include <wx/stattext.h>
+#include <wx/button.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/stdpaths.h>
+#include <wx/dir.h>
+#include <wx/file.h>
+#include <wx/stdpaths.h>
+#include <wx/dynlib.h>
+
+#include "se_utils.h"
+#include "Defs.hpp"
+#include "frame.h"
+#include "../settings.h"
+#include "../nonportable.h"
+#include "../springunitsynclib.h"
+#include "se_utils.h"
+
+
+#include "custom_dialogs.h"
+
+PathOptionPanel::PathOptionPanel(wxWindow* parent,settings_frame* _origin) : wxPanel(parent,-1),origin(_origin)
+{
+ usync_loc_lbl = new wxStaticText (this, -1 , _("Path to unitsync shared library"));
+ explanation_text = new wxStaticText (this, -1 , _("There was a problem retrieving your settings.\n"
+ "Please check that the path below is correct.\n"
+ "When you have corrected it, click\n"
+ "the \"Use this Path\" button to try again."),
+ wxDefaultPosition,wxSize(450,-1));
+
+
+ paths_ok_btn = new wxButton(this,ID_PATH_OK_BTN,_("Use this path"),wxDefaultPosition ,wxSize(-1,-1), wxBU_EXACTFIT);
+ usync_browse_btn = new wxButton(this, ID_PATH_USYNC_BTN, _("Browse") );
+
+
+
+ usync_ctrl = new wxTextCtrl(this,-1, sett().GetCurrentUsedUnitSync(), wxDefaultPosition,wxSize(400,-1));
+ usync_ctrl->SetToolTip(_("unitsync.so on linux, unitsync.dll on windows"));
+
+ usync_sizer = new wxFlexGridSizer(1,5,5);
+
+ parentSizer = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer* subSizerB = new wxBoxSizer(wxHORIZONTAL);
+ main_sizer = new wxStaticBoxSizer(wxVERTICAL ,this,_("Path settings")) ;
+
+ usync_sizer->Add(usync_loc_lbl,1,wxEXPAND);
+
+ subSizerB->Add(usync_ctrl,1,wxEXPAND);
+ subSizerB->Add(usync_browse_btn,0,wxEXPAND);
+ usync_sizer->Add(subSizerB,1,wxEXPAND);
+
+ usync_sizer->SetSizeHints(this);
+ usync_sizer->Fit(this);
+
+ main_sizer->Add(explanation_text,1,wxALL|wxEXPAND,15);
+ main_sizer->Add(usync_sizer,1,wxALL|wxEXPAND,10);
+ main_sizer->Add(paths_ok_btn,0,wxALL|wxEXPAND,10);
+
+ parentSizer->Add(main_sizer,0,wxALL,10);
+
+ SetSizer(parentSizer);
+}
+
+void PathOptionPanel::SetUsyncPath(wxCommandEvent& /*unused*/)
+{
+ wxString lib_ext = wxDynamicLibrary::CanonicalizeName(_T(""), wxDL_MODULE);
+ wxFileDialog pic( this, _("Choose an unitsync library"),
+ wxPathOnly( sett().AutoFindSpringBin() ),
+ _T("unitsync") + lib_ext, wxString(_T("Library")) + _T("(*") + lib_ext + _T(")|*") + lib_ext + _T("|") + wxString(_("Any File")) + _T(" (*.*)|*.*") );
+ if ( pic.ShowModal() == wxID_OK )
+ usync_ctrl->SetValue( pic.GetPath() );
+}
+
+void PathOptionPanel::UsePaths(wxCommandEvent& /*unused*/)
+{
+ sett().SetUnitSync( sett().GetCurrentUsedSpringIndex(), usync_ctrl->GetValue() );
+ usync().ReloadUnitSyncLib();
+
+ if ( !(susynclib().IsLoaded()) )
+ {
+ customMessageBox(SS_MAIN_ICON, _("SpringSettings is unable to load your unitsync library.\n"
+ "You might want to take another look at your unitsync setting.\n"
+ "Your Spring version has to be 0.76 or newer, otherwise \n"
+ "this will fail in any case."), _("Spring error"), wxOK );
+ }
+ else
+ {
+ origin->buildGuiFromErrorPanel();
+ sett().SaveSettings();
+ }
+
+}
+
+PathOptionPanel::~PathOptionPanel()
+{
+}
+
+
+BEGIN_EVENT_TABLE(PathOptionPanel, wxPanel)
+ EVT_BUTTON ( ID_PATH_USYNC_BTN, PathOptionPanel::SetUsyncPath )
+ EVT_BUTTON ( ID_PATH_OK_BTN, PathOptionPanel::UsePaths )
+END_EVENT_TABLE()
+
diff --git a/src/settings++/panel_pathoption.h b/src/settings++/panel_pathoption.h
new file mode 100644
index 0000000..66f52db
--- /dev/null
+++ b/src/settings++/panel_pathoption.h
@@ -0,0 +1,58 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+#ifndef PANEL_PATHOPTION_H_
+#define PANEL_PATHOPTION_H_
+
+#include <wx/panel.h>
+
+class wxWindow;
+class wxButton;
+class wxBoxSizer;
+class wxStaticBoxSizer;
+class wxTextCtrl;
+class wxStaticText;
+class wxFlexGridSizer;
+class settings_frame;
+
+/** \brief only used in standalone mode to get usync location if not immediately found */
+class PathOptionPanel : public wxPanel
+{
+
+public:
+ PathOptionPanel(wxWindow*,settings_frame*);
+ virtual ~PathOptionPanel();
+ void SetUsyncPath(wxCommandEvent& );
+ void UsePaths(wxCommandEvent& );
+
+private:
+ wxStaticText* usync_loc_lbl;
+ wxStaticText* explanation_text;
+
+ wxButton* paths_ok_btn;
+ wxButton* usync_browse_btn;
+
+ wxTextCtrl* usync_ctrl;
+ settings_frame* origin;
+ wxFlexGridSizer* usync_sizer;
+
+ wxBoxSizer* parentSizer;
+ wxStaticBoxSizer* main_sizer;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif /*PANEL_PATHOPTION_H_*/
diff --git a/src/settings++/presets.h b/src/settings++/presets.h
new file mode 100644
index 0000000..2afe43a
--- /dev/null
+++ b/src/settings++/presets.h
@@ -0,0 +1,139 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef SETTINGS_PRESETS_H_
+#define SETTINGS_PRESETS_H_
+#include <map>
+#include <string>
+#include <wx/intl.h>
+/** \brief Presets for tab_simple go here
+ * presets are only used for performance relevant (render detail + AA) settings
+ * and screen resolutions
+ */
+template <typename T, int valueCount> class presetValues
+{
+
+public:
+ std::map<wxString,T> values;
+ wxString key;
+
+ //levelLabels and values_arg MUST have same length
+ presetValues ( wxString key_arg,const wxString* levelLabels,const T* values_arg) {
+ for(int i = 0; i< valueCount;++i) {
+ values[levelLabels[i]]=values_arg[i];
+ }
+ key = key_arg;
+ }
+};
+const int levels_low_To_High_size = 3;
+const int levels_vlow_To_vHigh_size =5;
+const wxString levels_low_To_High[levels_low_To_High_size] = { _("low"),_("medium"),_("high")};
+const wxString levels_vlow_To_vHigh[levels_vlow_To_vHigh_size] = { _("very low"),_("low"),_("medium"),_("high"),_("very high")};
+
+//TODO generally rethink preset values
+/** RENDER_DETAIL ***************************************************************/
+const int vl_ShadowMapSize[3] = { 1024, 4096, 8192 }; //shadowmapsize
+const int vl_TreeRadius[3] = { 600, 1900, 3000 }; //tree view distance
+const int vl_GroundDetail[3] = { 20, 70, 120 }; //terrain detail
+const int vl_UnitLodDist[3] = { 100, 350, 1000 }; //unit LOD distance
+const int vl_GrassDetail[3] = { 0, 5, 10 }; //grass detail
+const int vl_GroundDecals[3] = { 0, 0, 1 }; // ground decals
+const int vl_UnitIconDist[3] = { 100, 550, 1000 }; // unit icon distance
+const int vl_MaxParticles[3] = { 100, 4000, 20000 };
+const int vl_MaxNanoParticles[3] = { 100, 6000, 20000 };
+//const int vl_SM3MaxTextureStages[3] = { 1, 6, 20 };
+
+const presetValues<int, 3> pr_ShadowMapSize = presetValues<int, 3>(_T("ShadowMapSize"),levels_low_To_High,vl_ShadowMapSize);
+const presetValues<int, 3> pr_TreeRadius = presetValues<int, 3>(_T("TreeRadius"),levels_low_To_High,vl_TreeRadius);
+const presetValues<int, 3> pr_GroundDetail = presetValues<int, 3>(_T("GroundDetail"),levels_low_To_High,vl_GroundDetail);
+const presetValues<int, 3> pr_UnitLodDist = presetValues<int, 3>(_T("UnitLodDist"),levels_low_To_High,vl_UnitLodDist);
+const presetValues<int, 3> pr_GrassDetail = presetValues<int, 3>(_T("GrassDetail"),levels_low_To_High,vl_GrassDetail);
+const presetValues<int, 3> pr_GroundDecals = presetValues<int, 3>(_T("GroundDecals"),levels_low_To_High,vl_GroundDecals);
+const presetValues<int, 3> pr_UnitIconDist = presetValues<int, 3>(_T("UnitIconDist"),levels_low_To_High,vl_UnitIconDist);
+const presetValues<int, 3> pr_MaxParticles = presetValues<int, 3>(_T("MaxParticles"),levels_low_To_High,vl_MaxParticles);
+const presetValues<int, 3> pr_MaxNanoParticles = presetValues<int, 3>(_T("MaxNanoParticles"),levels_low_To_High,vl_MaxNanoParticles);
+//const presetValues<int, 3> pr_SM3MaxTextureStages = presetValues<int, 3>(wxT("SM3MaxTextureStages"),levels_low_To_High,vl_SM3MaxTextureStages);
+
+const int prVal_RenderDetail_size = 9;
+const presetValues<int, 3> prVal_RenderDetail[prVal_RenderDetail_size] = {pr_ShadowMapSize, pr_TreeRadius, pr_GroundDetail,
+ pr_UnitLodDist, pr_GrassDetail, pr_GroundDecals,
+ pr_UnitIconDist, pr_MaxParticles,pr_MaxNanoParticles};
+
+/** RENDER QUALITY **********************************************************/
+const int vl_DepthBufferBits[5] = {16,16,16,24,24};
+const int vl_ReflectiveWater[5] = {0,0,1,3,2};
+const int vl_Shadows[5] = {0,0,0,0,1};
+const int vl_3DTrees[5] = {0,1,1,1,1};
+const int vl_AdvSky[5] = {0,0,0,0,1};//high-res clouds
+const int vl_DynamicSky[5] = {0,0,0,0,1};//dynamic clouds
+const int vl_SmoothPoints[5] = {0,1,1,1,1};
+const int vl_SmoothLines[5] = {0,0,1,1,1};
+const int vl_FSAA[5] = {0,0,0,0,1};//fullscreen aa enable/disable
+const int vl_FSAALevel[5] = {0,0,0,0,1};//fullscene aa samples
+const int vl_AdvUnitShading[5] = {0,0,0,1,1}; //refl. units
+
+const presetValues<int, 5> pr_DepthBufferBits = presetValues<int, 5>(wxT("DepthBufferBits"),levels_vlow_To_vHigh,vl_DepthBufferBits);
+const presetValues<int, 5> pr_ReflectiveWater = presetValues<int, 5>(_T("ReflectiveWater"),levels_vlow_To_vHigh,vl_ReflectiveWater);
+const presetValues<int, 5> pr_Shadows = presetValues<int, 5>(_T("Shadows"),levels_vlow_To_vHigh,vl_Shadows);
+const presetValues<int, 5> pr_3DTrees = presetValues<int, 5>(_T("3DTrees"),levels_vlow_To_vHigh,vl_3DTrees);
+const presetValues<int, 5> pr_AdvSky = presetValues<int, 5>(_T("AdvSky"),levels_vlow_To_vHigh,vl_AdvSky);
+const presetValues<int, 5> pr_DynamicSky = presetValues<int, 5>(_T("DynamicSky"),levels_vlow_To_vHigh,vl_DynamicSky);
+const presetValues<int, 5> pr_SmoothPoints = presetValues<int, 5>(_T("SmoothPoints"),levels_vlow_To_vHigh,vl_SmoothPoints);
+const presetValues<int, 5> pr_SmoothLines = presetValues<int, 5>(_T("SmoothLines"),levels_vlow_To_vHigh,vl_SmoothLines);
+const presetValues<int, 5> pr_FSAA = presetValues<int, 5>(_T("FSAA"),levels_vlow_To_vHigh,vl_FSAA);
+const presetValues<int, 5> pr_FSAALevel = presetValues<int, 5>(_T("FSAALevel"),levels_vlow_To_vHigh,vl_FSAALevel);
+const presetValues<int, 5> pr_AdvUnitShading = presetValues<int, 5>(_T("AdvUnitShading"),levels_vlow_To_vHigh,vl_AdvUnitShading);
+
+const int prVal_RenderQuality_size = 11;
+const presetValues<int, 5> prVal_RenderQuality[prVal_RenderQuality_size] = { pr_DepthBufferBits, pr_ReflectiveWater, pr_Shadows, pr_3DTrees,
+ pr_AdvSky, pr_DynamicSky, pr_SmoothPoints, pr_SmoothLines,pr_FSAA, pr_FSAALevel, pr_AdvUnitShading };
+
+
+/** VIDEO MODES ********************************************************/
+const int vl_Resolution_Str_size = 13;
+const int vl_Resolution_X[vl_Resolution_Str_size] = { 800, 1024, 1152, 1280, 1280, 1600, 1280, 1440, 1680, 1920, 2048, 2560, 3200};
+const int vl_Resolution_Y[vl_Resolution_Str_size] = { 600, 768, 864, 960, 1024, 1200, 800, 900, 1050, 1200, 768, 1024, 1200};
+const int vl_Resolution_startOfDualScreenRes = 9;
+//must be same order
+const wxString vl_Resolution_Str[vl_Resolution_Str_size] =
+{ _T("800 x 600"), _T("1024 x 768"), _T("1152 x 864"), _T("1280 x 960"), _T("1280 x 1024"),
+ _T("1600 x 1200"), _T("1280 x 800 (widescreen)"), _T("1440 x 900 (widescreen)"), _T("1680 x 1050 (widescreen)") ,
+ _T("1920 x 1200 (widescreen)"),
+ _T("2048 x 768 (dual-screen)"), _T("2560 x 1024 (dual-screen)"), _T("3200 x 1200 (dual-screen)")};
+
+/*** Water 4 (bump water) presets ***********************************************/
+const int vl_w4_BumpWaterReflection[5] = { 0, 0, 1, 1, 1 };
+const int vl_w4_BumpWaterRefraction[5] = { 0, 1, 1, 1, 2 };
+const int vl_w4_BumpWaterShoreWaves[5] = { 0, 0, 0, 1, 1 };
+const float vl_w4_BumpWaterAnisotropy[5] = { 0.f, 0.f, 2.f, 4.f, 6.f };
+const int vl_w4_BumpWaterUseDepthTexture[5] = { 0, 1, 1, 1, 1 };
+const int vl_w4_BumpWaterTexSizeReflection[5] = { 0, 0,128,256,512 };
+const int vl_w4_BumpWaterBlurReflection[5] = { 0, 0, 0, 0, 1 };
+
+const presetValues<int, 5> pr_w4_BumpWaterReflection = presetValues<int, 5>(_T("BumpWaterReflection"),levels_vlow_To_vHigh,vl_w4_BumpWaterReflection);
+const presetValues<int, 5> pr_w4_BumpWaterRefraction = presetValues<int, 5>(_T("BumpWaterRefraction"),levels_vlow_To_vHigh,vl_w4_BumpWaterRefraction);
+const presetValues<int, 5> pr_w4_BumpWaterShoreWaves = presetValues<int, 5>(_T("BumpWaterShoreWaves"),levels_vlow_To_vHigh,vl_w4_BumpWaterShoreWaves);
+const presetValues<float, 5> pr_w4_BumpWaterAnisotropy = presetValues<float, 5>(_T("BumpWaterAnisotropy"),levels_vlow_To_vHigh,vl_w4_BumpWaterAnisotropy );
+const presetValues<int, 5> pr_w4_BumpWaterUseDepthTexture = presetValues<int, 5>(_T("BumpWaterUseDepthTexture"),levels_vlow_To_vHigh,vl_w4_BumpWaterUseDepthTexture );
+const presetValues<int, 5> pr_w4_BumpWaterTexSizeReflection = presetValues<int, 5>(_T("BumpWaterTexSizeReflection"),levels_vlow_To_vHigh,vl_w4_BumpWaterTexSizeReflection );
+const presetValues<int, 5> pr_w4_BumpWaterBlurReflection = presetValues<int, 5>(_T("BumpWaterBlurReflection"),levels_vlow_To_vHigh,vl_w4_BumpWaterBlurReflection );
+
+const int prVal_W4_size = 6;
+const presetValues<int, 5> prVal_W4[prVal_W4_size] = { pr_w4_BumpWaterReflection, pr_w4_BumpWaterRefraction, pr_w4_BumpWaterShoreWaves,
+ pr_w4_BumpWaterUseDepthTexture, pr_w4_BumpWaterTexSizeReflection, pr_w4_BumpWaterBlurReflection };
+
+#endif /*PRESETS_H_*/
diff --git a/src/settings++/se_utils.cpp b/src/settings++/se_utils.cpp
new file mode 100644
index 0000000..8277b4c
--- /dev/null
+++ b/src/settings++/se_utils.cpp
@@ -0,0 +1,45 @@
+#include <wx/filename.h>
+#include <wx/stdpaths.h>
+#include <wx/filename.h>
+#include <wx/utils.h>
+#include <wx/log.h>
+#include <wx/intl.h>
+
+#include <string>
+#include <sstream>
+
+#include "se_utils.h"
+
+#include "custom_dialogs.h"
+#include "../settings.h"
+#include "../springunitsynclib.h"
+//#include "../utils/.h"
+
+static bool standalonemode = true;
+
+bool IsSettingsStandAlone()
+{
+ return standalonemode;
+}
+
+void SetSettingsStandAlone( bool value )
+{
+ standalonemode = value;
+}
+
+
+int fromString(const wxString& s) {
+ long temp = 0;
+ s.ToLong(&temp);
+ return int(temp);
+}
+
+void openUrl( const wxString& url )
+{
+ if ( !wxLaunchDefaultBrowser( url ) )
+ {
+ wxLogWarning( _( "can't launch default browser" ) );
+ customMessageBox( SL_MAIN_ICON, _( "Couldn't launch browser. URL is: " ) + url, _( "Couldn't launch browser." ) );
+ }
+}
+
diff --git a/src/settings++/se_utils.h b/src/settings++/se_utils.h
new file mode 100644
index 0000000..38064d5
--- /dev/null
+++ b/src/settings++/se_utils.h
@@ -0,0 +1,44 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef SE_UTILS_H_
+#define SE_UTILS_H_
+
+#include <wx/string.h>
+#include <sstream>
+/** \name SPringSettings Utils
+ * these are necessary duplications for standalone mode atm
+ * \todo can prolly be avoided if properly use code from SL
+ * @{ */
+
+int fromString(const wxString& s);
+
+void openUrl(const wxString& url);
+
+template<class T>
+wxString towxString(T arg){
+ std::stringstream s;
+ s << arg;
+ return wxString(s.str().c_str(),wxConvUTF8);
+}
+/** @} */
+
+bool IsSettingsStandAlone();
+void SetSettingsStandAlone( bool value );
+
+#endif /*SE_UTILS_H_*/
+
diff --git a/src/settings++/settings.rc b/src/settings++/settings.rc
new file mode 100644
index 0000000..0b76bc3
--- /dev/null
+++ b/src/settings++/settings.rc
@@ -0,0 +1,2 @@
+springsettings ICON "../images/springsettings.ico"
+#include <wx/msw/wx.rc>
diff --git a/src/settings++/tab_abstract.cpp b/src/settings++/tab_abstract.cpp
new file mode 100644
index 0000000..ddfa718
--- /dev/null
+++ b/src/settings++/tab_abstract.cpp
@@ -0,0 +1,609 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#include "tab_abstract.h"
+#include <wx/string.h>
+#include <wx/gbsizer.h>
+#include <wx/event.h>
+#include <wx/defs.h>
+#include <wx/slider.h>
+#include <wx/log.h>
+#include <wx/checkbox.h>
+#include <wx/radiobut.h>
+#include <wx/combobox.h>
+#include <wx/spinctrl.h>
+
+#include "custom_dialogs.h"
+#include "../springunitsynclib.h"
+
+#include "Defs.hpp"
+#include "se_utils.h"
+#include "../settings.h"
+#include "presets.h"
+#include "../spinctld.h"
+#include "../utils/debug.h"
+
+intMap abstract_panel::intSettings;
+//stringMap abstract_panel::stringSettings;
+floatMap abstract_panel::floatSettings;
+
+bool abstract_panel::settingsChanged = false;
+//const category_sizes_map s_category_sizes ( entries_ , entries_ + sizeof(entries_[0]) );
+
+const Control intControls[] = {
+ // RO_SLI[8]
+ RO_SLI[0],RO_SLI[1],RO_SLI[2],RO_SLI[3],RO_SLI[4],RO_SLI[5],RO_SLI[6],RO_SLI[7],RO_SLI[8],
+ // VO_CBOX[3]
+ VO_CBOX[0],VO_CBOX[1],VO_CBOX[2],
+ //VO_RBUT[2] <- only one key
+ VO_RBUT[0],
+ // VO_SLI[1]
+ VO_SLI[0],
+ //VO_SLI_EXT[1]
+ VO_SLI_EXT[0],
+ // AO_SLI[3]
+ AO_SLI[0],AO_SLI[1],AO_SLI[2],AO_SLI[3],AO_SLI[4],AO_SLI[5],
+ // QA_CBOX[10]
+ QA_CBOX[0],QA_CBOX[1],QA_CBOX[2],QA_CBOX[3],QA_CBOX[4],QA_CBOX[5],QA_CBOX[6],QA_CBOX[7],QA_CBOX[8],
+ QA_CBOX[9],QA_CBOX[10],QA_CBOX[11],
+ //UI_CBOX[16]
+ UI_CBOX[0],UI_CBOX[1],UI_CBOX[2],UI_CBOX[3],UI_CBOX[4],UI_CBOX[5],UI_CBOX[6],UI_CBOX[7],UI_CBOX[8],
+ UI_CBOX[9],UI_CBOX[10],UI_CBOX[11],UI_CBOX[12],UI_CBOX[13],UI_CBOX[14],UI_CBOX[15],UI_CBOX[16],
+ //MO_SLI[5]
+ MO_SLI[0],MO_SLI[1],MO_SLI[2],MO_SLI[3],MO_SLI[4],
+ //MO_SLI_EXT[5]
+ MO_SLI_EXT[0],MO_SLI_EXT[1],MO_SLI_EXT[2],MO_SLI_EXT[3],MO_SLI_EXT[4],
+ //DO_SLI[1]
+ DO_SLI[0],
+ //DO_CBOX[1]
+ DO_CBOX[0],
+ //WR_COMBOX[1]
+ WR_COMBOX[0],
+ //MO_CBOX[2]
+ MO_CBOX[0],MO_CBOX[1],
+ //MO_RBUT[5] <- only first
+ MO_RBUT[0],
+ //RC_TEXT[2]
+ RC_TEXT[0],RC_TEXT[1],
+ //UI_ZOOM[1]
+ UI_ZOOM[0],
+ //W4_CONTROLS[7]
+ W4_CONTROLS[0],W4_CONTROLS[1],W4_CONTROLS[2],W4_CONTROLS[3],
+ W4_CONTROLS[4],W4_CONTROLS[5]
+
+};
+
+const Control floatControls[] = {
+ W4_CONTROLS[6]
+};
+
+const int intControls_size = sizeof(intControls) / sizeof(intControls[0] ) ;
+const int floatControls_size = sizeof(floatControls) / sizeof(floatControls[0] ) ;
+const int allControls_size = intControls_size + floatControls_size;
+
+abstract_panel::abstract_panel(wxWindow *parent, wxWindowID id , const wxString &title , const wxPoint& pos , const wxSize& size, long style)
+ : wxScrolledWindow(parent, id, pos, size, style|wxTAB_TRAVERSAL|wxHSCROLL,title) {
+// abstract_panel::expertModeEnadbled = false;
+ SetScrollbars( 10, 10, 62, 62 );
+}
+
+abstract_panel::~abstract_panel(void) {
+
+}
+
+bool abstract_panel::loadValuesIntoMap()
+{
+ try
+ {
+ for (int i = 0; i< intControls_size;++i)
+ {
+ intSettings[intControls[i].key] = configHandler.GetSpringConfigInt(intControls[i].key,fromString(intControls[i].def));
+ }
+ for (int i = 0; i< floatControls_size;++i)
+ {
+ float tmp = configHandler.GetSpringConfigFloat(floatControls[i].key,fromString(floatControls[i].def));
+ floatSettings[floatControls[i].key] = tmp;
+ }
+ }
+ catch (...)
+ {
+ customMessageBox(SS_MAIN_ICON,_("Could not access your settings.\n"), _("Error"), wxOK|wxICON_HAND, 0);
+ abstract_panel::settingsChanged = false;
+ return false;
+ }
+
+ return true; // SUCCESS!
+}
+
+void abstract_panel::loadDefaults()
+{
+ //const Control RO_SLI[9]
+ for (int i = 0;i< s_category_sizes[_T("RO_SLI")]; ++i)
+ intSettings[RO_SLI[i].key] = fromString( RO_SLI[i].def);
+
+ //const Control VO_CBOX[3]
+ for (int i = 0;i< s_category_sizes[_T("VO_CBOX")]; ++i)
+ intSettings[VO_CBOX[i].key] = fromString( VO_CBOX[i].def);
+
+ //const Control VO_RBUT[2]
+ for (int i = 0;i< s_category_sizes[_T("VO_RBUT")]; ++i)
+ intSettings[VO_RBUT[i].key] = fromString( VO_RBUT[i].def);
+
+ // const Control VO_SLI[1]
+ for (int i = 0;i< s_category_sizes[_T("VO_SLI")]; ++i)
+ intSettings[VO_SLI[i].key] = fromString( VO_SLI[i].def);
+
+ // const Control VO_SLI_EXT[1]
+ for (int i = 0;i< s_category_sizes[_T("VO_SLI_EXT")]; ++i)
+ intSettings[VO_SLI_EXT[i].key] = fromString( VO_SLI_EXT[i].def);
+
+// const Control AO_SLI[3]
+ for (int i = 0;i< s_category_sizes[_T("AO_SLI")]; ++i)
+ intSettings[AO_SLI[i].key] = fromString( AO_SLI[i].def);
+
+ // const Control QA_CBOX[10]
+ for (int i = 0;i< s_category_sizes[_T("QA_CBOX")]; ++i)
+ intSettings[QA_CBOX[i].key] = fromString( QA_CBOX[i].def);
+
+ // const Control UI_CBOX[17]
+ for (int i = 0;i< s_category_sizes[_T("UI_CBOX")]; ++i)
+ intSettings[UI_CBOX[i].key] = fromString(UI_CBOX [i].def);
+
+ // const Control MO_SLI[5]
+ for (int i = 0;i< s_category_sizes[_T("MO_SLI")]; ++i)
+ intSettings[MO_SLI[i].key] = fromString( MO_SLI[i].def);
+
+ // const Control MO_SLI_EXT[5]
+ for (int i = 0;i< s_category_sizes[_T("MO_SLI_EXT")]; ++i)
+ intSettings[MO_SLI_EXT[i].key] = fromString( MO_SLI_EXT[i].def);
+
+ // const Control DO_SLI[1]
+ for (int i = 0;i< s_category_sizes[_T("DO_SLI")]; ++i)
+ intSettings[DO_SLI[i].key] = fromString( DO_SLI[i].def);
+
+ // const Control DO_CBOX[2]
+ for (int i = 0;i< s_category_sizes[_T("DO_CBOX")]; ++i)
+ intSettings[DO_CBOX[i].key] = fromString( DO_CBOX[i].def);
+
+ // const Control WR_COMBOX[4]
+ for (int i = 0;i< s_category_sizes[_T("WR_COMBOX")]; ++i)
+ intSettings[WR_COMBOX[i].key] = fromString( WR_COMBOX[i].def);
+
+ // const Control MO_CBOX[2]
+ for (int i = 0;i< s_category_sizes[_T("MO_CBOX")]; ++i)
+ intSettings[MO_CBOX[i].key] = fromString( MO_CBOX[i].def);
+
+ // const Control MO_RBUT[5]
+ for (int i = 0;i< s_category_sizes[_T("MO_RBUT")]; ++i)
+ intSettings[MO_RBUT[i].key] = fromString(MO_RBUT [i].def);
+
+ // const Control RC_TEXT[2]
+ for (int i = 0;i< s_category_sizes[_T("RC_TEXT")]; ++i)
+ intSettings[RC_TEXT[i].key] = fromString( RC_TEXT[i].def);
+
+ // const Control UI_ZOOM[1]
+ for (int i = 0;i< s_category_sizes[_T("UI_ZOOM")]; ++i)
+ intSettings[UI_ZOOM[i].key] = fromString( UI_ZOOM[i].def);
+
+ for (int i = 0;i< s_category_sizes[_T("W4_CONTROLS")] - 1; ++i)
+ intSettings[W4_CONTROLS[i].key] = fromString( W4_CONTROLS[i].def);
+
+ floatSettings[W4_CONTROLS[ s_category_sizes[_T("W4_CONTROLS")] ].key] = fromString( W4_CONTROLS[ s_category_sizes[_T("W4_CONTROLS")] ].def);
+
+}
+
+void abstract_panel::OnSliderMove(wxCommandEvent& event) {
+
+ settingsChanged = true;
+
+ wxSlider* slider = (wxSlider*) event.GetEventObject();
+
+ int value = slider->GetValue();
+ int id = event.GetId();
+
+ switch (event.GetId()) {
+ case ID_RO_SLI_0: {
+ // shadow-map sizes
+ int val = slider->GetValue();
+
+ if (val < 1536) {
+ slider->SetValue(1024);
+ (intSettings)[RO_SLI[0].key]=1024;
+ }
+ if (val > 1536 && val < 3072) {
+ slider->SetValue(2048);
+ (intSettings)[RO_SLI[0].key]=2048;
+ }
+ if (val > 3072 && val < 6144) {
+ slider->SetValue(4096);
+ (intSettings)[RO_SLI[0].key]=4096;
+ }
+ if (val > 6144) {
+ slider->SetValue(8192);
+ (intSettings)[RO_SLI[0].key]=8192;
+ }
+ } break;
+
+ case ID_RO_SLI_1:
+ case ID_RO_SLI_2:
+ case ID_RO_SLI_3:
+ case ID_RO_SLI_4:
+ case ID_RO_SLI_5:
+ case ID_RO_SLI_6:
+ case ID_RO_SLI_7:
+ case ID_RO_SLI_8: {
+ int i = id - RO_SLI[0].id;
+ (intSettings)[RO_SLI[i].key]= value;
+ } break;
+
+
+ case ID_VO_SLI_0: {
+ (intSettings)[VO_SLI_EXT[0].key]= (value > 0)? 1: 0;
+ (intSettings)[VO_SLI[0].key]= value;
+ } break;
+
+ case ID_AO_SLI_0:
+ case ID_AO_SLI_1:
+ case ID_AO_SLI_2:
+ case ID_AO_SLI_3:
+ case ID_AO_SLI_4:
+ case ID_AO_SLI_5: {
+ int i = id - AO_SLI[0].id;
+ (intSettings)[AO_SLI[i].key]= value;
+ } break;
+
+
+ case ID_DO_SLI_0: { (intSettings)[DO_SLI[0].key]= value; } break;
+
+ case ID_MO_SLI_0: {
+ (intSettings)[MO_SLI[0].key]= value;
+ (intSettings)[MO_SLI_EXT[0].key]= ( value > 0 ? 1 : 0);
+ } break;
+ case ID_MO_SLI_1: {
+ (intSettings)[MO_SLI[1].key]= value;
+ (intSettings)[MO_SLI_EXT[1].key]= ( value > 0 ? 1 : 0);
+ } break;
+ case ID_MO_SLI_2: {
+ (intSettings)[MO_SLI[2].key]= value;
+ (intSettings)[MO_SLI_EXT[2].key]= ( value > 0 ? 1 : 0);
+ } break;
+ case ID_MO_SLI_3: {
+ (intSettings)[MO_SLI[3].key]= value;
+ (intSettings)[MO_SLI_EXT[3].key]= ( value > 0 ? 1 : 0);
+ } break;
+ case ID_MO_SLI_4: {
+ (intSettings)[MO_SLI[4].key]= value;
+ (intSettings)[MO_SLI_EXT[4].key]= ( value > 0 ? 1 : 0);
+ } break;
+ default:
+ wxLogDebugFunc( _T("unhandled case val") );
+ break;
+ }
+}
+
+
+void abstract_panel::OnTextUpdate(wxCommandEvent& event) {
+
+ settingsChanged = true;
+ int eventID = event.GetId();
+
+ if (eventID == ID_RES_CHOICES_LBOX_X || eventID == ID_RES_CHOICES_LBOX_Y)
+ {
+ wxTextCtrl* textField = (wxTextCtrl*) event.GetEventObject();
+ wxString wxStr = textField->GetValue();
+ long* res = new long;
+ bool success = (wxStr.ToLong(res));
+
+ switch (eventID) {
+ case ID_RES_CHOICES_LBOX_X: {
+ // TODO: input validation?
+ if (success)
+ (intSettings)[RC_TEXT[0].key]= int((*res));
+ } break;
+ case ID_RES_CHOICES_LBOX_Y: {
+ // TODO: input validation?
+ if (success)
+ (intSettings)[RC_TEXT[1].key]= int((*res));
+ } break;
+
+ default:
+ wxLogDebugFunc( _T("unhandled case val") );
+ break;
+ }
+ }
+
+
+}
+
+
+void abstract_panel::OnCheckBoxTick(wxCommandEvent& event) {
+
+ settingsChanged = true;
+
+ wxCheckBox* checkBox = (wxCheckBox*) event.GetEventObject();
+ int checked = checkBox->IsChecked();
+ int id = event.GetId();
+
+ switch (id) {
+ case ID_WINDOWP_VO_CBOX_0:
+ case ID_WINDOWP_VO_CBOX_1:
+ case ID_WINDOWP_VO_CBOX_2: {
+ int i = id - VO_CBOX[0].id;
+ (intSettings)[VO_CBOX[i].key]= checked;
+ } break;
+
+ case ID_WINDOWP_QA_CBOX_0:
+ case ID_WINDOWP_QA_CBOX_1:
+ case ID_WINDOWP_QA_CBOX_2:
+ case ID_WINDOWP_QA_CBOX_3:
+ case ID_WINDOWP_QA_CBOX_4:
+ case ID_WINDOWP_QA_CBOX_5:
+ case ID_WINDOWP_QA_CBOX_6:
+ case ID_WINDOWP_QA_CBOX_7:
+ case ID_WINDOWP_QA_CBOX_8:
+ case ID_WINDOWP_QA_CBOX_9:
+ case ID_WINDOWP_QA_CBOX_10:
+ case ID_WINDOWP_QA_CBOX_11:{
+ int i = id - QA_CBOX[0].id;
+ (intSettings)[QA_CBOX[i].key]= checked;
+ } break;
+
+ //case ID_WINDOWP_UI_CBOX_0:
+ case ID_WINDOWP_UI_CBOX_1:
+ case ID_WINDOWP_UI_CBOX_2:
+ case ID_WINDOWP_UI_CBOX_3:
+ case ID_WINDOWP_UI_CBOX_4:
+ case ID_WINDOWP_UI_CBOX_5:
+ case ID_WINDOWP_UI_CBOX_6:
+ case ID_WINDOWP_UI_CBOX_7:
+ case ID_WINDOWP_UI_CBOX_8:
+ case ID_WINDOWP_UI_CBOX_9:
+ case ID_WINDOWP_UI_CBOX_10:
+ case ID_WINDOWP_UI_CBOX_11:
+ case ID_WINDOWP_UI_CBOX_12:
+ case ID_WINDOWP_UI_CBOX_13:
+ case ID_WINDOWP_UI_CBOX_14:
+ case ID_WINDOWP_UI_CBOX_15:
+ case ID_WINDOWP_UI_CBOX_16:
+ case ID_WINDOWP_UI_CBOX_17:
+ case ID_WINDOWP_UI_CBOX_18:{
+ int i = id - UI_CBOX[0].id;
+ (intSettings)[UI_CBOX[i].key]= checked;
+ } break;
+
+ case ID_W4_BumpWaterBlurReflection:
+ case ID_W4_BumpWaterReflection:
+ case ID_W4_BumpWaterShoreWaves:
+ case ID_W4_BumpWaterUseDepthTexture:{
+ int i = id - W4_CONTROLS[0].id;
+ (intSettings)[W4_CONTROLS[i].key]= checked;
+ } break;
+
+
+ case ID_WINDOWP_DO_CBOX_0: { (intSettings)[DO_CBOX[0].key]= checked; } break;
+
+
+ case ID_WINDOWC_MO_CBOX_0: { (intSettings)[MO_CBOX[0].key]= checked; } break;
+ case ID_WINDOWC_MO_CBOX_1: { (intSettings)[MO_CBOX[1].key]= checked; } break;
+
+ default:
+ wxLogDebugFunc( _T("unhandled case val") );
+ break;
+ }
+}
+
+
+void abstract_panel::OnRadioButtonToggle(wxCommandEvent& event) {
+
+ settingsChanged = true;
+
+ wxRadioButton* radioButton = (wxRadioButton*) event.GetEventObject();
+ radioButton->GetValue();
+
+ switch (event.GetId()) {
+ case ID_WINDOWP_VO_RBUT_0: { (intSettings)[VO_RBUT[0].key]= 16; } break;
+ case ID_WINDOWP_VO_RBUT_1: { (intSettings)[VO_RBUT[0].key]= 24; } break;
+
+ case ID_WINDOWC_MO_RBUT_0: { (intSettings)[MO_RBUT[0].key]= 1; } break; // OH button (CamMode 1)
+ case ID_WINDOWC_MO_RBUT_1: { (intSettings)[MO_RBUT[1].key]= 3; } break; // ROH button (CamMode 2)
+ case ID_WINDOWC_MO_RBUT_2: { (intSettings)[MO_RBUT[2].key]= 2; } break; // TW button (CamMode 3)
+ case ID_WINDOWC_MO_RBUT_3: { (intSettings)[MO_RBUT[3].key]= 0; } break; // FPS button (CamMode 0)
+ case ID_WINDOWC_MO_RBUT_4: { (intSettings)[MO_RBUT[4].key]= 4; } break; // FC button (CamMode 4)
+
+ default:
+ wxLogDebugFunc( _T("unhandled case val") );
+ break;
+ }
+}
+
+void abstract_panel::OnComboBoxChange(wxCommandEvent& event) {
+
+ settingsChanged = true;
+
+ wxComboBox* comboBox = (wxComboBox*) event.GetEventObject();
+ const wxString choice = comboBox->GetValue();
+
+ switch (event.GetId())
+ {
+ case ID_WINDOWP_WR_COMBOX:
+ {
+ int choiceIndex=0;
+ for (unsigned int i =1; i<sizeof(WR_COMBOX_CHOICES)/sizeof(WR_COMBOX_CHOICES[0]);++i)
+ {
+ if (choice==WR_COMBOX_CHOICES[i])
+ choiceIndex = i;
+ }
+ switch (choiceIndex) {
+ case 0: { (intSettings)[WR_COMBOX[0].key]= 0; } break; // Basic
+ case 1: { (intSettings)[WR_COMBOX[0].key]= 1; } break; // Refl
+ case 2: { (intSettings)[WR_COMBOX[0].key]= 3; } break; // Refl + Refr
+ case 3: { (intSettings)[WR_COMBOX[0].key]= 2; } break; // Dyna
+ case 4: { (intSettings)[WR_COMBOX[0].key]= 4; } break; // BumpWater
+
+ default:
+ wxLogDebugFunc( _T("unhandled case val") );
+ break;
+ }
+ break;
+ }
+
+ case ID_W4_BumpWaterRefraction:
+ {
+ int choiceIndex=0;
+ for (unsigned int i =1; i<sizeof(W4_REFRACTION_CHOICES)/sizeof(W4_REFRACTION_CHOICES[0]);++i)
+ {
+ if (choice==W4_REFRACTION_CHOICES[i])
+ choiceIndex = i;
+ }
+
+ (intSettings)[W4_CONTROLS[5].key]= choiceIndex;
+ break;
+ }
+
+ case ID_W4_BumpWaterTexSizeReflection:
+ {
+ int choiceIndex=0;
+ for (unsigned int i =1; i<sizeof(W4_TEXSIZE_CHOICES)/sizeof(W4_TEXSIZE_CHOICES[0]);++i)
+ {
+ if (choice==W4_TEXSIZE_CHOICES[i])
+ choiceIndex = i;
+ }
+
+ long val = 128;
+ choice.ToLong( &val );
+ (intSettings)[W4_CONTROLS[4].key]= val;
+ break;
+ }
+
+ case ID_SIMPLE_QUAL_CBX:
+ {
+
+ for (int i=0; i<prVal_RenderQuality_size;++i)
+ {
+ presetValues<int,5> pop = prVal_RenderQuality[i];
+ int k = (pop.values[choice]);
+
+ (intSettings)[prVal_RenderQuality[i].key]= k;
+ }
+
+ for (int i=0; i<prVal_W4_size;++i)
+ {
+ presetValues<int,5> pop = prVal_W4[i];
+ int k = (pop.values[choice]);
+
+ (intSettings)[prVal_W4[i].key]= k;
+ }
+
+ presetValues<float,5> pop = pr_w4_BumpWaterAnisotropy;
+ float k = (pop.values[choice]);
+ wxString key = pr_w4_BumpWaterAnisotropy.key;
+ (floatSettings)[key] = k;
+ //float debug = (floatSettings)[key]
+ break;
+ }
+ case ID_SIMPLE_DETAIL_CBX:
+ {
+ for (int i=0; i<prVal_RenderDetail_size;++i)
+ {
+ presetValues<int,3> pop = prVal_RenderDetail[i];
+ int k = (pop.values[choice]);
+ (intSettings)[prVal_RenderDetail[i].key]= k;
+ }
+ break;
+ }
+ case ID_SIMPLE_MODE_CBX:
+ {
+ int modeIndex=-1;
+ for (int i=0; i<vl_Resolution_Str_size;++i)
+ {
+ if (choice == vl_Resolution_Str[i])
+ modeIndex = i;
+ }
+ if (modeIndex!=-1)
+ {
+ (intSettings)[_T("XResolution")] = vl_Resolution_X[modeIndex];
+ (intSettings)[_T("YResolution")] = vl_Resolution_Y[modeIndex];
+ if (modeIndex > vl_Resolution_startOfDualScreenRes)
+ (intSettings)[_T("DualScreenMode")] = 1;
+ else
+ (intSettings)[_T("DualScreenMode")] = 0;
+ }
+ break;
+ }
+
+ default:
+ wxLogDebugFunc( _T("unhandled case val") );
+ break;
+ }
+}
+void abstract_panel::OnSpinControlChange(wxSpinEvent& event)
+{
+ if (event.GetId()==ID_WINDOWP_UI_MW_SPD)
+ {
+ wxSpinCtrl* zoom = (wxSpinCtrl*) event.GetEventObject();
+ (intSettings)[UI_ZOOM[0].key] = zoom->GetValue();
+ settingsChanged = true;
+ }
+ if (event.GetId()==ID_W4_BumpWaterAnisotropy)
+ {
+ wxSpinCtrlDbl* aniso = (wxSpinCtrlDbl*) event.GetEventObject();
+ (floatSettings)[W4_CONTROLS[6].key] = aniso->GetValue();
+ settingsChanged = true;
+ }
+}
+
+//TODO inquire about floatsettings
+bool abstract_panel::saveSettings() {
+ try {
+ for (intMap::iterator i = intSettings.begin(); i != intSettings.end();++i)
+ {
+ configHandler.SetSpringConfigInt(i->first,i->second);
+ }
+// for (stringMap::iterator s = stringSettings.begin(); s != stringSettings.end();++s)
+// {
+// //not used
+// //configHandler.SetSpringConfigString(s->first,s->second);
+// }
+ for (floatMap::iterator f = floatSettings.begin(); f != floatSettings.end();++f)
+ {
+ configHandler.SetSpringConfigFloat(f->first,f->second);
+ }
+ } catch (...) {
+ customMessageBox(SS_MAIN_ICON,_("Could not save, unitsync not properly loaded"), _("SpringSettings Error"), wxOK|wxICON_HAND, 0);
+ return false;
+ }
+
+ return true;
+}
+
+void abstract_panel::updateControls(int /*unused*/)
+{}
+
+BEGIN_EVENT_TABLE(abstract_panel, wxPanel)
+ EVT_SLIDER(wxID_ANY, abstract_panel::OnSliderMove)
+ EVT_TEXT(wxID_ANY, abstract_panel::OnTextUpdate)
+ EVT_CHECKBOX(wxID_ANY, abstract_panel::OnCheckBoxTick)
+ EVT_RADIOBUTTON(wxID_ANY, abstract_panel::OnRadioButtonToggle)
+// EVT_IDLE( abstract_panel::update)
+ EVT_SPINCTRL(wxID_ANY, abstract_panel::OnSpinControlChange)
+ EVT_COMBOBOX(wxID_ANY, abstract_panel::OnComboBoxChange)
+ END_EVENT_TABLE()
diff --git a/src/settings++/tab_abstract.h b/src/settings++/tab_abstract.h
new file mode 100644
index 0000000..e0153b7
--- /dev/null
+++ b/src/settings++/tab_abstract.h
@@ -0,0 +1,95 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef __TAB_ABSTRACT_h__
+#define __TAB_ABSTRACT_h__
+
+#include <wx/scrolwin.h>
+
+#include <map>
+class wxString;
+class wxCommandEvent;
+
+class wxWindow;
+class wxPoint;
+class wxSize;
+class wxCloseEvent;
+class wxSpinEvent;
+
+
+typedef std::map<wxString,int> intMap;
+typedef std::map<wxString,wxString> stringMap;
+typedef std::map<wxString,float> floatMap;
+
+template <int numerator, int denominator = 1>
+class Scaler
+{
+ private:
+
+
+ public:
+ template < typename T >
+ static T Up( const T val )
+ {
+ const double fac = denominator != 0 ? numerator/(double)denominator : numerator;
+ return (T) ( fac * val );
+ }
+
+ template < typename T >
+ static T Down ( const T val )
+ {
+ const double fac = denominator != 0 ? numerator/(double)denominator : numerator;
+ return (T) ( val / fac );
+ }
+};
+
+
+class abstract_panel : public wxScrolledWindow
+{
+
+ public:
+ abstract_panel(wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("Project2"),
+ const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
+ virtual ~abstract_panel();
+
+ void OnSliderMove(wxCommandEvent&);
+ void OnTextUpdate(wxCommandEvent&);
+ void OnCheckBoxTick(wxCommandEvent&);
+ void OnRadioButtonToggle(wxCommandEvent&);
+ //void update(wxIdleEvent&);
+ virtual void OnComboBoxChange(wxCommandEvent& event);
+ static intMap intSettings;
+ //static stringMap stringSettings;
+ static floatMap floatSettings;
+ static bool settingsChanged;
+ static bool saveSettings();
+
+ static void loadDefaults();
+ virtual void updateControls(int what_to_update);
+ static bool loadValuesIntoMap();
+ void OnSpinControlChange(wxSpinEvent& event);
+ protected:
+ void OnClose(wxCloseEvent& event);
+ void CreateGUIControls();
+
+ private:
+
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
diff --git a/src/settings++/tab_audio.cpp b/src/settings++/tab_audio.cpp
new file mode 100644
index 0000000..de776a6
--- /dev/null
+++ b/src/settings++/tab_audio.cpp
@@ -0,0 +1,88 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#include "tab_audio.h"
+#include "se_utils.h"
+#include <wx/string.h>
+#include <wx/sizer.h>
+#include <wx/event.h>
+#include <wx/defs.h>
+#include <wx/slider.h>
+#include <wx/stattext.h>
+#include <wx/statbox.h>
+
+#include "Defs.hpp"
+
+void audio_panel::initAudioSizer(wxStaticBoxSizer* sizer) {
+
+ for (int i = 0; i < ctrl_audio_sliders_size; ++i ) {
+ ctrl_audio_sliders[i] = new wxSlider(this, AO_SLI[i].id, 1, 0, i == 0 ? 128 : 100, WX_DEF_P, WX_SLI_S, SLI_STYLE, WX_DEF_V);
+ ctrl_audio_sliders[i]->SetToolTip(AO_SLI[i].tTip[0]);
+ ctrl_audio_sliders[i]->SetTickFreq( 10, 1 );
+ sizer->Add( new wxStaticText(this, -1, (AO_SLI[i].lbl)), 0, wxTOP, 15 );
+ sizer->Add( ctrl_audio_sliders[i], 0, wxALIGN_LEFT, 0 );
+ }
+ ctrl_audio_sliders[0]->SetTickFreq((128 / 10 ) ,1);
+}
+
+audio_panel::audio_panel(wxWindow *parent, wxWindowID id , const wxString &title , const wxPoint& pos , const wxSize& size, long style)
+ : abstract_panel(parent, id , title , pos , size, style)
+{
+ ctrl_audio_sliders = new wxSlider*[ctrl_audio_sliders_size];
+ parentSizer = new wxBoxSizer(wxHORIZONTAL); // main window sizer (three columns)
+ childLSizer = new wxBoxSizer(wxVERTICAL); // main window left column sizer
+
+ // sizers for static boxes containing sliders, checkboxes, radiobuttons
+ audioSizer = new wxStaticBoxSizer(new wxStaticBox(this, -1, _("Audio Options"),
+ WX_DEF_P, wxSize(230, 100), 0, wxEmptyString), wxVERTICAL);
+ initAudioSizer(audioSizer);
+
+
+ childLSizer->Add(0, 5, 0);
+ childLSizer->Add(audioSizer,0,wxEXPAND|wxALL,5);
+
+ parentSizer->Add(10, 0, 0);
+ parentSizer->Add(childLSizer,0,wxEXPAND|wxTOP,5);
+
+ updateControls(UPDATE_ALL);
+ SetSizer(parentSizer); // true --> delete old sizer if present
+}
+
+void audio_panel::updateControls(int /*unused*/)
+{
+ for (int i = 0; i < ctrl_audio_sliders_size; ++i ) {
+ ctrl_audio_sliders[i]->SetValue(intSettings[AO_SLI[i].key]);
+ }
+}
+
+audio_panel::~audio_panel(void) {
+
+}
+
+
+BEGIN_EVENT_TABLE(audio_panel, wxPanel)
+ EVT_SLIDER(wxID_ANY, audio_panel::OnSliderMove)
+// EVT_TEXT(wxID_ANY, audio_panel::OnTextUpdate)
+// EVT_CHECKBOX(wxID_ANY, audio_panel::OnCheckBoxTick)
+ EVT_RADIOBUTTON(wxID_ANY, audio_panel::OnRadioButtonToggle)
+// EVT_IDLE( audio_panel::update)
+END_EVENT_TABLE()
diff --git a/src/settings++/tab_audio.h b/src/settings++/tab_audio.h
new file mode 100644
index 0000000..eaf1b47
--- /dev/null
+++ b/src/settings++/tab_audio.h
@@ -0,0 +1,55 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef __TAB_AUDIO_h__
+#define __TAB_AUDIO_h__
+
+#include "tab_abstract.h"
+
+
+class wxSlider;
+class wxStaticBoxSizer;
+class wxString;
+class wxWindow;
+class wxPoint;
+class wxSize;
+class wxCloseEvent;
+
+class audio_panel : public abstract_panel
+{
+
+ public:
+ audio_panel(wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("Project2"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
+ virtual ~audio_panel();
+
+ void initAudioSizer(wxStaticBoxSizer*);
+ void updateControls(int);
+ protected:
+ void OnClose(wxCloseEvent& event);
+ void CreateGUIControls();
+
+ wxSlider** ctrl_audio_sliders;
+ static const int ctrl_audio_sliders_size = 6;
+
+ wxSizer* parentSizer ; // main window sizer (three columns)
+ wxSizer* childLSizer;
+ wxStaticBoxSizer* audioSizer;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
diff --git a/src/settings++/tab_quality_video.cpp b/src/settings++/tab_quality_video.cpp
new file mode 100644
index 0000000..1929a69
--- /dev/null
+++ b/src/settings++/tab_quality_video.cpp
@@ -0,0 +1,341 @@
+/**
+c This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "tab_quality_video.h"
+#include "se_utils.h"
+#include <wx/string.h>
+#include <wx/sizer.h>
+#include <wx/event.h>
+#include <wx/defs.h>
+#include <wx/slider.h>
+#include <wx/checkbox.h>
+#include <wx/stattext.h>
+#include <wx/checkbox.h>
+#include <wx/radiobut.h>
+#include <wx/combobox.h>
+#include "../spinctld.h"
+
+#include "Defs.hpp"
+
+void tab_quality_video::initVideoSizer(wxFlexGridSizer* sizer) {
+
+
+ // i < "sizeof"(VO_CBOX)
+ for (int i = 0; i < ctrl_vo_Boxes_size; i++) {
+ ctrl_vo_Boxes[i] = new wxCheckBox(this, VO_CBOX[i].id, (VO_CBOX[i].lbl));
+ ctrl_vo_Boxes[i]->SetToolTip(VO_CBOX[i].tTip[0]);
+ sizer->Add(ctrl_vo_Boxes[i], 0, wxTOP, (i == 0)? 5 : 0);
+ }
+
+ ctrl_x_res = new wxTextCtrl(this, ID_RES_CHOICES_LBOX_X,_T(""), WX_DEF_P, wxSize(60, 20), 0);
+ ctrl_y_res = new wxTextCtrl(this, ID_RES_CHOICES_LBOX_Y, _T(""), WX_DEF_P, wxSize(60, 20), 0);
+ ctrl_x_res->SetToolTip(RC_TEXT[0].tTip[0]);
+ ctrl_y_res->SetToolTip(RC_TEXT[1].tTip[0]);
+
+
+ wxSizer* subSizer = new wxBoxSizer(wxHORIZONTAL);
+
+ subSizer->Add(ctrl_x_res, 0, wxALIGN_LEFT, 10);
+ subSizer->Add(5, 0, 0);
+ subSizer->Add(new wxStaticText(this, -1, wxT("x")), 0, wxTOP | wxBOTTOM, 0);
+ subSizer->Add(5, 0, 0);
+ subSizer->Add(ctrl_y_res, 0, wxALIGN_RIGHT, 10);
+
+ wxSizer* subSizer2 = new wxBoxSizer(wxVERTICAL);
+ subSizer2->Add(new wxStaticText(this, -1, _("Screen Resolution")), 1, wxTOP|wxEXPAND , 10);
+ subSizer2->Add(subSizer);
+ sizer->Add(subSizer2);
+ sizer->Add(0,5,0);
+
+}
+
+void tab_quality_video::updateControls(int what_to_update)
+{
+ if (what_to_update == UPDATE_ALL)
+ {
+ //the rest
+ for (int i = 5; i < 7; i++) {
+ ctrl_qa_Boxes[i]->SetValue(intSettings[QA_CBOX[i].key]);
+ }
+
+ for (int i = 0; i < ctrl_vo_Boxes_size; i++) {
+ ctrl_vo_Boxes[i]->SetValue(intSettings[VO_CBOX[i].key]);
+ }
+ }
+
+ if (what_to_update == UPDATE_VIDEO_MODE || what_to_update == UPDATE_ALL)
+ {
+ ctrl_x_res->SetValue(wxString::Format( _("%d"),intSettings[RC_TEXT[0].key]));
+ ctrl_y_res->SetValue(wxString::Format( _("%d"),intSettings[RC_TEXT[1].key]));
+ }
+ if (what_to_update == UPDATE_QA_BOXES || what_to_update == UPDATE_ALL)
+ {
+ //option 7-9 are not on presets
+ for (int i = 0; i < 9; i++) {
+ ctrl_qa_Boxes[i]->SetValue(intSettings[QA_CBOX[i].key]);
+ }
+ for (int i = 10; i < ctrl_qa_Boxes_size; i++) {
+ ctrl_qa_Boxes[i]->SetValue(intSettings[QA_CBOX[i].key]);
+ }
+
+ m_enable_w4 = false;
+ int waterOptIndex = 0;
+ int waterSetting = intSettings[WR_COMBOX[0].key];
+ switch (waterSetting)
+ {
+ case 0:
+ case 1: waterOptIndex = waterSetting; break;
+ case 2: waterOptIndex = 3; break;
+ case 3: waterOptIndex = 2; break;
+ case 4: waterOptIndex = 4; m_enable_w4 = true; break;
+ }
+ ctrl_waterQ_CBox->SetValue(WR_COMBOX_CHOICES[waterOptIndex]);
+
+ int useFSAA = intSettings[VO_SLI_EXT[0].key];
+ int FSAALev = intSettings[VO_SLI[0].key];
+ ctrl_fsaa_slider->SetValue((useFSAA == 1)? FSAALev: 0);
+
+ switch (intSettings[VO_RBUT[0].key]) {
+ case 16: { ctrl_z_radio1->SetValue(1); } break;
+ case 24: { ctrl_z_radio2->SetValue(1); } break;
+ }
+
+ }
+ if (what_to_update == UPDATE_W4_CONTROLS || what_to_update == UPDATE_ALL)
+ {
+ for ( unsigned int i = 0; i < m_w4_controls.size(); ++i )
+ {
+ wxControl* tmp = m_w4_controls[i];
+ tmp->Enable( m_enable_w4 );
+ switch ( i )
+ {
+ case 0: case 1: case 2: case 3:
+ ( (wxCheckBox*)tmp )->SetValue( intSettings[W4_CONTROLS[i].key ] );
+ break;
+ case 4:{
+ int val = intSettings[W4_CONTROLS[i].key ];
+ for ( unsigned int j = 0; j < sizeof(W4_TEXSIZE_CHOICES)/sizeof(W4_TEXSIZE_CHOICES[0]); ++j){
+ if ( W4_TEXSIZE_CHOICES[j] == towxString( val ) )
+ ( (wxComboBox*)tmp)->SetValue( W4_TEXSIZE_CHOICES[ j ] );
+ }
+ }
+ break;
+ case 5:
+ ( (wxComboBox*)tmp)->SetValue( W4_REFRACTION_CHOICES[ intSettings[W4_CONTROLS[i].key ] ] );
+ break;
+ case 6:
+ //doesn't work if catsed from wxControl like the others
+ double tmpval = double(floatSettings[W4_CONTROLS[i].key ]) ;
+ m_aniso_spin->SetValue(tmpval);
+ break;
+ }
+ }
+
+ }
+
+
+}
+
+void tab_quality_video::initQualitySizer(wxFlexGridSizer* sizer)
+{
+ sizer->Add(new wxStaticText(this, -1, _("If an option needs special hardware to work\n"
+ "it will be mentioned in the tooltip.")), 1, wxTOP|wxEXPAND , 10);
+
+ // i < 8 with High resolution LOS textures
+ // i < 7 without
+ for (int i = 0; i < ctrl_qa_Boxes_size-3; i++) {
+ ctrl_qa_Boxes[i] = new wxCheckBox(this, QA_CBOX[i].id, (QA_CBOX[i].lbl));
+ //ctrl_qa_Boxes[i]->SetValue(configHandler.GetSpringConfigInt(QA_CBOX[i].key,fromString(QA_CBOX[i].def)));
+ ctrl_qa_Boxes[i]->SetToolTip(QA_CBOX[i].tTip[0]);
+ sizer->Add(ctrl_qa_Boxes[i], 0, wxTOP, (i == 0)? 5: 0);
+ }
+
+ wxSizer* subSizer = new wxBoxSizer(wxVERTICAL);
+ subSizer->Add(new wxStaticText(this, -1, _("Water Quality")), 0, wxTOP| wxEXPAND, 10);
+ ctrl_waterQ_CBox = new wxComboBox(this, ID_WINDOWP_WR_COMBOX, WR_COMBOX_CHOICES[0], wxDefaultPosition, wxSize(220,21),
+ 5,WR_COMBOX_CHOICES,wxCB_DROPDOWN|wxCB_READONLY);
+ ctrl_waterQ_CBox->SetToolTip(WR_COMBOX[0].tTip[0]);
+ subSizer->Add(ctrl_waterQ_CBox, 0, wxBOTTOM, 5);
+
+ sizer->Add(subSizer,0, wxBOTTOM, 5);
+
+}
+
+void tab_quality_video::initAASizer(wxFlexGridSizer* sizer){
+ for (int i = 10; i < ctrl_qa_Boxes_size; i++) {
+ ctrl_qa_Boxes[i] = new wxCheckBox(this, QA_CBOX[i].id, (QA_CBOX[i].lbl));
+ //ctrl_qa_Boxes[i]->SetValue(configHandler.GetSpringConfigInt(QA_CBOX[i].key,fromString(QA_CBOX[i].def)));
+ ctrl_qa_Boxes[i]->SetToolTip(QA_CBOX[i].tTip[0]);
+ sizer->Add(ctrl_qa_Boxes[i], 0, wxTOP, (i == 10)? 5: 0);
+ }
+ wxSizer* subsizer = new wxBoxSizer(wxVERTICAL);
+
+ ctrl_fsaa_slider = new wxSlider(this, VO_SLI[0].id, 0, 0, 16, WX_DEF_P, WX_SLI_S, SLI_STYLE, WX_DEF_V);
+ ctrl_fsaa_slider->SetToolTip(VO_SLI[0].tTip[0]);
+ subsizer->Add(new wxStaticText(this, -1, (VO_SLI[0].lbl)), 0, wxTOP|wxEXPAND, 10);
+ subsizer->Add(ctrl_fsaa_slider, 0, wxALIGN_LEFT|wxBOTTOM|wxEXPAND, 5);
+ sizer->Add(subsizer);
+}
+
+void tab_quality_video::initZBufferSizer(wxFlexGridSizer* sizer)
+{
+ //z-buffer
+
+ sizer->Add(new wxStaticText(this, -1, _("Resolution in bit")), 0, wxTOP ,15);
+
+ ctrl_z_radio1 = new wxRadioButton(this, VO_RBUT[0].id, (VO_RBUT[0].lbl), WX_DEF_P, WX_DEF_S, wxRB_GROUP, WX_DEF_V);
+ ctrl_z_radio2 = new wxRadioButton(this, VO_RBUT[1].id, (VO_RBUT[1].lbl), WX_DEF_P, WX_DEF_S, 0, WX_DEF_V);
+
+ ctrl_z_radio1->SetToolTip(VO_RBUT[0].tTip[0]);
+ ctrl_z_radio2->SetToolTip(VO_RBUT[1].tTip[0]);
+
+ sizer->Add(ctrl_z_radio1, 0, wxTOP, 0);
+ sizer->Add(ctrl_z_radio2, 0, wxBOTTOM, 10);
+
+}
+
+void tab_quality_video::initW4Sizer(wxSizer* sizer)
+{
+ for ( int i = 0; i < 4; ++i ) {
+ wxCheckBox* blurChk = new wxCheckBox( this, W4_CONTROLS[i].id, W4_CONTROLS[i].lbl );
+ m_w4_controls.push_back( (wxControl*) blurChk );
+ blurChk->SetToolTip( W4_CONTROLS[i].tTip[0] );
+ sizer->Add( blurChk, 0, wxEXPAND|wxALL, 4 );
+ }
+
+ sizer->Add(new wxStaticText(this, -1, (W4_CONTROLS[4].lbl)) , 0, wxTOP|wxEXPAND, 5);
+ wxComboBox* texsizeCom = new wxComboBox(this, W4_CONTROLS[4].id, W4_TEXSIZE_CHOICES[0], wxDefaultPosition, wxSize(220,21),
+ 4,W4_TEXSIZE_CHOICES,wxCB_DROPDOWN|wxCB_READONLY);
+ texsizeCom->SetToolTip(W4_CONTROLS[4].tTip[0]);
+ m_w4_controls.push_back( (wxControl*) texsizeCom );
+ sizer->Add( texsizeCom, 0, wxEXPAND|wxALL, 4 );
+
+ sizer->Add(new wxStaticText(this, -1, (W4_CONTROLS[5].lbl)) , 0, wxTOP|wxEXPAND, 5);
+ wxComboBox* refractionCom = new wxComboBox(this, W4_CONTROLS[5].id, W4_REFRACTION_CHOICES[0], wxDefaultPosition, wxSize(220,21),
+ 3,W4_REFRACTION_CHOICES,wxCB_DROPDOWN|wxCB_READONLY);
+ refractionCom->SetToolTip(W4_CONTROLS[5].tTip[0]);
+ m_w4_controls.push_back( (wxControl*) refractionCom );
+ sizer->Add( refractionCom, 0, wxEXPAND|wxALL, 4 );
+
+ sizer->Add(new wxStaticText(this, -1, (W4_CONTROLS[6].lbl)) , 0, wxTOP|wxEXPAND, 5);
+ m_aniso_spin = new wxSpinCtrlDbl();
+ m_aniso_spin->Create(this, W4_CONTROLS[6].id, _T(""),
+ wxDefaultPosition, wxDefaultSize, 0, 0.f, 6.f,
+ 0.f,0.25f, wxSPINCTRLDBL_AUTODIGITS, _T(""));
+ m_aniso_spin->SetToolTip(W4_CONTROLS[6].tTip[0]);
+ m_w4_controls.push_back( (wxControl*) m_aniso_spin );
+ sizer->Add( m_aniso_spin, 0, wxEXPAND|wxALL, 4 );
+
+
+}
+
+
+
+tab_quality_video::tab_quality_video(wxWindow *parent, wxWindowID id , const wxString &title , const wxPoint& pos ,
+ const wxSize& size, long style)
+: abstract_panel(parent, id , title , pos , size, style) {
+ ctrl_qa_Boxes = new wxCheckBox*[ctrl_qa_Boxes_size];
+ ctrl_vo_Boxes = new wxCheckBox*[ctrl_vo_Boxes_size];
+ parentSizer = new wxFlexGridSizer(3,0,0);
+ leftSizer = new wxFlexGridSizer(1,15,0);
+ middleSizer = new wxFlexGridSizer(1,15,0);
+ rightSizer = new wxFlexGridSizer(1,15,0);//for info
+ SizerA = new wxFlexGridSizer(1,15,10);
+ SizerB = new wxFlexGridSizer(1,15,10);
+ SizerC = new wxFlexGridSizer(1,15,10);
+ SizerD = new wxFlexGridSizer(1,5,10);
+ SizerE = new wxBoxSizer(wxVERTICAL);
+ boxA = new wxStaticBoxSizer(wxVERTICAL ,this,_("Render Quality Options"));
+ boxB = new wxStaticBoxSizer(wxVERTICAL ,this,_("Video Mode Options"));
+ boxC = new wxStaticBoxSizer(wxVERTICAL ,this,_("Anti-Aliasing Options"));
+ boxD = new wxStaticBoxSizer(wxVERTICAL ,this,_("Z-/Depth-Buffer"));
+ boxE = new wxStaticBoxSizer(wxVERTICAL ,this,_("Bump-mapped Water"));
+ SizerA->AddGrowableCol(0);
+ SizerB->AddGrowableCol(0);
+ SizerC->AddGrowableCol(0);
+ SizerD->AddGrowableCol(0);
+
+ initVideoSizer(SizerB);
+ initZBufferSizer(SizerD);
+ initQualitySizer(SizerA);
+ initAASizer(SizerC);
+ initW4Sizer(SizerE);
+
+ SizerA->Fit(this);
+ SizerA->SetSizeHints(this);
+ SizerB->Fit(this);
+ SizerB->SetSizeHints(this);
+ SizerC->Fit(this);
+ SizerC->SetSizeHints(this);
+ SizerD->Fit(this);
+ SizerD->SetSizeHints(this);
+ SizerE->Fit(this);
+ SizerE->SetSizeHints(this);
+
+ boxA->Add(SizerA,1,wxEXPAND);
+ boxB->Add(SizerB,1,wxEXPAND);
+ boxC->Add(SizerC,1,wxEXPAND);
+ boxD->Add(SizerD,1,wxEXPAND);
+ boxE->Add(SizerE,1,wxEXPAND);
+ leftSizer->Add(boxB,1,wxEXPAND|wxALL,5);
+ rightSizer->Add(boxC,1,wxEXPAND|wxALL,5);
+ rightSizer->Add(boxE,1,wxEXPAND|wxALL,5);
+ middleSizer->Add(boxA,1,wxEXPAND|wxALL,5);
+ leftSizer->Add(boxD,1,wxEXPAND|wxALL,5);
+ parentSizer->Add(leftSizer,0,wxALL|wxEXPAND,10);
+ parentSizer->Add(middleSizer,0,wxALL|wxEXPAND,10);
+ parentSizer->Add(rightSizer,0,wxALL|wxEXPAND,10);
+
+ updateControls(UPDATE_ALL);
+
+ SetSizer(parentSizer, true); // true --> delete old sizer if present
+
+
+}
+
+tab_quality_video::~tab_quality_video(void) {
+
+}
+
+void tab_quality_video::OnComboBoxChange(wxCommandEvent& event)
+{
+ if ( event.GetId() == ID_WINDOWP_WR_COMBOX )
+ {
+ wxComboBox* comboBox = (wxComboBox*) event.GetEventObject();
+ const wxString choice = comboBox->GetValue();
+ m_enable_w4 = ( choice == WR_COMBOX_CHOICES[4] );
+ updateControls( UPDATE_W4_CONTROLS );
+ }
+
+ abstract_panel::OnComboBoxChange( event );
+}
+
+BEGIN_EVENT_TABLE(tab_quality_video, abstract_panel)
+ EVT_SLIDER(wxID_ANY, tab_quality_video::OnSliderMove)
+ EVT_TEXT(ID_RES_CHOICES_LBOX_X, tab_quality_video::OnTextUpdate)
+ EVT_TEXT(ID_RES_CHOICES_LBOX_Y, tab_quality_video::OnTextUpdate)
+ EVT_CHECKBOX(wxID_ANY, tab_quality_video::OnCheckBoxTick)
+ EVT_SPINCTRL(wxID_ANY, tab_quality_video::OnSpinControlChange)
+ EVT_RADIOBUTTON(wxID_ANY, tab_quality_video::OnRadioButtonToggle)
+ //EVT_IDLE( tab_quality_video::update)
+ EVT_COMBOBOX(wxID_ANY, tab_quality_video::OnComboBoxChange)
+END_EVENT_TABLE()
diff --git a/src/settings++/tab_quality_video.h b/src/settings++/tab_quality_video.h
new file mode 100644
index 0000000..d5aa1a3
--- /dev/null
+++ b/src/settings++/tab_quality_video.h
@@ -0,0 +1,95 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef __TAB_QUALITY_VIDEO_h__
+#define __TAB_QUALITY_VIDEO_h__
+
+#include "tab_abstract.h"
+#include <vector>
+
+class wxComboBox;
+class wxCheckBox;
+class wxBoxSizer;
+class wxTextCtrl;
+class wxFlexGridSizer;
+class wxRadioButton;
+class wxString;
+class wxWindow;
+class wxPoint;
+class wxSize;
+class wxCloseEvent;
+class wxSlider;
+class wxStaticBoxSizer;
+class wxSpinCtrlDbl;
+
+class tab_quality_video : public abstract_panel
+{
+
+ public:
+ tab_quality_video(wxWindow *parent, wxWindowID id, const wxString &title = wxT("Project2"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
+ virtual ~tab_quality_video();
+
+ void initVideoSizer(wxFlexGridSizer*);
+ void initQualitySizer(wxFlexGridSizer* );
+ void initAASizer(wxFlexGridSizer* );
+ void initZBufferSizer(wxFlexGridSizer* );
+ void initW4Sizer(wxSizer* );
+ void updateControls(int);
+ virtual void OnComboBoxChange(wxCommandEvent& event);
+
+ private:
+ void OnClose(wxCloseEvent& event);
+ void CreateGUIControls();
+
+ wxComboBox* ctrl_waterQ_CBox;
+ wxCheckBox** ctrl_vo_Boxes;
+ static const int ctrl_vo_Boxes_size = 3;
+ wxTextCtrl* ctrl_x_res;
+ wxTextCtrl* ctrl_y_res;
+ wxCheckBox** ctrl_qa_Boxes;
+ static const int ctrl_qa_Boxes_size = 12;
+ wxSlider* ctrl_fsaa_slider;
+
+ wxRadioButton* ctrl_z_radio1;
+ wxRadioButton* ctrl_z_radio2;
+
+ wxSizer* parentSizer ;
+ wxSizer* leftSizer ;
+ wxSizer* middleSizer;
+ wxSizer* rightSizer;
+ wxFlexGridSizer* SizerA ;
+ wxFlexGridSizer* SizerB ;
+ wxFlexGridSizer* SizerC ;
+ wxFlexGridSizer* SizerD ;
+ wxBoxSizer* SizerE ;
+ wxStaticBoxSizer* boxA ;
+ wxStaticBoxSizer* boxB ;
+ wxStaticBoxSizer* boxC ;
+ wxStaticBoxSizer* boxD ;
+ wxStaticBoxSizer* boxE ;
+
+ bool m_enable_w4;
+
+ std::vector<wxControl*> m_w4_controls;
+
+ wxSpinCtrlDbl* m_aniso_spin;
+
+ protected:
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
diff --git a/src/settings++/tab_render_detail.cpp b/src/settings++/tab_render_detail.cpp
new file mode 100644
index 0000000..0758e77
--- /dev/null
+++ b/src/settings++/tab_render_detail.cpp
@@ -0,0 +1,104 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#include "tab_render_detail.h"
+#include "se_utils.h"
+#include <wx/string.h>
+#include <wx/stattext.h>
+#include <wx/sizer.h>
+#include <wx/event.h>
+#include <wx/defs.h>
+#include <wx/slider.h>
+
+#include "Defs.hpp"
+
+void tab_render_detail::initRendererSizer(wxFlexGridSizer* sizerL,wxFlexGridSizer* sizerR ) {
+ const int extrema[] = {
+ 1024, 8192, 600, 3000, 20, 120, 100, 600, 0, 10, 0, 5, 100, 1000, 0, 20000, 0, 20000
+ };
+
+ for (int i = 0; i < ctrl_detail_sliders_size/2; i++) {
+ ctrl_detail_sliders[i] = new wxSlider(
+ this, RO_SLI[i].id, 0, extrema[i * 2], extrema[(i * 2) + 1], WX_DEF_P, wxSize(180, -1), SLI_STYLE, WX_DEF_V );
+ //ctrl_detail_sliders[i]->SetTickFreq((extrema[(i*2)+1] - extrema[i * 2]) / 10 ,1);
+ ctrl_detail_sliders[i]->SetToolTip(RO_SLI[i].tTip[0]);
+ sizerL->Add(new wxStaticText(this, -1, (RO_SLI[i].lbl)), 1,wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND);
+ sizerL->Add(ctrl_detail_sliders[i], 0,wxALIGN_CENTER_VERTICAL|wxALL);
+ }
+ for (int i = ctrl_detail_sliders_size/2; i < ctrl_detail_sliders_size; i++) {
+ ctrl_detail_sliders[i] = new wxSlider(
+ this, RO_SLI[i].id, 0, extrema[i * 2], extrema[(i * 2) + 1], WX_DEF_P, wxSize(180, -1), SLI_STYLE, WX_DEF_V);
+ //ctrl_detail_sliders[i]->SetTickFreq((extrema[(i*2)+1] - extrema[i * 2]) / 10 ,1);
+ ctrl_detail_sliders[i]->SetToolTip(RO_SLI[i].tTip[0]);
+ sizerR->Add(new wxStaticText(this, -1, (RO_SLI[i].lbl)), 1,wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND);
+ sizerR->Add(ctrl_detail_sliders[i], 0,wxALIGN_CENTER_VERTICAL|wxALL);
+ }
+}
+
+tab_render_detail::tab_render_detail(wxWindow *parent, wxWindowID id , const wxString &title , const wxPoint& pos , const wxSize& size, long style)
+ : abstract_panel(parent, id , title , pos , size, style) {
+ ctrl_detail_sliders = new wxSlider*[ctrl_detail_sliders_size];
+ renderSizer = new wxGridSizer(2,15,5);
+ parentSizer = new wxGridSizer(1,0,0);
+ rendererSizerA = new wxFlexGridSizer(2,35,10);
+ rendererSizerB = new wxFlexGridSizer(2,35,10);
+ box = new wxStaticBoxSizer(wxVERTICAL ,this,_("Rendering detail levels"));
+ rendererSizerA->AddGrowableCol(0);
+ rendererSizerA->AddGrowableCol(1);
+ rendererSizerB->AddGrowableCol(0);
+ rendererSizerB->AddGrowableCol(1);
+ initRendererSizer(rendererSizerA,rendererSizerB);
+ rendererSizerA->Fit(this);
+ rendererSizerA->SetSizeHints(this);
+ rendererSizerB->Fit(this);
+ rendererSizerB->SetSizeHints(this);
+
+ renderSizer->Add(rendererSizerA,0,wxALIGN_LEFT|wxALL,5);
+ renderSizer->Add(rendererSizerB,0,wxALIGN_RIGHT|wxALL,5);
+
+ box->Add(renderSizer,0,wxALL,5);
+ parentSizer->Add(box,0,wxALL,15);
+
+ updateControls(UPDATE_ALL);
+ SetSizer(parentSizer); // true --> delete old sizer if present
+
+}
+
+void tab_render_detail::updateControls(int what_to_update)
+{
+ for (int i = 0; i < ctrl_detail_sliders_size; i++) {
+ ctrl_detail_sliders[i]->SetValue(intSettings[RO_SLI[i].key]);
+ }
+
+}
+
+tab_render_detail::~tab_render_detail(void) {
+
+}
+
+BEGIN_EVENT_TABLE(tab_render_detail, abstract_panel)
+ EVT_SLIDER(wxID_ANY, tab_render_detail::OnSliderMove)
+// EVT_TEXT(wxID_ANY, tab_render_detail::OnTextUpdate)
+ //EVT_CHECKBOX(wxID_ANY, tab_render_detail::OnCheckBoxTick)
+// EVT_RADIOBUTTON(wxID_ANY, tab_render_detail::OnRadioButtonToggle)
+// EVT_IDLE( tab_render_detail::update)
+END_EVENT_TABLE()
diff --git a/src/settings++/tab_render_detail.h b/src/settings++/tab_render_detail.h
new file mode 100644
index 0000000..f2dd00e
--- /dev/null
+++ b/src/settings++/tab_render_detail.h
@@ -0,0 +1,57 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef __TAB_RENDER_DETAIL_h__
+#define __TAB_RENDER_DETAIL_h__
+
+#include "tab_abstract.h"
+
+class wxSlider;
+class wxFlexGridSizer;
+class wxString;
+class wxWindow;
+class wxPoint;
+class wxSize;
+class wxCloseEvent;
+class wxStaticBoxSizer;
+
+class tab_render_detail : public abstract_panel
+{
+
+ public:
+ tab_render_detail(wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("Project2"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
+ virtual ~tab_render_detail();
+
+ void initRendererSizer(wxFlexGridSizer*,wxFlexGridSizer*);
+ void updateControls(int what_to_update);
+ protected:
+ void OnClose(wxCloseEvent& event);
+ void CreateGUIControls();
+
+ wxSlider** ctrl_detail_sliders;
+ static const int ctrl_detail_sliders_size = 9;
+
+ wxSizer* renderSizer ;
+ wxSizer* parentSizer ;
+ wxFlexGridSizer* rendererSizerA ;
+ wxFlexGridSizer* rendererSizerB ;
+ wxStaticBoxSizer* box ;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
diff --git a/src/settings++/tab_simple.cpp b/src/settings++/tab_simple.cpp
new file mode 100644
index 0000000..2e306ad
--- /dev/null
+++ b/src/settings++/tab_simple.cpp
@@ -0,0 +1,199 @@
+/**
+d This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "tab_simple.h"
+#include "se_utils.h"
+#include <wx/string.h>
+#include <wx/sizer.h>
+#include <wx/stattext.h>
+#include <wx/event.h>
+#include <wx/defs.h>
+#include <wx/slider.h>
+#include <wx/combobox.h>
+#include <wx/button.h>
+
+#include "Defs.hpp"
+#include "presets.h"
+#include "frame.h"
+#include "../settings.h"
+#include "../springunitsynclib.h"
+
+const wxString infoTextContent= _("These options let you roughly control Spring's rendering.\n"
+ "For more speed try lowering the settings.\n"
+ "Full control over all settings is available in the\n"
+ "\"Expert mode\", either click on the button on the\n"
+ "right or use the \"Mode\" menu in the top menubar.\n"
+ "You can go back to this mode at any time by choosing\n"
+ "\"Simple mode\" from the \"Mode\" menu.\n"
+ "If you encounter error messages concerning graphics\n"
+ "when running Spring it might be necessary to disable\n "
+ "some options in expert mode.\n");
+
+const wxString renderQuality_CBX_lbl = _("Graphics quality");
+const wxString renderDetail_CBX_lbl = _("Graphics detail");
+const wxString videoMode_CBX_lbl = _("Screen resolution");
+const wxString button_lbl = _("Switch to expert mode");
+
+void tab_simple::getSetUpResolutionCBX()
+{
+ int x_res = 0;
+ int y_res = 0;
+
+ if (abstract_panel::settingsChanged)
+ {
+ x_res = intSettings[RC_TEXT[0].key];
+ y_res = intSettings[RC_TEXT[1].key];
+ }
+ else
+ {
+ try{
+ x_res = susynclib().GetSpringConfigInt(RC_TEXT[0].key,fromString(RC_TEXT[0].def));
+ y_res = susynclib().GetSpringConfigInt(RC_TEXT[1].key,fromString(RC_TEXT[1].def));
+ }
+ catch (...) {}
+ }
+ wxString currentRes;
+ currentRes << x_res << _T(" x ") << y_res;
+ wxArrayString choices(vl_Resolution_Str_size,vl_Resolution_Str);
+ choices.Add((currentRes + _(" (current)")));
+
+ videoMode_CBX = new wxComboBox(this, ID_SIMPLE_MODE_CBX,choices.Last() , wxDefaultPosition, wxSize(220,21),
+ choices,wxCB_DROPDOWN|wxCB_READONLY);
+}
+
+void tab_simple::initOptSizer(wxFlexGridSizer* sizer ) {
+ sizer->Add(new wxStaticText(this, -1, renderQuality_CBX_lbl) , 0,wxTOP|wxBOTTOM,15);
+
+ renderQuality_CBX = new wxComboBox(this, ID_SIMPLE_QUAL_CBX, sett().getSimpleQuality(), wxDefaultPosition, wxSize(220,21),
+ levels_vlow_To_vHigh_size,levels_vlow_To_vHigh,wxCB_DROPDOWN|wxCB_READONLY);
+ renderQuality_CBX->SetToolTip(_("Sets all quality options to predefined values according to your choice."));
+ sizer->Add(renderQuality_CBX, 0, wxTOP|wxBOTTOM, 15);
+
+ sizer->Add(new wxStaticText(this, -1,renderDetail_CBX_lbl ), 0,wxALL);
+ renderDetail_CBX = new wxComboBox(this, ID_SIMPLE_DETAIL_CBX, sett().getSimpleDetail(), wxDefaultPosition, wxSize(220,21),
+ levels_low_To_High_size,levels_low_To_High,wxCB_DROPDOWN|wxCB_READONLY);
+ renderDetail_CBX->SetToolTip(_("Sets all detail options to predefined values according to your choice."));
+ sizer->Add(renderDetail_CBX, 0, wxBOTTOM, 15);
+
+ sizer->Add(new wxStaticText(this, -1, videoMode_CBX_lbl ), 0,wxALL);
+ getSetUpResolutionCBX();
+ videoMode_CBX->SetToolTip(_("Select the resolution fitting your monitor(s).\n"
+ "Selecting a dual screen resolution will automatically enable dual screen mode.\n"
+ "If the appropiate resolution is not available you can set it manually in expert mode.\n"
+ "Please also contact the author so it can be added in future releases."));
+ sizer->Add(videoMode_CBX, 0, wxBOTTOM, 15);
+
+ sizer->Add(new wxStaticText(this, -1, (AO_SLI[1].lbl)), 0, wxTOP, 15);
+ audioVolume_SLI = new wxSlider(this, AO_SLI[1].id,0, 0, 100, WX_DEF_P, WX_SLI_S, SLI_STYLE, WX_DEF_V);
+ audioVolume_SLI->SetToolTip(AO_SLI[1].tTip[0]);
+ sizer->Add(audioVolume_SLI, 0, wxBOTTOM, 15);
+}
+
+void tab_simple::initInfoSizer(wxFlexGridSizer* sizer)
+{
+ infoText = new wxStaticText(this,-1,infoTextContent);
+ sizer->Add(infoText,0,wxALL,10);
+}
+
+void tab_simple::initButSizer(wxSizer* sizer)
+{
+ goExpert_BUT = new wxButton(this, ID_SIMPLE_GOEXPERT_BUT,button_lbl ,wxPoint(-1,-1) ,wxSize(-1,-1), wxBU_EXACTFIT);
+ sizer->Add(goExpert_BUT,0,wxALIGN_CENTER_VERTICAL);
+}
+
+tab_simple::tab_simple(settings_frame* _origin, wxWindow *parent, wxWindowID id , const wxString &title , const wxPoint& pos , const wxSize& size, long style)
+: abstract_panel(parent, id , title , pos , size, style) {
+
+ origin = _origin;
+
+ parentSizer = new wxFlexGridSizer(2,1,1);
+ leftSizer = new wxFlexGridSizer(1,15,1);
+ rightSizer = new wxFlexGridSizer(1,15,1);
+ Sizer_CBX = new wxFlexGridSizer(2,10,10);
+ Sizer_info = new wxFlexGridSizer(1,15,10);
+ Sizer_BUT = new wxBoxSizer(wxVERTICAL);
+ boxA = new wxStaticBoxSizer(wxVERTICAL ,this,_("Options"));
+ boxB = new wxStaticBoxSizer(wxVERTICAL ,this,_("Info"));
+
+ initOptSizer(Sizer_CBX);
+ initInfoSizer(Sizer_info);
+ initButSizer(Sizer_BUT);
+
+ Sizer_CBX->Fit(this);
+ Sizer_CBX->SetSizeHints(this);
+ Sizer_info->Fit(this);
+ Sizer_info->SetSizeHints(this);
+ Sizer_BUT->Fit(this);
+ Sizer_BUT->SetSizeHints(this);
+
+ boxA->Add(Sizer_CBX,1,wxEXPAND);
+ boxB->Add(Sizer_info,1,wxEXPAND);
+
+ leftSizer->Add(boxA,1,wxEXPAND);
+ leftSizer->Add(boxB,1,wxEXPAND);
+ rightSizer->Add(Sizer_BUT,1,wxEXPAND|wxALIGN_CENTER);
+
+ parentSizer->Add(leftSizer,1,wxALL|wxEXPAND,15);
+ parentSizer->Add(goExpert_BUT,0,wxLEFT|wxALIGN_CENTER,35);
+
+ updateControls(UPDATE_ALL);
+ SetSizer(parentSizer); // true --> delete old sizer if present
+}
+
+void tab_simple::updateControls(int what_to_update)
+{
+ audioVolume_SLI->SetValue(intSettings[AO_SLI[1].key]);
+}
+
+tab_simple::~tab_simple(void) {
+
+
+}
+
+void tab_simple::OnComboBoxChange(wxCommandEvent& event)
+{
+ abstract_panel::OnComboBoxChange(event);
+}
+
+void tab_simple::OnButtonClick(wxCommandEvent& event)
+{
+ origin->switchToExpertMode();
+}
+
+void tab_simple::saveCbxChoices()
+{
+ sett().setSimpleDetail(renderDetail_CBX->GetValue());
+ sett().setSimpleRes(videoMode_CBX->GetValue());
+ sett().setSimpleQuality(renderQuality_CBX->GetValue());
+}
+
+BEGIN_EVENT_TABLE(tab_simple, abstract_panel)
+ EVT_SLIDER(wxID_ANY, tab_simple::OnSliderMove)
+// EVT_TEXT(wxID_ANY, tab_simple::OnTextUpdate)
+ EVT_CHECKBOX(wxID_ANY, tab_simple::OnCheckBoxTick)
+// EVT_RADIOBUTTON(wxID_ANY, tab_simple::OnRadioButtonToggle)
+// EVT_IDLE( tab_simple::update)
+ EVT_COMBOBOX(wxID_ANY, tab_simple::OnComboBoxChange)
+ EVT_BUTTON(ID_SIMPLE_GOEXPERT_BUT, tab_simple::OnButtonClick)
+END_EVENT_TABLE()
+
+
diff --git a/src/settings++/tab_simple.h b/src/settings++/tab_simple.h
new file mode 100644
index 0000000..ba07f90
--- /dev/null
+++ b/src/settings++/tab_simple.h
@@ -0,0 +1,89 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef __TAB_SIMPLE_h__
+#define __TAB_SIMPLE_h__
+
+#include "tab_abstract.h"
+
+class wxComboBox;
+//class wxCheckBox;
+//class wxTextCtrl;
+class wxSlider;
+class wxFlexGridSizer;
+//class wxRadioButton;
+class wxString;
+//class wxCommandEvent;
+class wxWindow;
+class wxPoint;
+class wxSize;
+class wxCloseEvent;
+class wxStaticText;
+class wxStaticBoxSizer;
+class wxButton;
+class settings_frame;
+
+class tab_simple : public abstract_panel
+{
+
+ public:
+ tab_simple(settings_frame* _origin, wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("Project2"),
+ const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
+ virtual ~tab_simple();
+
+
+ void updateControls(int);
+ void saveCbxChoices();
+ void setTabs(abstract_panel* ,abstract_panel* );
+ void OnComboBoxChange(wxCommandEvent& event);
+
+ protected:
+ void getSetUpResolutionCBX();
+ void OnClose(wxCloseEvent& event);
+ void OnButtonClick(wxCommandEvent& event);
+ void CreateGUIControls();
+ void initOptSizer(wxFlexGridSizer*);
+ void initInfoSizer(wxFlexGridSizer*);
+ void initButSizer(wxSizer* );
+ wxComboBox* renderQuality_CBX;
+ wxComboBox* renderDetail_CBX;
+ wxComboBox* videoMode_CBX;
+ wxSlider* audioVolume_SLI;
+ wxButton* goExpert_BUT;
+ wxStaticText* infoText;
+
+ //dirty
+ abstract_panel* detailTab;
+ abstract_panel* qualityTab;
+
+ wxSizer* parentSizer;
+
+ wxFlexGridSizer* leftSizer ;
+ wxFlexGridSizer* rightSizer;
+ wxFlexGridSizer* Sizer_CBX ;
+ wxFlexGridSizer* Sizer_info;
+ wxSizer* Sizer_BUT;
+
+ wxStaticBoxSizer* boxA ;
+ wxStaticBoxSizer* boxB ;
+ settings_frame* origin;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
+
diff --git a/src/settings++/tab_ui.cpp b/src/settings++/tab_ui.cpp
new file mode 100644
index 0000000..2e24bb4
--- /dev/null
+++ b/src/settings++/tab_ui.cpp
@@ -0,0 +1,177 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007
+ Original work by Kloot
+ cross-plattform/UI adaptation and currently maintained by koshi (Ren� Milk)
+ visit http://spring.clan-sy.com/phpbb/viewtopic.php?t=12104
+ for more info/help
+
+ springsettings is free software: you can redistribute 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.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#include "tab_ui.h"
+
+#include <wx/wx.h>
+#include <wx/spinctrl.h>
+#include <wx/log.h>
+
+#include "Defs.hpp"
+#include "../utils/debug.h"
+#include "se_utils.h"
+
+//TODO maybe use only one chkbox for minimap on left
+void tab_ui::initScrollSpeedSizer(wxStaticBoxSizer* sizer) {
+ // i < "sizeof"(MO_SLI)
+ sizer->Add(5,10,0);
+ sizer->Add(new wxStaticText(this, -1, _("Setting a slider to 0 will exclude that\n"
+ "mode from being cycled through ingame.")) , 0,wxBOTTOM,15);
+ for (int i = 0; i < ctrl_scroll_slider_size; i++) {
+ //set to dummy value
+ ctrl_scroll_slider[i] = new wxSlider(this, MO_SLI[i].id, 0, 0, 100, WX_DEF_P, WX_SLI_S, SLI_STYLE, WX_DEF_V);
+ ctrl_scroll_slider[i]->SetToolTip(MO_SLI[i].tTip[0]);
+ if (i > 0)
+ sizer->Add(5,23,0);
+ sizer->Add(new wxStaticText(this, wxID_ANY, (MO_SLI[i].lbl), wxDefaultPosition, wxDefaultSize, 10),1,wxEXPAND);
+ sizer->Add(ctrl_scroll_slider[i], 0, wxTOP, 0);
+ }
+ sizer->Add(5,10,0);
+}
+
+void tab_ui::initCameraSizer(wxStaticBoxSizer* sizer) {
+ ctrl_cam_radio0 = new wxRadioButton(this, MO_RBUT[0].id, (MO_RBUT[0].lbl), WX_DEF_P, WX_DEF_S, wxRB_GROUP, WX_DEF_V);
+ ctrl_cam_radio1 = new wxRadioButton(this, MO_RBUT[1].id, (MO_RBUT[1].lbl), WX_DEF_P, WX_DEF_S, 0, WX_DEF_V);
+ ctrl_cam_radio2 = new wxRadioButton(this, MO_RBUT[2].id, (MO_RBUT[2].lbl), WX_DEF_P, WX_DEF_S, 0, WX_DEF_V);
+ ctrl_cam_radio3 = new wxRadioButton(this, MO_RBUT[3].id, (MO_RBUT[3].lbl), WX_DEF_P, WX_DEF_S, 0, WX_DEF_V);
+ ctrl_cam_radio4 = new wxRadioButton(this, MO_RBUT[4].id, (MO_RBUT[4].lbl), WX_DEF_P, WX_DEF_S, 0, WX_DEF_V);
+
+ ctrl_cam_radio0->SetToolTip(MO_RBUT[0].tTip[0]);
+ ctrl_cam_radio1->SetToolTip(MO_RBUT[1].tTip[0]);
+ ctrl_cam_radio2->SetToolTip(MO_RBUT[2].tTip[0]);
+ ctrl_cam_radio3->SetToolTip(MO_RBUT[3].tTip[0]);
+ ctrl_cam_radio4->SetToolTip(MO_RBUT[4].tTip[0]);
+
+
+ sizer->Add(ctrl_cam_radio0, 0, wxTOP, 10);
+ sizer->Add(ctrl_cam_radio1, 0, wxTOP, 5);
+ sizer->Add(ctrl_cam_radio2, 0, wxTOP, 5);
+ sizer->Add(ctrl_cam_radio3, 0, wxTOP, 5);
+ sizer->Add(ctrl_cam_radio4, 0, wxTOP|wxBOTTOM, 5);
+}
+
+void tab_ui::initUiOptSizer(wxStaticBoxSizer* sizer)
+{
+ wxBoxSizer* subSizer = new wxBoxSizer(wxVERTICAL);
+ for (int i = 0; i < ctrl_ui_chkb_size; i++) {
+ ctrl_ui_chkb[i] = new wxCheckBox(this, UI_CBOX[i].id, (UI_CBOX[i].lbl));
+ subSizer->Add(ctrl_ui_chkb[i], 0, wxTOP, 5);
+ ctrl_ui_chkb[i]->SetToolTip(UI_CBOX[i].tTip[0]);
+ }
+ sizer->Add(subSizer);
+ sizer->Add(0,5,0);
+}
+
+void tab_ui::initZoomSizer(wxStaticBoxSizer* sizer)
+{
+ wxBoxSizer* subSizer = new wxBoxSizer(wxVERTICAL);
+ ctrl_zoom_spin = new wxSpinCtrl(this,UI_ZOOM[0].id,_T(""),wxDefaultPosition,wxDefaultSize,wxSP_ARROW_KEYS,-255,255);
+ ctrl_zoom_spin->SetToolTip(UI_ZOOM[0].tTip[0]);
+ subSizer->Add(new wxStaticText(this, -1, UI_ZOOM[0].lbl) , 0,wxTOP,10);
+ subSizer->Add(ctrl_zoom_spin,0,wxALIGN_RIGHT|wxALL,5);
+ sizer->Add(subSizer,5,wxALL);
+ sizer->Add(0,5,0);
+}
+
+void tab_ui::updateControls(int /*what_to_update*/)
+{
+ for (int i = 0; i < ctrl_ui_chkb_size; i++) {
+ ctrl_ui_chkb[i]->SetValue(intSettings[UI_CBOX[i].key]);
+ }
+
+ switch (intSettings[MO_RBUT[0].key]) {
+ case 0: { ctrl_cam_radio3->SetValue(1); } break; // CamMode 0: FPS
+ case 1: { ctrl_cam_radio0->SetValue(1); } break; // CamMode 1: OH
+ case 3: { ctrl_cam_radio1->SetValue(1); } break; // CamMode 2: ROH
+ case 2: { ctrl_cam_radio2->SetValue(1); } break; // CamMode 3: TW
+ case 4: { ctrl_cam_radio4->SetValue(1); } break; // CamMode 4: FC
+ default:
+ wxLogDebugFunc( _T("unhandled case val") );
+ break;
+ }
+
+ for (int i = 0; i < ctrl_scroll_slider_size; i++) {
+ ctrl_scroll_slider[i]->SetValue(intSettings[MO_SLI[i].key]);
+ }
+
+ ctrl_zoom_spin->SetValue(intSettings[UI_ZOOM[0].key]);
+}
+
+tab_ui::tab_ui(wxWindow *parent, wxWindowID id , const wxString &title , const wxPoint& pos , const wxSize& size, long style)
+ : abstract_panel(parent, id , title , pos , size, style) {
+ ctrl_scroll_slider = new wxSlider*[ctrl_scroll_slider_size];
+ ctrl_ui_chkb = new wxCheckBox*[ctrl_ui_chkb_size];
+ pSizer = new wxFlexGridSizer(3,15,15);
+ cSizerL = new wxFlexGridSizer(1,10,10);
+ cSizerR = new wxFlexGridSizer(1,10,10);
+ cSizerM = new wxFlexGridSizer(1,10,10);
+
+ scrollSpeedSizer = new wxStaticBoxSizer(new wxStaticBox(this, -1, _("Scroll Speeds (mouse + keyboard)"),
+ WX_DEF_P, wxSize(-1, -1), 0, wxEmptyString), wxVERTICAL);
+
+
+ cameraSizer = new wxStaticBoxSizer(new wxStaticBox(this, -1, _("Default Camera Mode"),
+ WX_DEF_P, wxSize(-1, -1), 0, wxEmptyString), wxVERTICAL);
+ uiOptSizer = new wxStaticBoxSizer(new wxStaticBox(this, -1, _("Misc. UI Options"),
+ WX_DEF_P, wxSize(-1, -1), 0, wxEmptyString), wxVERTICAL);
+ zoomSizer = new wxStaticBoxSizer(new wxStaticBox(this, -1, _("Zoom"),
+ WX_DEF_P, wxSize(-1, -1), 0, wxEmptyString), wxVERTICAL);
+
+ initScrollSpeedSizer(scrollSpeedSizer);
+ initUiOptSizer(uiOptSizer);
+ initCameraSizer(cameraSizer);
+ initZoomSizer(zoomSizer);
+
+
+ cSizerM->Add(uiOptSizer,0,wxALL,5);
+ cSizerL->Add(scrollSpeedSizer,0,wxALL,5);
+ cSizerR->Add(cameraSizer,0,wxALL,5);
+ cSizerR->Add(zoomSizer,1,wxALL|wxEXPAND,5);
+
+ cSizerL->Fit(this);
+ cSizerL->SetSizeHints(this);
+ cSizerM->Fit(this);
+ cSizerM->SetSizeHints(this);
+ cSizerR->Fit(this);
+ cSizerR->SetSizeHints(this);
+
+
+ pSizer->Add(cSizerL,0,wxALL|wxEXPAND,10);
+ pSizer->Add(cSizerM,0,wxALL|wxEXPAND,10);
+ pSizer->Add(cSizerR,0,wxALL|wxEXPAND,10);
+
+ updateControls(UPDATE_ALL);
+ SetSizer(pSizer); // true --> delete old sizer if present
+
+}
+
+tab_ui::~tab_ui(void) {
+
+}
+
+BEGIN_EVENT_TABLE(tab_ui, abstract_panel)
+ EVT_SLIDER(wxID_ANY, tab_ui::OnSliderMove)
+ EVT_TEXT(wxID_ANY, tab_ui::OnTextUpdate)
+ EVT_CHECKBOX(wxID_ANY, tab_ui::OnCheckBoxTick)
+ EVT_RADIOBUTTON(wxID_ANY, tab_ui::OnRadioButtonToggle)
+// EVT_IDLE( tab_ui::update)
+END_EVENT_TABLE()
diff --git a/src/settings++/tab_ui.h b/src/settings++/tab_ui.h
new file mode 100644
index 0000000..9a91554
--- /dev/null
+++ b/src/settings++/tab_ui.h
@@ -0,0 +1,75 @@
+/**
+ This file is part of springsettings,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with springsettings. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+#ifndef __TAB_UI_h__
+#define __TAB_UI_h__
+
+#include "tab_abstract.h"
+
+class wxCheckBox;
+class wxStaticBoxSizer;
+class wxRadioButton;
+class wxString;
+class wxWindow;
+class wxPoint;
+class wxSize;
+class wxCloseEvent;
+class wxSlider;
+class wxStaticBoxSizer;
+class wxFlexGridSizer;
+class wxSpinCtrl;
+
+class tab_ui : public abstract_panel
+{
+
+ public:
+ tab_ui(wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("Project2"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
+ virtual ~tab_ui();
+
+ void initCameraSizer(wxStaticBoxSizer*);
+ void initScrollSpeedSizer(wxStaticBoxSizer* );
+ void initUiOptSizer(wxStaticBoxSizer* );
+ void initZoomSizer(wxStaticBoxSizer* );
+ void updateControls(int what_to_update);
+ protected:
+ void OnClose(wxCloseEvent& event);
+ void CreateGUIControls();
+ wxSlider** ctrl_scroll_slider;
+ static const int ctrl_scroll_slider_size = 5;
+ wxRadioButton* ctrl_cam_radio0;
+ wxRadioButton* ctrl_cam_radio1;
+ wxRadioButton* ctrl_cam_radio2;
+ wxRadioButton* ctrl_cam_radio3;
+ wxRadioButton* ctrl_cam_radio4;
+ wxCheckBox** ctrl_ui_chkb;
+ wxSpinCtrl* ctrl_zoom_spin;
+ static const int ctrl_ui_chkb_size = 17;
+
+ wxFlexGridSizer* pSizer;
+ wxFlexGridSizer* cSizerL ;
+ wxFlexGridSizer* cSizerR;
+ wxFlexGridSizer* cSizerM;
+
+ wxStaticBoxSizer* zoomSizer;
+ wxStaticBoxSizer* scrollSpeedSizer ;
+ wxStaticBoxSizer* cameraSizer;
+ wxStaticBoxSizer* uiOptSizer;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
diff --git a/src/settings.cpp b/src/settings.cpp
new file mode 100644
index 0000000..1e4fe43
--- /dev/null
+++ b/src/settings.cpp
@@ -0,0 +1,2434 @@
+/* Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: Settings
+//
+
+#include "settings.h"
+
+#ifdef __WXMSW__
+#include <wx/fileconf.h>
+#include <wx/msw/registry.h>
+#else
+#include <wx/config.h>
+#endif
+#include <wx/filename.h>
+#include <wx/filefn.h>
+#include <wx/intl.h>
+#include <wx/stdpaths.h>
+#include <wx/filename.h>
+#include <wx/colour.h>
+#include <wx/cmndata.h>
+#include <wx/font.h>
+#include <wx/log.h>
+#include <wx/wfstream.h>
+#include <wx/settings.h>
+#include <wx/tokenzr.h>
+
+#include "nonportable.h"
+#include "utils/conversion.h"
+#include "utils/debug.h"
+#include "utils/math.h"
+#include "utils/platform.h"
+#include "uiutils.h"
+#include "battlelistfiltervalues.h"
+#include "playback/playbackfiltervalues.h"
+#include "globalsmanager.h"
+#include "springunitsynclib.h"
+#include "customlistctrl.h"
+#include "settings++/presets.h"
+#include "Helper/sortutil.h"
+#include "mainwindow.h"
+#ifdef SL_DUMMY_COL
+#include "settings++/custom_dialogs.h"
+#endif
+
+bool Settings::m_user_defined_config = false;
+wxString Settings::m_user_defined_config_path = wxEmptyString;
+
+
+const wxColour defaultHLcolor ( 255, 0, 0 );
+
+Settings& sett()
+{
+ static GlobalObjectHolder<Settings> m_sett;
+ return m_sett;
+}
+
+SL_WinConf::SL_WinConf( wxFileInputStream& in ):
+ wxFileConfig( in )
+{
+}
+
+bool SL_WinConf::DoWriteLong( const wxString& key, long lValue )
+{
+ return wxFileConfig::DoWriteString( key, TowxString<long>( lValue ) );
+}
+
+Settings::Settings()
+{
+#if defined(__WXMSW__) || defined(__WXMAC__)
+ wxString userfilepath = wxStandardPaths::Get().GetUserDataDir() + wxFileName::GetPathSeparator() + _T( "springlobby.conf" );
+ wxString localfilepath = GetExecutableFolder() + wxFileName::GetPathSeparator() + _T( "springlobby.conf" );
+
+ if ( !wxFileName::FileExists( localfilepath ) || !wxFileName::IsFileWritable( localfilepath ) )
+ {
+ //either local conf file soes not exist, or it exists but is not writable
+ m_chosen_path = userfilepath;
+ SetPortableMode( false );
+ }
+ else
+ {
+ m_chosen_path = localfilepath; // portable mode, use only current app paths
+ SetPortableMode ( true );
+ }
+
+ // if it doesn't exist, try to create it
+ if ( !wxFileName::FileExists( m_chosen_path ) )
+ {
+ // if directory doesn't exist, try to create it
+ if ( !IsPortableMode() && !wxFileName::DirExists( wxStandardPaths::Get().GetUserDataDir() ) )
+ wxFileName::Mkdir( wxStandardPaths::Get().GetUserDataDir(), 0755 );
+
+ wxFileOutputStream outstream( m_chosen_path );
+
+ if ( !outstream.IsOk() )
+ {
+ if ( m_user_defined_config ) {
+ wxLogError( _T( "unable to use specified config file" ) );
+ exit( -1 );
+ }
+ }
+ }
+
+ wxFileInputStream instream( m_chosen_path );
+
+ if ( !instream.IsOk() )
+ {
+ if ( m_user_defined_config ) {
+ wxLogError( _T( "unable to use specified config file" ) );
+ exit( -1 );
+ }
+ }
+#ifdef __WXMSW__
+ m_config = new SL_WinConf( instream );
+#else
+ m_config = new wxFileConfig( instream );
+#endif
+#else
+ //removed temporarily because it's suspected to cause a bug with userdir creation
+// m_config = new wxConfig( _T("SpringLobby"), wxEmptyString, _T(".springlobby/springlobby.conf"), _T("springlobby.global.conf"), wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_GLOBAL_FILE );
+ wxString path = m_user_defined_config ? m_user_defined_config_path : _T( ".springlobby/springlobby.conf" );
+ m_config = new wxConfig( _T( "SpringLobby" ), wxEmptyString, path, _T( "springlobby.global.conf" ) );
+ SetPortableMode ( false );
+#endif
+ m_config->SetRecordDefaults( true );
+}
+
+Settings::~Settings()
+{
+}
+
+//! @brief Saves the settings to file
+void Settings::SaveSettings()
+{
+ m_config->Write( _T( "/General/firstrun" ), false );
+ SetCacheVersion();
+ SetSettingsVersion();
+ m_config->Flush();
+#if defined(__WXMSW__) || defined(__WXMAC__)
+ wxFileOutputStream outstream( m_chosen_path );
+
+ if ( !outstream.IsOk() )
+ {
+ // TODO: error handling
+ }
+
+ m_config->Save( outstream );
+#endif
+}
+
+
+#ifdef __WXMSW__
+void Settings::SetDefaultConfigs( SL_WinConf& conf )
+#else
+void Settings::SetDefaultConfigs( wxConfig& conf )
+#endif
+{
+ wxString str;
+ long dummy;
+ wxString previousgroup;
+
+ // now all groups...
+ bool groupcontinue = conf.GetFirstGroup( str, dummy );
+ while ( groupcontinue )
+ {
+ // climb all tree branches until you hit the most further
+ groupcontinue = conf.GetFirstGroup( str, dummy );
+ if ( groupcontinue && ( previousgroup != str ) )
+ {
+ conf.SetPath( str );
+ previousgroup = str;
+ }
+ else
+ {
+ // enum all entries and add to the config
+ wxString currentpath = conf.GetPath();
+ bool exist = conf.GetFirstEntry( str, dummy );
+ while ( exist )
+ {
+ if ( !m_config->Exists( currentpath + _T( "/" ) + str ) ) // in theory "main" config should be blank at this point, but better be paranoyd and don't overwrite existing keys...
+ {
+ m_config->Write( currentpath + _T( "/" ) + str, conf.Read( str, _T( "" ) ) ); // append to main config
+ }
+
+ exist = conf.GetNextEntry( str, dummy );
+ }
+
+ if ( !currentpath.IsEmpty() )
+ {
+ wxString todelete = currentpath.AfterLast( _T( '/' ) );
+ currentpath = currentpath.BeforeLast( _T( '/' ) );
+ conf.SetPath( currentpath ); // go to the parent folder
+ conf.DeleteGroup( todelete ); // remove last analyzed group so it doesn't get iterated again
+ groupcontinue = true;
+ }
+ previousgroup = _T( "" );
+ }
+ }
+ m_config->Flush();
+}
+
+
+wxArrayString Settings::GetGroupList( const wxString& base_key )
+{
+ wxString old_path = m_config->GetPath();
+ m_config->SetPath( base_key );
+ wxString groupname;
+ long dummy;
+ wxArrayString ret;
+ bool groupexist = m_config->GetFirstGroup( groupname, dummy );
+ while ( groupexist )
+ {
+ ret.Add( groupname );
+ groupexist = m_config->GetNextGroup( groupname, dummy );
+ }
+ m_config->SetPath( old_path );
+ return ret;
+}
+
+wxArrayString Settings::GetEntryList( const wxString& base_key )
+{
+ wxString old_path = m_config->GetPath();
+ m_config->SetPath( base_key );
+ wxString entryname;
+ long dummy;
+ wxArrayString ret;
+ bool entryexist = m_config->GetFirstEntry( entryname, dummy );
+ while ( entryexist )
+ {
+ ret.Add( entryname );
+ entryexist = m_config->GetNextEntry( entryname, dummy );
+ }
+ m_config->SetPath( old_path );
+ return ret;
+}
+
+unsigned int Settings::GetGroupCount( const wxString& base_key )
+{
+ wxString currentpath = m_config->GetPath();
+ m_config->SetPath( base_key );
+ unsigned int count = m_config->GetNumberOfGroups( false );
+ m_config->SetPath( currentpath );
+ return count;
+}
+
+bool Settings::IsPortableMode()
+{
+ return m_portable_mode;
+}
+
+void Settings::SetPortableMode( bool mode )
+{
+ m_portable_mode = mode;
+}
+
+
+bool Settings::IsFirstRun()
+{
+ return m_config->Read( _T( "/General/firstrun" ), true );
+}
+
+
+void Settings::SetSettingsVersion()
+{
+ m_config->Write( _T( "/General/SettingsVersion" ), SETTINGS_VERSION );
+}
+
+
+unsigned int Settings::GetSettingsVersion()
+{
+ return m_config->Read( _T( "/General/SettingsVersion" ), 0l );
+}
+
+
+wxString Settings::GetLobbyWriteDir()
+{
+ wxString sep = wxFileName::GetPathSeparator();
+ wxString path = GetCurrentUsedDataDir() + sep + _T( "lobby" );
+ if ( !wxFileName::DirExists( path ) )
+ {
+ if ( !wxFileName::Mkdir( path, 0755 ) ) return wxEmptyString;
+ }
+ path += sep + _T( "SpringLobby" ) + sep;
+ if ( !wxFileName::DirExists( path ) )
+ {
+ if ( !wxFileName::Mkdir( path, 0755 ) ) return wxEmptyString;
+ }
+ return path;
+}
+
+
+bool Settings::UseOldSpringLaunchMethod()
+{
+ return m_config->Read( _T( "/Spring/UseOldLaunchMethod" ), 0l );
+}
+
+bool Settings::GetNoUDP()
+{
+ return m_config->Read( _T( "/General/NoUDP" ), 0l );
+}
+
+void Settings::SetNoUDP( bool value )
+{
+ m_config->Write( _T( "/General/NoUDP" ), value );
+}
+
+int Settings::GetClientPort()
+{
+ return m_config->Read( _T( "/General/ClientPort" ), 0l );
+}
+
+void Settings::SetClientPort( int value )
+{
+ m_config->Write( _T( "/General/ClientPort" ), value );
+}
+
+bool Settings::GetShowIPAddresses()
+{
+ return m_config->Read( _T( "/General/ShowIP" ), 0l );
+}
+
+void Settings::SetShowIPAddresses( bool value )
+{
+ m_config->Write( _T( "/General/ShowIP" ), value );
+}
+
+void Settings::SetOldSpringLaunchMethod( bool value )
+{
+ m_config->Write( _T( "/Spring/UseOldLaunchMethod" ), value );
+}
+
+
+bool Settings::GetWebBrowserUseDefault()
+{
+ // See note on ambiguities, in wx/confbase.h near line 180.
+ bool useDefault;
+ m_config->Read( _T( "/General/WebBrowserUseDefault" ), &useDefault, DEFSETT_WEB_BROWSER_USE_DEFAULT );
+ return useDefault;
+}
+
+void Settings::SetWebBrowserUseDefault( bool useDefault )
+{
+ m_config->Write( _T( "/General/WebBrowserUseDefault" ), useDefault );
+}
+
+wxString Settings::GetWebBrowserPath()
+{
+ return m_config->Read( _T( "/General/WebBrowserPath" ), wxEmptyString );
+}
+
+
+void Settings::SetWebBrowserPath( const wxString& path )
+{
+ m_config->Write( _T( "/General/WebBrowserPath" ), path );
+}
+
+
+wxString Settings::GetCachePath()
+{
+ wxString path = GetLobbyWriteDir() + _T( "cache" ) + wxFileName::GetPathSeparator();
+ if ( !wxFileName::DirExists( path ) )
+ {
+ if ( !wxFileName::Mkdir( path, 0755 ) ) return wxEmptyString;
+ }
+ return path;
+}
+
+
+//! @brief sets version number for the cache, needed to nuke it in case it becomes obsolete & incompatible with new versions
+void Settings::SetCacheVersion()
+{
+ m_config->Write( _T( "/General/CacheVersion" ), CACHE_VERSION );
+}
+
+
+//! @brief returns the cache versioning number, do decide whenever to delete if becomes obsolete & incompatible with new versions
+int Settings::GetCacheVersion()
+{
+ return m_config->Read( _T( "/General/CacheVersion" ), 0l );
+}
+
+
+void Settings::SetMapCachingThreadProgress( unsigned int index )
+{
+ m_config->Write( _T( "/General/LastMapCachingThreadIndex" ), ( int )index );
+}
+
+
+unsigned int Settings::GetMapCachingThreadProgress()
+{
+ return m_config->Read( _T( "/General/LastMapCachingThreadIndex" ), 0l );
+}
+
+
+void Settings::SetModCachingThreadProgress( unsigned int index )
+{
+ m_config->Write( _T( "/General/LastModCachingThreadIndex" ), ( int )index );
+}
+
+
+unsigned int Settings::GetModCachingThreadProgress()
+{
+ return m_config->Read( _T( "/General/LastModCachingThreadIndex" ), 0l );
+}
+
+bool Settings::ShouldAddDefaultServerSettings()
+{
+ return !m_config->Exists( _T( "/Server" ) );
+}
+
+//! @brief Restores default settings
+void Settings::SetDefaultServerSettings()
+{
+ SetServer( WX_STRINGC( DEFSETT_DEFAULT_SERVER_NAME ), WX_STRINGC( DEFSETT_DEFAULT_SERVER_HOST ), DEFSETT_DEFAULT_SERVER_PORT );
+ SetServer( _T( "Backup server 1" ), _T( "springbackup1.servegame.com" ), 8200 );
+ SetServer( _T( "Backup server 2" ), _T( "springbackup2.servegame.org" ), 8200 );
+ SetServer( _T( "Test server" ), _T( "taspringmaster.servegame.com" ), 8300 );
+ SetDefaultServer( WX_STRINGC( DEFSETT_DEFAULT_SERVER_NAME ) );
+}
+
+
+//! @brief convert old server settings format
+void Settings::ConvertOldServerSettings()
+{
+ wxArrayString servers;
+ std::map<wxString, bool> m_autosave_pass;
+ std::map<wxString, wxString> m_saved_nicks;
+ std::map<wxString, wxString> m_saved_pass;
+ std::map<wxString, wxString> m_saved_hosts;
+ std::map<wxString, int> m_saved_ports;
+ int count = m_config->Read( _T( "/Servers/Count" ), 0l );
+ for ( int i = 0; i < count; i++ )
+ {
+ wxString server_name = m_config->Read( wxString::Format( _T( "/Servers/Server%d" ), i ), _T( "" ) );
+ if ( server_name == _T( "TAS Server" ) ) server_name = WX_STRINGC( DEFSETT_DEFAULT_SERVER_NAME );
+ servers.Add( server_name );
+ m_saved_nicks[server_name] = m_config->Read( _T( "/Server/" ) + server_name + _T( "/nick" ), _T( "" ) );
+ m_saved_pass[server_name] = m_config->Read( _T( "/Server/" ) + server_name + _T( "/pass" ), _T( "" ) );
+ m_autosave_pass[server_name] = m_config->Read( _T( "/Server/" ) + server_name + _T( "/savepass" ), 0l );
+ m_saved_ports[server_name] = m_config->Read( _T( "/Server/" ) + server_name + _T( "/port" ), DEFSETT_DEFAULT_SERVER_PORT );
+ m_saved_hosts[server_name] = m_config->Read( _T( "/Server/" ) + server_name + _T( "/host" ), DEFSETT_DEFAULT_SERVER_HOST );
+ }
+ m_config->DeleteGroup( _T( "/Server" ) );
+ m_config->DeleteGroup( _T( "/Servers" ) );
+ SetDefaultServerSettings();
+ count = servers.GetCount();
+ for ( int i = 0; i < count; i++ )
+ {
+ wxString server_name = servers[i];
+ SetServer( server_name, m_saved_hosts[server_name], m_saved_ports[server_name] );
+ SetServerAccountNick( server_name, m_saved_nicks[server_name] );
+ SetServerAccountPass( server_name, m_saved_pass[server_name] );
+ SetServerAccountSavePass( server_name, m_autosave_pass[server_name] );
+ }
+
+}
+
+//! @brief Checks if the server name/alias exists in the settings
+bool Settings::ServerExists( const wxString& server_name )
+{
+ return m_config->Exists( _T( "/Server/Servers/" ) + server_name );
+}
+
+
+//! @brief Get the name/alias of the default server.
+//!
+//! @note Normally this will be the previously selected server. But at first run it will be a server that is set as the default.
+wxString Settings::GetDefaultServer()
+{
+ wxString serv = WX_STRINGC( DEFSETT_DEFAULT_SERVER_NAME );
+ return m_config->Read( _T( "/Server/Default" ), serv );
+}
+
+void Settings::SetAutoConnect( bool do_autoconnect )
+{
+ m_config->Write( _T( "/Server/Autoconnect" ), do_autoconnect );
+}
+
+bool Settings::GetAutoConnect( )
+{
+ return m_config->Read( _T( "/Server/Autoconnect" ), 0l );
+}
+
+
+//! @brief Set the name/alias of the default server.
+//!
+//! @param server_name the server name/alias
+//! @see GetDefaultServer()
+void Settings::SetDefaultServer( const wxString& server_name )
+{
+ m_config->Write( _T( "/Server/Default" ), server_name );
+}
+
+
+//! @brief Get hostname of a server.
+//!
+//! @param server_name the server name/alias
+wxString Settings::GetServerHost( const wxString& server_name )
+{
+ wxString host = WX_STRINGC( DEFSETT_DEFAULT_SERVER_HOST );
+ return m_config->Read( _T( "/Server/Servers/" ) + server_name + _T( "/Host" ), host );
+}
+
+
+//! @brief Set hostname of a server.
+//!
+//! @param server_name the server name/alias
+//! @param the host url address
+//! @param the port where the service is run
+void Settings::SetServer( const wxString& server_name, const wxString& url, int port )
+{
+ m_config->Write( _T( "/Server/Servers/" ) + server_name + _T( "/Host" ), url );
+ m_config->Write( _T( "/Server/Servers/" ) + server_name + _T( "/Port" ), port );
+}
+
+//! @brief Deletes a server from the list.
+//!
+//! @param server_name the server name/alias
+void Settings::DeleteServer( const wxString& server_name )
+{
+ m_config->DeleteGroup( _T( "/Server/Servers/" ) + server_name );
+}
+
+
+//! @brief Get port number of a server.
+//!
+//! @param server_name the server name/alias
+int Settings::GetServerPort( const wxString& server_name )
+{
+ return m_config->Read( _T( "/Server/Servers/" ) + server_name + _T( "/Port" ), DEFSETT_DEFAULT_SERVER_PORT );
+}
+
+//! @brief Get list of server aliases
+wxArrayString Settings::GetServers()
+{
+ return GetGroupList( _T( "/Server/Servers/" ) );
+}
+
+
+//! @brief Get nickname of the default account for a server.
+//!
+//! @param server_name the server name/alias
+wxString Settings::GetServerAccountNick( const wxString& server_name )
+{
+ return m_config->Read( _T( "/Server/Servers/" ) + server_name + _T( "/Nick" ), _T( "" ) ) ;
+}
+
+
+//! @brief Set nickname of the default account for a server.
+//!
+//! @param server_name the server name/alias
+//! @param value the vaule to be set
+void Settings::SetServerAccountNick( const wxString& server_name, const wxString& value )
+{
+ m_config->Write( _T( "/Server/Servers/" ) + server_name + _T( "/Nick" ), value );
+}
+
+
+//! @brief Get password of the default account for a server.
+//!
+//! @param server_name the server name/alias
+//! @todo Implement
+wxString Settings::GetServerAccountPass( const wxString& server_name )
+{
+ return m_config->Read( _T( "/Server/Servers/" ) + server_name + _T( "/Pass" ), _T( "" ) );
+}
+
+
+//! @brief Set password of the default account for a server.
+//!
+//! @param server_name the server name/alias
+//! @param value the vaule to be set
+//! @todo Implement
+void Settings::SetServerAccountPass( const wxString& server_name, const wxString& value )
+{
+ m_config->Write( _T( "/Server/Servers/" ) + server_name + _T( "/Pass" ), value );
+}
+
+
+//! @brief Get if the password should be saved for a default server account.
+//!
+//! @param server_name the server name/alias
+//! @todo Implement
+bool Settings::GetServerAccountSavePass( const wxString& server_name )
+{
+ return m_config->Read( _T( "/Server/Servers/" ) + server_name + _T( "/savepass" ), ( long int )false );
+}
+
+
+//! @brief Set if the password should be saved for a default server account.
+//!
+//! @param server_name the server name/alias
+//! @param value the vaule to be set
+//! @todo Implement
+void Settings::SetServerAccountSavePass( const wxString& server_name, const bool value )
+{
+ m_config->Write( _T( "/Server/Servers/" ) + server_name + _T( "/savepass" ), ( long int )value );
+}
+
+
+int Settings::GetNumChannelsJoin()
+{
+ return GetGroupCount( _T( "/Channels/AutoJoin" ) );
+}
+
+void Settings::AddChannelJoin( const wxString& channel , const wxString& key )
+{
+ int index = GetNumChannelsJoin();
+
+ m_config->Write( wxString::Format( _T( "/Channels/AutoJoin/Channel%d/Name" ), index ), channel );
+ m_config->Write( wxString::Format( _T( "/Channels/AutoJoin/Channel%d/Password" ), index ), key );
+}
+
+
+void Settings::RemoveChannelJoin( const wxString& channel )
+{
+ int index = GetChannelJoinIndex( channel );
+ if ( index == -1 ) return;
+ int total = GetNumChannelsJoin();
+ m_config->DeleteGroup( _T( "/Channels/AutoJoin/Channel" ) + TowxString( index ) );
+ m_config->RenameGroup( _T( "/Channels/AutoJoin/Channel" ) + TowxString( total - 1 ), _T( "/Channels/AutoJoin/Channel" ) + TowxString( index ) );
+}
+
+void Settings::RemoveAllChannelsJoin()
+{
+ m_config->DeleteGroup( _T( "/Channels/AutoJoin" ) );
+}
+
+
+int Settings::GetChannelJoinIndex( const wxString& name )
+{
+ int numchannels = GetNumChannelsJoin();
+ int ret = -1;
+ for ( int i = 0; i < numchannels; i++ )
+ {
+ if ( m_config->Read( wxString::Format( _T( "/Channels/AutoJoin/Channel%d/Name" ), i ), _T( "" ) ) == name ) ret = i;
+ }
+ return ret;
+}
+
+std::vector<ChannelJoinInfo> Settings::GetChannelsJoin()
+{
+ std::vector<ChannelJoinInfo> ret;
+ int num = GetNumChannelsJoin();
+ for ( int i = 0; i < num; i++ )
+ {
+ ChannelJoinInfo info;
+ info.name = m_config->Read( wxString::Format( _T( "/Channels/AutoJoin/Channel%d/Name" ), i ), _T( "" ) );
+ info.password = m_config->Read( wxString::Format( _T( "/Channels/AutoJoin/Channel%d/Password" ), i ), _T( "" ) );
+ ret.push_back( info );
+ }
+ return ret;
+}
+
+void Settings::ConvertOldChannelSettings()
+{
+ int numchannels = m_config->Read( _T( "/Channels/Count" ), 0l );
+ m_config->DeleteEntry( _T( "/Channels/Count" ) );
+ for ( int i = 0; i < numchannels; i++ )
+ {
+ wxString channelinfo = m_config->Read( _T( "/Channels/Channel" ) + TowxString( i ), _T( "" ) );
+ m_config->DeleteEntry( _T( "/Channels/Channel" ) + TowxString( i ) );
+ if ( channelinfo.Contains( _T( " " ) ) ) AddChannelJoin( channelinfo.BeforeFirst( _T( ' ' ) ), channelinfo.AfterLast( _T( ' ' ) ) );
+ else AddChannelJoin( channelinfo, _T( "" ) );
+ }
+}
+
+bool Settings::ShouldAddDefaultChannelSettings()
+{
+ return !m_config->Exists( _T( "/Channels" ) );
+}
+
+/************* SPRINGLOBBY WINDOW POS/SIZE ******************/
+//! @brief Get width of MainWindow.
+int Settings::GetWindowWidth( const wxString& window )
+{
+ return m_config->Read( _T( "/GUI/" ) + window + _T( "/width" ), DEFSETT_MW_WIDTH );
+}
+
+
+//! @brief Set width position of MainWindow
+void Settings::SetWindowWidth( const wxString& window, const int value )
+{
+ m_config->Write(
+ _T( "/GUI/" ) + window + _T( "/width" ),
+ clamp( value,
+ wxSystemSettings::GetMetric( wxSYS_WINDOWMIN_X ),
+ wxSystemSettings::GetMetric( wxSYS_SCREEN_X )
+ )
+ );
+}
+
+
+//! @brief Get height of MainWindow.
+int Settings::GetWindowHeight( const wxString& window )
+{
+ return m_config->Read( _T( "/GUI/" ) + window + _T( "/height" ), DEFSETT_MW_HEIGHT );
+}
+
+
+//! @brief Set height position of MainWindow
+void Settings::SetWindowHeight( const wxString& window, const int value )
+{
+ m_config->Write(
+ _T( "/GUI/" ) + window + _T( "/height" ),
+ clamp( value,
+ wxSystemSettings::GetMetric( wxSYS_WINDOWMIN_Y ),
+ wxSystemSettings::GetMetric( wxSYS_SCREEN_Y )
+ )
+ );
+}
+
+
+//! @brief Get top position of MainWindow.
+int Settings::GetWindowTop( const wxString& window )
+{
+ return m_config->Read( _T( "/GUI/" ) + window + _T( "/top" ), DEFSETT_MW_TOP );
+}
+
+
+//! @brief Set top position of MainWindow
+void Settings::SetWindowTop( const wxString& window, const int value )
+{
+ m_config->Write(
+ _T( "/GUI/" ) + window + _T( "/top" ),
+ clamp( value,
+ 0,
+ wxSystemSettings::GetMetric( wxSYS_SCREEN_Y ) - 20
+ )
+ );
+}
+
+
+//! @brief Get left position of MainWindow.
+int Settings::GetWindowLeft( const wxString& window )
+{
+ return m_config->Read( _T( "/GUI/" ) + window + _T( "/left" ), DEFSETT_MW_LEFT );
+}
+
+//! @brief Set left position of MainWindow
+void Settings::SetWindowLeft( const wxString& window, const int value )
+{
+ m_config->Write(
+ _T( "/GUI/" ) + window + _T( "/left" ),
+ clamp( value,
+ 0,
+ wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 20
+ )
+ );
+}
+
+//some code duplication necessary to be able to simply use wx defaults
+wxSize Settings::GetWindowSize( const wxString& window, const wxSize& def )
+{
+ wxSize ret = def;
+ ret.SetHeight( m_config->Read( _T( "/GUI/" ) + window + _T( "/height" ), ret.GetHeight() ) );
+ ret.SetWidth( m_config->Read( _T( "/GUI/" ) + window + _T( "/width" ), ret.GetWidth() ) );
+ return ret;
+}
+
+void Settings::SetWindowSize( const wxString& window, const wxSize& size )
+{
+ SetWindowWidth( window, size.GetWidth() );
+ SetWindowHeight( window, size.GetHeight() );
+}
+
+//some code duplication necessary to be able to simply use wx defaults
+wxPoint Settings::GetWindowPos( const wxString& window, const wxPoint& def )
+{
+ wxPoint ret = def;
+ ret.x = m_config->Read( _T( "/GUI/" ) + window + _T( "/left" ), ret.x );
+ ret.y = m_config->Read( _T( "/GUI/" ) + window + _T( "/top" ), ret.y );
+ return ret;
+}
+
+void Settings::SetWindowPos( const wxString& window, const wxPoint& pos )
+{
+ SetWindowLeft( window, pos.x );
+ SetWindowTop( window, pos.y );
+}
+
+// ========================================================
+
+wxPathList Settings::GetAdditionalSearchPaths( wxPathList& pl )
+{
+ wxPathList ret;
+ wxChar sep = wxFileName::GetPathSeparator();
+ wxStandardPathsBase& sp = wxStandardPathsBase::Get();
+
+ pl.Add( wxFileName::GetCwd() );
+ pl.Add( sp.GetExecutablePath() );
+ pl.Add( wxFileName::GetCwd() );
+ pl.Add( sp.GetExecutablePath() );
+ pl.Add( wxFileName::GetHomeDir() );
+ pl.Add( sp.GetUserDataDir().BeforeLast( sep ) );
+ pl.Add( sp.GetDataDir().BeforeLast( sep ) );
+ pl.Add( sp.GetResourcesDir().BeforeLast( sep ) );
+
+ pl.Add( wxGetOSDirectory() );
+
+ for ( size_t i = 0; i < pl.GetCount(); i++ )
+ {
+ wxString path = pl[i];
+ if ( path.Last() != sep ) path += sep;
+ ret.Add( path );
+ ret.Add( path + _T( "Spring" ) + sep );
+ ret.Add( path + _T( "spring" ) + sep );
+ ret.Add( path + _T( "games" ) + sep + _T( "Spring" ) + sep );
+ ret.Add( path + _T( "games" ) + sep + _T( "spring" ) + sep );
+ }
+ return ret;
+}
+
+wxString Settings::AutoFindSpringBin()
+{
+ wxPathList pl;
+
+ pl.AddEnvList( _T( "%ProgramFiles%" ) );
+ pl.AddEnvList( _T( "PATH" ) );
+
+ pl = GetAdditionalSearchPaths( pl );
+
+ return pl.FindValidPath( SPRING_BIN );
+}
+
+
+wxString Settings::AutoFindUnitSync()
+{
+ wxPathList pl;
+
+ pl.AddEnvList( _T( "%ProgramFiles%" ) );
+
+ pl.AddEnvList( _T( "LDPATH" ) );
+ pl.AddEnvList( _T( "LD_LIBRARY_PATH" ) );
+
+ pl.Add( _T( "/usr/local/lib64" ) );
+ pl.Add( _T( "/usr/local/games" ) );
+ pl.Add( _T( "/usr/local/games/lib" ) );
+ pl.Add( _T( "/usr/local/lib" ) );
+ pl.Add( _T( "/usr/lib64" ) );
+ pl.Add( _T( "/usr/lib" ) );
+ pl.Add( _T( "/usr/games" ) );
+ pl.Add( _T( "/usr/games/lib64" ) );
+ pl.Add( _T( "/usr/games/lib" ) );
+
+ pl = GetAdditionalSearchPaths( pl );
+
+ wxString retpath = pl.FindValidPath( _T( "unitsync" ) + GetLibExtension() );
+ if ( retpath.IsEmpty() )
+ retpath = pl.FindValidPath( _T( "libunitsync" ) + GetLibExtension() );
+ return retpath;
+}
+
+
+void Settings::ConvertOldSpringDirsOptions()
+{
+ SetUnitSync( _T( "default" ), m_config->Read( _T( "/Spring/unitsync_loc" ), _T( "" ) ) );
+ SetSpringBinary( _T( "default" ), m_config->Read( _T( "/Spring/exec_loc" ), _T( "" ) ) );
+
+ SetUsedSpringIndex( _T( "default" ) );
+
+ m_config->DeleteEntry( _T( "/Spring/unitsync_loc" ) );
+ m_config->DeleteEntry( _T( "/Spring/use_spring_def_loc" ) );
+ m_config->DeleteEntry( _T( "/Spring/use_unitsync_def_loc" ) );
+ m_config->DeleteEntry( _T( "/Spring/dir" ) );
+ m_config->DeleteEntry( _T( "/Spring/exec_loc" ) );
+}
+
+std::map<wxString, wxString> Settings::GetSpringVersionList()
+{
+ return m_spring_versions;
+}
+
+void Settings::RefreshSpringVersionList()
+{
+ wxLogDebugFunc( _T( "" ) );
+ wxArrayString list = GetGroupList( _T( "/Spring/Paths" ) );
+ int count = list.GetCount();
+ std::map<wxString, wxString> usync_paths;
+ for ( int i = 0; i < count; i++ )
+ {
+ wxString groupname = list[i];
+ usync_paths[groupname] = m_config->Read( _T( "/Spring/Paths/" ) + groupname + _T( "/UnitSyncPath" ), _T( "" ) );
+ }
+ m_spring_versions = susynclib().GetSpringVersionList( usync_paths );
+}
+
+wxString Settings::GetCurrentUsedSpringIndex()
+{
+ return m_config->Read( _T( "/Spring/CurrentIndex" ), _T( "default" ) );
+}
+
+void Settings::SetUsedSpringIndex( const wxString& index )
+{
+ m_config->Write( _T( "/Spring/CurrentIndex" ), index );
+}
+
+bool Settings::GetSearchSpringOnlyInSLPath()
+{
+ bool defaultval = false;
+#ifdef __WXMSW__
+ defaultval = true;
+#endif
+ return m_config->Read( _T( "/Spring/SearchSpringOnlyInSLPath" ), defaultval );
+}
+
+void Settings::SetSearchSpringOnlyInSLPath( bool value )
+{
+ m_config->Write( _T( "/Spring/SearchSpringOnlyInSLPath" ), value );
+}
+
+void Settings::DeleteSpringVersionbyIndex( const wxString& index )
+{
+ m_config->DeleteGroup( _T( "/Spring/Path/" ) + index );
+ if ( GetCurrentUsedSpringIndex() == index ) SetUsedSpringIndex( _T( "" ) );
+}
+
+
+wxString Settings::GetCurrentUsedDataDir()
+{
+ wxString dir;
+ if ( susynclib().IsLoaded() )
+ {
+ if ( susynclib().VersionSupports( IUnitSync::USYNC_GetDataDir ) ) dir = susynclib().GetSpringDataDir();
+ else dir = susynclib().GetSpringConfigString( _T( "SpringData" ), _T( "" ) );
+ }
+#ifdef __WXMSW__
+ if ( dir.IsEmpty() ) dir = GetExecutableFolder(); // fallback
+#else
+ if ( dir.IsEmpty() ) dir = wxFileName::GetHomeDir() + wxFileName::GetPathSeparator() + _T( ".spring" ); // fallback
+#endif
+ return dir;
+}
+
+
+wxString Settings::GetCurrentUsedSpringBinary()
+{
+ if ( IsPortableMode() ) return GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T( "spring.exe" );
+#ifdef __WXMSW__
+ else if ( GetSearchSpringOnlyInSLPath() ) return GetExecutableFolder() + wxFileName::GetPathSeparator() + _T( "spring.exe" );
+#endif
+ else return GetSpringBinary( GetCurrentUsedSpringIndex() );
+}
+
+
+wxString Settings::GetCurrentUsedUnitSync()
+{
+ if ( IsPortableMode() ) return GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T( "unitsync" ) + GetLibExtension();
+#ifdef __WXMSW__
+ else if ( GetSearchSpringOnlyInSLPath() ) return GetExecutableFolder() + wxFileName::GetPathSeparator() + _T( "unitsync" ) + GetLibExtension();
+#endif
+ else return GetUnitSync( GetCurrentUsedSpringIndex() );
+}
+
+wxString Settings::GetCurrentUsedSpringConfigFilePath()
+{
+ wxString path;
+ try
+ {
+ path = susynclib().GetConfigFilePath();
+ }
+ catch ( unitsync_assert ) {}
+ return path;
+}
+
+wxString Settings::GetUnitSync( const wxString& index )
+{
+ return m_config->Read( _T( "/Spring/Paths/" ) + index + _T( "/UnitSyncPath" ), AutoFindUnitSync() );
+}
+
+
+wxString Settings::GetSpringBinary( const wxString& index )
+{
+ return m_config->Read( _T( "/Spring/Paths/" ) + index + _T( "/SpringBinPath" ), AutoFindSpringBin() );
+}
+
+void Settings::SetUnitSync( const wxString& index, const wxString& path )
+{
+ m_config->Write( _T( "/Spring/Paths/" ) + index + _T( "/UnitSyncPath" ), path );
+}
+
+void Settings::SetSpringBinary( const wxString& index, const wxString& path )
+{
+ m_config->Write( _T( "/Spring/Paths/" ) + index + _T( "/SpringBinPath" ), path );
+}
+
+wxString Settings::GetForcedSpringConfigFilePath()
+{
+ if ( IsPortableMode() ) return GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T( "springsettings.cfg" );
+ else return _T( "" );
+}
+
+// ===================================================
+
+bool Settings::GetChatLogEnable()
+{
+ if ( !m_config->Exists( _T( "/ChatLog/chatlog_enable" ) ) ) SetChatLogEnable( true );
+ return m_config->Read( _T( "/ChatLog/chatlog_enable" ), true );
+}
+
+
+void Settings::SetChatLogEnable( const bool value )
+{
+ m_config->Write( _T( "/ChatLog/chatlog_enable" ), value );
+}
+
+
+wxString Settings::GetChatLogLoc()
+{
+ wxString path = GetLobbyWriteDir() + _T( "chatlog" );
+ if ( !wxFileName::DirExists( path ) )
+ {
+ if ( !wxFileName::Mkdir( path, 0755 ) ) return wxEmptyString;
+ }
+ return path;
+}
+
+
+wxString Settings::GetLastHostDescription()
+{
+ return m_config->Read( _T( "/Hosting/LastDescription" ), _T( "" ) );
+}
+
+
+wxString Settings::GetLastHostMod()
+{
+ return m_config->Read( _T( "/Hosting/LastMod" ), _T( "" ) );
+}
+
+
+wxString Settings::GetLastHostPassword()
+{
+ return m_config->Read( _T( "/Hosting/LastPassword" ), _T( "" ) );
+}
+
+
+int Settings::GetLastHostPort()
+{
+ return m_config->Read( _T( "/Hosting/LastPort" ), DEFSETT_SPRING_PORT );
+}
+
+
+int Settings::GetLastHostPlayerNum()
+{
+ return m_config->Read( _T( "/Hosting/LastPlayerNum" ), 4 );
+}
+
+
+int Settings::GetLastHostNATSetting()
+{
+ return m_config->Read( _T( "/Hosting/LastNATSetting" ), ( long )0 );
+}
+
+
+wxString Settings::GetLastHostMap()
+{
+ return m_config->Read( _T( "/Hosting/LastMap" ), _T( "" ) );
+}
+
+int Settings::GetLastRankLimit()
+{
+ return m_config->Read( _T( "/Hosting/LastRank" ), 0l );
+}
+
+bool Settings::GetTestHostPort()
+{
+ return m_config->Read( _T( "/Hosting/TestHostPort" ), 0l );
+}
+
+bool Settings::GetLastAutolockStatus()
+{
+ return m_config->Read( _T( "/Hosting/LastAutoLock" ), true );
+}
+
+bool Settings::GetLastHostRelayedMode()
+{
+ return m_config->Read( _T( "/Hosting/LastRelayedMode" ), 0l );
+}
+
+wxColour Settings::GetBattleLastColour()
+{
+ return wxColour( m_config->Read( _T( "/Hosting/MyLastColour" ), _T( "#FFFF00" ) ) );
+}
+
+
+void Settings::SetBattleLastColour( const wxColour& col )
+{
+ m_config->Write( _T( "/Hosting/MyLastColour" ), col.GetAsString( wxC2S_HTML_SYNTAX ) );
+}
+
+void Settings::SetLastHostDescription( const wxString& value )
+{
+ m_config->Write( _T( "/Hosting/LastDescription" ), value );
+}
+
+
+void Settings::SetLastHostMod( const wxString& value )
+{
+ m_config->Write( _T( "/Hosting/LastMod" ), value );
+}
+
+
+void Settings::SetLastHostPassword( const wxString& value )
+{
+ m_config->Write( _T( "/Hosting/LastPassword" ), value );
+}
+
+
+void Settings::SetLastHostPort( int value )
+{
+ m_config->Write( _T( "/Hosting/LastPort" ), value );
+}
+
+
+void Settings::SetLastHostPlayerNum( int value )
+{
+ m_config->Write( _T( "/Hosting/LastPlayerNum" ), value );
+}
+
+
+void Settings::SetLastHostNATSetting( int value )
+{
+ m_config->Write( _T( "/Hosting/LastNATSetting" ), value );
+}
+
+
+void Settings::SetLastHostMap( const wxString& value )
+{
+ m_config->Write( _T( "/Hosting/LastMap" ), value );
+}
+
+void Settings::SetLastRankLimit( int rank )
+{
+ m_config->Write( _T( "/Hosting/LastRank" ), rank );
+}
+
+void Settings::SetLastAI( const wxString& ai )
+{
+ m_config->Write( _T( "/SinglePlayer/LastAI" ), ai );
+}
+
+void Settings::SetTestHostPort( bool value )
+{
+ m_config->Write( _T( "/Hosting/TestHostPort" ), value );
+}
+
+void Settings::SetLastAutolockStatus( bool value )
+{
+ m_config->Write( _T( "/Hosting/LastAutoLock" ), value );
+}
+
+void Settings::SetLastHostRelayedMode( bool value )
+{
+ m_config->Write( _T( "/Hosting/LastRelayedMode" ), value );
+}
+
+void Settings::SetHostingPreset( const wxString& name, int optiontype, std::map<wxString, wxString> options )
+{
+ m_config->DeleteGroup( _T( "/Hosting/Preset/" ) + name + _T( "/" ) + TowxString( optiontype ) );
+ for ( std::map<wxString, wxString>::iterator it = options.begin(); it != options.end(); ++it )
+ {
+ m_config->Write( _T( "/Hosting/Preset/" ) + name + _T( "/" ) + TowxString( optiontype ) + _T( "/" ) + it->first , it->second );
+ }
+}
+
+std::map<wxString, wxString> Settings::GetHostingPreset( const wxString& name, int optiontype )
+{
+ wxString path_base = _T( "/Hosting/Preset/" ) + name + _T( "/" ) + TowxString( optiontype );
+ std::map<wxString, wxString> ret;
+ wxArrayString list = GetEntryList( path_base );
+
+ wxString old_path = m_config->GetPath();
+ m_config->SetPath( path_base );
+
+ int count = list.GetCount();
+ for ( int i = 0; i < count; i ++ )
+ {
+ wxString keyname = list[i];
+ wxString val = m_config->Read( keyname );
+ ret[keyname] = val;
+ }
+
+ m_config->SetPath( old_path );
+
+ return ret;
+}
+
+
+wxArrayString Settings::GetPresetList()
+{
+ return GetGroupList( _T( "/Hosting/Preset" ) );
+}
+
+
+void Settings::DeletePreset( const wxString& name )
+{
+ m_config->DeleteGroup( _T( "/Hosting/Preset/" ) + name );
+
+ //delete mod default preset associated
+ wxArrayString list = GetEntryList( _T( "/Hosting/ModDefaultPreset" ) );
+ int count = list.GetCount();
+ for ( int i = 0; i < count; i ++ )
+ {
+ wxString keyname = list[i];
+ if ( m_config->Read( keyname ) == name ) m_config->DeleteEntry( keyname );
+ }
+}
+
+
+wxString Settings::GetModDefaultPresetName( const wxString& modname )
+{
+ return m_config->Read( _T( "/Hosting/ModDefaultPreset/" ) + modname );
+}
+
+
+void Settings::SetModDefaultPresetName( const wxString& modname, const wxString& presetname )
+{
+ m_config->Write( _T( "/Hosting/ModDefaultPreset/" ) + modname, presetname );
+}
+
+
+void Settings::SetBalanceMethod( int value )
+{
+ m_config->Write( _T( "/Hosting/BalanceMethod" ), value );
+}
+int Settings::GetBalanceMethod()
+{
+ return m_config->Read( _T( "/Hosting/BalanceMethod" ), 1l );
+}
+
+void Settings::SetBalanceClans( bool value )
+{
+ m_config->Write( _T( "/Hosting/BalanceClans" ), value );
+}
+bool Settings::GetBalanceClans()
+{
+ return m_config->Read( _T( "/Hosting/BalanceClans" ), true );
+}
+
+void Settings::SetBalanceStrongClans( bool value )
+{
+ m_config->Write( _T( "/Hosting/BalanceStrongClans" ), value );
+}
+
+bool Settings::GetBalanceStrongClans()
+{
+ return m_config->Read( _T( "/Hosting/BalanceStrongClans" ), 0l );
+}
+
+void Settings::SetBalanceGrouping( int value )
+{
+ m_config->Write( _T( "/Hosting/BalanceGroupingSize" ), value );
+}
+
+int Settings::GetBalanceGrouping()
+{
+ return m_config->Read( _T( "/Hosting/BalanceGroupingSize" ), 0l );
+}
+
+
+void Settings::SetFixIDMethod( int value )
+{
+ m_config->Write( _T( "/Hosting/FixIDMethod" ), value );
+}
+int Settings::GetFixIDMethod()
+{
+ return m_config->Read( _T( "/Hosting/FixIDMethod" ), 1l );
+}
+
+void Settings::SetFixIDClans( bool value )
+{
+ m_config->Write( _T( "/Hosting/FixIDClans" ), value );
+}
+bool Settings::GetFixIDClans()
+{
+ return m_config->Read( _T( "/Hosting/FixIDClans" ), true );
+}
+
+void Settings::SetFixIDStrongClans( bool value )
+{
+ m_config->Write( _T( "/Hosting/FixIDStrongClans" ), value );
+}
+
+bool Settings::GetFixIDStrongClans()
+{
+ return m_config->Read( _T( "/Hosting/FixIDStrongClans" ), 0l );
+}
+
+void Settings::SetFixIDGrouping( int value )
+{
+ m_config->Write( _T( "/Hosting/FixIDGroupingSize" ), value );
+}
+
+int Settings::GetFixIDGrouping()
+{
+ return m_config->Read( _T( "/Hosting/FixIDGroupingSize" ), 0l );
+}
+
+
+wxString Settings::GetLastAI()
+{
+ return m_config->Read( _T( "/SinglePlayer/LastAI" ), wxEmptyString );
+}
+
+void Settings::SetDisplayJoinLeave( bool display, const wxString& channel )
+{
+ m_config->Write( _T( "/Channels/DisplayJoinLeave/" ) + channel, display );
+}
+
+bool Settings::GetDisplayJoinLeave( const wxString& channel )
+{
+ return m_config->Read( _T( "/Channels/DisplayJoinLeave/" ) + channel, true );
+}
+
+
+void Settings::SetChatHistoryLenght( int historylines )
+{
+ m_config->Write( _T( "/Chat/HistoryLinesLenght/" ), historylines );
+}
+
+
+int Settings::GetChatHistoryLenght()
+{
+ return m_config->Read( _T( "/Chat/HistoryLinesLenght/" ), 1000 );
+}
+
+
+void Settings::SetChatPMSoundNotificationEnabled( bool enabled )
+{
+ m_config->Write( _T( "/Chat/PMSound" ), enabled );
+}
+
+
+bool Settings::GetChatPMSoundNotificationEnabled()
+{
+ return m_config->Read( _T( "/Chat/PMSound" ), 1l );
+}
+
+wxColour ConvertOldRGBFormat( wxString color )
+{
+ long R = 0, G = 0, B = 0;
+ color.BeforeFirst( _T( ' ' ) ).ToLong( &R );
+ color = color.AfterFirst( _T( ' ' ) );
+ color.BeforeFirst( _T( ' ' ) ).ToLong( &G );
+ color = color.AfterFirst( _T( ' ' ) );
+ color.BeforeFirst( _T( ' ' ) ).ToLong( &B );
+ return wxColour( R % 256, G % 256, B % 256 );
+}
+
+void Settings::ConvertOldColorSettings()
+{
+ SetChatColorNormal( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Normal" ), _T( "0 0 0" ) ) ) );
+ SetChatColorBackground( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Background" ), _T( "255 255 255" ) ) ) );
+ SetChatColorHighlight( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Highlight" ), _T( "255 0 0" ) ) ) );
+ SetChatColorMine( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Mine" ), _T( "138 138 138" ) ) ) );
+ SetChatColorNotification( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Notification" ), _T( "255 40 40" ) ) ) );
+ SetChatColorServer( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Server" ), _T( "0 80 128" ) ) ) );
+ SetChatColorClient( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Client" ), _T( "20 200 25" ) ) ) );
+ SetChatColorJoinPart( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/JoinPart" ), _T( "66 204 66" ) ) ) );
+ SetChatColorError( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Error" ), _T( "128 0 0" ) ) ) );
+ SetChatColorTime( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Time" ), _T( "100 100 140" ) ) ) );
+ SetChatColorAction( ConvertOldRGBFormat( m_config->Read( _T( "/Chat/Colour/Action" ), _T( "230 0 255" ) ) ) );
+ SetBattleLastColour( ConvertOldRGBFormat( m_config->Read( _T( "/Hosting/MyLastColour" ), _T( "255 255 0" ) ) ) );
+
+ //convert custom color palette, note 16 colors is wx limit
+ wxArrayString palettes = GetGroupList( _T( "/CustomColors" ) );
+ for ( unsigned int j = 0; j < palettes.GetCount(); j++ )
+ {
+ wxString paletteName = palettes[j];
+ for ( int i = 0; i < 16; ++i )
+ {
+ wxColour col( ConvertOldRGBFormat( m_config->Read( _T( "/CustomColors/" ) + paletteName + _T( "/" ) + TowxString( i ), _T( "255 255 255" ) ) ) );
+ m_config->Write( _T( "/CustomColors/" ) + paletteName + _T( "/" ) + TowxString( i ), col.GetAsString( wxC2S_HTML_SYNTAX ) );
+ }
+ }
+
+ wxArrayString groups = GetGroupList( _T( "/Groups" ) );
+ for ( unsigned int j = 0; j < groups.GetCount(); j++ )
+ {
+ wxString group = groups[j];
+ wxColour col( ConvertOldRGBFormat ( m_config->Read( _T( "/Groups/" ) + group + _T( "/Opts/HLColor" ) , _T( "100 100 140" ) ) ) );
+ m_config->Write( _T( "/Groups/" ) + group + _T( "/Opts/HLColor" ), col.GetAsString( wxC2S_HTML_SYNTAX ) );
+ }
+
+}
+
+wxColour Settings::GetChatColorNormal()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Normal" ), _T( "#000000" ) ) );
+}
+
+void Settings::SetChatColorNormal( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Normal" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+
+wxColour Settings::GetChatColorBackground()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Background" ), _T( "#FFFFFF" ) ) );
+}
+
+void Settings::SetChatColorBackground( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Background" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorHighlight()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Highlight" ), _T( "#FF0000" ) ) );
+}
+
+void Settings::SetChatColorHighlight( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Highlight" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorMine()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Mine" ), _T( "#8A8A8A" ) ) );
+}
+
+void Settings::SetChatColorMine( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Mine" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorNotification()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Notification" ), _T( "#FF2828" ) ) );
+}
+
+void Settings::SetChatColorNotification( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Notification" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorAction()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Action" ), _T( "#E600FF" ) ) );
+}
+
+void Settings::SetChatColorAction( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Action" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorServer()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Server" ), _T( "#005080" ) ) );
+}
+
+void Settings::SetChatColorServer( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Server" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorClient()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Client" ), _T( "#14C819" ) ) );
+}
+
+void Settings::SetChatColorClient( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Client" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorJoinPart()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/JoinPart" ), _T( "#42CC42" ) ) );
+}
+
+void Settings::SetChatColorJoinPart( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/JoinPart" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorError()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Error" ), _T( "#800000" ) ) );
+}
+
+void Settings::SetChatColorError( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Error" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxColour Settings::GetChatColorTime()
+{
+ return wxColour( m_config->Read( _T( "/Chat/Colour/Time" ), _T( "#64648C" ) ) );
+}
+
+void Settings::SetChatColorTime( wxColour value )
+{
+ m_config->Write( _T( "/Chat/Colour/Time" ), value.GetAsString( wxC2S_CSS_SYNTAX ) );
+}
+
+wxFont Settings::GetChatFont()
+{
+ wxString info = m_config->Read( _T( "/Chat/Font" ), wxEmptyString );
+ if ( info != wxEmptyString ) {
+ wxFont f;
+ f.SetNativeFontInfo( info );
+ return f;
+ }
+ else {
+ wxFont f( 8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
+ return f;
+ }
+}
+
+void Settings::SetChatFont( wxFont value )
+{
+ m_config->Write( _T( "/Chat/Font" ), value.GetNativeFontInfoDesc() );
+}
+
+
+bool Settings::GetSmartScrollEnabled()
+{
+ return m_config->Read( _T( "/Chat/SmartScrollEnabled" ), true );
+}
+
+void Settings::SetSmartScrollEnabled( bool value ) {
+ m_config->Write( _T( "/Chat/SmartScrollEnabled" ), value );
+}
+
+bool Settings::GetAlwaysAutoScrollOnFocusLost()
+{
+ return m_config->Read( _T( "/Chat/AlwaysAutoScrollOnFocusLost" ), true );
+}
+
+void Settings::SetAlwaysAutoScrollOnFocusLost( bool value )
+{
+ m_config->Write( _T( "/Chat/AlwaysAutoScrollOnFocusLost" ), value );
+}
+
+void Settings::ConvertOldHiglightSettings()
+{
+ SetHighlightedWords( wxStringTokenize( m_config->Read( _T( "/Chat/HighlightedWords" ), _T( "" ) ), _T( ";" ) ) );
+}
+
+void Settings::SetUseIrcColors( bool value )
+{
+ m_config->Write( _T( "/Chat/UseIrcColors" ), value );
+}
+
+bool Settings::GetUseIrcColors()
+{
+ return m_config->Read( _T( "/Chat/UseIrcColors" ), true );
+}
+
+
+void Settings::SetHighlightedWords( const wxArrayString& words )
+{
+ if ( m_config->Exists( _T( "/Chat/HighlightedWords" ) ) ) // flush existing entries
+ m_config->DeleteGroup( _T( "/Chat/HighlightedWords" ) );
+
+ for ( unsigned int i = 0; i < words.GetCount(); i++ )
+ {
+ m_config->Write( _T( "/Chat/HighlightedWords/" ) + words[i], words[i] );
+ }
+}
+
+wxArrayString Settings::GetHighlightedWords()
+{
+ return GetEntryList( _T( "/Chat/HighlightedWords" ) );
+}
+
+void Settings::SetRequestAttOnHighlight( const bool req )
+{
+ m_config->Write( _T( "/Chat/ReqAttOnHighlight" ), req );
+}
+
+bool Settings::GetRequestAttOnHighlight( )
+{
+ return m_config->Read( _T( "/Chat/ReqAttOnHighlight" ), 0l );
+}
+
+BattleListFilterValues Settings::GetBattleFilterValues( const wxString& profile_name )
+{
+ BattleListFilterValues filtervalues;
+ filtervalues.description = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/description" ), _T( "" ) );
+ filtervalues.host = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/host" ), _T( "" ) );
+ filtervalues.map = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/map" ), _T( "" ) );
+ filtervalues.map_show = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/map_show" ), 0L );
+ filtervalues.maxplayer = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/maxplayer" ), _T( "All" ) );
+ filtervalues.maxplayer_mode = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/maxplayer_mode" ), _T( "=" ) );
+ filtervalues.mod = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/mod" ), _T( "" ) );
+ filtervalues.mod_show = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/mod_show" ), 0L );
+ filtervalues.player_mode = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/player_mode" ), _T( "=" ) );
+ filtervalues.player_num = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/player_num" ), _T( "All" ) );
+ filtervalues.rank = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/rank" ), _T( "All" ) );
+ filtervalues.rank_mode = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/rank_mode" ), _T( "<" ) );
+ filtervalues.spectator = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/spectator" ), _T( "All" ) );
+ filtervalues.spectator_mode = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/spectator_mode" ), _T( "=" ) );
+ filtervalues.status_full = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/status_full" ), true );
+ filtervalues.status_locked = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/status_locked" ), true );
+ filtervalues.status_open = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/status_open" ), true );
+ filtervalues.status_passworded = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/status_passworded" ), true );
+ filtervalues.status_start = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/status_start" ), true );
+ filtervalues.highlighted_only = m_config->Read( _T( "/BattleFilter/" ) + profile_name + _T( "/highlighted_only" ), 0l );
+ return filtervalues;
+}
+
+void Settings::SetBattleFilterValues( const BattleListFilterValues& filtervalues, const wxString& profile_name )
+{
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/description" ), filtervalues.description );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/host" ), filtervalues.host );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/map" ), filtervalues.map );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/map_show" ), filtervalues.map_show );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/maxplayer" ), filtervalues.maxplayer );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/maxplayer_mode" ), filtervalues.maxplayer_mode );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/mod" ), filtervalues.mod );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/mod_show" ), filtervalues.mod_show );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/player_mode" ), filtervalues.player_mode );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/player_num" ), filtervalues.player_num );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/rank" ), filtervalues.rank );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/rank_mode" ), filtervalues.rank_mode );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/spectator" ), filtervalues.spectator );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/spectator_mode" ), filtervalues.spectator_mode );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/status_full" ), filtervalues.status_full );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/status_locked" ), filtervalues.status_locked );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/status_open" ), filtervalues.status_open );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/status_passworded" ), filtervalues.status_passworded );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/status_start" ), filtervalues.status_start );
+ m_config->Write( _T( "/BattleFilter/" ) + profile_name + _T( "/highlighted_only" ), filtervalues.highlighted_only );
+ m_config->Write( _T( "/BattleFilter/lastprofile" ), profile_name );
+}
+
+bool Settings::GetBattleFilterActivState() const
+{
+ return m_config->Read( _T( "/BattleFilter/Active" ) , 0l );
+}
+
+void Settings::SetBattleFilterActivState( const bool state )
+{
+ m_config->Write( _T( "/BattleFilter/Active" ) , state );
+}
+
+bool Settings::GetBattleLastAutoStartState()
+{
+ return m_config->Read( _T( "/Hosting/AutoStart" ) , 0l );
+}
+
+void Settings::SetBattleLastAutoStartState( bool value )
+{
+ m_config->Write( _T( "/Hosting/AutoStart" ), value );
+}
+
+bool Settings::GetBattleLastAutoControlState()
+{
+ return m_config->Read( _T( "/Hosting/AutoControl" ) , 0l );
+}
+
+void Settings::SetBattleLastAutoControlState( bool value )
+{
+ m_config->Write( _T( "/Hosting/AutoControl" ), value );
+}
+
+int Settings::GetBattleLastAutoSpectTime()
+{
+ return m_config->Read( _T( "/Hosting/AutoSpectTime" ) , 0l );
+}
+
+void Settings::SetBattleLastAutoSpectTime( int value )
+{
+ m_config->Write( _T( "/Hosting/AutoSpectTime" ) , value );
+}
+
+bool Settings::GetBattleLastAutoAnnounceDescription()
+{
+ return m_config->Read( _T( "/Hosting/AutoAnnounceDescription" ) , 0l );
+}
+
+void Settings::SetBattleLastAutoAnnounceDescription( bool value )
+{
+ m_config->Write( _T( "/Hosting/AutoAnnounceDescription" ) , value );
+}
+
+void Settings::SetMapLastStartPosType( const wxString& mapname, const wxString& startpostype )
+{
+ m_config->Write( _T( "/Hosting/MapLastValues/" ) + mapname + _T( "/startpostype" ), startpostype );
+}
+
+void Settings::SetMapLastRectPreset( const wxString& mapname, std::vector<Settings::SettStartBox> rects )
+{
+ wxString basepath = _T( "/Hosting/MapLastValues/" ) + mapname + _T( "/Rects" );
+ m_config->DeleteGroup( basepath );
+ for ( std::vector<Settings::SettStartBox>::iterator itor = rects.begin(); itor != rects.end(); itor++ )
+ {
+ SettStartBox box = *itor;
+ wxString additionalpath = basepath + _T( "/Rect" ) + TowxString( box.ally ) + _T( "/" );
+ m_config->Write( additionalpath + _T( "TopLeftX" ), box.topx );
+ m_config->Write( additionalpath + _T( "TopLeftY" ), box.topy );
+ m_config->Write( additionalpath + _T( "BottomRightX" ), box.bottomx );
+ m_config->Write( additionalpath + _T( "BottomRightY" ), box.bottomy );
+ m_config->Write( additionalpath + _T( "AllyTeam" ), box.ally );
+ }
+}
+
+wxString Settings::GetMapLastStartPosType( const wxString& mapname )
+{
+ return m_config->Read( _T( "/Hosting/MapLastValues/" ) + mapname + _T( "/startpostype" ), _T( "" ) );
+}
+
+std::vector<Settings::SettStartBox> Settings::GetMapLastRectPreset( const wxString& mapname )
+{
+ wxString basepath = _T( "/Hosting/MapLastValues/" ) + mapname + _T( "/Rects" );
+ wxArrayString boxes = GetGroupList( basepath );
+ std::vector<Settings::SettStartBox> ret;
+ for ( unsigned int i = 0; i < boxes.GetCount(); i++ )
+ {
+ wxString additionalpath = basepath + _T( "/" ) + boxes[i] + _T( "/" );
+ SettStartBox box;
+ box.topx = m_config->Read( additionalpath + _T( "TopLeftX" ), -1 );
+ box.topy = m_config->Read( additionalpath + _T( "TopLeftY" ), -1 );
+ box.bottomx = m_config->Read( additionalpath + _T( "BottomRightX" ), -1 );
+ box.bottomy = m_config->Read( additionalpath + _T( "BottomRightY" ), -1 );
+ box.ally = m_config->Read( additionalpath + _T( "AllyTeam" ), -1 );
+ ret.push_back( box );
+ }
+ return ret;
+}
+
+bool Settings::GetDisableSpringVersionCheck()
+{
+ bool ret;
+ m_config->Read( _T( "/Spring/DisableVersionCheck" ), &ret, false );
+ return ret;
+}
+
+wxString Settings::GetLastBattleFilterProfileName()
+{
+ return m_config->Read( _T( "/BattleFilter/lastprofile" ), _T( "default" ) );
+}
+
+
+unsigned int Settings::GetTorrentPort()
+{
+ return ( unsigned int )m_config->Read( _T( "/Torrent/Port" ), DEFSETT_SPRING_PORT + 1 );
+}
+
+
+void Settings::SetTorrentPort( unsigned int port )
+{
+ m_config->Write( _T( "/Torrent/port" ), ( int )port );
+}
+
+
+int Settings::GetTorrentUploadRate()
+{
+ return m_config->Read( _T( "/Torrent/UploadRate" ), -1 );
+}
+
+
+void Settings::SetTorrentUploadRate( int speed )
+{
+ m_config->Write( _T( "/Torrent/UploadRate" ), speed );
+}
+
+
+int Settings::GetTorrentDownloadRate()
+{
+ return m_config->Read( _T( "/Torrent/DownloadRate" ), -1 );
+}
+
+
+
+void Settings::SetTorrentDownloadRate( int speed )
+{
+ m_config->Write( _T( "/Torrent/DownloadRate" ), speed );
+}
+
+
+int Settings::GetTorrentSystemSuspendMode()
+{
+ return m_config->Read( _T( "/Torrent/SuspendMode" ), 0l );
+}
+
+
+
+void Settings::SetTorrentSystemSuspendMode( int mode )
+{
+ m_config->Write( _T( "/Torrent/SuspendMode" ), mode );
+}
+
+
+int Settings::GetTorrentThrottledUploadRate()
+{
+ return m_config->Read( _T( "/Torrent/ThrottledUploadRate" ), 0l );
+}
+
+
+void Settings::SetTorrentThrottledUploadRate( int speed )
+{
+ m_config->Write( _T( "/Torrent/ThrottledUploadRate" ), speed );
+}
+
+
+int Settings::GetTorrentThrottledDownloadRate()
+{
+ return m_config->Read( _T( "/Torrent/ThrottledDownloadRate" ), 0l );
+}
+
+
+void Settings::SetTorrentThrottledDownloadRate( int speed )
+{
+ m_config->Write( _T( "/Torrent/ThrottledDownloadRate" ), speed );
+}
+
+
+int Settings::GetTorrentSystemAutoStartMode()
+{
+ return m_config->Read( _T( "/Torrent/AutoStartMode" ), 0l );
+}
+
+
+void Settings::SetTorrentSystemAutoStartMode( int mode )
+{
+ m_config->Write( _T( "/Torrent/AutoStartMode" ), mode );
+}
+
+
+void Settings::SetTorrentMaxConnections( int connections )
+{
+ m_config->Write( _T( "/Torrent/MaxConnections" ), connections );
+}
+
+
+int Settings::GetTorrentMaxConnections()
+{
+ return m_config->Read( _T( "/Torrent/MaxConnections" ), 250 );
+}
+
+void Settings::SetTorrentListToResume( const wxArrayString& list )
+{
+ unsigned int TorrentCount = list.GetCount();
+ m_config->DeleteGroup( _T( "/Torrent/ResumeList" ) );
+ for ( unsigned int i = 0; i < TorrentCount; i++ )
+ {
+ m_config->Write( _T( "/Torrent/ResumeList/" ) + TowxString( i ), list[i] );
+ }
+}
+
+
+wxArrayString Settings::GetTorrentListToResume()
+{
+ wxArrayString list;
+ wxString old_path = m_config->GetPath();
+ m_config->SetPath( _T( "/Torrent/ResumeList" ) );
+ unsigned int TorrentCount = m_config->GetNumberOfEntries( false );
+ for ( unsigned int i = 0; i < TorrentCount; i++ )
+ {
+ wxString ToAdd;
+ if ( m_config->Read( _T( "/Torrent/ResumeList/" ) + TowxString( i ), &ToAdd ) ) list.Add( ToAdd );
+ }
+
+ m_config->SetPath( old_path );
+ return list;
+}
+
+
+wxFileName Settings::GetTorrentDir()
+{
+ wxFileName torrentDir( GetLobbyWriteDir() );
+ torrentDir.AppendDir( _T( "torrents" ) );
+
+ if ( !torrentDir.DirExists() )
+ {
+ if ( !torrentDir.Mkdir( 0755 ) ) torrentDir.Clear();
+ }
+
+ return torrentDir;
+}
+
+wxFileName Settings::GetTorrentDataDir()
+{
+ wxFileName torrentDir( GetLobbyWriteDir() );
+ torrentDir.AppendDir( _T( "downloads" ) );
+
+ if ( !torrentDir.DirExists() )
+ {
+ if ( !torrentDir.Mkdir( 0755 ) ) torrentDir.Clear();
+ }
+
+ return torrentDir;
+}
+
+wxString Settings::GetTempStorage()
+{
+ return wxFileName::GetTempDir();
+}
+
+
+void Settings::SetShowTooltips( bool show )
+{
+ m_config->Write( _T( "/GUI/ShowTooltips" ), show );
+}
+
+bool Settings::GetShowTooltips()
+{
+ return m_config->Read( _T( "/GUI/ShowTooltips" ), 1l );
+}
+
+void Settings::SaveLayout( wxString& layout_name, wxString& layout )
+{
+ m_config->Write( _T( "/Layout/" ) + layout_name, layout );
+}
+
+wxString Settings::GetLayout( wxString& layout_name )
+{
+ return m_config->Read( _T( "/Layout/" ) + layout_name, _T( "" ) );
+}
+
+wxArrayString Settings::GetLayoutList()
+{
+ return GetEntryList( _T( "/Layout" ) );
+}
+
+void Settings::SetDefaultLayout( const wxString& layout_name )
+{
+ m_config->Write( _T( "/GUI/DefaultLayout" ), layout_name );
+}
+
+wxString Settings::GetDefaultLayout()
+{
+ return m_config->Read( _T( "/GUI/DefaultLayout" ), _T( "" ) );
+}
+
+void Settings::SetColumnWidth( const wxString& list_name, const int column_ind, const int column_width )
+{
+ m_config->Write( _T( "GUI/ColumnWidths/" ) + list_name + _T( "/" ) + TowxString( column_ind ), column_width );
+}
+
+int Settings::GetColumnWidth( const wxString& list_name, const int column )
+{
+ const int orgwidth = m_config->Read( _T( "GUI/ColumnWidths/" ) + list_name + _T( "/" ) + TowxString( column ), columnWidthUnset );
+ int width = orgwidth;
+ if ( orgwidth > -1 ) //-3 is unset, -2 and -1 used for auto size by wx
+ width = std::max ( width, int( Settings::columnWidthMinimum ) ); //removing the temporary creation here gives me undefined ref error (koshi)
+ return width;
+}
+
+void Settings::SetPeopleList( const wxArrayString& friends, const wxString& group )
+{
+ unsigned int friendsCount = friends.GetCount();
+ m_config->DeleteGroup( _T( "/Groups/" ) + group + _T( "/Members/" ) );
+ for ( unsigned int i = 0; i < friendsCount ; i++ )
+ {
+ m_config->Write( _T( "/Groups/" ) + group + _T( "/Members/" ) + TowxString( i ), friends[i] );
+ }
+}
+
+wxArrayString Settings::GetPeopleList( const wxString& group ) const
+{
+ wxArrayString list;
+ wxString old_path = m_config->GetPath();
+ m_config->SetPath( _T( "/Groups/" ) + group + _T( "/Members/" ) );
+ unsigned int friendsCount = m_config->GetNumberOfEntries( false );
+ for ( unsigned int i = 0; i < friendsCount ; i++ )
+ {
+ wxString ToAdd;
+ if ( m_config->Read( _T( "/Groups/" ) + group + _T( "/Members/" ) + TowxString( i ), &ToAdd ) ) list.Add( ToAdd );
+ }
+ m_config->SetPath( old_path );
+ return list;
+}
+
+void Settings::SetGroupHLColor( const wxColour& color, const wxString& group )
+{
+ m_config->Write( _T( "/Groups/" ) + group + _T( "/Opts/HLColor" ), color.GetAsString( wxC2S_HTML_SYNTAX ) );
+}
+
+wxColour Settings::GetGroupHLColor( const wxString& group ) const
+{
+ return wxColour( m_config->Read( _T( "/Groups/" ) + group + _T( "/Opts/HLColor" ) , _T( "#64648C" ) ) );
+}
+
+wxArrayString Settings::GetGroups( )
+{
+ return GetGroupList( _T( "/Groups/" ) );
+}
+
+void Settings::AddGroup( const wxString& group )
+{
+ if ( !m_config->Exists( _T( "/Groups/" ) + group ) )
+ {
+ m_config->Write( _T( "/Groups/" ) , group );
+ //set defaults
+ SetGroupActions( group, UserActions::ActNone );
+ SetGroupHLColor( defaultHLcolor, group );
+ }
+}
+
+void Settings::DeleteGroup( const wxString& group )
+{
+ if ( m_config->Exists( _T( "/Groups/" ) + group ) )
+ {
+ m_config->DeleteGroup( _T( "/Groups/" ) + group );
+ }
+}
+
+void Settings::SetGroupActions( const wxString& group, UserActions::ActionType action )
+{
+ //m_config->Write( _T("/Groups/") + group + _T("/Opts/Actions"), action );
+ wxString key = _T( "/Groups/" ) + group + _T( "/Opts/ActionsList" );
+ m_config->DeleteGroup( key );
+ key += _T( "/" );
+ unsigned int tmp = action & ( ( UserActions::ActLast << 1 ) - 1 );
+ int i = 0;
+ while ( tmp != 0 )
+ {
+ if ( tmp&1 )m_config->Write( key + m_configActionNames[i], true );
+ i++;
+ tmp >>= 1;
+ }
+}
+
+UserActions::ActionType Settings::GetGroupActions( const wxString& group ) const
+{
+ wxString key = _T( "/Groups/" ) + group + _T( "/Opts/Actions" );
+ if ( m_config->HasEntry( key ) )// Backward compatibility.
+ {
+ wxLogMessage( _T( "loading deprecated group actions and updating config" ) );
+ UserActions::ActionType action = ( UserActions::ActionType )m_config->Read( key, ( long )UserActions::ActNone ) ;
+ m_config->DeleteEntry( key );
+
+ // a bit ugly, but i want to update options
+ Settings *this_nonconst = const_cast<Settings*>( this );
+ this_nonconst->SetGroupActions( group, action );
+
+ return action;
+ }
+ key = _T( "/Groups/" ) + group + _T( "/Opts/ActionsList" );
+ if ( !m_config->Exists( key ) ) return UserActions::ActNone;
+ key += _T( "/" );
+ int i = 0;
+ int mask = 1;
+ int result = 0;
+ while ( mask <= UserActions::ActLast )
+ {
+ if ( m_config->Read( key + m_configActionNames[i], 0l ) )
+ {
+ result |= mask;
+ }
+ i++;
+ mask <<= 1;
+ }
+ if ( result == 0 ) return UserActions::ActNone;
+ return ( UserActions::ActionType )result;
+}
+
+bool Settings::ShouldAddDefaultGroupSettings()
+{
+ return !m_config->Exists( _T( "/Groups" ) );
+}
+
+void Settings::SaveCustomColors( const wxColourData& _cdata, const wxString& paletteName )
+{
+ //note 16 colors is wx limit
+ wxColourData cdata = _cdata;
+ for ( int i = 0; i < 16; ++i )
+ {
+ wxColour col = cdata.GetCustomColour( i );
+ if ( !col.IsOk() )
+ col = wxColour ( 255, 255, 255 );
+ m_config->Write( _T( "/CustomColors/" ) + paletteName + _T( "/" ) + TowxString( i ), col.GetAsString( wxC2S_HTML_SYNTAX ) ) ;
+ }
+}
+
+wxColourData Settings::GetCustomColors( const wxString& paletteName )
+{
+ wxColourData cdata;
+ //note 16 colors is wx limit
+ for ( int i = 0; i < 16; ++i )
+ {
+ wxColour col( m_config->Read( _T( "/CustomColors/" ) + paletteName + _T( "/" ) + TowxString( i ), wxColour ( 255, 255, 255 ).GetAsString( wxC2S_HTML_SYNTAX ) ) );
+ cdata.SetCustomColour( i, col );
+ }
+
+ return cdata;
+}
+
+
+bool Settings::GetReportStats()
+{
+ return m_config->Read( _T( "/General/reportstats" ), 1l );
+}
+
+
+void Settings::SetReportStats( const bool value )
+{
+ m_config->Write( _T( "/General/reportstats" ), value );
+}
+
+
+void Settings::SetAutoUpdate( const bool value )
+{
+ m_config->Write( _T( "/General/AutoUpdate" ), value );
+}
+
+
+bool Settings::GetAutoUpdate()
+{
+ return m_config->Read( _T( "/General/AutoUpdate" ), true );
+}
+
+PlaybackListFilterValues Settings::GetReplayFilterValues( const wxString& profile_name )
+{
+ PlaybackListFilterValues filtervalues;
+ filtervalues.duration = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/duration" ), _T( "" ) );
+ filtervalues.map = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/map" ), _T( "" ) );
+ filtervalues.map_show = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/map_show" ), 0L );
+ filtervalues.filesize = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/filesize" ), _T( "" ) );
+ filtervalues.filesize_mode = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/filesize_mode" ), _T( ">" ) );
+ filtervalues.duration_mode = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/duration_mode" ), _T( ">" ) );
+ filtervalues.mod = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/mod" ), _T( "" ) );
+ filtervalues.mod_show = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/mod_show" ), 0L );
+ filtervalues.player_mode = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/player_mode" ), _T( "=" ) );
+ filtervalues.player_num = m_config->Read( _T( "/ReplayFilter/" ) + profile_name + _T( "/player_num" ), _T( "All" ) );
+
+ return filtervalues;
+}
+
+void Settings::SetReplayFilterValues( const PlaybackListFilterValues& filtervalues, const wxString& profile_name )
+{
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/duration" ), filtervalues.duration );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/map" ), filtervalues.map );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/map_show" ), filtervalues.map_show );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/filesize" ), filtervalues.filesize );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/filesize_mode" ), filtervalues.filesize_mode );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/duration_mode" ), filtervalues.duration_mode );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/mod" ), filtervalues.mod );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/mod_show" ), filtervalues.mod_show );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/player_mode" ), filtervalues.player_mode );
+ m_config->Write( _T( "/ReplayFilter/" ) + profile_name + _T( "/player_num" ), filtervalues.player_num );
+ m_config->Write( _T( "/ReplayFilter/lastprofile" ), profile_name );
+}
+
+bool Settings::GetReplayFilterActivState() const
+{
+ return m_config->Read( _T( "/ReplayFilter/Active" ) , 0l );
+}
+
+void Settings::SetReplayFilterActivState( const bool state )
+{
+ m_config->Write( _T( "/ReplayFilter/Active" ) , state );
+}
+
+wxString Settings::GetLastReplayFilterProfileName()
+{
+ return m_config->Read( _T( "/ReplayFilter/lastprofile" ), _T( "default" ) );
+}
+wxString Settings::GetLastRelayedHost()
+{
+ return m_config->Read(_T("/General/RelayHost"),_T(""));
+}
+void Settings::SetLastRelayedHost(wxString relhost)
+{
+ m_config->Write(_T("/General/RelayHost"),relhost);
+}
+void Settings::SetCompletionMethod( CompletionMethod method )
+{
+ m_config->Write( _T( "/General/CompletionMethod" ), ( int )method );
+}
+Settings::CompletionMethod Settings::GetCompletionMethod( ) const
+{
+ return ( CompletionMethod )m_config->Read( _T( "/General/CompletionMethod" ), ( int )MatchExact );
+}
+
+
+unsigned int Settings::GetHorizontalSortkeyIndex()
+{
+ return m_config->Read( _T( "/GUI/MapSelector/HorizontalSortkeyIndex" ), 0l );
+}
+
+void Settings::SetHorizontalSortkeyIndex( const unsigned int idx )
+{
+ m_config->Write( _T( "/GUI/MapSelector/HorizontalSortkeyIndex" ), ( int ) idx );
+}
+
+unsigned int Settings::GetVerticalSortkeyIndex()
+{
+ return m_config->Read( _T( "/GUI/MapSelector/VerticalSortkeyIndex" ), 0l );
+}
+
+void Settings::SetVerticalSortkeyIndex( const unsigned int idx )
+{
+ m_config->Write( _T( "/GUI/MapSelector/VerticalSortkeyIndex" ), ( int ) idx );
+}
+
+bool Settings::GetHorizontalSortorder()
+{
+ return m_config->Read( _T( "/GUI/MapSelector/HorizontalSortorder" ), 0l );
+}
+
+void Settings::SetHorizontalSortorder( const bool order )
+{
+ m_config->Write( _T( "/GUI/MapSelector/HorizontalSortorder" ), order );
+}
+
+bool Settings::GetVerticalSortorder()
+{
+ return m_config->Read( _T( "/GUI/MapSelector/VerticalSortorder" ), 0l );
+}
+
+void Settings::SetVerticalSortorder( const bool order )
+{
+ m_config->Write( _T( "/GUI/MapSelector/VerticalSortorder" ), order );
+}
+
+void Settings::SetMapSelectorFollowsMouse( bool value )
+{
+ m_config->Write( _T( "/GUI/MapSelector/SelectionFollowsMouse" ), value );
+}
+
+bool Settings::GetMapSelectorFollowsMouse()
+{
+ return m_config->Read( _T( "/GUI/MapSelector/SelectionFollowsMouse" ), 0l );
+}
+
+unsigned int Settings::GetMapSelectorFilterRadio()
+{
+ return m_config->Read( _T( "/GUI/MapSelector/FilterRadio" ), 0l );
+}
+
+void Settings::SetMapSelectorFilterRadio( const unsigned int val )
+{
+ m_config->Write( _T( "/GUI/MapSelector/FilterRadio" ), ( int ) val );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/// SpringSettings ///
+//////////////////////////////////////////////////////////////////////////////
+
+
+int Settings::getMode()
+{
+ int mode;
+ m_config->Read( _T( "/SpringSettings/mode" ), &mode, SET_MODE_SIMPLE );
+ return mode;
+}
+
+void Settings::setMode( int mode )
+{
+ m_config->Write( _T( "/SpringSettings/mode" ), mode );
+}
+
+bool Settings::getDisableWarning()
+{
+ bool tmp;
+ m_config->Read( _T( "/SpringSettings/disableWarning" ), &tmp, false );
+ return tmp;
+}
+
+void Settings::setDisableWarning( bool disable )
+{
+ m_config->Write( _T( "/SpringSettings/disableWarning" ), disable );
+}
+
+
+wxString Settings::getSimpleRes()
+{
+ wxString def = vl_Resolution_Str[1];
+ m_config->Read( _T( "/SpringSettings/SimpleRes" ), &def );
+ return def;
+}
+void Settings::setSimpleRes( wxString res )
+{
+ m_config->Write( _T( "/SpringSettings/SimpleRes" ), res );
+}
+
+wxString Settings::getSimpleQuality()
+{
+ wxString def = wxT( "medium" );
+ m_config->Read( _T( "/SpringSettings/SimpleQuality" ), &def );
+ return def;
+}
+
+void Settings::setSimpleQuality( wxString qual )
+{
+ m_config->Write( _T( "/SpringSettings/SimpleQuality" ), qual );
+}
+
+wxString Settings::getSimpleDetail()
+{
+ wxString def = wxT( "medium" );
+ m_config->Read( _T( "/SpringSettings/SimpleDetail" ), &def );
+ return def;
+}
+
+void Settings::setSimpleDetail( wxString det )
+{
+ m_config->Write( _T( "/SpringSettings/SimpleDetail" ), det );
+}
+
+bool Settings::IsSpringBin( const wxString& path )
+{
+ if ( !wxFile::Exists( path ) ) return false;
+ if ( !wxFileName::IsFileExecutable( path ) ) return false;
+ return true;
+}
+
+void Settings::SetLanguageID ( const long id )
+{
+ m_config->Write( _T( "/General/LanguageID" ) , id );
+}
+
+long Settings::GetLanguageID ( )
+{
+ return m_config->Read( _T( "/General/LanguageID" ) , wxLANGUAGE_DEFAULT );
+}
+
+SortOrder Settings::GetSortOrder( const wxString& list_name )
+{
+ SortOrder order;
+ wxString old_path = m_config->GetPath();
+ m_config->SetPath( _T( "/UI/SortOrder/" ) + list_name + _T( "/" ) );
+ unsigned int entries = m_config->GetNumberOfGroups( false ); //do not recurse
+ for ( unsigned int i = 0; i < entries ; i++ )
+ {
+ SortOrderItem it;
+ it.direction = m_config->Read( TowxString( i ) + _T( "/dir" ), 1 );
+ it.col = m_config->Read( TowxString( i ) + _T( "/col" ), i );
+ order[i] = it;
+ }
+ m_config->SetPath( old_path );
+ return order;
+}
+
+void Settings::SetSortOrder( const wxString& list_name, const SortOrder& order )
+{
+ SortOrder::const_iterator it = order.begin();
+ for ( ; it != order.end(); ++it ) {
+ m_config->Write( _T( "/UI/SortOrder/" ) + list_name + _T( "/" ) + TowxString( it->first ) + _T( "/dir" ), it->second.direction );
+ m_config->Write( _T( "/UI/SortOrder/" ) + list_name + _T( "/" ) + TowxString( it->first ) + _T( "/col" ), it->second.col );
+ }
+}
+
+bool Settings::GetUseTabIcons()
+{
+ return m_config->Read( _T( "/GUI/UseTabIcons" ), 1l );
+}
+
+void Settings::SetUseTabIcons( bool use )
+{
+ m_config->Write( _T( "/GUI/UseTabIcons" ), use );
+}
+
+int Settings::GetSashPosition( const wxString& window_name )
+{
+ return m_config->Read( _T( "/GUI/SashPostion/" ) + window_name , 200l );
+}
+
+void Settings::SetSashPosition( const wxString& window_name, const int pos )
+{
+ m_config->Write( _T( "/GUI/SashPostion/" ) + window_name , pos );
+}
+
+bool Settings::GetSplitBRoomHorizontally()
+{
+ return m_config->Read( _T( "/GUI/SplitBRoomHorizontally" ) , 1l );
+}
+
+void Settings::SetSplitBRoomHorizontally( const bool vertical )
+{
+ m_config->Write( _T( "/GUI/SplitBRoomHorizontally" ) , vertical );
+}
+
+void Settings::SetStartTab( const int idx )
+{
+ m_config->Write( _T( "/GUI/StartTab" ) , idx );
+}
+
+unsigned int Settings::GetStartTab( )
+{
+ return m_config->Read( _T( "/GUI/StartTab" ) , MainWindow::PAGE_SINGLE ); //default is SP tab
+}
+
+//! simply move saved col size +1 to account for dummy col, force dummy col width to 0
+void Settings::TranslateSavedColumWidths()
+{
+#ifdef SL_DUMMY_COL
+ wxString old_path = m_config->GetPath();
+ bool old_record = m_config->IsRecordingDefaults( );
+ m_config->SetRecordDefaults( false );
+ std::vector<wxString> ctrls;
+ ctrls.push_back( _T( "NickListCtrl" ) );
+ ctrls.push_back( _T( "BattleroomListCtrl" ) );
+ ctrls.push_back( _T( "BattleListCtrl" ) );
+ ctrls.push_back( _T( "WidgetDownloadListCtrl" ) );
+ ctrls.push_back( _T( "ChannelListCtrl" ) );
+ ctrls.push_back( _T( "PlaybackListCtrl" ) );
+ for ( std::vector<wxString>::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it ) {
+ m_config->SetPath( _T( "/GUI/ColumnWidths/" ) + *it );
+ unsigned int entries = m_config->GetNumberOfEntries( false ); //do not recurse
+ for ( unsigned int i = entries; i > 0 ; --i )
+ {
+ m_config->Write( TowxString( i ), m_config->Read( TowxString( i - 1 ) , -1 ) );
+ }
+ m_config->Write( TowxString( 0 ), 0 );
+ }
+
+ m_config->SetPath( old_path );
+ m_config->SetRecordDefaults( old_record );
+ customMessageBoxNoModal( SL_MAIN_ICON, _( "The way column widths are saved has changed, you may need to re-adjust your col widths manually once." ), _( "Important" ) );
+#endif
+}
+
+wxString Settings::GetEditorPath( )
+{
+ #if defined(__WXMSW__)
+ wxString def = wxGetOSDirectory() + wxFileName::GetPathSeparator() + _T("system32") + wxFileName::GetPathSeparator() + _T("notepad.exe");
+ if ( !wxFile::Exists( def ) )
+ def = wxEmptyString;
+ #else
+ wxString def = wxEmptyString;
+ #endif
+ return m_config->Read( _T( "/GUI/Editor" ) , def );
+}
+
+void Settings::SetEditorPath( const wxString& path )
+{
+ m_config->Write( _T( "/GUI/Editor" ) , path );
+}
+
+bool Settings::GetShowXallTabs()
+{
+ return m_config->Read( _T( "/GUI/CloseOnAll" ) , 0l );
+}
+
+void Settings::SetShowXallTabs( bool show )
+{
+ m_config->Write( _T( "/GUI/CloseOnAll" ) , show );
+}
diff --git a/src/settings.h b/src/settings.h
new file mode 100644
index 0000000..0e0d629
--- /dev/null
+++ b/src/settings.h
@@ -0,0 +1,761 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SETTINGS_H
+#define SPRINGLOBBY_HEADERGUARD_SETTINGS_H
+
+#include <wx/string.h>
+#include <vector>
+
+const int CACHE_VERSION = 10;
+const int SETTINGS_VERSION = 15;
+
+const wxString DEFSETT_DEFAULT_SERVER_NAME= _T("Official server");
+const wxString DEFSETT_DEFAULT_SERVER_HOST = _T("taspringmaster.clan-sy.com");
+const int DEFSETT_DEFAULT_SERVER_PORT = 8200;
+const bool DEFSETT_SAVE_PASSWORD = false;
+const unsigned int DEFSETT_MW_WIDTH = 880;
+const unsigned int DEFSETT_MW_HEIGHT = 600;
+const unsigned int DEFSETT_MW_TOP = 50;
+const unsigned int DEFSETT_MW_LEFT = 50;
+const unsigned int DEFSETT_SPRING_PORT = 8452;
+
+const unsigned int SET_MODE_EXPERT = 5000;
+const unsigned int SET_MODE_SIMPLE = 5001;
+const unsigned int DEFSETT_SW_WIDTH = 770;
+const unsigned int DEFSETT_SW_HEIGHT = 580;
+const unsigned int DEFSETT_SW_TOP = 50;
+const unsigned int DEFSETT_SW_LEFT = 50;
+
+const unsigned int SPRING_MAX_USERS = 64;
+const unsigned int SPRING_MAX_TEAMS = 16;
+const unsigned int SPRING_MAX_ALLIES = 16;
+
+/** Default value for config path /General/WebBrowserUseDefault.
+ */
+const bool DEFSETT_WEB_BROWSER_USE_DEFAULT = true;
+
+#include <wx/fileconf.h>
+#include "useractions.h"
+#include "Helper/sortutil.h"
+
+class wxWindow;
+class wxConfigBase;
+class wxFileConfig;
+class wxFont;
+struct BattleListFilterValues;
+struct PlaybackListFilterValues;
+class wxFileInputStream;
+class wxFileName;
+class wxColour;
+class wxColour;
+class wxColourData;
+class wxSize;
+class wxPoint;
+class wxPathList;
+
+typedef std::map<unsigned int,unsigned int> ColumnMap;
+
+struct ChannelJoinInfo
+{
+ wxString name;
+ wxString password;
+};
+
+class SL_WinConf : public wxFileConfig
+{
+ public:
+ SL_WinConf ( const wxString& appName, const wxString& vendorName, const wxString& strLocal, const wxString& strGlobal, long style, const wxMBConv& /*conv*/):
+ wxFileConfig( appName, vendorName, strLocal, strGlobal, style)
+ {
+ }
+
+ SL_WinConf( wxFileInputStream& in );
+ protected:
+ bool DoWriteLong(const wxString& key, long lValue);
+};
+
+
+//! @brief Class used to store and restore application settings.
+class Settings
+{
+ public:
+
+ /** Default constructor.
+ */
+ Settings();
+ ~Settings();
+
+ /** used for passing config file at command line
+ */
+ static bool m_user_defined_config;
+ static wxString m_user_defined_config_path;
+
+ /// used to import default configs from a file in windows
+ #ifdef __WXMSW__
+ void SetDefaultConfigs( SL_WinConf& conf );
+ #else
+ void SetDefaultConfigs( wxConfig& conf );
+ #endif
+
+ /// list all entries subkeys of a parent group
+ wxArrayString GetGroupList( const wxString& base_key );
+ /// list all groups subkeys of a parent group
+ wxArrayString GetEntryList( const wxString& base_key );
+ /// counts all groups subkeys of a parent group
+ unsigned int GetGroupCount( const wxString& base_key );
+
+ bool IsPortableMode();
+ void SetPortableMode( bool mode );
+
+ /** Initialize all settings to default.
+ */
+ void SetDefaultServerSettings();
+ void SaveSettings();
+
+ bool IsFirstRun();
+
+ //! Sets/Gets settings revision number
+ void SetSettingsVersion();
+ unsigned int GetSettingsVersion();
+
+ //! should we sayex/pm bot?
+ void SetReportStats(const bool value);
+ bool GetReportStats();
+
+ void SetAutoUpdate( const bool value );
+ bool GetAutoUpdate();
+
+ wxString GetLobbyWriteDir();
+
+ wxString GetTempStorage();
+
+ /* ================================================================ */
+ /** @name Network
+ * @{
+ */
+ bool GetNoUDP();
+ void SetNoUDP(bool value);
+
+ int GetClientPort();/// use zero to pick port automatically, nonzero to override. This allows to play if you have broken router, by setting SourcePort to some forwarded port.
+ void SetClientPort(int value);
+
+ bool GetShowIPAddresses();
+ void SetShowIPAddresses(bool value);
+ /**@}*/
+
+ /* ================================================================ */
+ /** @name Web Browser
+ *
+ * Web browser preferences.
+ *
+ *@{
+ */
+
+ /** Fetch the "Use Default" setting for the web browser.
+ *
+ * @returns the current setting.
+ */
+ bool GetWebBrowserUseDefault();
+
+
+ /** Set the "Use Default" setting for the web browser. If @c true, we use
+ * wxLaunchDefaultBrowser when we want to open a web browser.
+ *
+ * @param useDefault Whether or not to use the system-default browser.
+ *
+ * @sa Ui::OpenWebBrowser
+ */
+ void SetWebBrowserUseDefault(bool useDefault);
+
+ /** Get the path to the user-configured browser.
+ *
+ * @returns The user-defined browser path, if set, otherwise an empty string
+ * (wxEmptyString).
+ */
+ wxString GetWebBrowserPath();
+
+ /** Set the path to the user-configured browser.
+ *
+ * @param path A path to a web browser
+ */
+ void SetWebBrowserPath( const wxString& path );
+
+ /**@}*/
+
+ /* ================================================================ */
+ /** @name Cache
+ *
+ * Information about the directory tree used to cache infomation about maps
+ * and mods.
+ *
+ * @{
+ */
+ wxString GetCachePath();
+
+ void SetCacheVersion();
+ int GetCacheVersion();
+
+ void SetMapCachingThreadProgress( unsigned int index );
+ unsigned int GetMapCachingThreadProgress();
+
+ void SetModCachingThreadProgress( unsigned int index );
+ unsigned int GetModCachingThreadProgress();
+
+ /**@}*/
+
+ /* ================================================================ */
+ /** @name Servers
+ * @{
+ */
+ void ConvertOldServerSettings();
+ wxString GetDefaultServer();
+ void SetDefaultServer( const wxString& server_name );
+ void SetAutoConnect( bool do_autoconnect );
+ bool GetAutoConnect( );
+
+ wxString GetServerHost( const wxString& server_name );
+ int GetServerPort( const wxString& server_name );
+
+ wxArrayString GetServers();
+ bool ServerExists( const wxString& server_name );
+ void SetServer( const wxString& server_name, const wxString& url, int port );
+ void DeleteServer( const wxString& server_name );
+
+ bool ShouldAddDefaultServerSettings();
+ /**@}*/
+
+ /* ================================================================ */
+ /** @name Accounts
+ * @{
+ */
+ wxString GetServerAccountNick( const wxString& server_name );
+ void SetServerAccountNick( const wxString& server_name, const wxString& value );
+
+ wxString GetServerAccountPass( const wxString& server_name );
+ void SetServerAccountPass( const wxString& server_name, const wxString& value );
+
+ bool GetServerAccountSavePass( const wxString& server_name );
+ void SetServerAccountSavePass( const wxString& server_name, const bool value );
+ /**@}*/
+
+ /* ================================================================ */
+ /** @name Automatic channel join list
+ *
+ * These functions are used to manipulate the list of channels that
+ * SpringLobby should join upon connecting to a server.
+ *
+ * @{
+ */
+
+ /** Fetch the number of channels in the autojoin list.
+ */
+ int GetNumChannelsJoin();
+
+
+ /** Add a channel to the autojoin list.
+ */
+ void AddChannelJoin( const wxString& channel , const wxString& key );
+
+ /** Remove a channel from the autojoin list.
+ *
+ * @param channel The name of the channel to remove
+ */
+ void RemoveChannelJoin( const wxString& channel );
+
+
+ /** Returns the list of channels to autojoin
+ *
+ * @returns std::vector of ChannelJoinInfo struct, don't break ordering index!
+ */
+ std::vector<ChannelJoinInfo> GetChannelsJoin();
+
+
+ /** Deletes all autojoined channels
+ *
+ */
+ void RemoveAllChannelsJoin();
+
+ /** Returns the join order of a channel
+ *
+ * @returns the order of the channel during autojoin or -1 if not found
+ */
+ int GetChannelJoinIndex( const wxString& name );
+
+ void ConvertOldChannelSettings();
+
+ bool ShouldAddDefaultChannelSettings();
+ /**@}*/
+
+ /* ================================================================ */
+ /** @name UI
+ * @{
+ */
+
+ void SetStartTab( const int idx );
+ unsigned int GetStartTab( );
+
+ void SaveCustomColors( const wxColourData& cdata, const wxString& paletteName = _T("Default") );
+ wxColourData GetCustomColors( const wxString& paletteName = _T("Default") );
+
+ int GetWindowWidth( const wxString& window );
+ void SetWindowWidth( const wxString& window, const int value );
+
+ int GetWindowHeight( const wxString& window );
+ void SetWindowHeight( const wxString& window, const int value );
+
+ int GetWindowTop( const wxString& window );
+ void SetWindowTop( const wxString& window, const int value );
+
+ int GetWindowLeft( const wxString& window );
+ void SetWindowLeft( const wxString& window, const int value );
+
+ wxSize GetWindowSize( const wxString& window, const wxSize& def );
+ void SetWindowSize( const wxString& window, const wxSize& size );
+
+ wxPoint GetWindowPos( const wxString& window, const wxPoint& def );
+ void SetWindowPos( const wxString& window, const wxPoint& pos );
+
+ bool UseOldSpringLaunchMethod();
+ void SetOldSpringLaunchMethod( bool value );
+
+ void SetShowTooltips( bool show);
+ bool GetShowTooltips();
+
+ ColumnMap GetColumnMap( const wxString& name );
+ void GetColumnMap( const wxString& name, const ColumnMap& map );
+
+ SortOrder GetSortOrder( const wxString& list_name );
+ void SetSortOrder( const wxString& list_name, const SortOrder& order );
+
+ void SetColumnWidth( const wxString& list_name, const int column_ind, const int column_width );
+ int GetColumnWidth( const wxString& list_name, const int column );
+ //! used to signal unset column width in Get...
+ static const int columnWidthUnset = -3;
+ static const int columnWidthMinimum = 5;
+
+ void SetLanguageID ( const long id );
+ long GetLanguageID ( );
+
+ int GetSashPosition( const wxString& window_name );
+ void SetSashPosition( const wxString& window_name, const int pos );
+
+ bool GetSplitBRoomHorizontally();
+ void SetSplitBRoomHorizontally( const bool vertical );
+
+ bool GetShowXallTabs();
+ void SetShowXallTabs( bool show );
+
+ void TranslateSavedColumWidths();
+
+ wxString GetEditorPath( );
+ void SetEditorPath( const wxString& path );
+ /*@}*/
+
+ /* ================================================================ */
+ /** @name People/Group management
+ * @{
+ */
+ void SetPeopleList( const wxArrayString& friends, const wxString& group = _T("default") );
+ wxArrayString GetPeopleList( const wxString& group = _T("default") ) const;
+
+ wxArrayString GetGroups( );
+ void AddGroup( const wxString& group ) ;
+ void DeleteGroup( const wxString& group ) ;
+
+ void SetGroupHLColor( const wxColour& color, const wxString& group = _T("default") );
+ wxColour GetGroupHLColor( const wxString& group = _T("default") ) const;
+
+ void SetGroupActions( const wxString& group, UserActions::ActionType action );
+ UserActions::ActionType GetGroupActions( const wxString& group ) const;
+
+ bool ShouldAddDefaultGroupSettings();
+
+ /*@}*/
+
+ /* ================================================================ */
+ /** @name Spring locations
+ * @{
+ */
+
+ wxPathList GetAdditionalSearchPaths( wxPathList& pl );
+
+ void ConvertOldSpringDirsOptions();
+
+ void RefreshSpringVersionList();
+ std::map<wxString, wxString> GetSpringVersionList(); /// index -> version
+ wxString GetCurrentUsedSpringIndex();
+ void SetUsedSpringIndex( const wxString& index );
+ void DeleteSpringVersionbyIndex( const wxString& index );
+
+ /// when this mode is enabled in windows SL will search for spring files only in the current executable folder
+ void SetSearchSpringOnlyInSLPath( bool value );
+ bool GetSearchSpringOnlyInSLPath();
+
+ /// convenience wrappers to get current used version paths
+ wxString GetCurrentUsedDataDir();
+ wxString GetCurrentUsedUnitSync();
+ wxString GetCurrentUsedSpringBinary();
+ //!@brief returns config file path unitsync uses, returns empty if unitsync isn't loaded
+ wxString GetCurrentUsedSpringConfigFilePath();
+
+ wxString GetUnitSync( const wxString& index );
+ wxString GetSpringBinary( const wxString& index );
+
+ void SetUnitSync( const wxString& index, const wxString& path );
+ void SetSpringBinary( const wxString& index, const wxString& path );
+
+ wxString AutoFindSpringBin();
+ wxString AutoFindUnitSync();
+
+ //!@brief returns config file path spring should use, returns empty for default
+ wxString GetForcedSpringConfigFilePath();
+
+ /*@}*/
+
+ /* ================================================================ */
+ /** @name Chat
+ * @{
+ */
+ bool GetChatLogEnable();
+ void SetChatLogEnable( const bool value );
+ wxString GetChatLogLoc();
+ void SetChatLogLoc( const wxString& loc );
+
+ //!@brief sets how many lines can stay in a chat panel before the old will start getting erased, 0 to disable
+ void SetChatHistoryLenght( int historylines );
+ int GetChatHistoryLenght();
+
+ void SetChatPMSoundNotificationEnabled( bool enabled );
+ bool GetChatPMSoundNotificationEnabled();
+
+ void ConvertOldColorSettings();
+
+ wxColour GetChatColorNormal();
+ void SetChatColorNormal( wxColour value );
+ wxColour GetChatColorBackground();
+ void SetChatColorBackground( wxColour value );
+ wxColour GetChatColorHighlight();
+ void SetChatColorHighlight( wxColour value );
+ wxColour GetChatColorMine();
+ void SetChatColorMine( wxColour value );
+ wxColour GetChatColorNotification();
+ void SetChatColorNotification( wxColour value );
+ wxColour GetChatColorAction();
+ void SetChatColorAction( wxColour value );
+ wxColour GetChatColorServer();
+ void SetChatColorServer( wxColour value );
+ wxColour GetChatColorClient();
+ void SetChatColorClient( wxColour value );
+ wxColour GetChatColorJoinPart();
+ void SetChatColorJoinPart( wxColour value );
+ wxColour GetChatColorError();
+ void SetChatColorError( wxColour value );
+ wxColour GetChatColorTime();
+ void SetChatColorTime( wxColour value );
+ wxFont GetChatFont();
+ void SetChatFont( wxFont value );
+
+ void SetDisplayJoinLeave( bool display, const wxString& channel );
+ bool GetDisplayJoinLeave( const wxString& channel );
+
+ void SetHighlightedWords( const wxArrayString& words );
+ wxArrayString GetHighlightedWords( );
+
+ //!\brief controls if user attention is requested when highlighting a line
+ void SetRequestAttOnHighlight( const bool req );
+ bool GetRequestAttOnHighlight( );
+ /**@}*/
+
+ /* Do these go in Chat? */
+ bool GetSmartScrollEnabled();
+ void SetSmartScrollEnabled(bool value);
+ bool GetAlwaysAutoScrollOnFocusLost();
+ void SetAlwaysAutoScrollOnFocusLost(bool value);
+
+ void ConvertOldHiglightSettings();
+
+ void SetUseIrcColors( bool value );
+ bool GetUseIrcColors();
+
+ /* ================================================================ */
+ /** @name Hosting
+ *
+ * %Settings to use when hosting games. Includes "sticky" settings from the
+ * last time a game was hosted.
+ *
+ * @{
+ */
+ wxString GetLastHostDescription();
+ wxString GetLastHostMod();
+ wxString GetLastHostPassword();
+ int GetLastHostPort();
+ int GetLastHostPlayerNum();
+ int GetLastHostNATSetting();
+ wxString GetLastHostMap();
+ int GetLastRankLimit();
+ bool GetTestHostPort();
+ bool GetLastAutolockStatus();
+ bool GetLastHostRelayedMode();
+
+ void SetLastHostDescription( const wxString& value );
+ void SetLastHostMod( const wxString& value );
+ void SetLastHostPassword( const wxString& value );
+ void SetLastHostPort( int value );
+ void SetLastHostPlayerNum( int value );
+ void SetLastHostNATSetting( int value );
+ void SetLastHostMap( const wxString& value );
+ void SetLastRankLimit( int rank );
+ void SetTestHostPort( bool value );
+ void SetLastAutolockStatus( bool value );
+ void SetLastHostRelayedMode( bool value );
+
+ void SetHostingPreset( const wxString& name, int optiontype, std::map<wxString,wxString> options );
+ std::map<wxString,wxString> GetHostingPreset( const wxString& name, int optiontype );
+ wxArrayString GetPresetList();
+ void DeletePreset( const wxString& name );
+
+ wxString GetModDefaultPresetName( const wxString& modname );
+ void SetModDefaultPresetName( const wxString& modname, const wxString& presetname );
+
+ /**@}*/
+
+
+ /* ================================================================ */
+ wxColour GetBattleLastColour();
+ void SetBattleLastColour( const wxColour& col );
+
+
+ void SetLastAI( const wxString& ai );
+ wxString GetLastAI();
+
+ void SetBalanceMethod(int value);
+ int GetBalanceMethod();
+
+ void SetBalanceClans(bool value);
+ bool GetBalanceClans();
+
+ void SetBalanceStrongClans(bool value);
+ bool GetBalanceStrongClans();
+
+ void SetBalanceGrouping( int value );
+ int GetBalanceGrouping();
+
+ void SetFixIDMethod(int value);
+ int GetFixIDMethod();
+
+ void SetFixIDClans(bool value);
+ bool GetFixIDClans();
+
+ void SetFixIDStrongClans(bool value);
+ bool GetFixIDStrongClans();
+
+ void SetFixIDGrouping( int value );
+ int GetFixIDGrouping();
+
+ /** @name Battle filters
+ * @{
+ */
+ BattleListFilterValues GetBattleFilterValues(const wxString& profile_name = (_T("default")));
+ void SetBattleFilterValues(const BattleListFilterValues& blfValues, const wxString& profile_name = _T("default"));
+ wxString GetLastBattleFilterProfileName();
+ void SetBattleFilterActivState( const bool state );
+ bool GetBattleFilterActivState( ) const;
+
+ bool GetBattleLastAutoStartState();
+ void SetBattleLastAutoStartState( bool value );
+
+ bool GetBattleLastAutoControlState();
+ void SetBattleLastAutoControlState( bool value );
+
+ int GetBattleLastAutoSpectTime();
+ void SetBattleLastAutoSpectTime( int value );
+
+ bool GetBattleLastAutoAnnounceDescription();
+ void SetBattleLastAutoAnnounceDescription( bool value );
+
+ struct SettStartBox
+ {
+ int ally;
+ int topx;
+ int topy;
+ int bottomx;
+ int bottomy;
+ };
+
+ void SetMapLastStartPosType( const wxString& mapname, const wxString& startpostype );
+ void SetMapLastRectPreset( const wxString& mapname, std::vector<Settings::SettStartBox> rects );
+
+ wxString GetMapLastStartPosType( const wxString& mapname );
+ std::vector<Settings::SettStartBox> GetMapLastRectPreset( const wxString& mapname );
+ /**@}*/
+
+ /** @name Replay filters
+ * @{
+ */
+ PlaybackListFilterValues GetReplayFilterValues(const wxString& profile_name = (_T("default")));
+ void SetReplayFilterValues(const PlaybackListFilterValues& blfValues, const wxString& profile_name = _T("default"));
+ wxString GetLastReplayFilterProfileName();
+ void SetReplayFilterActivState( const bool state );
+ bool GetReplayFilterActivState( ) const;
+ /**@}*/
+
+ bool GetDisableSpringVersionCheck();
+
+ /* ================================================================ */
+ /** @name Torrent System
+ * @{
+ */
+ unsigned int GetTorrentPort();
+ void SetTorrentPort( unsigned int port );
+ int GetTorrentUploadRate();
+ void SetTorrentUploadRate( int speed );
+ int GetTorrentDownloadRate();
+ void SetTorrentDownloadRate( int speed );
+
+ int GetTorrentSystemSuspendMode();
+ void SetTorrentSystemSuspendMode( int mode );
+ int GetTorrentThrottledUploadRate();
+ void SetTorrentThrottledUploadRate( int speed );
+ int GetTorrentThrottledDownloadRate();
+ void SetTorrentThrottledDownloadRate( int speed );
+
+ int GetTorrentSystemAutoStartMode();
+ void SetTorrentSystemAutoStartMode( int mode );
+
+ void SetTorrentMaxConnections( int connections );
+ int GetTorrentMaxConnections();
+
+ void SetTorrentListToResume( const wxArrayString& list );
+ wxArrayString GetTorrentListToResume();
+
+ /** Get the path to the directory where *.torrent files are stored.
+ */
+ wxFileName GetTorrentDir();
+
+
+ /** Get the path to the directory where partially-downloaded
+ * torrented files are stored.
+ *
+ * @sa GetTorrentsFolder
+ */
+ wxFileName GetTorrentDataDir();
+
+ /**@}*/
+
+ /** @name Aui
+ *
+ * Functions used to store and retrieve the current SpringLobby
+ * interface layout.
+ *
+ * @{
+ */
+ void SaveLayout( wxString& layout_name, wxString& layout_string );
+ wxString GetLayout( wxString& layout_name );
+ wxArrayString GetLayoutList();
+ void SetDefaultLayout( const wxString& layout_name );
+ wxString GetDefaultLayout();
+ //! icons for mainwindow tabs??
+ bool GetUseTabIcons();
+ void SetUseTabIcons( bool use );
+ /**@}*/
+
+ enum CompletionMethod {
+ MatchNearest = 1,
+ MatchExact = 2
+ };
+
+ void SetCompletionMethod( CompletionMethod method );
+ CompletionMethod GetCompletionMethod( ) const;
+
+ /** @name SpringSettings
+ * @{
+ */
+ int getMode();
+ void setMode( int );
+ bool getDisableWarning();
+ void setDisableWarning( bool );
+ wxString getSimpleRes();
+ void setSimpleRes( wxString );
+ wxString getSimpleQuality();
+ void setSimpleQuality( wxString );
+ wxString getSimpleDetail();
+ void setSimpleDetail( wxString );
+
+ /**@}*/
+
+ /* ================================================================ */
+ /** @name Map selection dialog
+ * @{
+ */
+ unsigned int GetVerticalSortkeyIndex( );
+ void SetVerticalSortkeyIndex( const unsigned int idx );
+
+ unsigned int GetHorizontalSortkeyIndex( );
+ void SetHorizontalSortkeyIndex( const unsigned int idx );
+
+ /** \return true for "<" false for ">" */
+ bool GetHorizontalSortorder();
+ void SetHorizontalSortorder( const bool order );
+
+ /** \return true for "á´§", false for "á´ " */
+ bool GetVerticalSortorder();
+ void SetVerticalSortorder( const bool order );
+
+ void SetMapSelectorFollowsMouse( bool value );
+ bool GetMapSelectorFollowsMouse();
+
+ /** \return m_filter_all_sett = 0; (default)
+ m_filter_recent_sett = 1;
+ m_filter_popular_sett = 2; */
+ unsigned int GetMapSelectorFilterRadio();
+ void SetMapSelectorFilterRadio( const unsigned int val );
+ /**@}*/
+ /* ============================================================== */
+ /** @name Relayed Hosts
+ * @{
+ */
+
+ wxString GetLastRelayedHost(void);
+ void SetLastRelayedHost(wxString relhost);
+
+ /**@}*/
+
+ protected:
+ bool IsSpringBin( const wxString& path );
+
+ #ifdef __WXMSW__
+ SL_WinConf* m_config; //!< wxConfig object to store and restore all settings in.
+ #elif defined(__WXMAC__)
+ wxFileConfig* m_config; //!< wxConfig object to store and restore all settings in.
+ #else
+ wxConfigBase* m_config; //!< wxConfig object to store and restore all settings in.
+ #endif
+
+ wxString m_chosen_path;
+ bool m_portable_mode;
+
+ std::map<wxString, wxString> m_spring_versions;
+
+ Settings( const Settings& );
+
+};
+
+Settings& sett();
+
+#endif // SPRINGLOBBY_HEADERGUARD_SETTINGS_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/singleplayerbattle.cpp b/src/singleplayerbattle.cpp
new file mode 100644
index 0000000..78fe5c9
--- /dev/null
+++ b/src/singleplayerbattle.cpp
@@ -0,0 +1,77 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include <stdexcept>
+#include <wx/log.h>
+
+#include "singleplayerbattle.h"
+#include "mainsingleplayertab.h"
+#include "server.h"
+#include "ui.h"
+#include "settings.h"
+#include "spring.h"
+
+
+SinglePlayerBattle::SinglePlayerBattle(Ui& ui, MainSinglePlayerTab& msptab):
+ m_ui(ui),
+ m_sptab(msptab),
+ m_me( User( usync().IsLoaded() ? usync().GetDefaultNick() : _T("invalid") ) )
+{
+ OnUserAdded( m_me );
+ m_me.BattleStatus().colour = sett().GetBattleLastColour();
+ CustomBattleOptions().setSingleOption( _T("startpostype"), wxString::Format(_T("%d"), ST_Pick), OptionsWrapper::EngineOption );
+}
+
+
+SinglePlayerBattle::~SinglePlayerBattle()
+{
+
+}
+
+
+void SinglePlayerBattle::SendHostInfo( HostInfo update )
+{
+ if ( (update & HI_StartType) != 0 ) m_sptab.UpdateMinimap();
+ if ( (update & HI_Restrictions) != 0 ) m_sptab.ReloadRestrictions();
+ if ( (update & HI_Map_Changed) != 0 )
+ {
+ SetLocalMap( usync().GetMapEx( usync().GetMapIndex( m_host_map.name ) ) );
+ CustomBattleOptions().loadOptions( OptionsWrapper::MapOption, GetHostMapName() );
+ m_sptab.ReloadMapOptContrls();
+ }
+ if ( (update & HI_Mod_Changed) != 0 )
+ {
+ for ( unsigned int num = 1; num < GetNumBots(); num++ ) KickPlayer( GetUser( num ) ); // remove all bots
+ CustomBattleOptions().loadOptions( OptionsWrapper::ModOption, GetHostModName() );
+ wxString presetname = sett().GetModDefaultPresetName( GetHostModName() );
+ if ( !presetname.IsEmpty() )
+ {
+ LoadOptionsPreset( presetname );
+ SendHostInfo( HI_Send_All_opts );
+ }
+ m_sptab.ReloadModOptContrls();
+ Update( wxString::Format(_T("%d_%s"), OptionsWrapper::PrivateOptions , _T("mapname") ) );
+ }
+ if ( (update & HI_Send_All_opts) != 0 )
+ {
+ for ( int i = 0; i < (int)OptionsWrapper::LastOption; i++)
+ {
+ std::map<wxString,wxString> options = CustomBattleOptions().getOptionsMap( (OptionsWrapper::GameOption)i );
+ for ( std::map<wxString,wxString>::iterator itor = options.begin(); itor != options.end(); itor++ )
+ {
+ Update( wxString::Format(_T("%d_%s"), i , itor->first.c_str() ) );
+ }
+ }
+ }
+}
+
+
+void SinglePlayerBattle::Update( const wxString& Tag )
+{
+ m_sptab.Update( Tag );
+}
+
+void SinglePlayerBattle::StartSpring()
+{
+ spring().Run( *this );
+ ui().OnSpringStarting();
+}
diff --git a/src/singleplayerbattle.h b/src/singleplayerbattle.h
new file mode 100644
index 0000000..4d69f94
--- /dev/null
+++ b/src/singleplayerbattle.h
@@ -0,0 +1,63 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SINGLEPLAYERBATTLE_H
+#define SPRINGLOBBY_HEADERGUARD_SINGLEPLAYERBATTLE_H
+
+#include "ibattle.h"
+#include "user.h"
+
+class Ui;
+class BattleBot;
+class MainSinglePlayerTab;
+class wxColour;
+class wxString;
+
+
+class SinglePlayerBattle: public IBattle
+{
+ public:
+
+ SinglePlayerBattle( Ui& ui, MainSinglePlayerTab& msptab );
+ ~SinglePlayerBattle();
+
+// (koshi) these are never called
+// unsigned int AddBot( int ally, int posx, int posy, int handicap, const wxString& aidll );
+// void UpdateBot( unsigned int index, int ally, int posx, int posy, int side );
+
+ bool IsFounderMe() { return true; }
+
+ User& GetMe() { return m_me; }
+
+ void SendHostInfo( HostInfo update );
+ void SendHostInfo( const wxString& /*unused*/ ){}
+
+ void Update( const wxString& Tag );
+
+ void StartSpring();
+
+ protected:
+
+ Ui& m_ui;
+ MainSinglePlayerTab& m_sptab;
+
+ User m_me;
+
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_SINGLEPLAYERBATTLE_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/singleplayertab.cpp b/src/singleplayertab.cpp
new file mode 100644
index 0000000..417473a
--- /dev/null
+++ b/src/singleplayertab.cpp
@@ -0,0 +1,393 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+
+#include <wx/intl.h>
+#include <wx/sizer.h>
+#include <wx/choice.h>
+#include <wx/button.h>
+#include <wx/panel.h>
+#include <wx/statline.h>
+#include <wx/stattext.h>
+#include <wx/checkbox.h>
+#include <wx/colordlg.h>
+
+#include "singleplayertab.h"
+#include "mapctrl.h"
+#include "mapselectdialog.h"
+#include "utils/controls.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "uiutils.h"
+#include "ui.h"
+#include "iunitsync.h"
+#include "addbotdialog.h"
+#include "server.h"
+#include "settings.h"
+#include "Helper/colorbutton.h"
+#include "aui/auimanager.h"
+#include "settings++/custom_dialogs.h"
+#include "springunitsynclib.h"
+
+BEGIN_EVENT_TABLE(SinglePlayerTab, wxPanel)
+
+ EVT_CHOICE( SP_MAP_PICK, SinglePlayerTab::OnMapSelect )
+ EVT_CHOICE( SP_MOD_PICK, SinglePlayerTab::OnModSelect )
+ EVT_BUTTON( SP_BROWSE_MAP, SinglePlayerTab::OnMapBrowse )
+ EVT_BUTTON( SP_ADD_BOT, SinglePlayerTab::OnAddBot )
+ EVT_BUTTON( SP_RESET, SinglePlayerTab::OnReset )
+ EVT_BUTTON( SP_START, SinglePlayerTab::OnStart )
+ EVT_CHECKBOX( SP_RANDOM, SinglePlayerTab::OnRandomCheck )
+ EVT_CHECKBOX( SP_SPECTATE, SinglePlayerTab::OnSpectatorCheck )
+ EVT_BUTTON( SP_COLOUR, SinglePlayerTab::OnColorButton )
+ EVT_MOUSEWHEEL( SinglePlayerTab::OnMouseWheel )
+
+END_EVENT_TABLE()
+
+
+SinglePlayerTab::SinglePlayerTab(wxWindow* parent, Ui& ui, MainSinglePlayerTab& msptab):
+ wxScrolledWindow( parent, -1 ),
+ m_ui( ui ),
+ m_battle( ui, msptab )
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("singleplayertab") );
+
+ wxBoxSizer* m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_minimap = new MapCtrl( this, 100, &m_battle, ui, false, false, true, true );
+ m_minimap->SetToolTip( TE(_("You can drag the sun/bot icon around to define start position.\n "
+ "Hover over the icon for a popup that lets you change side, ally and bonus." )) );
+ m_main_sizer->Add( m_minimap, 1, wxALL|wxEXPAND, 5 );
+
+ wxBoxSizer* m_ctrl_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_map_lbl = new wxStaticText( this, -1, _("Map:") );
+ m_ctrl_sizer->Add( m_map_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ m_map_pick = new wxChoice( this, SP_MAP_PICK );
+ m_ctrl_sizer->Add( m_map_pick, 1, wxALL, 5 );
+
+ m_select_btn = new wxButton( this, SP_BROWSE_MAP, _T("..."), wxDefaultPosition, wxSize(CONTROL_HEIGHT, CONTROL_HEIGHT), wxBU_EXACTFIT );
+ m_ctrl_sizer->Add( m_select_btn, 0, wxBOTTOM|wxRIGHT|wxTOP, 5 );
+
+ m_mod_lbl = new wxStaticText( this, -1, _("Mod:") );
+ m_ctrl_sizer->Add( m_mod_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+
+ m_mod_pick = new wxChoice( this, SP_MOD_PICK );
+ m_ctrl_sizer->Add( m_mod_pick, 1, wxALL, 5 );
+
+
+// m_ctrl_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+ m_addbot_btn = new wxButton( this, SP_ADD_BOT, _("Add bot..."), wxDefaultPosition, wxSize(80, CONTROL_HEIGHT), 0 );
+ m_ctrl_sizer->Add( m_addbot_btn, 0, wxALL, 5 );
+
+ m_main_sizer->Add( m_ctrl_sizer, 0, wxEXPAND, 5 );
+
+ m_buttons_sep = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ m_main_sizer->Add( m_buttons_sep, 0, wxLEFT|wxRIGHT|wxEXPAND, 5 );
+
+ wxBoxSizer* m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+// see http://trac.springlobby.info/ticket/649
+// m_reset_btn = new wxButton( this, SP_RESET, _("Reset"), wxDefaultPosition, wxSize(80, CONTROL_HEIGHT), 0 );
+// m_buttons_sizer->Add( m_reset_btn, 0, wxALL, 5 );
+
+ m_buttons_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
+
+ m_color_btn = new ColorButton( this, SP_COLOUR, sett().GetBattleLastColour(), wxDefaultPosition, wxSize(30, CONTROL_HEIGHT) );
+ m_buttons_sizer->Add( m_color_btn, 0, wxALL, 0 );
+
+ m_spectator_check = new wxCheckBox( this, SP_SPECTATE, _("Spectate only") );
+ m_buttons_sizer->Add( m_spectator_check, 0, wxALL, 5 );
+
+ m_random_check = new wxCheckBox( this, SP_RANDOM, _("Random start positions") );
+ m_buttons_sizer->Add( m_random_check, 0, wxALL, 5 );
+
+ m_start_btn = new wxButton( this, SP_START, _("Start"), wxDefaultPosition, wxSize(80, CONTROL_HEIGHT), 0 );
+ m_buttons_sizer->Add( m_start_btn, 0, wxALL, 5 );
+
+ m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND, 5 );
+
+ SetScrollRate( 3, 3 );
+ this->SetSizer( m_main_sizer );
+ this->Layout();
+
+ ReloadMaplist();
+ ReloadModlist();
+
+}
+
+
+SinglePlayerTab::~SinglePlayerTab()
+{
+
+}
+
+
+void SinglePlayerTab::UpdateMinimap()
+{
+ m_minimap->UpdateMinimap();
+}
+
+
+void SinglePlayerTab::ReloadMaplist()
+{
+ m_map_pick->Clear();
+
+ TransformedArrayString maplist ( usync().GetMapList(), &RefineMapname ) ;
+ //maplist.Sort(CompareStringIgnoreCase);
+//
+// size_t nummaps = maplist.Count();
+// for ( size_t i = 0; i < nummaps; i++ )
+// m_map_pick->Insert( RefineMapname(maplist[i]), i );
+ m_map_pick->Append( maplist );
+
+ m_map_pick->Insert( _("-- Select one --"), m_map_pick->GetCount() );
+ if ( m_battle.GetHostMapName() != wxEmptyString )
+ {
+ m_map_pick->SetStringSelection( RefineMapname( m_battle.GetHostMapName() ) );
+ if ( m_map_pick->GetStringSelection() == wxEmptyString ) SetMap( m_mod_pick->GetCount()-1 );
+ }
+ else
+ {
+ m_map_pick->SetSelection( m_map_pick->GetCount()-1 );
+ m_addbot_btn->Enable(false);
+ }
+}
+
+
+void SinglePlayerTab::ReloadModlist()
+{
+ m_mod_pick->Clear();
+
+ wxArrayString modlist= usync().GetModList();
+ //modlist.Sort(CompareStringIgnoreCase);
+
+ size_t nummods = modlist.Count();
+ for ( size_t i = 0; i < nummods; i++ ) m_mod_pick->Insert( modlist[i], i );
+
+ m_mod_pick->Insert( _("-- Select one --"), m_mod_pick->GetCount() );
+
+ if ( !m_battle.GetHostModName().IsEmpty() )
+ {
+ m_mod_pick->SetStringSelection( m_battle.GetHostModName() );
+ if ( m_mod_pick->GetStringSelection() == wxEmptyString ) SetMod( m_mod_pick->GetCount()-1 );
+ }
+ else
+ {
+ m_mod_pick->SetSelection( m_mod_pick->GetCount()-1 );
+ }
+}
+
+
+void SinglePlayerTab::SetMap( unsigned int index )
+{
+ //m_ui.ReloadUnitSync();
+ m_addbot_btn->Enable( false );
+ if ( index >= m_map_pick->GetCount()-1 ) {
+ m_battle.SetHostMap( wxEmptyString, wxEmptyString );
+ } else {
+ try {
+ UnitSyncMap map = usync().GetMapEx( index );
+ m_battle.SetHostMap( map.name, map.hash );
+ m_addbot_btn->Enable( true );
+ } catch (...) {}
+ }
+ m_minimap->UpdateMinimap();
+ m_battle.SendHostInfo( IBattle::HI_Map_Changed ); // reload map options
+ m_map_pick->SetSelection( index );
+}
+
+void SinglePlayerTab::ResetUsername()
+{
+ m_battle.GetMe().SetNick( usync().GetDefaultNick() );
+}
+
+void SinglePlayerTab::SetMod( unsigned int index )
+{
+ //m_ui.ReloadUnitSync();
+ if ( index >= m_mod_pick->GetCount()-1 )
+ {
+ m_battle.SetHostMod( wxEmptyString, wxEmptyString );
+ }
+ else
+ {
+ try
+ {
+ UnitSyncMod mod = usync().GetMod( index );
+ m_battle.SetLocalMod( mod );
+ m_battle.SetHostMod( mod.name, mod.hash );
+ }
+ catch (...) {}
+ }
+ m_minimap->UpdateMinimap();
+ m_battle.SendHostInfo( IBattle::HI_Restrictions ); // Update restrictions in options.
+ m_battle.SendHostInfo( IBattle::HI_Mod_Changed ); // reload mod options
+ m_mod_pick->SetSelection( index );
+}
+
+
+bool SinglePlayerTab::ValidSetup()
+{
+ if ( (unsigned int)m_mod_pick->GetSelection() >= m_mod_pick->GetCount()-1 )
+ {
+ wxLogWarning( _T("no mod selected") );
+ customMessageBox(SL_MAIN_ICON, _("You have to select a mod first."), _("Gamesetup error") );
+ return false;
+ }
+
+ if ( (unsigned int)m_map_pick->GetSelection() >= m_map_pick->GetCount()-1 )
+ {
+ wxLogWarning( _T("no map selected") );
+ customMessageBox(SL_MAIN_ICON, _("You have to select a map first."), _("Gamesetup error") );
+ return false;
+ }
+
+ if ( m_battle.GetNumUsers() == 1 )
+ {
+ wxLogWarning(_T("trying to start sp game without bot"));
+ if ( customMessageBox(SL_MAIN_ICON, _("Continue without adding a bot first?.\n The game will be over pretty fast.\n "),
+ _("No Bot added"), wxYES_NO) == wxNO )
+ return false;
+ }
+ return true;
+}
+
+
+void SinglePlayerTab::OnMapSelect( wxCommandEvent& /*unused*/ )
+{
+ unsigned int index = (unsigned int)m_map_pick->GetCurrentSelection();
+ SetMap( index );
+}
+
+
+void SinglePlayerTab::OnModSelect( wxCommandEvent& /*unused*/ )
+{
+ unsigned int index = (unsigned int)m_mod_pick->GetCurrentSelection();
+ SetMod( index );
+}
+
+
+void SinglePlayerTab::OnMapBrowse( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ MapSelectDialog dlg( (wxWindow*)&m_ui.mw(), m_ui );
+
+ if ( dlg.ShowModal() == wxID_OK && dlg.GetSelectedMap() != NULL )
+ {
+ wxLogDebugFunc( dlg.GetSelectedMap()->name );
+ const wxString mapname = RefineMapname( dlg.GetSelectedMap()->name );
+ const int idx = m_map_pick->FindString( mapname, true /*case sensitive*/ );
+ if ( idx != wxNOT_FOUND ) SetMap( idx );
+ }
+}
+
+
+void SinglePlayerTab::OnAddBot( wxCommandEvent& /*unused*/ )
+{
+ AddBotDialog dlg( this, m_battle, true );
+ if ( dlg.ShowModal() == wxID_OK )
+ {
+ UserBattleStatus bs;
+ bs.owner = m_battle.GetMe().GetNick();
+ bs.aishortname = dlg.GetAIShortName();
+ bs.aiversion = dlg.GetAIVersion();
+ bs.aitype = dlg.GetAIType();
+ bs.team = m_battle.GetFreeTeamNum();
+ bs.ally = m_battle.GetFreeAlly();
+ bs.colour = m_battle.GetNewColour();
+ User& bot = m_battle.OnBotAdded( _T("Bot") + TowxString( bs.team ), bs );
+ ASSERT_LOGIC( &bot != 0, _T("bot == 0") );
+ m_minimap->UpdateMinimap();
+ }
+}
+
+
+void SinglePlayerTab::OnStart( wxCommandEvent& /*unused*/ )
+{
+ wxLogDebugFunc( _T("SP: ") );
+
+ if ( m_ui.IsSpringRunning() )
+ {
+ wxLogWarning(_T("trying to start spring while another instance is running") );
+ customMessageBoxNoModal(SL_MAIN_ICON, _("You cannot start a spring instance while another is already running"), _("Spring error"), wxICON_EXCLAMATION );
+ return;
+ }
+
+ if ( ValidSetup() ) m_battle.StartSpring();
+}
+
+
+void SinglePlayerTab::OnRandomCheck( wxCommandEvent& /*unused*/ )
+{
+ if ( m_random_check->IsChecked() ) m_battle.CustomBattleOptions().setSingleOption( _T("startpostype"), TowxString<int>(IBattle::ST_Random), OptionsWrapper::EngineOption );
+ else m_battle.CustomBattleOptions().setSingleOption( _T("startpostype"), TowxString<int>(IBattle::ST_Pick), OptionsWrapper::EngineOption );
+ m_battle.SendHostInfo( IBattle::HI_StartType );
+}
+
+void SinglePlayerTab::OnSpectatorCheck( wxCommandEvent& /*unused*/ )
+{
+ m_battle.GetMe().BattleStatus().spectator = m_spectator_check->IsChecked();
+ UpdateMinimap();
+}
+
+void SinglePlayerTab::OnColorButton( wxCommandEvent& /*unused*/ )
+{
+ User& u = m_battle.GetMe();
+ wxColour CurrentColour = u.BattleStatus().colour;
+ CurrentColour = GetColourFromUser(this, CurrentColour);
+ if ( !CurrentColour.IsColourOk() ) return;
+ sett().SetBattleLastColour( CurrentColour );
+ m_battle.ForceColour( u, CurrentColour );
+ UpdateMinimap();
+}
+
+void SinglePlayerTab::Update( const wxString& Tag )
+{
+ long type;
+ Tag.BeforeFirst( '_' ).ToLong( &type );
+ wxString key = Tag.AfterFirst( '_' );
+ wxString value = m_battle.CustomBattleOptions().getSingleValue( key, (OptionsWrapper::GameOption)type);
+ long longval;
+ value.ToLong( &longval );
+ if ( type == OptionsWrapper::PrivateOptions )
+ {
+ if ( key == _T("mapname") )
+ {
+ if ( key == _T("mapname") )
+ {
+ m_addbot_btn->Enable( false );
+ try
+ {
+ m_map_pick->SetSelection( usync().GetMapIndex( m_battle.GetHostMapName() ) );
+ UpdateMinimap();
+ m_addbot_btn->Enable( true );
+ }
+ catch (...) {}
+ }
+ }
+ }
+}
+
+void SinglePlayerTab::UpdatePresetList()
+{
+}
+
+void SinglePlayerTab::OnReset( wxCommandEvent& /*unused*/ )
+{
+
+}
+
+void SinglePlayerTab::OnMouseWheel( wxMouseEvent& event )
+{
+ if ( m_minimap )
+ {
+ wxRect map_rect = m_minimap->GetRect();
+ if ( map_rect.Contains( event.GetPosition() ) )
+ {
+ m_minimap->OnMouseWheel( event );
+ return;
+ }
+ }
+ event.Skip();
+}
diff --git a/src/singleplayertab.h b/src/singleplayertab.h
new file mode 100644
index 0000000..7cb8cd8
--- /dev/null
+++ b/src/singleplayertab.h
@@ -0,0 +1,108 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SINGLEPLAYERTAB_H
+#define SPRINGLOBBY_HEADERGUARD_SINGLEPLAYERTAB_H
+
+#include <wx/scrolwin.h>
+
+#include "singleplayerbattle.h"
+
+
+class Ui;
+class MapCtrl;
+class SinglePlayerBattle;
+
+class wxWindow;
+class wxButton;
+class wxStaticLine;
+class wxChoice;
+class wxStaticText;
+class wxCommandEvent;
+class wxCheckBox;
+class wxMouseEvent;
+class ColorButton;
+
+class SinglePlayerTab: public wxScrolledWindow
+{
+ public:
+
+ SinglePlayerTab( wxWindow* parent, Ui& ui, MainSinglePlayerTab& msptab );
+ ~SinglePlayerTab();
+
+ void UpdateMinimap();
+ void ReloadMaplist();
+ void ReloadModlist();
+ void Update( const wxString& Tag );
+ void UpdatePresetList();
+
+ SinglePlayerBattle& GetBattle() { return m_battle; }
+
+ bool ValidSetup();
+
+ void OnMapSelect( wxCommandEvent& event );
+ void OnModSelect( wxCommandEvent& event );
+ void OnMapBrowse( wxCommandEvent& event );
+ void OnAddBot( wxCommandEvent& event );
+ void OnStart( wxCommandEvent& event );
+ void OnRandomCheck( wxCommandEvent& event );
+ void OnSpectatorCheck( wxCommandEvent& event );
+ void OnColorButton( wxCommandEvent& event );
+ void OnReset( wxCommandEvent& event );
+ void OnMouseWheel( wxMouseEvent& event );
+
+ void OnUnitSyncReloaded();
+ void ResetUsername();
+
+ void SetMap( unsigned int index );
+ void SetMod( unsigned int index );
+
+ protected:
+
+ Ui& m_ui;
+ SinglePlayerBattle m_battle;
+
+ MapCtrl* m_minimap;
+ wxChoice* m_map_pick;
+ wxChoice* m_mod_pick;
+ wxStaticText* m_map_lbl;
+ wxStaticText* m_mod_lbl;
+ wxButton* m_select_btn;
+ wxButton* m_addbot_btn;
+ wxStaticLine* m_buttons_sep;
+ wxButton* m_reset_btn;
+ wxCheckBox* m_random_check;
+ wxCheckBox* m_spectator_check;
+ wxButton* m_start_btn;
+ ColorButton* m_color_btn;
+
+ enum
+ {
+ SP_MAP_PICK = wxID_HIGHEST,
+ SP_MOD_PICK,
+ SP_BROWSE_MAP,
+ SP_ADD_BOT,
+ SP_RESET,
+ SP_START,
+ SP_RANDOM,
+ SP_SPECTATE,
+ SP_COLOUR
+ };
+ DECLARE_EVENT_TABLE()
+};
+#endif // SPRINGLOBBY_HEADERGUARD_SINGLEPLAYERTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/socket.cpp b/src/socket.cpp
new file mode 100644
index 0000000..b396150
--- /dev/null
+++ b/src/socket.cpp
@@ -0,0 +1,449 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/socket.h>
+#include <wx/thread.h>
+#include <wx/string.h>
+#include <wx/log.h>
+#include <stdexcept>
+#include <algorithm>
+
+#include "socket.h"
+#include "server.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+
+#ifdef __WXMSW__
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include <windows.h>
+#include <wx/msw/winundef.h>
+#include <iphlpapi.h>
+#pragma comment(lib, "iphlpapi.lib")
+#else
+#include <sys/ioctl.h>
+#include <net/if.h>
+#endif
+
+#define LOCK_SOCKET wxCriticalSectionLocker criticalsection_lock(m_lock)
+
+
+BEGIN_EVENT_TABLE(SocketEvents, wxEvtHandler)
+
+EVT_SOCKET(SOCKET_ID, SocketEvents::OnSocketEvent)
+
+END_EVENT_TABLE()
+
+
+void SocketEvents::OnSocketEvent(wxSocketEvent& event)
+{
+ Socket* sock = (Socket*)event.GetClientData();
+ try
+ {
+ ASSERT_LOGIC( sock != 0, _T("sock = 0") );
+ } catch (...) { return; }
+
+ if ( event.GetSocketEvent() == wxSOCKET_INPUT ) {
+ m_net_class.OnDataReceived( sock );
+ } else if ( event.GetSocketEvent() == wxSOCKET_LOST ) {
+ m_net_class.OnDisconnected( sock );
+ } else if ( event.GetSocketEvent() == wxSOCKET_CONNECTION ) {
+ m_net_class.OnConnected( sock );
+ } else {
+ try
+ {
+ ASSERT_LOGIC( false, _T("Unknown socket event."));
+ } catch (...) { return; };
+ }
+}
+
+
+//! @brief Constructor
+Socket::Socket( iNetClass& netclass, bool blocking ):
+ m_block(blocking),
+ m_net_class(netclass),
+ m_rate(-1),
+ m_sent(0)
+{
+ m_connecting = false;
+
+ m_sock = 0;
+ m_events = 0;
+
+ //resetting the ping state vars.
+ m_ping_msg = wxEmptyString;
+ m_ping_int = 0;
+ m_ping_t = 0;
+
+}
+
+
+//! @brief Destructor
+Socket::~Socket()
+{
+ _EnablePingThread( false );
+
+ LOCK_SOCKET;
+ if ( m_sock ) m_sock->Destroy();
+ delete m_events;
+}
+
+
+//! @brief Creates an TCP socket and sets it up.
+wxSocketClient* Socket::_CreateSocket()
+{
+ wxSocketClient* sock = new wxSocketClient();
+
+ sock->SetClientData( (void*)this );
+ if ( !m_block ) {
+ if ( m_events == 0 ) m_events = new SocketEvents( m_net_class );
+ sock->SetFlags( wxSOCKET_NOWAIT );
+
+ sock->SetEventHandler(*m_events, SOCKET_ID);
+ sock->SetNotify( wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG );
+ sock->Notify(true);
+ } else {
+ if ( m_events != 0 ) {
+ delete m_events;
+ m_events = 0;
+ }
+ }
+ return sock;
+}
+
+//! @brief Connect to remote host.
+//! @note This turns off the ping thread.
+void Socket::Connect( const wxString& addr, const int port )
+{
+ LOCK_SOCKET;
+ _EnablePingThread( false ); // Turn off ping thread.
+
+ wxIPV4address wxaddr;
+ m_connecting = true;
+ m_buffer = "";
+
+ wxaddr.Hostname( addr );
+ wxaddr.Service( port );
+
+ if ( m_sock != 0 ) m_sock->Destroy();
+ m_sock = _CreateSocket();
+ m_sock->Connect( wxaddr, m_block );
+ m_sock->SetTimeout( 40 );
+}
+
+void Socket::SetTimeout( const int seconds )
+{
+ if ( m_sock != 0 )
+ m_sock->SetTimeout( seconds );
+}
+
+//! @brief Disconnect from remote host if connected.
+//! @note This turns off the ping thread.
+void Socket::Disconnect( )
+{
+ if ( m_sock ) m_sock->SetTimeout( 0 );
+ m_net_class.OnDisconnected( this );
+ _EnablePingThread( false );
+ m_buffer = "";
+
+ if ( m_sock )
+ {
+ m_sock->Destroy();
+ m_sock = 0;
+ }
+}
+
+
+//! @brief Send data over connection.
+bool Socket::Send( const wxString& data )
+{
+ LOCK_SOCKET;
+ return _Send( data );
+}
+
+
+//! @brief Internal send function.
+//! @note Does not lock the criticalsection.
+bool Socket::_Send( const wxString& data )
+{
+ if ( !m_sock )
+ {
+ wxLogError( _T("Socket NULL") );
+ return false;
+ }
+
+ m_buffer += (const char*)data.mb_str(wxConvUTF8);
+ int crop = m_buffer.length();
+ if ( m_rate > 0 )
+ {
+ int max = m_rate - m_sent;
+ if ( crop > 0 ) crop = max;
+ }
+ std::string send = m_buffer.substr( 0, crop );
+ //wxLogMessage( _T("send: %d sent: %d max: %d : buff: %d"), send.length() , m_sent, max, m_buffer.length() );
+ m_sock->Write( send.c_str(), send.length() );
+ if ( !m_sock->Error() )
+ {
+ wxUint32 sentdata = m_sock->LastCount();
+ m_buffer.erase( 0, sentdata );
+ m_sent += sentdata;
+ }
+ return !m_sock->Error();
+}
+
+
+//! @brief Receive data from connection
+wxString Socket::Receive()
+{
+ wxString ret;
+ if ( m_sock == 0 )
+ {
+ wxLogError( _T("Socket NULL") );
+ return ret;
+ }
+
+ LOCK_SOCKET;
+
+ const int chunk_size = 1337;
+
+ std::vector<char> buff;
+ int readnum = 0;
+ int totalbytes = 0;
+
+ do
+ {
+ buff.resize( totalbytes + chunk_size ); // increase buffer capacity to fit incoming chunk
+ m_sock->Read( &buff[totalbytes], chunk_size );
+ readnum = m_sock->LastCount();
+ totalbytes += readnum;
+ } while ( readnum >= chunk_size );
+
+ if ( totalbytes > 0 )
+ {
+ ret = wxString( &buff[0], wxConvUTF8, totalbytes );
+ if ( ret.IsEmpty() )
+ {
+ ret = wxString( &buff[0], wxConvLocal, totalbytes );
+ if ( ret.IsEmpty() )
+ {
+ ret = wxString( &buff[0], wxCSConv(_T("latin-1")), totalbytes );
+ }
+ }
+ }
+
+ return ret;
+}
+
+wxString Socket::GetHandle()
+{
+ wxString handle;
+ #ifdef __WXMSW__
+
+ IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information for 16 cards
+ DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
+
+ DWORD dwStatus = GetAdaptersInfo ( AdapterInfo, &dwBufLen); // Get info
+ if (dwStatus != NO_ERROR) return _T(""); // Check status
+ for (unsigned int i=0; i<std::min( (unsigned int)6, (unsigned int)AdapterInfo[0].AddressLength); i++)
+ {
+ handle += TowxString(((unsigned int)AdapterInfo[0].Address[i])&255);
+ if (i != 5) handle += _T(':');
+ }
+ #elif defined(__WXGTK__) && defined(linux)
+ int sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ return _T(""); //not a valid socket
+ }
+ struct ifreq dev; //container for the hw data
+ struct if_nameindex *NameList = if_nameindex(); //container for the interfaces list
+ if (NameList == NULL)
+ {
+ close(sock);
+ return _T(""); //cannot list the interfaces
+ }
+
+ int pos = 0;
+ std::string InterfaceName;
+ do
+ {
+ if (NameList[pos].if_index == 0)
+ {
+ close(sock);
+ if_freenameindex(NameList);
+ return _T(""); // no valid interfaces found
+ }
+ InterfaceName = NameList[pos].if_name;
+ pos++;
+ } while (InterfaceName.substr(0,2) == "lo" || InterfaceName.substr(0,3) == "sit");
+
+ if_freenameindex(NameList); //free the memory
+
+ strcpy (dev.ifr_name, InterfaceName.c_str()); //select from the name
+ if (ioctl(sock, SIOCGIFHWADDR, &dev) < 0) //get the interface data
+ {
+ close(sock);
+ return _T(""); //cannot list the interfaces
+ }
+
+ for (int i=0; i<6; i++)
+ {
+ handle += TowxString(((unsigned int)dev.ifr_hwaddr.sa_data[i])&255);
+ if (i != 5) handle += _T(':');
+ }
+ close(sock);
+ #endif
+ return handle;
+}
+
+//! @brief Get curent socket state
+SockState Socket::State( )
+{
+ if ( m_sock == 0 ) return SS_Closed;
+
+ LOCK_SOCKET;
+ if ( m_sock->IsConnected() ) {
+ m_connecting = false;
+ return SS_Open;
+ } else {
+ if ( m_connecting ) {
+ return SS_Connecting;
+ } else {
+ return SS_Closed;
+ }
+ }
+}
+
+
+//! @brief Get socket error code
+//! @todo Implement
+SockError Socket::Error( ) const
+{
+ return (SockError)-1;
+}
+
+
+//! @brief used to retrieve local ip address behind NAT to communicate to the server on login
+wxString Socket::GetLocalAddress() const
+{
+ if ( !m_sock || !m_sock->IsConnected() )
+ return wxEmptyString;
+
+ wxIPV4address localaddr;
+ m_sock->GetLocal( localaddr );
+
+ return localaddr.IPAddress();
+}
+
+
+//! @brief Set ping info to be used by the ping thread.
+//! @note Set msg to an empty string to turn off the ping thread.
+//! @note This has to be set every time the socket connects.
+void Socket::SetPingInfo( const wxString& msg, unsigned int interval )
+{
+ LOCK_SOCKET;
+ m_ping_msg = msg;
+ m_ping_int = interval;
+ _EnablePingThread( _ShouldEnablePingThread() );
+}
+
+
+void Socket::_EnablePingThread( bool enable )
+{
+
+ if ( !enable ) {
+ if ( m_ping_t ) {
+
+ // Reset values to be sure.
+ m_ping_int = 0;
+ m_ping_msg = wxEmptyString;
+
+ m_ping_t->Wait();
+ delete m_ping_t;
+
+ m_ping_t = 0;
+ }
+ } else {
+ if ( !m_ping_t ) {
+ m_ping_t = new PingThread( *this );
+ m_ping_t->Init();
+ }
+ }
+}
+
+
+//! @brief Check if we should enable or dsable the ping htread.
+//! @see Socket::_EnablePingThread
+bool Socket::_ShouldEnablePingThread() const
+{
+ return ( (m_ping_msg != wxEmptyString) );
+}
+
+
+//! @brief Set the maximum upload ratio.
+void Socket::SetSendRateLimit( int Bps )
+{
+ m_rate = Bps;
+}
+
+
+//! @brief Ping remote host with custom protocol message.
+//! @note Called from separate thread
+void Socket::Ping()
+{
+ // Dont log here, else it may crash.
+ // wxLogMessage( _T("Sent ping.") );
+ if ( m_ping_msg != wxEmptyString ) Send( m_ping_msg );
+}
+
+
+
+void Socket::OnTimer( int mselapsed )
+{
+ LOCK_SOCKET;
+
+ if ( m_rate > 0 ) {
+ m_sent -= int( ( mselapsed / 1000.0 ) * m_rate );
+ if ( m_sent < 0 ) m_sent = 0;
+ if ( m_buffer.length() > 0 ) _Send(_T(""));
+ } else {
+ m_sent = 0;
+ }
+}
+
+PingThread::PingThread( Socket& sock ):
+ m_sock(sock)
+{
+}
+
+
+void PingThread::Init()
+{
+ Create();
+ SetPriority( WXTHREAD_MAX_PRIORITY );
+ Run();
+}
+
+
+void* PingThread::Entry()
+{
+ int milliseconds = m_sock.GetPingInterval();
+
+ while ( !TestDestroy() )
+ {
+ if ( !m_sock.GetPingEnabled() ) break;
+ m_sock.Ping();
+ // break if woken
+ if(!Sleep(milliseconds))break;
+ }
+ return 0;
+}
+
+void PingThread::OnExit()
+{
+}
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..162dff2
--- /dev/null
+++ b/src/socket.h
@@ -0,0 +1,163 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SOCKET_H
+#define SPRINGLOBBY_HEADERGUARD_SOCKET_H
+
+#include <wx/string.h>
+
+#include <wx/event.h>
+#include "thread.h"
+
+class iNetClass;
+class Socket;
+class wxSocketEvent;
+class wxSocketClient;
+class wxCriticalSection;
+
+class PingThread;
+
+enum SockState
+{
+ SS_Closed,
+ SS_Connecting,
+ SS_Open
+};
+
+enum SockError
+{
+ SE_No_Error,
+ SE_NotConnected,
+ SE_Resolve_Host_Failed,
+ SE_Connect_Host_Failed
+};
+
+#define SOCKET_ID 100
+
+
+class SocketEvents: public wxEvtHandler
+{
+ public:
+ SocketEvents( iNetClass& netclass ): m_net_class(netclass) {}
+ void OnSocketEvent(wxSocketEvent& event);
+ protected:
+ iNetClass& m_net_class;
+ DECLARE_EVENT_TABLE()
+};
+
+typedef void (*socket_callback)(Socket*);
+
+
+//! @brief Class that implements a TCP client socket.
+class Socket
+{
+ public:
+
+ Socket( iNetClass& netclass, bool blocking = false );
+ ~Socket();
+
+ // Socket interface
+
+ void Connect( const wxString& addr, const int port );
+ void Disconnect( );
+
+ bool Send( const wxString& data );
+ wxString Receive();
+
+
+ void Ping();
+ void SetPingInfo( const wxString& msg = wxEmptyString, unsigned int interval = 10000 );
+ unsigned int GetPingInterval() const { return m_ping_int; }
+ bool GetPingEnabled() const { return m_ping_msg != wxEmptyString; }
+
+ wxString GetLocalAddress() const;
+ wxString GetHandle();
+
+ SockState State( );
+ SockError Error( ) const;
+
+ void SetSendRateLimit( int Bps = -1 );
+ void OnTimer( int mselapsed );
+
+ void SetTimeout( const int seconds );
+
+ protected:
+
+ // Socket variables
+
+ wxSocketClient* m_sock;
+ SocketEvents* m_events;
+
+ wxCriticalSection m_lock;
+
+ wxString m_ping_msg;
+ unsigned int m_ping_int;
+
+ PingThread* m_ping_t;
+
+ bool m_connecting;
+ bool m_block;
+ iNetClass& m_net_class;
+
+ unsigned int m_udp_private_port;
+ int m_rate;
+ int m_sent;
+ std::string m_buffer;
+
+ wxSocketClient* _CreateSocket();
+
+ bool _Send( const wxString& data );
+ void _EnablePingThread( bool enable = true );
+ bool _ShouldEnablePingThread() const;
+};
+
+
+/** A thread class that sends pings to socket.
+ * Implemented as joinable thread.
+ * When you want it started, construct it then call Init()
+ * When you want it killed, call Wait() method.
+ * Dont call other methods, especially the Destroy() method.
+ */
+ /*
+class PingThread: public wxThread
+{
+ public:
+ PingThread( Socket& sock );
+ void Init();
+ /// overrides wxThread::Wait
+ ExitCode Wait();
+ private:
+ Socket& m_sock;
+ wxSemaphore m_thread_sleep_semaphore;
+
+ void* Entry();
+ void OnExit();
+};*/
+class PingThread: public Thread
+{
+ public:
+ PingThread( Socket& sock );
+ void Init();
+ private:
+ Socket& m_sock;
+ void* Entry();
+ void OnExit();
+};
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_SOCKET_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/sounds/pm_sound.h b/src/sounds/pm_sound.h
new file mode 100644
index 0000000..32f4c99
--- /dev/null
+++ b/src/sounds/pm_sound.h
@@ -0,0 +1,4 @@
+/* receive.wav - 55008 bytes */
+ static const unsigned char pm_sound_data[] = {
+82, 73, 70, 70, 216, 214, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 1, 0, 2, 0, 34, 86, 0, 0, 136, 88, 1, 0, 4, 0, 16, 0, 100, 97, 116, 97, 76, 214, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 124, 0, 124, 0, 181, 1, 181, 1, 162, 3, 162, 3, 183, 6, 183, 6, 230, 10, 230, 10, 163, 15, 163, 15, 188, 20, 187, 20, 25, 26, 25, 26, 74, 31, 74, 31, 5, 36, 5, 36, 13, 40, 13, 40, 39, 43, 38, 43, 58, 45, 58, 45, 62, 46, 62, 46, 78, 46, 77, 46, 103, 45, 102, 45, 146, 43, 145, 43, 216, 40, 215, 40, 88, 37, 88, 37, 69, 33, 68, 33, 221, 28, 221, 28, 104, 24, 104, 24, 48, 20, 48, 20, 115, 16, 114, 16, 97, 13, 96, 13, 25, 11, 25, 11, 164, 9, 164, 9, 250, 8, 249, 8, 255, 8, 255, 8, 142, 9, 142, 9, 123, 10, 123, 10, 151, 11, 151, 11, 183, 12, 183, 12, 181, 13, 181, 13, 117, 14, 119, 14, 230, 14, 237, 14, 255, 14, 17, 15, 192, 14, 246, 14, 52, 14, 215, 14, 104, 13, 233, 14, 111, 12, 60, 15, 89, 11, 193, 15, 59, 10, 93, 16, 36, 9, 13, 17, 17, 8, 152, 17, 239, 6, 204, 17, 156, 5, 106, 17, 245, 3, 71, 16, 227, 1, 80, 14, 97, 255, 128, 11, 114, 252, 225, 7, 45, 249, 144, 3, 182, 245, 202, 254, 57, 242, 212, 249, 225, 238, 2, 245, 218, 235, 162, 240, 73, 233, 252, 236, 73, 231, 57, 234, 237, 229, 116, 232, 57, 229, 167, 231, 38, 229, 189, 231, 167, 229, 144, 232, 162, 230, 237, 233, 252, 231, 164, 235, 152, 233, 131, 237, 84, 235, 96, 239, 28, 237, 27, 241, 243, 238, 173, 242, 242, 240, 29, 244, 10, 243, 107, 245, 84, 245, 177, 246, 2, 248, 34, 248, 5, 251, 207, 249, 88, 254, 183, 251, 15, 2, 216, 253, 2, 6, 4, 0, 3, 10, 18, 2, 222, 13, 218, 3, 82, 17, 56, 5, 57, 20, 25, 6, 108, 22, 120, 6, 211, 23, 87, 6, 112, 24, 207, 5, 75, 24, 241, 4, 122, 23, 218, 3, 28, 22, 163, 2, 65, 20, 90, 1, 21, 18, 20, 0, 173, 15, 216, 254, 39, 13, 170, 253, 164, 10, 145, 252, 46, 8, 141, 251, 227, 5, 158, 250, 201, 3, 204, 249, 232, 1, 38, 249, 71, 0, 184, 248, 229, 254, 133, 248, 186, 253, 127, 248, 194, 252, 145, 248, 228, 251, 142, 248, 243, 250, 57, 248, 203, 249, 99, 247, 71, 248, 230, 245, 98, 246, 196, 243, 40, 244, 20, 241, 173, 241, 1, 238, 30, 239, 201, 234, 157, 236, 164, 231, 86, 234, 207, 228, 105, 232, 114, 226, 234, 230, 171, 224, 224, 229, 117, 223, 74, 229, 204, 222, 23, 229, 155, 222, 48, 229, 189, 222, 126, 229, 25, 223, 225, 229, 142, 223, 68, 230, 254, 223, 137, 230, 70, 224, 164, 230, 69, 224, 146, 230, 232, 223, 71, 230, 33, 223, 187, 229, 241, 221, 234, 228, 100, 220, 214, 227, 146, 218, 128, 226, 153, 216, 242, 224, 152, 214, 62, 223, 178, 212, 115, 221, 1, 211, 169, 219, 161, 209, 247, 217, 161, 208, 111, 216, 10, 208, 42, 215, 229, 207, 49, 214, 36, 208, 135, 213, 183, 208, 51, 213, 148, 209, 51, 213, 162, 210, 129, 213, 211, 211, 24, 214, 23, 213, 236, 214, 93, 214, 242, 215, 156, 215, 33, 217, 204, 216, 105, 218, 232, 217, 198, 219, 240, 218, 42, 221, 231, 219, 145, 222, 212, 220, 247, 223, 199, 221, 92, 225, 207, 222, 199, 226, 242, 223, 62, 228, 53, 225, 201, 229, 152, 226, 106, 231, 26, 228, 32, 233, 179, 229, 235, 234, 95, 231, 227, 236, 49, 233, 60, 239, 89, 235, 46, 242, 17, 238, 222, 245, 123, 241, 87, 250, 167, 245, 133, 255, 135, 250, 56, 5, 242, 255, 51, 11, 166, 5, 39, 17, 101, 11, 198, 22, 227, 16, 203, 27, 216, 21, 252, 31, 16, 26, 49, 35, 100, 29, 90, 37, 193, 31, 121, 38, 38, 33, 158, 38, 165, 33, 239, 37, 94, 33, 150, 36, 124, 32, 195, 34, 54, 31, 169, 32, 202, 29, 118, 30, 109, 28, 80, 28, 70, 27, 84, 26, 110, 26, 142, 24, 237, 25, 4, 23, 197, 25, 182, 21, 236, 25, 160, 20, 84, 26, 188, 19, 233, 26, 4, 19, 150, 27, 106, 18, 62, 28, 207, 17, 183, 28, 16, 17, 210, 28, 15, 16, 112, 28, 190, 14, 128, 27, 30, 13, 6, 26, 59, 11, 24, 24, 45, 9, 214, 21, 13, 7, 109, 19, 248, 4, 10, 17, 3, 3, 212, 14, 68, 1, 233, 12, 201, 255, 96, 11, 147, 254, 65, 10, 163, 253, 140, 9, 240, 252, 54, 9, 111, 252, 44, 9, 20, 252, 89, 9, 207, 251, 160, 9, 148, 251, 228, 9, 86, 251, 11, 10, 17, 251, 0, 10, 190, 250, 182, 9, 93, 250, 44, 9, 238, 249, 106, 8, 119, 249, 124, 7, 253, 248, 113, 6, 133, 248, 95, 5, 20, 248, 85, 4, 171, 247, 97, 3, 62, 247, 127, 2, 181, 246, 154, 1, 242, 245, 155, 0, 220, 244, 103, 255, 103, 243, 234, 253, 142, 241, 29, 252, 89, 239, 4, 250, 223, 236, 171, 247, 58, 234, 41, 245, 140, 231, 156, 242, 250, 228, 33, 240, 166, 226, 219, 237, 173, 224, 229, 235, 39, 223, 91, 234, 36, 222, 74, 233, 171, 221, 193, 232, 188, 221, 204, 232, 77, 222, 112, 233, 84, 223, 172, 234, 199, 224, 104, 236, 158, 226, 133, 238, 207, 228, 223, 240, 72, 231, 73, 243, 243, 233, 157, 245, 185, 236, 185, 247, 129, 239, 134, 249, 64, 242, 4, 251, 248, 244, 73, 252, 168, 247, 105, 253, 74, 250, 116, 254, 207, 252, 118, 255, 37, 255, 109, 0, 52, 1, 88, 1, 232, 2, 43, 2, 49, 4, 217, 2, 4, 5, 87, 3, 93, 5, 156, 3, 68, 5, 166, 3, 199, 4, 118, 3, 251, 3, 19, 3, 247, 2, 134, 2, 214, 1, 222, 1, 178, 0, 40, 1, 162, 255, 116, 0, 185, 254, 212, 255, 4, 254, 81, 255, 146, 253, 237, 254, 105, 253, 164, 254, 135, 253, 113, 254, 226, 253, 71, 254, 106, 254, 32, 254, 14, 255, 238, 253, 187, 255, 172, 253, 101, 0, 84, 253, 247, 0, 219, 252, 89, 1, 46, 252, 104, 1, 49, 251, 10, 1, 210, 249, 54, 0, 11, 248, 240, 254, 227, 245, 67, 253, 110, 243, 79, 251, 205, 240, 58, 249, 37, 238, 31, 247, 154, 235, 41, 245, 80, 233, 106, 243, 97, 231, 249, 241, 221, 229, 226, 240, 203, 228, 30, 240, 40, 228, 174, 239, 232, 227, 127, 239, 248, 227, 129, 239, 64, 228, 163, 239, 167, 228, 208, 239, 15, 229, 252, 239, 89, 229, 23, 240, 102, 229, 29, 240, 35, 229, 6, 240, 133, 228, 208, 239, 138, 227, 115, 239, 62, 226, 243, 238, 184, 224, 79, 238, 15, 223, 139, 237, 95, 221, 175, 236, 200, 219, 194, 235, 102, 218, 206, 234, 74, 217, 217, 233, 125, 216, 241, 232, 12, 216, 31, 232, 242, 215, 109, 231, 45, 216, 225, 230, 179, 216, 132, 230, 115, 217, 88, 230, 100, 218, 94, 230, 113, 219, 150, 230, 141, 220, 252, 230, 173, 221, 139, 231, 199, 222, 62, 232, 211, 223, 16, 233, 206, 224, 249, 233, 187, 225, 241, 234, 158, 226, 242, 235, 128, 227, 244, 236, 107, 228, 250, 237, 101, 229, 0, 239, 111, 230, 16, 240, 139, 231, 45, 241, 182, 232, 92, 242, 240, 233, 159, 243, 52, 235, 253, 244, 134, 236, 144, 246, 7, 238, 132, 248, 226, 239, 253, 250, 62, 242, 9, 254, 54, 245, 168, 1, 204, 248, 198, 5, 240, 252, 61, 10, 126, 1, 217, 14, 72, 6, 95, 19, 19, 11, 153, 23, 166, 15, 82, 27, 204, 19, 97, 30, 89, 23, 166, 32, 46, 26, 21, 34, 59, 28, 174, 34, 128, 29, 127, 34, 10, 30, 160, 33, 238, 29, 53, 32, 76, 29, 94, 30, 80, 28, 71, 28, 34, 27, 18, 26, 234, 25, 227, 23, 203, 24, 213, 21, 222, 23, 247, 19, 50, 23, 79, 18, 208, 22, 226, 16, 184, 22, 173, 15, 225, 22, 173, 14, 64, 23, 221, 13, 194, 23, 41, 13, 72, 24, 126, 12, 169, 24, 193, 11, 194, 24, 225, 10, 120, 24, 217, 9, 190, 23, 166, 8, 153, 22, 83, 7, 24, 21, 241, 5, 84, 19, 149, 4, 112, 17, 82, 3, 138, 15, 61, 2, 195, 13, 107, 1, 51, 12, 231, 0, 235, 10, 180, 0, 243, 9, 204, 0, 77, 9, 35, 1, 241, 8, 163, 1, 211, 8, 54, 2, 227, 8, 199, 2, 12, 9, 63, 3, 55, 9, 142, 3, 80, 9, 173, 3, 69, 9, 147, 3, 13, 9, 66, 3, 163, 8, 193, 2, 12, 8, 26, 2, 81, 7, 90, 1, 126, 6, 141, 0, 161, 5, 195, 255, 198, 4, 251, 254, 242, 3, 46, 254, 32, 3, 77, 253, 61, 2, 69, 252, 58, 1, 8, 251, 6, 0, 143, 249, 155, 254, 213, 247, 243, 252, 228, 245, 21, 251, 201, 243, 15, 249, 149, 241, 240, 246, 93, 239, 210, 244, 48, 237, 203, 242, 33, 235, 244, 240, 64, 233, 97, 239, 158, 231, 38, 238, 74, 230, 86, 237, 80, 229, 0, 237, 184, 228, 50, 237, 135, 228, 238, 237, 186, 228, 39, 239, 84, 229, 200, 240, 85, 230, 179, 242, 184, 231, 195, 244, 115, 233, 211, 246, 119, 235, 197, 248, 175, 237, 125, 250, 15, 240, 247, 251, 145, 242, 55, 253, 43, 245, 78, 254, 209, 247, 73, 255, 113, 250, 49, 0, 242, 252, 15, 1, 59, 255, 224, 1, 52, 1, 159, 2, 201, 2, 65, 3, 235, 3, 192, 3, 145, 4, 20, 4, 189, 4, 55, 4, 120, 4, 38, 4, 207, 3, 231, 3, 217, 2, 126, 3, 174, 1, 244, 2, 106, 0, 84, 2, 35, 255, 170, 1, 238, 253, 1, 1, 221, 252, 99, 0, 253, 251, 215, 255, 84, 251, 94, 255, 227, 250, 250, 254, 164, 250, 171, 254, 139, 250, 108, 254, 135, 250, 55, 254, 134, 250, 9, 254, 123, 250, 217, 253, 89, 250, 160, 253, 15, 250, 77, 253, 136, 249, 200, 252, 176, 248, 251, 251, 128, 247, 213, 250, 246, 245, 82, 249, 36, 244, 121, 247, 31, 242, 94, 245, 6, 240, 26, 243, 251, 237, 205, 240, 30, 236, 150, 238, 147, 234, 145, 236, 124, 233, 213, 234, 236, 232, 113, 233, 236, 232, 107, 232, 121, 233, 197, 231, 129, 234, 115, 231, 230, 235, 106, 231, 137, 237, 150, 231, 68, 239, 225, 231, 245, 240, 47, 232, 125, 242, 98, 232, 195, 243, 96, 232, 184, 244, 25, 232, 82, 245, 132, 231, 142, 245, 166, 230, 112, 245, 135, 229, 254, 244, 60, 228, 67, 244, 216, 226, 78, 243, 113, 225, 50, 242, 33, 224, 1, 241, 249, 222, 208, 239, 11, 222, 176, 238, 99, 221, 177, 237, 7, 221, 223, 236, 246, 220, 68, 236, 45, 221, 227, 235, 164, 221, 191, 235, 81, 222, 211, 235, 36, 223, 22, 236, 19, 224, 124, 236, 20, 225, 251, 236, 29, 226, 131, 237, 34, 227, 13, 238, 27, 228, 147, 238, 11, 229, 21, 239, 242, 229, 148, 239, 216, 230, 20, 240, 193, 231, 152, 240, 174, 232, 35, 241, 163, 233, 189, 241, 156, 234, 115, 242, 156, 235, 71, 243, 158, 236, 63, 244, 163, 237, 94, 245, 172, 238, 175, 246, 200, 239, 81, 248, 28, 241, 94, 250, 204, 242, 234, 252, 249, 244, 247, 255, 175, 247, 120, 3, 237, 250, 88, 7, 161, 254, 110, 11, 170, 2, 142, 15, 224, 6, 137, 19, 17, 11, 52, 23, 17, 15, 105, 26, 177, 18, 10, 29, 207, 21, 3, 31, 82, 24, 72, 32, 46, 26, 215, 32, 96, 27, 182, 32, 239, 27, 250, 31, 238, 27, 185, 30, 115, 27, 22, 29, 157, 26, 46, 27, 144, 25, 36, 25, 107, 24, 22, 23, 83, 23, 31, 21, 92, 22, 82, 19, 156, 21, 186, 17, 30, 21, 90, 16, 228, 20, 54, 15, 236, 20, 72, 14, 43, 21, 132, 13, 141, 21, 214, 12, 242, 21, 35, 12, 54, 22, 90, 11, 62, 22, 109, 10, 244, 21, 91, 9, 80, 21, 38, 8, 87, 20, 223, 6, 21, 19, 147, 5, 160, 17, 87, 4, 17, 16, 68, 3, 129, 14, 104, 2, 8, 13, 212, 1, 186, 11, 136, 1, 164, 10, 132, 1, 207, 9, 188, 1, 57, 9, 31, 2, 224, 8, 157, 2, 187, 8, 31, 3, 189, 8, 149, 3, 213, 8, 236, 3, 238, 8, 27, 4, 249, 8, 28, 4, 234, 8, 234, 3, 182, 8, 139, 3, 92, 8, 3, 3, 222, 7, 94, 2, 65, 7, 165, 1, 144, 6, 229, 0, 212, 5, 36, 0, 21, 5, 97, 255, 83, 4, 145, 254, 132, 3, 167, 253, 155, 2, 151, 252, 143, 1, 87, 251, 87, 0, 229, 249, 242, 254, 66, 248, 93, 253, 119, 246, 162, 251, 141, 244, 206, 249, 143, 242, 241, 247, 139, 240, 29, 246, 143, 238, 100, 244, 173, 236, 218, 242, 245, 234, 144, 241, 121, 233, 156, 240, 70, 232, 15, 240, 104, 231, 248, 239, 230, 230, 91, 240, 196, 230, 51, 241, 255, 230, 112, 242, 145, 231, 249, 243, 122, 232, 178, 245, 180, 233, 125, 247, 55, 235, 61, 249, 249, 236, 219, 250, 241, 238, 71, 252, 28, 241, 133, 253, 116, 243, 156, 254, 240, 245, 150, 255, 129, 248, 125, 0, 20, 251, 87, 1, 143, 253, 37, 2, 216, 255, 227, 2, 211, 1, 139, 3, 115, 3, 21, 4, 163, 4, 123, 4, 94, 5, 182, 4, 161, 5, 194, 4, 118, 5, 161, 4, 235, 4, 84, 4, 16, 4, 227, 3, 253, 2, 86, 3, 201, 1, 180, 2, 139, 0, 6, 2, 89, 255, 83, 1, 66, 254, 163, 0, 82, 253, 1, 0, 147, 252, 115, 255, 8, 252, 250, 254, 173, 251, 155, 254, 125, 251, 84, 254, 105, 251, 32, 254, 97, 251, 253, 253, 90, 251, 226, 253, 67, 251, 194, 253, 7, 251, 136, 253, 142, 250, 28, 253, 202, 249, 106, 252, 180, 248, 102, 251, 80, 247, 15, 250, 173, 245, 105, 248, 224, 243, 137, 246, 6, 242, 133, 244, 64, 240, 117, 242, 180, 238, 118, 240, 129, 237, 161, 238, 189, 236, 8, 237, 117, 236, 185, 235, 167, 236, 185, 234, 73, 237, 10, 234, 72, 238, 169, 233, 137, 239, 137, 233, 241, 240, 153, 233, 96, 242, 195, 233, 186, 243, 236, 233, 234, 244, 253, 233, 223, 245, 226, 233, 139, 246, 145, 233, 237, 246, 4, 233, 4, 247, 58, 232, 211, 246, 65, 231, 97, 246, 37, 230, 184, 245, 247, 228, 227, 244, 203, 227, 239, 243, 179, 226, 237, 242, 191, 225, 232, 241, 252, 224, 241, 240, 117, 224, 18, 240, 45, 224, 85, 239, 38, 224, 194, 238, 92, 224, 92, 238, 203, 224, 38, 238, 109, 225, 23, 238, 53, 226, 38, 238, 20, 227, 76, 238, 3, 228, 133, 238, 247, 228, 204, 238, 235, 229, 31, 239, 222, 230, 126, 239, 207, 231, 234, 239, 192, 232, 99, 240, 178, 233, 235, 240, 164, 234, 131, 241, 150, 235, 42, 242, 132, 236, 226, 242, 111, 237, 177, 243, 84, 238, 153, 244, 53, 239, 155, 245, 17, 240, 195, 246, 244, 240, 37, 248, 249, 241, 217, 249, 64, 243, 247, 251, 232, 244, 133, 254, 6, 247, 130, 1, 160, 249, 225, 4, 178, 252, 133, 8, 36, 0, 77, 12, 217, 3, 16, 16, 174, 7, 168, 19, 120, 11, 238, 22, 14, 15, 196, 25, 79, 18, 17, 28, 29, 21, 190, 29, 101, 23, 196, 30, 25, 25, 35, 31, 56, 26, 231, 30, 196, 26, 33, 30, 205, 26, 234, 28, 99, 26, 95, 27, 159, 25, 159, 25, 165, 24, 195, 23, 146, 23, 235, 21, 130, 22, 44, 20, 146, 21, 149, 18, 209, 20, 50, 17, 76, 20, 5, 16, 7, 20, 11, 15, 254, 19, 63, 14, 41, 20, 143, 13, 112, 20, 228, 12, 180, 20, 43, 12, 220, 20, 86, 11, 206, 20, 91, 10, 122, 20, 63, 9, 221, 19, 7, 8, 250, 18, 196, 6, 222, 17, 136, 5, 153, 16, 105, 4, 65, 15, 122, 3, 232, 13, 197, 2, 163, 12, 84, 2, 130, 11, 38, 2, 144, 10, 50, 2, 211, 9, 111, 2, 76, 9, 203, 2, 248, 8, 57, 3, 208, 8, 165, 3, 200, 8, 0, 4, 212, 8, 63, 4, 226, 8, 90, 4, 229, 8, 75, 4, 211, 8, 18, 4, 164, 8, 178, 3, 84, 8, 47, 3, 230, 7, 147, 2, 95, 7, 232, 1, 197, 6, 52, 1, 30, 6, 122, 0, 111, 5, 184, 255, 179, 4, 224, 254, 225, 3, 234, 253, 242, 2, 206, 252, 221, 1, 135, 251, 162, 0, 22, 250, 64, 255, 124, 248, 184, 253, 190, 246, 22, 252, 227, 244, 100, 250, 245, 242, 177, 248, 3, 241, 13, 247, 27, 239, 134, 245, 79, 237, 50, 244, 177, 235, 38, 243, 79, 234, 114, 242, 57, 233, 36, 242, 117, 232, 67, 242, 10, 232, 203, 242, 249, 231, 180, 243, 61, 232, 233, 244, 209, 232, 85, 246, 176, 233, 222, 247, 210, 234, 109, 249, 52, 236, 233, 250, 206, 237, 67, 252, 159, 239, 118, 253, 167, 241, 136, 254, 227, 243, 128, 255, 72, 246, 100, 0, 199, 248, 61, 1, 77, 251, 14, 2, 193, 253, 211, 2, 8, 0, 135, 3, 11, 2, 36, 4, 184, 3, 164, 4, 255, 4, 255, 4, 215, 5, 48, 5, 61, 6, 54, 5, 56, 6, 15, 5, 210, 5, 191, 4, 28, 5, 76, 4, 40, 4, 186, 3, 12, 3, 15, 3, 220, 1, 80, 2, 173, 0, 136, 1, 144, 255, 194, 0, 145, 254, 8, 0, 185, 253, 100, 255, 16, 253, 217, 254, 149, 252, 110, 254, 68, 252, 33, 254, 21, 252, 241, 253, 251, 251, 215, 253, 233, 251, 200, 253, 200, 251, 180, 253, 131, 251, 130, 253, 4, 251, 29, 253, 64, 250, 115, 252, 54, 249, 126, 251, 233, 247, 61, 250, 105, 246, 184, 248, 207, 244, 2, 247, 58, 243, 44, 245, 202, 241, 78, 243, 155, 240, 126, 241, 195, 239, 208, 239, 79, 239, 87, 238, 66, 239, 28, 237, 153, 239, 41, 236, 67, 240, 125, 235, 47, 241, 18, 235, 70, 242, 223, 234, 112, 243, 210, 234, 150, 244, 216, 234, 164, 245, 221, 234, 136, 246, 204, 234, 54, 247, 152, 234, 168, 247, 57, 234, 221, 247, 173, 233, 215, 247, 245, 232, 155, 247, 27, 232, 46, 247, 41, 231, 152, 246, 47, 230, 225, 245, 57, 229, 19, 245, 86, 228, 58, 244, 148, 227, 96, 243, 251, 226, 143, 242, 150, 226, 208, 241, 106, 226, 44, 241, 118, 226, 164, 240, 180, 226, 55, 240, 34, 227, 229, 239, 181, 227, 170, 239, 105, 228, 133, 239, 51, 229, 116, 239, 14, 230, 122, 239, 242, 230, 148, 239, 223, 231, 197, 239, 212, 232, 13, 240, 203, 233, 110, 240, 197, 234, 231, 240, 191, 235, 119, 241, 181, 236, 29, 242, 164, 237, 215, 242, 139, 238, 163, 243, 102, 239, 130, 244, 55, 240, 117, 245, 254, 240, 131, 246, 194, 241, 188, 247, 154, 242, 55, 249, 161, 243, 11, 251, 244, 244, 70, 253, 171, 246, 231, 255, 208, 248, 233, 2, 101, 251, 58, 6, 95, 254, 190, 9, 166, 1, 85, 13, 33, 5, 221, 16, 174, 8, 49, 20, 42, 12, 47, 23, 112, 15, 185, 25, 101, 18, 184, 27, 241, 20, 31, 29, 2, 23, 234, 29, 141, 24, 28, 30, 143, 25, 195, 29, 9, 26, 242, 28, 6, 26, 193, 27, 153, 25, 74, 26, 221, 24, 167, 24, 238, 23, 242, 22, 235, 22, 66, 21, 238, 21, 170, 19, 10, 21, 55, 18, 83, 20, 247, 16, 213, 19, 233, 15, 144, 19, 10, 15, 131, 19, 77, 14, 159, 19, 161, 13, 205, 19, 240, 12, 244, 19, 43, 12, 251, 19, 72, 11, 210, 19, 68, 10, 111, 19, 33, 9, 206, 18, 239, 7, 245, 17, 188, 6, 239, 16, 155, 5, 202, 15, 157, 4, 152, 14, 206, 3, 106, 13, 55, 3, 78, 12, 217, 2, 81, 11, 179, 2, 123, 10, 190, 2, 212, 9, 238, 2, 90, 9, 57, 3, 12, 9, 141, 3, 229, 8, 222, 3, 217, 8, 35, 4, 222, 8, 80, 4, 229, 8, 93, 4, 227, 8, 72, 4, 207, 8, 17, 4, 163, 8, 185, 3, 94, 8, 68, 3, 252, 7, 185, 2, 132, 7, 30, 2, 251, 6, 118, 1, 97, 6, 191, 0, 184, 5, 245, 255, 247, 4, 14, 255, 26, 4, 3, 254, 27, 3, 210, 252, 248, 1, 120, 251, 178, 0, 245, 249, 75, 255, 76, 248, 200, 253, 130, 246, 52, 252, 159, 244, 155, 250, 178, 242, 9, 249, 202, 240, 143, 247, 246, 238, 66, 246, 73, 237, 50, 245, 208, 235, 112, 244, 152, 234, 7, 244, 173, 233, 252, 243, 18, 233, 79, 244, 205, 232, 248, 244, 217, 232, 234, 245, 49, 233, 17, 247, 208, 233, 91, 248, 173, 234, 178, 249, 196, 235, 2, 251, 15, 237, 60, 252, 143, 238, 90, 253, 73, 240, 94, 254, 58, 242, 77, 255, 95, 244, 45, 0, 177, 246, 5, 1, 31, 249, 215, 1, 147, 251, 162, 2, 250, 253, 98, 3, 55, 0, 16, 4, 55, 2, 167, 4, 231, 3, 31, 5, 57, 5, 113, 5, 35, 6, 155, 5, 164, 6, 154, 5, 189, 6, 110, 5, 122, 6, 24, 5, 230, 5, 156, 4, 18, 5, 253, 3, 17, 4, 63, 3, 244, 2, 109, 2, 209, 1, 146, 1, 181, 0, 186, 0, 176, 255, 244, 255, 202, 254, 68, 255, 10, 254, 180, 254, 117, 253, 70, 254, 7, 253, 253, 253, 189, 252, 209, 253, 139, 252, 191, 253, 99, 252, 183, 253, 47, 252, 165, 253, 217, 251, 115, 253, 82, 251, 15, 253, 143, 250, 108, 252, 144, 249, 130, 251, 97, 248, 85, 250, 18, 247, 236, 248, 187, 245, 87, 247, 120, 244, 165, 245, 96, 243, 236, 243, 133, 242, 63, 242, 245, 241, 176, 240, 182, 241, 76, 239, 197, 241, 33, 238, 30, 242, 50, 237, 180, 242, 127, 236, 117, 243, 3, 236, 82, 244, 178, 235, 55, 245, 129, 235, 20, 246, 95, 235, 218, 246, 60, 235, 124, 247, 12, 235, 244, 247, 196, 234, 61, 248, 94, 234, 87, 248, 216, 233, 67, 248, 53, 233, 6, 248, 125, 232, 164, 247, 181, 231, 34, 247, 234, 230, 137, 246, 38, 230, 221, 245, 120, 229, 40, 245, 229, 228, 113, 244, 116, 228, 190, 243, 47, 228, 21, 243, 21, 228, 121, 242, 40, 228, 234, 241, 101, 228, 106, 241, 203, 228, 249, 240, 82, 229, 154, 240, 246, 229, 79, 240, 177, 230, 27, 240, 128, 231, 2, 240, 98, 232, 3, 240, 81, 233, 36, 240, 74, 234, 100, 240, 77, 235, 198, 240, 79, 236, 68, 241, 76, 237, 221, 241, 66, 238, 142, 242, 42, 239, 85, 243, 4, 240, 44, 244, 207, 240, 21, 245, 140, 241, 18, 246, 63, 242, 42, 247, 246, 242, 117, 248, 203, 243, 8, 250, 217, 244, 242, 251, 54, 246, 60, 254, 244, 247, 228, 0, 26, 250, 226, 3, 164, 252, 36, 7, 134, 255, 141, 10, 169, 2, 255, 13, 247, 5, 88, 17, 79, 9, 116, 20, 146, 12, 54, 23, 162, 15, 133, 25, 102, 18, 78, 27, 201, 20, 136, 28, 185, 22, 51, 29, 42, 24, 82, 29, 25, 25, 246, 28, 136, 25, 46, 28, 130, 25, 17, 27, 26, 25, 179, 25, 103, 24, 47, 24, 134, 23, 156, 22, 148, 22, 15, 21, 167, 21, 152, 19, 212, 20, 68, 18, 41, 20, 27, 17, 175, 19, 32, 16, 105, 19, 74, 15, 80, 19, 138, 14, 83, 19, 207, 13, 93, 19, 11, 13, 92, 19, 48, 12, 62, 19, 57, 11, 245, 18, 41, 10, 124, 18, 7, 9, 211, 17, 226, 7, 1, 17, 198, 6, 14, 16, 192, 5, 4, 15, 223, 4, 245, 13, 40, 4, 235, 12, 162, 3, 245, 11, 77, 3, 28, 11, 37, 3, 101, 10, 37, 3, 214, 9, 66, 3, 110, 9, 117, 3, 43, 9, 176, 3, 8, 9, 235, 3, 252, 8, 27, 4, 251, 8, 57, 4, 253, 8, 63, 4, 246, 8, 42, 4, 224, 8, 249, 3, 180, 8, 173, 3, 112, 8, 73, 3, 22, 8, 208, 2, 169, 7, 70, 2, 42, 7, 168, 1, 151, 6, 244, 0, 238, 5, 34, 0, 40, 5, 47, 255, 66, 4, 20, 254, 57, 3, 207, 252, 14, 2, 94, 251, 194, 0, 195, 249, 92, 255, 3, 248, 225, 253, 41, 246, 93, 252, 62, 244, 219, 250, 83, 242, 108, 249, 119, 240, 34, 248, 186, 238, 13, 247, 42, 237, 60, 246, 211, 235, 183, 245, 194, 234, 133, 245, 251, 233, 166, 245, 131, 233, 20, 246, 89, 233, 196, 246, 121, 233, 171, 247, 223, 233, 183, 248, 131, 234, 216, 249, 91, 235, 253, 250, 100, 236, 22, 252, 156, 237, 28, 253, 9, 239, 16, 254, 174, 240, 246, 254, 140, 242, 209, 255, 159, 244, 166, 0, 221, 246, 122, 1, 55, 249, 75, 2, 154, 251, 21, 3, 242, 253, 212, 3, 39, 0, 129, 4, 38, 2, 21, 5, 221, 3, 136, 5, 63, 5, 214, 5, 64, 6, 252, 5, 224, 6, 244, 5, 30, 7, 193, 5, 2, 7, 96, 5, 149, 6, 211, 4, 230, 5, 32, 4, 5, 5, 80, 3, 3, 4, 108, 2, 239, 2, 129, 1, 219, 1, 159, 0, 210, 0, 209, 255, 225, 255, 30, 255, 14, 255, 141, 254, 95, 254, 34, 254, 212, 253, 219, 253, 106, 253, 180, 253, 24, 253, 163, 253, 205, 252, 151, 253, 116, 252, 125, 253, 255, 251, 63, 253, 96, 251, 209, 252, 148, 250, 39, 252, 161, 249, 63, 251, 147, 248, 30, 250, 124, 247, 202, 248, 110, 246, 81, 247, 123, 245, 193, 245, 177, 244, 46, 244, 28, 244, 166, 242, 194, 243, 56, 241, 166, 243, 241, 239, 196, 243, 215, 238, 21, 244, 238, 237, 145, 244, 51, 237, 40, 245, 163, 236, 208, 245, 54, 236, 123, 246, 226, 235, 28, 247, 155, 235, 170, 247, 86, 235, 28, 248, 10, 235, 107, 248, 175, 234, 151, 248, 65, 234, 159, 248, 192, 233, 131, 248, 46, 233, 74, 248, 145, 232, 244, 247, 240, 231, 134, 247, 78, 231, 6, 247, 182, 230, 117, 246, 49, 230, 220, 245, 196, 229, 62, 245, 117, 229, 156, 244, 73, 229, 250, 243, 65, 229, 89, 243, 95, 229, 188, 242, 160, 229, 39, 242, 4, 230, 159, 241, 133, 230, 39, 241, 35, 231, 198, 240, 220, 231, 129, 240, 176, 232, 91, 240, 152, 233, 85, 240, 141, 234, 115, 240, 141, 235, 180, 240, 143, 236, 22, 241, 142, 237, 152, 241, 135, 238, 55, 242, 114, 239, 238, 242, 77, 240, 185, 243, 24, 241, 149, 244, 211, 241, 130, 245, 127, 242, 134, 246, 41, 243, 178, 247, 231, 243, 26, 249, 207, 244, 207, 250, 247, 245, 220, 252, 115, 247, 68, 255, 77, 249, 2, 2, 133, 251, 10, 5, 21, 254, 69, 8, 236, 0, 153, 11, 249, 3, 231, 14, 32, 7, 12, 18, 71, 10, 237, 20, 83, 13, 113, 23, 42, 16, 131, 25, 180, 18, 22, 27, 222, 20, 38, 28, 154, 22, 176, 28, 221, 23, 189, 28, 164, 24, 90, 28, 247, 24, 154, 27, 226, 24, 143, 26, 123, 24, 77, 25, 216, 23, 235, 23, 16, 23, 122, 22, 61, 22, 13, 21, 112, 21, 180, 19, 187, 20, 120, 18, 41, 20, 98, 17, 193, 19, 111, 16, 130, 19, 152, 15, 98, 19, 207, 14, 83, 19, 2, 14, 65, 19, 42, 13, 30, 19, 62, 12, 222, 18, 63, 11, 120, 18, 49, 10, 234, 17, 28, 9, 54, 17, 10, 8, 97, 16, 4, 7, 116, 15, 21, 6, 122, 14, 68, 5, 127, 13, 152, 4, 142, 12, 19, 4, 175, 11, 183, 3, 236, 10, 128, 3, 75, 10, 105, 3, 204, 9, 110, 3, 113, 9, 133, 3, 57, 9, 167, 3, 28, 9, 203, 3, 18, 9, 234, 3, 17, 9, 253, 3, 17, 9, 1, 4, 10, 9, 240, 3, 244, 8, 201, 3, 204, 8, 140, 3, 145, 8, 59, 3, 64, 8, 214, 2, 220, 7, 90, 2, 99, 7, 196, 1, 209, 6, 14, 1, 35, 6, 50, 0, 82, 5, 46, 255, 95, 4, 249, 253, 71, 3, 148, 252, 14, 2, 1, 251, 186, 0, 71, 249, 82, 255, 110, 247, 220, 253, 130, 245, 102, 252, 147, 243, 4, 251, 174, 241, 194, 249, 227, 239, 175, 248, 62, 238, 215, 247, 207, 236, 67, 247, 158, 235, 247, 246, 179, 234, 241, 246, 17, 234, 49, 247, 185, 233, 174, 247, 171, 233, 93, 248, 223, 233, 49, 249, 83, 234, 30, 250, 252, 234, 20, 251, 211, 235, 6, 252, 216, 236, 239, 252, 11, 238, 204, 253, 115, 239, 160, 254, 18, 241, 112, 255, 233, 242, 61, 0, 242, 244, 13, 1, 35, 247, 223, 1, 110, 249, 175, 2, 193, 251, 121, 3, 9, 254, 55, 4, 50, 0, 226, 4, 40, 2, 114, 5, 221, 3, 226, 5, 69, 5, 44, 6, 84, 6, 74, 6, 8, 7, 57, 6, 96, 7, 248, 5, 99, 7, 134, 5, 23, 7, 232, 4, 138, 6, 37, 4, 200, 5, 71, 3, 225, 4, 90, 2, 226, 3, 108, 1, 219, 2, 137, 0, 215, 1, 188, 255, 226, 0, 13, 255, 5, 0, 128, 254, 70, 255, 24, 254, 164, 254, 212, 253, 32, 254, 173, 253, 174, 253, 151, 253, 64, 253, 127, 253, 199, 252, 85, 253, 56, 252, 9, 253, 143, 251, 142, 252, 206, 250, 224, 251, 249, 249, 251, 250, 28, 249, 227, 249, 64, 248, 160, 248, 114, 247, 62, 247, 188, 246, 203, 245, 39, 246, 83, 244, 185, 245, 231, 242, 120, 245, 145, 241, 96, 245, 89, 240, 113, 245, 68, 239, 166, 245, 84, 238, 248, 245, 139, 237, 93, 246, 228, 236, 205, 246, 91, 236, 65, 247, 232, 235, 173, 247, 133, 235, 13, 248, 40, 235, 89, 248, 202, 234, 142, 248, 105, 234, 169, 248, 0, 234, 170, 248, 141, 233, 146, 248, 18, 233, 98, 248, 147, 232, 30, 248, 18, 232, 198, 247, 151, 231, 93, 247, 37, 231, 231, 246, 195, 230, 99, 246, 120, 230, 210, 245, 70, 230, 55, 245, 48, 230, 148, 244, 57, 230, 236, 243, 95, 230, 71, 243, 166, 230, 167, 242, 15, 231, 22, 242, 150, 231, 149, 241, 59, 232, 45, 241, 251, 232, 226, 240, 210, 233, 184, 240, 187, 234, 176, 240, 176, 235, 205, 240, 171, 236, 13, 241, 166, 237, 112, 241, 156, 238, 242, 241, 134, 239, 143, 242, 98, 240, 68, 243, 45, 241, 13, 244, 231, 241, 232, 244, 145, 242, 214, 245, 51, 243, 228, 246, 224, 243, 36, 248, 169, 244, 164, 249, 167, 245, 117, 251, 234, 246, 154, 253, 127, 248, 19, 0, 108, 250, 216, 2, 173, 252, 218, 5, 56, 255, 0, 9, 0, 2, 49, 12, 240, 4, 80, 15, 243, 7, 65, 18, 237, 10, 237, 20, 201, 13, 63, 23, 110, 16, 39, 25, 199, 18, 156, 26, 194, 20, 152, 27, 83, 22, 31, 28, 118, 23, 54, 28, 41, 24, 232, 27, 117, 24, 70, 27, 102, 24, 94, 26, 15, 24, 67, 25, 132, 23, 6, 24, 221, 22, 187, 22, 42, 22, 108, 21, 124, 21, 43, 20, 226, 20, 0, 19, 100, 20, 241, 17, 6, 20, 251, 16, 195, 19, 20, 16, 145, 19, 51, 15, 100, 19, 78, 14, 47, 19, 97, 13, 231, 18, 102, 12, 132, 18, 99, 11, 1, 18, 87, 10, 93, 17, 74, 9, 156, 16, 69, 8, 198, 15, 74, 7, 223, 14, 101, 6, 243, 13, 153, 5, 12, 13, 237, 4, 48, 12, 98, 4, 106, 11, 248, 3, 193, 10, 175, 3, 53, 10, 130, 3, 201, 9, 111, 3, 125, 9, 110, 3, 78, 9, 123, 3, 54, 9, 142, 3, 47, 9, 161, 3, 46, 9, 175, 3, 46, 9, 178, 3, 39, 9, 167, 3, 17, 9, 141, 3, 237, 8, 97, 3, 182, 8, 34, 3, 108, 8, 206, 2, 15, 8, 95, 2, 152, 7, 208, 1, 7, 7, 24, 1, 83, 6, 51, 0, 124, 5, 30, 255, 131, 4, 210, 253, 101, 3, 83, 252, 42, 2, 169, 250, 214, 0, 219, 248, 117, 255, 246, 246, 17, 254, 5, 245, 186, 252, 25, 243, 126, 251, 62, 241, 105, 250, 131, 239, 134, 249, 244, 237, 220, 248, 156, 236, 111, 248, 132, 235, 65, 248, 175, 234, 77, 248, 33, 234, 145, 248, 217, 233, 5, 249, 213, 233, 161, 249, 17, 234, 86, 250, 131, 234, 27, 251, 42, 235, 229, 251, 252, 235, 173, 252, 251, 236, 111, 253, 42, 238, 46, 254, 141, 239, 237, 254, 40, 241, 176, 255, 247, 242, 120, 0, 246, 244, 70, 1, 29, 247, 24, 2, 90, 249, 234, 2, 161, 251, 183, 3, 223, 253, 119, 4, 0, 0, 36, 5, 244, 1, 180, 5, 176, 3, 35, 6, 35, 5, 104, 6, 71, 6, 126, 6, 20, 7, 98, 6, 142, 7, 19, 6, 181, 7, 148, 5, 144, 7, 236, 4, 42, 7, 31, 4, 139, 6, 60, 3, 195, 5, 77, 2, 220, 4, 96, 1, 230, 3, 128, 0, 234, 2, 184, 255, 245, 1, 13, 255, 15, 1, 131, 254, 62, 0, 28, 254, 134, 255, 212, 253, 226, 254, 164, 253, 74, 254, 124, 253, 179, 253, 78, 253, 24, 253, 9, 253, 115, 252, 165, 252, 196, 251, 23, 252, 13, 251, 90, 251, 81, 250, 113, 250, 151, 249, 95, 249, 230, 248, 44, 248, 67, 248, 224, 246, 181, 247, 137, 245, 66, 247, 50, 244, 236, 246, 226, 242, 181, 246, 163, 241, 155, 246, 124, 240, 160, 246, 113, 239, 190, 246, 131, 238, 240, 246, 178, 237, 48, 247, 255, 236, 122, 247, 102, 236, 198, 247, 226, 235, 15, 248, 110, 235, 78, 248, 1, 235, 129, 248, 152, 234, 164, 248, 48, 234, 180, 248, 198, 233, 177, 248, 91, 233, 155, 248, 238, 232, 115, 248, 129, 232, 59, 248, 25, 232, 243, 247, 183, 231, 155, 247, 98, 231, 48, 247, 29, 231, 180, 246, 236, 230, 40, 246, 209, 230, 143, 245, 208, 230, 237, 244, 235, 230, 68, 244, 34, 231, 158, 243, 118, 231, 253, 242, 234, 231, 107, 242, 122, 232, 236, 241, 39, 233, 134, 241, 235, 233, 61, 241, 196, 234, 20, 241, 171, 235, 14, 241, 155, 236, 43, 241, 142, 237, 105, 241, 124, 238, 200, 241, 99, 239, 68, 242, 61, 240, 218, 242, 9, 241, 136, 243, 196, 241, 74, 244, 112, 242, 31, 245, 18, 243, 16, 246, 181, 243, 43, 247, 110, 244, 127, 248, 79, 245, 24, 250, 105, 246, 255, 251, 202, 247, 56, 254, 122, 249, 188, 0, 121, 251, 127, 3, 193, 253, 114, 6, 73, 0, 126, 9, 1, 3, 138, 12, 216, 5, 129, 15, 183, 8, 74, 18, 136, 11, 207, 20, 53, 14, 1, 23, 167, 16, 209, 24, 204, 18, 57, 26, 153, 20, 51, 27, 3, 22, 195, 27, 8, 23, 237, 27, 171, 23, 187, 27, 243, 23, 58, 27, 238, 23, 118, 26, 173, 23, 128, 25, 64, 23, 103, 24, 185, 22, 57, 23, 40, 22, 2, 22, 152, 21, 208, 20, 24, 21, 173, 19, 172, 20, 153, 18, 84, 20, 148, 17, 11, 20, 150, 16, 198, 19, 153, 15, 125, 19, 155, 14, 38, 19, 152, 13, 185, 18, 143, 12, 52, 18, 128, 11, 149, 17, 113, 10, 220, 16, 101, 9, 16, 16, 97, 8, 53, 15, 106, 7, 83, 14, 135, 6, 114, 13, 189, 5, 155, 12, 12, 5, 213, 11, 122, 4, 36, 11, 6, 4, 141, 10, 175, 3, 20, 10, 116, 3, 184, 9, 80, 3, 122, 9, 64, 3, 85, 9, 63, 3, 67, 9, 72, 3, 63, 9, 84, 3, 63, 9, 95, 3, 64, 9, 100, 3, 55, 9, 96, 3, 37, 9, 81, 3, 3, 9, 50, 3, 209, 8, 0, 3, 141, 8, 181, 2, 49, 8, 72, 2, 185, 7, 177, 1, 33, 7, 235, 0, 102, 6, 241, 255, 134, 5, 191, 254, 131, 4, 88, 253, 95, 3, 195, 251, 34, 2, 7, 250, 215, 0, 47, 248, 136, 255, 72, 246, 66, 254, 93, 244, 17, 253, 127, 242, 0, 252, 186, 240, 23, 251, 24, 239, 94, 250, 166, 237, 216, 249, 108, 236, 136, 249, 110, 235, 108, 249, 178, 234, 129, 249, 57, 234, 193, 249, 1, 234, 39, 250, 7, 234, 169, 250, 72, 234, 62, 251, 188, 234, 222, 251, 96, 235, 130, 252, 48, 236, 39, 253, 47, 237, 207, 253, 96, 238, 126, 254, 197, 239, 51, 255, 96, 241, 243, 255, 45, 243, 186, 0, 37, 245, 141, 1, 64, 247, 100, 2, 112, 249, 57, 3, 168, 251, 7, 4, 213, 253, 200, 4, 233, 255, 112, 5, 211, 1, 249, 5, 137, 3, 92, 6, 254, 4, 146, 6, 43, 6, 151, 6, 10, 7, 104, 6, 153, 7, 9, 6, 220, 7, 126, 5, 215, 7, 203, 4, 147, 7, 252, 3, 22, 7, 27, 3, 109, 6, 51, 2, 164, 5, 80, 1, 196, 4, 123, 0, 217, 3, 191, 255, 237, 2, 29, 255, 8, 2, 155, 254, 51, 1, 55, 254, 107, 0, 236, 253, 179, 255, 176, 253, 3, 255, 117, 253, 88, 254, 48, 253, 176, 253, 212, 252, 9, 253, 89, 252, 96, 252, 187, 251, 185, 251, 245, 250, 18, 251, 10, 250, 112, 250, 255, 248, 215, 249, 217, 247, 73, 249, 161, 246, 203, 248, 97, 245, 95, 248, 30, 244, 9, 248, 226, 242, 201, 247, 178, 241, 159, 247, 148, 240, 140, 247, 140, 239, 140, 247, 156, 238, 157, 247, 200, 237, 187, 247, 12, 237, 225, 247, 105, 236, 13, 248, 218, 235, 58, 248, 89, 235, 98, 248, 229, 234, 132, 248, 121, 234, 156, 248, 18, 234, 169, 248, 175, 233, 168, 248, 78, 233, 153, 248, 242, 232, 125, 248, 154, 232, 81, 248, 73, 232, 18, 248, 1, 232, 193, 247, 200, 231, 92, 247, 158, 231, 228, 246, 132, 231, 91, 246, 126, 231, 197, 245, 142, 231, 37, 245, 185, 231, 131, 244, 254, 231, 227, 243, 97, 232, 74, 243, 224, 232, 193, 242, 121, 233, 75, 242, 43, 234, 238, 241, 240, 234, 172, 241, 197, 235, 136, 241, 164, 236, 132, 241, 135, 237, 162, 241, 106, 238, 223, 241, 73, 239, 57, 242, 29, 240, 173, 242, 228, 240, 58, 243, 156, 241, 221, 243, 71, 242, 149, 244, 231, 242, 104, 245, 134, 243, 98, 246, 53, 244, 142, 247, 5, 245, 249, 248, 3, 246, 171, 250, 64, 247, 168, 252, 193, 248, 237, 254, 139, 250, 111, 1, 155, 252, 40, 4, 234, 254, 3, 7, 109, 1, 236, 9, 20, 4, 209, 12, 206, 6, 156, 15, 133, 9, 57, 18, 37, 12, 151, 20, 154, 14, 168, 22, 211, 16, 98, 24, 195, 18, 189, 25, 94, 20, 181, 26, 162, 21, 77, 27, 139, 22, 139, 27, 31, 23, 117, 27, 102, 23, 19, 27, 109, 23, 114, 26, 63, 23, 159, 25, 237, 22, 167, 24, 132, 22, 152, 23, 18, 22, 126, 22, 164, 21, 98, 21, 62, 21, 74, 20, 228, 20, 58, 19, 146, 20, 46, 18, 68, 20, 40, 17, 241, 19, 34, 16, 147, 19, 25, 15, 35, 19, 13, 14, 159, 18, 252, 12, 3, 18, 232, 11, 79, 17, 211, 10, 138, 16, 194, 9, 180, 15, 182, 8, 214, 14, 183, 7, 246, 13, 201, 6, 26, 13, 240, 5, 75, 12, 47, 5, 142, 11, 137, 4, 231, 10, 0, 4, 92, 10, 148, 3, 235, 9, 66, 3, 151, 9, 10, 3, 96, 9, 233, 2, 61, 9, 216, 2, 45, 9, 213, 2, 41, 9, 220, 2, 43, 9, 230, 2, 45, 9, 240, 2, 40, 9, 244, 2, 26, 9, 240, 2, 0, 9, 222, 2, 213, 8, 182, 2, 150, 8, 111, 2, 61, 8, 0, 2, 196, 7, 96, 1, 41, 7, 140, 0, 106, 6, 132, 255, 136, 5, 68, 254, 133, 4, 211, 252, 103, 3, 57, 251, 59, 2, 126, 249, 7, 1, 173, 247, 218, 255, 210, 245, 186, 254, 251, 243, 178, 253, 51, 242, 201, 252, 134, 240, 5, 252, 254, 238, 106, 251, 164, 237, 252, 250, 128, 236, 184, 250, 150, 235, 158, 250, 233, 234, 172, 250, 121, 234, 219, 250, 69, 234, 39, 251, 75, 234, 136, 251, 135, 234, 248, 251, 244, 234, 113, 252, 146, 235, 241, 252, 94, 236, 121, 253, 92, 237, 11, 254, 141, 238, 170, 254, 243, 239, 87, 255, 139, 241, 18, 0, 83, 243, 218, 0, 66, 245, 172, 1, 82, 247, 132, 2, 115, 249, 90, 3, 154, 251, 39, 4, 185, 253, 227, 4, 192, 255, 133, 5, 160, 1, 5, 6, 81, 3, 91, 6, 201, 4, 132, 6, 253, 5, 126, 6, 235, 6, 71, 6, 143, 7, 227, 5, 237, 7, 86, 5, 7, 8, 168, 4, 228, 7, 226, 3, 137, 7, 12, 3, 0, 7, 51, 2, 84, 6, 95, 1, 142, 5, 151, 0, 182, 4, 230, 255, 217, 3, 78, 255, 252, 2, 207, 254, 39, 2, 105, 254, 92, 1, 20, 254, 156, 0, 197, 253, 234, 255, 115, 253, 63, 255, 21, 253, 154, 254, 160, 252, 247, 253, 15, 252, 86, 253, 95, 251, 183, 252, 142, 250, 25, 252, 161, 249, 127, 251, 153, 248, 235, 250, 125, 247, 92, 250, 82, 246, 217, 249, 30, 245, 99, 249, 231, 243, 252, 248, 182, 242, 165, 248, 142, 241, 96, 248, 117, 240, 45, 248, 112, 239, 11, 248, 128, 238, 250, 247, 169, 237, 246, 247, 234, 236, 254, 247, 65, 236, 15, 248, 173, 235, 35, 248, 41, 235, 59, 248, 179, 234, 81, 248, 72, 234, 100, 248, 230, 233, 112, 248, 139, 233, 116, 248, 55, 233, 110, 248, 236, 232, 89, 248, 169, 232, 52, 248, 110, 232, 253, 247, 62, 232, 178, 247, 23, 232, 84, 247, 0, 232, 229, 246, 250, 231, 101, 246, 6, 232, 218, 245, 42, 232, 73, 245, 103, 232, 182, 244, 190, 232, 38, 244, 46, 233, 158, 243, 183, 233, 35, 243, 87, 234, 186, 242, 10, 235, 104, 242, 206, 235, 47, 242, 157, 236, 17, 242, 112, 237, 15, 242, 69, 238, 41, 242, 23, 239, 94, 242, 225, 239, 173, 242, 163, 240, 21, 243, 87, 241, 147, 243, 0, 242, 39, 244, 158, 242, 214, 244, 58, 243, 170, 245, 224, 243, 169, 246, 159, 244, 225, 247, 133, 245, 88, 249, 159, 246, 19, 251, 246, 247, 18, 253, 142, 249, 80, 255, 105, 251, 196, 1, 129, 253, 101, 4, 208, 255, 34, 7, 69, 2, 234, 9, 215, 4, 170, 12, 111, 7, 83, 15, 253, 9, 210, 17, 111, 12, 24, 20, 181, 14, 27, 22, 192, 16, 207, 23, 136, 18, 47, 25, 3, 20, 54, 26, 48, 21, 231, 26, 14, 22, 68, 27, 162, 22, 82, 27, 243, 22, 26, 27, 13, 23, 165, 26, 251, 22, 253, 25, 200, 22, 44, 25, 129, 22, 65, 24, 49, 22, 66, 23, 221, 21, 59, 22, 140, 21, 47, 21, 60, 21, 33, 20, 235, 20, 18, 19, 147, 20, 2, 18, 47, 20, 239, 16, 187, 19, 212, 15, 50, 19, 179, 14, 147, 18, 143, 13, 224, 17, 104, 12, 26, 17, 64, 11, 70, 16, 27, 10, 105, 15, 253, 8, 136, 14, 237, 7, 169, 13, 237, 6, 212, 12, 0, 6, 12, 12, 46, 5, 88, 11, 117, 4, 187, 10, 218, 3, 57, 10, 92, 3, 210, 9, 250, 2, 133, 9, 179, 2, 83, 9, 132, 2, 54, 9, 106, 2, 39, 9, 97, 2, 36, 9, 101, 2, 38, 9, 110, 2, 40, 9, 124, 2, 38, 9, 135, 2, 27, 9, 138, 2, 4, 9, 126, 2, 221, 8, 86, 2, 160, 8, 10, 2, 70, 8, 146, 1, 205, 7, 234, 0, 51, 7, 13, 0, 118, 6, 254, 254, 154, 5, 189, 253, 164, 4, 78, 252, 157, 3, 186, 250, 140, 2, 12, 249, 122, 1, 76, 247, 111, 0, 134, 245, 117, 255, 197, 243, 143, 254, 19, 242, 195, 253, 125, 240, 23, 253, 10, 239, 140, 252, 194, 237, 35, 252, 171, 236, 220, 251, 200, 235, 183, 251, 30, 235, 178, 251, 173, 234, 198, 251, 114, 234, 241, 251, 110, 234, 47, 252, 157, 234, 121, 252, 252, 234, 207, 252, 143, 235, 48, 253, 83, 236, 161, 253, 76, 237, 34, 254, 121, 238, 181, 254, 217, 239, 91, 255, 108, 241, 18, 0, 43, 243, 216, 0, 18, 245, 170, 1, 21, 247, 131, 2, 43, 249, 87, 3, 70, 251, 33, 4, 90, 253, 215, 4, 90, 255, 112, 5, 55, 1, 230, 5, 236, 2, 53, 6, 108, 4, 87, 6, 175, 5, 76, 6, 179, 6, 22, 6, 115, 7, 181, 5, 241, 7, 48, 5, 46, 8, 142, 4, 47, 8, 214, 3, 249, 7, 17, 3, 149, 7, 73, 2, 10, 7, 133, 1, 96, 6, 205, 0, 162, 5, 37, 0, 215, 4, 147, 255, 10, 4, 20, 255, 63, 3, 163, 254, 122, 2, 60, 254, 189, 1, 214, 253, 8, 1, 103, 253, 88, 0, 232, 252, 175, 255, 86, 252, 7, 255, 171, 251, 93, 254, 231, 250, 181, 253, 10, 250, 14, 253, 20, 249, 103, 252, 10, 248, 198, 251, 241, 246, 42, 251, 203, 245, 149, 250, 160, 244, 12, 250, 114, 243, 144, 249, 75, 242, 35, 249, 46, 241, 199, 248, 30, 240, 123, 248, 33, 239, 65, 248, 57, 238, 24, 248, 104, 237, 254, 247, 173, 236, 241, 247, 7, 236, 239, 247, 118, 235, 247, 247, 243, 234, 4, 248, 129, 234, 21, 248, 28, 234, 38, 248, 195, 233, 49, 248, 114, 233, 52, 248, 42, 233, 45, 248, 235, 232, 24, 248, 179, 232, 242, 247, 133, 232, 188, 247, 98, 232, 118, 247, 76, 232, 31, 247, 68, 232, 187, 246, 79, 232, 74, 246, 112, 232, 209, 245, 165, 232, 84, 245, 243, 232, 214, 244, 89, 233, 92, 244, 214, 233, 235, 243, 106, 234, 133, 243, 14, 235, 47, 243, 192, 235, 235, 242, 126, 236, 188, 242, 65, 237, 162, 242, 7, 238, 160, 242, 204, 238, 181, 242, 140, 239, 226, 242, 70, 240, 37, 243, 245, 240, 126, 243, 154, 241, 235, 243, 55, 242, 114, 244, 207, 242, 25, 245, 111, 243, 233, 245, 32, 244, 234, 246, 241, 244, 35, 248, 238, 245, 155, 249, 33, 247, 82, 251, 143, 248, 71, 253, 58, 250, 118, 255, 33, 252, 213, 1, 61, 254, 91, 4, 131, 0, 251, 6, 231, 2, 163, 9, 94, 5, 72, 12, 210, 7, 215, 14, 57, 10, 66, 17, 129, 12, 125, 19, 158, 14, 122, 21, 134, 16, 53, 23, 49, 18, 163, 24, 151, 19, 195, 25, 185, 20, 147, 26, 149, 21, 21, 27, 49, 22, 77, 27, 148, 22, 66, 27, 198, 22, 249, 26, 210, 22, 124, 26, 192, 22, 213, 25, 154, 22, 13, 25, 102, 22, 46, 24, 43, 22, 61, 23, 233, 21, 62, 22, 159, 21, 50, 21, 72, 21, 28, 20, 224, 20, 255, 18, 105, 20, 215, 17, 221, 19, 166, 16, 61, 19, 110, 15, 137, 18, 47, 14, 194, 17, 237, 12, 238, 16, 170, 11, 15, 16, 108, 10, 42, 15, 54, 9, 71, 14, 14, 8, 106, 13, 248, 6, 151, 12, 248, 5, 215, 11, 19, 5, 43, 11, 73, 4, 151, 10, 157, 3, 30, 10, 17, 3, 190, 9, 162, 2, 120, 9, 79, 2, 72, 9, 23, 2, 45, 9, 245, 1, 31, 9, 232, 1, 27, 9, 232, 1, 28, 9, 242, 1, 30, 9, 1, 2, 28, 9, 13, 2, 19, 9, 14, 2, 254, 8, 250, 1, 216, 8, 201, 1, 153, 8, 114, 1, 63, 8, 241, 0, 199, 7, 65, 0, 48, 7, 97, 255, 124, 6, 81, 254, 175, 5, 20, 253, 208, 4, 178, 251, 230, 3, 48, 250, 245, 2, 150, 248, 5, 2, 239, 246, 28, 1, 69, 245, 64, 0, 159, 243, 118, 255, 9, 242, 192, 254, 141, 240, 33, 254, 47, 239, 157, 253, 248, 237, 51, 253, 237, 236, 228, 252, 18, 236, 175, 252, 104, 235, 146, 252, 242, 234, 140, 252, 175, 234, 152, 252, 158, 234, 179, 252, 191, 234, 221, 252, 18, 235, 22, 253, 154, 235, 96, 253, 86, 236, 192, 253, 72, 237, 53, 254, 110, 238, 191, 254, 199, 239, 97, 255, 81, 241, 21, 0, 6, 243, 218, 0, 224, 244, 170, 1, 212, 246, 125, 2, 219, 248, 74, 3, 232, 250, 10, 4, 239, 252, 180, 4, 229, 254, 66, 5, 188, 0, 174, 5, 112, 2, 243, 5, 245, 3, 17, 6, 69, 5, 5, 6, 91, 6, 210, 5, 51, 7, 121, 5, 206, 7, 1, 5, 46, 8, 111, 4, 82, 8, 202, 3, 66, 8, 26, 3, 3, 8, 102, 2, 156, 7, 181, 1, 21, 7, 12, 1, 122, 6, 113, 0, 209, 5, 230, 255, 35, 5, 100, 255, 113, 4, 233, 254, 191, 3, 112, 254, 15, 3, 241, 253, 96, 2, 105, 253, 175, 1, 209, 252, 254, 0, 36, 252, 75, 0, 99, 251, 149, 255, 140, 250, 221, 254, 160, 249, 33, 254, 160, 248, 101, 253, 142, 247, 171, 252, 112, 246, 245, 251, 75, 245, 70, 251, 31, 244, 161, 250, 247, 242, 10, 250, 213, 241, 129, 249, 189, 240, 10, 249, 181, 239, 164, 248, 192, 238, 80, 248, 224, 237, 16, 248, 22, 237, 225, 247, 97, 236, 195, 247, 195, 235, 180, 247, 56, 235, 176, 247, 190, 234, 181, 247, 84, 234, 189, 247, 246, 233, 199, 247, 164, 233, 204, 247, 93, 233, 201, 247, 32, 233, 189, 247, 235, 232, 166, 247, 192, 232, 130, 247, 159, 232, 80, 247, 139, 232, 18, 247, 133, 232, 202, 246, 144, 232, 119, 246, 174, 232, 27, 246, 226, 232, 186, 245, 43, 233, 87, 245, 137, 233, 243, 244, 250, 233, 148, 244, 126, 234, 59, 244, 18, 235, 235, 243, 180, 235, 166, 243, 95, 236, 113, 243, 17, 237, 74, 243, 198, 237, 54, 243, 124, 238, 52, 243, 47, 239, 69, 243, 222, 239, 105, 243, 133, 240, 159, 243, 37, 241, 233, 243, 189, 241, 74, 244, 81, 242, 198, 244, 233, 242, 103, 245, 146, 243, 54, 246, 86, 244, 53, 247, 63, 245, 110, 248, 87, 246, 224, 249, 163, 247, 143, 251, 40, 249, 119, 253, 228, 250, 147, 255, 212, 252, 218, 1, 238, 254, 70, 4, 39, 1, 201, 6, 118, 3, 86, 9, 206, 5, 222, 11, 33, 8, 85, 14, 97, 10, 174, 16, 132, 12, 221, 18, 126, 14, 216, 20, 72, 16, 150, 22, 218, 17, 17, 24, 49, 19, 71, 25, 74, 20, 51, 26, 40, 21, 216, 26, 205, 21, 55, 27, 66, 22, 86, 27, 140, 22, 57, 27, 178, 22, 232, 26, 189, 22, 109, 26, 178, 22, 205, 25, 150, 22, 15, 25, 108, 22, 58, 24, 53, 22, 78, 23, 238, 21, 79, 22, 148, 21, 63, 21, 39, 21, 27, 20, 164, 20, 234, 18, 12, 20, 169, 17, 95, 19, 92, 16, 157, 18, 7, 15, 204, 17, 171, 13, 238, 16, 78, 12, 7, 16, 245, 10, 31, 15, 164, 9, 58, 14, 96, 8, 93, 13, 48, 7, 140, 12, 22, 6, 204, 11, 23, 5, 34, 11, 53, 4, 143, 10, 114, 3, 22, 10, 208, 2, 181, 9, 76, 2, 109, 9, 232, 1, 59, 9, 161, 1, 26, 9, 115, 1, 7, 9, 90, 1, 0, 9, 82, 1, 254, 8, 85, 1, 254, 8, 91, 1, 252, 8, 95, 1, 244, 8, 86, 1, 222, 8, 54, 1, 182, 8, 252, 0, 119, 8, 156, 0, 30, 8, 22, 0, 173, 7, 103, 255, 34, 7, 139, 254, 128, 6, 133, 253, 205, 5, 90, 252, 11, 5, 14, 251, 64, 4, 166, 249, 113, 3, 44, 248, 162, 2, 165, 246, 215, 1, 28, 245, 20, 1, 152, 243, 94, 0, 32, 242, 184, 255, 190, 240, 34, 255, 119, 239, 159, 254, 82, 238, 47, 254, 84, 237, 212, 253, 127, 236, 141, 253, 213, 235, 89, 253, 90, 235, 56, 253, 14, 235, 39, 253, 240, 234, 36, 253, 4, 235, 51, 253, 75, 235, 85, 253, 200, 235, 142, 253, 122, 236, 221, 253, 98, 237, 72, 254, 126, 238, 203, 254, 205, 239, 101, 255, 73, 241, 19, 0, 239, 242, 209, 0, 184, 244, 151, 1, 154, 246, 94, 2, 142, 248, 30, 3, 135, 250, 209, 3, 125, 252, 110, 4, 102, 254, 240, 4, 53, 0, 84, 5, 228, 1, 149, 5, 107, 3, 179, 5, 195, 4, 172, 5, 230, 5, 130, 5, 211, 6, 56, 5, 136, 7, 209, 4, 5, 8, 83, 4, 76, 8, 196, 3, 97, 8, 42, 3, 73, 8, 141, 2, 13, 8, 240, 1, 180, 7, 87, 1, 71, 7, 199, 0, 204, 6, 63, 0, 70, 6, 189, 255, 183, 5, 59, 255, 33, 5, 179, 254, 132, 4, 36, 254, 225, 3, 134, 253, 54, 3, 217, 252, 130, 2, 27, 252, 198, 1, 72, 251, 2, 1, 98, 250, 55, 0, 105, 249, 103, 255, 94, 248, 147, 254, 68, 247, 189, 253, 33, 246, 233, 252, 247, 244, 28, 252, 204, 243, 88, 251, 164, 242, 160, 250, 133, 241, 247, 249, 114, 240, 94, 249, 112, 239, 219, 248, 130, 238, 108, 248, 170, 237, 16, 248, 232, 236, 202, 247, 60, 236, 149, 247, 164, 235, 114, 247, 32, 235, 93, 247, 173, 234, 81, 247, 75, 234, 75, 247, 246, 233, 71, 247, 173, 233, 66, 247, 113, 233, 57, 247, 63, 233, 41, 247, 23, 233, 19, 247, 250, 232, 246, 246, 233, 232, 209, 246, 234, 232, 163, 246, 249, 232, 111, 246, 25, 233, 52, 246, 75, 233, 244, 245, 143, 233, 176, 245, 229, 233, 105, 245, 75, 234, 36, 245, 194, 234, 224, 244, 69, 235, 160, 244, 212, 235, 103, 244, 109, 236, 53, 244, 12, 237, 13, 244, 173, 237, 241, 243, 81, 238, 226, 243, 244, 238, 224, 243, 148, 239, 237, 243, 48, 240, 8, 244, 198, 240, 52, 244, 86, 241, 112, 244, 227, 241, 197, 244, 116, 242, 56, 245, 17, 243, 208, 245, 196, 243, 148, 246, 152, 244, 139, 247, 150, 245, 183, 248, 192, 246, 27, 250, 31, 248, 183, 251, 176, 249, 135, 253, 112, 251, 137, 255, 92, 253, 179, 1, 105, 255, 254, 3, 142, 1, 97, 6, 196, 3, 207, 8, 253, 5, 59, 11, 45, 8, 154, 13, 76, 10, 225, 15, 79, 12, 5, 18, 45, 14, 253, 19, 224, 15, 192, 21, 97, 17, 72, 23, 173, 18, 145, 24, 195, 19, 153, 25, 165, 20, 95, 26, 87, 21, 229, 26, 220, 21, 46, 27, 58, 22, 63, 27, 119, 22, 30, 27, 155, 22, 213, 26, 167, 22, 101, 26, 160, 22, 209, 25, 136, 22, 29, 25, 90, 22, 75, 24, 23, 22, 94, 23, 189, 21, 85, 22, 77, 21, 51, 21, 196, 20, 251, 19, 37, 20, 175, 18, 112, 19, 84, 17, 168, 18, 234, 15, 209, 17, 120, 14, 239, 16, 3, 13, 5, 16, 144, 11, 27, 15, 38, 10, 53, 14, 201, 8, 88, 13, 126, 7, 136, 12, 74, 6, 202, 11, 49, 5, 32, 11, 54, 4, 140, 10, 91, 3, 17, 10, 161, 2, 174, 9, 8, 2, 97, 9, 143, 1, 42, 9, 52, 1, 4, 9, 245, 0, 236, 8, 203, 0, 223, 8, 178, 0, 218, 8, 165, 0, 214, 8, 156, 0, 210, 8, 144, 0, 199, 8, 121, 0, 175, 8, 79, 0, 136, 8, 12, 0, 77, 8, 172, 255, 254, 7, 40, 255, 156, 7, 128, 254, 38, 7, 180, 253, 159, 6, 196, 252, 10, 6, 180, 251, 104, 5, 135, 250, 190, 4, 66, 249, 15, 4, 236, 247, 93, 3, 139, 246, 173, 2, 39, 245, 255, 1, 198, 243, 89, 1, 110, 242, 186, 0, 39, 241, 39, 0, 246, 239, 162, 255, 225, 238, 43, 255, 236, 237, 193, 254, 27, 237, 103, 254, 111, 236, 28, 254, 235, 235, 224, 253, 146, 235, 178, 253, 102, 235, 148, 253, 106, 235, 137, 253, 160, 235, 149, 253, 11, 236, 184, 253, 172, 236, 247, 253, 129, 237, 81, 254, 137, 238, 197, 254, 194, 239, 80, 255, 39, 241, 239, 255, 181, 242, 154, 0, 101, 244, 78, 1, 46, 246, 3, 2, 9, 248, 178, 2, 238, 249, 86, 3, 210, 251, 231, 3, 172, 253, 100, 4, 116, 255, 197, 4, 31, 1, 8, 5, 169, 2, 45, 5, 12, 4, 51, 5, 64, 5, 27, 5, 68, 6, 229, 4, 22, 7, 151, 4, 181, 7, 51, 4, 36, 8, 191, 3, 102, 8, 64, 3, 128, 8, 187, 2, 123, 8, 50, 2, 91, 8, 172, 1, 36, 8, 39, 1, 218, 7, 162, 0, 127, 7, 27, 0, 19, 7, 143, 255, 150, 6, 250, 254, 9, 6, 87, 254, 108, 5, 166, 253, 192, 4, 229, 252, 6, 4, 16, 252, 61, 3, 40, 251, 103, 2, 47, 250, 133, 1, 36, 249, 154, 0, 12, 248, 171, 255, 233, 246, 184, 254, 190, 245, 199, 253, 145, 244, 219, 252, 103, 243, 248, 251, 65, 242, 34, 251, 39, 241, 91, 250, 27, 240, 167, 249, 32, 239, 8, 249, 58, 238, 125, 248, 105, 237, 8, 248, 174, 236, 170, 247, 8, 236, 94, 247, 118, 235, 36, 247, 249, 234, 248, 246, 140, 234, 215, 246, 47, 234, 190, 246, 225, 233, 170, 246, 160, 233, 151, 246, 107, 233, 134, 246, 68, 233, 118, 246, 42, 233, 98, 246, 29, 233, 75, 246, 30, 233, 50, 246, 46, 233, 22, 246, 77, 233, 246, 245, 125, 233, 212, 245, 189, 233, 174, 245, 13, 234, 135, 245, 106, 234, 95, 245, 214, 234, 55, 245, 77, 235, 15, 245, 207, 235, 234, 244, 88, 236, 200, 244, 231, 236, 172, 244, 123, 237, 148, 244, 17, 238, 133, 244, 168, 238, 126, 244, 60, 239, 128, 244, 205, 239, 140, 244, 91, 240, 162, 244, 227, 240, 196, 244, 106, 241, 247, 244, 241, 241, 64, 245, 131, 242, 166, 245, 38, 243, 50, 246, 228, 243, 233, 246, 197, 244, 207, 247, 206, 245, 232, 248, 4, 247, 54, 250, 105, 248, 184, 251, 250, 249, 108, 253, 181, 251, 79, 255, 146, 253, 87, 1, 141, 255, 130, 3, 154, 1, 196, 5, 181, 3, 19, 8, 209, 5, 101, 10, 230, 7, 175, 12, 235, 9, 231, 14, 215, 11, 3, 17, 164, 13, 251, 18, 74, 15, 199, 20, 196, 16, 96, 22, 18, 18, 193, 23, 47, 19, 233, 24, 31, 20, 214, 25, 227, 20, 138, 26, 128, 21, 6, 27, 249, 21, 79, 27, 84, 22, 103, 27, 146, 22, 83, 27, 184, 22, 20, 27, 197, 22, 170, 26, 185, 22, 24, 26, 148, 22, 94, 25, 84, 22, 128, 24, 251, 21, 128, 23, 135, 21, 94, 22, 248, 20, 31, 21, 79, 20, 197, 19, 145, 19, 87, 18, 194, 18, 219, 16, 228, 17, 84, 15, 253, 16, 201, 13, 18, 16, 64, 12, 40, 15, 190, 10, 65, 14, 73, 9, 101, 13, 230, 7, 151, 12, 154, 6, 218, 11, 106, 5, 48, 11, 86, 4, 156, 10, 100, 3, 32, 10, 147, 2, 186, 9, 227, 1, 106, 9, 84, 1, 46, 9, 226, 0, 3, 9, 137, 0, 229, 8, 71, 0, 210, 8, 21, 0, 198, 8, 243, 255, 189, 8, 213, 255, 179, 8, 179, 255, 165, 8, 140, 255, 139, 8, 84, 255, 103, 8, 10, 255, 52, 8, 166, 254, 242, 7, 40, 254, 161, 7, 139, 253, 65, 7, 208, 252, 211, 6, 248, 251, 90, 6, 5, 251, 213, 5, 249, 249, 70, 5, 217, 248, 177, 4, 170, 247, 22, 4, 111, 246, 121, 3, 48, 245, 220, 2, 242, 243, 63, 2, 186, 242, 167, 1, 143, 241, 21, 1, 117, 240, 138, 0, 113, 239, 10, 0, 134, 238, 150, 255, 185, 237, 43, 255, 12, 237, 203, 254, 131, 236, 121, 254, 31, 236, 53, 254, 231, 235, 2, 254, 220, 235, 228, 253, 3, 236, 222, 253, 94, 236, 242, 253, 237, 236, 34, 254, 174, 237, 108, 254, 161, 238, 208, 254, 194, 239, 73, 255, 14, 241, 212, 255, 128, 242, 106, 0, 20, 244, 10, 1, 193, 245, 171, 1, 129, 247, 72, 2, 76, 249, 221, 2, 25, 251, 98, 3, 225, 252, 215, 3, 155, 254, 53, 4, 63, 0, 123, 4, 200, 1, 167, 4, 48, 3, 185, 4, 113, 4, 175, 4, 137, 5, 141, 4, 117, 6, 85, 4, 56, 7, 10, 4, 209, 7, 177, 3, 69, 8, 75, 3, 152, 8, 222, 2, 205, 8, 107, 2, 232, 8, 245, 1, 233, 8, 123, 1, 209, 8, 251, 0, 160, 8, 115, 0, 87, 8, 226, 255, 246, 7, 67, 255, 124, 7, 148, 254, 235, 6, 211, 253, 66, 6, 0, 253, 131, 5, 25, 252, 177, 4, 32, 251, 203, 3, 22, 250, 215, 2, 253, 248, 215, 1, 216, 247, 206, 0, 171, 246, 195, 255, 121, 245, 182, 254, 71, 244, 174, 253, 25, 243, 174, 252, 245, 241, 186, 251, 219, 240, 214, 250, 210, 239, 5, 250, 219, 238, 72, 249, 249, 237, 162, 248, 44, 237, 16, 248, 116, 236, 148, 247, 211, 235, 42, 247, 69, 235, 211, 246, 204, 234, 139, 246, 100, 234, 80, 246, 13, 234, 34, 246, 199, 233, 251, 245, 143, 233, 219, 245, 101, 233, 193, 245, 73, 233, 170, 245, 59, 233, 152, 245, 61, 233, 136, 245, 76, 233, 122, 245, 108, 233, 110, 245, 153, 233, 99, 245, 214, 233, 88, 245, 32, 234, 78, 245, 119, 234, 66, 245, 219, 234, 55, 245, 72, 235, 45, 245, 191, 235, 34, 245, 62, 236, 25, 245, 194, 236, 17, 245, 72, 237, 9, 245, 209, 237, 6, 245, 90, 238, 5, 245, 227, 238, 7, 245, 106, 239, 16, 245, 237, 239, 29, 245, 110, 240, 48, 245, 236, 240, 77, 245, 107, 241, 120, 245, 242, 241, 186, 245, 135, 242, 26, 246, 52, 243, 157, 246, 253, 243, 73, 247, 234, 244, 35, 248, 0, 246, 44, 249, 61, 247, 104, 250, 165, 248, 212, 251, 50, 250, 110, 253, 229, 251, 53, 255, 182, 253, 32, 1, 159, 255, 43, 3, 151, 1, 77, 5, 155, 3, 126, 7, 160, 5, 181, 9, 156, 7, 232, 11, 140, 9, 13, 14, 102, 11, 30, 16, 36, 13, 17, 18, 191, 14, 221, 19, 53, 16, 127, 21, 131, 17, 243, 22, 168, 18, 53, 24, 164, 19, 68, 25, 121, 20, 33, 26, 43, 21, 204, 26, 187, 21, 71, 27, 45, 22, 147, 27, 132, 22, 176, 27, 191, 22, 158, 27, 222, 22, 94, 27, 225, 22, 239, 26, 199, 22, 79, 26, 142, 22, 133, 25, 54, 22, 146, 24, 195, 21, 122, 23, 54, 21, 63, 22, 144, 20, 232, 20, 212, 19, 121, 19, 6, 19, 245, 17, 43, 18, 101, 16, 70, 17, 205, 14, 91, 16, 52, 13, 113, 15, 160, 11, 139, 14, 23, 10, 174, 13, 157, 8, 222, 12, 58, 7, 29, 12, 238, 5, 111, 11, 192, 4, 214, 10, 177, 3, 82, 10, 193, 2, 228, 9, 241, 1, 137, 9, 63, 1, 65, 9, 170, 0, 10, 9, 47, 0, 225, 8, 204, 255, 195, 8, 123, 255, 173, 8, 55, 255, 157, 8, 251, 254, 139, 8, 194, 254, 120, 8, 133, 254, 95, 8, 62, 254, 63, 8, 234, 253, 22, 8, 131, 253, 226, 7, 8, 253, 163, 7, 117, 252, 88, 7, 204, 251, 0, 7, 11, 251, 156, 6, 53, 250, 47, 6, 74, 249, 181, 5, 78, 248, 53, 5, 68, 247, 172, 4, 49, 246, 30, 4, 24, 245, 141, 3, 255, 243, 249, 2, 235, 242, 102, 2, 221, 241, 213, 1, 221, 240, 71, 1, 239, 239, 193, 0, 20, 239, 65, 0, 81, 238, 204, 255, 169, 237, 94, 255, 33, 237, 252, 254, 187, 236, 168, 254, 125, 236, 102, 254, 107, 236, 57, 254, 135, 236, 38, 254, 212, 236, 43, 254, 82, 237, 75, 254, 0, 238, 132, 254, 220, 238, 213, 254, 227, 239, 58, 255, 19, 241, 176, 255, 104, 242, 50, 0, 221, 243, 187, 0, 107, 245, 74, 1, 12, 247, 214, 1, 187, 248, 93, 2, 111, 250, 217, 2, 32, 252, 71, 3, 200, 253, 164, 3, 98, 255, 238, 3, 227, 0, 34, 4, 75, 2, 63, 4, 149, 3, 70, 4, 189, 4, 56, 4, 196, 5, 21, 4, 170, 6, 226, 3, 110, 7, 160, 3, 20, 8, 82, 3, 157, 8, 250, 2, 10, 9, 154, 2, 92, 9, 53, 2, 145, 9, 197, 1, 168, 9, 75, 1, 159, 9, 196, 0, 120, 9, 49, 0, 49, 9, 140, 255, 203, 8, 212, 254, 70, 8, 8, 254, 165, 7, 42, 253, 232, 6, 55, 252, 19, 6, 51, 251, 40, 5, 31, 250, 41, 4, 253, 248, 28, 3, 210, 247, 4, 2, 161, 246, 231, 0, 110, 245, 201, 255, 59, 244, 172, 254, 13, 243, 149, 253, 233, 241, 138, 252, 210, 240, 140, 251, 204, 239, 160, 250, 216, 238, 200, 249, 250, 237, 2, 249, 48, 237, 81, 248, 124, 236, 180, 247, 223, 235, 43, 247, 87, 235, 179, 246, 226, 234, 76, 246, 127, 234, 246, 245, 45, 234, 173, 245, 236, 233, 113, 245, 187, 233, 65, 245, 154, 233, 27, 245, 136, 233, 254, 244, 134, 233, 234, 244, 148, 233, 222, 244, 176, 233, 216, 244, 218, 233, 216, 244, 19, 234, 221, 244, 88, 234, 230, 244, 170, 234, 242, 244, 7, 235, 255, 244, 107, 235, 12, 245, 216, 235, 27, 245, 74, 236, 41, 245, 194, 236, 55, 245, 60, 237, 69, 245, 184, 237, 83, 245, 53, 238, 95, 245, 178, 238, 109, 245, 45, 239, 123, 245, 166, 239, 137, 245, 29, 240, 153, 245, 146, 240, 171, 245, 7, 241, 197, 245, 129, 241, 237, 245, 7, 242, 42, 246, 157, 242, 131, 246, 77, 243, 251, 246, 27, 244, 155, 247, 9, 245, 102, 248, 29, 246, 93, 249, 87, 247, 130, 250, 181, 248, 212, 251, 54, 250, 81, 253, 215, 251, 247, 254, 147, 253, 193, 0, 102, 255, 169, 2, 70, 1, 170, 4, 49, 3, 186, 6, 31, 5, 212, 8, 6, 7, 237, 10, 227, 8, 254, 12, 175, 10, 0, 15, 97, 12, 233, 16, 248, 13, 182, 18, 109, 15, 98, 20, 191, 16, 231, 21, 238, 17, 66, 23, 248, 18, 114, 24, 223, 19, 119, 25, 165, 20, 77, 26, 76, 21, 246, 26, 212, 21, 112, 27, 63, 22, 184, 27, 139, 22, 206, 27, 183, 22, 177, 27, 198, 22, 98, 27, 181, 22, 225, 26, 132, 22, 47, 26, 53, 22, 81, 25, 201, 21, 74, 24, 65, 21, 28, 23, 160, 20, 206, 21, 234, 19, 100, 20, 34, 19, 229, 18, 77, 18, 84, 17, 109, 17, 186, 15, 137, 16, 28, 14, 164, 15, 127, 12, 195, 14, 235, 10, 232, 13, 99, 9, 25, 13, 239, 7, 89, 12, 145, 6, 169, 11, 77, 5, 13, 11, 37, 4, 132, 10, 25, 3, 14, 10, 41, 2, 171, 9, 86, 1, 90, 9, 158, 0, 24, 9, 1, 0, 229, 8, 123, 255, 189, 8, 9, 255, 158, 8, 165, 254, 133, 8, 78, 254, 114, 8, 252, 253, 95, 8, 170, 253, 74, 8, 85, 253, 50, 8, 248, 252, 19, 8, 143, 252, 238, 7, 24, 252, 190, 7, 145, 251, 133, 7, 249, 250, 65, 7, 80, 250, 242, 6, 149, 249, 152, 6, 201, 248, 51, 6, 240, 247, 195, 5, 11, 247, 76, 5, 29, 246, 203, 4, 42, 245, 68, 4, 51, 244, 185, 3, 63, 243, 44, 3, 80, 242, 156, 2, 105, 241, 14, 2, 143, 240, 131, 1, 196, 239, 251, 0, 12, 239, 123, 0, 107, 238, 1, 0, 229, 237, 148, 255, 125, 237, 52, 255, 59, 237, 228, 254, 33, 237, 169, 254, 48, 237, 134, 254, 109, 237, 121, 254, 215, 237, 133, 254, 109, 238, 168, 254, 47, 239, 225, 254, 25, 240, 45, 255, 42, 241, 138, 255, 92, 242, 244, 255, 174, 243, 101, 0, 23, 245, 221, 0, 149, 246, 87, 1, 33, 248, 206, 1, 183, 249, 63, 2, 77, 251, 166, 2, 222, 252, 1, 3, 102, 254, 77, 3, 223, 255, 136, 3, 67, 1, 176, 3, 149, 2, 198, 3, 206, 3, 202, 3, 239, 4, 189, 3, 247, 5, 160, 3, 229, 6, 118, 3, 185, 7, 63, 3, 116, 8, 254, 2, 19, 9, 178, 2, 148, 9, 92, 2, 246, 9, 249, 1, 55, 10, 136, 1, 85, 10, 6, 1, 77, 10, 114, 0, 34, 10, 203, 255, 210, 9, 15, 255, 96, 9, 62, 254, 203, 8, 88, 253, 24, 8, 94, 252, 72, 7, 84, 251, 94, 6, 60, 250, 95, 5, 21, 249, 78, 4, 229, 247, 48, 3, 177, 246, 10, 2, 124, 245, 222, 0, 73, 244, 180, 255, 30, 243, 142, 254, 252, 241, 111, 253, 232, 240, 93, 252, 228, 239, 87, 251, 243, 238, 99, 250, 23, 238, 127, 249, 79, 237, 173, 248, 157, 236, 238, 247, 254, 235, 65, 247, 117, 235, 169, 246, 254, 234, 34, 246, 154, 234, 173, 245, 73, 234, 73, 245, 10, 234, 246, 244, 221, 233, 178, 244, 192, 233, 126, 244, 181, 233, 87, 244, 186, 233, 60, 244, 206, 233, 48, 244, 242, 233, 46, 244, 37, 234, 53, 244, 99, 234, 70, 244, 174, 234, 92, 244, 1, 235, 121, 244, 93, 235, 153, 244, 193, 235, 187, 244, 42, 236, 223, 244, 151, 236, 4, 245, 8, 237, 39, 245, 123, 237, 74, 245, 239, 237, 109, 245, 98, 238, 140, 245, 213, 238, 169, 245, 71, 239, 195, 245, 182, 239, 218, 245, 37, 240, 240, 245, 148, 240, 7, 246, 5, 241, 38, 246, 127, 241, 81, 246, 7, 242, 144, 246, 163, 242, 233, 246, 86, 243, 97, 247, 39, 244, 251, 247, 23, 245, 190, 248, 40, 246, 168, 249, 92, 247, 187, 250, 177, 248, 248, 251, 37, 250, 93, 253, 182, 251, 231, 254, 96, 253, 144, 0, 29, 255, 87, 2, 232, 0, 54, 4, 189, 2, 38, 6, 150, 4, 31, 8, 106, 6, 27, 10, 54, 8, 19, 12, 243, 9, 0, 14, 156, 11, 222, 15, 45, 13, 166, 17, 161, 14, 84, 19, 248, 15, 228, 20, 46, 17, 82, 22, 70, 18, 155, 23, 61, 19, 190, 24, 22, 20, 184, 25, 210, 20, 135, 26, 112, 21, 40, 27, 240, 21, 152, 27, 81, 22, 215, 27, 147, 22, 225, 27, 179, 22, 182, 27, 179, 22, 87, 27, 147, 22, 199, 26, 83, 22, 6, 26, 245, 21, 24, 25, 123, 21, 3, 24, 231, 20, 201, 22, 61, 20, 110, 21, 128, 19, 250, 19, 178, 18, 112, 18, 216, 17, 218, 16, 249, 16, 60, 15, 24, 16, 157, 13, 57, 15, 2, 12, 95, 14, 113, 10, 143, 13, 238, 8, 203, 12, 126, 7, 22, 12, 33, 6, 114, 11, 220, 4, 223, 10, 176, 3, 94, 10, 157, 2, 239, 9, 164, 1, 144, 9, 198, 0, 65, 9, 0, 0, 1, 9, 85, 255, 207, 8, 187, 254, 168, 8, 51, 254, 137, 8, 185, 253, 112, 8, 71, 253, 92, 8, 220, 252, 72, 8, 114, 252, 52, 8, 5, 252, 27, 8, 146, 251, 252, 7, 24, 251, 215, 7, 149, 250, 169, 7, 5, 250, 113, 7, 106, 249, 46, 7, 195, 248, 224, 6, 16, 248, 135, 6, 82, 247, 35, 6, 139, 246, 181, 5, 189, 245, 62, 5, 234, 244, 191, 4, 20, 244, 59, 4, 63, 243, 177, 3, 109, 242, 37, 3, 161, 241, 151, 2, 223, 240, 10, 2, 40, 240, 128, 1, 130, 239, 250, 0, 238, 238, 122, 0, 114, 238, 5, 0, 17, 238, 159, 255, 209, 237, 71, 255, 182, 237, 2, 255, 192, 237, 210, 254, 244, 237, 183, 254, 80, 238, 177, 254, 213, 238, 194, 254, 129, 239, 231, 254, 83, 240, 31, 255, 72, 241, 102, 255, 93, 242, 187, 255, 143, 243, 26, 0, 217, 244, 128, 0, 54, 246, 235, 0, 163, 247, 85, 1, 26, 249, 189, 1, 149, 250, 30, 2, 18, 252, 119, 2, 137, 253, 198, 2, 249, 254, 6, 3, 93, 0, 56, 3, 181, 1, 91, 3, 254, 2, 110, 3, 53, 4, 113, 3, 90, 5, 103, 3, 105, 6, 81, 3, 99, 7, 46, 3, 69, 8, 255, 2, 11, 9, 197, 2, 180, 9, 123, 2, 59, 10, 34, 2, 158, 10, 183, 1, 219, 10, 56, 1, 241, 10, 165, 0, 223, 10, 253, 255, 165, 10, 63, 255, 70, 10, 107, 254, 195, 9, 128, 253, 30, 9, 131, 252, 91, 8, 117, 251, 122, 7, 88, 250, 129, 6, 47, 249, 115, 5, 254, 247, 86, 4, 201, 246, 45, 3, 148, 245, 252, 1, 97, 244, 202, 0, 55, 243, 154, 255, 22, 242, 109, 254, 2, 241, 72, 253, 255, 239, 44, 252, 14, 239, 30, 251, 47, 238, 29, 250, 101, 237, 45, 249, 175, 236, 79, 248, 14, 236, 129, 247, 129, 235, 200, 246, 8, 235, 33, 246, 163, 234, 142, 245, 81, 234, 15, 245, 18, 234, 162, 244, 232, 233, 74, 244, 209, 233, 4, 244, 204, 233, 208, 243, 215, 233, 172, 243, 241, 233, 151, 243, 25, 234, 145, 243, 79, 234, 151, 243, 143, 234, 169, 243, 217, 234, 197, 243, 45, 235, 233, 243, 135, 235, 19, 244, 231, 235, 65, 244, 76, 236, 115, 244, 180, 236, 165, 244, 30, 237, 216, 244, 137, 237, 11, 245, 246, 237, 59, 245, 98, 238, 104, 245, 205, 238, 145, 245, 56, 239, 181, 245, 161, 239, 211, 245, 10, 240, 240, 245, 116, 240, 15, 246, 228, 240, 52, 246, 94, 241, 102, 246, 230, 241, 170, 246, 131, 242, 5, 247, 54, 243, 126, 247, 5, 244, 22, 248, 242, 244, 211, 248, 252, 245, 181, 249, 38, 247, 188, 250, 111, 248, 232, 251, 214, 249, 57, 253, 87, 251, 172, 254, 238, 252, 61, 0, 155, 254, 234, 1, 83, 0, 173, 3, 22, 2, 129, 5, 223, 3, 96, 7, 165, 5, 68, 9, 100, 7, 40, 11, 23, 9, 8, 13, 186, 10, 221, 14, 73, 12, 162, 16, 192, 13, 84, 18, 28, 15, 238, 19, 94, 16, 108, 21, 130, 17, 202, 22, 138, 18, 7, 24, 119, 19, 30, 25, 69, 20, 12, 26, 246, 20, 205, 26, 138, 21, 93, 27, 252, 21, 187, 27, 78, 22, 228, 27, 128, 22, 216, 27, 143, 22, 151, 27, 126, 22, 35, 27, 76, 22, 126, 26, 251, 21, 167, 25, 139, 21, 165, 24, 1, 21, 128, 23, 98, 20, 57, 22, 174, 19, 214, 20, 236, 18, 94, 19, 30, 18, 213, 17, 74, 17, 65, 16, 113, 16, 170, 14, 154, 15, 18, 13, 198, 14, 127, 11, 249, 13, 244, 9, 55, 13, 119, 8, 129, 12, 10, 7, 217, 11, 173, 5, 64, 11, 103, 4, 184, 10, 54, 3, 64, 10, 27, 2, 215, 9, 27, 1, 127, 9, 49, 0, 52, 9, 97, 255, 248, 8, 164, 254, 200, 8, 249, 253, 163, 8, 93, 253, 134, 8, 206, 252, 111, 8, 73, 252, 91, 8, 201, 251, 72, 8, 75, 251, 51, 8, 207, 250, 27, 8, 80, 250, 252, 7, 204, 249, 215, 7, 67, 249, 170, 7, 179, 248, 114, 7, 27, 248, 49, 7, 125, 247, 228, 6, 215, 246, 141, 6, 43, 246, 43, 6, 122, 245, 191, 5, 198, 244, 75, 5, 15, 244, 208, 4, 88, 243, 78, 4, 163, 242, 200, 3, 244, 241, 63, 3, 75, 241, 181, 2, 170, 240, 44, 2, 21, 240, 165, 1, 146, 239, 36, 1, 35, 239, 172, 0, 205, 238, 63, 0, 147, 238, 225, 255, 120, 238, 146, 255, 127, 238, 85, 255, 170, 238, 42, 255, 249, 238, 19, 255, 109, 239, 14, 255, 2, 240, 29, 255, 185, 240, 60, 255, 144, 241, 107, 255, 131, 242, 168, 255, 145, 243, 240, 255, 181, 244, 62, 0, 237, 245, 149, 0, 51, 247, 238, 0, 134, 248, 71, 1, 226, 249, 157, 1, 66, 251, 238, 1, 165, 252, 56, 2, 7, 254, 120, 2, 102, 255, 174, 2, 188, 0, 216, 2, 12, 2, 245, 2, 82, 3, 6, 3, 138, 4, 13, 3, 180, 5, 7, 3, 203, 6, 246, 2, 204, 7, 218, 2, 180, 8, 175, 2, 126, 9, 117, 2, 41, 10, 43, 2, 176, 10, 205, 1, 19, 11, 92, 1, 78, 11, 215, 0, 104, 11, 65, 0, 104, 11, 165, 255, 84, 11, 8, 255, 65, 11, 121, 254, 129, 11, 80, 254, 155, 12, 19, 255, 131, 14, 176, 0, 26, 17, 14, 3, 5, 20, 207, 5, 112, 22, 32, 8, 66, 24, 229, 9, 22, 25, 186, 10, 163, 24, 86, 10, 7, 23, 214, 8, 91, 20, 79, 6, 251, 16, 34, 3, 56, 13, 158, 255, 116, 9, 32, 252, 243, 5, 237, 248, 234, 2, 57, 246, 119, 0, 29, 244, 154, 254, 154, 242, 66, 253, 162, 241, 85, 252, 21, 241, 181, 251, 217, 240, 63, 251, 205, 240, 219, 250, 217, 240, 115, 250, 251, 240, 233, 249, 55, 241, 21, 249, 105, 241, 209, 247, 96, 241, 15, 246, 251, 240, 213, 243, 6, 240, 66, 241, 140, 238, 131, 238, 163, 236, 202, 235, 100, 234, 79, 233, 11, 232, 61, 231, 202, 229, 185, 229, 218, 227, 211, 228, 100, 226, 143, 228, 135, 225, 224, 228, 75, 225, 174, 229, 168, 225, 215, 230, 135, 226, 62, 232, 203, 227, 203, 233, 93, 229, 129, 235, 53, 231, 107, 237, 88, 233, 131, 239, 185, 235, 183, 241, 57, 238, 229, 243, 178, 240, 226, 245, 242, 242, 140, 247, 199, 244, 198, 248, 12, 246, 134, 249, 175, 246, 210, 249, 182, 246, 194, 249, 63, 246, 119, 249, 124, 245, 26, 249, 162, 244, 210, 248, 237, 243, 191, 248, 167, 243, 246, 248, 14, 244, 129, 249, 42, 245, 96, 250, 241, 246, 129, 251, 45, 249, 191, 252, 124, 251, 222, 253, 146, 253, 171, 254, 20, 255, 14, 255, 213, 255, 11, 255, 221, 255, 190, 254, 87, 255, 82, 254, 136, 254, 246, 253, 180, 253, 211, 253, 20, 253, 4, 254, 207, 252, 148, 254, 240, 252, 124, 255, 112, 253, 166, 0, 53, 254, 244, 1, 31, 255, 69, 3, 9, 0, 120, 4, 210, 0, 114, 5, 104, 1, 35, 6, 189, 1, 129, 6, 202, 1, 142, 6, 147, 1, 85, 6, 23, 1, 226, 5, 94, 0, 69, 5, 117, 255, 144, 4, 99, 254, 204, 3, 49, 253, 5, 3, 234, 251, 66, 2, 153, 250, 136, 1, 80, 249, 214, 0, 35, 248, 45, 0, 38, 247, 142, 255, 103, 246, 245, 254, 242, 245, 101, 254, 203, 245, 231, 253, 245, 245, 130, 253, 105, 246, 81, 253, 36, 247, 145, 253, 48, 248, 129, 254, 193, 249, 100, 0, 29, 252, 86, 3, 96, 255, 42, 7, 128, 3, 197, 11, 70, 8, 220, 16, 86, 13, 236, 21, 74, 18, 142, 26, 187, 22, 71, 30, 88, 26, 196, 32, 238, 28, 248, 33, 106, 30, 214, 33, 217, 30, 137, 32, 97, 30, 83, 30, 59, 29, 128, 27, 161, 27, 98, 24, 210, 25, 65, 21, 254, 23, 87, 18, 77, 22, 197, 15, 210, 20, 147, 13, 129, 19, 156, 11, 45, 18, 180, 9, 168, 16, 180, 7, 221, 14, 133, 5, 215, 12, 33, 3, 200, 10, 151, 0, 231, 8, 7, 254, 107, 7, 137, 251, 118, 6, 58, 249, 17, 6, 36, 247, 48, 6, 77, 245, 176, 6, 183, 243, 101, 7, 92, 242, 32, 8, 59, 241, 181, 8, 75, 240, 4, 9, 138, 239, 253, 8, 250, 238, 156, 8, 152, 238, 236, 7, 96, 238, 247, 6, 57, 238, 191, 5, 5, 238, 58, 4, 176, 237, 99, 2, 49, 237, 64, 0, 136, 236, 222, 253, 199, 235, 79, 251, 6, 235, 179, 248, 105, 234, 54, 246, 16, 234, 0, 244, 19, 234, 57, 242, 126, 234, 254, 240, 81, 235, 98, 240, 132, 236, 103, 240, 9, 238, 3, 241, 204, 239, 33, 242, 183, 241, 162, 243, 186, 243, 114, 245, 212, 245, 149, 247, 22, 248, 25, 250, 136, 250, 249, 252, 25, 253, 24, 0, 164, 255, 69, 3, 243, 1, 60, 6, 212, 3, 180, 8, 28, 5, 105, 10, 173, 5, 45, 11, 123, 5, 234, 10, 142, 4, 173, 9, 3, 3, 154, 7, 4, 1, 231, 4, 198, 254, 213, 1, 120, 252, 166, 254, 67, 250, 142, 251, 69, 248, 184, 248, 141, 246, 64, 246, 24, 245, 42, 244, 211, 243, 97, 242, 140, 242, 173, 240, 11, 241, 210, 238, 44, 239, 167, 236, 222, 236, 39, 234, 52, 234, 107, 231, 80, 231, 160, 228, 99, 228, 253, 225, 160, 225, 176, 223, 50, 223, 213, 221, 57, 221, 123, 220, 197, 219, 160, 219, 212, 218, 43, 219, 84, 218, 251, 218, 46, 218, 246, 218, 73, 218, 251, 218, 136, 218, 248, 218, 218, 218, 224, 218, 48, 219, 173, 218, 132, 219, 93, 218, 216, 219, 241, 217, 60, 220, 113, 217, 203, 220, 227, 216, 162, 221, 86, 216, 214, 222, 212, 215, 112, 224, 100, 215, 123, 226, 16, 215, 241, 228, 219, 214, 190, 231, 202, 214, 198, 234, 237, 214, 226, 237, 72, 215, 232, 240, 228, 215, 179, 243, 194, 216, 37, 246, 223, 217, 49, 248, 57, 219, 214, 249, 200, 220, 34, 251, 143, 222, 75, 252, 171, 224, 163, 253, 84, 227, 121, 255, 182, 230, 251, 1, 217, 234, 45, 5, 163, 239, 227, 8, 212, 244, 216, 12, 28, 250, 189, 16, 38, 255, 64, 20, 162, 3, 34, 23, 93, 7, 55, 25, 55, 10, 120, 26, 45, 12, 243, 26, 84, 13, 208, 26, 210, 13, 68, 26, 217, 13, 133, 25, 157, 13, 199, 24, 75, 13, 51, 24, 16, 13, 228, 23, 3, 13, 227, 23, 39, 13, 27, 24, 99, 13, 95, 24, 142, 13, 144, 24, 143, 13, 149, 24, 96, 13, 102, 24, 27, 13, 9, 24, 236, 12, 143, 23, 255, 12, 14, 23, 122, 13, 147, 22, 106, 14, 44, 22, 206, 15, 223, 21, 140, 17, 172, 21, 126, 19, 144, 21, 118, 21, 133, 21, 72, 23, 129, 21, 205, 24, 127, 21, 231, 25, 116, 21, 136, 26, 92, 21, 175, 26, 48, 21, 101, 26, 223, 20, 172, 25, 72, 20, 127, 24, 85, 19, 220, 22, 250, 17, 197, 20, 57, 16, 73, 18, 32, 14, 122, 15, 204, 11, 117, 12, 98, 9, 94, 9, 255, 6, 93, 6, 190, 4, 157, 3, 177, 2, 65, 1, 225, 0, 104, 255, 80, 255, 29, 254, 251, 253, 101, 253, 220, 252, 59, 253, 237, 251, 144, 253, 37, 251, 86, 254, 136, 250, 139, 255, 38, 250, 52, 1, 15, 250, 84, 3, 70, 250, 210, 5, 182, 250, 133, 8, 59, 251, 53, 11, 165, 251, 164, 13, 198, 251, 149, 15, 117, 251, 215, 16, 151, 250, 74, 17, 39, 249, 236, 16, 54, 247, 205, 15, 233, 244, 21, 14, 107, 242, 246, 11, 236, 239, 166, 9, 150, 237, 89, 7, 137, 235, 57, 5, 216, 233, 101, 3, 135, 232, 233, 1, 138, 231, 187, 0, 190, 230, 187, 255, 240, 229, 180, 254, 239, 228, 123, 253, 161, 227, 253, 251, 0, 226, 61, 250, 31, 224, 87, 248, 26, 222, 113, 246, 28, 220, 178, 244, 78, 218, 57, 243, 208, 216, 21, 242, 183, 215, 75, 241, 13, 215, 206, 240, 207, 214, 143, 240, 240, 214, 115, 240, 93, 215, 102, 240, 2, 216, 82, 240, 201, 216, 43, 240, 167, 217, 235, 239, 148, 218, 142, 239, 139, 219, 17, 239, 134, 220, 120, 238, 149, 221, 205, 237, 204, 222, 32, 237, 69, 224, 126, 236, 25, 226, 241, 235, 93, 228, 126, 235, 25, 231, 43, 235, 69, 234, 254, 234, 198, 237, 251, 234, 119, 241, 41, 235, 46, 245, 136, 235, 192, 248, 30, 236, 11, 252, 232, 236, 250, 254, 224, 237, 131, 1, 5, 239, 174, 3, 87, 240, 150, 5, 228, 241, 122, 7, 208, 243, 165, 9, 73, 246, 77, 12, 96, 249, 137, 15, 9, 253, 71, 19, 26, 1, 85, 23, 84, 5, 105, 27, 108, 9, 48, 31, 24, 13, 96, 34, 27, 16, 193, 36, 74, 18, 55, 38, 145, 19, 192, 38, 243, 19, 117, 38, 134, 19, 125, 37, 111, 18, 7, 36, 216, 16, 65, 34, 238, 14, 91, 32, 222, 12, 115, 30, 198, 10, 159, 28, 185, 8, 223, 26, 181, 6, 24, 25, 166, 4, 53, 23, 126, 2, 32, 21, 54, 0, 216, 18, 225, 253, 100, 16, 160, 251, 209, 13, 160, 249, 51, 11, 9, 248, 152, 8, 245, 246, 18, 6, 107, 246, 172, 3, 95, 246, 114, 1, 187, 246, 107, 255, 89, 247, 154, 253, 16, 248, 255, 251, 189, 248, 154, 250, 65, 249, 104, 249, 133, 249, 100, 248, 130, 249, 140, 247, 54, 249, 212, 246, 167, 248, 37, 246, 209, 247, 99, 245, 171, 246, 117, 244, 53, 245, 87, 243, 116, 243, 18, 242, 117, 241, 186, 240, 77, 239, 102, 239, 20, 237, 46, 238, 232, 234, 35, 237, 236, 232, 79, 236, 63, 231, 183, 235, 252, 229, 91, 235, 53, 229, 57, 235, 245, 228, 74, 235, 57, 229, 136, 235, 250, 229, 236, 235, 49, 231, 114, 236, 218, 232, 40, 237, 246, 234, 26, 238, 127, 237, 78, 239, 99, 240, 192, 240, 131, 243, 86, 242, 174, 246, 237, 243, 177, 249, 88, 245, 87, 252, 106, 246, 114, 254, 1, 247, 226, 255, 16, 247, 153, 0, 156, 246, 164, 0, 192, 245, 26, 0, 166, 244, 41, 255, 120, 243, 251, 253, 100, 242, 195, 252, 142, 241, 174, 251, 15, 241, 219, 250, 247, 240, 93, 250, 66, 241, 55, 250, 221, 241, 88, 250, 160, 242, 155, 250, 91, 243, 218, 250, 236, 243, 250, 250, 62, 244, 237, 250, 81, 244, 191, 250, 55, 244, 133, 250, 8, 244, 91, 250, 228, 243, 92, 250, 232, 243, 150, 250, 39, 244, 15, 251, 174, 244, 192, 251, 124, 245, 154, 252, 136, 246, 138, 253, 192, 247, 118, 254, 13, 249, 76, 255, 93, 250, 250, 255, 153, 251, 112, 0, 177, 252, 168, 0, 157, 253, 156, 0, 88, 254, 77, 0, 229, 254, 199, 255, 79, 255, 19, 255, 174, 255, 70, 254, 32, 0, 109, 253, 202, 0, 148, 252, 193, 1, 194, 251, 8, 3, 255, 250, 147, 4, 83, 250, 70, 6, 195, 249, 253, 7, 88, 249, 148, 9, 21, 249, 230, 10, 253, 248, 224, 11, 17, 249, 114, 12, 84, 249, 160, 12, 202, 249, 122, 12, 122, 250, 47, 12, 125, 251, 7, 12, 252, 252, 68, 12, 19, 255, 17, 13, 200, 1, 122, 14, 7, 5, 105, 16, 163, 8, 171, 18, 95, 12, 247, 20, 250, 15, 5, 23, 54, 19, 153, 24, 226, 21, 139, 25, 222, 23, 204, 25, 29, 25, 98, 25, 163, 25, 103, 24, 133, 25, 253, 22, 225, 24, 78, 21, 219, 23, 125, 19, 152, 22, 175, 17, 53, 21, 250, 15, 200, 19, 103, 14, 89, 18, 232, 12, 225, 16, 103, 11, 81, 15, 205, 9, 160, 13, 16, 8, 213, 11, 50, 6, 8, 10, 62, 4, 94, 8, 60, 2, 250, 6, 56, 0, 253, 5, 63, 254, 118, 5, 89, 252, 100, 5, 150, 250, 183, 5, 253, 248, 84, 6, 152, 247, 25, 7, 106, 246, 225, 7, 115, 245, 142, 8, 181, 244, 6, 9, 43, 244, 55, 9, 211, 243, 30, 9, 164, 243, 187, 8, 143, 243, 13, 8, 120, 243, 13, 7, 67, 243, 184, 5, 228, 242, 18, 4, 93, 242, 37, 2, 190, 241, 3, 0, 26, 241, 193, 253, 137, 240, 121, 251, 24, 240, 74, 249, 215, 239, 86, 247, 202, 239, 183, 245, 246, 239, 133, 244, 90, 240, 208, 243, 242, 240, 158, 243, 189, 241, 237, 243, 179, 242, 193, 244, 211, 243, 18, 246, 32, 245, 220, 247, 171, 246, 25, 250, 124, 248, 186, 252, 141, 250, 159, 255, 206, 252, 152, 2, 28, 255, 115, 5, 70, 1, 248, 7, 27, 3, 244, 9, 104, 4, 60, 11, 16, 5, 184, 11, 9, 5, 99, 11, 93, 4, 74, 10, 42, 3, 141, 8, 151, 1, 85, 6, 209, 255, 208, 3, 0, 254, 46, 1, 70, 252, 155, 254, 187, 250, 46, 252, 107, 249, 248, 249, 78, 248, 250, 247, 80, 247, 37, 246, 71, 246, 93, 244, 17, 245, 136, 242, 153, 243, 153, 240, 216, 241, 150, 238, 219, 239, 146, 236, 182, 237, 165, 234, 139, 235, 235, 232, 120, 233, 117, 231, 154, 231, 78, 230, 3, 230, 120, 229, 193, 228, 232, 228, 214, 227, 144, 228, 57, 227, 93, 228, 224, 226, 59, 228, 187, 226, 25, 228, 185, 226, 232, 227, 206, 226, 156, 227, 241, 226, 49, 227, 27, 227, 164, 226, 68, 227, 246, 225, 118, 227, 57, 225, 186, 227, 121, 224, 47, 228, 199, 223, 247, 228, 47, 223, 42, 230, 185, 222, 213, 231, 102, 222, 238, 233, 59, 222, 94, 236, 61, 222, 2, 239, 109, 222, 179, 241, 203, 222, 73, 244, 88, 223, 164, 246, 21, 224, 172, 248, 3, 225, 86, 250, 35, 226, 164, 251, 119, 227, 178, 252, 11, 229, 186, 253, 254, 230, 252, 254, 114, 233, 169, 0, 115, 236, 221, 2, 251, 239, 149, 5, 233, 243, 174, 8, 15, 248, 238, 11, 54, 252, 21, 15, 33, 0, 229, 17, 163, 3, 50, 20, 153, 6, 231, 21, 237, 8, 254, 22, 154, 10, 134, 23, 173, 11, 153, 23, 61, 12, 91, 23, 103, 12, 238, 22, 76, 12, 118, 22, 7, 12, 15, 22, 177, 11, 200, 21, 88, 11, 161, 21, 3, 11, 135, 21, 166, 10, 101, 21, 58, 10, 44, 21, 191, 9, 216, 20, 62, 9, 108, 20, 213, 8, 238, 19, 160, 8, 102, 19, 193, 8, 217, 18, 72, 9, 81, 18, 57, 10, 217, 17, 141, 11, 117, 17, 46, 13, 44, 17, 255, 14, 255, 16, 217, 16, 235, 16, 155, 18, 237, 16, 38, 20, 1, 17, 99, 21, 28, 17, 65, 22, 55, 17, 187, 22, 68, 17, 207, 22, 45, 17, 114, 22, 214, 16, 160, 21, 45, 16, 88, 20, 48, 15, 165, 18, 236, 13, 149, 16, 114, 12, 61, 14, 216, 10, 184, 11, 46, 9, 37, 9, 135, 7, 164, 6, 239, 5, 85, 4, 107, 4, 86, 2, 3, 3, 187, 0, 186, 1, 150, 255, 143, 0, 241, 254, 132, 255, 213, 254, 153, 254, 66, 255, 209, 253, 50, 0, 63, 253, 162, 1, 242, 252, 134, 3, 243, 252, 198, 5, 56, 253, 62, 8, 176, 253, 191, 10, 55, 254, 25, 13, 160, 254, 28, 15, 191, 254, 155, 16, 114, 254, 121, 17, 167, 253, 168, 17, 93, 252, 42, 17, 164, 250, 15, 16, 155, 248, 119, 14, 101, 246, 138, 12, 40, 244, 111, 10, 5, 242, 78, 8, 24, 240, 69, 6, 113, 238, 102, 4, 20, 237, 187, 2, 246, 235, 64, 1, 247, 234, 226, 255, 245, 233, 137, 254, 216, 232, 38, 253, 147, 231, 179, 251, 37, 230, 59, 250, 154, 228, 205, 248, 8, 227, 128, 247, 135, 225, 98, 246, 47, 224, 126, 245, 20, 223, 218, 244, 70, 222, 111, 244, 200, 221, 50, 244, 152, 221, 18, 244, 174, 221, 1, 244, 253, 221, 236, 243, 120, 222, 195, 243, 18, 223, 123, 243, 191, 223, 11, 243, 117, 224, 113, 242, 50, 225, 180, 241, 246, 225, 223, 240, 204, 226, 3, 240, 199, 227, 48, 239, 255, 228, 118, 238, 143, 230, 220, 237, 134, 232, 107, 237, 226, 234, 36, 237, 150, 237, 9, 237, 136, 240, 26, 237, 153, 243, 88, 237, 171, 246, 193, 237, 156, 249, 86, 238, 84, 252, 21, 239, 194, 254, 0, 240, 225, 0, 24, 241, 191, 2, 99, 242, 130, 4, 246, 243, 97, 6, 239, 245, 138, 8, 94, 248, 28, 11, 68, 251, 25, 14, 140, 254, 110, 17, 14, 2, 235, 20, 158, 5, 89, 24, 3, 9, 123, 27, 14, 12, 36, 30, 149, 14, 46, 32, 123, 16, 138, 33, 178, 17, 55, 34, 58, 18, 70, 34, 33, 18, 207, 33, 125, 17, 241, 32, 105, 16, 205, 31, 254, 14, 127, 30, 84, 13, 30, 29, 132, 11, 177, 27, 158, 9, 52, 26, 163, 7, 156, 24, 148, 5, 221, 22, 115, 3, 245, 20, 76, 1, 227, 18, 53, 255, 180, 16, 74, 253, 109, 14, 173, 251, 29, 12, 116, 250, 211, 9, 173, 249, 154, 7, 89, 249, 126, 5, 108, 249, 136, 3, 208, 249, 193, 1, 106, 250, 41, 0, 27, 251, 197, 254, 197, 251, 141, 253, 81, 252, 130, 252, 173, 252, 156, 251, 206, 252, 212, 250, 173, 252, 24, 250, 65, 252, 81, 249, 128, 251, 109, 248, 103, 250, 100, 247, 248, 248, 60, 246, 64, 247, 252, 244, 78, 245, 181, 243, 55, 243, 120, 242, 22, 241, 83, 241, 4, 239, 81, 240, 30, 237, 122, 239, 125, 235, 210, 238, 57, 234, 90, 238, 100, 233, 18, 238, 14, 233, 247, 237, 65, 233, 4, 238, 0, 234, 58, 238, 67, 235, 158, 238, 0, 237, 64, 239, 45, 239, 39, 240, 183, 241, 81, 241, 128, 244, 175, 242, 96, 247, 38, 244, 45, 250, 147, 245, 189, 252, 209, 246, 231, 254, 191, 247, 140, 0, 75, 248, 155, 1, 102, 248, 15, 2, 26, 248, 241, 1, 122, 247, 88, 1, 161, 246, 100, 0, 173, 245, 59, 255, 191, 244, 253, 253, 244, 243, 200, 252, 96, 243, 182, 251, 17, 243, 215, 250, 5, 243, 52, 250, 42, 243, 194, 249, 101, 243, 112, 249, 155, 243, 45, 249, 186, 243, 238, 248, 189, 243, 182, 248, 166, 243, 137, 248, 128, 243, 118, 248, 94, 243, 138, 248, 80, 243, 206, 248, 104, 243, 70, 249, 177, 243, 236, 249, 48, 244, 185, 250, 228, 244, 158, 251, 198, 245, 137, 252, 202, 246, 104, 253, 228, 247, 40, 254, 2, 249, 183, 254, 25, 250, 11, 255, 28, 251, 31, 255, 3, 252, 245, 254, 206, 252, 150, 254, 132, 253, 15, 254, 52, 254, 112, 253, 240, 254, 202, 252, 199, 255, 41, 252, 199, 0, 148, 251, 249, 1, 19, 251, 89, 3, 167, 250, 218, 4, 83, 250, 104, 6, 26, 250, 236, 7, 254, 249, 80, 9, 1, 250, 127, 10, 38, 250, 103, 11, 116, 250, 4, 12, 234, 250, 88, 12, 138, 251, 126, 12, 101, 252, 165, 12, 149, 253, 0, 13, 52, 255, 180, 13, 75, 1, 209, 14, 213, 3, 78, 16, 188, 6, 18, 18, 215, 9, 244, 19, 252, 12, 200, 21, 251, 15, 95, 23, 169, 18, 147, 24, 229, 20, 76, 25, 151, 22, 124, 25, 178, 23, 41, 25, 58, 24, 100, 24, 61, 24, 66, 23, 203, 23, 224, 21, 249, 22, 86, 20, 220, 21, 189, 18, 138, 20, 39, 17, 24, 19, 147, 15, 142, 17, 248, 13, 237, 15, 79, 12, 54, 14, 142, 10, 113, 12, 181, 8, 173, 10, 199, 6, 4, 9, 208, 4, 147, 7, 217, 2, 114, 6, 241, 0, 181, 5, 36, 255, 96, 5, 121, 253, 109, 5, 250, 251, 208, 5, 171, 250, 112, 6, 145, 249, 50, 7, 170, 248, 250, 7, 245, 247, 174, 8, 109, 247, 56, 9, 12, 247, 139, 9, 205, 246, 159, 9, 161, 246, 104, 9, 117, 246, 221, 8, 55, 246, 245, 7, 220, 245, 177, 6, 95, 245, 25, 5, 196, 244, 59, 3, 22, 244, 42, 1, 97, 243, 252, 254, 184, 242, 203, 252, 39, 242, 177, 250, 188, 241, 204, 248, 127, 241, 53, 247, 118, 241, 3, 246, 163, 241, 77, 245, 4, 242, 32, 245, 151, 242, 133, 245, 91, 243, 116, 246, 81, 244, 230, 247, 133, 245, 207, 249, 254, 246, 31, 252, 186, 248, 185, 254, 172, 250, 119, 1, 181, 252, 48, 4, 183, 254, 183, 6, 139, 0, 225, 8, 18, 2, 136, 10, 49, 3, 146, 11, 212, 3, 239, 11, 244, 3, 159, 11, 155, 3, 174, 10, 215, 2, 53, 9, 193, 1, 83, 7, 119, 0, 40, 5, 23, 255, 212, 2, 179, 253, 114, 0, 99, 252, 30, 254, 48, 251, 233, 251, 18, 250, 215, 249, 249, 248, 226, 247, 208, 247, 255, 245, 134, 246, 38, 244, 21, 245, 87, 242, 127, 243, 153, 240, 206, 241, 248, 238, 18, 240, 131, 237, 95, 238, 69, 236, 198, 236, 68, 235, 87, 235, 131, 234, 32, 234, 252, 233, 37, 233, 163, 233, 99, 232, 107, 233, 218, 231, 68, 233, 128, 231, 24, 233, 75, 231, 217, 232, 48, 231, 123, 232, 39, 231, 245, 231, 41, 231, 74, 231, 55, 231, 129, 230, 89, 231, 163, 229, 154, 231, 192, 228, 6, 232, 234, 227, 166, 232, 42, 227, 130, 233, 141, 226, 161, 234, 26, 226, 5, 236, 209, 225, 162, 237, 177, 225, 110, 239, 187, 225, 87, 241, 239, 225, 71, 243, 79, 226, 43, 245, 222, 226, 240, 246, 158, 227, 137, 248, 140, 228, 238, 249, 165, 229, 42, 251, 238, 230, 93, 252, 125, 232, 181, 253, 106, 234, 83, 255, 196, 236, 73, 1, 142, 239, 154, 3, 187, 242, 52, 6, 44, 246, 250, 8, 189, 249, 201, 11, 68, 253, 123, 14, 152, 0, 230, 16, 150, 3, 238, 18, 36, 6, 133, 20, 51, 8, 162, 21, 188, 9, 76, 22, 198, 10, 145, 22, 90, 11, 135, 22, 136, 11, 72, 22, 103, 11, 235, 21, 10, 11, 133, 21, 138, 10, 32, 21, 246, 9, 184, 20, 84, 9, 67, 20, 163, 8, 187, 19, 234, 7, 27, 19, 51, 7, 99, 18, 142, 6, 157, 17, 22, 6, 211, 16, 226, 5, 21, 16, 5, 6, 108, 15, 139, 6, 224, 14, 116, 7, 122, 14, 181, 8, 58, 14, 60, 10, 32, 14, 241, 11, 40, 14, 180, 13, 76, 14, 109, 15, 131, 14, 1, 17, 200, 14, 89, 18, 14, 15, 106, 19, 75, 15, 35, 20, 110, 15, 120, 20, 102, 15, 90, 20, 37, 15, 199, 19, 162, 14, 192, 18, 216, 13, 79, 17, 206, 12, 133, 15, 140, 11, 121, 13, 38, 10, 66, 11, 172, 8, 253, 8, 47, 7, 198, 6, 190, 5, 186, 4, 101, 4, 249, 2, 43, 3, 157, 1, 21, 2, 189, 0, 37, 1, 101, 0, 91, 0, 149, 0, 185, 255, 69, 1, 72, 255, 111, 2, 17, 255, 8, 4, 27, 255, 251, 5, 93, 255, 46, 8, 197, 255, 121, 10, 57, 0, 184, 12, 160, 0, 193, 14, 224, 0, 113, 16, 224, 0, 169, 17, 141, 0, 83, 18, 222, 255, 103, 18, 207, 254, 232, 17, 104, 253, 227, 16, 187, 251, 112, 15, 222, 249, 168, 13, 234, 247, 166, 11, 246, 245, 135, 9, 25, 244, 103, 7, 97, 242, 92, 5, 208, 240, 115, 3, 93, 239, 171, 1, 247, 237, 255, 255, 143, 236, 102, 254, 32, 235, 222, 252, 165, 233, 103, 251, 38, 232, 13, 250, 172, 230, 217, 248, 70, 229, 213, 247, 1, 228, 6, 247, 235, 226, 111, 246, 12, 226, 12, 246, 106, 225, 210, 245, 6, 225, 183, 245, 220, 224, 168, 245, 231, 224, 150, 245, 30, 225, 109, 245, 118, 225, 35, 245, 233, 225, 176, 244, 115, 226, 21, 244, 17, 227, 87, 243, 203, 227, 126, 242, 168, 228, 153, 241, 172, 229, 183, 240, 222, 230, 230, 239, 59, 232, 50, 239, 199, 233, 160, 238, 130, 235, 55, 238, 109, 237, 247, 237, 129, 239, 223, 237, 181, 241, 243, 237, 0, 244, 51, 238, 80, 246, 162, 238, 151, 248, 65, 239, 202, 250, 14, 240, 222, 252, 5, 241, 212, 254, 38, 242, 189, 0, 125, 243, 191, 2, 34, 245, 248, 4, 37, 247, 117, 7, 141, 249, 56, 10, 78, 252, 55, 13, 85, 255, 90, 16, 128, 2, 130, 19, 171, 5, 141, 22, 174, 8, 90, 25, 99, 11, 196, 27, 171, 13, 182, 29, 115, 15, 33, 31, 172, 16, 1, 32, 86, 17, 91, 32, 114, 17, 62, 32, 12, 17, 190, 31, 53, 16, 240, 30, 3, 15, 235, 29, 142, 13, 190, 28, 235, 11, 108, 27, 35, 10, 242, 25, 62, 8, 77, 24, 68, 6, 124, 22, 63, 4, 128, 20, 63, 2, 102, 18, 92, 0, 58, 16, 178, 254, 14, 14, 84, 253, 241, 11, 83, 252, 242, 9, 185, 251, 27, 8, 128, 251, 111, 6, 159, 251, 240, 4, 5, 252, 159, 3, 154, 252, 118, 2, 70, 253, 113, 1, 241, 253, 137, 0, 135, 254, 187, 255, 247, 254, 253, 254, 52, 255, 66, 254, 46, 255, 127, 253, 214, 254, 166, 252, 36, 254, 174, 251, 20, 253, 144, 250, 175, 251, 75, 249, 255, 249, 230, 247, 22, 248, 110, 246, 9, 246, 243, 244, 239, 243, 136, 243, 226, 241, 60, 242, 254, 239, 29, 241, 98, 238, 53, 240, 40, 237, 137, 239, 105, 236, 25, 239, 46, 236, 228, 238, 121, 236, 232, 238, 69, 237, 37, 239, 136, 238, 167, 239, 57, 240, 104, 240, 72, 242, 102, 241, 159, 244, 144, 242, 30, 247, 209, 243, 166, 249, 21, 245, 17, 252, 68, 246, 61, 254, 74, 247, 14, 0, 22, 248, 109, 1, 154, 248, 75, 2, 208, 248, 168, 2, 185, 248, 135, 2, 93, 248, 250, 1, 204, 247, 18, 1, 23, 247, 234, 255, 83, 246, 155, 254, 152, 245, 65, 253, 243, 244, 245, 251, 113, 244, 204, 250, 12, 244, 202, 249, 187, 243, 240, 248, 115, 243, 54, 248, 42, 243, 153, 247, 222, 242, 24, 247, 143, 242, 182, 246, 69, 242, 122, 246, 10, 242, 109, 246, 232, 241, 148, 246, 232, 241, 241, 246, 19, 242, 127, 247, 108, 242, 57, 248, 243, 242, 16, 249, 164, 243, 244, 249, 121, 244, 210, 250, 103, 245, 152, 251, 103, 246, 56, 252, 107, 247, 168, 252, 111, 248, 227, 252, 116, 249, 234, 252, 125, 250, 194, 252, 141, 251, 119, 252, 164, 252, 20, 252, 195, 253, 166, 251, 229, 254, 56, 251, 7, 0, 212, 250, 39, 1, 126, 250, 73, 2, 58, 250, 110, 3, 10, 250, 146, 4, 242, 249, 181, 5, 243, 249, 208, 6, 22, 250, 219, 7, 92, 250, 209, 8, 197, 250, 169, 9, 79, 251, 97, 10, 247, 251, 3, 11, 197, 252, 171, 11, 208, 253, 119, 12, 44, 255, 118, 13, 227, 0, 181, 14, 251, 2, 49, 16, 105, 5, 221, 17, 21, 8, 166, 19, 225, 10, 112, 21, 170, 13, 33, 23, 79, 16, 155, 24, 172, 18, 194, 25, 170, 20, 132, 26, 54, 22, 214, 26, 69, 23, 182, 26, 209, 23, 43, 26, 225, 23, 67, 25, 126, 23, 16, 24, 185, 22, 168, 22, 169, 21, 27, 21, 98, 20, 111, 19, 238, 18, 166, 17, 89, 17, 191, 15, 170, 15, 185, 13, 234, 13, 152, 11, 37, 12, 101, 9, 110, 10, 48, 7, 221, 8, 9, 5, 137, 7, 0, 3, 130, 6, 35, 1, 214, 5, 125, 255, 136, 5, 17, 254, 145, 5, 226, 252, 230, 5, 235, 251, 115, 6, 40, 251, 37, 7, 146, 250, 228, 7, 34, 250, 152, 8, 206, 249, 50, 9, 146, 249, 162, 9, 102, 249, 215, 9, 58, 249, 193, 9, 255, 248, 83, 9, 171, 248, 135, 8, 49, 248, 94, 7, 142, 247, 225, 5, 195, 246, 30, 4, 216, 245, 39, 2, 221, 244, 18, 0, 227, 243, 248, 253, 1, 243, 244, 251, 68, 242, 38, 250, 188, 241, 174, 248, 115, 241, 165, 247, 108, 241, 23, 247, 168, 241, 12, 247, 37, 242, 128, 247, 228, 242, 109, 248, 230, 243, 202, 249, 45, 245, 141, 251, 176, 246, 161, 253, 96, 248, 237, 255, 45, 250, 81, 2, 255, 251, 171, 4, 191, 253, 214, 6, 87, 255, 179, 8, 179, 0, 38, 10, 196, 1, 24, 11, 126, 2, 126, 11, 218, 2, 87, 11, 214, 2, 167, 10, 121, 2, 123, 9, 209, 1, 230, 7, 238, 0, 0, 6, 227, 255, 229, 3, 193, 254, 179, 1, 151, 253, 131, 255, 104, 252, 94, 253, 48, 251, 76, 251, 233, 249, 77, 249, 144, 248, 99, 247, 36, 247, 143, 245, 171, 245, 214, 243, 43, 244, 68, 242, 175, 242, 223, 240, 67, 241, 176, 239, 242, 239, 189, 238, 198, 238, 6, 238, 195, 237, 136, 237, 238, 236, 53, 237, 69, 236, 1, 237, 199, 235, 220, 236, 110, 235, 178, 236, 48, 235, 121, 236, 10, 235, 36, 236, 251, 234, 174, 235, 5, 235, 24, 235, 44, 235, 99, 234, 113, 235, 153, 233, 213, 235, 197, 232, 87, 236, 241, 231, 242, 236, 42, 231, 159, 237, 120, 230, 91, 238, 226, 229, 37, 239, 108, 229, 253, 239, 25, 229, 232, 240, 235, 228, 231, 241, 233, 228, 248, 242, 20, 229, 26, 244, 113, 229, 71, 245, 252, 229, 122, 246, 179, 230, 172, 247, 147, 231, 225, 248, 152, 232, 43, 250, 212, 233, 156, 251, 89, 235, 71, 253, 55, 237, 51, 255, 113, 239, 96, 1, 4, 242, 198, 3, 220, 244, 84, 6, 229, 247, 244, 8, 253, 250, 140, 11, 6, 254, 3, 14, 224, 0, 62, 16, 114, 3, 40, 18, 169, 5, 180, 19, 116, 7, 216, 20, 202, 8, 148, 21, 170, 9, 241, 21, 31, 10, 254, 21, 54, 10, 204, 21, 2, 10, 107, 21, 154, 9, 232, 20, 11, 9, 68, 20, 95, 8, 125, 19, 157, 7, 149, 18, 202, 6, 145, 17, 244, 5, 121, 16, 39, 5, 90, 15, 120, 4, 68, 14, 250, 3, 71, 13, 193, 3, 116, 12, 219, 3, 213, 11, 79, 4, 110, 11, 26, 5, 63, 11, 52, 6, 68, 11, 143, 7, 116, 11, 21, 9, 198, 11, 179, 10, 45, 12, 79, 12, 162, 12, 213, 13, 27, 13, 53, 15, 142, 13, 88, 16, 237, 13, 47, 17, 38, 14, 165, 17, 43, 14, 178, 17, 237, 13, 79, 17, 101, 13, 130, 16, 149, 12, 85, 15, 129, 11, 216, 13, 52, 10, 29, 12, 193, 8, 59, 10, 61, 7, 80, 8, 191, 5, 126, 6, 86, 4, 226, 4, 19, 3, 151, 3, 255, 1, 176, 2, 32, 1, 54, 2, 118, 0, 42, 2, 3, 0, 138, 2, 200, 255, 81, 3, 196, 255, 125, 4, 246, 255, 254, 5, 82, 0, 194, 7, 208, 0, 177, 9, 93, 1, 173, 11, 231, 1, 152, 13, 92, 2, 82, 15, 169, 2, 192, 16, 194, 2, 204, 17, 153, 2, 99, 18, 38, 2, 125, 18, 102, 1, 25, 18, 90, 0, 58, 17, 13, 255, 240, 15, 134, 253, 80, 14, 217, 251, 111, 12, 24, 250, 107, 10, 81, 248, 92, 8, 143, 246, 85, 6, 209, 244, 95, 4, 21, 243, 122, 2, 87, 241, 172, 0, 153, 239, 245, 254, 222, 237, 86, 253, 44, 236, 217, 251, 142, 234, 131, 250, 12, 233, 94, 249, 176, 231, 111, 248, 132, 230, 185, 247, 139, 229, 56, 247, 202, 228, 229, 246, 65, 228, 178, 246, 238, 227, 144, 246, 201, 227, 111, 246, 206, 227, 68, 246, 247, 227, 2, 246, 70, 228, 163, 245, 186, 228, 37, 245, 85, 229, 138, 244, 22, 230, 214, 243, 249, 230, 18, 243, 250, 231, 73, 242, 20, 233, 133, 241, 63, 234, 207, 240, 117, 235, 49, 240, 179, 236, 175, 239, 246, 237, 77, 239, 67, 239, 13, 239, 158, 240, 247, 238, 12, 242, 14, 239, 143, 243, 82, 239, 36, 245, 197, 239, 204, 246, 97, 240, 129, 248, 32, 241, 66, 250, 3, 242, 25, 252, 18, 243, 21, 254, 95, 244, 66, 0, 250, 245, 174, 2, 235, 247, 89, 5, 49, 250, 60, 8, 192, 252, 72, 11, 133, 255, 105, 14, 101, 2, 132, 17, 66, 5, 129, 20, 254, 7, 67, 23, 121, 10, 180, 25, 156, 12, 190, 27, 81, 14, 81, 29, 137, 15, 104, 30, 63, 16, 3, 31, 119, 16, 43, 31, 56, 16, 236, 30, 150, 15, 87, 30, 164, 14, 120, 29, 112, 13, 79, 28, 5, 12, 225, 26, 110, 10, 55, 25, 181, 8, 86, 23, 229, 6, 75, 21, 12, 5, 39, 19, 62, 3, 253, 16, 142, 1, 222, 14, 21, 0, 220, 12, 229, 254, 8, 11, 7, 254, 107, 9, 129, 253, 7, 8, 82, 253, 218, 6, 111, 253, 225, 5, 204, 253, 18, 5, 85, 254, 100, 4, 248, 254, 208, 3, 161, 255, 78, 3, 60, 0, 215, 2, 187, 0, 95, 2, 11, 1, 214, 1, 23, 1, 43, 1, 211, 0, 82, 0, 53, 0, 69, 255, 62, 255, 253, 253, 242, 253, 128, 252, 95, 252, 216, 250, 146, 250, 19, 249, 161, 248, 70, 247, 166, 246, 134, 245, 193, 244, 231, 243, 14, 243, 124, 242, 166, 241, 80, 241, 158, 240, 109, 240, 254, 239, 211, 239, 203, 239, 132, 239, 4, 240, 127, 239, 166, 240, 196, 239, 174, 241, 78, 240, 19, 243, 23, 241, 201, 244, 19, 242, 186, 246, 51, 243, 206, 248, 100, 244, 233, 250, 150, 245, 239, 252, 183, 246, 199, 254, 181, 247, 85, 0, 135, 248, 136, 1, 31, 249, 83, 2, 120, 249, 172, 2, 143, 249, 149, 2, 102, 249, 21, 2, 3, 249, 59, 1, 118, 248, 29, 0, 203, 247, 214, 254, 16, 247, 123, 253, 81, 246, 34, 252, 143, 245, 214, 250, 208, 244, 158, 249, 14, 244, 125, 248, 78, 243, 118, 247, 146, 242, 141, 246, 226, 241, 201, 245, 70, 241, 49, 245, 199, 240, 205, 244, 109, 240, 163, 244, 62, 240, 182, 244, 65, 240, 3, 245, 116, 240, 131, 245, 216, 240, 40, 246, 105, 241, 227, 246, 31, 242, 168, 247, 244, 242, 100, 248, 227, 243, 13, 249, 235, 244, 153, 249, 10, 246, 1, 250, 60, 247, 68, 250, 126, 248, 99, 250, 203, 249, 99, 250, 28, 251, 72, 250, 103, 252, 30, 250, 165, 253, 235, 249, 208, 254, 183, 249, 226, 255, 137, 249, 215, 0, 100, 249, 180, 1, 78, 249, 127, 2, 80, 249, 62, 3, 107, 249, 249, 3, 164, 249, 182, 4, 251, 249, 119, 5, 111, 250, 59, 6, 252, 250, 4, 7, 161, 251, 217, 7, 103, 252, 200, 8, 92, 253, 223, 9, 146, 254, 42, 11, 19, 0, 177, 12, 231, 1, 113, 14, 8, 4, 92, 16, 103, 6, 102, 18, 241, 8, 121, 20, 139, 11, 124, 22, 25, 14, 90, 24, 128, 16, 250, 25, 166, 18, 73, 27, 114, 20, 51, 28, 209, 21, 175, 28, 186, 22, 189, 28, 48, 23, 96, 28, 55, 23, 161, 27, 220, 22, 143, 26, 47, 22, 53, 25, 64, 21, 152, 23, 26, 20, 190, 21, 197, 18, 172, 19, 74, 17, 107, 17, 176, 15, 8, 15, 5, 14, 148, 12, 87, 12, 33, 10, 187, 10, 194, 7, 68, 9, 138, 5, 5, 8, 137, 3, 13, 7, 203, 1, 100, 6, 85, 0, 12, 6, 41, 255, 2, 6, 64, 254, 60, 6, 147, 253, 169, 6, 23, 253, 60, 7, 198, 252, 225, 7, 150, 252, 135, 8, 126, 252, 30, 9, 112, 252, 143, 9, 91, 252, 202, 9, 44, 252, 189, 9, 213, 251, 91, 9, 76, 251, 163, 8, 139, 250, 149, 7, 150, 249, 57, 6, 114, 248, 157, 4, 43, 247, 211, 2, 212, 245, 244, 0, 128, 244, 30, 255, 71, 243, 106, 253, 59, 242, 241, 251, 107, 241, 199, 250, 229, 240, 248, 249, 172, 240, 139, 249, 194, 240, 127, 249, 37, 241, 215, 249, 213, 241, 145, 250, 207, 242, 168, 251, 14, 244, 20, 253, 135, 245, 196, 254, 43, 247, 163, 0, 234, 248, 152, 2, 175, 250, 138, 4, 102, 252, 91, 6, 254, 253, 244, 7, 101, 255, 57, 9, 139, 0, 25, 10, 106, 1, 133, 10, 249, 1, 120, 10, 52, 2, 242, 9, 29, 2, 254, 8, 187, 1, 173, 7, 26, 1, 18, 6, 71, 0, 72, 4, 79, 255, 99, 2, 53, 254, 112, 0, 255, 252, 123, 254, 174, 251, 135, 252, 71, 250, 154, 250, 207, 248, 187, 248, 79, 247, 243, 246, 207, 245, 74, 245, 92, 244, 201, 243, 255, 242, 123, 242, 194, 241, 100, 241, 172, 240, 135, 240, 193, 239, 222, 239, 2, 239, 99, 239, 111, 238, 11, 239, 4, 238, 201, 238, 192, 237, 144, 238, 161, 237, 87, 238, 167, 237, 20, 238, 208, 237, 192, 237, 27, 238, 88, 237, 128, 238, 218, 236, 253, 238, 75, 236, 135, 239, 173, 235, 24, 240, 8, 235, 169, 240, 100, 234, 51, 241, 198, 233, 177, 241, 53, 233, 35, 242, 183, 232, 134, 242, 82, 232, 224, 242, 11, 232, 60, 243, 232, 231, 160, 243, 235, 231, 21, 244, 20, 232, 162, 244, 95, 232, 72, 245, 205, 232, 8, 246, 89, 233, 230, 246, 6, 234, 238, 247, 228, 234, 45, 249, 2, 236, 176, 250, 107, 237, 125, 252, 40, 239, 149, 254, 58, 241, 236, 0, 149, 243, 119, 3, 43, 246, 35, 6, 229, 248, 215, 8, 171, 251, 123, 11, 96, 254, 250, 13, 234, 0, 60, 16, 49, 3, 48, 18, 34, 5, 200, 19, 177, 6, 250, 20, 216, 7, 199, 21, 154, 8, 50, 22, 255, 8, 69, 22, 23, 9, 7, 22, 237, 8, 127, 21, 141, 8, 178, 20, 255, 7, 168, 19, 74, 7, 106, 18, 120, 6, 4, 17, 146, 5, 136, 15, 167, 4, 9, 14, 200, 3, 156, 12, 7, 3, 81, 11, 119, 2, 57, 10, 41, 2, 99, 9, 40, 2, 209, 8, 121, 2, 138, 8, 26, 3, 136, 8, 4, 4, 193, 8, 45, 5, 43, 9, 132, 6, 188, 9, 247, 7, 106, 10, 116, 9, 39, 11, 233, 10, 228, 11, 66, 12, 140, 12, 105, 13, 12, 13, 74, 14, 80, 13, 214, 14, 75, 13, 1, 15, 246, 12, 204, 14, 80, 12, 56, 14, 92, 11, 80, 13, 38, 10, 34, 12, 187, 8, 199, 10, 48, 7, 85, 9, 155, 5, 233, 7, 16, 4, 153, 6, 163, 2, 121, 5, 101, 1, 152, 4, 95, 0, 1, 4, 151, 255, 183, 3, 11, 255, 190, 3, 193, 254, 27, 4, 187, 254, 206, 4, 244, 254, 210, 5, 105, 255, 31, 7, 12, 0, 164, 8, 211, 0, 79, 10, 170, 1, 6, 12, 127, 2, 179, 13, 63, 3, 60, 15, 218, 3, 136, 16, 64, 4, 130, 17, 105, 4, 25, 18, 75, 4, 63, 18, 225, 3, 245, 17, 43, 3, 64, 17, 44, 2, 41, 16, 238, 0, 196, 14, 125, 255, 36, 13, 226, 253, 93, 11, 38, 252, 128, 9, 81, 250, 148, 7, 99, 248, 164, 5, 100, 246, 181, 3, 92, 244, 205, 1, 84, 242, 247, 255, 87, 240, 58, 254, 113, 238, 160, 252, 172, 236, 52, 251, 20, 235, 254, 249, 177, 233, 254, 248, 132, 232, 52, 248, 147, 231, 154, 247, 220, 230, 40, 247, 93, 230, 210, 246, 22, 230, 142, 246, 4, 230, 81, 246, 39, 230, 17, 246, 124, 230, 200, 245, 255, 230, 111, 245, 168, 231, 6, 245, 112, 232, 138, 244, 76, 233, 0, 244, 53, 234, 106, 243, 33, 235, 209, 242, 9, 236, 58, 242, 236, 236, 170, 241, 193, 237, 41, 241, 140, 238, 190, 240, 78, 239, 109, 240, 11, 240, 60, 240, 207, 240, 45, 240, 163, 241, 67, 240, 144, 242, 123, 240, 153, 243, 211, 240, 192, 244, 73, 241, 10, 246, 223, 241, 131, 247, 161, 242, 55, 249, 157, 243, 51, 251, 227, 244, 127, 253, 120, 246, 24, 0, 96, 248, 250, 2, 148, 250, 21, 6, 5, 253, 86, 9, 163, 255, 163, 12, 80, 2, 229, 15, 247, 4, 0, 19, 122, 7, 222, 21, 190, 9, 107, 24, 174, 11, 145, 26, 58, 13, 71, 28, 90, 14, 133, 29, 13, 15, 74, 30, 87, 15, 154, 30, 65, 15, 123, 30, 217, 14, 243, 29, 40, 14, 8, 29, 53, 13, 192, 27, 9, 12, 37, 26, 170, 10, 72, 24, 35, 9, 60, 22, 131, 7, 17, 20, 215, 5, 224, 17, 53, 4, 190, 15, 177, 2, 187, 13, 92, 1, 232, 11, 71, 0, 84, 10, 126, 255, 3, 9, 255, 254, 245, 7, 204, 254, 40, 7, 223, 254, 147, 6, 43, 255, 49, 6, 163, 255, 244, 5, 55, 0, 209, 5, 216, 0, 186, 5, 115, 1, 155, 5, 244, 1, 95, 5, 69, 2, 245, 4, 86, 2, 77, 4, 28, 2, 97, 3, 142, 1, 44, 2, 177, 0, 177, 0, 138, 255, 253, 254, 37, 254, 26, 253, 150, 252, 26, 251, 241, 250, 18, 249, 80, 249, 24, 247, 197, 247, 65, 245, 101, 246, 159, 243, 62, 245, 62, 242, 91, 244, 38, 241, 193, 243, 88, 240, 117, 243, 220, 239, 126, 243, 182, 239, 221, 243, 227, 239, 146, 244, 98, 240, 154, 245, 42, 241, 232, 246, 44, 242, 107, 248, 90, 243, 18, 250, 159, 244, 198, 251, 232, 245, 114, 253, 36, 247, 250, 254, 65, 248, 71, 0, 48, 249, 73, 1, 233, 249, 240, 1, 101, 250, 54, 2, 157, 250, 29, 2, 148, 250, 171, 1, 78, 250, 236, 0, 211, 249, 245, 255, 45, 249, 213, 254, 102, 248, 155, 253, 130, 247, 82, 252, 134, 246, 3, 251, 119, 245, 181, 249, 92, 244, 109, 248, 63, 243, 53, 247, 42, 242, 21, 246, 41, 241, 23, 245, 70, 240, 69, 244, 140, 239, 166, 243, 3, 239, 65, 243, 175, 238, 20, 243, 149, 238, 27, 243, 179, 238, 81, 243, 10, 239, 173, 243, 152, 239, 36, 244, 92, 240, 174, 244, 83, 241, 62, 245, 117, 242, 203, 245, 186, 243, 80, 246, 25, 245, 196, 246, 135, 246, 38, 247, 249, 247, 114, 247, 99, 249, 171, 247, 187, 250, 212, 247, 251, 251, 239, 247, 27, 253, 3, 248, 25, 254, 21, 248, 243, 254, 41, 248, 172, 255, 72, 248, 69, 0, 112, 248, 202, 0, 169, 248, 69, 1, 242, 248, 190, 1, 76, 249, 61, 2, 182, 249, 199, 2, 48, 250, 96, 3, 187, 250, 22, 4, 97, 251, 249, 4, 51, 252, 22, 6, 63, 253, 123, 7, 144, 254, 41, 9, 44, 0, 31, 11, 18, 2, 84, 13, 61, 4, 183, 15, 155, 6, 51, 18, 25, 9, 176, 20, 159, 11, 23, 23, 19, 14, 78, 25, 90, 16, 66, 27, 94, 18, 225, 28, 15, 20, 27, 30, 97, 21, 230, 30, 79, 22, 61, 31, 216, 22, 32, 31, 3, 23, 147, 30, 219, 22, 154, 29, 102, 22, 58, 28, 170, 21, 118, 26, 171, 20, 92, 24, 112, 19, 1, 22, 9, 18, 118, 19, 125, 16, 207, 16, 220, 14, 36, 14, 57, 13, 138, 11, 166, 11, 22, 9, 54, 10, 217, 6, 250, 8, 225, 4, 254, 7, 53, 3, 74, 7, 219, 1, 224, 6, 211, 0, 188, 6, 22, 0, 216, 6, 159, 255, 40, 7, 96, 255, 159, 7, 78, 255, 46, 8, 89, 255, 197, 8, 108, 255, 80, 9, 116, 255, 186, 9, 93, 255, 240, 9, 19, 255, 230, 9, 142, 254, 144, 9, 199, 253, 235, 8, 190, 252, 255, 7, 122, 251, 210, 6, 6, 250, 119, 5, 114, 248, 254, 3, 208, 246, 123, 2, 51, 245, 1, 1, 176, 243, 162, 255, 91, 242, 108, 254, 64, 241, 107, 253, 105, 240, 166, 252, 220, 239, 38, 252, 162, 239, 239, 251, 192, 239, 9, 252, 57, 240, 121, 252, 13, 241, 58, 253, 53, 242, 70, 254, 164, 243, 144, 255, 72, 245, 8, 1, 17, 247, 155, 2, 234, 248, 52, 4, 186, 250, 182, 5, 112, 252, 12, 7, 249, 253, 31, 8, 74, 255, 223, 8, 84, 0, 64, 9, 19, 1, 62, 9, 131, 1, 219, 8, 164, 1, 33, 8, 119, 1, 26, 7, 7, 1, 214, 5, 89, 0, 98, 4, 117, 255, 201, 2, 92, 254, 18, 1, 19, 253, 71, 255, 166, 251, 108, 253, 28, 250, 140, 251, 131, 248, 179, 249, 234, 246, 234, 247, 91, 245, 62, 246, 229, 243, 185, 244, 146, 242, 97, 243, 105, 241, 60, 242, 113, 240, 73, 241, 172, 239, 133, 240, 31, 239, 237, 239, 201, 238, 119, 239, 172, 238, 29, 239, 197, 238, 214, 238, 14, 239, 154, 238, 126, 239, 97, 238, 13, 240, 37, 238, 178, 240, 226, 237, 93, 241, 148, 237, 7, 242, 61, 237, 167, 242, 220, 236, 53, 243, 117, 236, 173, 243, 12, 236, 9, 244, 165, 235, 75, 244, 72, 235, 118, 244, 248, 234, 139, 244, 184, 234, 146, 244, 138, 234, 148, 244, 116, 234, 155, 244, 114, 234, 175, 244, 134, 234, 213, 244, 175, 234, 24, 245, 240, 234, 130, 245, 79, 235, 38, 246, 219, 235, 20, 247, 163, 236, 86, 248, 178, 237, 244, 249, 15, 239, 236, 251, 188, 240, 55, 254, 182, 242, 198, 0, 238, 244, 134, 3, 84, 247, 96, 6, 211, 249, 59, 9, 82, 252, 254, 11, 184, 254, 148, 14, 240, 0, 234, 16, 235, 2, 238, 18, 156, 4, 149, 20, 251, 5, 214, 21, 6, 7, 171, 22, 192, 7, 21, 23, 47, 8, 24, 23, 91, 8, 182, 22, 71, 8, 246, 21, 249, 7, 225, 20, 117, 7, 133, 19, 196, 6, 242, 17, 239, 5, 61, 16, 1, 5, 122, 14, 11, 4, 193, 12, 30, 3, 37, 11, 77, 2, 183, 9, 171, 1, 137, 8, 65, 1, 162, 7, 30, 1, 10, 7, 68, 1, 196, 6, 179, 1, 206, 6, 103, 2, 31, 7, 85, 3, 174, 7, 117, 4, 106, 8, 183, 5, 68, 9, 10, 7, 37, 10, 92, 8, 248, 10, 151, 9, 164, 11, 168, 10, 23, 12, 125, 11, 66, 12, 10, 12, 28, 12, 73, 12, 163, 11, 59, 12, 216, 10, 229, 11, 196, 9, 84, 11, 116, 8, 148, 10, 249, 6, 181, 9, 100, 5, 200, 8, 200, 3, 218, 7, 57, 2, 251, 6, 197, 0, 54, 6, 122, 255, 149, 5, 98, 254, 35, 5, 135, 253, 228, 4, 246, 252, 229, 4, 180, 252, 44, 5, 197, 252, 188, 5, 40, 253, 146, 6, 211, 253, 167, 7, 186, 254, 241, 8, 204, 255, 92, 10, 243, 0, 215, 11, 31, 2, 76, 13, 58, 3, 163, 14, 49, 4, 198, 15, 245, 4, 164, 16, 122, 5, 48, 17, 183, 5, 99, 17, 167, 5, 59, 17, 72, 5, 186, 16, 157, 4, 236, 15, 170, 3, 219, 14, 118, 2, 145, 13, 8, 1, 28, 12, 101, 255, 130, 10, 146, 253, 200, 8, 149, 251, 246, 6, 125, 249, 22, 5, 83, 247, 50, 3, 37, 245, 82, 1, 6, 243, 133, 255, 254, 240, 212, 253, 28, 239, 71, 252, 107, 237, 228, 250, 240, 235, 176, 249, 182, 234, 170, 248, 192, 233, 210, 247, 20, 233, 35, 247, 176, 232, 150, 246, 146, 232, 38, 246, 181, 232, 203, 245, 15, 233, 124, 245, 150, 233, 52, 245, 62, 234, 239, 244, 251, 234, 165, 244, 194, 235, 87, 244, 135, 236, 1, 244, 67, 237, 165, 243, 240, 237, 74, 243, 139, 238, 242, 242, 18, 239, 160, 242, 133, 239, 89, 242, 234, 239, 29, 242, 67, 240, 241, 241, 150, 240, 213, 241, 236, 240, 201, 241, 77, 241, 206, 241, 193, 241, 229, 241, 79, 242, 14, 242, 3, 243, 80, 242, 240, 243, 185, 242, 39, 245, 87, 243, 184, 246, 57, 244, 170, 248, 103, 245, 253, 250, 231, 246, 174, 253, 181, 248, 174, 0, 201, 250, 238, 3, 18, 253, 83, 7, 126, 255, 196, 10, 243, 1, 41, 14, 93, 4, 103, 17, 164, 6, 103, 20, 180, 8, 21, 23, 128, 10, 99, 25, 250, 11, 63, 27, 29, 13, 160, 28, 232, 13, 134, 29, 94, 14, 239, 29, 131, 14, 220, 29, 91, 14, 82, 29, 230, 13, 84, 28, 42, 13, 241, 26, 44, 12, 61, 25, 248, 10, 73, 23, 151, 9, 45, 21, 24, 8, 0, 19, 142, 6, 215, 16, 11, 5, 200, 14, 162, 3, 228, 12, 99, 2, 55, 11, 93, 1, 208, 9, 152, 0, 181, 8, 24, 0, 229, 7, 222, 255, 96, 7, 225, 255, 28, 7, 26, 0, 12, 7, 130, 0, 34, 7, 9, 1, 73, 7, 159, 1, 110, 7, 50, 2, 121, 7, 173, 2, 86, 7, 254, 2, 245, 6, 22, 3, 74, 6, 238, 2, 83, 5, 134, 2, 14, 4, 223, 1, 132, 2, 3, 1, 189, 0, 252, 255, 205, 254, 212, 254, 190, 252, 153, 253, 165, 250, 88, 252, 148, 248, 31, 251, 156, 246, 248, 249, 202, 244, 241, 248, 46, 243, 15, 248, 213, 241, 93, 247, 202, 240, 232, 246, 27, 240, 181, 246, 205, 239, 207, 246, 226, 239, 50, 247, 84, 240, 224, 247, 26, 241, 205, 248, 36, 242, 237, 249, 96, 243, 49, 251, 186, 244, 131, 252, 31, 246, 208, 253, 122, 247, 3, 255, 184, 248, 7, 0, 205, 249, 208, 0, 172, 250, 85, 1, 78, 251, 145, 1, 176, 251, 132, 1, 205, 251, 50, 1, 170, 251, 163, 0, 76, 251, 227, 255, 180, 250, 246, 254, 229, 249, 228, 253, 230, 248, 177, 252, 188, 247, 102, 251, 113, 246, 11, 250, 17, 245, 168, 248, 171, 243, 73, 247, 76, 242, 249, 245, 2, 241, 194, 244, 218, 239, 175, 243, 225, 238, 199, 242, 30, 238, 15, 242, 156, 237, 139, 241, 98, 237, 59, 241, 116, 237, 27, 241, 209, 237, 41, 241, 115, 238, 93, 241, 87, 239, 174, 241, 114, 240, 24, 242, 182, 241, 145, 242, 21, 243, 17, 243, 131, 244, 146, 243, 243, 245, 15, 244, 88, 247, 133, 244, 167, 248, 242, 244, 217, 249, 88, 245, 234, 250, 185, 245, 214, 251, 21, 246, 158, 252, 112, 246, 68, 253, 202, 246, 203, 253, 35, 247, 55, 254, 126, 247, 141, 254, 219, 247, 214, 254, 57, 248, 24, 255, 155, 248, 95, 255, 2, 249, 183, 255, 115, 249, 50, 0, 251, 249, 230, 0, 171, 250, 227, 1, 146, 251, 54, 3, 184, 252, 228, 4, 38, 254, 233, 6, 219, 255, 63, 9, 210, 1, 213, 11, 0, 4, 151, 14, 85, 6, 113, 17, 188, 8, 70, 20, 31, 11, 255, 22, 107, 13, 134, 25, 141, 15, 197, 27, 118, 17, 169, 29, 23, 19, 36, 31, 106, 20, 44, 32, 107, 21, 187, 32, 27, 22, 207, 32, 125, 22, 105, 32, 145, 22, 139, 31, 88, 22, 57, 30, 213, 21, 129, 28, 11, 21, 113, 26, 3, 20, 26, 24, 198, 18, 147, 21, 96, 17, 241, 18, 224, 15, 78, 16, 89, 14, 190, 13, 222, 12, 83, 11, 125, 11, 32, 9, 72, 10, 52, 7, 75, 9, 151, 5, 140, 8, 80, 4, 14, 8, 93, 3, 207, 7, 186, 2, 202, 7, 92, 2, 248, 7, 52, 2, 77, 8, 50, 2, 188, 8, 64, 2, 50, 9, 72, 2, 158, 9, 54, 2, 237, 9, 248, 1, 18, 10, 128, 1, 3, 10, 201, 0, 190, 9, 208, 255, 68, 9, 151, 254, 151, 8, 37, 253, 190, 7, 136, 251, 194, 6, 206, 249, 173, 5, 3, 248, 136, 4, 57, 246, 97, 3, 129, 244, 64, 2, 232, 242, 50, 1, 125, 241, 63, 0, 80, 240, 113, 255, 112, 239, 210, 254, 234, 238, 110, 254, 201, 238, 78, 254, 14, 239, 118, 254, 184, 239, 229, 254, 191, 240, 151, 255, 23, 242, 128, 0, 175, 243, 147, 1, 113, 245, 193, 2, 73, 247, 243, 3, 33, 249, 23, 5, 230, 250, 27, 6, 134, 252, 238, 6, 240, 253, 131, 7, 30, 255, 214, 7, 4, 0, 226, 7, 160, 0, 165, 7, 241, 0, 39, 7, 247, 0, 107, 6, 181, 0, 121, 5, 43, 0, 84, 4, 93, 255, 1, 3, 80, 254, 134, 1, 10, 253, 234, 255, 153, 251, 53, 254, 8, 250, 110, 252, 103, 248, 160, 250, 195, 246, 218, 248, 44, 245, 36, 247, 175, 243, 137, 245, 89, 242, 17, 244, 55, 241, 193, 242, 82, 240, 158, 241, 177, 239, 170, 240, 84, 239, 227, 239, 60, 239, 69, 239, 100, 239, 203, 238, 191, 239, 114, 238, 71, 240, 48, 238, 239, 240, 0, 238, 169, 241, 219, 237, 105, 242, 188, 237, 34, 243, 160, 237, 205, 243, 133, 237, 98, 244, 105, 237, 218, 244, 79, 237, 52, 245, 54, 237, 112, 245, 31, 237, 143, 245, 11, 237, 148, 245, 248, 236, 130, 245, 232, 236, 94, 245, 218, 236, 45, 245, 208, 236, 249, 244, 200, 236, 202, 244, 197, 236, 173, 244, 204, 236, 183, 244, 232, 236, 250, 244, 39, 237, 138, 245, 155, 237, 117, 246, 78, 238, 194, 247, 72, 239, 117, 249, 141, 240, 136, 251, 28, 242, 239, 253, 235, 243, 151, 0, 238, 245, 111, 3, 20, 248, 96, 6, 74, 250, 81, 9, 127, 252, 40, 12, 160, 254, 211, 14, 157, 0, 59, 17, 107, 2, 81, 19, 0, 4, 6, 21, 86, 5, 84, 22, 105, 6, 54, 23, 58, 7, 167, 23, 200, 7, 171, 23, 19, 8, 65, 23, 27, 8, 114, 22, 227, 7, 74, 21, 110, 7, 217, 19, 197, 6, 48, 18, 242, 5, 102, 16, 2, 5, 143, 14, 5, 4, 193, 12, 14, 3, 17, 11, 44, 2, 143, 9, 112, 1, 76, 8, 232, 0, 85, 7, 155, 0, 175, 6, 143, 0, 91, 6, 198, 0, 87, 6, 61, 1, 155, 6, 236, 1, 26, 7, 206, 2, 195, 7, 214, 3, 131, 8, 242, 4, 68, 9, 18, 6, 239, 9, 35, 7, 114, 10, 23, 8, 188, 10, 224, 8, 194, 10, 120, 9, 126, 10, 221, 9, 237, 9, 15, 10, 22, 9, 16, 10, 0, 8, 227, 9, 181, 6, 143, 9, 65, 5, 27, 9, 178, 3, 144, 8, 22, 2, 249, 7, 126, 0, 92, 7, 248, 254, 198, 6, 148, 253, 62, 6, 99, 252, 208, 5, 118, 251, 138, 5, 218, 250, 119, 5, 151, 250, 159, 5, 176, 250, 3, 6, 33, 251, 165, 6, 226, 251, 126, 7, 230, 252, 131, 8, 28, 254, 167, 9, 112, 255, 217, 10, 206, 0, 8, 12, 35, 2, 37, 13, 93, 3, 30, 14, 108, 4, 231, 14, 67, 5, 117, 15, 217, 5, 196, 15, 40, 6, 207, 15, 44, 6, 152, 15, 229, 5, 34, 15, 82, 5, 113, 14, 116, 4, 136, 13, 77, 3, 103, 12, 222, 1, 20, 11, 49, 0, 148, 9, 81, 254, 239, 7, 69, 252, 46, 6, 33, 250, 89, 4, 243, 247, 124, 2, 204, 245, 163, 0, 187, 243, 219, 254, 207, 241, 43, 253, 26, 240, 157, 251, 166, 238, 56, 250, 122, 237, 254, 248, 156, 236, 242, 247, 12, 236, 20, 247, 197, 235, 96, 246, 193, 235, 208, 245, 246, 235, 98, 245, 88, 236, 13, 245, 219, 236, 203, 244, 114, 237, 152, 244, 18, 238, 110, 244, 175, 238, 74, 244, 68, 239, 42, 244, 199, 239, 15, 244, 52, 240, 246, 243, 140, 240, 226, 243, 206, 240, 206, 243, 251, 240, 186, 243, 22, 241, 166, 243, 34, 241, 145, 243, 35, 241, 125, 243, 32, 241, 105, 243, 34, 241, 87, 243, 54, 241, 77, 243, 108, 241, 82, 243, 218, 241, 117, 243, 148, 242, 199, 243, 170, 243, 84, 244, 38, 245, 38, 245, 13, 247, 66, 246, 93, 249, 168, 247, 11, 252, 81, 249, 10, 255, 50, 251, 67, 2, 61, 253, 163, 5, 98, 255, 17, 9, 140, 1, 114, 12, 175, 3, 175, 15, 184, 5, 176, 18, 153, 7, 98, 21, 70, 9, 180, 23, 183, 10, 156, 25, 230, 11, 19, 27, 208, 12, 17, 28, 114, 13, 147, 28, 202, 13, 154, 28, 214, 13, 42, 28, 149, 13, 74, 27, 13, 13, 10, 26, 65, 12, 120, 24, 58, 11, 168, 22, 4, 10, 178, 20, 174, 8, 169, 18, 73, 7, 163, 16, 230, 5, 181, 14, 151, 4, 241, 12, 107, 3, 105, 11, 110, 2, 35, 10, 168, 1, 39, 9, 30, 1, 115, 8, 208, 0, 5, 8, 189, 0, 212, 7, 223, 0, 209, 7, 43, 1, 237, 7, 150, 1, 18, 8, 15, 2, 45, 8, 135, 2, 41, 8, 237, 2, 246, 7, 56, 3, 137, 7, 96, 3, 216, 6, 95, 3, 226, 5, 52, 3, 166, 4, 222, 2, 43, 3, 93, 2, 121, 1, 183, 1, 156, 255, 239, 0, 157, 253, 15, 0, 140, 251, 29, 255, 119, 249, 31, 254, 112, 247, 33, 253, 135, 245, 43, 252, 207, 243, 73, 251, 90, 242, 137, 250, 56, 241, 248, 249, 117, 240, 160, 249, 22, 240, 133, 249, 29, 240, 169, 249, 130, 240, 11, 250, 62, 241, 161, 250, 65, 242, 98, 251, 120, 243, 63, 252, 211, 244, 44, 253, 60, 246, 23, 254, 160, 247, 245, 254, 241, 248, 183, 255, 30, 250, 81, 0, 29, 251, 189, 0, 228, 251, 248, 0, 111, 252, 254, 0, 189, 252, 209, 0, 200, 252, 115, 0, 146, 252, 230, 255, 24, 252, 40, 255, 93, 251, 60, 254, 101, 250, 39, 253, 56, 249, 239, 251, 224, 247, 153, 250, 107, 246, 46, 249, 230, 244, 185, 247, 97, 243, 68, 246, 238, 241, 219, 244, 158, 240, 136, 243, 127, 239, 87, 242, 160, 238, 80, 241, 9, 238, 119, 240, 190, 237, 209, 239, 193, 237, 94, 239, 14, 238, 29, 239, 159, 238, 12, 239, 106, 239, 36, 239, 100, 240, 96, 239, 128, 241, 184, 239, 178, 242, 41, 240, 236, 243, 170, 240, 35, 245, 55, 241, 78, 246, 205, 241, 99, 247, 105, 242, 95, 248, 9, 243, 60, 249, 169, 243, 249, 249, 70, 244, 150, 250, 220, 244, 17, 251, 107, 245, 111, 251, 239, 245, 177, 251, 105, 246, 223, 251, 215, 246, 254, 251, 62, 247, 26, 252, 157, 247, 67, 252, 253, 247, 140, 252, 108, 248, 11, 253, 247, 248, 208, 253, 174, 249, 234, 254, 158, 250, 96, 0, 202, 251, 53, 2, 57, 253, 100, 4, 227, 254, 227, 6, 196, 0, 161, 9, 210, 2, 138, 12, 255, 4, 139, 15, 60, 7, 138, 18, 120, 9, 112, 21, 167, 11, 37, 24, 184, 13, 150, 26, 159, 15, 177, 28, 81, 17, 105, 30, 201, 18, 183, 31, 0, 20, 146, 32, 243, 20, 247, 32, 156, 21, 225, 32, 250, 21, 81, 32, 8, 22, 72, 31, 195, 21, 211, 29, 51, 21, 8, 28, 97, 20, 244, 25, 83, 19, 173, 23, 26, 18, 71, 21, 194, 16, 219, 18, 95, 15, 124, 16, 255, 13, 63, 14, 180, 12, 52, 12, 139, 11, 102, 10, 142, 10, 223, 8, 197, 9, 161, 7, 51, 9, 172, 6, 218, 8, 249, 5, 182, 8, 131, 5, 193, 8, 58, 5, 243, 8, 13, 5, 61, 9, 233, 4, 146, 9, 188, 4, 230, 9, 117, 4, 42, 10, 7, 4, 88, 10, 103, 3, 104, 10, 144, 2, 86, 10, 129, 1, 32, 10, 57, 0, 195, 9, 195, 254, 63, 9, 30, 253, 152, 8, 88, 251, 210, 7, 127, 249, 244, 6, 156, 247, 2, 6, 194, 245, 6, 5, 254, 243, 9, 4, 98, 242, 21, 3, 1, 241, 54, 2, 236, 239, 123, 1, 49, 239, 238, 0, 216, 238, 152, 0, 230, 238, 126, 0, 87, 239, 157, 0, 37, 240, 243, 0, 70, 241, 119, 1, 168, 242, 33, 2, 59, 244, 227, 2, 236, 245, 177, 3, 167, 247, 124, 4, 89, 249, 56, 5, 243, 250, 218, 5, 103, 252, 86, 6, 169, 253, 166, 6, 177, 254, 199, 6, 122, 255, 180, 6, 255, 255, 111, 6, 59, 0, 244, 5, 45, 0, 69, 5, 212, 255, 94, 4, 47, 255, 67, 3, 67, 254, 248, 1, 26, 253, 130, 0, 192, 251, 231, 254, 63, 250, 48, 253, 169, 248, 103, 251, 16, 247, 153, 249, 133, 245, 210, 247, 24, 244, 29, 246, 216, 242, 134, 244, 209, 241, 17, 243, 6, 241, 200, 241, 126, 240, 172, 240, 57, 240, 192, 239, 48, 240, 2, 239, 94, 240, 111, 238, 186, 240, 5, 238, 57, 241, 187, 237, 207, 241, 143, 237, 114, 242, 122, 237, 25, 243, 121, 237, 183, 243, 135, 237, 70, 244, 162, 237, 193, 244, 196, 237, 35, 245, 235, 237, 104, 245, 19, 238, 144, 245, 56, 238, 155, 245, 87, 238, 137, 245, 110, 238, 95, 245, 122, 238, 34, 245, 125, 238, 214, 244, 120, 238, 136, 244, 108, 238, 67, 244, 94, 238, 26, 244, 92, 238, 33, 244, 114, 238, 108, 244, 177, 238, 11, 245, 34, 239, 5, 246, 207, 239, 99, 247, 188, 240, 34, 249, 232, 241, 58, 251, 78, 243, 162, 253, 232, 244, 70, 0, 172, 246, 22, 3, 141, 248, 252, 5, 127, 250, 226, 8, 114, 252, 176, 11, 93, 254, 80, 14, 47, 0, 181, 16, 224, 1, 206, 18, 106, 3, 146, 20, 196, 4, 247, 21, 232, 5, 249, 22, 211, 6, 145, 23, 127, 7, 188, 23, 232, 7, 127, 23, 12, 8, 222, 22, 239, 7, 229, 21, 146, 7, 160, 20, 254, 6, 32, 19, 61, 6, 123, 17, 92, 5, 196, 15, 105, 4, 16, 14, 117, 3, 115, 12, 144, 2, 251, 10, 200, 1, 184, 9, 38, 1, 179, 8, 184, 0, 241, 7, 128, 0, 116, 7, 129, 0, 58, 7, 188, 0, 61, 7, 44, 1, 114, 7, 204, 1, 202, 7, 141, 2, 52, 8, 103, 3, 159, 8, 76, 4, 248, 8, 48, 5, 49, 9, 11, 6, 61, 9, 210, 6, 21, 9, 126, 7, 179, 8, 11, 8, 17, 8, 115, 8, 54, 7, 181, 8, 33, 6, 206, 8, 219, 4, 194, 8, 111, 3, 147, 8, 231, 1, 70, 8, 81, 0, 225, 7, 188, 254, 107, 7, 54, 253, 238, 6, 211, 251, 118, 6, 163, 250, 15, 6, 185, 249, 200, 5, 31, 249, 169, 5, 221, 248, 184, 5, 243, 248, 248, 5, 95, 249, 104, 6, 26, 250, 2, 7, 24, 251, 193, 7, 75, 252, 154, 8, 161, 253, 132, 9, 9, 255, 115, 10, 113, 0, 92, 11, 201, 1, 49, 12, 4, 3, 235, 12, 19, 4, 127, 13, 237, 4, 232, 13, 139, 5, 35, 14, 233, 5, 42, 14, 0, 6, 254, 13, 204, 5, 155, 13, 75, 5, 254, 12, 123, 4, 41, 12, 95, 3, 26, 11, 254, 1, 214, 9, 97, 0, 99, 8, 149, 254, 199, 6, 165, 252, 11, 5, 168, 250, 59, 3, 174, 248, 99, 1, 201, 246, 146, 255, 8, 245, 208, 253, 120, 243, 39, 252, 34, 242, 162, 250, 11, 241, 69, 249, 55, 240, 21, 248, 163, 239, 18, 247, 76, 239, 61, 246, 41, 239, 147, 245, 53, 239, 17, 245, 102, 239, 178, 244, 176, 239, 113, 244, 10, 240, 77, 244, 107, 240, 64, 244, 203, 240, 67, 244, 35, 241, 85, 244, 111, 241, 112, 244, 168, 241, 145, 244, 204, 241, 176, 244, 218, 241, 203, 244, 212, 241, 223, 244, 186, 241, 232, 244, 146, 241, 230, 244, 97, 241, 216, 244, 43, 241, 193, 244, 255, 240, 164, 244, 235, 240, 139, 244, 1, 241, 132, 244, 89, 241, 158, 244, 255, 241, 228, 244, 3, 243, 98, 245, 108, 244, 28, 246, 58, 246, 22, 247, 107, 248, 78, 248, 246, 250, 189, 249, 204, 253, 95, 251, 218, 0, 38, 253, 14, 4, 8, 255, 80, 7, 245, 0, 138, 10, 229, 2, 164, 13, 200, 4, 140, 16, 145, 6, 49, 19, 56, 8, 134, 21, 179, 9, 129, 23, 253, 10, 23, 25, 11, 12, 66, 26, 217, 12, 252, 26, 98, 13, 66, 27, 159, 13, 21, 27, 144, 13, 128, 26, 55, 13, 139, 25, 155, 12, 71, 24, 194, 11, 197, 22, 185, 10, 24, 21, 141, 9, 86, 19, 77, 8, 146, 17, 11, 7, 222, 15, 214, 5, 72, 14, 185, 4, 222, 12, 194, 3, 166, 11, 246, 2, 167, 10, 94, 2, 225, 9, 250, 1, 82, 9, 201, 1, 244, 8, 200, 1, 189, 8, 239, 1, 157, 8, 52, 2, 134, 8, 142, 2, 104, 8, 242, 2, 49, 8, 84, 3, 217, 7, 172, 3, 82, 7, 242, 3, 151, 6, 31, 4, 163, 5, 44, 4, 116, 4, 22, 4, 12, 3, 218, 3, 114, 1, 119, 3, 175, 255, 239, 2, 202, 253, 70, 2, 207, 251, 128, 1, 208, 249, 164, 0, 216, 247, 188, 255, 249, 245, 208, 254, 72, 244, 239, 253, 213, 242, 38, 253, 175, 241, 129, 252, 225, 240, 6, 252, 112, 240, 187, 251, 92, 240, 161, 251, 161, 240, 183, 251, 56, 241, 249, 251, 21, 242, 98, 252, 42, 243, 229, 252, 102, 244, 126, 253, 186, 245, 32, 254, 20, 247, 192, 254, 102, 248, 84, 255, 162, 249, 211, 255, 186, 250, 53, 0, 169, 251, 119, 0, 103, 252, 148, 0, 235, 252, 137, 0, 51, 253, 79, 0, 55, 253, 232, 255, 244, 252, 77, 255, 106, 252, 126, 254, 156, 251, 126, 253, 145, 250, 79, 252, 84, 249, 249, 250, 243, 247, 130, 249, 125, 246, 247, 247, 5, 245, 98, 246, 156, 243, 207, 244, 81, 242, 78, 243, 50, 241, 230, 241, 71, 240, 161, 240, 154, 239, 138, 239, 44, 239, 160, 238, 1, 239, 235, 237, 17, 239, 105, 237, 92, 239, 25, 237, 218, 239, 249, 236, 127, 240, 6, 237, 68, 241, 59, 237, 30, 242, 150, 237, 5, 243, 17, 238, 238, 243, 163, 238, 208, 244, 74, 239, 165, 245, 255, 239, 103, 246, 186, 240, 15, 247, 120, 241, 156, 247, 47, 242, 13, 248, 223, 242, 97, 248, 130, 243, 157, 248, 22, 244, 197, 248, 154, 244, 222, 248, 14, 245, 240, 248, 117, 245, 8, 249, 215, 245, 55, 249, 64, 246, 146, 249, 189, 246, 42, 250, 92, 247, 13, 251, 38, 248, 71, 252, 35, 249, 218, 253, 86, 250, 201, 255, 194, 251, 11, 2, 99, 253, 153, 4, 51, 255, 101, 7, 42, 1, 89, 10, 64, 3, 99, 13, 106, 5, 110, 16, 153, 7, 99, 19, 194, 9, 49, 22, 218, 11, 197, 24, 212, 13, 16, 27, 169, 15, 8, 29, 80, 17, 162, 30, 191, 18, 215, 31, 240, 19, 158, 32, 221, 20, 241, 32, 126, 21, 212, 32, 209, 21, 70, 32, 213, 21, 81, 31, 141, 21, 255, 29, 254, 20, 97, 28, 51, 20, 139, 26, 55, 19, 141, 24, 25, 18, 124, 22, 232, 16, 103, 20, 177, 15, 96, 18, 132, 14, 121, 16, 112, 13, 187, 14, 124, 12, 46, 13, 177, 11, 214, 11, 19, 11, 181, 10, 165, 10, 201, 9, 100, 10, 11, 9, 77, 10, 114, 8, 89, 10, 240, 7, 128, 10, 118, 7, 185, 10, 249, 6, 252, 10, 106, 6, 61, 11, 191, 5, 116, 11, 240, 4, 156, 11, 244, 3, 171, 11, 201, 2, 156, 11, 110, 1, 106, 11, 230, 255, 18, 11, 55, 254, 149, 10, 105, 252, 244, 9, 134, 250, 51, 9, 154, 248, 88, 8, 180, 246, 104, 7, 225, 244, 110, 6, 51, 243, 119, 5, 189, 241, 144, 4, 141, 240, 194, 3, 176, 239, 24, 3, 44, 239, 154, 2, 7, 239, 72, 2, 64, 239, 38, 2, 208, 239, 48, 2, 175, 240, 100, 2, 209, 241, 187, 2, 38, 243, 45, 3, 161, 244, 177, 3, 49, 246, 60, 4, 197, 247, 195, 4, 79, 249, 63, 5, 194, 250, 167, 5, 18, 252, 244, 5, 56, 253, 31, 6, 42, 254, 36, 6, 225, 254, 0, 6, 85, 255, 172, 5, 129, 255, 35, 5, 97, 255, 99, 4, 246, 254, 109, 3, 67, 254, 63, 2, 81, 253, 223, 0, 44, 252, 86, 255, 224, 250, 168, 253, 127, 249, 227, 251, 25, 248, 20, 250, 188, 246, 69, 248, 117, 245, 131, 246, 80, 244, 215, 244, 84, 243, 75, 243, 137, 242, 229, 241, 241, 241, 170, 240, 140, 241, 157, 239, 87, 241, 190, 238, 79, 241, 12, 238, 109, 241, 135, 237, 170, 241, 43, 237, 253, 241, 246, 236, 95, 242, 227, 236, 200, 242, 236, 236, 48, 243, 14, 237, 144, 243, 65, 237, 225, 243, 129, 237, 32, 244, 196, 237, 71, 244, 7, 238, 84, 244, 69, 238, 74, 244, 120, 238, 43, 244, 157, 238, 249, 243, 181, 238, 185, 243, 190, 238, 114, 243, 186, 238, 44, 243, 173, 238, 247, 242, 162, 238, 229, 242, 166, 238, 7, 243, 197, 238, 108, 243, 11, 239, 34, 244, 125, 239, 48, 245, 36, 240, 151, 246, 2, 241, 87, 248, 22, 242, 107, 250, 95, 243, 197, 252, 215, 244, 87, 255, 119, 246, 15, 2, 52, 248, 223, 4, 6, 250, 177, 7, 225, 251, 114, 10, 187, 253, 18, 13, 136, 255, 131, 15, 63, 1, 183, 17, 216, 2, 164, 19, 76, 4, 65, 21, 146, 5, 133, 22, 160, 6, 103, 23, 112, 7, 229, 23, 255, 7, 255, 23, 72, 8, 184, 23, 78, 8, 25, 23, 18, 8, 48, 22, 158, 7, 9, 21, 252, 6, 182, 19, 54, 6, 71, 18, 93, 5, 205, 16, 126, 4, 90, 15, 166, 3, 247, 13, 226, 2, 180, 12, 59, 2, 152, 11, 189, 1, 168, 10, 105, 1, 235, 9, 69, 1, 94, 9, 82, 1, 0, 9, 142, 1, 202, 8, 244, 1, 176, 8, 127, 2, 168, 8, 39, 3, 164, 8, 224, 3, 152, 8, 164, 4, 119, 8, 106, 5, 56, 8, 38, 6, 209, 7, 208, 6, 61, 7, 99, 7, 121, 6, 214, 7, 133, 5, 38, 8, 100, 4, 81, 8, 28, 3, 86, 8, 181, 1, 56, 8, 56, 0, 251, 7, 179, 254, 162, 7, 45, 253, 52, 7, 185, 251, 192, 6, 101, 250, 78, 6, 67, 249, 234, 5, 96, 248, 156, 5, 196, 247, 111, 5, 119, 247, 101, 5, 124, 247, 130, 5, 207, 247, 198, 5, 108, 248, 47, 6, 73, 249, 187, 6, 92, 250, 98, 7, 152, 251, 27, 8, 237, 252, 226, 8, 78, 254, 169, 9, 174, 255, 105, 10, 252, 0, 27, 11, 48, 2, 180, 11, 64, 3, 50, 12, 34, 4, 141, 12, 207, 4, 192, 12, 62, 5, 195, 12, 104, 5, 148, 12, 71, 5, 43, 12, 216, 4, 134, 11, 31, 4, 166, 10, 31, 3, 140, 9, 229, 1, 61, 8, 123, 0, 191, 6, 239, 254, 31, 5, 80, 253, 104, 3, 171, 251, 164, 1, 15, 250, 225, 255, 134, 248, 40, 254, 28, 247, 130, 252, 216, 245, 249, 250, 192, 244, 147, 249, 214, 243, 83, 248, 27, 243, 62, 247, 141, 242, 85, 246, 40, 242, 152, 245, 232, 241, 6, 245, 198, 241, 156, 244, 189, 241, 88, 244, 199, 241, 54, 244, 218, 241, 47, 244, 241, 241, 62, 244, 4, 242, 95, 244, 15, 242, 136, 244, 12, 242, 181, 244, 251, 241, 223, 244, 219, 241, 2, 245, 172, 241, 25, 245, 113, 241, 35, 245, 47, 241, 30, 245, 233, 240, 12, 245, 167, 240, 240, 244, 116, 240, 209, 244, 97, 240, 187, 244, 124, 240, 186, 244, 214, 240, 216, 244, 125, 241, 31, 245, 122, 242, 151, 245, 210, 243, 67, 246, 134, 245, 39, 247, 146, 247, 65, 248, 237, 249, 143, 249, 140, 252, 11, 251, 95, 255, 172, 252, 85, 2, 106, 254, 93, 5, 58, 0, 102, 8, 18, 2, 92, 11, 233, 3, 49, 14, 178, 5, 213, 16, 101, 7, 61, 19, 247, 8, 94, 21, 97, 10, 44, 23, 152, 11, 158, 24, 147, 12, 173, 25, 77, 13, 84, 26, 191, 13, 149, 26, 232, 13, 115, 26, 201, 13, 249, 25, 103, 13, 48, 25, 200, 12, 39, 24, 250, 11, 237, 22, 7, 11, 142, 21, 253, 9, 28, 20, 233, 8, 163, 18, 217, 7, 52, 17, 217, 6, 215, 15, 242, 5, 149, 14, 44, 5, 118, 13, 140, 4, 123, 12, 22, 4, 167, 11, 203, 3, 246, 10, 172, 3, 98, 10, 177, 3, 225, 9, 215, 3, 106, 9, 21, 4, 241, 8, 100, 4, 108, 8, 185, 4, 207, 7, 11, 5, 16, 7, 84, 5, 43, 6, 136, 5, 26, 5, 162, 5, 220, 3, 155, 5, 114, 2, 112, 5, 226, 0, 31, 5, 50, 255, 170, 4, 103, 253, 17, 4, 140, 251, 89, 3, 173, 249, 135, 2, 215, 247, 165, 1, 26, 246, 191, 0, 134, 244, 224, 255, 39, 243, 16, 255, 11, 242, 89, 254, 58, 241, 194, 253, 184, 240, 80, 253, 137, 240, 4, 253, 169, 240, 226, 252, 19, 241, 231, 252, 191, 241, 14, 253, 162, 242, 83, 253, 175, 243, 174, 253, 219, 244, 25, 254, 24, 246, 137, 254, 89, 247, 249, 254, 146, 248, 95, 255, 184, 249, 182, 255, 194, 250, 248, 255, 167, 251, 28, 0, 95, 252, 33, 0, 224, 252, 254, 255, 35, 253, 171, 255, 38, 253, 37, 255, 229, 252, 106, 254, 102, 252, 123, 253, 176, 251, 91, 252, 201, 250, 16, 251, 191, 249, 163, 249, 157, 248, 31, 248, 114, 247, 142, 246, 72, 246, 251, 244, 43, 245, 114, 243, 36, 244, 252, 241, 61, 243, 162, 240, 125, 242, 109, 239, 230, 241, 98, 238, 122, 241, 132, 237, 58, 241, 214, 236, 37, 241, 89, 236, 53, 241, 14, 236, 104, 241, 243, 235, 183, 241, 4, 236, 28, 242, 63, 236, 144, 242, 158, 236, 11, 243, 25, 237, 136, 243, 173, 237, 255, 243, 80, 238, 108, 244, 253, 238, 205, 244, 171, 239, 29, 245, 87, 240, 95, 245, 251, 240, 145, 245, 147, 241, 184, 245, 29, 242, 214, 245, 152, 242, 238, 245, 7, 243, 11, 246, 109, 243, 55, 246, 212, 243, 129, 246, 69, 244, 247, 246, 205, 244, 167, 247, 114, 245, 155, 248, 62, 246, 219, 249, 54, 247, 106, 251, 94, 248, 71, 253, 183, 249, 107, 255, 64, 251, 205, 1, 245, 252, 103, 4, 208, 254, 39, 7, 201, 0, 255, 9, 217, 2, 223, 12, 247, 4, 183, 15, 24, 7, 119, 18, 49, 9, 19, 21, 57, 11, 123, 23, 39, 13, 167, 25, 243, 14, 140, 27, 145, 16, 28, 29, 249, 17, 82, 30, 32, 19, 37, 31, 4, 20, 145, 31, 156, 20, 153, 31, 231, 20, 70, 31, 235, 20, 156, 30, 171, 20, 169, 29, 49, 20, 119, 28, 136, 19, 20, 27, 187, 18, 141, 25, 215, 17, 240, 23, 231, 16, 76, 22, 250, 15, 169, 20, 23, 15, 19, 19, 69, 14, 145, 17, 144, 13, 44, 16, 251, 12, 229, 14, 137, 12, 189, 13, 61, 12, 179, 12, 20, 12, 193, 11, 13, 12, 224, 10, 33, 12, 9, 10, 73, 12, 49, 9, 124, 12, 78, 8, 180, 12, 88, 7, 230, 12, 73, 6, 10, 13, 27, 5, 26, 13, 205, 3, 16, 13, 93, 2, 230, 12, 206, 0, 152, 12, 40, 255, 40, 12, 107, 253, 150, 11, 160, 251, 228, 10, 208, 249, 23, 10, 5, 248, 53, 9, 78, 246, 70, 8, 183, 244, 86, 7, 78, 243, 109, 6, 30, 242, 151, 5, 50, 241, 216, 4, 145, 240, 56, 4, 61, 240, 189, 3, 54, 240, 102, 3, 125, 240, 54, 3, 9, 241, 43, 3, 212, 241, 63, 3, 209, 242, 112, 3, 248, 243, 181, 3, 60, 245, 9, 4, 144, 246, 98, 4, 233, 247, 185, 4, 60, 249, 9, 5, 126, 250, 74, 5, 165, 251, 119, 5, 169, 252, 135, 5, 127, 253, 116, 5, 32, 254, 55, 5, 132, 254, 200, 4, 170, 254, 37, 4, 144, 254, 76, 3, 59, 254, 63, 2, 176, 253, 1, 1, 247, 252, 154, 255, 25, 252, 16, 254, 32, 251, 109, 252, 23, 250, 188, 250, 9, 249, 7, 249, 254, 247, 89, 247, 255, 246, 187, 245, 20, 246, 53, 244, 66, 245, 204, 242, 141, 244, 136, 241, 247, 243, 108, 240, 130, 243, 123, 239, 42, 243, 182, 238, 240, 242, 31, 238, 207, 242, 178, 237, 194, 242, 109, 237, 198, 242, 76, 237, 210, 242, 74, 237, 227, 242, 98, 237, 243, 242, 143, 237, 253, 242, 198, 237, 0, 243, 5, 238, 247, 242, 65, 238, 228, 242, 123, 238, 197, 242, 169, 238, 155, 242, 205, 238, 108, 242, 228, 238, 56, 242, 238, 238, 7, 242, 238, 238, 224, 241, 233, 238, 209, 241, 235, 238, 228, 241, 250, 238, 40, 242, 33, 239, 168, 242, 105, 239, 107, 243, 216, 239, 120, 244, 114, 240, 206, 245, 59, 241, 109, 247, 52, 242, 79, 249, 91, 243, 109, 251, 173, 244, 188, 253, 36, 246, 46, 0, 188, 247, 185, 2, 106, 249, 79, 5, 39, 251, 227, 7, 235, 252, 102, 10, 170, 254, 205, 12, 94, 0, 12, 15, 254, 1, 25, 17, 129, 3, 233, 18, 221, 4, 113, 20, 8, 6, 171, 21, 253, 6, 148, 22, 181, 7, 38, 23, 46, 8, 104, 23, 104, 8, 90, 23, 100, 8, 4, 23, 43, 8, 112, 22, 196, 7, 166, 21, 57, 7, 179, 20, 149, 6, 160, 19, 228, 5, 124, 18, 47, 5, 80, 17, 131, 4, 38, 16, 231, 3, 9, 15, 98, 3, 252, 13, 253, 2, 8, 13, 189, 2, 47, 12, 165, 2, 113, 11, 180, 2, 204, 10, 234, 2, 59, 10, 66, 3, 183, 9, 182, 3, 55, 9, 63, 4, 179, 8, 213, 4, 37, 8, 112, 5, 132, 7, 7, 6, 202, 6, 147, 6, 244, 5, 10, 7, 0, 5, 105, 7, 239, 3, 171, 7, 193, 2, 204, 7, 124, 1, 205, 7, 35, 0, 173, 7, 192, 254, 112, 7, 88, 253, 26, 7, 245, 251, 178, 6, 165, 250, 63, 6, 113, 249, 204, 5, 104, 248, 97, 5, 145, 247, 4, 5, 244, 246, 192, 4, 151, 246, 152, 4, 125, 246, 143, 4, 166, 246, 167, 4, 15, 247, 224, 4, 178, 247, 57, 5, 137, 248, 173, 5, 139, 249, 56, 6, 173, 250, 209, 6, 229, 251, 118, 7, 40, 253, 28, 8, 106, 254, 191, 8, 162, 255, 86, 9, 199, 0, 220, 9, 209, 1, 75, 10, 179, 2, 154, 10, 103, 3, 193, 10, 228, 3, 184, 10, 39, 4, 123, 10, 46, 4, 6, 10, 247, 3, 88, 9, 135, 3, 116, 8, 227, 2, 93, 7, 17, 2, 27, 6, 25, 1, 182, 4, 4, 0, 54, 3, 219, 254, 166, 1, 167, 253, 16, 0, 112, 252, 125, 254, 64, 251, 246, 252, 27, 250, 130, 251, 9, 249, 39, 250, 13, 248, 237, 248, 42, 247, 216, 247, 98, 246, 234, 246, 180, 245, 38, 246, 32, 245, 138, 245, 163, 244, 23, 245, 58, 244, 200, 244, 224, 243, 154, 244, 145, 243, 137, 244, 73, 243, 143, 244, 3, 243, 164, 244, 191, 242, 196, 244, 122, 242, 232, 244, 49, 242, 10, 245, 230, 241, 39, 245, 153, 241, 58, 245, 74, 241, 66, 245, 254, 240, 62, 245, 184, 240, 47, 245, 126, 240, 25, 245, 89, 240, 3, 245, 86, 240, 247, 244, 128, 240, 252, 244, 225, 240, 28, 245, 132, 241, 96, 245, 109, 242, 205, 245, 161, 243, 103, 246, 31, 245, 50, 247, 230, 246, 46, 248, 239, 248, 88, 249, 50, 251, 171, 250, 165, 253, 36, 252, 59, 0, 190, 253, 233, 2, 108, 255, 163, 5, 40, 1, 92, 8, 234, 2, 4, 11, 168, 4, 148, 13, 90, 6, 251, 15, 245, 7, 49, 18, 113, 9, 41, 20, 193, 10, 219, 21, 223, 11, 63, 23, 194, 12, 80, 24, 101, 13, 15, 25, 198, 13, 122, 25, 231, 13, 149, 25, 202, 13, 103, 25, 117, 13, 246, 24, 241, 12, 75, 24, 73, 12, 112, 23, 135, 11, 113, 22, 181, 10, 86, 21, 221, 9, 43, 20, 8, 9, 248, 18, 64, 8, 199, 17, 140, 7, 157, 16, 243, 6, 130, 15, 123, 6, 118, 14, 39, 6, 122, 13, 246, 5, 142, 12, 229, 5, 172, 11, 243, 5, 207, 10, 21, 6, 239, 9, 71, 6, 6, 9, 129, 6, 15, 8, 186, 6, 3, 7, 235, 6, 224, 5, 13, 7, 160, 4, 24, 7, 71, 3, 8, 7, 213, 1, 216, 6, 75, 0, 135, 6, 175, 254, 22, 6, 4, 253, 133, 5, 81, 251, 215, 4, 160, 249, 17, 4, 251, 247, 59, 3, 109, 246, 93, 2, 0, 245, 128, 1, 193, 243, 171, 0, 181, 242, 234, 255, 231, 241, 64, 255, 88, 241, 178, 254, 13, 241, 68, 254, 3, 241, 248, 253, 55, 241, 206, 253, 167, 241, 196, 253, 74, 242, 214, 253, 26, 243, 0, 254, 11, 244, 59, 254, 21, 245, 131, 254, 47, 246, 208, 254, 78, 247, 29, 255, 106, 248, 101, 255, 120, 249, 159, 255, 112, 250, 197, 255, 72, 251, 207, 255, 250, 251, 181, 255, 128, 252, 112, 255, 213, 252, 251, 254, 248, 252, 87, 254, 235, 252, 130, 253, 173, 252, 126, 252, 69, 252, 83, 251, 183, 251, 6, 250, 10, 251, 159, 248, 69, 250, 39, 247, 112, 249, 170, 245, 147, 248, 45, 244, 181, 247, 188, 242, 222, 246, 94, 241, 19, 246, 26, 240, 87, 245, 249, 238, 178, 244, 253, 237, 36, 244, 44, 237, 175, 243, 137, 236, 82, 243, 19, 236, 12, 243, 202, 235, 219, 242, 172, 235, 189, 242, 181, 235, 173, 242, 227, 235, 167, 242, 46, 236, 169, 242, 147, 236, 177, 242, 8, 237, 186, 242, 137, 237, 196, 242, 16, 238, 207, 242, 151, 238, 217, 242, 27, 239, 229, 242, 153, 239, 241, 242, 13, 240, 255, 242, 119, 240, 22, 243, 218, 240, 60, 243, 57, 241, 121, 243, 155, 241, 215, 243, 11, 242, 95, 244, 143, 242, 26, 245, 45, 243, 15, 246, 239, 243, 65, 247, 216, 244, 179, 248, 237, 245, 99, 250, 45, 247, 82, 252, 154, 248, 118, 254, 50, 250, 200, 0, 238, 251, 66, 3, 204, 253, 217, 5, 195, 255, 128, 8, 203, 1, 46, 11, 224, 3, 214, 13, 246, 5, 110, 16, 6, 8, 233, 18, 6, 10, 60, 21, 237, 11, 94, 23, 175, 13, 67, 25, 69, 15, 228, 26, 166, 16, 59, 28, 201, 17, 67, 29, 172, 18, 251, 29, 77, 19, 99, 30, 173, 19, 122, 30, 207, 19, 73, 30, 186, 19, 214, 29, 117, 19, 36, 29, 10, 19, 58, 28, 127, 18, 37, 27, 223, 17, 241, 25, 54, 17, 166, 24, 140, 16, 78, 23, 233, 15, 241, 21, 86, 15, 150, 20, 218, 14, 65, 19, 121, 14, 246, 17, 52, 14, 181, 16, 13, 14, 125, 15, 255, 13, 74, 14, 7, 14, 25, 13, 30, 14, 227, 11, 65, 14, 166, 10, 101, 14, 93, 9, 135, 14, 5, 8, 157, 14, 156, 6, 161, 14, 33, 5, 141, 14, 147, 3, 94, 14, 246, 1, 17, 14, 74, 0, 165, 13, 150, 254, 25, 13, 220, 252, 112, 12, 35, 251, 173, 11, 116, 249, 213, 10, 216, 247, 239, 9, 90, 246, 4, 9, 2, 245, 28, 8, 217, 243, 62, 7, 228, 242, 114, 6, 42, 242, 190, 5, 175, 241, 37, 5, 117, 241, 171, 4, 120, 241, 81, 4, 184, 241, 24, 4, 48, 242, 251, 3, 216, 242, 247, 3, 170, 243, 12, 4, 158, 244, 48, 4, 171, 245, 96, 4, 200, 246, 150, 4, 235, 247, 203, 4, 13, 249, 251, 4, 36, 250, 28, 5, 38, 251, 40, 5, 12, 252, 23, 5, 208, 252, 225, 4, 109, 253, 129, 4, 222, 253, 242, 3, 33, 254, 52, 3, 55, 254, 71, 2, 31, 254, 47, 1, 223, 253, 242, 255, 119, 253, 147, 254, 238, 252, 28, 253, 75, 252, 149, 251, 146, 251, 4, 250, 202, 250, 116, 248, 249, 249, 237, 246, 39, 249, 118, 245, 87, 248, 21, 244, 143, 247, 210, 242, 210, 246, 176, 241, 35, 246, 180, 240, 132, 245, 223, 239, 243, 244, 50, 239, 115, 244, 171, 238, 255, 243, 73, 238, 150, 243, 10, 238, 56, 243, 232, 237, 226, 242, 224, 237, 145, 242, 233, 237, 69, 242, 1, 238, 252, 241, 32, 238, 182, 241, 68, 238, 115, 241, 103, 238, 49, 241, 132, 238, 243, 240, 154, 238, 185, 240, 168, 238, 135, 240, 172, 238, 97, 240, 171, 238, 78, 240, 169, 238, 87, 240, 173, 238, 132, 240, 190, 238, 219, 240, 230, 238, 100, 241, 43, 239, 36, 242, 145, 239, 30, 243, 32, 240, 84, 244, 215, 240, 197, 245, 186, 241, 109, 247, 199, 242, 73, 249, 252, 243, 83, 251, 87, 245, 130, 253, 209, 246, 206, 255, 101, 248, 43, 2, 12, 250, 147, 4, 192, 251, 251, 6, 119, 253, 89, 9, 43, 255, 162, 11, 210, 0, 205, 13, 101, 2, 206, 15, 217, 3, 159, 17, 38, 5, 56, 19, 69, 6, 147, 20, 46, 7, 172, 21, 224, 7, 127, 22, 90, 8, 15, 23, 157, 8, 90, 23, 174, 8, 102, 23, 146, 8, 55, 23, 81, 8, 210, 22, 241, 7, 62, 22, 125, 7, 133, 21, 252, 6, 173, 20, 118, 6, 191, 19, 246, 5, 195, 18, 130, 5, 191, 17, 34, 5, 187, 16, 220, 4, 185, 15, 179, 4, 188, 14, 169, 4, 197, 13, 188, 4, 209, 12, 234, 4, 223, 11, 46, 5, 236, 10, 132, 5, 245, 9, 228, 5, 245, 8, 72, 6, 236, 7, 170, 6, 213, 6, 4, 7, 177, 5, 77, 7, 125, 4, 132, 7, 61, 3, 163, 7, 239, 1, 168, 7, 151, 0, 146, 7, 58, 255, 97, 7, 217, 253, 24, 7, 123, 252, 183, 6, 40, 251, 69, 6, 233, 249, 201, 5, 196, 248, 74, 5, 196, 247, 207, 4, 237, 246, 96, 4, 69, 246, 2, 4, 211, 245, 187, 3, 151, 245, 142, 3, 146, 245, 125, 3, 197, 245, 138, 3, 43, 246, 180, 3, 193, 246, 248, 3, 130, 247, 84, 4, 102, 248, 194, 4, 101, 249, 64, 5, 121, 250, 198, 5, 155, 251, 80, 6, 192, 252, 216, 6, 226, 253, 87, 7, 248, 254, 197, 7, 250, 255, 26, 8, 222, 0, 78, 8, 164, 1, 91, 8, 66, 2, 60, 8, 184, 2, 237, 7, 2, 3, 109, 7, 29, 3, 191, 6, 12, 3, 229, 5, 207, 2, 227, 4, 106, 2, 192, 3, 225, 1, 132, 2, 56, 1, 51, 1, 117, 0, 217, 255, 160, 255, 124, 254, 187, 254, 35, 253, 205, 253, 214, 251, 218, 252, 155, 250, 233, 251, 122, 249, 253, 250, 118, 248, 23, 250, 145, 247, 60, 249, 206, 246, 105, 248, 46, 246, 161, 247, 177, 245, 227, 246, 82, 245, 47, 246, 17, 245, 132, 245, 233, 244, 227, 244, 214, 244, 73, 244, 211, 244, 182, 243, 217, 244, 43, 243, 230, 244, 167, 242, 244, 244, 44, 242, 1, 245, 184, 241, 8, 245, 78, 241, 8, 245, 239, 240, 0, 245, 158, 240, 239, 244, 97, 240, 220, 244, 65, 240, 202, 244, 67, 240, 194, 244, 109, 240, 203, 244, 200, 240, 236, 244, 86, 241, 43, 245, 29, 242, 143, 245, 33, 243, 27, 246, 95, 244, 208, 246, 217, 245, 178, 247, 139, 247, 189, 248, 113, 249, 240, 249, 132, 251, 72, 251, 190, 253, 191, 252, 19, 0, 80, 254, 127, 2, 243, 255, 247, 4, 162, 1, 114, 7, 85, 3, 229, 9, 5, 5, 71, 12, 167, 6, 141, 14, 51, 8, 174, 16, 159, 9, 160, 18, 226, 10, 93, 20, 245, 11, 224, 21, 211, 12, 32, 23, 121, 13, 29, 24, 231, 13, 214, 24, 31, 14, 74, 25, 35, 14, 124, 25, 251, 13, 112, 25, 171, 13, 39, 25, 60, 13, 170, 24, 182, 12, 3, 24, 30, 12, 52, 23, 130, 11, 72, 22, 232, 10, 71, 21, 87, 10, 53, 20, 215, 9, 26, 19, 109, 9, 248, 17, 27, 9, 209, 16, 226, 8, 164, 15, 192, 8, 117, 14, 179, 8, 62, 13, 181, 8, 0, 12, 196, 8, 186, 10, 216, 8, 105, 9, 234, 8, 11, 8, 245, 8, 160, 6, 245, 8, 40, 5, 226, 8, 163, 3, 185, 8, 18, 2, 118, 8, 120, 0, 25, 8, 216, 254, 159, 7, 50, 253, 10, 7, 142, 251, 90, 6, 241, 249, 149, 5, 98, 248, 190, 4, 236, 246, 224, 3, 146, 245, 255, 2, 93, 244, 35, 2, 84, 243, 84, 1, 123, 242, 150, 0, 212, 241, 241, 255, 102, 241, 102, 255, 46, 241, 247, 254, 45, 241, 164, 254, 95, 241, 111, 254, 193, 241, 84, 254, 78, 242, 81, 254, 0, 243, 98, 254, 209, 243, 131, 254, 187, 244, 176, 254, 180, 245, 226, 254, 183, 246, 20, 255, 188, 247, 63, 255, 187, 248, 91, 255, 173, 249, 97, 255, 139, 250, 74, 255, 80, 251, 15, 255, 247, 251, 174, 254, 124, 252, 35, 254, 220, 252, 111, 253, 22, 253, 146, 252, 41, 253, 146, 251, 23, 253, 113, 250, 225, 252, 55, 249, 138, 252, 236, 247, 23, 252, 148, 246, 141, 251, 56, 245, 239, 250, 225, 243, 67, 250, 148, 242, 143, 249, 90, 241, 215, 248, 57, 240, 30, 248, 53, 239, 104, 247, 82, 238, 184, 246, 147, 237, 15, 246, 249, 236, 110, 245, 133, 236, 214, 244, 53, 236, 72, 244, 7, 236, 196, 243, 250, 235, 75, 243, 7, 236, 220, 242, 44, 236, 118, 242, 98, 236, 28, 242, 166, 236, 203, 241, 243, 236, 132, 241, 70, 237, 73, 241, 153, 237, 24, 241, 235, 237, 244, 240, 57, 238, 221, 240, 131, 238, 216, 240, 202, 238, 233, 240, 18, 239, 23, 241, 96, 239, 105, 241, 189, 239, 226, 241, 47, 240, 136, 242, 187, 240, 93, 243, 104, 241, 103, 244, 56, 242, 166, 245, 50, 243, 27, 247, 85, 244, 195, 248, 160, 245, 157, 250, 20, 247, 164, 252, 172, 248, 211, 254, 104, 250, 31, 1, 63, 252, 135, 3, 45, 254, 2, 6, 43, 0, 133, 8, 50, 2, 8, 11, 60, 4, 131, 13, 64, 6, 237, 15, 52, 8, 59, 18, 15, 10, 99, 20, 200, 11, 96, 22, 87, 13, 41, 24, 182, 14, 183, 25, 224, 15, 7, 27, 210, 16, 21, 28, 141, 17, 224, 28, 18, 18, 101, 29, 101, 18, 168, 29, 139, 18, 173, 29, 137, 18, 118, 29, 102, 18, 8, 29, 42, 18, 107, 28, 221, 17, 163, 27, 133, 17, 185, 26, 44, 17, 179, 25, 217, 16, 149, 24, 145, 16, 98, 23, 84, 16, 32, 22, 41, 16, 210, 20, 15, 16, 121, 19, 4, 16, 23, 18, 6, 16, 169, 16, 18, 16, 51, 15, 34, 16, 179, 13, 50, 16, 40, 12, 60, 16, 147, 10, 59, 16, 243, 8, 41, 16, 75, 7, 4, 16, 154, 5, 200, 15, 227, 3, 114, 15, 40, 2, 2, 15, 108, 0, 120, 14, 179, 254, 211, 13, 254, 252, 21, 13, 88, 251, 67, 12, 196, 249, 99, 11, 75, 248, 124, 10, 243, 246, 148, 9, 192, 245, 179, 8, 186, 244, 222, 7, 227, 243, 27, 7, 64, 243, 109, 6, 207, 242, 218, 5, 149, 242, 97, 5, 142, 242, 2, 5, 183, 242, 190, 4, 15, 243, 147, 4, 144, 243, 125, 4, 53, 244, 123, 4, 249, 244, 135, 4, 214, 245, 157, 4, 195, 246, 183, 4, 189, 247, 208, 4, 188, 248, 223, 4, 184, 249, 225, 4, 172, 250, 205, 4, 143, 251, 155, 4, 93, 252, 71, 4, 17, 253, 206, 3, 166, 253, 46, 3, 25, 254, 103, 2, 104, 254, 124, 1, 146, 254, 110, 0, 151, 254, 69, 255, 121, 254, 1, 254, 56, 254, 172, 252, 218, 253, 75, 251, 95, 253, 231, 249, 207, 252, 132, 248, 42, 252, 42, 247, 120, 251, 224, 245, 186, 250, 170, 244, 246, 249, 141, 243, 44, 249, 140, 242, 96, 248, 170, 241, 148, 247, 231, 240, 202, 246, 68, 240, 5, 246, 191, 239, 68, 245, 86, 239, 138, 244, 8, 239, 214, 243, 207, 238, 43, 243, 169, 238, 137, 242, 145, 238, 241, 241, 132, 238, 98, 241, 125, 238, 223, 240, 121, 238, 103, 240, 117, 238, 252, 239, 112, 238, 157, 239, 100, 238, 79, 239, 84, 238, 21, 239, 67, 238, 244, 238, 53, 238, 241, 238, 48, 238, 17, 239, 58, 238, 90, 239, 90, 238, 205, 239, 148, 238, 112, 240, 237, 238, 69, 241, 107, 239, 74, 242, 16, 240, 131, 243, 219, 240, 237, 244, 205, 241, 133, 246, 230, 242, 74, 248, 35, 244, 52, 250, 128, 245, 64, 252, 249, 246, 102, 254, 137, 248, 158, 0, 42, 250, 229, 2, 213, 251, 49, 5, 132, 253, 122, 7, 46, 255, 184, 9, 201, 0, 226, 11, 81, 2, 240, 13, 188, 3, 217, 15, 3, 5, 151, 17, 32, 6, 36, 19, 15, 7, 123, 20, 206, 7, 154, 21, 95, 8, 125, 22, 195, 8, 36, 23, 253, 8, 145, 23, 19, 9, 196, 23, 7, 9, 192, 23, 225, 8, 139, 23, 168, 8, 41, 23, 100, 8, 160, 22, 28, 8, 245, 21, 215, 7, 46, 21, 154, 7, 81, 20, 107, 7, 94, 19, 76, 7, 89, 18, 63, 7, 70, 17, 67, 7, 37, 16, 87, 7, 247, 14, 119, 7, 188, 13, 162, 7, 120, 12, 210, 7, 40, 11, 2, 8, 207, 9, 46, 8, 109, 8, 81, 8, 2, 7, 103, 8, 144, 5, 110, 8, 24, 4, 97, 8, 156, 2, 63, 8, 29, 1, 5, 8, 161, 255, 180, 7, 41, 254, 77, 7, 184, 252, 209, 6, 86, 251, 72, 6, 10, 250, 180, 5, 214, 248, 30, 5, 197, 247, 139, 4, 214, 246, 1, 4, 15, 246, 134, 3, 116, 245, 28, 3, 8, 245, 202, 2, 203, 244, 144, 2, 188, 244, 112, 2, 222, 244, 105, 2, 43, 245, 124, 2, 162, 245, 166, 2, 63, 246, 229, 2, 252, 246, 52, 3, 213, 247, 145, 3, 196, 248, 246, 3, 197, 249, 94, 4, 210, 250, 195, 4, 228, 251, 31, 5, 244, 252, 105, 5, 251, 253, 157, 5, 244, 254, 179, 5, 217, 255, 166, 5, 162, 0, 118, 5, 79, 1, 32, 5, 219, 1, 163, 4, 66, 2, 2, 4, 132, 2, 63, 3, 159, 2, 95, 2, 150, 2, 101, 1, 103, 2, 90, 0, 23, 2, 66, 255, 169, 1, 34, 254, 31, 1, 1, 253, 125, 0, 230, 251, 201, 255, 215, 250, 1, 255, 216, 249, 44, 254, 236, 248, 76, 253, 24, 248, 99, 252, 91, 247, 118, 251, 184, 246, 134, 250, 48, 246, 150, 249, 193, 245, 168, 248, 105, 245, 189, 247, 38, 245, 216, 246, 244, 244, 252, 245, 209, 244, 41, 245, 184, 244, 96, 244, 168, 244, 163, 243, 156, 244, 242, 242, 144, 244, 80, 242, 132, 244, 189, 241, 115, 244, 59, 241, 94, 244, 205, 240, 68, 244, 118, 240, 43, 244, 61, 240, 23, 244, 38, 240, 13, 244, 53, 240, 21, 244, 111, 240, 52, 244, 214, 240, 110, 244, 110, 241, 201, 244, 56, 242, 72, 245, 54, 243, 237, 245, 103, 244, 186, 246, 202, 245, 174, 247, 93, 247, 199, 248, 27, 249, 3, 250, 1, 251, 95, 251, 11, 253, 214, 252, 48, 255, 99, 254, 106, 1, 0, 0, 182, 3, 166, 1, 11, 6, 81, 3, 95, 8, 248, 4, 171, 10, 143, 6, 231, 12, 18, 8, 7, 15, 118, 9, 6, 17, 182, 10, 222, 18, 205, 11, 133, 20, 182, 12, 248, 21, 113, 13, 52, 23, 254, 13, 52, 24, 94, 14, 249, 24, 148, 14, 129, 25, 166, 14, 208, 25, 150, 14, 229, 25, 108, 14, 198, 25, 45, 14, 118, 25, 226, 13, 249, 24, 145, 13, 85, 24, 64, 13, 141, 23, 244, 12, 163, 22, 175, 12, 156, 21, 116, 12, 125, 20, 70, 12, 69, 19, 34, 12, 250, 17, 8, 12, 157, 16, 246, 11, 46, 15, 232, 11, 178, 13, 216, 11, 38, 12, 197, 11, 141, 10, 170, 11, 234, 8, 129, 11, 62, 7, 73, 11, 139, 5, 253, 10, 210, 3, 156, 10, 22, 2, 35, 10, 90, 0, 147, 9, 160, 254, 233, 8, 235, 252, 41, 8, 64, 251, 85, 7, 167, 249, 117, 6, 37, 248, 138, 5, 191, 246, 158, 4, 122, 245, 181, 3, 89, 244, 213, 2, 98, 243, 4, 2, 151, 242, 69, 1, 250, 241, 157, 0, 141, 241, 13, 0, 78, 241, 152, 255, 61, 241, 58, 255, 90, 241, 244, 254, 160, 241, 198, 254, 13, 242, 173, 254, 157, 242, 165, 254, 74, 243, 170, 254, 19, 244, 185, 254, 242, 244, 203, 254, 225, 245, 219, 254, 218, 246, 228, 254, 214, 247, 222, 254, 208, 248, 195, 254, 192, 249, 142, 254, 160, 250, 61, 254, 109, 251, 203, 253, 32, 252, 57, 253, 184, 252, 136, 252, 48, 253, 183, 251, 135, 253, 204, 250, 188, 253, 200, 249, 207, 253, 178, 248, 194, 253, 144, 247, 148, 253, 102, 246, 73, 253, 58, 245, 228, 252, 20, 244, 104, 252, 248, 242, 215, 251, 234, 241, 52, 251, 240, 240, 129, 250, 12, 240, 195, 249, 65, 239, 252, 248, 144, 238, 47, 248, 251, 237, 94, 247, 131, 237, 143, 246, 37, 237, 192, 245, 223, 236, 246, 244, 176, 236, 51, 244, 150, 236, 122, 243, 139, 236, 202, 242, 143, 236, 39, 242, 158, 236, 146, 241, 178, 236, 11, 241, 203, 236, 148, 240, 232, 236, 46, 240, 3, 237, 219, 239, 30, 237, 158, 239, 60, 237, 123, 239, 94, 237, 119, 239, 139, 237, 149, 239, 199, 237, 219, 239, 25, 238, 72, 240, 133, 238, 227, 240, 16, 239, 171, 241, 189, 239, 164, 242, 141, 240, 204, 243, 135, 241, 35, 245, 166, 242, 170, 246, 236, 243, 92, 248, 88, 245, 56, 250, 229, 246, 56, 252, 146, 248, 88, 254, 88, 250, 147, 0, 53, 252, 227, 2, 32, 254, 70, 5, 20, 0, 176, 7, 11, 2, 26, 10, 252, 3, 124, 12, 223, 5, 206, 14, 173, 7, 7, 17, 93, 9, 31, 19, 233, 10, 15, 21, 77, 12, 209, 22, 134, 13, 98, 24, 146, 14, 187, 25, 114, 15, 219, 26, 38, 16, 192, 27, 177, 16, 104, 28, 23, 17, 211, 28, 92, 17, 7, 29, 134, 17, 5, 29, 155, 17, 206, 28, 162, 17, 105, 28, 159, 17, 216, 27, 153, 17, 31, 27, 147, 17, 66, 26, 145, 17, 67, 25, 148, 17, 39, 24, 154, 17, 237, 22, 167, 17, 154, 21, 181, 17, 49, 20, 196, 17, 179, 18, 208, 17, 32, 17, 214, 17, 125, 15, 208, 17, 206, 13, 192, 17, 19, 12, 158, 17, 80, 10, 105, 17, 133, 8, 31, 17, 182, 6, 190, 16, 231, 4, 68, 16, 23, 3, 177, 15, 77, 1, 4, 15, 140, 255, 66, 14, 217, 253, 111, 13, 57, 252, 143, 12, 176, 250, 167, 11, 70, 249, 190, 10, 252, 247, 219, 9, 214, 246, 2, 9, 217, 245, 53, 8, 7, 245, 121, 7, 97, 244, 210, 6, 231, 243, 65, 6, 155, 243, 199, 5, 124, 243, 100, 5, 135, 243, 23, 5, 187, 243, 223, 4, 20, 244, 185, 4, 144, 244, 162, 4, 44, 245, 150, 4, 227, 245, 146, 4, 179, 246, 145, 4, 148, 247, 141, 4, 129, 248, 128, 4, 116, 249, 101, 4, 102, 250, 54, 4, 80, 251, 238, 3, 46, 252, 139, 3, 250, 252, 11, 3, 176, 253, 108, 2, 75, 254, 176, 1, 201, 254, 217, 0, 39, 255, 233, 255, 102, 255, 227, 254, 130, 255, 203, 253, 125, 255, 166, 252, 89, 255, 122, 251, 22, 255, 76, 250, 180, 254, 33, 249, 57, 254, 252, 247, 164, 253, 228, 246, 250, 252, 218, 245, 60, 252, 227, 244, 110, 251, 255, 243, 146, 250, 49, 243, 173, 249, 122, 242, 193, 248, 217, 241, 209, 247, 78, 241, 223, 246, 213, 240, 239, 245, 111, 240, 3, 245, 25, 240, 31, 244, 208, 239, 67, 243, 146, 239, 113, 242, 91, 239, 173, 241, 40, 239, 246, 240, 248, 238, 78, 240, 201, 238, 183, 239, 152, 238, 51, 239, 104, 238, 197, 238, 58, 238, 114, 238, 18, 238, 61, 238, 246, 237, 43, 238, 235, 237, 63, 238, 245, 237, 125, 238, 24, 238, 228, 238, 90, 238, 120, 239, 187, 238, 58, 240, 66, 239, 43, 241, 236, 239, 73, 242, 188, 240, 149, 243, 177, 241, 12, 245, 200, 242, 170, 246, 1, 244, 111, 248, 87, 245, 83, 250, 198, 246, 85, 252, 73, 248, 113, 254, 222, 249, 157, 0, 125, 251, 215, 2, 31, 253, 21, 5, 189, 254, 79, 7, 77, 0, 126, 9, 204, 1, 155, 11, 51, 3, 156, 13, 122, 4, 124, 15, 160, 5, 55, 17, 160, 6, 197, 18, 123, 7, 36, 20, 48, 8, 81, 21, 192, 8, 73, 22, 47, 9, 12, 23, 127, 9, 154, 23, 182, 9, 244, 23, 215, 9, 27, 24, 233, 9, 19, 24, 240, 9, 221, 23, 241, 9, 124, 23, 240, 9, 242, 22, 241, 9, 67, 22, 245, 9, 114, 21, 254, 9, 129, 20, 12, 10, 115, 19, 31, 10, 76, 18, 52, 10, 11, 17, 73, 10, 182, 15, 93, 10, 78, 14, 108, 10, 215, 12, 114, 10, 81, 11, 109, 10, 193, 9, 90, 10, 40, 8, 55, 10, 136, 6, 1, 10, 228, 4, 181, 9, 62, 3, 86, 9, 155, 1, 224, 8, 254, 255, 86, 8, 106, 254, 187, 7, 227, 252, 18, 7, 111, 251, 96, 6, 20, 250, 172, 5, 213, 248, 248, 4, 183, 247, 75, 4, 188, 246, 170, 3, 231, 245, 25, 3, 59, 245, 155, 2, 184, 244, 48, 2, 96, 244, 221, 1, 52, 244, 161, 1, 47, 244, 125, 1, 84, 244, 111, 1, 160, 244, 116, 1, 16, 245, 140, 1, 163, 245, 179, 1, 86, 246, 230, 1, 37, 247, 30, 2, 12, 248, 91, 2, 4, 249, 150, 2, 9, 250, 199, 2, 21, 251, 236, 2, 32, 252, 252, 2, 37, 253, 247, 2, 28, 254, 216, 2, 4, 255, 158, 2, 214, 255, 72, 2, 140, 0, 214, 1, 41, 1, 74, 1, 165, 1, 166, 0, 1, 2, 238, 255, 60, 2, 37, 255, 85, 2, 79, 254, 76, 2, 113, 253, 33, 2, 143, 252, 215, 1, 174, 251, 110, 1, 208, 250, 234, 0, 251, 249, 75, 0, 50, 249, 152, 255, 118, 248, 208, 254, 202, 247, 245, 253, 46, 247, 14, 253, 164, 246, 28, 252, 43, 246, 35, 251, 195, 245, 40, 250, 108, 245, 43, 249, 32, 245, 49, 248, 226, 244, 60, 247, 172, 244, 79, 246, 127, 244, 107, 245, 86, 244, 148, 244, 47, 244, 200, 243, 9, 244, 12, 243, 225, 243, 97, 242, 185, 243, 202, 241, 144, 243, 73, 241, 108, 243, 228, 240, 78, 243, 158, 240, 61, 243, 123, 240, 60, 243, 127, 240, 80, 243, 171, 240, 127, 243, 1, 241, 200, 243, 130, 241, 49, 244, 49, 242, 189, 244, 13, 243, 107, 245, 23, 244, 62, 246, 77, 245, 51, 247, 175, 246, 74, 248, 56, 248, 128, 249, 232, 249, 209, 250, 187, 251, 60, 252, 171, 253, 186, 253, 183, 255, 72, 255, 214, 1, 222, 0, 4, 4, 120, 2, 57, 6, 13, 4, 108, 8, 151, 5, 151, 10, 15, 7, 176, 12, 112, 8, 178, 14, 179, 9, 149, 16, 214, 10, 85, 18, 214, 11, 236, 19, 179, 12, 86, 21, 107, 13, 144, 22, 0, 14, 152, 23, 118, 14, 105, 24, 204, 14, 7, 25, 10, 15, 113, 25, 50, 15, 169, 25, 73, 15, 173, 25, 84, 15, 129, 25, 87, 15, 40, 25, 84, 15, 165, 24, 79, 15, 249, 23, 73, 15, 38, 23, 66, 15, 47, 22, 59, 15, 23, 21, 51, 15, 224, 19, 40, 15, 141, 18, 24, 15, 31, 17, 1, 15, 156, 15, 223, 14, 7, 14, 176, 14, 97, 12, 115, 14, 173, 10, 36, 14, 239, 8, 194, 13, 42, 7, 75, 13, 95, 5, 189, 12, 147, 3, 24, 12, 199, 1, 93, 11, 0, 0, 141, 10, 68, 254, 172, 9, 149, 252, 190, 8, 249, 250, 199, 7, 116, 249, 204, 6, 10, 248, 211, 5, 193, 246, 224, 4, 153, 245, 249, 3, 151, 244, 31, 3, 187, 243, 86, 2, 9, 243, 162, 1, 126, 242, 2, 1, 31, 242, 120, 0, 233, 241, 4, 0, 218, 241, 168, 255, 244, 241, 92, 255, 51, 242, 34, 255, 151, 242, 247, 254, 30, 243, 215, 254, 196, 243, 192, 254, 132, 244, 172, 254, 89, 245, 151, 254, 62, 246, 124, 254, 44, 247, 84, 254, 30, 248, 30, 254, 13, 249, 213, 253, 245, 249, 119, 253, 209, 250, 2, 253, 155, 251, 119, 252, 81, 252, 212, 251, 238, 252, 30, 251, 113, 253, 84, 250, 216, 253, 122, 249, 32, 254, 149, 248, 73, 254, 168, 247, 84, 254, 182, 246, 64, 254, 196, 245, 13, 254, 212, 244, 189, 253, 236, 243, 83, 253, 14, 243, 207, 252, 60, 242, 53, 252, 122, 241, 134, 251, 199, 240, 199, 250, 39, 240, 251, 249, 153, 239, 36, 249, 28, 239, 70, 248, 178, 238, 100, 247, 87, 238, 131, 246, 12, 238, 162, 245, 205, 237, 198, 244, 154, 237, 242, 243, 111, 237, 41, 243, 75, 237, 106, 242, 45, 237, 185, 241, 17, 237, 22, 241, 247, 236, 132, 240, 224, 236, 6, 240, 206, 236, 160, 239, 197, 236, 86, 239, 198, 236, 43, 239, 216, 236, 35, 239, 254, 236, 65, 239, 61, 237, 136, 239, 151, 237, 249, 239, 18, 238, 149, 240, 173, 238, 93, 241, 108, 239, 79, 242, 80, 240, 112, 243, 87, 241, 186, 244, 129, 242, 45, 246, 206, 243, 201, 247, 57, 245, 137, 249, 193, 246, 108, 251, 96, 248, 109, 253, 21, 250, 137, 255, 217, 251, 184, 1, 168, 253, 246, 3, 121, 255, 61, 6, 70, 1, 131, 8, 11, 3, 192, 10, 191, 4, 239, 12, 94, 6, 8, 15, 226, 7, 7, 17, 74, 9, 228, 18, 146, 10, 152, 20, 184, 11, 37, 22, 189, 12, 132, 23, 162, 13, 177, 24, 105, 14, 173, 25, 20, 15, 117, 26, 167, 15, 10, 27, 37, 16, 107, 27, 144, 16, 153, 27, 238, 16, 149, 27, 64, 17, 94, 27, 135, 17, 249, 26, 200, 17, 105, 26, 3, 18, 176, 25, 57, 18, 208, 24, 106, 18, 205, 23, 148, 18, 168, 22, 182, 18, 100, 21, 207, 18, 6, 20, 221, 18, 143, 18, 221, 18, 2, 17, 205, 18, 100, 15, 171, 18, 184, 13, 117, 18, 254, 11, 40, 18, 59, 10, 196, 17, 115, 8, 73, 17, 167, 6, 180, 16, 220, 4, 10, 16, 21, 3, 75, 15, 87, 1, 123, 14, 170, 255, 157, 13, 13, 254, 183, 12, 135, 252, 206, 11, 28, 251, 228, 10, 207, 249, 1, 10, 163, 248, 40, 9, 155, 247, 92, 8, 184, 246, 158, 7, 251, 245, 242, 6, 101, 245, 90, 6, 246, 244, 212, 5, 175, 244, 99, 5, 144, 244, 3, 5, 150, 244, 182, 4, 195, 244, 119, 4, 21, 245, 69, 4, 136, 245, 29, 4, 27, 246, 252, 3, 201, 246, 222, 3, 140, 247, 190, 3, 95, 248, 151, 3, 62, 249, 100, 3, 32, 250, 36, 3, 1, 251, 210, 2, 221, 251, 110, 2, 173, 252, 244, 1, 110, 253, 102, 1, 29, 254, 196, 0, 181, 254, 14, 0, 53, 255, 74, 255, 155, 255, 117, 254, 227, 255, 148, 253, 11, 0, 173, 252, 21, 0, 191, 251, 2, 0, 209, 250, 209, 255, 227, 249, 128, 255, 250, 248, 19, 255, 24, 248, 139, 254, 62, 247, 235, 253, 113, 246, 54, 253, 176, 245, 110, 252, 251, 244, 150, 251, 85, 244, 178, 250, 190, 243, 195, 249, 50, 243, 208, 248, 179, 242, 216, 247, 63, 242, 224, 246, 213, 241, 235, 245, 112, 241, 251, 244, 19, 241, 17, 244, 186, 240, 49, 243, 98, 240, 92, 242, 14, 240, 147, 241, 185, 239, 218, 240, 104, 239, 52, 240, 27, 239, 164, 239, 213, 238, 47, 239, 156, 238, 215, 238, 113, 238, 162, 238, 91, 238, 145, 238, 93, 238, 168, 238, 121, 238, 231, 238, 180, 238, 80, 239, 15, 239, 228, 239, 138, 239, 162, 240, 41, 240, 140, 241, 234, 240, 158, 242, 203, 241, 219, 243, 206, 242, 63, 245, 238, 243, 202, 246, 42, 245, 120, 248, 127, 246, 70, 250, 232, 247, 48, 252, 96, 249, 48, 254, 227, 250, 64, 0, 107, 252, 90, 2, 240, 253, 120, 4, 110, 255, 146, 6, 221, 0, 161, 8, 59, 2, 159, 10, 133, 3, 134, 12, 180, 4, 81, 14, 202, 5, 252, 15, 195, 6, 130, 17, 161, 7, 224, 18, 100, 8, 19, 20, 13, 9, 26, 21, 160, 9, 241, 21, 32, 10, 154, 22, 140, 10, 18, 23, 234, 10, 91, 23, 60, 11, 116, 23, 133, 11, 98, 23, 199, 11, 34, 23, 3, 12, 185, 22, 57, 12, 40, 22, 105, 12, 111, 21, 148, 12, 147, 20, 185, 12, 148, 19, 214, 12, 117, 18, 232, 12, 60, 17, 240, 12, 232, 15, 234, 12, 127, 14, 212, 12, 4, 13, 174, 12, 121, 11, 116, 12, 225, 9, 39, 12, 64, 8, 197, 11, 152, 6, 77, 11, 236, 4, 193, 10, 65, 3, 32, 10, 153, 1, 110, 9, 253, 255, 176, 8, 109, 254, 232, 7, 238, 252, 26, 7, 134, 251, 77, 6, 54, 250, 130, 5, 3, 249, 190, 4, 241, 247, 6, 4, 0, 247, 91, 3, 50, 246, 193, 2, 137, 245, 58, 2, 5, 245, 197, 1, 168, 244, 100, 1, 113, 244, 23, 1, 97, 244, 218, 0, 119, 244, 177, 0, 179, 244, 150, 0, 20, 245, 136, 0, 151, 245, 134, 0, 56, 246, 140, 0, 244, 246, 148, 0, 198, 247, 156, 0, 168, 248, 159, 0, 150, 249, 153, 0, 137, 250, 135, 0, 123, 251, 102, 0, 105, 252, 53, 0, 78, 253, 243, 255, 37, 254, 160, 255, 234, 254, 56, 255, 156, 255, 193, 254, 51, 0, 60, 254, 178, 0, 169, 253, 21, 1, 13, 253, 90, 1, 106, 252, 129, 1, 192, 251, 135, 1, 21, 251, 110, 1, 104, 250, 55, 1, 192, 249, 227, 0, 27, 249, 116, 0, 125, 248, 236, 255, 233, 247, 76, 255, 92, 247, 151, 254, 218, 246, 209, 253, 98, 246, 252, 252, 245, 245, 27, 252, 146, 245, 52, 251, 56, 245, 70, 250, 228, 244, 87, 249, 152, 244, 103, 248, 81, 244, 123, 247, 13, 244, 148, 246, 203, 243, 180, 245, 138, 243, 220, 244, 74, 243, 16, 244, 10, 243, 83, 243, 205, 242, 167, 242, 149, 242, 16, 242, 100, 242, 148, 241, 64, 242, 53, 241, 43, 242, 248, 240, 41, 242, 222, 240, 63, 242, 234, 240, 111, 242, 31, 241, 187, 242, 123, 241, 38, 243, 0, 242, 177, 243, 177, 242, 93, 244, 138, 243, 42, 245, 142, 244, 22, 246, 186, 245, 31, 247, 13, 247, 70, 248, 135, 248, 134, 249, 37, 250, 223, 250, 228, 251, 74, 252, 191, 253, 197, 253, 177, 255, 73, 255, 179, 1, 208, 0, 193, 3, 87, 2, 212, 5, 216, 3, 229, 7, 75, 5, 237, 9, 175, 6, 230, 11, 254, 7, 204, 13, 54, 9, 151, 15, 85, 10, 67, 17, 90, 11, 207, 18, 71, 12, 53, 20, 25, 13, 112, 21, 212, 13, 130, 22, 121, 14, 101, 23, 10, 15, 25, 24, 137, 15, 158, 24, 247, 15, 243, 24, 87, 16, 23, 25, 171, 16, 12, 25, 243, 16, 213, 24, 51, 17, 114, 24, 104, 17, 227, 23, 149, 17, 45, 23, 184, 17, 81, 22, 208, 17, 80, 21, 220, 17, 47, 20, 218, 17, 239, 18, 200, 17, 147, 17, 166, 17, 32, 16, 112, 17, 151, 14, 38, 17, 252, 12, 198, 16, 82, 11, 79, 16, 154, 9, 191, 15, 219, 7, 25, 15, 21, 6, 92, 14, 79, 4, 138, 13, 140, 2, 166, 12, 207, 0, 180, 11, 33, 255, 183, 10, 128, 253, 181, 9, 244, 251, 176, 8, 128, 250, 173, 7, 40, 249, 177, 6, 237, 247, 190, 5, 210, 246, 215, 4, 216, 245, 1, 4, 2, 245, 57, 3, 80, 244, 132, 2, 196, 243, 224, 1, 95, 243, 79, 1, 34, 243, 207, 0, 11, 243, 95, 0, 27, 243, 0, 0, 81, 243, 173, 255, 170, 243, 100, 255, 37, 244, 34, 255, 186, 244, 229, 254, 104, 245, 169, 254, 40, 246, 105, 254, 245, 246, 34, 254, 203, 247, 210, 253, 163, 248, 118, 253, 122, 249, 13, 253, 74, 250, 151, 252, 16, 251, 18, 252, 201, 251, 126, 251, 112, 252, 223, 250, 2, 253, 52, 250, 126, 253, 126, 249, 223, 253, 194, 248, 38, 254, 0, 248, 79, 254, 59, 247, 91, 254, 119, 246, 74, 254, 179, 245, 28, 254, 242, 244, 210, 253, 55, 244, 110, 253, 132, 243, 241, 252, 218, 242, 93, 252, 57, 242, 183, 251, 163, 241, 255, 250, 24, 241, 58, 250, 152, 240, 107, 249, 34, 240, 146, 248, 183, 239, 180, 247, 84, 239, 213, 246, 249, 238, 245, 245, 164, 238, 23, 245, 85, 238, 63, 244, 11, 238, 109, 243, 196, 237, 163, 242, 128, 237, 230, 241, 65, 237, 55, 241, 7, 237, 152, 240, 214, 236, 17, 240, 178, 236, 163, 239, 156, 236, 83, 239, 152, 236, 36, 239, 170, 236, 24, 239, 214, 236, 50, 239, 29, 237, 115, 239, 130, 237, 220, 239, 7, 238, 111, 240, 172, 238, 43, 241, 115, 239, 18, 242, 90, 240, 35, 243, 98, 241, 93, 244, 136, 242, 193, 245, 204, 243, 75, 247, 42, 245, 249, 248, 160, 246, 201, 250, 42, 248, 181, 252, 195, 249, 185, 254, 103, 251, 206, 0, 16, 253, 239, 2, 185, 254, 22, 5, 92, 0, 60, 7, 246, 1, 89, 9, 131, 3, 107, 11, 255, 4, 104, 13, 101, 6, 77, 15, 181, 7, 22, 17, 239, 8, 190, 18, 17, 10, 66, 20, 28, 11, 156, 21, 17, 12, 204, 22, 240, 12, 206, 23, 188, 13, 160, 24, 117, 14, 67, 25, 30, 15, 183, 25, 184, 15, 251, 25, 69, 16, 17, 26, 197, 16, 247, 25, 58, 17, 178, 25, 164, 17, 65, 25, 2, 18, 166, 24, 83, 18, 227, 23, 152, 18, 249, 22, 203, 18, 235, 21, 239, 18, 191, 20, 3, 19, 118, 19, 4, 19, 20, 18, 242, 18, 156, 16, 202, 18, 16, 15, 141, 18, 116, 13, 58, 18, 203, 11, 208, 17, 25, 10, 78, 17, 96, 8, 184, 16, 164, 6, 13, 16, 234, 4, 82, 15, 55, 3, 136, 14, 141, 1, 180, 13, 244, 255, 219, 12, 109, 254, 255, 11, 252, 252, 35, 11, 163, 251, 76, 10, 104, 250, 124, 9, 74, 249, 182, 8, 78, 248, 252, 7, 116, 247, 79, 7, 190, 246, 177, 6, 46, 246, 34, 6, 196, 245, 162, 5, 131, 245, 48, 5, 105, 245, 205, 4, 117, 245, 118, 4, 167, 245, 43, 4, 250, 245, 233, 3, 111, 246, 172, 3, 254, 246, 115, 3, 165, 247, 58, 3, 94, 248, 251, 2, 35, 249, 182, 2, 241, 249, 105, 2, 194, 250, 15, 2, 145, 251, 171, 1, 91, 252, 55, 1, 27, 253, 181, 0, 206, 253, 39, 0, 110, 254, 142, 255, 250, 254, 231, 254, 110, 255, 53, 254, 200, 255, 125, 253, 5, 0, 188, 252, 37, 0, 248, 251, 42, 0, 50, 251, 16, 0, 107, 250, 218, 255, 166, 249, 136, 255, 228, 248, 26, 255, 40, 248, 148, 254, 113, 247, 248, 253, 194, 246, 71, 253, 28, 246, 133, 252, 125, 245, 180, 251, 231, 244, 216, 250, 90, 244, 242, 249, 212, 243, 6, 249, 85, 243, 23, 248, 222, 242, 38, 247, 107, 242, 55, 246, 253, 241, 74, 245, 147, 241, 99, 244, 43, 241, 130, 243, 198, 240, 171, 242, 102, 240, 226, 241, 12, 240, 43, 241, 186, 239, 136, 240, 114, 239, 253, 239, 57, 239, 143, 239, 19, 239, 64, 239, 0, 239, 19, 239, 5, 239, 10, 239, 34, 239, 39, 239, 92, 239, 109, 239, 180, 239, 219, 239, 41, 240, 115, 240, 188, 240, 54, 241, 110, 241, 35, 242, 63, 242, 58, 243, 45, 243, 123, 244, 53, 244, 229, 245, 86, 245, 114, 247, 141, 246, 34, 249, 217, 247, 239, 250, 51, 249, 213, 252, 152, 250, 206, 254, 1, 252, 209, 0, 109, 253, 221, 2, 212, 254, 234, 4, 51, 0, 240, 6, 134, 1, 236, 8, 204, 2, 215, 10, 0, 4, 173, 12, 33, 5, 106, 14, 47, 6, 6, 16, 39, 7, 129, 17, 11, 8, 212, 18, 220, 8, 255, 19, 152, 9, 254, 20, 67, 10, 208, 21, 222, 10, 116, 22, 106, 11, 234, 22, 232, 11, 50, 23, 88, 12, 76, 23, 190, 12, 58, 23, 25, 13, 253, 22, 105, 13, 149, 22, 173, 13, 6, 22, 231, 13, 80, 21, 21, 14, 119, 20, 52, 14, 124, 19, 71, 14, 98, 18, 75, 14, 44, 17, 62, 14, 221, 15, 31, 14, 120, 14, 240, 13, 255, 12, 172, 13, 118, 11, 84, 13, 223, 9, 234, 12, 61, 8, 107, 12, 149, 6, 218, 11, 234, 4, 57, 11, 65, 3, 137, 10, 157, 1, 207, 9, 3, 0, 13, 9, 122, 254, 69, 8, 0, 253, 126, 7, 156, 251, 184, 6, 81, 250, 247, 5, 33, 249, 63, 5, 15, 248, 142, 4, 30, 247, 235, 3, 79, 246, 84, 3, 164, 245, 204, 2, 31, 245, 83, 2, 193, 244, 231, 1, 140, 244, 139, 1, 126, 244, 60, 1, 150, 244, 249, 0, 212, 244, 194, 0, 53, 245, 148, 0, 181, 245, 109, 0, 81, 246, 73, 0, 5, 247, 37, 0, 203, 247, 0, 0, 158, 248, 214, 255, 122, 249, 164, 255, 91, 250, 105, 255, 58, 251, 33, 255, 20, 252, 207, 254, 229, 252, 112, 254, 168, 253, 4, 254, 89, 254, 143, 253, 246, 254, 13, 253, 123, 255, 130, 252, 230, 255, 239, 251, 51, 0, 86, 251, 100, 0, 183, 250, 120, 0, 23, 250, 110, 0, 116, 249, 72, 0, 211, 248, 6, 0, 52, 248, 170, 255, 153, 247, 50, 255, 3, 247, 165, 254, 114, 246, 3, 254, 233, 245, 79, 253, 103, 245, 139, 252, 236, 244, 187, 251, 120, 244, 225, 250, 12, 244, 255, 249, 166, 243, 26, 249, 70, 243, 48, 248, 235, 242, 72, 247, 150, 242, 96, 246, 68, 242, 125, 245, 246, 241, 160, 244, 171, 241, 204, 243, 103, 241, 5, 243, 40, 241, 80, 242, 243, 240, 174, 241, 202, 240, 36, 241, 175, 240, 184, 240, 166, 240, 106, 240, 176, 240, 60, 240, 210, 240, 52, 240, 13, 241, 81, 240, 99, 241, 151, 240, 214, 241, 8, 241, 101, 242, 163, 241, 18, 243, 106, 242, 220, 243, 93, 243, 194, 244, 125, 244, 198, 245, 199, 245, 227, 246, 58, 247, 24, 248, 211, 248, 99, 249, 142, 250, 193, 250, 104, 252, 45, 252, 91, 254, 163, 253, 97, 0, 31, 255, 116, 2, 154, 0, 144, 4, 19, 2, 172, 6, 134, 3, 195, 8, 237, 4, 208, 10, 70, 6, 205, 12, 143, 7, 179, 14, 198, 8, 128, 16, 233, 9, 44, 18, 248, 10, 181, 19, 242, 11, 23, 21, 215, 12, 78, 22, 168, 13, 89, 23, 103, 14, 54, 24, 19, 15, 227, 24, 176, 15, 97, 25, 61, 16, 176, 25, 187, 16, 209, 25, 44, 17, 195, 25, 143, 17, 136, 25, 229, 17, 31, 25, 45, 18, 142, 24, 103, 18, 209, 23, 144, 18, 236, 22, 168, 18, 229, 21, 176, 18, 189, 20, 167, 18, 120, 19, 141, 18, 24, 18, 94, 18, 159, 16, 29, 18, 17, 15, 200, 17, 112, 13, 93, 17, 193, 11, 223, 16, 5, 10, 76, 16, 64, 8, 165, 15, 120, 6, 237, 14, 175, 4, 38, 14, 235, 2, 84, 13, 49, 1, 120, 12, 133, 255, 151, 11, 232, 253, 180, 10, 94, 252, 208, 9, 237, 250, 239, 8, 151, 249, 20, 8, 94, 248, 64, 7, 72, 247, 118, 6, 85, 246, 182, 5, 134, 245, 3, 5, 224, 244, 92, 4, 97, 244, 195, 3, 12, 244, 54, 3, 223, 243, 181, 2, 217, 243, 64, 2, 250, 243, 214, 1, 64, 244, 115, 1, 165, 244, 23, 1, 39, 245, 189, 0, 193, 245, 101, 0, 111, 246, 11, 0, 44, 247, 173, 255, 242, 247, 72, 255, 189, 248, 218, 254, 137, 249, 98, 254, 81, 250, 225, 253, 17, 251, 85, 253, 195, 251, 189, 252, 102, 252, 27, 252, 244, 252, 113, 251, 108, 253, 189, 250, 203, 253, 3, 250, 15, 254, 67, 249, 55, 254, 127, 248, 67, 254, 186, 247, 50, 254, 244, 246, 6, 254, 48, 246, 191, 253, 111, 245, 95, 253, 178, 244, 231, 252, 252, 243, 89, 252, 75, 243, 184, 251, 162, 242, 6, 251, 2, 242, 70, 250, 106, 241, 122, 249, 218, 240, 164, 248, 81, 240, 200, 247, 210, 239, 230, 246, 90, 239, 3, 246, 234, 238, 32, 245, 129, 238, 63, 244, 30, 238, 97, 243, 194, 237, 138, 242, 107, 237, 190, 241, 29, 237, 255, 240, 216, 236, 79, 240, 158, 236, 183, 239, 116, 236, 53, 239, 90, 236, 208, 238, 84, 236, 137, 238, 99, 236, 99, 238, 139, 236, 98, 238, 205, 236, 136, 238, 42, 237, 215, 238, 164, 237, 79, 239, 59, 238, 243, 239, 239, 238, 196, 240, 194, 239, 192, 241, 177, 240, 233, 242, 187, 241, 60, 244, 225, 242, 184, 245, 30, 244, 90, 247, 113, 245, 31, 249, 215, 246, 2, 251, 76, 248, 253, 252, 205, 249, 13, 255, 85, 251, 41, 1, 222, 252, 78, 3, 104, 254, 117, 5, 235, 255, 152, 7, 100, 1, 178, 9, 212, 2, 188, 11, 55, 4, 178, 13, 137, 5, 142, 15, 202, 6, 74, 17, 248, 7, 228, 18, 20, 9, 88, 20, 28, 10, 161, 21, 18, 11, 192, 22, 246, 11, 177, 23, 200, 12, 116, 24, 138, 13, 9, 25, 61, 14, 111, 25, 225, 14, 166, 25, 117, 15, 177, 25, 254, 15, 142, 25, 118, 16, 64, 25, 225, 16, 200, 24, 61, 17, 40, 24, 137, 17, 97, 23, 198, 17, 120, 22, 242, 17, 109, 21, 12, 18, 67, 20, 20, 18, 254, 18, 9, 18, 159, 17, 235, 17, 40, 16, 184, 17, 157, 14, 112, 17, 2, 13, 21, 17, 90, 11, 166, 16, 169, 9, 38, 16, 242, 7, 148, 15, 59, 6, 246, 14, 135, 4, 75, 14, 219, 2, 152, 13, 58, 1, 222, 12, 171, 255, 34, 12, 45, 254, 102, 11, 198, 252, 171, 10, 121, 251, 244, 9, 73, 250, 67, 9, 58, 249, 154, 8, 75, 248, 251, 7, 130, 247, 101, 7, 223, 246, 217, 6, 99, 246, 89, 6, 16, 246, 227, 5, 227, 245, 120, 5, 221, 245, 22, 5, 252, 245, 189, 4, 61, 246, 106, 4, 158, 246, 29, 4, 26, 247, 208, 3, 173, 247, 133, 3, 84, 248, 54, 3, 9, 249, 227, 2, 199, 249, 139, 2, 139, 250, 41, 2, 79, 251, 190, 1, 14, 252, 74, 1, 198, 252, 202, 0, 112, 253, 63, 0, 11, 254, 173, 255, 146, 254, 15, 255, 2, 255, 103, 254, 91, 255, 185, 253, 153, 255, 4, 253, 187, 255, 73, 252, 195, 255, 140, 251, 175, 255, 205, 250, 127, 255, 13, 250, 53, 255, 79, 249, 210, 254, 147, 248, 87, 254, 219, 247, 199, 253, 40, 247, 36, 253, 122, 246, 111, 252, 209, 245, 171, 251, 47, 245, 220, 250, 147, 244, 1, 250, 254, 243, 31, 249, 112, 243, 55, 248, 233, 242, 76, 247, 103, 242, 95, 246, 235, 241, 115, 245, 117, 241, 138, 244, 6, 241, 166, 243, 156, 240, 203, 242, 58, 240, 253, 241, 225, 239, 62, 241, 147, 239, 148, 240, 84, 239, 0, 240, 36, 239, 135, 239, 7, 239, 43, 239, 255, 238, 240, 238, 14, 239, 216, 238, 53, 239, 231, 238, 117, 239, 29, 239, 208, 239, 126, 239, 70, 240, 10, 240, 216, 240, 193, 240, 135, 241, 165, 241, 79, 242, 180, 242, 50, 243, 237, 243, 45, 244, 79, 245, 64, 245, 215, 246, 102, 246, 128, 248, 160, 247, 72, 250, 231, 248, 40, 252, 57, 250, 29, 254, 146, 251, 31, 0, 238, 252, 42, 2, 74, 254, 57, 4, 162, 255, 70, 6, 242, 0, 75, 8, 59, 2, 65, 10, 118, 3, 38, 12, 165, 4, 241, 13, 196, 5, 160, 15, 211, 6, 47, 17, 209, 7, 153, 18, 189, 8, 219, 19, 152, 9, 245, 20, 98, 10, 228, 21, 29, 11, 167, 22, 200, 11, 61, 23, 101, 12, 167, 23, 243, 12, 229, 23, 115, 13, 246, 23, 230, 13, 220, 23, 74, 14, 151, 23, 161, 14, 39, 23, 231, 14, 144, 22, 30, 15, 212, 21, 70, 15, 246, 20, 93, 15, 245, 19, 100, 15, 214, 18, 90, 15, 155, 17, 63, 15, 71, 16, 18, 15, 220, 14, 211, 14, 93, 13, 129, 14, 205, 11, 30, 14, 48, 10, 169, 13, 136, 8, 37, 13, 219, 6, 146, 12, 43, 5, 242, 11, 128, 3, 73, 11, 218, 1, 152, 10, 63, 0, 228, 9, 180, 254, 45, 9, 58, 253, 117, 8, 213, 251, 192, 7, 140, 250, 15, 7, 93, 249, 99, 6, 80, 248, 191, 5, 102, 247, 36, 5, 159, 246, 146, 4, 255, 245, 11, 4, 134, 245, 143, 3, 53, 245, 29, 3, 10, 245, 181, 2, 7, 245, 87, 2, 39, 245, 3, 2, 106, 245, 181, 1, 204, 245, 109, 1, 73, 246, 39, 1, 221, 246, 225, 0, 133, 247, 154, 0, 59, 248, 81, 0, 251, 248, 1, 0, 193, 249, 174, 255, 136, 250, 81, 255, 75, 251, 235, 254, 6, 252, 124, 254, 180, 252, 3, 254, 84, 253, 129, 253, 223, 253, 247, 252, 86, 254, 100, 252, 182, 254, 203, 251, 251, 254, 43, 251, 40, 255, 134, 250, 58, 255, 223, 249, 49, 255, 54, 249, 13, 255, 139, 248, 208, 254, 226, 247, 123, 254, 59, 247, 15, 254, 150, 246, 141, 253, 247, 245, 248, 252, 92, 245, 83, 252, 197, 244, 158, 251, 53, 244, 220, 250, 170, 243, 16, 250, 38, 243, 60, 249, 169, 242, 97, 248, 50, 242, 130, 247, 194, 241, 161, 246, 88, 241, 192, 245, 245, 240, 225, 244, 152, 240, 6, 244, 66, 240, 53, 243, 244, 239, 112, 242, 177, 239, 187, 241, 123, 239, 24, 241, 83, 239, 141, 240, 59, 239, 26, 240, 55, 239, 197, 239, 71, 239, 146, 239, 109, 239, 129, 239, 173, 239, 149, 239, 3, 240, 210, 239, 117, 240, 56, 240, 1, 241, 202, 240, 166, 241, 134, 241, 103, 242, 110, 242, 66, 243, 129, 243, 53, 244, 190, 244, 64, 245, 35, 246, 98, 246, 174, 247, 152, 247, 91, 249, 224, 248, 38, 251, 53, 250, 10, 253, 149, 251, 3, 255, 252, 252, 7, 1, 102, 254, 22, 3, 209, 255, 42, 5, 56, 1, 59, 7, 153, 2, 68, 9, 243, 3, 64, 11, 66, 5, 40, 13, 131, 6, 248, 14, 183, 7, 173, 16, 217, 8, 65, 18, 235, 9, 176, 19, 236, 10, 249, 20, 220, 11, 25, 22, 186, 12, 15, 23, 136, 13, 218, 23, 69, 14, 120, 24, 243, 14, 233, 24, 144, 15, 46, 25, 31, 16, 71, 25, 158, 16, 52, 25, 13, 17, 248, 24, 108, 17, 146, 24, 187, 17, 4, 24, 250, 17, 81, 23, 40, 18, 122, 22, 68, 18, 128, 21, 78, 18, 103, 20, 70, 18, 49, 19, 44, 18, 222, 17, 254, 17, 115, 16, 188, 17, 242, 14, 105, 17, 96, 13, 2, 17, 192, 11, 139, 16, 21, 10, 3, 16, 98, 8, 108, 15, 174, 6, 202, 14, 250, 4, 29, 14, 76, 3, 105, 13, 169, 1, 174, 12, 17, 0, 240, 11, 141, 254, 49, 11, 29, 253, 115, 10, 198, 251, 184, 9, 140, 250, 1, 9, 112, 249, 79, 8, 117, 248, 164, 7, 159, 247, 1, 7, 236, 246, 102, 6, 96, 246, 211, 5, 251, 245, 74, 5, 187, 245, 202, 4, 161, 245, 80, 4, 170, 245, 222, 3, 212, 245, 114, 3, 28, 246, 11, 3, 127, 246, 164, 2, 249, 246, 62, 2, 134, 247, 214, 1, 33, 248, 107, 1, 199, 248, 252, 0, 114, 249, 134, 0, 30, 250, 10, 0, 200, 250, 136, 255, 107, 251, 250, 254, 2, 252, 101, 254, 139, 252, 200, 253, 3, 253, 34, 253, 103, 253, 117, 252, 181, 253, 194, 251, 237, 253, 8, 251, 11, 254, 75, 250, 18, 254, 139, 249, 0, 254, 201, 248, 213, 253, 7, 248, 147, 253, 69, 247, 58, 253, 133, 246, 204, 252, 201, 245, 74, 252, 16, 245, 181, 251, 92, 244, 17, 251, 173, 243, 94, 250, 4, 243, 160, 249, 98, 242, 215, 248, 198, 241, 6, 248, 49, 241, 46, 247, 163, 240, 81, 246, 29, 240, 116, 245, 158, 239, 151, 244, 39, 239, 187, 243, 184, 238, 228, 242, 81, 238, 23, 242, 245, 237, 85, 241, 165, 237, 163, 240, 99, 237, 3, 240, 47, 237, 121, 239, 14, 237, 10, 239, 1, 237, 183, 238, 8, 237, 132, 238, 39, 237, 117, 238, 93, 237, 139, 238, 174, 237, 200, 238, 23, 238, 48, 239, 154, 238, 193, 239, 57, 239, 125, 240, 241, 239, 99, 241, 195, 240, 116, 242, 174, 241, 174, 243, 176, 242, 14, 245, 200, 243, 147, 246, 244, 244, 56, 248, 48, 246, 251, 249, 123, 247, 213, 251, 208, 248, 196, 253, 45, 250, 192, 255, 143, 251, 197, 1, 242, 252, 206, 3, 85, 254, 214, 5, 179, 255, 214, 7, 8, 1, 202, 9, 87, 2, 172, 11, 155, 3, 120, 13, 210, 4, 41, 15, 250, 5, 187, 16, 22, 7, 44, 18, 33, 8, 121, 19, 28, 9, 159, 20, 8, 10, 158, 21, 228, 10, 115, 22, 176, 11, 29, 23, 111, 12, 159, 23, 29, 13, 245, 23, 190, 13, 34, 24, 79, 14, 35, 24, 209, 14, 252, 23, 66, 15, 171, 23, 162, 15, 52, 23, 243, 15, 152, 22, 51, 16, 217, 21, 98, 16, 249, 20, 127, 16, 250, 19, 140, 16, 222, 18, 135, 16, 168, 17, 111, 16, 89, 16, 71, 16, 245, 14, 13, 16, 127, 13, 194, 15, 250, 11, 104, 15, 106, 10, 254, 14, 210, 8, 135, 14, 55, 7, 6, 14, 156, 5, 121, 13, 5, 4, 230, 12, 120, 2, 78, 12, 247, 0, 178, 11, 135, 255, 22, 11, 44, 254, 121, 10, 231, 252, 222, 9, 190, 251, 70, 9, 179, 250, 179, 8, 199, 249, 37, 8, 255, 248, 159, 7, 90, 248, 31, 7, 215, 247, 166, 6, 122, 247, 54, 6, 65, 247, 205, 5, 42, 247, 106, 5, 53, 247, 14, 5, 96, 247, 182, 4, 166, 247, 98, 4, 7, 248, 15, 4, 124, 248, 187, 3, 4, 249, 102, 3, 153, 249, 14, 3, 55, 250, 177, 2, 218, 250, 78, 2, 126, 251, 228, 1, 31, 252, 115, 1, 184, 252, 250, 0, 70, 253, 120, 0, 199, 253, 239, 255, 54, 254, 94, 255, 147, 254, 196, 254, 219, 254, 35, 254, 13, 255, 124, 253, 40, 255, 208, 252, 44, 255, 32, 252, 23, 255, 109, 251, 236, 254, 185, 250, 169, 254, 3, 250, 81, 254, 79, 249, 228, 253, 155, 248, 100, 253, 235, 247, 210, 252, 61, 247, 49, 252, 146, 246, 128, 251, 236, 245, 196, 250, 75, 245, 253, 249, 175, 244, 45, 249, 24, 244, 86, 248, 136, 243, 123, 247, 254, 242, 157, 246, 123, 242, 190, 245, 255, 241, 225, 244, 137, 241, 9, 244, 28, 241, 57, 243, 185, 240, 116, 242, 97, 240, 189, 241, 23, 240, 25, 241, 219, 239, 137, 240, 176, 239, 19, 240, 152, 239, 185, 239, 148, 239, 126, 239, 165, 239, 101, 239, 204, 239, 112, 239, 11, 240, 162, 239, 98, 240, 252, 239, 210, 240, 126, 240, 89, 241, 42, 241, 250, 241, 255, 241, 178, 242, 251, 242, 128, 243, 31, 244, 100, 244, 105, 245, 92, 245, 214, 246, 104, 246, 97, 248, 131, 247, 9, 250, 171, 248, 200, 251, 222, 249, 154, 253, 23, 251, 121, 255, 86, 252, 96, 1, 151, 253, 77, 3, 215, 254, 56, 5, 18, 0, 28, 7, 72, 1, 245, 8, 121, 2, 188, 10, 158, 3, 111, 12, 185, 4, 10, 14, 200, 5, 135, 15, 200, 6, 229, 16, 187, 7, 33, 18, 160, 8, 58, 19, 117, 9, 44, 20, 59, 10, 248, 20, 244, 10, 157, 21, 158, 11, 25, 22, 57, 12, 109, 22, 198, 12, 154, 22, 67, 13, 159, 22, 178, 13, 125, 22, 18, 14, 53, 22, 98, 14, 199, 21, 162, 14, 54, 21, 209, 14, 131, 20, 241, 14, 176, 19, 0, 15, 190, 18, 254, 14, 174, 17, 235, 14, 133, 16, 199, 14, 69, 15, 148, 14, 240, 13, 80, 14, 136, 12, 253, 13, 17, 11, 155, 13, 144, 9, 45, 13, 7, 8, 179, 12, 122, 6, 45, 12, 238, 4, 160, 11, 101, 3, 13, 11, 229, 1, 118, 10, 113, 0, 220, 9, 15, 255, 64, 9, 191, 253, 166, 8, 134, 252, 14, 8, 103, 251, 120, 7, 100, 250, 232, 6, 129, 249, 93, 6, 190, 248, 215, 5, 29, 248, 88, 5, 159, 247, 225, 4, 67, 247, 114, 4, 10, 247, 10, 4, 242, 246, 167, 3, 251, 246, 75, 3, 33, 247, 243, 2, 98, 247, 159, 2, 188, 247, 77, 2, 41, 248, 250, 1, 167, 248, 167, 1, 50, 249, 80, 1, 198, 249, 246, 0, 95, 250, 152, 0, 249, 250, 51, 0, 144, 251, 202, 255, 32, 252, 88, 255, 167, 252, 222, 254, 32, 253, 93, 254, 138, 253, 212, 253, 228, 253, 68, 253, 41, 254, 174, 252, 90, 254, 18, 252, 118, 254, 113, 251, 124, 254, 204, 250, 108, 254, 37, 250, 69, 254, 124, 249, 10, 254, 210, 248, 185, 253, 40, 248, 85, 253, 127, 247, 222, 252, 215, 246, 86, 252, 50, 246, 190, 251, 144, 245, 25, 251, 242, 244, 102, 250, 88, 244, 168, 249, 195, 243, 227, 248, 52, 243, 22, 248, 170, 242, 68, 247, 38, 242, 112, 246, 171, 241, 153, 245, 53, 241, 196, 244, 200, 240, 245, 243, 99, 240, 45, 243, 9, 240, 111, 242, 187, 239, 192, 241, 123, 239, 34, 241, 74, 239, 154, 240, 42, 239, 42, 240, 29, 239, 215, 239, 36, 239, 163, 239, 65, 239, 144, 239, 116, 239, 161, 239, 191, 239, 217, 239, 34, 240, 57, 240, 157, 240, 194, 240, 49, 241, 116, 241, 221, 241, 78, 242, 161, 242, 80, 243, 123, 243, 121, 244, 107, 244, 198, 245, 111, 245, 53, 247, 133, 246, 197, 248, 171, 247, 110, 250, 222, 248, 48, 252, 28, 250, 4, 254, 98, 251, 229, 255, 172, 252, 206, 1, 249, 253, 188, 3, 71, 255, 167, 5, 144, 0, 142, 7, 213, 1, 104, 9, 22, 3, 49, 11, 75, 4, 232, 12, 120, 5, 133, 14, 152, 6, 7, 16, 172, 7, 107, 17, 178, 8, 172, 18, 168, 9, 204, 19, 145, 10, 199, 20, 105, 11, 155, 21, 52, 12, 74, 22, 240, 12, 207, 22, 155, 13, 47, 23, 57, 14, 101, 23, 197, 14, 115, 23, 64, 15, 89, 23, 172, 15, 25, 23, 6, 16, 180, 22, 79, 16, 43, 22, 135, 16, 127, 21, 174, 16, 179, 20, 195, 16, 199, 19, 199, 16, 190, 18, 185, 16, 155, 17, 154, 16, 96, 16, 108, 16, 15, 15, 43, 16, 171, 13, 220, 15, 56, 12, 126, 15, 185, 10, 19, 15, 49, 9, 155, 14, 165, 7, 25, 14, 25, 6, 143, 13, 143, 4, 254, 12, 14, 3, 105, 12, 152, 1, 207, 11, 51, 0, 52, 11, 227, 254, 153, 10, 166, 253, 255, 9, 132, 252, 103, 9, 125, 251, 210, 8, 148, 250, 66, 8, 204, 249, 183, 7, 35, 249, 49, 7, 156, 248, 177, 6, 55, 248, 56, 6, 243, 247, 197, 5, 208, 247, 87, 5, 204, 247, 238, 4, 227, 247, 138, 4, 21, 248, 39, 4, 95, 248, 198, 3, 189, 248, 100, 3, 42, 249, 2, 3, 163, 249, 156, 2, 37, 250, 50, 2, 172, 250, 197, 1, 51, 251, 81, 1, 182, 251, 216, 0, 52, 252, 87, 0, 168, 252, 208, 255, 17, 253, 66, 255, 106, 253, 172, 254, 179, 253, 14, 254, 235, 253, 107, 253, 14, 254, 193, 252, 29, 254, 19, 252, 25, 254, 97, 251, 254, 253, 171, 250, 207, 253, 244, 249, 140, 253, 59, 249, 53, 253, 129, 248, 203, 252, 201, 247, 79, 252, 17, 247, 196, 251, 92, 246, 41, 251, 169, 245, 129, 250, 249, 244, 204, 249, 78, 244, 13, 249, 167, 243, 70, 248, 6, 243, 121, 247, 106, 242, 166, 246, 214, 241, 209, 245, 72, 241, 251, 244, 194, 240, 38, 244, 69, 240, 88, 243, 208, 239, 144, 242, 104, 239, 212, 241, 12, 239, 39, 241, 190, 238, 139, 240, 130, 238, 4, 240, 86, 238, 152, 239, 60, 238, 70, 239, 56, 238, 20, 239, 73, 238, 3, 239, 113, 238, 22, 239, 175, 238, 78, 239, 6, 239, 173, 239, 116, 239, 51, 240, 251, 239, 224, 240, 153, 240, 181, 241, 78, 241, 177, 242, 25, 242, 209, 243, 250, 242, 23, 245, 238, 243, 124, 246, 245, 244, 255, 247, 11, 246, 157, 249, 47, 247, 80, 251, 94, 248, 22, 253, 148, 249, 234, 254, 210, 250, 196, 0, 18, 252, 162, 2, 83, 253, 128, 4, 148, 254, 87, 6, 209, 255, 36, 8, 7, 1, 226, 9, 56, 2, 141, 11, 97, 3, 34, 13, 127, 4, 156, 14, 144, 5, 251, 15, 149, 6, 58, 17, 143, 7, 89, 18, 122, 8, 85, 19, 88, 9, 46, 20, 40, 10, 227, 20, 233, 10, 114, 21, 157, 11, 219, 21, 64, 12, 30, 22, 213, 12, 59, 22, 89, 13, 50, 22, 207, 13, 5, 22, 52, 14, 179, 21, 135, 14, 64, 21, 203, 14, 170, 20, 254, 14, 243, 19, 32, 15, 29, 19, 47, 15, 42, 18, 47, 15, 30, 17, 31, 15, 250, 15, 254, 14, 192, 14, 205, 14, 114, 13, 142, 14, 22, 12, 64, 14, 174, 10, 231, 13, 61, 9, 130, 13, 199, 7, 21, 13, 81, 6, 159, 12, 222, 4, 35, 12, 114, 3, 162, 11, 17, 2, 30, 11, 191, 0, 153, 10, 129, 255, 19, 10, 87, 254, 142, 9, 68, 253, 11, 9, 75, 252, 138, 8, 111, 251, 14, 8, 177, 250, 149, 7, 17, 250, 35, 7, 146, 249, 181, 6, 50, 249, 77, 6, 241, 248, 234, 5, 208, 248, 141, 5, 203, 248, 52, 5, 225, 248, 220, 4, 15, 249, 137, 4, 83, 249, 54, 4, 170, 249, 226, 3, 15, 250, 141, 3, 128, 250, 54, 3, 248, 250, 220, 2, 116, 251, 125, 2, 241, 251, 24, 2, 107, 252, 173, 1, 223, 252, 60, 1, 75, 253, 195, 0, 172, 253, 68, 0, 255, 253, 190, 255, 67, 254, 48, 255, 117, 254, 156, 254, 150, 254, 1, 254, 164, 254, 98, 253, 157, 254, 189, 252, 132, 254, 19, 252, 86, 254, 104, 251, 21, 254, 185, 250, 193, 253, 10, 250, 90, 253, 89, 249, 226, 252, 169, 248, 90, 252, 249, 247, 195, 251, 76, 247, 30, 251, 160, 246, 109, 250, 246, 245, 177, 249, 81, 245, 235, 248, 176, 244, 31, 248, 20, 244, 79, 247, 125, 243, 122, 246, 236, 242, 164, 245, 98, 242, 207, 244, 224, 241, 255, 243, 103, 241, 54, 243, 250, 240, 119, 242, 153, 240, 200, 241, 70, 240, 41, 241, 3, 240, 159, 240, 208, 239, 46, 240, 175, 239, 217, 239, 163, 239, 162, 239, 173, 239, 140, 239, 202, 239, 153, 239, 0, 240, 203, 239, 76, 240, 34, 240, 175, 240, 161, 240, 42, 241, 69, 241, 187, 241, 17, 242, 100, 242, 2, 243, 34, 243, 24, 244, 244, 243, 82, 245, 219, 244, 172, 246, 211, 245, 35, 248, 218, 246, 179, 249, 238, 247, 90, 251, 14, 249, 18, 253, 55, 250, 217, 254, 101, 251, 165, 0, 152, 252, 118, 2, 204, 253, 71, 4, 1, 255, 19, 6, 49, 0, 212, 7, 93, 1, 136, 9, 133, 2, 43, 11, 164, 3, 184, 12, 186, 4, 44, 14, 196, 5, 132, 15, 195, 6, 193, 16, 182, 7, 221, 17, 155, 8, 217, 18, 115, 9, 178, 19, 62, 10, 103, 20, 249, 10, 249, 20, 165, 11, 100, 21, 67, 12, 171, 21, 209, 12, 202, 21, 77, 13, 198, 21, 186, 13, 157, 21, 22, 14, 80, 21, 98, 14, 225, 20, 156, 14, 80, 20, 196, 14, 159, 19, 221, 14, 209, 18, 228, 14, 229, 17, 219, 14, 221, 16, 195, 14, 192, 15, 153, 14, 140, 14, 97, 14, 69, 13, 27, 14, 238, 11, 199, 13, 139, 10, 103, 13, 32, 9, 253, 12, 174, 7, 139, 12, 62, 6, 16, 12, 208, 4, 144, 11, 105, 3, 12, 11, 14, 2, 133, 10, 192, 0, 253, 9, 133, 255, 116, 9, 95, 254, 235, 8, 79, 253, 102, 8, 89, 252, 226, 7, 126, 251, 98, 7, 193, 250, 232, 6, 33, 250, 114, 6, 159, 249, 1, 6, 61, 249, 149, 5, 249, 248, 48, 5, 211, 248, 206, 4, 199, 248, 113, 4, 215, 248, 23, 4, 254, 248, 192, 3, 58, 249, 105, 3, 136, 249, 19, 3, 228, 249, 188, 2, 75, 250, 98, 2, 186, 250, 5, 2, 44, 251, 165, 1, 159, 251, 64, 1, 16, 252, 213, 0, 123, 252, 101, 0, 223, 252, 239, 255, 56, 253, 115, 255, 132, 253, 238, 254, 195, 253, 99, 254, 241, 253, 211, 253, 15, 254, 59, 253, 26, 254, 158, 252, 18, 254, 253, 251, 248, 253, 88, 251, 203, 253, 175, 250, 139, 253, 4, 250, 57, 253, 88, 249, 213, 252, 170, 248, 96, 252, 251, 247, 219, 251, 78, 247, 71, 251, 160, 246, 166, 250, 244, 245, 249, 249, 76, 245, 65, 249, 166, 244, 128, 248, 5, 244, 183, 247, 104, 243, 235, 246, 209, 242, 26, 246, 64, 242, 72, 245, 182, 241, 119, 244, 52, 241, 171, 243, 188, 240, 230, 242, 79, 240, 45, 242, 240, 239, 129, 241, 158, 239, 232, 240, 94, 239, 100, 240, 45, 239, 249, 239, 16, 239, 170, 239, 7, 239, 121, 239, 19, 239, 104, 239, 52, 239, 122, 239, 109, 239, 176, 239, 188, 239, 11, 240, 34, 240, 140, 240, 160, 240, 51, 241, 53, 241, 1, 242, 223, 241, 244, 242, 161, 242, 10, 244, 119, 243, 68, 245, 95, 244, 157, 246, 90, 245, 18, 248, 101, 246, 162, 249, 125, 247, 71, 251, 161, 248, 252, 252, 207, 249, 191, 254, 2, 251, 136, 0, 58, 252, 87, 2, 118, 253, 37, 4, 178, 254, 239, 5, 236, 255, 175, 7, 33, 1, 97, 9, 82, 2, 3, 11, 125, 3, 145, 12, 158, 4, 8, 14, 182, 5, 102, 15, 194, 6, 167, 16, 195, 7, 201, 17, 182, 8, 204, 18, 157, 9, 175, 19, 118, 10, 110, 20, 64, 11, 10, 21, 252, 11, 130, 21, 168, 12, 214, 21, 69, 13, 5, 22, 208, 13, 15, 22, 76, 14, 246, 21, 182, 14, 184, 21, 15, 15, 88, 21, 86, 15, 213, 20, 139, 15, 49, 20, 174, 15, 111, 19, 191, 15, 143, 18, 192, 15, 148, 17, 176, 15, 129, 16, 142, 15, 87, 15, 95, 15, 26, 14, 33, 15, 205, 12, 213, 14, 115, 11, 125, 14, 15, 10, 27, 14, 167, 8, 175, 13, 61, 7, 59, 13, 214, 5, 194, 12, 117, 4, 67, 12, 29, 3, 193, 11, 213, 1, 60, 11, 156, 0, 183, 10, 120, 255, 51, 10, 106, 254, 175, 9, 114, 253, 45, 9, 150, 252, 174, 8, 213, 251, 50, 8, 48, 251, 186, 7, 169, 250, 71, 7, 63, 250, 217, 6, 243, 249, 111, 6, 195, 249, 9, 6, 173, 249, 167, 5, 176, 249, 71, 5, 201, 249, 233, 4, 246, 249, 141, 4, 51, 250, 48, 4, 127, 250, 210, 3, 212, 250, 114, 3, 48, 251, 14, 3, 145, 251, 167, 2, 243, 251, 59, 2, 83, 252, 202, 1, 174, 252, 83, 1, 2, 253, 214, 0, 76, 253, 83, 0, 138, 253, 201, 255, 188, 253, 57, 255, 223, 253, 162, 254, 242, 253, 4, 254, 244, 253, 98, 253, 228, 253, 186, 252, 195, 253, 14, 252, 144, 253, 94, 251, 75, 253, 170, 250, 245, 252, 244, 249, 141, 252, 61, 249, 21, 252, 132, 248, 141, 251, 204, 247, 247, 250, 19, 247, 85, 250, 92, 246, 166, 249, 167, 245, 236, 248, 245, 244, 42, 248, 71, 244, 97, 247, 156, 243, 147, 246, 246, 242, 192, 245, 87, 242, 237, 244, 191, 241, 27, 244, 48, 241, 78, 243, 170, 240, 137, 242, 48, 240, 207, 241, 195, 239, 36, 241, 101, 239, 139, 240, 22, 239, 7, 240, 218, 238, 155, 239, 175, 238, 75, 239, 153, 238, 26, 239, 153, 238, 8, 239, 174, 238, 23, 239, 218, 238, 76, 239, 28, 239, 165, 239, 119, 239, 35, 240, 233, 239, 199, 240, 113, 240, 144, 241, 16, 241, 125, 242, 197, 241, 143, 243, 143, 242, 192, 244, 109, 243, 17, 246, 91, 244, 126, 247, 91, 245, 4, 249, 104, 246, 159, 250, 130, 247, 75, 252, 165, 248, 3, 254, 208, 249, 196, 255, 1, 251, 136, 1, 54, 252, 77, 3, 107, 253, 15, 5, 162, 254, 200, 6, 213, 255, 117, 8, 2, 1, 18, 10, 44, 2, 158, 11, 79, 3, 19, 13, 104, 4, 112, 14, 119, 5, 178, 15, 122, 6, 216, 16, 115, 7, 224, 17, 95, 8, 199, 18, 61, 9, 141, 19, 12, 10, 50, 20, 206, 10, 179, 20, 128, 11, 16, 21, 34, 12, 74, 21, 180, 12, 96, 21, 53, 13, 81, 21, 165, 13, 33, 21, 3, 14, 206, 20, 80, 14, 90, 20, 139, 14, 198, 19, 181, 14, 20, 19, 207, 14, 68, 18, 214, 14, 90, 17, 206, 14, 87, 16, 182, 14, 61, 15, 143, 14, 16, 14, 89, 14, 210, 12, 22, 14, 135, 11, 200, 13, 52, 10, 110, 13, 218, 8, 13, 13, 128, 7, 164, 12, 39, 6, 52, 12, 212, 4, 192, 11, 139, 3, 73, 11, 78, 2, 208, 10, 34, 1, 86, 10, 7, 0, 219, 9, 4, 255, 97, 9, 21, 254, 234, 8, 64, 253, 117, 8, 133, 252, 3, 8, 228, 251, 150, 7, 95, 251, 45, 7, 247, 250, 199, 6, 170, 250, 103, 6, 120, 250, 9, 6, 95, 250, 176, 5, 93, 250, 88, 5, 113, 250, 2, 5, 151, 250, 174, 4, 205, 250, 88, 4, 15, 251, 3, 4, 92, 251, 170, 3, 174, 251, 80, 3, 5, 252, 242, 2, 94, 252, 143, 2, 180, 252, 39, 2, 6, 253, 187, 1, 82, 253, 72, 1, 150, 253, 207, 0, 206, 253, 78, 0, 250, 253, 202, 255, 24, 254, 62, 255, 39, 254, 170, 254, 39, 254, 18, 254, 22, 254, 117, 253, 245, 253, 210, 252, 194, 253, 43, 252, 126, 253, 129, 251, 41, 253, 211, 250, 196, 252, 35, 250, 78, 252, 113, 249, 200, 251, 189, 248, 54, 251, 10, 248, 150, 250, 87, 247, 235, 249, 165, 246, 52, 249, 244, 245, 118, 248, 71, 245, 175, 247, 157, 244, 226, 246, 248, 243, 19, 246, 88, 243, 66, 245, 191, 242, 115, 244, 45, 242, 169, 243, 165, 241, 230, 242, 41, 241, 46, 242, 184, 240, 133, 241, 86, 240, 238, 240, 4, 240, 107, 240, 195, 239, 2, 240, 148, 239, 178, 239, 120, 239, 128, 239, 114, 239, 109, 239, 127, 239, 123, 239, 164, 239, 171, 239, 222, 239, 0, 240, 47, 240, 120, 240, 151, 240, 20, 241, 22, 241, 214, 241, 170, 241, 186, 242, 83, 242, 192, 243, 18, 243, 232, 244, 228, 243, 46, 246, 199, 244, 142, 247, 186, 245, 7, 249, 188, 246, 147, 250, 201, 247, 49, 252, 225, 248, 219, 253, 2, 250, 141, 255, 40, 251, 66, 1, 84, 252, 249, 2, 128, 253, 173, 4, 174, 254, 90, 6, 218, 255, 252, 7, 1, 1, 144, 9, 36, 2, 18, 11, 65, 3, 129, 12, 86, 4, 218, 13, 98, 5, 24, 15, 100, 6, 61, 16, 91, 7, 68, 17, 69, 8, 46, 18, 34, 9, 248, 18, 242, 9, 160, 19, 179, 10, 40, 20, 101, 11, 141, 20, 7, 12, 207, 20, 153, 12, 238, 20, 27, 13, 235, 20, 139, 13, 197, 20, 234, 13, 126, 20, 55, 14, 20, 20, 114, 14, 139, 19, 156, 14, 227, 18, 179, 14, 32, 18, 187, 14, 65, 17, 177, 14, 73, 16, 152, 14, 59, 15, 112, 14, 25, 14, 58, 14, 231, 12, 247, 13, 169, 11, 169, 13, 98, 10, 81, 13, 19, 9, 238, 12, 196, 7, 134, 12, 118, 6, 23, 12, 46, 5, 163, 11, 239, 3, 44, 11, 186, 2, 179, 10, 148, 1, 56, 10, 127, 0, 189, 9, 129, 255, 67, 9, 150, 254, 202, 8, 194, 253, 84, 8, 8, 253, 226, 7, 103, 252, 114, 7, 224, 251, 5, 7, 115, 251, 158, 6, 33, 251, 58, 6, 232, 250, 218, 5, 199, 250, 124, 5, 187, 250, 34, 5, 195, 250, 201, 4, 221, 250, 114, 4, 5, 251, 26, 4, 58, 251, 193, 3, 120, 251, 103, 3, 189, 251, 11, 3, 5, 252, 171, 2, 80, 252, 71, 2, 153, 252, 223, 1, 223, 252, 115, 1, 31, 253, 1, 1, 86, 253, 137, 0, 134, 253, 10, 0, 169, 253, 136, 255, 191, 253, 253, 254, 201, 253, 109, 254, 195, 253, 214, 253, 174, 253, 59, 253, 137, 253, 155, 252, 85, 253, 245, 251, 16, 253, 76, 251, 187, 252, 160, 250, 87, 252, 241, 249, 226, 251, 63, 249, 96, 251, 141, 248, 207, 250, 217, 247, 50, 250, 38, 247, 139, 249, 115, 246, 216, 248, 193, 245, 29, 248, 19, 245, 91, 247, 103, 244, 147, 246, 192, 243, 201, 245, 29, 243, 253, 244, 129, 242, 50, 244, 237, 241, 110, 243, 99, 241, 177, 242, 227, 240, 255, 241, 112, 240, 92, 241, 12, 240, 203, 240, 183, 239, 79, 240, 115, 239, 234, 239, 66, 239, 159, 239, 35, 239, 113, 239, 24, 239, 97, 239, 36, 239, 114, 239, 69, 239, 165, 239, 124, 239, 249, 239, 202, 239, 113, 240, 46, 240, 13, 241, 169, 240, 203, 241, 57, 241, 172, 242, 223, 241, 174, 243, 153, 242, 208, 244, 102, 243, 14, 246, 69, 244, 102, 247, 52, 245, 213, 248, 50, 246, 88, 250, 61, 247, 236, 251, 82, 248, 139, 253, 112, 249, 52, 255, 150, 250, 223, 0, 192, 251, 142, 2, 238, 252, 57, 4, 29, 254, 222, 5, 75, 255, 123, 7, 118, 0, 11, 9, 157, 1, 137, 10, 193, 2, 246, 11, 220, 3, 78, 13, 240, 4, 142, 14, 249, 5, 181, 15, 248, 6, 193, 16, 237, 7, 177, 17, 211, 8, 129, 18, 173, 9, 50, 19, 120, 10, 194, 19, 54, 11, 50, 20, 226, 11, 127, 20, 126, 12, 171, 20, 10, 13, 182, 20, 132, 13, 157, 20, 238, 13, 101, 20, 69, 14, 11, 20, 139, 14, 148, 19, 192, 14, 254, 18, 226, 14, 74, 18, 244, 14, 125, 17, 245, 14, 150, 16, 230, 14, 153, 15, 199, 14, 137, 14, 154, 14, 102, 13, 96, 14, 55, 12, 26, 14, 255, 10, 203, 13, 193, 9, 113, 13, 129, 8, 16, 13, 65, 7, 169, 12, 6, 6, 61, 12, 210, 4, 203, 11, 169, 3, 88, 11, 141, 2, 227, 10, 128, 1, 108, 10, 134, 0, 247, 9, 160, 255, 130, 9, 208, 254, 15, 9, 22, 254, 158, 8, 115, 253, 48, 8, 234, 252, 198, 7, 121, 252, 95, 7, 32, 252, 251, 6, 222, 251, 155, 6, 179, 251, 61, 6, 156, 251, 225, 5, 151, 251, 134, 5, 162, 251, 43, 5, 187, 251, 209, 4, 224, 251, 118, 4, 13, 252, 25, 4, 64, 252, 187, 3, 121, 252, 89, 3, 177, 252, 243, 2, 235, 252, 138, 2, 32, 253, 27, 2, 81, 253, 168, 1, 123, 253, 46, 1, 156, 253, 175, 0, 180, 253, 42, 0, 191, 253, 160, 255, 190, 253, 16, 255, 176, 253, 121, 254, 148, 253, 221, 253, 106, 253, 60, 253, 47, 253, 150, 252, 230, 252, 236, 251, 141, 252, 61, 251, 38, 252, 140, 250, 177, 251, 216, 249, 46, 251, 33, 249, 157, 250, 106, 248, 0, 250, 178, 247, 89, 249, 249, 246, 168, 248, 67, 246, 238, 247, 142, 245, 46, 247, 220, 244, 104, 246, 45, 244, 160, 245, 131, 243, 215, 244, 224, 242, 16, 244, 68, 242, 79, 243, 178, 241, 150, 242, 42, 241, 232, 241, 174, 240, 73, 241, 66, 240, 188, 240, 227, 239, 67, 240, 150, 239, 224, 239, 91, 239, 152, 239, 50, 239, 107, 239, 30, 239, 92, 239, 30, 239, 108, 239, 52, 239, 156, 239, 95, 239, 239, 239, 161, 239, 98, 240, 249, 239, 248, 240, 103, 240, 175, 241, 235, 240, 136, 242, 131, 241, 129, 243, 49, 242, 152, 244, 242, 242, 203, 245, 195, 243, 23, 247, 167, 244, 121, 248, 152, 245, 238, 249, 150, 246, 114, 251, 161, 247, 4, 253, 180, 248, 158, 254, 208, 249, 60, 0, 242, 250, 219, 1, 23, 252, 122, 3, 62, 253, 20, 5, 103, 254, 165, 6, 141, 255, 43, 8, 176, 0, 162, 9, 207, 1, 8, 11, 232, 2, 91, 12, 251, 3, 153, 13, 5, 5, 191, 14, 5, 6, 204, 15, 251, 6, 189, 16, 228, 7, 146, 17, 193, 8, 73, 18, 144, 9, 225, 18, 80, 10, 89, 19, 2, 11, 176, 19, 163, 11, 230, 19, 52, 12, 253, 19, 181, 12, 242, 19, 35, 13, 199, 19, 129, 13, 124, 19, 203, 13, 19, 19, 5, 14, 140, 18, 46, 14, 232, 17, 70, 14, 43, 17, 77, 14, 86, 16, 69, 14, 107, 15, 46, 14, 108, 14, 9, 14, 93, 13, 215, 13, 66, 12, 153, 13, 29, 11, 81, 13, 243, 9, 1, 13, 197, 8, 168, 12, 151, 7, 73, 12, 109, 6, 230, 11, 73, 5, 126, 11, 47, 4, 18, 11, 33, 3, 165, 10, 32, 2, 53, 10, 50, 1, 200, 9, 84, 0, 91, 9, 141, 255, 238, 8, 217, 254, 132, 8, 58, 254, 28, 8, 180, 253, 183, 7, 67, 253, 86, 7, 232, 252, 247, 6, 164, 252, 154, 6, 115, 252, 65, 6, 85, 252, 233, 5, 71, 252, 147, 5, 72, 252, 61, 5, 87, 252, 232, 4, 112, 252, 146, 4, 145, 252, 57, 4, 184, 252, 224, 3, 227, 252, 131, 3, 17, 253, 35, 3, 61, 253, 192, 2, 103, 253, 88, 2, 141, 253, 234, 1, 172, 253, 120, 1, 196, 253, 0, 1, 211, 253, 130, 0, 215, 253, 0, 0, 208, 253, 120, 255, 188, 253, 233, 254, 156, 253, 84, 254, 110, 253, 187, 253, 49, 253, 28, 253, 230, 252, 120, 252, 142, 252, 209, 251, 39, 252, 38, 251, 178, 251, 119, 250, 49, 251, 199, 249, 163, 250, 19, 249, 10, 250, 95, 248, 101, 249, 171, 247, 184, 248, 247, 246, 3, 248, 68, 246, 71, 247, 147, 245, 134, 246, 229, 244, 195, 245, 60, 244, 0, 245, 152, 243, 63, 244, 252, 242, 131, 243, 105, 242, 209, 242, 223, 241, 41, 242, 98, 241, 144, 241, 242, 240, 8, 241, 144, 240, 148, 240, 63, 240, 54, 240, 255, 239, 240, 239, 209, 239, 198, 239, 182, 239, 184, 239, 175, 239, 199, 239, 189, 239, 245, 239, 225, 239, 69, 240, 26, 240, 181, 240, 104, 240, 69, 241, 204, 240, 245, 241, 70, 241, 197, 242, 211, 241, 179, 243, 117, 242, 190, 244, 41, 243, 228, 245, 239, 243, 32, 247, 199, 244, 116, 248, 172, 245, 216, 249, 158, 246, 76, 251, 156, 247, 205, 252, 165, 248, 86, 254, 182, 249, 228, 255, 205, 250, 115, 1, 233, 251, 3, 3, 8, 253, 143, 4, 40, 254, 19, 6, 73, 255, 141, 7, 102, 0, 250, 8, 127, 1, 89, 10, 150, 2, 165, 11, 165, 3, 221, 12, 173, 4, 0, 14, 172, 5, 10, 15, 160, 6, 252, 15, 138, 7, 209, 16, 103, 8, 139, 17, 55, 9, 40, 18, 251, 9, 165, 18, 173, 10, 4, 19, 81, 11, 68, 19, 229, 11, 100, 19, 104, 12, 101, 19, 218, 12, 70, 19, 59, 13, 10, 19, 139, 13, 174, 18, 202, 13, 55, 18, 247, 13, 164, 17, 20, 14, 247, 16, 33, 14, 52, 16, 29, 14, 89, 15, 10, 14, 108, 14, 234, 13, 113, 13, 189, 13, 103, 12, 132, 13, 84, 11, 66, 13, 59, 10, 246, 12, 31, 9, 162, 12, 2, 8, 72, 12, 231, 6, 231, 11, 211, 5, 131, 11, 198, 4, 27, 11, 196, 3, 177, 10, 206, 2, 70, 10, 232, 1, 218, 9, 18, 1, 109, 9, 79, 0, 3, 9, 160, 255, 155, 8, 4, 255, 52, 8, 124, 254, 207, 7, 9, 254, 109, 7, 170, 253, 14, 7, 94, 253, 176, 6, 38, 253, 86, 6, 253, 252, 253, 5, 228, 252, 165, 5, 217, 252, 78, 5, 218, 252, 246, 4, 228, 252, 158, 4, 246, 252, 68, 4, 14, 253, 234, 3, 42, 253, 141, 3, 71, 253, 44, 3, 100, 253, 200, 2, 128, 253, 96, 2, 151, 253, 243, 1, 169, 253, 130, 1, 181, 253, 10, 1, 185, 253, 142, 0, 179, 253, 13, 0, 162, 253, 135, 255, 135, 253, 250, 254, 95, 253, 103, 254, 42, 253, 208, 253, 232, 252, 51, 253, 155, 252, 146, 252, 63, 252, 236, 251, 214, 251, 66, 251, 98, 251, 149, 250, 224, 250, 230, 249, 83, 250, 52, 249, 187, 249, 128, 248, 25, 249, 204, 247, 111, 248, 24, 247, 190, 247, 101, 246, 5, 247, 178, 245, 74, 246, 3, 245, 140, 245, 89, 244, 208, 244, 179, 243, 22, 244, 21, 243, 98, 243, 127, 242, 182, 242, 243, 241, 22, 242, 115, 241, 132, 241, 0, 241, 3, 241, 155, 240, 150, 240, 69, 240, 62, 240, 1, 240, 253, 239, 205, 239, 215, 239, 174, 239, 204, 239, 161, 239, 222, 239, 169, 239, 13, 240, 199, 239, 92, 240, 248, 239, 201, 240, 63, 240, 86, 241, 155, 240, 1, 242, 13, 241, 203, 242, 145, 241, 177, 243, 43, 242, 178, 244, 215, 242, 206, 245, 148, 243, 255, 246, 98, 244, 69, 248, 63, 245, 156, 249, 41, 246, 2, 251, 31, 247, 116, 252, 33, 248, 239, 253, 43, 249, 112, 255, 61, 250, 242, 0, 83, 251, 116, 2, 109, 252, 243, 3, 138, 253, 108, 5, 167, 254, 221, 6, 195, 255, 66, 8, 220, 0, 154, 9, 242, 1, 224, 10, 2, 3, 21, 12, 12, 4, 54, 13, 13, 5, 64, 14, 7, 6, 50, 15, 245, 6, 11, 16, 216, 7, 202, 16, 174, 8, 108, 17, 119, 9, 241, 17, 49, 10, 89, 18, 220, 10, 164, 18, 120, 11, 208, 18, 3, 12, 221, 18, 126, 12, 205, 18, 232, 12, 159, 18, 64, 13, 84, 18, 136, 13, 238, 17, 191, 13, 108, 17, 229, 13, 210, 16, 252, 13, 34, 16, 1, 14, 93, 15, 250, 13, 134, 14, 228, 13, 160, 13, 193, 13, 172, 12, 147, 13, 175, 11, 90, 13, 171, 10, 25, 13, 163, 9, 206, 12, 154, 8, 125, 12, 146, 7, 38, 12, 143, 6, 202, 11, 146, 5, 107, 11, 158, 4, 7, 11, 182, 3, 163, 10, 218, 2, 61, 10, 13, 2, 215, 9, 81, 1, 113, 9, 166, 0, 12, 9, 14, 0, 169, 8, 136, 255, 70, 8, 20, 255, 231, 7, 176, 254, 137, 7, 96, 254, 46, 7, 31, 254, 211, 6, 237, 253, 122, 6, 201, 253, 35, 6, 177, 253, 203, 5, 163, 253, 115, 5, 158, 253, 27, 5, 161, 253, 193, 4, 170, 253, 102, 4, 181, 253, 8, 4, 193, 253, 167, 3, 207, 253, 67, 3, 219, 253, 219, 2, 227, 253, 110, 2, 231, 253, 253, 1, 228, 253, 135, 1, 219, 253, 13, 1, 200, 253, 140, 0, 173, 253, 6, 0, 135, 253, 124, 255, 86, 253, 235, 254, 26, 253, 85, 254, 210, 252, 186, 253, 126, 252, 25, 253, 30, 252, 118, 252, 178, 251, 204, 251, 58, 251, 32, 251, 183, 250, 113, 250, 42, 250, 190, 249, 146, 249, 11, 249, 242, 248, 86, 248, 73, 248, 161, 247, 154, 247, 236, 246, 230, 246, 56, 246, 46, 246, 134, 245, 118, 245, 217, 244, 191, 244, 49, 244, 11, 244, 144, 243, 94, 243, 246, 242, 186, 242, 102, 242, 32, 242, 225, 241, 149, 241, 106, 241, 27, 241, 254, 240, 179, 240, 163, 240, 96, 240, 88, 240, 35, 240, 30, 240, 0, 240, 246, 239, 247, 239, 224, 239, 9, 240, 224, 239, 56, 240, 242, 239, 132, 240, 26, 240, 238, 240, 85, 240, 118, 241, 166, 240, 26, 242, 11, 241, 219, 242, 132, 241, 183, 243, 16, 242, 173, 244, 175, 242, 186, 245, 95, 243, 221, 246, 31, 244, 20, 248, 238, 244, 91, 249, 203, 245, 176, 250, 182, 246, 17, 252, 169, 247, 123, 253, 168, 248, 234, 254, 173, 249, 91, 0, 185, 250, 205, 1, 202, 251, 62, 3, 221, 252, 168, 4, 242, 253, 11, 6, 8, 255, 101, 7, 25, 0, 177, 8, 41, 1, 240, 9, 52, 2, 29, 11, 59, 3, 56, 12, 59, 4, 63, 13, 50, 5, 47, 14, 31, 6, 8, 15, 1, 7, 199, 15, 216, 7, 109, 16, 162, 8, 248, 16, 95, 9, 102, 17, 13, 10, 184, 17, 172, 10, 237, 17, 60, 11, 6, 18, 187, 11, 1, 18, 42, 12, 226, 17, 137, 12, 166, 17, 214, 12, 80, 17, 21, 13, 225, 16, 66, 13, 90, 16, 95, 13, 189, 15, 110, 13, 13, 15, 110, 13, 75, 14, 97, 13, 122, 13, 70, 13, 157, 12, 34, 13, 183, 11, 242, 12, 201, 10, 185, 12, 215, 9, 120, 12, 227, 8, 47, 12, 239, 7, 225, 11, 0, 7, 142, 11, 22, 6, 54, 11, 51, 5, 219, 10, 90, 4, 126, 10, 140, 3, 31, 10, 204, 2, 192, 9, 25, 2, 97, 9, 118, 1, 3, 9, 227, 0, 165, 8, 95, 0, 72, 8, 238, 255, 237, 7, 139, 255, 148, 7, 55, 255, 59, 7, 242, 254, 229, 6, 184, 254, 144, 6, 141, 254, 59, 6, 107, 254, 229, 5, 83, 254, 145, 5, 67, 254, 59, 5, 57, 254, 228, 4, 52, 254, 139, 4, 51, 254, 49, 4, 50, 254, 210, 3, 50, 254, 114, 3, 48, 254, 14, 3, 44, 254, 166, 2, 36, 254, 56, 2, 21, 254, 199, 1, 1, 254, 81, 1, 228, 253, 213, 0, 191, 253, 85, 0, 146, 253, 208, 255, 90, 253, 69, 255, 23, 253, 180, 254, 202, 252, 31, 254, 114, 252, 131, 253, 15, 252, 228, 252, 160, 251, 65, 252, 39, 251, 153, 251, 164, 250, 238, 250, 23, 250, 65, 250, 129, 249, 145, 249, 227, 248, 224, 248, 62, 248, 45, 248, 146, 247, 124, 247, 227, 246, 202, 246, 50, 246, 27, 246, 128, 245, 112, 245, 208, 244, 201, 244, 36, 244, 40, 244, 126, 243, 143, 243, 226, 242, 255, 242, 81, 242, 121, 242, 206, 241, 0, 242, 91, 241, 147, 241, 249, 240, 53, 241, 172, 240, 230, 240, 118, 240, 168, 240, 86, 240, 123, 240, 80, 240, 97, 240, 99, 240, 89, 240, 146, 240, 100, 240, 221, 240, 132, 240, 67, 241, 183, 240, 198, 241, 255, 240, 99, 242, 89, 241, 28, 243, 200, 241, 238, 243, 73, 242, 216, 244, 220, 242, 216, 245, 128, 243, 237, 246, 52, 244, 20, 248, 247, 244, 75, 249, 200, 245, 143, 250, 166, 246, 223, 251, 142, 247, 55, 253, 129, 248, 150, 254, 122, 249, 246, 255, 124, 250, 87, 1, 130, 251, 183, 2, 141, 252, 19, 4, 153, 253, 105, 5, 166, 254, 181, 6, 178, 255, 246, 7, 186, 0, 42, 9, 193, 1, 80, 10, 195, 2, 100, 11, 190, 3, 100, 12, 179, 4, 81, 13, 158, 5, 39, 14, 128, 6, 230, 14, 85, 7, 141, 15, 31, 8, 25, 16, 220, 8, 140, 16, 140, 9, 228, 16, 44, 10, 33, 17, 190, 10, 67, 17, 65, 11, 73, 17, 180, 11, 53, 17, 23, 12, 7, 17, 105, 12, 192, 16, 172, 12, 97, 16, 222, 12, 236, 15, 2, 13, 98, 15, 23, 13, 197, 14, 30, 13, 23, 14, 24, 13, 91, 13, 5, 13, 147, 12, 231, 12, 194, 11, 191, 12, 234, 10, 141, 12, 13, 10, 84, 12, 46, 9, 19, 12, 79, 8, 203, 11, 114, 7, 127, 11, 153, 6, 45, 11, 199, 5, 217, 10, 253, 4, 129, 10, 61, 4, 40, 10, 136, 3, 206, 9, 223, 2, 115, 9, 67, 2, 24, 9, 181, 1, 189, 8, 54, 1, 100, 8, 196, 0, 11, 8, 95, 0, 180, 7, 9, 0, 94, 7, 192, 255, 8, 7, 129, 255, 179, 6, 77, 255, 95, 6, 34, 255, 10, 6, 255, 254, 181, 5, 227, 254, 95, 5, 204, 254, 8, 5, 186, 254, 175, 4, 170, 254, 85, 4, 156, 254, 247, 3, 142, 254, 151, 3, 126, 254, 51, 3, 108, 254, 203, 2, 86, 254, 96, 2, 59, 254, 240, 1, 27, 254, 123, 1, 243, 253, 2, 1, 196, 253, 131, 0, 140, 253, 0, 0, 75, 253, 120, 255, 0, 253, 235, 254, 172, 252, 86, 254, 79, 252, 190, 253, 231, 251, 33, 253, 116, 251, 129, 252, 249, 250, 220, 251, 116, 250, 51, 251, 230, 249, 136, 250, 81, 249, 219, 249, 180, 248, 43, 249, 17, 248, 123, 248, 106, 247, 202, 247, 191, 246, 27, 247, 19, 246, 109, 246, 103, 245, 195, 245, 190, 244, 28, 245, 25, 244, 124, 244, 124, 243, 227, 243, 232, 242, 82, 243, 94, 242, 204, 242, 228, 241, 81, 242, 120, 241, 227, 241, 30, 241, 130, 241, 216, 240, 49, 241, 166, 240, 239, 240, 140, 240, 190, 240, 137, 240, 159, 240, 158, 240, 145, 240, 205, 240, 150, 240, 23, 241, 175, 240, 124, 241, 218, 240, 250, 241, 25, 241, 146, 242, 107, 241, 68, 243, 207, 241, 12, 244, 70, 242, 235, 244, 207, 242, 224, 245, 104, 243, 231, 246, 17, 244, 0, 248, 202, 244, 40, 249, 144, 245, 93, 250, 98, 246, 156, 251, 64, 247, 227, 252, 40, 248, 49, 254, 23, 249, 130, 255, 14, 250, 211, 0, 12, 251, 35, 2, 13, 252, 113, 3, 18, 253, 185, 4, 23, 254, 249, 5, 30, 255, 47, 7, 33, 0, 89, 8, 34, 1, 117, 9, 32, 2, 131, 10, 24, 3, 126, 11, 10, 4, 102, 12, 245, 4, 59, 13, 213, 5, 248, 13, 172, 6, 160, 14, 119, 7, 47, 15, 54, 8, 166, 15, 232, 8, 4, 16, 140, 9, 72, 16, 34, 10, 116, 16, 169, 10, 134, 16, 33, 11, 126, 16, 138, 11, 94, 16, 228, 11, 39, 16, 45, 12, 217, 15, 104, 12, 118, 15, 148, 12, 255, 14, 179, 12, 119, 14, 193, 12, 223, 13, 197, 12, 58, 13, 189, 12, 137, 12, 169, 12, 207, 11, 139, 12, 14, 11, 100, 12, 72, 10, 51, 12, 127, 9, 252, 11, 181, 8, 191, 11, 237, 7, 124, 11, 40, 7, 52, 11, 104, 6, 232, 10, 174, 5, 153, 10, 254, 4, 72, 10, 86, 4, 245, 9, 185, 3, 161, 9, 38, 3, 77, 9, 159, 2, 248, 8, 37, 2, 164, 8, 182, 1, 80, 8, 82, 1, 253, 7, 250, 0, 170, 7, 172, 0, 88, 7, 104, 0, 5, 7, 45, 0, 178, 6, 252, 255, 96, 6, 207, 255, 13, 6, 169, 255, 184, 5, 134, 255, 98, 5, 104, 255, 11, 5, 76, 255, 177, 4, 48, 255, 85, 4, 21, 255, 247, 3, 248, 254, 148, 3, 215, 254, 45, 3, 180, 254, 196, 2, 141, 254, 85, 2, 95, 254, 226, 1, 44, 254, 107, 1, 241, 253, 238, 0, 176, 253, 108, 0, 100, 253, 232, 255, 18, 253, 92, 255, 182, 252, 202, 254, 81, 252, 53, 254, 227, 251, 155, 253, 108, 251, 252, 252, 237, 250, 90, 252, 101, 250, 179, 251, 214, 249, 10, 251, 64, 249, 95, 250, 164, 248, 177, 249, 4, 248, 2, 249, 95, 247, 84, 248, 183, 246, 165, 247, 15, 246, 248, 246, 106, 245, 78, 246, 199, 244, 169, 245, 41, 244, 9, 245, 146, 243, 111, 244, 5, 243, 222, 243, 132, 242, 87, 243, 16, 242, 218, 242, 171, 241, 105, 242, 88, 241, 5, 242, 23, 241, 175, 241, 234, 240, 105, 241, 211, 240, 49, 241, 210, 240, 12, 241, 234, 240, 248, 240, 25, 241, 245, 240, 96, 241, 5, 241, 192, 241, 39, 241, 58, 242, 92, 241, 202, 242, 162, 241, 114, 243, 252, 241, 49, 244, 102, 242, 4, 245, 226, 242, 235, 245, 111, 243, 227, 246, 10, 244, 236, 247, 180, 244, 3, 249, 109, 245, 38, 250, 49, 246, 84, 251, 1, 247, 137, 252, 219, 247, 197, 253, 190, 248, 4, 255, 168, 249, 67, 0, 153, 250, 130, 1, 142, 251, 192, 2, 135, 252, 249, 3, 130, 253, 43, 5, 127, 254, 84, 6, 122, 255, 114, 7, 114, 0, 132, 8, 104, 1, 135, 9, 91, 2, 123, 10, 71, 3, 93, 11, 44, 4, 44, 12, 10, 5, 232, 12, 222, 5, 143, 13, 166, 6, 31, 14, 100, 7, 152, 14, 22, 8, 251, 14, 187, 8, 70, 15, 83, 9, 121, 15, 221, 9, 148, 15, 88, 10, 153, 15, 198, 10, 134, 15, 36, 11, 94, 15, 115, 11, 33, 15, 181, 11, 209, 14, 232, 11, 110, 14, 14, 12, 251, 13, 38, 12, 122, 13, 51, 12, 234, 12, 51, 12, 81, 12, 41, 12, 174, 11, 21, 12, 4, 11, 247, 11, 86, 10, 210, 11, 164, 9, 165, 11, 240, 8, 113, 11, 62, 8, 56, 11, 142, 7, 250, 10, 226, 6, 184, 10, 59, 6, 114, 10, 154, 5, 42, 10, 1, 5, 224, 9, 113, 4, 147, 9, 234, 3, 71, 9, 108, 3, 249, 8, 248, 2, 172, 8, 142, 2, 94, 8, 45, 2, 16, 8, 213, 1, 194, 7, 135, 1, 116, 7, 63, 1, 38, 7, 0, 1, 215, 6, 199, 0, 136, 6, 147, 0, 57, 6, 100, 0, 232, 5, 57, 0, 149, 5, 16, 0, 65, 5, 234, 255, 233, 4, 196, 255, 144, 4, 156, 255, 52, 4, 115, 255, 212, 3, 71, 255, 114, 3, 24, 255, 10, 3, 229, 254, 159, 2, 173, 254, 48, 2, 111, 254, 188, 1, 42, 254, 67, 1, 222, 253, 197, 0, 139, 253, 65, 0, 47, 253, 187, 255, 205, 252, 47, 255, 97, 252, 157, 254, 238, 251, 7, 254, 116, 251, 108, 253, 241, 250, 205, 252, 103, 250, 43, 252, 215, 249, 134, 251, 65, 249, 222, 250, 166, 248, 52, 250, 6, 248, 136, 249, 102, 247, 220, 248, 194, 246, 48, 248, 32, 246, 134, 247, 127, 245, 223, 246, 227, 244, 59, 246, 76, 244, 157, 245, 189, 243, 5, 245, 55, 243, 117, 244, 189, 242, 238, 243, 81, 242, 113, 243, 242, 241, 255, 242, 165, 241, 154, 242, 105, 241, 66, 242, 65, 241, 248, 241, 45, 241, 190, 241, 47, 241, 147, 241, 71, 241, 122, 241, 117, 241, 113, 241, 186, 241, 121, 241, 23, 242, 147, 241, 138, 242, 191, 241, 20, 243, 253, 241, 180, 243, 76, 242, 104, 244, 172, 242, 47, 245, 28, 243, 8, 246, 156, 243, 243, 246, 44, 244, 237, 247, 201, 244, 244, 248, 116, 245, 6, 250, 44, 246, 34, 251, 239, 246, 69, 252, 188, 247, 111, 253, 146, 248, 157, 254, 111, 249, 203, 255, 83, 250, 249, 0, 61, 251, 37, 2, 42, 252, 78, 3, 27, 253, 113, 4, 13, 254, 140, 5, 255, 254, 157, 6, 240, 255, 164, 7, 220, 0, 158, 8, 199, 1, 136, 9, 173, 2, 100, 10, 140, 3, 46, 11, 100, 4, 229, 11, 51, 5, 137, 12, 250, 5, 25, 13, 181, 6, 148, 13, 101, 7, 250, 13, 10, 8, 74, 14, 161, 8, 131, 14, 44, 9, 168, 14, 171, 9, 183, 14, 27, 10, 177, 14, 125, 10, 150, 14, 209, 10, 105, 14, 23, 11, 41, 14, 81, 11, 217, 13, 124, 11, 122, 13, 156, 11, 12, 13, 176, 11, 148, 12, 185, 11, 16, 12, 183, 11, 132, 11, 172, 11, 242, 10, 152, 11, 89, 10, 123, 11, 190, 9, 87, 11, 33, 9, 46, 11, 132, 8, 253, 10, 231, 7, 200, 10, 78, 7, 143, 10, 185, 6, 82, 10, 41, 6, 18, 10, 158, 5, 207, 9, 27, 5, 139, 9, 158, 4, 69, 9, 42, 4, 254, 8, 189, 3, 183, 8, 89, 3, 111, 8, 251, 2, 38, 8, 164, 2, 221, 7, 86, 2, 148, 7, 12, 2, 73, 7, 201, 1, 254, 6, 139, 1, 178, 6, 81, 1, 100, 6, 26, 1, 22, 6, 230, 0, 198, 5, 181, 0, 115, 5, 131, 0, 30, 5, 82, 0, 199, 4, 32, 0, 109, 4, 237, 255, 15, 4, 183, 255, 174, 3, 125, 255, 72, 3, 62, 255, 223, 2, 251, 254, 114, 2, 177, 254, 0, 2, 99, 254, 138, 1, 14, 254, 14, 1, 177, 253, 142, 0, 79, 253, 10, 0, 229, 252, 129, 255, 115, 252, 242, 254, 251, 251, 94, 254, 123, 251, 199, 253, 244, 250, 43, 253, 104, 250, 140, 252, 214, 249, 235, 251, 64, 249, 69, 251, 166, 248, 158, 250, 8, 248, 246, 249, 105, 247, 76, 249, 203, 246, 163, 248, 45, 246, 253, 247, 146, 245, 88, 247, 251, 244, 183, 246, 107, 244, 26, 246, 227, 243, 132, 245, 101, 243, 245, 244, 242, 242, 111, 244, 140, 242, 243, 243, 51, 242, 128, 243, 236, 241, 26, 243, 182, 241, 193, 242, 145, 241, 117, 242, 129, 241, 55, 242, 133, 241, 8, 242, 156, 241, 234, 241, 203, 241, 220, 241, 14, 242, 222, 241, 103, 242, 241, 241, 213, 242, 21, 242, 87, 243, 74, 242, 238, 243, 143, 242, 152, 244, 229, 242, 84, 245, 75, 243, 33, 246, 192, 243, 253, 246, 67, 244, 232, 247, 213, 244, 222, 248, 115, 245, 225, 249, 29, 246, 236, 250, 211, 246, 255, 251, 147, 247, 23, 253, 92, 248, 51, 254, 46, 249, 81, 255, 6, 250, 109, 0, 227, 250, 137, 1, 197, 251, 162, 2, 170, 252, 182, 3, 145, 253, 195, 4, 121, 254, 199, 5, 96, 255, 194, 6, 68, 0, 177, 7, 39, 1, 146, 8, 6, 2, 101, 9, 223, 2, 41, 10, 177, 3, 220, 10, 124, 4, 125, 11, 61, 5, 11, 12, 247, 5, 136, 12, 165, 6, 239, 12, 72, 7, 67, 13, 224, 7, 132, 13, 108, 8, 176, 13, 235, 8, 201, 13, 94, 9, 206, 13, 196, 9, 193, 13, 27, 10, 164, 13, 103, 10, 117, 13, 167, 10, 55, 13, 218, 10, 235, 12, 1, 11, 147, 12, 29, 11, 47, 12, 47, 11, 193, 11, 54, 11, 75, 11, 53, 11, 207, 10, 42, 11, 77, 10, 24, 11, 200, 9, 254, 10, 65, 9, 222, 10, 185, 8, 184, 10, 50, 8, 141, 10, 172, 7, 93, 10, 41, 7, 42, 10, 170, 6, 243, 9, 46, 6, 186, 9, 185, 5, 126, 9, 72, 5, 65, 9, 222, 4, 2, 9, 121, 4, 194, 8, 27, 4, 129, 8, 194, 3, 62, 8, 111, 3, 251, 7, 32, 3, 182, 7, 215, 2, 113, 7, 147, 2, 43, 7, 81, 2, 226, 6, 18, 2, 153, 6, 214, 1, 79, 6, 156, 1, 2, 6, 98, 1, 178, 5, 41, 1, 97, 5, 239, 0, 13, 5, 179, 0, 180, 4, 118, 0, 90, 4, 53, 0, 253, 3, 243, 255, 154, 3, 171, 255, 52, 3, 93, 255, 201, 2, 11, 255, 90, 2, 180, 254, 231, 1, 86, 254, 111, 1, 242, 253, 241, 0, 136, 253, 111, 0, 23, 253, 234, 255, 159, 252, 95, 255, 33, 252, 207, 254, 158, 251, 58, 254, 20, 251, 163, 253, 133, 250, 8, 253, 242, 249, 104, 252, 91, 249, 198, 251, 194, 248, 35, 251, 39, 248, 125, 250, 138, 247, 216, 249, 238, 246, 50, 249, 85, 246, 141, 248, 191, 245, 236, 247, 46, 245, 77, 247, 164, 244, 179, 246, 34, 244, 31, 246, 170, 243, 145, 245, 60, 243, 12, 245, 221, 242, 144, 244, 139, 242, 30, 244, 72, 242, 183, 243, 21, 242, 92, 243, 244, 241, 13, 243, 230, 241, 205, 242, 234, 241, 155, 242, 2, 242, 119, 242, 46, 242, 99, 242, 110, 242, 95, 242, 194, 242, 106, 242, 41, 243, 134, 242, 164, 243, 178, 242, 50, 244, 238, 242, 209, 244, 57, 243, 129, 245, 147, 243, 65, 246, 252, 243, 15, 247, 115, 244, 233, 247, 247, 244, 208, 248, 136, 245, 193, 249, 36, 246, 187, 250, 205, 246, 187, 251, 128, 247, 193, 252, 58, 248, 203, 253, 253, 248, 215, 254, 199, 249, 227, 255, 152, 250, 236, 0, 109, 251, 245, 1, 68, 252, 250, 2, 32, 253, 247, 3, 252, 253, 238, 4, 216, 254, 220, 5, 179, 255, 191, 6, 139, 0, 150, 7, 95, 1, 96, 8, 49, 2, 29, 9, 251, 2, 202, 9, 192, 3, 103, 10, 124, 4, 243, 10, 47, 5, 110, 11, 218, 5, 215, 11, 123, 6, 47, 12, 16, 7, 116, 12, 155, 7, 167, 12, 26, 8, 202, 12, 142, 8, 218, 12, 246, 8, 218, 12, 81, 9, 202, 12, 161, 9, 171, 12, 229, 9, 126, 12, 29, 10, 69, 12, 75, 10, 255, 11, 110, 10, 175, 11, 136, 10, 87, 11, 151, 10, 247, 10, 158, 10, 144, 10, 156, 10, 37, 10, 147, 10, 181, 9, 131, 10, 67, 9, 109, 10, 208, 8, 80, 10, 92, 8, 46, 10, 233, 7, 9, 10, 120, 7, 224, 9, 10, 7, 178, 9, 158, 6, 130, 9, 55, 6, 80, 9, 210, 5, 27, 9, 114, 5, 228, 8, 23, 5, 172, 8, 192, 4, 114, 8, 109, 4, 55, 8, 31, 4, 251, 7, 211, 3, 188, 7, 139, 3, 125, 7, 71, 3, 60, 7, 3, 3, 249, 6, 194, 2, 181, 6, 131, 2, 111, 6, 68, 2, 38, 6, 5, 2, 219, 5, 197, 1, 142, 5, 133, 1, 61, 5, 66, 1, 234, 4, 252, 0, 147, 4, 179, 0, 57, 4, 103, 0, 217, 3, 23, 0, 120, 3, 196, 255, 17, 3, 106, 255, 166, 2, 10, 255, 54, 2, 166, 254, 193, 1, 58, 254, 72, 1, 203, 253, 202, 0, 84, 253, 72, 0, 216, 252, 194, 255, 86, 252, 54, 255, 207, 251, 166, 254, 67, 251, 19, 254, 179, 250, 123, 253, 31, 250, 224, 252, 137, 249, 67, 252, 241, 248, 163, 251, 86, 248, 2, 251, 190, 247, 96, 250, 38, 247, 190, 249, 144, 246, 30, 249, 0, 246, 128, 248, 116, 245, 229, 247, 240, 244, 78, 247, 116, 244, 189, 246, 1, 244, 50, 246, 154, 243, 175, 245, 63, 243, 52, 245, 242, 242, 195, 244, 179, 242, 92, 244, 132, 242, 1, 244, 102, 242, 177, 243, 89, 242, 111, 243, 94, 242, 57, 243, 117, 242, 18, 243, 158, 242, 250, 242, 219, 242, 240, 242, 41, 243, 245, 242, 139, 243, 10, 243, 254, 243, 45, 243, 129, 244, 96, 243, 22, 245, 161, 243, 185, 245, 241, 243, 107, 246, 79, 244, 43, 247, 186, 244, 246, 247, 51, 245, 205, 248, 183, 245, 174, 249, 71, 246, 150, 250, 226, 246, 133, 251, 134, 247, 121, 252, 52, 248, 114, 253, 234, 248, 108, 254, 165, 249, 103, 255, 104, 250, 96, 0, 48, 251, 87, 1, 251, 251, 75, 2, 202, 252, 58, 3, 153, 253, 34, 4, 106, 254, 2, 5, 59, 255, 217, 5, 7, 0, 166, 6, 210, 0, 103, 7, 153, 1, 26, 8, 91, 2, 193, 8, 23, 3, 88, 9, 205, 3, 225, 9, 123, 4, 91, 10, 32, 5, 197, 10, 188, 5, 30, 11, 79, 6, 103, 11, 215, 6, 161, 11, 85, 7, 203, 11, 200, 7, 229, 11, 48, 8, 239, 11, 142, 8, 236, 11, 223, 8, 219, 11, 39, 9, 191, 11, 100, 9, 150, 11, 151, 9, 98, 11, 192, 9, 38, 11, 223, 9, 224, 10, 247, 9, 148, 10, 5, 10, 66, 10, 12, 10, 235, 9, 10, 10, 144, 9, 3, 10, 50, 9, 246, 9, 211, 8, 227, 9, 114, 8, 203, 9, 17, 8, 174, 9, 178, 7, 141, 9, 82, 7, 105, 9, 247, 6, 66, 9, 156, 6, 23, 9, 68, 6, 235, 8, 240, 5, 189, 8, 157, 5, 140, 8, 78, 5, 90, 8, 2, 5, 37, 8, 184, 4, 240, 7, 113, 4, 184, 7, 43, 4, 126, 7, 231, 3, 67, 7, 165, 3, 7, 7, 99, 3, 199, 6, 33, 3, 133, 6, 222, 2, 65, 6, 155, 2, 251, 5, 87, 2, 178, 5, 17, 2, 102, 5, 200, 1, 22, 5, 124, 1, 195, 4, 46, 1, 108, 4, 219, 0, 18, 4, 132, 0, 180, 3, 40, 0, 81, 3, 202, 255, 233, 2, 101, 255, 125, 2, 249, 254, 13, 2, 136, 254, 151, 1, 20, 254, 29, 1, 152, 253, 159, 0, 24, 253, 28, 0, 148, 252, 150, 255, 10, 252, 10, 255, 125, 251, 122, 254, 236, 250, 231, 253, 88, 250, 81, 253, 195, 249, 184, 252, 44, 249, 28, 252, 148, 248, 127, 251, 254, 247, 226, 250, 106, 247, 69, 250, 218, 246, 169, 249, 77, 246, 15, 249, 199, 245, 120, 248, 71, 245, 229, 247, 209, 244, 87, 247, 100, 244, 207, 246, 2, 244, 78, 246, 172, 243, 214, 245, 98, 243, 101, 245, 40, 243, 0, 245, 253, 242, 164, 244, 223, 242, 84, 244, 211, 242, 16, 244, 216, 242, 216, 243, 237, 242, 174, 243, 20, 243, 146, 243, 75, 243, 131, 243, 149, 243, 130, 243, 239, 243, 144, 243, 89, 244, 172, 243, 211, 244, 214, 243, 92, 245, 14, 244, 244, 245, 84, 244, 153, 246, 167, 244, 74, 247, 7, 245, 6, 248, 115, 245, 206, 248, 235, 245, 156, 249, 111, 246, 116, 250, 252, 246, 82, 251, 147, 247, 51, 252, 51, 248, 26, 253, 218, 248, 2, 254, 137, 249, 236, 254, 62, 250, 212, 255, 247, 250, 186, 0, 182, 251, 157, 1, 119, 252, 124, 2, 58, 253, 86, 3, 254, 253, 41, 4, 194, 254, 243, 4, 133, 255, 180, 5, 67, 0, 106, 6, 0, 1, 22, 7, 184, 1, 181, 7, 108, 2, 71, 8, 26, 3, 204, 8, 192, 3, 68, 9, 96, 4, 173, 9, 248, 4, 8, 10, 134, 5, 85, 10, 11, 6, 147, 10, 134, 6, 195, 10, 249, 6, 230, 10, 97, 7, 252, 10, 191, 7, 4, 11, 19, 8, 1, 11, 93, 8, 243, 10, 158, 8, 218, 10, 214, 8, 184, 10, 5, 9, 141, 10, 42, 9, 91, 10, 72, 9, 34, 10, 93, 9, 226, 9, 108, 9, 160, 9, 116, 9, 88, 9, 117, 9, 13, 9, 113, 9, 193, 8, 103, 9, 115, 8, 88, 9, 36, 8, 69, 9, 214, 7, 46, 9, 135, 7, 19, 9, 57, 7, 245, 8, 237, 6, 213, 8, 162, 6, 176, 8, 89, 6, 139, 8, 16, 6, 99, 8, 202, 5, 57, 8, 133, 5, 12, 8, 66, 5, 222, 7, 255, 4, 173, 7, 189, 4, 122, 7, 124, 4, 70, 7, 58, 4, 15, 7, 249, 3, 215, 6, 182, 3, 155, 6, 115, 3, 93, 6, 46, 3, 28, 6, 231, 2, 216, 5, 157, 2, 144, 5, 80, 2, 70, 5, 0, 2, 248, 4, 173, 1, 165, 4, 85, 1, 79, 4, 249, 0, 245, 3, 152, 0, 151, 3, 51, 0, 52, 3, 202, 255, 204, 2, 92, 255, 96, 2, 231, 254, 239, 1, 109, 254, 122, 1, 239, 253, 255, 0, 108, 253, 129, 0, 230, 252, 255, 255, 90, 252, 121, 255, 204, 251, 238, 254, 59, 251, 94, 254, 168, 250, 205, 253, 19, 250, 56, 253, 126, 249, 162, 252, 233, 248, 9, 252, 86, 248, 113, 251, 198, 247, 216, 250, 58, 247, 64, 250, 178, 246, 170, 249, 48, 246, 23, 249, 181, 245, 135, 248, 67, 245, 252, 247, 218, 244, 119, 247, 124, 244, 249, 246, 42, 244, 130, 246, 228, 243, 19, 246, 171, 243, 174, 245, 128, 243, 82, 245, 100, 243, 1, 245, 88, 243, 187, 244, 91, 243, 129, 244, 109, 243, 84, 244, 144, 243, 51, 244, 195, 243, 32, 244, 5, 244, 25, 244, 87, 244, 32, 244, 184, 244, 52, 244, 39, 245, 85, 244, 165, 245, 132, 244, 47, 246, 192, 244, 198, 246, 9, 245, 104, 247, 93, 245, 21, 248, 189, 245, 204, 248, 41, 246, 139, 249, 159, 246, 81, 250, 31, 247, 29, 251, 168, 247, 237, 251, 57, 248, 193, 252, 212, 248, 152, 253, 117, 249, 112, 254, 27, 250, 72, 255, 199, 250, 29, 0, 119, 251, 240, 0, 43, 252, 191, 1, 225, 252, 139, 2, 152, 253, 79, 3, 79, 254, 12, 4, 5, 255, 194, 4, 186, 255, 110, 5, 107, 0, 17, 6, 25, 1, 168, 6, 196, 1, 54, 7, 106, 2, 183, 7, 8, 3, 44, 8, 161, 3, 149, 8, 50, 4, 240, 8, 188, 4, 64, 9, 62, 5, 132, 9, 183, 5, 186, 9, 38, 6, 229, 9, 142, 6, 4, 10, 236, 6, 24, 10, 65, 7, 33, 10, 142, 7, 32, 10, 210, 7, 22, 10, 14, 8, 3, 10, 64, 8, 234, 9, 108, 8, 201, 9, 144, 8, 162, 9, 172, 8, 118, 9, 194, 8, 68, 9, 209, 8, 15, 9, 219, 8, 215, 8, 223, 8, 156, 8, 221, 8, 96, 8, 216, 8, 35, 8, 207, 8, 228, 7, 192, 8, 165, 7, 174, 8, 103, 7, 154, 8, 40, 7, 131, 8, 233, 6, 104, 8, 171, 6, 74, 8, 109, 6, 44, 8, 49, 6, 9, 8, 243, 5, 229, 7, 183, 5, 191, 7, 122, 5, 149, 7, 60, 5, 107, 7, 255, 4, 62, 7, 192, 4, 14, 7, 128, 4, 219, 6, 63, 4, 166, 6, 251, 3, 109, 6, 182, 3, 50, 6, 110, 3, 244, 5, 34, 3, 178, 5, 211, 2, 110, 5, 128, 2, 37, 5, 41, 2, 216, 4, 207, 1, 135, 4, 112, 1, 49, 4, 12, 1, 216, 3, 163, 0, 122, 3, 54, 0, 23, 3, 197, 255, 176, 2, 78, 255, 68, 2, 210, 254, 210, 1, 81, 254, 93, 1, 205, 253, 228, 0, 69, 253, 101, 0, 186, 252, 229, 255, 43, 252, 96, 255, 155, 251, 213, 254, 9, 251, 72, 254, 119, 250, 185, 253, 228, 249, 39, 253, 82, 249, 148, 252, 194, 248, 0, 252, 53, 248, 109, 251, 172, 247, 217, 250, 41, 247, 71, 250, 171, 246, 185, 249, 53, 246, 45, 249, 199, 245, 166, 248, 98, 245, 37, 248, 8, 245, 169, 247, 184, 244, 53, 247, 116, 244, 200, 246, 61, 244, 99, 246, 19, 244, 7, 246, 246, 243, 182, 245, 233, 243, 111, 245, 233, 243, 52, 245, 248, 243, 3, 245, 22, 244, 224, 244, 67, 244, 198, 244, 127, 244, 187, 244, 199, 244, 189, 244, 31, 245, 201, 244, 132, 245, 226, 244, 245, 245, 9, 245, 115, 246, 60, 245, 252, 246, 121, 245, 144, 247, 195, 245, 46, 248, 24, 246, 212, 248, 119, 246, 131, 249, 225, 246, 56, 250, 84, 247, 242, 250, 208, 247, 176, 251, 84, 248, 116, 252, 224, 248, 57, 253, 115, 249, 255, 253, 11, 250, 197, 254, 169, 250, 139, 255, 76, 251, 77, 0, 241, 251, 12, 1, 153, 252, 201, 1, 67, 253, 128, 2, 237, 253, 48, 3, 151, 254, 218, 3, 64, 255, 124, 4, 230, 255, 22, 5, 137, 0, 166, 5, 42, 1, 44, 6, 197, 1, 169, 6, 92, 2, 27, 7, 237, 2, 131, 7, 118, 3, 223, 7, 250, 3, 48, 8, 120, 4, 119, 8, 236, 4, 179, 8, 90, 5, 229, 8, 191, 5, 12, 9, 28, 6, 42, 9, 113, 6, 61, 9, 191, 6, 73, 9, 5, 7, 76, 9, 67, 7, 72, 9, 122, 7, 62, 9, 169, 7, 44, 9, 210, 7, 21, 9, 245, 7, 250, 8, 17, 8, 217, 8, 38, 8, 182, 8, 55, 8, 142, 8, 67, 8, 101, 8, 74, 8, 57, 8, 76, 8, 11, 8, 75, 8, 220, 7, 69, 8, 172, 7, 61, 8, 122, 7, 49, 8, 72, 7, 34, 8, 23, 7, 16, 8, 227, 6, 252, 7, 176, 6, 229, 7, 124, 6, 203, 7, 72, 6, 174, 7, 18, 6, 144, 7, 219, 5, 111, 7, 164, 5, 75, 7, 106, 5, 37, 7, 47, 5, 251, 6, 242, 4, 208, 6, 179, 4, 160, 6, 112, 4, 110, 6, 43, 4, 58, 6, 226, 3, 1, 6, 151, 3, 197, 5, 71, 3, 134, 5, 242, 2, 66, 5, 155, 2, 251, 4, 62, 2, 176, 4, 221, 1, 96, 4, 119, 1, 12, 4, 12, 1, 179, 3, 157, 0, 85, 3, 41, 0, 243, 2, 178, 255, 140, 2, 54, 255, 33, 2, 181, 254, 176, 1, 48, 254, 60, 1, 169, 253, 195, 0, 30, 253, 70, 0, 146, 252, 199, 255, 4, 252, 67, 255, 115, 251, 188, 254, 228, 250, 50, 254, 85, 250, 165, 253, 198, 249, 24, 253, 58, 249, 138, 252, 178, 248, 252, 251, 45, 248, 110, 251, 174, 247, 226, 250, 53, 247, 89, 250, 196, 246, 210, 249, 90, 246, 80, 249, 249, 245, 210, 248, 162, 245, 91, 248, 85, 245, 233, 247, 20, 245, 126, 247, 222, 244, 28, 247, 181, 244, 194, 246, 152, 244, 113, 246, 137, 244, 43, 246, 134, 244, 238, 245, 147, 244, 188, 245, 171, 244, 149, 245, 210, 244, 122, 245, 7, 245, 105, 245, 71, 245, 101, 245, 150, 245, 108, 245, 240, 245, 127, 245, 85, 246, 157, 245, 198, 246, 199, 245, 66, 247, 252, 245, 199, 247, 58, 246, 86, 248, 133, 246, 237, 248, 217, 246, 138, 249, 55, 247, 46, 250, 158, 247, 216, 250, 13, 248, 134, 251, 132, 248, 55, 252, 2, 249, 235, 252, 136, 249, 160, 253, 19, 250, 85, 254, 163, 250, 10, 255, 55, 251, 189, 255, 208, 251, 109, 0, 106, 252, 25, 1, 6, 253, 195, 1, 163, 253, 102, 2, 64, 254, 4, 3, 220, 254, 155, 3, 119, 255, 43, 4, 15, 0, 179, 4, 163, 0, 51, 5, 52, 1, 170, 5, 194, 1, 24, 6, 74, 2, 126, 6, 204, 2, 217, 6, 73, 3, 44, 7, 192, 3, 116, 7, 48, 4, 179, 7, 152, 4, 234, 7, 250, 4, 25, 8, 86, 5, 62, 8, 170, 5, 91, 8, 247, 5, 113, 8, 61, 6, 128, 8, 124, 6, 136, 8, 181, 6, 138, 8, 231, 6, 134, 8, 19, 7, 126, 8, 58, 7, 112, 8, 90, 7, 95, 8, 118, 7, 74, 8, 140, 7, 49, 8, 158, 7, 22, 8, 172, 7, 249, 7, 181, 7, 217, 7, 187, 7, 183, 7, 189, 7, 148, 7, 187, 7, 111, 7, 183, 7, 73, 7, 175, 7, 34, 7, 165, 7, 250, 6, 152, 7, 208, 6, 136, 7, 164, 6, 118, 7, 121, 6, 97, 7, 74, 6, 74, 7, 26, 6, 48, 7, 232, 5, 19, 7, 179, 5, 244, 6, 124, 5, 209, 6, 66, 5, 172, 6, 6, 5, 131, 6, 199, 4, 88, 6, 131, 4, 41, 6, 60, 4, 247, 5, 241, 3, 193, 5, 162, 3, 135, 5, 78, 3, 75, 5, 246, 2, 9, 5, 154, 2, 195, 4, 57, 2, 122, 4, 211, 1, 43, 4, 104, 1, 216, 3, 250, 0, 129, 3, 134, 0, 36, 3, 14, 0, 196, 2, 149, 255, 93, 2, 22, 255, 243, 1, 146, 254, 134, 1, 13, 254, 18, 1, 133, 253, 156, 0, 251, 252, 34, 0, 112, 252, 165, 255, 228, 251, 36, 255, 88, 251, 160, 254, 205, 250, 27, 254, 68, 250, 148, 253, 189, 249, 12, 253, 58, 249, 132, 252, 186, 248, 253, 251, 64, 248, 119, 251, 204, 247, 243, 250, 96, 247, 115, 250, 250, 246, 245, 249, 158, 246, 125, 249, 74, 246, 10, 249, 0, 246, 155, 248, 192, 245, 53, 248, 140, 245, 214, 247, 99, 245, 125, 247, 69, 245, 46, 247, 53, 245, 232, 246, 48, 245, 172, 246, 56, 245, 121, 246, 76, 245, 80, 246, 108, 245, 50, 246, 153, 245, 30, 246, 211, 245, 21, 246, 23, 246, 23, 246, 103, 246, 35, 246, 194, 246, 59, 246, 38, 247, 93, 246, 149, 247, 138, 246, 13, 248, 192, 246, 140, 248, 0, 247, 20, 249, 74, 247, 161, 249, 156, 247, 53, 250, 247, 247, 206, 250, 91, 248, 107, 251, 197, 248, 11, 252, 55, 249, 173, 252, 175, 249, 82, 253, 44, 250, 247, 253, 175, 250, 154, 254, 54, 251, 61, 255, 192, 251, 223, 255, 76, 252, 124, 0, 219, 252, 22, 1, 106, 253, 172, 1, 251, 253, 62, 2, 138, 254, 202, 2, 24, 255, 80, 3, 164, 255, 207, 3, 45, 0, 72, 4, 179, 0, 185, 4, 54, 1, 34, 5, 180, 1, 131, 5, 47, 2, 221, 5, 165, 2, 47, 6, 20, 3, 120, 6, 125, 3, 187, 6, 225, 3, 245, 6, 62, 4, 39, 7, 150, 4, 83, 7, 232, 4, 120, 7, 51, 5, 150, 7, 121, 5, 175, 7, 184, 5, 193, 7, 240, 5, 205, 7, 37, 6, 213, 7, 84, 6, 217, 7, 125, 6, 216, 7, 161, 6, 211, 7, 192, 6, 203, 7, 220, 6, 192, 7, 243, 6, 178, 7, 5, 7, 161, 7, 20, 7, 142, 7, 33, 7, 121, 7, 41, 7, 98, 7, 47, 7, 73, 7, 49, 7, 46, 7, 48, 7, 18, 7, 46, 7, 243, 6, 40, 7, 211, 6, 32, 7, 176, 6, 21, 7, 140, 6, 7, 7, 101, 6, 247, 6, 60, 6, 227, 6, 16, 6, 205, 6, 225, 5, 181, 6, 175, 5, 153, 6, 122, 5, 123, 6, 66, 5, 90, 6, 5, 5, 53, 6, 197, 4, 12, 6, 129, 4, 226, 5, 57, 4, 178, 5, 236, 3, 127, 5, 155, 3, 72, 5, 69, 3, 14, 5, 234, 2, 206, 4, 139, 2, 139, 4, 39, 2, 66, 4, 191, 1, 246, 3, 82, 1, 165, 3, 225, 0, 78, 3, 108, 0, 243, 2, 244, 255, 149, 2, 121, 255, 50, 2, 250, 254, 202, 1, 119, 254, 94, 1, 243, 253, 238, 0, 110, 253, 122, 0, 231, 252, 3, 0, 96, 252, 139, 255, 217, 251, 14, 255, 84, 251, 143, 254, 208, 250, 15, 254, 78, 250, 143, 253, 209, 249, 13, 253, 88, 249, 140, 252, 226, 248, 13, 252, 115, 248, 143, 251, 11, 248, 21, 251, 170, 247, 157, 250, 80, 247, 42, 250, 0, 247, 187, 249, 185, 246, 81, 249, 122, 246, 239, 248, 71, 246, 145, 248, 30, 246, 60, 248, 0, 246, 238, 247, 236, 245, 169, 247, 228, 245, 108, 247, 232, 245, 56, 247, 246, 245, 14, 247, 17, 246, 238, 246, 54, 246, 215, 246, 103, 246, 202, 246, 162, 246, 198, 246, 231, 246, 205, 246, 54, 247, 222, 246, 142, 247, 248, 246, 239, 247, 28, 247, 88, 248, 74, 247, 201, 248, 128, 247, 64, 249, 192, 247, 190, 249, 7, 248, 66, 250, 86, 248, 201, 250, 173, 248, 86, 251, 12, 249, 229, 251, 112, 249, 118, 252, 219, 249, 9, 253, 75, 250, 158, 253, 192, 250, 49, 254, 57, 251, 196, 254, 181, 251, 86, 255, 52, 252, 229, 255, 181, 252, 112, 0, 55, 253, 248, 0, 185, 253, 127, 1, 60, 254, 255, 1, 190, 254, 123, 2, 62, 255, 241, 2, 189, 255, 97, 3, 54, 0, 205, 3, 175, 0, 49, 4, 36, 1, 143, 4, 150, 1, 230, 4, 3, 2, 55, 5, 106, 2, 129, 5, 206, 2, 196, 5, 44, 3, 2, 6, 133, 3, 56, 6, 217, 3, 105, 6, 39, 4, 148, 6, 112, 4, 187, 6, 181, 4, 219, 6, 243, 4, 245, 6, 45, 5, 13, 7, 98, 5, 31, 7, 147, 5, 45, 7, 191, 5, 56, 7, 230, 5, 63, 7, 10, 6, 67, 7, 41, 6, 67, 7, 69, 6, 65, 7, 94, 6, 60, 7, 114, 6, 52, 7, 132, 6, 43, 7, 147, 6, 31, 7, 158, 6, 17, 7, 167, 6, 1, 7, 174, 6, 238, 6, 177, 6, 217, 6, 179, 6, 194, 6, 177, 6, 168, 6, 173, 6, 139, 6, 166, 6, 108, 6, 156, 6, 74, 6, 144, 6, 37, 6, 129, 6, 252, 5, 112, 6, 207, 5, 91, 6, 160, 5, 68, 6, 108, 5, 41, 6, 52, 5, 11, 6, 248, 4, 233, 5, 184, 4, 195, 5, 115, 4, 155, 5, 41, 4, 110, 5, 220, 3, 61, 5, 137, 3, 9, 5, 49, 3, 208, 4, 213, 2, 147, 4, 117, 2, 80, 4, 15, 2, 11, 4, 166, 1, 193, 3, 56, 1, 113, 3, 199, 0, 29, 3, 82, 0, 196, 2, 219, 255, 104, 2, 98, 255, 7, 2, 228, 254, 161, 1, 101, 254, 57, 1, 229, 253, 204, 0, 99, 253, 92, 0, 225, 252, 234, 255, 97, 252, 117, 255, 225, 251, 254, 254, 99, 251, 133, 254, 232, 250, 11, 254, 112, 250, 145, 253, 252, 249, 23, 253, 140, 249, 159, 252, 35, 249, 40, 252, 191, 248, 179, 251, 99, 248, 65, 251, 13, 248, 212, 250, 191, 247, 106, 250, 122, 247, 6, 250, 62, 247, 166, 249, 11, 247, 77, 249, 225, 246, 250, 248, 194, 246, 175, 248, 172, 246, 107, 248, 161, 246, 47, 248, 161, 246, 251, 247, 171, 246, 208, 247, 190, 246, 174, 247, 219, 246, 149, 247, 4, 247, 132, 247, 54, 247, 125, 247, 112, 247, 127, 247, 179, 247, 137, 247, 0, 248, 157, 247, 84, 248, 186, 247, 175, 248, 223, 247, 18, 249, 12, 248, 123, 249, 67, 248, 234, 249, 128, 248, 94, 250, 197, 248, 213, 250, 18, 249, 81, 251, 100, 249, 208, 251, 189, 249, 81, 252, 27, 250, 212, 252, 127, 250, 88, 253, 231, 250, 219, 253, 83, 251, 95, 254, 194, 251, 227, 254, 52, 252, 100, 255, 168, 252, 227, 255, 28, 253, 93, 0, 146, 253, 214, 0, 7, 254, 77, 1, 125, 254, 191, 1, 242, 254, 44, 2, 100, 255, 149, 2, 213, 255, 249, 2, 66, 0, 88, 3, 173, 0, 177, 3, 21, 1, 5, 4, 120, 1, 84, 4, 216, 1, 157, 4, 53, 2, 226, 4, 141, 2, 32, 5, 224, 2, 90, 5, 47, 3, 143, 5, 123, 3, 190, 5, 192, 3, 233, 5, 2, 4, 16, 6, 63, 4, 50, 6, 119, 4, 81, 6, 172, 4, 107, 6, 221, 4, 130, 6, 10, 5, 148, 6, 51, 5, 165, 6, 88, 5, 177, 6, 121, 5, 188, 6, 153, 5, 195, 6, 181, 5, 200, 6, 205, 5, 203, 6, 227, 5, 203, 6, 246, 5, 200, 6, 7, 6, 195, 6, 21, 6, 188, 6, 32, 6, 178, 6, 42, 6, 165, 6, 48, 6, 150, 6, 51, 6, 131, 6, 54, 6, 110, 6, 52, 6, 86, 6, 48, 6, 57, 6, 43, 6, 27, 6, 34, 6, 247, 5, 21, 6, 209, 5, 7, 6, 166, 5, 245, 5, 119, 5, 225, 5, 69, 5, 201, 5, 12, 5, 174, 5, 208, 4, 143, 5, 145, 4, 108, 5, 75, 4, 69, 5, 1, 4, 27, 5, 178, 3, 237, 4, 95, 3, 185, 4, 8, 3, 131, 4, 171, 2, 72, 4, 75, 2, 9, 4, 229, 1, 197, 3, 125, 1, 124, 3, 18, 1, 47, 3, 162, 0, 222, 2, 47, 0, 136, 2, 189, 255, 46, 2, 70, 255, 209, 1, 205, 254, 111, 1, 83, 254, 10, 1, 216, 253, 161, 0, 94, 253, 55, 0, 228, 252, 202, 255, 107, 252, 91, 255, 244, 251, 235, 254, 127, 251, 121, 254, 14, 251, 7, 254, 161, 250, 149, 253, 56, 250, 35, 253, 212, 249, 181, 252, 118, 249, 71, 252, 29, 249, 220, 251, 203, 248, 118, 251, 129, 248, 17, 251, 63, 248, 178, 250, 5, 248, 88, 250, 211, 247, 3, 250, 170, 247, 180, 249, 138, 247, 108, 249, 114, 247, 43, 249, 101, 247, 241, 248, 96, 247, 189, 248, 101, 247, 147, 248, 116, 247, 112, 248, 139, 247, 85, 248, 171, 247, 66, 248, 212, 247, 55, 248, 5, 248, 54, 248, 62, 248, 59, 248, 127, 248, 74, 248, 199, 248, 96, 248, 21, 249, 126, 248, 107, 249, 163, 248, 198, 249, 208, 248, 38, 250, 6, 249, 138, 250, 64, 249, 243, 250, 130, 249, 95, 251, 202, 249, 206, 251, 24, 250, 64, 252, 106, 250, 179, 252, 193, 250, 39, 253, 29, 251, 155, 253, 124, 251, 17, 254, 222, 251, 133, 254, 67, 252, 248, 254, 170, 252, 106, 255, 18, 253, 218, 255, 123, 253, 70, 0, 227, 253, 176, 0, 77, 254, 23, 1, 181, 254, 124, 1, 28, 255, 221, 1, 130, 255, 57, 2, 228, 255, 146, 2, 68, 0, 231, 2, 162, 0, 54, 3, 253, 0, 130, 3, 86, 1, 202, 3, 170, 1, 12, 4, 251, 1, 75, 4, 72, 2, 134, 4, 146, 2, 188, 4, 216, 2, 239, 4, 26, 3, 30, 5, 88, 3, 72, 5, 147, 3, 112, 5, 202, 3, 148, 5, 253, 3, 181, 5, 46, 4, 210, 5, 91, 4, 236, 5, 132, 4, 4, 6, 171, 4, 25, 6, 206, 4, 44, 6, 240, 4, 59, 6, 13, 5, 72, 6, 41, 5, 82, 6, 67, 5, 90, 6, 89, 5, 96, 6, 111, 5, 99, 6, 128, 5, 100, 6, 144, 5, 98, 6, 158, 5, 92, 6, 170, 5, 83, 6, 179, 5, 72, 6, 185, 5, 58, 6, 190, 5, 40, 6, 192, 5, 18, 6, 191, 5, 249, 5, 187, 5, 220, 5, 182, 5, 187, 5, 172, 5, 150, 5, 161, 5, 109, 5, 146, 5, 63, 5, 128, 5, 13, 5, 107, 5, 214, 4, 82, 5, 154, 4, 53, 5, 90, 4, 21, 5, 22, 4, 241, 4, 204, 3, 200, 4, 127, 3, 156, 4, 44, 3, 108, 4, 214, 2, 55, 4, 123, 2, 254, 3, 29, 2, 194, 3, 187, 1, 128, 3, 85, 1, 58, 3, 236, 0, 240, 2, 128, 0, 162, 2, 19, 0, 79, 2, 165, 255, 249, 1, 52, 255, 159, 1, 192, 254, 66, 1, 78, 254, 226, 0, 219, 253, 127, 0, 105, 253, 25, 0, 248, 252, 180, 255, 136, 252, 75, 255, 27, 252, 225, 254, 177, 251, 119, 254, 73, 251, 14, 254, 231, 250, 165, 253, 137, 250, 60, 253, 48, 250, 214, 252, 221, 249, 115, 252, 144, 249, 17, 252, 74, 249, 180, 251, 9, 249, 90, 251, 210, 248, 5, 251, 161, 248, 181, 250, 120, 248, 106, 250, 87, 248, 37, 250, 62, 248, 231, 249, 46, 248, 174, 249, 38, 248, 125, 249, 38, 248, 83, 249, 46, 248, 46, 249, 63, 248, 18, 249, 88, 248, 253, 248, 120, 248, 240, 248, 160, 248, 235, 248, 207, 248, 237, 248, 4, 249, 246, 248, 64, 249, 5, 249, 131, 249, 29, 249, 203, 249, 60, 249, 25, 250, 97, 249, 106, 250, 140, 249, 193, 250, 191, 249, 26, 251, 246, 249, 120, 251, 52, 250, 216, 251, 118, 250, 58, 252, 190, 250, 159, 252, 10, 251, 4, 253, 90, 251, 106, 253, 173, 251, 208, 253, 3, 252, 54, 254, 92, 252, 156, 254, 181, 252, 1, 255, 17, 253, 100, 255, 110, 253, 199, 255, 203, 253, 37, 0, 40, 254, 130, 0, 133, 254, 221, 0, 225, 254, 53, 1, 59, 255, 139, 1, 148, 255, 221, 1, 235, 255, 44, 2, 62, 0, 119, 2, 144, 0, 191, 2, 224, 0, 4, 3, 44, 1, 69, 3, 119, 1, 132, 3, 189, 1, 190, 3, 1, 2, 245, 3, 66, 2, 42, 4, 128, 2, 91, 4, 187, 2, 136, 4, 242, 2, 179, 4, 38, 3, 220, 4, 87, 3, 1, 5, 135, 3, 36, 5, 180, 3, 68, 5, 221, 3, 97, 5, 4, 4, 124, 5, 41, 4, 148, 5, 75, 4, 171, 5, 106, 4, 191, 5, 137, 4, 208, 5, 164, 4, 223, 5, 190, 4, 235, 5, 214, 4, 244, 5, 235, 4, 252, 5, 254, 4, 255, 5, 15, 5, 0, 6, 30, 5, 254, 5, 44, 5, 249, 5, 55, 5, 241, 5, 64, 5, 228, 5, 70, 5, 213, 5, 74, 5, 193, 5, 75, 5, 170, 5, 74, 5, 142, 5, 71, 5, 110, 5, 63, 5, 75, 5, 54, 5, 34, 5, 41, 5, 245, 4, 25, 5, 195, 4, 5, 5, 141, 4, 238, 4, 83, 4, 212, 4, 19, 4, 180, 4, 209, 3, 146, 4, 137, 3, 108, 4, 60, 3, 66, 4, 236, 2, 20, 4, 153, 2, 226, 3, 64, 2, 171, 3, 229, 1, 112, 3, 135, 1, 49, 3, 38, 1, 239, 2, 194, 0, 168, 2, 92, 0, 92, 2, 245, 255, 14, 2, 140, 255, 188, 1, 34, 255, 103, 1, 183, 254, 14, 1, 76, 254, 179, 0, 226, 253, 86, 0, 121, 253, 249, 255, 18, 253, 153, 255, 173, 252, 56, 255, 75, 252, 215, 254, 235, 251, 117, 254, 143, 251, 20, 254, 56, 251, 180, 253, 229, 250, 86, 253, 151, 250, 250, 252, 78, 250, 160, 252, 12, 250, 74, 252, 208, 249, 247, 251, 154, 249, 168, 251, 107, 249, 93, 251, 68, 249, 23, 251, 35, 249, 215, 250, 9, 249, 156, 250, 247, 248, 103, 250, 236, 248, 55, 250, 232, 248, 14, 250, 236, 248, 235, 249, 248, 248, 206, 249, 10, 249, 186, 249, 34, 249, 170, 249, 66, 249, 163, 249, 104, 249, 161, 249, 147, 249, 166, 249, 197, 249, 178, 249, 253, 249, 196, 249, 58, 250, 221, 249, 122, 250, 251, 249, 191, 250, 31, 250, 9, 251, 74, 250, 85, 251, 122, 250, 165, 251, 174, 250, 246, 251, 231, 250, 75, 252, 37, 251, 162, 252, 101, 251, 249, 252, 171, 251, 82, 253, 243, 251, 171, 253, 62, 252, 5, 254, 138, 252, 94, 254, 217, 252, 182, 254, 41, 253, 14, 255, 123, 253, 101, 255, 204, 253, 186, 255, 30, 254, 13, 0, 112, 254, 94, 0, 192, 254, 174, 0, 16, 255, 252, 0, 95, 255, 71, 1, 171, 255, 145, 1, 246, 255, 215, 1, 62, 0, 26, 2, 133, 0, 92, 2, 202, 0, 155, 2, 13, 1, 215, 2, 77, 1, 16, 3, 139, 1, 70, 3, 198, 1, 123, 3, 254, 1, 173, 3, 52, 2, 219, 3, 104, 2, 8, 4, 154, 2, 51, 4, 200, 2, 90, 4, 245, 2, 128, 4, 32, 3, 164, 4, 71, 3, 197, 4, 110, 3, 229, 4, 147, 3, 1, 5, 180, 3, 27, 5, 212, 3, 52, 5, 243, 3, 74, 5, 16, 4, 93, 5, 43, 4, 110, 5, 68, 4, 125, 5, 91, 4, 138, 5, 113, 4, 146, 5, 133, 4, 152, 5, 151, 4, 156, 5, 167, 4, 155, 5, 181, 4, 151, 5, 193, 4, 144, 5, 203, 4, 133, 5, 210, 4, 119, 5, 216, 4, 101, 5, 219, 4, 78, 5, 218, 4, 51, 5, 216, 4, 20, 5, 211, 4, 241, 4, 203, 4, 202, 4, 191, 4, 157, 4, 176, 4, 109, 4, 159, 4, 56, 4, 137, 4, 255, 3, 113, 4, 194, 3, 83, 4, 128, 3, 51, 4, 60, 3, 14, 4, 243, 2, 230, 3, 165, 2, 186, 3, 85, 2, 138, 3, 2, 2, 86, 3, 171, 1, 30, 3, 81, 1, 226, 2, 246, 0, 162, 2, 152, 0, 95, 2, 57, 0, 23, 2, 218, 255, 205, 1, 122, 255, 128, 1, 23, 255, 48, 1, 181, 254, 221, 0, 83, 254, 136, 0, 243, 253, 50, 0, 149, 253, 219, 255, 55, 253, 132, 255, 221, 252, 42, 255, 133, 252, 208, 254, 48, 252, 120, 254, 223, 251, 32, 254, 146, 251, 202, 253, 74, 251, 117, 253, 7, 251, 34, 253, 200, 250, 211, 252, 143, 250, 134, 252, 92, 250, 60, 252, 47, 250, 248, 251, 8, 250, 182, 251, 232, 249, 122, 251, 206, 249, 66, 251, 186, 249, 17, 251, 172, 249, 228, 250, 165, 249, 187, 250, 165, 249, 154, 250, 172, 249, 125, 250, 184, 249, 104, 250, 202, 249, 88, 250, 226, 249, 78, 250, 255, 249, 74, 250, 35, 250, 75, 250, 74, 250, 83, 250, 119, 250, 97, 250, 169, 250, 116, 250, 222, 250, 140, 250, 24, 251, 170, 250, 85, 251, 205, 250, 149, 251, 244, 250, 215, 251, 32, 251, 29, 252, 82, 251, 101, 252, 134, 251, 175, 252, 189, 251, 249, 252, 249, 251, 69, 253, 55, 252, 145, 253, 119, 252, 223, 253, 186, 252, 44, 254, 253, 252, 122, 254, 67, 253, 199, 254, 137, 253, 19, 255, 207, 253, 95, 255, 23, 254, 170, 255, 94, 254, 242, 255, 165, 254, 56, 0, 234, 254, 126, 0, 47, 255, 195, 0, 115, 255, 6, 1, 182, 255, 71, 1, 246, 255, 134, 1, 52, 0, 195, 1, 114, 0, 253, 1, 173, 0, 55, 2, 230, 0, 110, 2, 31, 1, 164, 2, 84, 1, 215, 2, 135, 1, 9, 3, 185, 1, 56, 3, 232, 1, 101, 3, 22, 2, 145, 3, 66, 2, 186, 3, 109, 2, 226, 3, 149, 2, 7, 4, 188, 2, 43, 4, 225, 2, 77, 4, 4, 3, 109, 4, 38, 3, 139, 4, 70, 3, 167, 4, 101, 3, 192, 4, 130, 3, 215, 4, 158, 3, 236, 4, 185, 3, 254, 4, 210, 3, 15, 5, 233, 3, 28, 5, 254, 3, 38, 5, 19, 4, 44, 5, 37, 4, 48, 5, 53, 4, 49, 5, 67, 4, 46, 5, 79, 4, 40, 5, 90, 4, 29, 5, 98, 4, 15, 5, 104, 4, 253, 4, 107, 4, 231, 4, 109, 4, 205, 4, 107, 4, 175, 4, 102, 4, 141, 4, 95, 4, 102, 4, 84, 4, 60, 4, 71, 4, 12, 4, 54, 4, 218, 3, 33, 4, 163, 3, 10, 4, 104, 3, 238, 3, 42, 3, 208, 3, 231, 2, 173, 3, 163, 2, 135, 3, 90, 2, 93, 3, 14, 2, 46, 3, 192, 1, 253, 2, 111, 1, 200, 2, 28, 1, 143, 2, 199, 0, 83, 2, 113, 0, 19, 2, 25, 0, 208, 1, 195, 255, 139, 1, 105, 255, 66, 1, 16, 255, 248, 0, 185, 254, 172, 0, 97, 254, 94, 0, 11, 254, 15, 0, 183, 253, 193, 255, 100, 253, 112, 255, 21, 253, 31, 255, 199, 252, 207, 254, 125, 252, 128, 254, 55, 252, 50, 254, 245, 251, 229, 253, 183, 251, 154, 253, 125, 251, 81, 253, 72, 251, 12, 253, 25, 251, 202, 252, 238, 250, 139, 252, 201, 250, 79, 252, 170, 250, 24, 252, 144, 250, 229, 251, 123, 250, 183, 251, 109, 250, 141, 251, 99, 250, 104, 251, 95, 250, 72, 251, 97, 250, 45, 251, 105, 250, 24, 251, 118, 250, 7, 251, 136, 250, 252, 250, 158, 250, 247, 250, 185, 250, 247, 250, 217, 250, 252, 250, 253, 250, 5, 251, 37, 251, 20, 251, 80, 251, 40, 251, 128, 251, 64, 251, 177, 251, 93, 251, 231, 251, 126, 251, 30, 252, 163, 251, 89, 252, 204, 251, 149, 252, 248, 251, 210, 252, 39, 252, 17, 253, 89, 252, 82, 253, 141, 252, 147, 253, 196, 252, 213, 253, 254, 252, 23, 254, 54, 253, 90, 254, 114, 253, 157, 254, 174, 253, 223, 254, 236, 253, 34, 255, 41, 254, 99, 255, 102, 254, 164, 255, 162, 254, 227, 255, 223, 254, 32, 0, 27, 255, 94, 0, 85, 255, 154, 0, 143, 255, 214, 0, 199, 255, 15, 1, 254, 255, 72, 1, 50, 0, 127, 1, 103, 0, 181, 1, 153, 0, 233, 1, 202, 0, 27, 2, 250, 0, 77, 2, 40, 1, 124, 2, 86, 1, 170, 2, 128, 1, 214, 2, 170, 1, 2, 3, 210, 1, 43, 3, 249, 1, 83, 3, 30, 2, 121, 3, 67, 2, 157, 3, 101, 2, 193, 3, 134, 2, 226, 3, 167, 2, 1, 4, 199, 2, 31, 4, 228, 2, 58, 4, 1, 3, 83, 4, 29, 3, 105, 4, 55, 3, 127, 4, 80, 3, 145, 4, 104, 3, 160, 4, 126, 3, 173, 4, 147, 3, 183, 4, 166, 3, 190, 4, 184, 3, 193, 4, 200, 3, 193, 4, 214, 3, 190, 4, 227, 3, 184, 4, 237, 3, 173, 4, 245, 3, 160, 4, 252, 3, 142, 4, 255, 3, 120, 4, 1, 4, 95, 4, 255, 3, 66, 4, 251, 3, 32, 4, 244, 3, 252, 3, 234, 3, 210, 3, 221, 3, 166, 3, 205, 3, 117, 3, 186, 3, 65, 3, 163, 3, 10, 3, 136, 3, 207, 2, 107, 3, 145, 2, 74, 3, 81, 2, 37, 3, 12, 2, 253, 2, 199, 1, 210, 2, 126, 1, 162, 2, 52, 1, 113, 2, 231, 0, 59, 2, 154, 0, 2, 2, 76, 0, 199, 1, 253, 255, 137, 1, 175, 255, 72, 1, 95, 255, 5, 1, 16, 255, 193, 0, 192, 254, 123, 0, 115, 254, 53, 0, 39, 254, 238, 255, 220, 253, 166, 255, 148, 253, 94, 255, 78, 253, 21, 255, 11, 253, 206, 254, 203, 252, 135, 254, 143, 252, 65, 254, 86, 252, 254, 253, 33, 252, 189, 253, 241, 251, 125, 253, 196, 251, 65, 253, 156, 251, 7, 253, 121, 251, 209, 252, 90, 251, 158, 252, 65, 251, 113, 252, 44, 251, 70, 252, 29, 251, 31, 252, 18, 251, 253, 251, 11, 251, 223, 251, 10, 251, 197, 251, 12, 251, 177, 251, 20, 251, 160, 251, 32, 251, 149, 251, 49, 251, 142, 251, 69, 251, 140, 251, 93, 251, 142, 251, 122, 251, 149, 251, 153, 251, 161, 251, 188, 251, 176, 251, 226, 251, 195, 251, 10, 252, 219, 251, 53, 252, 246, 251, 100, 252, 21, 252, 147, 252, 55, 252, 197, 252, 92, 252, 249, 252, 132, 252, 46, 253, 174, 252, 100, 253, 219, 252, 155, 253, 9, 253, 211, 253, 57, 253, 12, 254, 107, 253, 70, 254, 158, 253, 126, 254, 209, 253, 184, 254, 5, 254, 242, 254, 57, 254, 42, 255, 110, 254, 99, 255, 162, 254, 155, 255, 214, 254, 211, 255, 9, 255, 8, 0, 60, 255, 63, 0, 110, 255, 117, 0, 159, 255, 169, 0, 208, 255, 221, 0, 254, 255, 15, 1, 42, 0, 65, 1, 87, 0, 114, 1, 131, 0, 162, 1, 173, 0, 208, 1, 214, 0, 253, 1, 254, 0, 42, 2, 37, 1, 85, 2, 75, 1, 127, 2, 112, 1, 168, 2, 147, 1, 207, 2, 182, 1, 245, 2, 215, 1, 25, 3, 248, 1, 60, 3, 24, 2, 94, 3, 55, 2, 126, 3, 84, 2, 156, 3, 113, 2, 185, 3, 141, 2, 211, 3, 169, 2, 235, 3, 194, 2, 1, 4, 219, 2, 21, 4, 243, 2, 38, 4, 8, 3, 52, 4, 30, 3, 65, 4, 50, 3, 74, 4, 68, 3, 80, 4, 85, 3, 82, 4, 100, 3, 82, 4, 114, 3, 79, 4, 127, 3, 72, 4, 135, 3, 61, 4, 144, 3, 47, 4, 149, 3, 29, 4, 152, 3, 8, 4, 154, 3, 239, 3, 152, 3, 210, 3, 147, 3, 179, 3, 141, 3, 143, 3, 131, 3, 104, 3, 118, 3, 61, 3, 102, 3, 16, 3, 84, 3, 223, 2, 62, 3, 171, 2, 36, 3, 117, 2, 8, 3, 60, 2, 233, 2, 255, 1, 197, 2, 193, 1, 159, 2, 129, 1, 118, 2, 62, 1, 74, 2, 251, 0, 27, 2, 182, 0, 232, 1, 112, 0, 180, 1, 42, 0, 125, 1, 229, 255, 68, 1, 159, 255, 9, 1, 87, 255, 204, 0, 17, 255, 142, 0, 204, 254, 79, 0, 136, 254, 15, 0, 70, 254, 209, 255, 5, 254, 144, 255, 199, 253, 80, 255, 139, 253, 16, 255, 81, 253, 209, 254, 27, 253, 148, 254, 232, 252, 87, 254, 184, 252, 29, 254, 140, 252, 228, 253, 100, 252, 175, 253, 62, 252, 124, 253, 29, 252, 75, 253, 2, 252, 30, 253, 233, 251, 245, 252, 212, 251, 206, 252, 196, 251, 171, 252, 184, 251, 140, 252, 176, 251, 113, 252, 172, 251, 90, 252, 172, 251, 70, 252, 176, 251, 56, 252, 184, 251, 45, 252, 196, 251, 37, 252, 211, 251, 34, 252, 229, 251, 35, 252, 251, 251, 39, 252, 19, 252, 48, 252, 46, 252, 60, 252, 77, 252, 76, 252, 110, 252, 96, 252, 145, 252, 118, 252, 182, 252, 144, 252, 222, 252, 171, 252, 6, 253, 202, 252, 49, 253, 236, 252, 94, 253, 15, 253, 138, 253, 53, 253, 184, 253, 92, 253, 232, 253, 133, 253, 23, 254, 174, 253, 72, 254, 217, 253, 121, 254, 4, 254, 170, 254, 48, 254, 220, 254, 93, 254, 13, 255, 136, 254, 63, 255, 180, 254, 112, 255, 225, 254, 160, 255, 12, 255, 209, 255, 55, 255, 0, 0, 97, 255, 47, 0, 140, 255, 94, 0, 181, 255, 142, 0, 221, 255, 187, 0, 3, 0, 233, 0, 42, 0, 21, 1, 79, 0, 65, 1, 116, 0, 108, 1, 151, 0, 150, 1, 187, 0, 191, 1, 222, 0, 232, 1, 255, 0, 16, 2, 31, 1, 55, 2, 63, 1, 92, 2, 94, 1, 128, 2, 125, 1, 163, 2, 155, 1, 197, 2, 183, 1, 230, 2, 213, 1, 5, 3, 240, 1, 35, 3, 11, 2, 63, 3, 38, 2, 88, 3, 62, 2, 113, 3, 87, 2, 135, 3, 111, 2, 155, 3, 133, 2, 173, 3, 155, 2, 189, 3, 176, 2, 201, 3, 196, 2, 211, 3, 214, 2, 218, 3, 231, 2, 224, 3, 247, 2, 225, 3, 6, 3, 223, 3, 18, 3, 219, 3, 28, 3, 211, 3, 37, 3, 200, 3, 44, 3, 185, 3, 48, 3, 168, 3, 52, 3, 147, 3, 52, 3, 123, 3, 50, 3, 95, 3, 45, 3, 65, 3, 38, 3, 31, 3, 29, 3, 250, 2, 16, 3, 211, 2, 1, 3, 169, 2, 238, 2, 123, 2, 217, 2, 76, 2, 194, 2, 26, 2, 166, 2, 229, 1, 136, 2, 175, 1, 103, 2, 119, 1, 67, 2, 61, 1, 28, 2, 2, 1, 243, 1, 198, 0, 199, 1, 136, 0, 153, 1, 74, 0, 104, 1, 12, 0, 54, 1, 207, 255, 2, 1, 145, 255, 204, 0, 83, 255, 150, 0, 22, 255, 94, 0, 219, 254, 38, 0, 161, 254, 239, 255, 103, 254, 182, 255, 47, 254, 125, 255, 250, 253, 69, 255, 199, 253, 12, 255, 150, 253, 214, 254, 105, 253, 161, 254, 62, 253, 109, 254, 22, 253, 59, 254, 241, 252, 12, 254, 208, 252, 222, 253, 177, 252, 179, 253, 151, 252, 139, 253, 127, 252, 101, 253, 107, 252, 67, 253, 91, 252, 35, 253, 79, 252, 7, 253, 70, 252, 239, 252, 64, 252, 217, 252, 62, 252, 199, 252, 62, 252, 185, 252, 66, 252, 175, 252, 74, 252, 167, 252, 84, 252, 163, 252, 98, 252, 163, 252, 113, 252, 166, 252, 132, 252, 172, 252, 154, 252, 182, 252, 177, 252, 194, 252, 203, 252, 211, 252, 231, 252, 229, 252, 5, 253, 249, 252, 36, 253, 17, 253, 69, 253, 43, 253, 105, 253, 71, 253, 141, 253, 99, 253, 178, 253, 131, 253, 216, 253, 163, 253, 0, 254, 197, 253, 40, 254, 233, 253, 81, 254, 12, 254, 123, 254, 49, 254, 165, 254, 86, 254, 207, 254, 123, 254, 249, 254, 160, 254, 36, 255, 198, 254, 79, 255, 236, 254, 121, 255, 16, 255, 165, 255, 53, 255, 207, 255, 89, 255, 248, 255, 125, 255, 33, 0, 160, 255, 75, 0, 195, 255, 117, 0, 229, 255, 157, 0, 5, 0, 198, 0, 36, 0, 238, 0, 69, 0, 21, 1, 101, 0, 61, 1, 131, 0, 100, 1, 162, 0, 136, 1, 192, 0, 175, 1, 220, 0, 211, 1, 250, 0, 245, 1, 22, 1, 25, 2, 49, 1, 58, 2, 76, 1, 90, 2, 103, 1, 121, 2, 129, 1, 151, 2, 155, 1, 180, 2, 180, 1, 207, 2, 205, 1, 232, 2, 229, 1, 0, 3, 252, 1, 22, 3, 18, 2, 42, 3, 40, 2, 59, 3, 60, 2, 75, 3, 81, 2, 88, 3, 100, 2, 99, 3, 118, 2, 107, 3, 134, 2, 113, 3, 150, 2, 116, 3, 164, 2, 116, 3, 176, 2, 113, 3, 188, 2, 108, 3, 197, 2, 99, 3, 204, 2, 88, 3, 211, 2, 74, 3, 214, 2, 56, 3, 216, 2, 36, 3, 215, 2, 13, 3, 213, 2, 244, 2, 208, 2, 215, 2, 201, 2, 183, 2, 190, 2, 150, 2, 177, 2, 113, 2, 162, 2, 73, 2, 144, 2, 32, 2, 123, 2, 245, 1, 100, 2, 200, 1, 74, 2, 152, 1, 46, 2, 103, 1, 14, 2, 53, 1, 236, 1, 1, 1, 200, 1, 205, 0, 162, 1, 151, 0, 121, 1, 97, 0, 79, 1, 43, 0, 36, 1, 245, 255, 245, 0, 192, 255, 199, 0, 138, 255, 151, 0, 84, 255, 102, 0, 32, 255, 52, 0, 236, 254, 2, 0, 186, 254, 210, 255, 137, 254, 160, 255, 90, 254, 111, 255, 45, 254, 62, 255, 2, 254, 14, 255, 217, 253, 224, 254, 180, 253, 178, 254, 144, 253, 134, 254, 110, 253, 93, 254, 81, 253, 52, 254, 53, 253, 14, 254, 29, 253, 235, 253, 7, 253, 203, 253, 244, 252, 173, 253, 229, 252, 145, 253, 216, 252, 120, 253, 207, 252, 98, 253, 200, 252, 79, 253, 195, 252, 64, 253, 194, 252, 50, 253, 195, 252, 40, 253, 200, 252, 33, 253, 206, 252, 29, 253, 216, 252, 28, 253, 227, 252, 30, 253, 241, 252, 36, 253, 2, 253, 43, 253, 20, 253, 52, 253, 40, 253, 66, 253, 62, 253, 81, 253, 86, 253, 98, 253, 111, 253, 118, 253, 138, 253, 138, 253, 167, 253, 161, 253, 197, 253, 186, 253, 228, 253, 212, 253, 4, 254, 239, 253, 36, 254, 12, 254, 70, 254, 41, 254, 105, 254, 70, 254, 140, 254, 101, 254, 175, 254, 131, 254, 212, 254, 163, 254, 248, 254, 194, 254, 29, 255, 225, 254, 66, 255, 1, 255, 103, 255, 32, 255, 140, 255, 62, 255, 177, 255, 93, 255, 215, 255, 122, 255, 252, 255, 153, 255, 30, 0, 182, 255, 67, 0, 211, 255, 103, 0, 240, 255, 139, 0, 10, 0, 176, 0, 37, 0, 210, 0, 65, 0, 246, 0, 92, 0, 25, 1, 117, 0, 59, 1, 143, 0, 93, 1, 169, 0, 126, 1, 195, 0, 158, 1, 219, 0, 189, 1, 244, 0, 221, 1, 12, 1, 249, 1, 37, 1, 22, 2, 60, 1, 51, 2, 83, 1, 77, 2, 105, 1, 102, 2, 128, 1, 126, 2, 150, 1, 148, 2, 172, 1, 168, 2, 193, 1, 187, 2, 213, 1, 204, 2, 232, 1, 219, 2, 250, 1, 232, 2, 13, 2, 242, 2, 30, 2, 250, 2, 46, 2, 0, 3, 60, 2, 4, 3, 74, 2, 6, 3, 87, 2, 4, 3, 97, 2, 0, 3, 107, 2, 250, 2, 116, 2, 241, 2, 122, 2, 229, 2, 126, 2, 215, 2, 129, 2, 198, 2, 128, 2, 179, 2, 127, 2, 156, 2, 124, 2, 133, 2, 118, 2, 106, 2, 110, 2, 77, 2, 99, 2, 46, 2, 87, 2, 12, 2, 72, 2, 233, 1, 54, 2, 195, 1, 34, 2, 157, 1, 12, 2, 116, 1, 243, 1, 74, 1, 216, 1, 32, 1, 187, 1, 243, 0, 156, 1, 197, 0, 122, 1, 151, 0, 87, 1, 105, 0, 51, 1, 58, 0, 12, 1, 11, 0, 229, 0, 223, 255, 187, 0, 176, 255, 145, 0, 130, 255, 103, 0, 85, 255, 60, 0, 40, 255, 16, 0, 254, 254, 230, 255, 211, 254, 187, 255, 171, 254, 144, 255, 133, 254, 102, 255, 95, 254, 60, 255, 60, 254, 19, 255, 27, 254, 236, 254, 252, 253, 197, 254, 223, 253, 161, 254, 198, 253, 126, 254, 174, 253, 93, 254, 152, 253, 62, 254, 133, 253, 33, 254, 117, 253, 7, 254, 103, 253, 238, 253, 91, 253, 216, 253, 82, 253, 197, 253, 75, 253, 180, 253, 71, 253, 166, 253, 70, 253, 155, 253, 70, 253, 146, 253, 72, 253, 140, 253, 76, 253, 136, 253, 83, 253, 134, 253, 92, 253, 135, 253, 103, 253, 139, 253, 116, 253, 145, 253, 130, 253, 153, 253, 146, 253, 163, 253, 164, 253, 175, 253, 182, 253, 190, 253, 203, 253, 205, 253, 224, 253, 223, 253, 248, 253, 242, 253, 16, 254, 6, 254, 41, 254, 28, 254, 66, 254, 50, 254, 93, 254, 74, 254, 121, 254, 98, 254, 149, 254, 122, 254, 177, 254, 148, 254, 207, 254, 174, 254, 236, 254, 199, 254, 10, 255, 226, 254, 41, 255, 252, 254, 71, 255, 22, 255, 102, 255, 47, 255, 133, 255, 73, 255, 164, 255, 98, 255, 196, 255, 124, 255, 226, 255, 149, 255, 0, 0, 174, 255, 31, 0, 198, 255, 61, 0, 222, 255, 93, 0, 246, 255, 123, 0, 12, 0, 154, 0, 35, 0, 185, 0, 58, 0, 215, 0, 81, 0, 244, 0, 103, 0, 18, 1, 125, 0, 47, 1, 148, 0, 76, 1, 170, 0, 104, 1, 192, 0, 131, 1, 213, 0, 157, 1, 235, 0, 183, 1, 1, 1, 208, 1, 21, 1, 232, 1, 41, 1, 254, 1, 62, 1, 20, 2, 82, 1, 40, 2, 101, 1, 59, 2, 120, 1, 76, 2, 139, 1, 92, 2, 157, 1, 106, 2, 174, 1, 118, 2, 191, 1, 129, 2, 207, 1, 137, 2, 222, 1, 143, 2, 235, 1, 147, 2, 248, 1, 150, 2, 5, 2, 149, 2, 15, 2, 147, 2, 24, 2, 143, 2, 33, 2, 136, 2, 39, 2, 126, 2, 43, 2, 115, 2, 46, 2, 101, 2, 46, 2, 85, 2, 46, 2, 67, 2, 45, 2, 47, 2, 41, 2, 25, 2, 34, 2, 1, 2, 26, 2, 230, 1, 15, 2, 203, 1, 2, 2, 173, 1, 243, 1, 141, 1, 226, 1, 109, 1, 207, 1, 74, 1, 186, 1, 38, 1, 163, 1, 1, 1, 137, 1, 220, 0, 110, 1, 182, 0, 81, 1, 143, 0, 51, 1, 104, 0, 19, 1, 64, 0, 242, 0, 24, 0, 207, 0, 241, 255, 172, 0, 203, 255, 136, 0, 164, 255, 99, 0, 126, 255, 61, 0, 88, 255, 24, 0, 51, 255, 244, 255, 15, 255, 207, 255, 237, 254, 169, 255, 204, 254, 133, 255, 173, 254, 96, 255, 144, 254, 62, 255, 115, 254, 28, 255, 88, 254, 250, 254, 64, 254, 219, 254, 42, 254, 189, 254, 22, 254, 160, 254, 3, 254, 133, 254, 243, 253, 109, 254, 229, 253, 85, 254, 216, 253, 65, 254, 206, 253, 45, 254, 197, 253, 29, 254, 191, 253, 15, 254, 188, 253, 2, 254, 185, 253, 248, 253, 186, 253, 240, 253, 187, 253, 235, 253, 189, 253, 231, 253, 194, 253, 229, 253, 200, 253, 230, 253, 209, 253, 233, 253, 218, 253, 237, 253, 230, 253, 243, 253, 243, 253, 252, 253, 0, 254, 7, 254, 15, 254, 17, 254, 31, 254, 31, 254, 49, 254, 45, 254, 66, 254, 61, 254, 86, 254, 77, 254, 107, 254, 95, 254, 127, 254, 114, 254, 149, 254, 133, 254, 170, 254, 153, 254, 194, 254, 173, 254, 217, 254, 195, 254, 241, 254, 216, 254, 9, 255, 237, 254, 34, 255, 3, 255, 59, 255, 25, 255, 84, 255, 45, 255, 109, 255, 67, 255, 135, 255, 89, 255, 161, 255, 110, 255, 187, 255, 131, 255, 214, 255, 152, 255, 239, 255, 173, 255, 9, 0, 194, 255, 34, 0, 214, 255, 61, 0, 234, 255, 87, 0, 255, 255, 113, 0, 17, 0, 140, 0, 37, 0, 165, 0, 56, 0, 191, 0, 76, 0, 217, 0, 95, 0, 242, 0, 114, 0, 11, 1, 133, 0, 35, 1, 153, 0, 59, 1, 172, 0, 82, 1, 191, 0, 105, 1, 210, 0, 128, 1, 228, 0, 149, 1, 247, 0, 169, 1, 9, 1, 188, 1, 27, 1, 207, 1, 45, 1, 224, 1, 63, 1, 239, 1, 79, 1, 253, 1, 95, 1, 10, 2, 111, 1, 21, 2, 126, 1, 30, 2, 141, 1, 39, 2, 155, 1, 45, 2, 167, 1, 49, 2, 179, 1, 51, 2, 190, 1, 52, 2, 200, 1, 51, 2, 209, 1, 47, 2, 217, 1, 43, 2, 222, 1, 35, 2, 227, 1, 26, 2, 231, 1, 14, 2, 232, 1, 2, 2, 232, 1, 243, 1, 231, 1, 226, 1, 227, 1, 208, 1, 222, 1, 187, 1, 215, 1, 166, 1, 207, 1, 143, 1, 195, 1, 117, 1, 182, 1, 90, 1, 168, 1, 63, 1, 151, 1, 34, 1, 133, 1, 4, 1, 113, 1, 229, 0, 91, 1, 197, 0, 68, 1, 164, 0, 44, 1, 132, 0, 17, 1, 98, 0, 245, 0, 64, 0, 216, 0, 31, 0, 187, 0, 254, 255, 156, 0, 221, 255, 125, 0, 189, 255, 92, 0, 156, 255, 60, 0, 125, 255, 28, 0, 94, 255, 253, 255, 64, 255, 220, 255, 35, 255, 189, 255, 7, 255, 157, 255, 236, 254, 126, 255, 212, 254, 95, 255, 188, 254, 66, 255, 166, 254, 38, 255, 145, 254, 11, 255, 126, 254, 241, 254, 108, 254, 216, 254, 92, 254, 193, 254, 79, 254, 171, 254, 66, 254, 151, 254, 55, 254, 134, 254, 46, 254, 117, 254, 39, 254, 103, 254, 34, 254, 90, 254, 30, 254, 79, 254, 27, 254, 70, 254, 26, 254, 64, 254, 27, 254, 59, 254, 30, 254, 55, 254, 33, 254, 54, 254, 38, 254, 54, 254, 44, 254, 56, 254, 51, 254, 60, 254, 60, 254, 65, 254, 69, 254, 72, 254, 80, 254, 80, 254, 92, 254, 90, 254, 105, 254, 100, 254, 119, 254, 112, 254, 133, 254, 125, 254, 149, 254, 139, 254, 165, 254, 154, 254, 181, 254, 169, 254, 199, 254, 185, 254, 217, 254, 202, 254, 235, 254, 219, 254, 254, 254, 236, 254, 17, 255, 253, 254, 37, 255, 14, 255, 57, 255, 33, 255, 78, 255, 50, 255, 98, 255, 68, 255, 119, 255, 87, 255, 141, 255, 104, 255, 162, 255, 122, 255, 184, 255, 140, 255, 205, 255, 158, 255, 228, 255, 175, 255, 250, 255, 192, 255, 14, 0, 209, 255, 36, 0, 226, 255, 59, 0, 244, 255, 81, 0, 3, 0, 103, 0, 19, 0, 126, 0, 36, 0, 148, 0, 53, 0, 170, 0, 70, 0, 192, 0, 86, 0, 213, 0, 103, 0, 234, 0, 120, 0, 255, 0, 136, 0, 20, 1, 153, 0, 40, 1, 170, 0, 59, 1, 186, 0, 78, 1, 203, 0, 95, 1, 219, 0, 112, 1, 235, 0, 128, 1, 251, 0, 143, 1, 10, 1, 157, 1, 25, 1, 170, 1, 40, 1, 181, 1, 53, 1, 191, 1, 67, 1, 199, 1, 81, 1, 207, 1, 93, 1, 213, 1, 104, 1, 217, 1, 115, 1, 219, 1, 125, 1, 220, 1, 135, 1, 219, 1, 142, 1, 217, 1, 149, 1, 213, 1, 155, 1, 207, 1, 159, 1, 201, 1, 163, 1, 191, 1, 164, 1, 180, 1, 165, 1, 168, 1, 164, 1, 154, 1, 162, 1, 138, 1, 157, 1, 122, 1, 152, 1, 103, 1, 143, 1, 84, 1, 134, 1, 63, 1, 124, 1, 41, 1, 111, 1, 17, 1, 98, 1, 249, 0, 82, 1, 223, 0, 64, 1, 198, 0, 45, 1, 171, 0, 25, 1, 144, 0, 4, 1, 116, 0, 237, 0, 88, 0, 214, 0, 60, 0, 189, 0, 32, 0, 164, 0, 4, 0, 138, 0, 234, 255, 111, 0, 207, 255, 84, 0, 179, 255, 56, 0, 153, 255, 28, 0, 127, 255, 1, 0, 102, 255, 231, 255, 78, 255, 203, 255, 55, 255, 176, 255, 33, 255, 151, 255, 12, 255, 124, 255, 248, 254, 99, 255, 230, 254, 76, 255, 213, 254, 52, 255, 197, 254, 29, 255, 182, 254, 9, 255, 169, 254, 245, 254, 157, 254, 227, 254, 146, 254, 210, 254, 137, 254, 195, 254, 130, 254, 182, 254, 124, 254, 169, 254, 119, 254, 158, 254, 116, 254, 149, 254, 114, 254, 141, 254, 112, 254, 135, 254, 113, 254, 131, 254, 114, 254, 129, 254, 117, 254, 127, 254, 120, 254, 127, 254, 125, 254, 129, 254, 131, 254, 132, 254, 137, 254, 137, 254, 146, 254, 142, 254, 153, 254, 149, 254, 162, 254, 156, 254, 173, 254, 165, 254, 183, 254, 175, 254, 195, 254, 185, 254, 208, 254, 197, 254, 220, 254, 209, 254, 233, 254, 221, 254, 248, 254, 234, 254, 6, 255, 248, 254, 21, 255, 7, 255, 35, 255, 20, 255, 51, 255, 35, 255, 67, 255, 49, 255, 84, 255, 64, 255, 100, 255, 78, 255, 117, 255, 93, 255, 134, 255, 107, 255, 152, 255, 122, 255, 170, 255, 137, 255, 187, 255, 151, 255, 205, 255, 166, 255, 224, 255, 181, 255, 242, 255, 195, 255, 3, 0, 210, 255, 21, 0, 224, 255, 40, 0, 238, 255, 60, 0, 253, 255, 78, 0, 9, 0, 97, 0, 23, 0, 116, 0, 37, 0, 135, 0, 52, 0, 153, 0, 67, 0, 171, 0, 81, 0, 190, 0, 96, 0, 208, 0, 110, 0, 225, 0, 125, 0, 243, 0, 139, 0, 4, 1, 154, 0, 20, 1, 168, 0, 35, 1, 183, 0, 49, 1, 197, 0, 63, 1, 211, 0, 77, 1, 224, 0, 89, 1, 237, 0, 99, 1, 250, 0, 110, 1, 7, 1, 119, 1, 19, 1, 127, 1, 31, 1, 133, 1, 42, 1, 138, 1, 53, 1, 142, 1, 63, 1, 145, 1, 71, 1, 146, 1, 80, 1, 146, 1, 87, 1, 143, 1, 93, 1, 140, 1, 98, 1, 136, 1, 103, 1, 130, 1, 106, 1, 122, 1, 107, 1, 114, 1, 108, 1, 104, 1, 107, 1, 92, 1, 105, 1, 80, 1, 102, 1, 66, 1, 97, 1, 50, 1, 91, 1, 33, 1, 83, 1, 16, 1, 73, 1, 253, 0, 63, 1, 234, 0, 50, 1, 213, 0, 37, 1, 192, 0, 22, 1, 171, 0, 6, 1, 148, 0, 245, 0, 125, 0, 226, 0, 102, 0, 207, 0, 79, 0, 187, 0, 55, 0, 166, 0, 31, 0, 143, 0, 8, 0, 121, 0, 243, 255, 98, 0, 219, 255, 74, 0, 197, 255, 51, 0, 174, 255, 26, 0, 153, 255, 2, 0, 133, 255, 236, 255, 112, 255, 214, 255, 93, 255, 190, 255, 74, 255, 167, 255, 57, 255, 145, 255, 41, 255, 123, 255, 25, 255, 103, 255, 11, 255, 84, 255, 253, 254, 65, 255, 241, 254, 47, 255, 230, 254, 31, 255, 219, 254, 15, 255, 211, 254, 1, 255, 204, 254, 244, 254, 197, 254, 232, 254, 192, 254, 222, 254, 188, 254, 212, 254, 184, 254, 204, 254, 182, 254, 199, 254, 181, 254, 193, 254, 180, 254, 190, 254, 182, 254, 187, 254, 184, 254, 186, 254, 186, 254, 185, 254, 190, 254, 187, 254, 194, 254, 190, 254, 200, 254, 193, 254, 206, 254, 198, 254, 212, 254, 203, 254, 218, 254, 209, 254, 227, 254, 216, 254, 236, 254, 225, 254, 245, 254, 233, 254, 255, 254, 243, 254, 9, 255, 253, 254, 20, 255, 7, 255, 31, 255, 18, 255, 42, 255, 29, 255, 55, 255, 41, 255, 67, 255, 52, 255, 80, 255, 64, 255, 93, 255, 76, 255, 106, 255, 89, 255, 119, 255, 101, 255, 133, 255, 112, 255, 148, 255, 125, 255, 162, 255, 137, 255, 176, 255, 149, 255, 191, 255, 161, 255, 207, 255, 174, 255, 222, 255, 186, 255, 236, 255, 198, 255, 253, 255, 210, 255, 11, 0, 222, 255, 26, 0, 234, 255, 42, 0, 246, 255, 58, 0, 2, 0, 74, 0, 13, 0, 90, 0, 26, 0, 106, 0, 38, 0, 121, 0, 50, 0, 137, 0, 63, 0, 153, 0, 75, 0, 169, 0, 88, 0, 184, 0, 100, 0, 198, 0, 113, 0, 213, 0, 126, 0, 226, 0, 139, 0, 239, 0, 151, 0, 253, 0, 164, 0, 8, 1, 176, 0, 19, 1, 188, 0, 31, 1, 199, 0, 40, 1, 211, 0, 49, 1, 222, 0, 57, 1, 232, 0, 63, 1, 243, 0, 68, 1, 253, 0, 73, 1, 6, 1, 77, 1, 16, 1, 79, 1, 24, 1, 80, 1, 31, 1, 81, 1, 37, 1, 79, 1, 43, 1, 76, 1, 48, 1, 73, 1, 51, 1, 68, 1, 54, 1, 62, 1, 56, 1, 55, 1, 57, 1, 46, 1, 56, 1, 37, 1, 54, 1, 26, 1, 50, 1, 14, 1, 47, 1, 1, 1, 41, 1, 243, 0, 35, 1, 229, 0, 26, 1, 213, 0, 18, 1, 197, 0, 8, 1, 180, 0, 251, 0, 163, 0, 239, 0, 144, 0, 225, 0, 125, 0, 210, 0, 107, 0, 194, 0, 87, 0, 178, 0, 68, 0, 161, 0, 48, 0, 143, 0, 29, 0, 124, 0, 9, 0, 104, 0, 247, 255, 85, 0, 229, 255, 65, 0, 209, 255, 44, 0, 191, 255, 24, 0, 174, 255, 4, 0, 157, 255, 242, 255, 140, 255, 222, 255, 124, 255, 202, 255, 108, 255, 183, 255, 94, 255, 164, 255, 81, 255, 146, 255, 68, 255, 128, 255, 56, 255, 112, 255, 46, 255, 96, 255, 35, 255, 82, 255, 26, 255, 68, 255, 18, 255, 55, 255, 11, 255, 43, 255, 4, 255, 32, 255, 0, 255, 22, 255, 251, 254, 13, 255, 248, 254, 6, 255, 245, 254, 0, 255, 243, 254, 250, 254, 241, 254, 246, 254, 241, 254, 243, 254, 242, 254, 241, 254, 243, 254, 241, 254, 246, 254, 240, 254, 249, 254, 241, 254, 252, 254, 243, 254, 1, 255, 246, 254, 5, 255, 250, 254, 10, 255, 255, 254, 16, 255, 4, 255, 23, 255, 10, 255, 29, 255, 16, 255, 36, 255, 23, 255, 45, 255, 32, 255, 53, 255, 40, 255, 61, 255, 48, 255, 69, 255, 57, 255, 79, 255, 66, 255, 89, 255, 76, 255, 99, 255, 86, 255, 108, 255, 95, 255, 119, 255, 104, 255, 130, 255, 115, 255, 141, 255, 124, 255, 153, 255, 134, 255, 163, 255, 145, 255, 176, 255, 154, 255, 187, 255, 165, 255, 200, 255, 174, 255, 212, 255, 184, 255, 224, 255, 195, 255, 237, 255, 204, 255, 249, 255, 215, 255, 5, 0, 224, 255, 18, 0, 235, 255, 31, 0, 246, 255, 44, 0, 255, 255, 58, 0, 7, 0, 71, 0, 17, 0, 85, 0, 29, 0, 99, 0, 38, 0, 112, 0, 50, 0, 125, 0, 61, 0, 138, 0, 72, 0, 150, 0, 82, 0, 162, 0, 93, 0, 175, 0, 104, 0, 186, 0, 115, 0, 198, 0, 126, 0, 208, 0, 136, 0, 219, 0, 147, 0, 227, 0, 158, 0, 237, 0, 168, 0, 246, 0, 178, 0, 253, 0, 187, 0, 3, 1, 197, 0, 9, 1, 205, 0, 14, 1, 215, 0, 18, 1, 223, 0, 20, 1, 230, 0, 23, 1, 237, 0, 24, 1, 243, 0, 23, 1, 249, 0, 23, 1, 254, 0, 21, 1, 2, 1, 18, 1, 6, 1, 14, 1, 8, 1, 8, 1, 10, 1, 2, 1, 11, 1, 252, 0, 10, 1, 244, 0, 9, 1, 235, 0, 6, 1, 225, 0, 3, 1, 215, 0, 254, 0, 203, 0, 248, 0, 191, 0, 241, 0, 178, 0, 233, 0, 164, 0, 224, 0, 150, 0, 214, 0, 135, 0, 203, 0, 120, 0, 192, 0, 105, 0, 179, 0, 89, 0, 165, 0, 73, 0, 152, 0, 57, 0, 136, 0, 41, 0, 120, 0, 24, 0, 105, 0, 8, 0, 89, 0, 250, 255, 72, 0, 235, 255, 55, 0, 219, 255, 37, 0, 204, 255, 20, 0, 190, 255, 3, 0, 175, 255, 244, 255, 161, 255, 228, 255, 148, 255, 211, 255, 136, 255, 194, 255, 124, 255, 178, 255, 113, 255, 164, 255, 103, 255, 149, 255, 92, 255, 134, 255, 83, 255, 121, 255, 75, 255, 109, 255, 67, 255, 97, 255, 61, 255, 85, 255, 55, 255, 76, 255, 50, 255, 67, 255, 46, 255, 58, 255, 42, 255, 51, 255, 39, 255, 45, 255, 37, 255, 39, 255, 35, 255, 34, 255, 35, 255, 32, 255, 34, 255, 29, 255, 35, 255, 27, 255, 35, 255, 26, 255, 36, 255, 27, 255, 39, 255, 27, 255, 41, 255, 29, 255, 45, 255, 32, 255, 49, 255, 35, 255, 53, 255, 38, 255, 57, 255, 43, 255, 62, 255, 48, 255, 68, 255, 54, 255, 74, 255, 59, 255, 80, 255, 65, 255, 86, 255, 72, 255, 93, 255, 79, 255, 100, 255, 86, 255, 107, 255, 95, 255, 115, 255, 102, 255, 123, 255, 110, 255, 132, 255, 118, 255, 140, 255, 125, 255, 149, 255, 134, 255, 158, 255, 143, 255, 166, 255, 150, 255, 176, 255, 158, 255, 186, 255, 167, 255, 195, 255, 175, 255, 206, 255, 183, 255, 216, 255, 193, 255, 225, 255, 201, 255, 236, 255, 209, 255, 247, 255, 218, 255, 1, 0, 226, 255, 11, 0, 235, 255, 22, 0, 243, 255, 34, 0, 252, 255, 45, 0, 3, 0, 56, 0, 11, 0, 67, 0, 21, 0, 79, 0, 31, 0, 90, 0, 40, 0, 101, 0, 49, 0, 112, 0, 58, 0, 123, 0, 67, 0, 134, 0, 77, 0, 144, 0, 86, 0, 153, 0, 96, 0, 163, 0, 106, 0, 172, 0, 114, 0, 181, 0, 124, 0, 189, 0, 133, 0, 196, 0, 143, 0, 204, 0, 151, 0, 210, 0, 160, 0, 216, 0, 168, 0, 221, 0, 176, 0, 224, 0, 184, 0, 229, 0, 191, 0, 231, 0, 197, 0, 232, 0, 203, 0, 234, 0, 209, 0, 233, 0, 214, 0, 233, 0, 218, 0, 232, 0, 222, 0, 229, 0, 225, 0, 226, 0, 227, 0, 221, 0, 228, 0, 217, 0, 229, 0, 211, 0, 228, 0, 204, 0, 227, 0, 197, 0, 225, 0, 189, 0, 222, 0, 180, 0, 218, 0, 170, 0, 213, 0, 160, 0, 207, 0, 149, 0, 200, 0, 138, 0, 192, 0, 126, 0, 184, 0, 114, 0, 174, 0, 101, 0, 165, 0, 88, 0, 154, 0, 75, 0, 142, 0, 62, 0, 130, 0, 48, 0, 117, 0, 35, 0, 104, 0, 22, 0, 90, 0, 8, 0, 76, 0, 252, 255, 62, 0, 240, 255, 47, 0, 227, 255, 33, 0, 215, 255, 18, 0, 202, 255, 4, 0, 191, 255, 247, 255, 180, 255, 233, 255, 169, 255, 219, 255, 158, 255, 205, 255, 149, 255, 192, 255, 140, 255, 179, 255, 131, 255, 166, 255, 122, 255, 155, 255, 116, 255, 143, 255, 110, 255, 133, 255, 103, 255, 124, 255, 98, 255, 114, 255, 93, 255, 105, 255, 88, 255, 97, 255, 85, 255, 91, 255, 81, 255, 85, 255, 79, 255, 80, 255, 78, 255, 75, 255, 76, 255, 72, 255, 76, 255, 69, 255, 75, 255, 67, 255, 76, 255, 65, 255, 76, 255, 64, 255, 78, 255, 65, 255, 79, 255, 65, 255, 81, 255, 67, 255, 83, 255, 69, 255, 87, 255, 71, 255, 90, 255, 75, 255, 93, 255, 79, 255, 98, 255, 83, 255, 102, 255, 88, 255, 107, 255, 93, 255, 112, 255, 97, 255, 117, 255, 103, 255, 117, 255, 103, 255, 122, 255, 109, 255, 128, 255, 114, 255, 135, 255, 121, 255, 140, 255, 127, 255, 147, 255, 134, 255, 153, 255, 140, 255, 160, 255, 147, 255, 168, 255, 153, 255, 175, 255, 160, 255, 182, 255, 167, 255, 190, 255, 173, 255, 198, 255, 181, 255, 206, 255, 187, 255, 214, 255, 194, 255, 222, 255, 201, 255, 231, 255, 207, 255, 239, 255, 215, 255, 248, 255, 222, 255, 76, 73, 83, 84, 96, 0, 0, 0, 73, 78, 70, 79, 73, 83, 70, 84, 53, 0, 0, 0, 71, 111, 108, 100, 87, 97, 118, 101, 32, 40, 67, 41, 32, 67, 104, 114, 105, 115, 32, 83, 46, 32, 67, 114, 97, 105, 103, 44, 32, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 103, 111, 108, 100, 119, 97, 118, 101, 46, 99, 111, 109, 0, 0, 73, 69, 78, 71, 2, 0, 0, 0, 32, 0, 73, 67, 82, 68, 11, 0, 0, 0, 50, 48, 48, 52, 45, 48, 56, 45, 49, 57, 0, 0};
+/* End Of File */
diff --git a/src/sounds/ring_sound.h b/src/sounds/ring_sound.h
new file mode 100644
index 0000000..e97ea6c
--- /dev/null
+++ b/src/sounds/ring_sound.h
@@ -0,0 +1,2 @@
+static const unsigned char ring_sound_data[] = {79,103,103,83,0,2,0,0,0,0,0,0,0,0,86,205,77,113,0,0,0,0,157,160,235,224,1,30,1,118,111,114,98,105,115,0,0,0,0,1,17,43,0,0,0,0,0,0,144,101,0,0,0,0,0,0,153,1,79,103,103,83,0,0,0,0,0,0,0,0,0,0,86,205,77,113,1,0,0,0,218,13,219,101,11,45,255,255,255,255,255,255,255,255,255,181,3,118,111,114,98,105,115,29,0,0,0,88,105,112,104,46,79,114,103,32,108,105,98,86,111,114,98,105,115,32,73,32,50,48,48,55,48,54,50,50,0,0,0,0,1,5,118,111,114,98,105,115,18,66,67,86,1,0,0,1,0,12,82,20,33,37,25,83,74,99,8,149,82,82,41,5,29,99,80,91,71,29,99,212,57,70,33,100,16,83,136,73,25,165,123,79,42,149,88,74,200,17,82,88,41,69,29,83,76,83,73,149,82,150,41,69,29,99,20,83,72,33,83,214,49,101,161,115,20,75,134,73,9,37,108,77,174,116,22,75,232,153,99,150,49,70,29,99,206,90,74,157,99,214,49,69,29,99,82,82,73,161,115,24,58,102,37,100,20,58,70,197,232,98,124,48,58,149,162,66,40,190,199,222,82,233,45,133,138,91,138,189,215,26,83,235,45,132,24,75,105,193,8,97,115,237,181,213,220,74,106,197,24,99,140,49,198,197,226,83,40,130,208,144,85,0,0,1,0,0,64,4,1,66,67,86,1,0,10,0,0,194,80,12,69,81,128,208,144,85,0,64,6,0,128,0,20,69,113,20,199,113,28,71,146,36,203,2,66,67,86,1,0,64,0,0,2,0,0,40,142,225,40,146,35,73,146,100,89,150,101,89,150,166,121,150,168,185,170,47,251,174,46,235,174,237,234,186,14,132,134,172,4,0,200,0,0,24,134,33,135,222,73,204,144,83,144,73,38,41,85,204,57,8,161,245,14,57,229,20,100,210,82,198,152,98,140,81,206,144,83,12,49,5,49,134,208,41,133,16,212,78,57,165,12,34,8,67,72,157,100,206,32,75,61,232,224,98,231,56,16,26,178,34,0,136,2,0,0,140,65,140,33,198,144,115,12,74,6,33,114,142,73,200,32,68,206,57,41,157,148,76,74,40,173,180,150,73,9,45,149,214,34,231,156,148,78,74,38,165,180,22,82,203,164,148,214,66,43,5,0,0,4,56,0,0,4,88,8,133,134,172,8,0,162,0,0,16,131,144,82,72,41,196,148,98,78,49,135,148,82,142,41,199,144,82,204,57,197,152,114,140,49,232,32,84,204,49,200,28,132,72,41,197,24,115,78,57,230,32,100,12,42,230,28,132,12,50,1,0,0,1,14,0,0,1,22,66,161,33,43,2,128,56,1,0,131,36,105,154,165,105,162,104,105,154,40,122,166,168,170,162,40,170,170,229,121,166,233,153,166,170,122,162,169,170,166,170,186,174,169,170,174,108,121,158,105,122,166,168,170,158,41,170,170,169,170,174,107,170,170,235,138,170,106,203,166,171,218,182,233,170,182,236,202,178,110,187,178,172,219,158,170,202,182,169,186,178,110,170,174,109,187,178,108,235,174,44,219,186,228,121,170,234,153,166,235,122,166,233,186,170,235,218,178,234,186,178,237,153,166,235,138,170,43,219,166,235,202,178,235,202,182,173,202,178,174,107,166,233,186,162,171,218,174,169,186,178,237,202,174,109,187,178,172,251,166,235,234,182,234,202,186,174,202,178,238,219,182,174,251,178,173,11,187,232,186,182,174,202,174,174,171,178,172,235,178,45,235,182,108,219,66,201,243,84,213,51,77,215,245,76,211,117,85,215,181,109,213,117,109,91,51,77,215,53,93,87,150,69,213,117,101,213,149,117,93,117,101,91,247,76,211,117,77,87,149,101,211,85,101,89,149,101,221,118,101,87,151,69,215,181,109,85,150,125,93,117,101,95,151,109,221,247,101,89,215,125,211,117,117,91,149,101,219,87,101,89,247,101,93,247,133,89,183,125,221,83,85,91,55,93,87,215,77,215,213,125,91,215,125,97,182,109,223,23,93,87,215,85,217,214,133,85,150,117,223,214,125,101,152,117,157,48,186,174,174,171,182,236,235,170,44,235,190,174,235,198,48,235,186,48,172,186,109,252,174,173,11,195,171,235,198,177,235,190,174,220,190,143,106,219,190,240,234,182,49,188,186,110,28,187,176,27,191,237,251,198,177,169,170,109,155,174,171,235,166,43,235,186,108,235,190,111,235,186,113,140,174,171,235,170,44,251,186,234,202,190,111,235,186,240,235,190,47,12,163,235,234,186,42,203,186,176,218,178,175,203,186,46,12,187,174,27,195,106,219,194,238,218,186,112,204,178,46,12,183,239,43,199,175,11,67,213,182,133,225,213,117,163,171,219,198,111,11,195,210,55,118,190,0,0,128,1,7,0,128,0,19,202,64,161,33,43,2,128,56,1,0,6,33,8,21,99,16,42,198,32,132,16,82,10,33,164,84,49,6,33,99,14,74,198,28,148,16,74,73,33,148,210,42,198,32,100,142,73,200,28,147,16,74,104,169,148,208,74,40,165,165,80,74,75,161,148,214,82,106,45,166,212,90,12,161,180,20,74,105,173,148,210,90,106,41,182,212,82,108,21,99,16,50,231,164,100,142,73,40,165,180,86,74,105,41,115,76,74,198,160,164,14,66,42,165,164,210,74,73,173,101,206,73,201,160,163,210,57,72,169,164,210,82,73,169,181,80,74,107,161,148,214,74,74,177,165,210,74,109,173,197,26,74,105,45,164,210,90,73,169,181,212,82,109,173,181,90,35,198,32,100,140,65,201,156,147,82,74,73,169,148,210,90,230,156,148,14,58,42,153,131,146,74,41,169,149,146,82,172,152,147,210,65,40,37,131,140,74,73,165,181,146,74,43,161,148,214,74,74,177,133,82,90,107,173,213,152,82,75,53,148,146,90,73,169,197,80,74,107,173,181,26,83,43,53,133,80,82,11,165,180,22,74,105,173,181,86,107,106,45,182,80,66,107,161,164,22,75,42,49,181,22,99,109,173,197,24,74,105,173,164,18,91,41,169,197,22,91,141,173,181,88,83,75,53,150,146,98,108,173,213,216,74,45,57,214,90,107,74,45,214,210,82,140,173,181,152,91,76,185,197,88,107,13,37,180,22,74,105,173,148,210,90,74,173,197,214,90,173,161,148,214,74,42,177,149,146,90,108,173,213,216,90,140,53,148,210,98,41,41,181,144,74,108,173,181,88,91,108,53,166,150,98,108,177,213,88,82,139,49,198,88,115,75,181,213,148,90,139,173,181,88,75,43,53,198,24,107,110,53,229,82,0,0,192,128,3,0,64,128,9,101,160,208,144,149,0,64,20,0,0,96,12,99,140,65,104,20,114,204,57,41,141,82,206,57,39,37,115,14,66,8,41,101,206,65,8,33,165,206,57,8,165,180,212,57,7,161,148,148,66,41,41,165,20,91,40,37,165,214,90,44,0,0,160,192,1,0,32,192,6,77,137,197,1,10,13,89,9,0,68,1,0,32,198,40,197,24,132,198,32,165,24,131,208,24,163,20,99,16,42,165,24,115,14,66,165,20,99,206,65,200,24,115,206,65,41,25,99,206,65,39,37,132,16,66,41,165,132,16,66,40,165,148,2,0,0,10,28,0,0,2,108,208,148,88,28,160,208,144,21,1,64,20,0,0,96,12,98,12,49,134,32,116,82,58,41,17,132,76,74,39,165,145,18,90,11,41,101,150,74,138,37,198,204,90,137,173,196,216,72,9,173,133,214,50,107,37,198,210,98,70,173,196,88,98,42,0,0,236,192,1,0,236,192,66,40,52,100,37,0,144,7,0,64,24,163,20,99,206,57,103,16,98,204,57,8,33,52,8,49,230,28,132,16,42,198,156,115,14,66,8,21,99,206,57,7,33,132,206,57,231,32,132,16,66,231,156,115,16,66,8,161,131,16,66,8,165,148,210,65,8,33,132,82,74,233,32,132,16,66,41,165,116,16,66,8,161,148,82,10,0,0,42,112,0,0,8,176,81,100,115,130,145,160,66,67,86,2,0,121,0,0,128,49,74,57,39,37,165,70,41,198,32,164,20,91,163,20,99,16,82,106,173,98,12,66,74,173,197,88,49,6,33,165,214,98,236,32,164,212,90,140,181,118,16,82,106,45,198,90,67,74,173,197,88,107,206,33,165,214,98,172,53,215,212,90,140,181,230,220,123,106,45,198,90,115,206,185,0,0,220,5,7,0,176,3,27,69,54,39,24,9,42,52,100,37,0,144,7,0,64,32,164,20,99,140,57,135,148,98,140,49,231,156,67,74,49,198,152,115,206,41,198,24,115,206,57,231,20,99,140,57,231,156,115,140,49,231,156,115,206,57,198,152,115,206,57,231,156,115,206,57,231,160,131,144,57,231,156,115,208,65,232,156,115,206,57,8,33,116,206,57,231,28,132,16,10,0,0,42,112,0,0,8,176,81,100,115,130,145,160,66,67,86,2,0,225,0,0,128,49,148,82,74,41,165,148,82,74,168,163,148,82,74,41,165,148,82,2,33,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,165,148,82,74,41,149,82,74,41,165,148,82,74,41,165,148,82,74,41,165,0,32,223,10,7,0,255,7,27,103,88,73,58,43,28,13,46,52,100,37,0,16,14,0,0,24,195,24,132,140,57,39,37,165,134,49,8,165,116,78,74,73,37,53,140,65,40,165,115,18,82,74,41,131,208,90,106,165,164,210,82,74,25,132,148,98,11,33,149,148,90,10,165,180,86,107,41,169,181,148,82,40,41,197,26,75,74,169,165,214,50,231,36,164,146,90,75,173,182,152,57,7,165,164,214,90,106,173,197,16,66,74,177,181,214,82,107,177,117,82,82,73,173,181,214,90,109,45,164,148,90,107,45,198,214,98,108,37,165,150,90,107,169,197,214,90,76,169,181,22,91,75,45,198,214,98,75,173,197,216,98,139,49,198,26,11,0,224,110,112,0,128,72,176,113,134,149,164,179,194,209,224,66,67,86,2,0,33,1,0,4,50,74,57,231,156,131,16,66,8,33,82,138,49,231,160,131,16,66,8,33,68,74,49,230,156,131,16,66,8,33,132,140,49,231,32,132,16,66,8,161,148,144,49,230,28,132,16,66,8,33,132,82,58,231,32,132,80,74,9,165,148,82,74,231,28,132,16,66,8,165,148,82,74,9,33,132,16,66,40,165,148,82,74,41,33,132,16,74,41,165,148,82,74,41,37,132,16,66,40,165,148,82,74,41,165,132,16,66,40,165,148,82,74,41,165,148,16,66,40,165,148,82,74,41,165,148,18,66,8,161,148,82,74,41,165,148,82,66,8,165,148,82,74,41,165,148,82,74,40,33,132,82,74,41,165,148,82,74,9,37,148,82,74,41,165,148,82,74,41,33,148,82,74,41,165,148,82,74,41,165,0,0,128,3,7,0,128,0,35,232,36,163,202,34,108,52,225,194,3,16,0,0,0,2,0,2,76,0,129,1,130,130,81,8,2,132,17,8,0,0,0,0,0,8,0,248,0,0,72,10,128,136,136,104,230,12,14,16,18,20,22,24,26,28,30,32,34,36,0,0,0,0,0,0,0,0,0,0,0,0,4,79,103,103,83,0,0,0,21,0,0,0,0,0,0,86,205,77,113,2,0,0,0,187,93,199,254,22,46,48,51,54,49,47,48,77,82,60,72,68,72,69,76,73,68,74,67,72,63,68,122,76,10,205,8,84,86,57,176,77,94,39,172,127,166,207,83,235,215,232,241,135,24,187,79,139,233,209,23,34,11,68,105,231,254,13,189,81,232,98,241,183,13,26,187,54,122,11,111,3,84,114,133,91,214,176,118,108,45,111,224,129,46,254,98,150,60,117,152,63,185,46,42,191,191,74,215,8,26,63,86,188,65,104,77,38,253,161,176,17,75,199,133,7,122,12,111,43,130,65,145,3,38,225,214,210,53,230,149,22,73,197,45,225,101,55,172,157,76,88,83,175,189,121,46,133,252,131,16,156,37,148,185,160,180,150,215,184,166,215,85,118,127,136,237,122,76,10,77,8,6,69,1,222,238,209,176,236,241,83,39,147,17,17,186,56,212,17,68,230,235,168,135,66,37,13,186,191,54,147,186,67,199,36,87,107,52,38,200,117,13,2,241,120,124,38,242,68,28,122,76,10,77,8,84,69,1,26,83,138,138,2,123,98,77,64,48,204,107,224,119,238,117,113,170,16,20,245,14,229,213,222,173,34,207,230,205,177,119,73,246,208,86,6,34,223,202,0,122,11,111,131,160,146,43,128,51,235,243,38,145,227,154,164,97,206,55,216,242,238,174,171,209,100,204,235,207,203,187,35,224,65,121,52,151,154,22,80,2,158,86,78,127,240,0,122,11,111,131,32,103,96,0,58,13,205,66,169,134,133,170,211,248,88,239,107,37,226,126,84,75,246,190,102,48,188,235,52,72,250,104,67,144,186,179,150,153,212,150,61,152,12,4,118,97,93,155,43,128,162,168,1,170,233,232,80,202,217,255,87,215,187,173,91,103,30,101,195,242,237,255,247,121,12,30,244,209,135,231,39,192,16,138,125,254,63,240,48,81,89,78,128,183,6,125,52,65,225,178,83,36,134,96,99,8,17,127,48,122,255,195,148,111,31,7,86,51,82,35,0,126,96,227,247,49,0,108,63,58,124,41,155,2,166,196,76,29,56,181,155,218,53,216,140,83,121,5,220,73,99,255,175,237,149,221,148,138,161,6,150,221,255,30,154,168,86,149,52,130,15,7,54,106,86,48,144,124,185,141,47,108,19,66,130,109,254,13,132,30,158,51,0,48,79,248,181,78,234,108,185,151,19,146,229,168,68,7,0,248,249,53,3,132,128,22,114,128,36,160,197,72,205,144,62,210,9,128,192,113,189,185,237,221,136,0,168,12,0,0,148,253,26,128,7,19,0,128,192,6,112,1,160,205,44,100,254,180,153,102,234,236,1,146,227,232,136,188,0,175,41,64,104,89,32,228,0,25,152,205,66,99,47,229,223,155,245,27,42,217,224,245,235,111,7,128,80,190,24,73,164,185,199,67,134,2,0,4,132,40,61,111,67,188,92,4,0,61,135,39,3,95,192,199,189,236,188,28,101,14,89,10,163,164,17,150,97,237,177,197,208,166,7,188,57,192,84,86,255,29,95,247,0,0,208,240,80,205,47,8,0,0,65,53,147,4,89,225,227,235,204,51,67,195,236,117,242,188,168,90,204,196,184,10,211,14,116,59,22,77,223,67,140,235,230,67,56,44,49,140,204,82,83,142,226,232,168,29,104,0,182,234,0,33,160,229,8,96,3,24,32,55,185,155,223,111,118,178,17,130,91,226,118,170,59,253,52,86,82,227,88,66,116,141,81,128,42,8,119,172,0,117,55,41,2,0,76,230,212,246,197,78,24,16,111,89,25,18,0,140,2,46,20,47,2,146,226,232,136,6,18,124,32,180,0,120,163,14,100,24,212,124,46,156,231,211,89,73,1,242,218,90,198,219,23,255,246,228,53,25,107,121,244,35,37,2,224,49,70,213,130,211,137,25,85,2,0,64,245,4,248,86,219,135,27,230,100,82,18,92,9,154,30,206,142,225,232,136,121,1,174,187,0,132,58,16,34,129,13,32,100,16,133,70,79,239,202,72,12,54,136,241,227,63,215,199,42,0,148,231,46,229,154,223,221,75,155,1,128,185,145,140,223,37,193,108,156,25,177,27,4,40,10,45,201,105,145,84,0,161,128,25,192,75,204,245,231,49,222,1,142,99,237,135,117,224,19,224,118,4,32,4,8,145,64,134,17,68,71,57,41,198,135,107,148,128,52,3,230,249,72,157,93,168,101,145,20,77,13,235,59,9,112,81,7,62,119,165,193,50,179,66,3,0,134,59,228,28,2,174,224,223,231,236,14,235,142,47,26,96,74,220,6,150,98,237,74,27,0,2,66,195,128,55,31,64,70,6,202,168,51,243,212,126,179,121,16,241,128,222,249,186,103,189,43,9,84,201,39,211,219,86,74,0,64,104,170,33,44,201,113,183,1,0,30,94,131,248,161,244,33,215,159,3,77,171,110,0,205,123,2,138,227,232,161,240,2,152,2,132,128,22,242,9,100,132,16,55,155,205,167,145,255,139,128,12,129,48,18,211,212,42,133,16,70,31,204,70,24,37,190,178,113,0,128,48,147,70,247,247,239,253,146,207,68,4,132,28,152,192,101,104,217,23,147,136,107,191,239,129,29,65,9,125,5,150,99,237,147,17,51,52,192,155,79,32,99,210,188,253,46,2,80,89,136,136,71,173,55,178,0,0,4,56,94,159,239,188,127,177,44,114,190,115,140,237,159,224,245,142,159,239,150,69,14,0,48,62,60,224,31,119,202,191,136,81,217,154,10,68,221,14,146,98,237,73,27,116,96,251,68,104,24,8,249,0,10,64,70,138,129,206,237,50,30,219,40,81,77,221,247,59,199,247,255,217,234,1,15,104,141,95,108,82,0,16,66,0,92,62,220,237,149,2,0,25,181,89,135,90,67,35,102,71,150,80,193,16,192,111,216,3,246,6,142,229,232,152,14,36,128,189,43,128,55,160,133,28,160,0,228,242,32,157,48,244,185,185,237,34,0,64,156,248,120,229,54,22,141,166,192,69,204,136,224,32,18,246,50,0,171,12,0,192,184,66,226,87,196,157,32,85,205,129,99,80,0,150,226,171,20,18,64,104,41,224,141,4,214,56,158,156,156,60,104,255,188,214,227,147,228,44,49,174,206,146,10,16,99,140,144,5,230,167,43,5,0,32,32,9,150,177,249,231,128,99,167,224,187,111,225,33,204,161,48,185,148,50,27,175,67,96,183,140,2,79,103,103,83,0,0,0,43,0,0,0,0,0,0,86,205,77,113,3,0,0,0,153,91,99,211,22,75,73,64,74,72,67,72,74,70,67,70,74,75,64,73,75,69,76,67,71,73,64,138,99,227,125,227,0,0,215,93,2,16,218,6,32,164,3,10,128,17,130,119,232,136,238,110,155,180,68,105,66,34,92,173,214,253,102,86,130,149,209,120,249,250,203,145,102,0,24,142,148,151,196,186,127,108,186,9,0,148,183,247,199,58,53,225,34,30,10,7,15,96,8,148,56,3,146,99,237,99,75,216,168,64,104,89,32,228,0,211,42,49,55,110,231,107,39,203,222,73,172,209,18,86,79,126,103,0,128,241,225,166,210,130,158,204,202,0,0,4,148,249,107,251,223,157,146,95,132,128,28,28,4,150,192,233,123,227,241,245,144,25,56,106,163,49,21,154,6,150,226,41,37,24,0,64,104,43,192,155,3,100,8,180,138,148,113,55,93,74,16,90,107,213,218,243,87,135,175,142,76,120,85,107,77,215,167,215,155,2,0,0,16,78,255,7,0,0,208,96,151,82,153,119,4,153,29,54,17,171,168,56,3,142,227,232,8,14,4,192,62,85,2,132,128,22,114,128,12,3,7,195,167,210,142,211,111,172,117,192,148,146,214,227,245,160,217,84,4,16,205,59,121,47,85,5,0,141,183,77,42,139,155,179,114,22,0,168,226,1,88,195,108,163,238,30,239,210,79,178,34,205,236,29,234,86,2,142,227,232,55,12,30,216,6,200,1,180,200,13,96,105,249,224,201,251,152,58,47,137,100,79,182,63,95,127,109,73,78,158,6,13,218,73,26,255,42,20,174,25,31,199,136,147,62,198,176,35,11,197,248,223,45,74,26,0,139,231,254,198,143,52,65,129,223,142,52,223,30,150,225,41,35,24,60,176,10,120,69,9,0,222,8,96,42,0,218,145,205,247,246,173,17,60,132,64,235,190,187,250,112,74,112,80,204,108,241,112,110,154,16,0,0,104,171,213,73,107,0,0,108,210,31,255,116,201,16,132,1,188,254,82,61,75,212,57,142,227,232,36,28,0,160,63,184,128,16,80,66,122,2,5,64,36,103,153,135,59,246,227,85,50,233,238,166,13,113,162,176,253,243,52,139,48,69,136,10,114,71,80,5,36,95,114,208,202,253,115,82,1,0,239,157,242,89,102,25,13,199,68,2,104,29,112,12,222,86,5,146,226,232,36,13,26,80,133,208,10,8,81,0,185,0,85,50,126,75,110,11,81,99,212,188,38,241,238,107,199,39,167,245,64,215,130,174,13,182,175,86,22,192,99,101,200,162,114,208,119,46,10,0,192,60,225,158,37,48,6,251,224,124,55,180,94,191,247,45,210,66,187,199,0,142,99,237,131,229,5,232,201,1,8,237,128,16,1,100,152,128,211,186,46,213,37,191,4,68,148,39,239,17,0,192,239,164,0,154,159,254,182,0,0,8,128,186,213,186,232,189,99,65,170,220,64,1,52,152,195,24,92,196,101,225,248,37,115,194,160,12,222,214,9,146,226,232,4,59,0,192,245,181,7,32,4,200,121,64,134,208,124,9,112,44,69,123,187,221,106,72,1,242,172,255,102,117,185,29,99,154,1,31,5,7,0,252,175,1,56,123,105,130,0,0,224,1,12,9,10,183,110,140,139,207,27,171,72,69,0,6,150,98,237,105,54,16,96,13,161,205,128,55,159,64,134,56,14,178,60,221,89,74,145,202,212,218,63,175,237,254,151,122,233,146,196,200,124,158,207,191,206,160,234,49,42,149,51,81,151,91,179,50,0,64,141,201,242,11,111,26,63,82,143,68,235,205,18,212,76,167,138,98,227,255,134,23,224,26,1,132,0,33,223,0,121,132,181,77,77,114,173,122,197,2,68,178,119,248,203,180,20,0,197,243,94,136,53,55,238,118,92,1,64,0,209,228,132,77,246,53,124,239,218,228,14,224,93,8,88,7,230,213,199,69,65,63,129,84,238,103,144,38,47,30,138,98,173,233,67,131,3,150,31,60,132,72,96,106,100,163,200,244,164,255,117,58,106,228,88,50,94,117,222,54,254,172,91,72,93,27,87,204,46,221,206,95,155,8,0,176,249,241,171,15,0,80,46,76,62,236,227,227,139,3,238,5,122,206,171,194,150,255,72,24,206,216,149,70,51,154,225,216,42,35,122,165,75,0,240,230,3,200,16,217,165,174,84,28,75,0,0,160,173,14,30,118,1,0,8,0,28,198,245,206,239,81,216,25,4,167,246,58,57,198,231,158,128,42,92,243,224,98,36,119,2,133,225,150,62,39,156,206,0,138,227,224,255,33,47,192,86,2,152,16,1,20,10,32,196,137,246,187,242,177,214,10,137,132,116,164,72,150,229,194,106,72,6,128,144,156,88,93,178,233,32,40,46,193,9,112,211,168,63,195,239,111,130,18,65,213,229,234,106,144,153,244,229,118,57,209,21,192,31,244,231,11,146,98,237,135,53,72,0,100,88,0,188,1,200,16,34,165,243,253,25,195,187,163,139,104,229,181,185,48,78,62,249,207,104,27,227,73,205,131,245,86,79,22,0,98,140,49,106,246,58,255,244,159,102,0,0,0,194,244,48,160,57,106,42,253,117,223,254,4,197,144,40,210,220,84,1,142,98,237,135,49,0,44,27,8,1,188,185,4,166,6,104,44,221,183,164,254,78,238,135,106,46,200,42,185,77,63,230,174,82,26,150,248,207,135,166,0,64,152,72,120,169,180,112,59,209,0,128,10,222,14,72,187,84,107,206,15,163,157,29,195,55,164,84,61,138,99,227,255,134,23,224,250,58,128,199,28,1,108,0,65,156,88,94,174,203,19,219,99,101,198,16,199,74,8,242,178,91,173,1,128,71,245,109,189,229,62,47,32,71,33,221,38,82,155,52,110,248,88,155,169,91,71,67,51,204,140,112,82,150,0,180,17,63,255,129,103,192,213,249,3,150,98,140,227,171,0,161,9,120,243,5,144,11,144,101,30,251,62,221,94,107,27,89,214,140,119,63,0,0,160,114,140,145,186,245,203,1,0,192,185,221,191,55,204,115,25,188,15,107,185,84,120,17,151,224,183,57,184,78,193,2,70,38,147,17,111,0,146,98,237,113,243,2,188,63,8,16,218,0,8,17,64,134,20,210,108,246,123,138,163,203,38,0,177,243,251,90,95,1,128,242,90,7,132,199,159,22,0,0,74,164,58,44,254,35,57,196,183,182,22,0,240,79,60,131,39,46,8,211,31,29,227,63,41,138,152,146,124,142,228,232,101,56,144,0,158,58,1,33,160,132,8,160,0,136,20,154,111,29,73,51,127,128,114,105,210,20,109,91,182,213,184,114,196,114,39,48,218,159,112,15,224,52,15,245,219,12,194,104,226,164,91,0,0,62,143,19,207,237,196,9,0,97,12,126,215,19,184,2,156,1,150,226,216,202,81,65,144,9,5,0,120,35,128,36,128,138,140,38,250,166,215,232,67,19,230,78,186,70,0,0,128,80,248,173,2,0,160,6,63,26,174,251,224,210,105,110,91,1,239,179,240,127,70,150,133,226,26,185,219,59,61,121,92,1,79,103,103,83,0,0,0,61,0,0,0,0,0,0,86,205,77,113,4,0,0,0,107,44,189,210,18,73,79,64,65,74,72,71,67,77,68,60,70,74,50,45,46,51,49,138,227,224,251,192,129,6,224,25,2,96,114,36,48,54,28,140,113,148,47,204,215,198,113,145,40,5,228,46,213,251,198,93,34,18,214,17,124,28,119,54,98,101,0,96,30,243,60,147,216,15,220,137,94,26,96,59,0,143,217,198,166,47,206,101,208,115,4,195,10,129,79,1,138,163,25,165,228,3,0,236,20,192,99,200,76,160,208,64,66,98,88,56,244,125,184,103,180,150,204,65,133,170,168,254,209,91,235,135,154,193,165,73,152,34,209,24,206,109,204,174,3,0,171,216,71,62,89,90,139,213,164,13,78,116,241,168,21,0,105,234,246,78,1,64,78,235,197,64,21,224,36,150,98,140,149,27,0,134,0,111,99,32,228,43,96,21,96,168,132,247,223,75,31,90,21,4,241,206,184,111,170,14,45,3,224,149,116,0,128,90,87,0,70,47,77,0,0,160,3,216,98,170,235,253,228,85,230,162,65,160,230,116,32,213,25,142,229,104,128,73,40,0,0,0,111,64,132,60,32,25,120,152,119,114,222,157,229,154,84,1,48,13,128,142,35,5,0,132,235,86,128,186,159,78,0,0,80,37,105,89,229,132,22,217,1,8,224,14,108,147,220,113,203,58,55,34,197,124,92,0,142,98,45,41,85,33,224,33,68,0,133,0,6,226,72,157,206,190,189,245,125,111,39,106,80,105,157,229,120,15,32,0,103,137,213,107,219,79,186,67,104,110,40,21,19,169,235,81,221,211,85,230,123,46,181,67,87,255,3,138,132,2,110,154,219,90,246,187,59,224,10,178,248,9,138,99,227,221,229,5,56,238,39,32,180,6,188,81,3,50,164,73,112,52,95,143,21,62,9,8,54,140,78,110,245,89,247,6,128,7,10,66,113,249,126,74,3,0,136,216,212,196,69,255,207,227,158,174,76,168,99,187,188,96,126,211,25,179,165,190,25,43,105,162,145,6,142,164,149,7,236,5,236,115,6,8,1,37,231,1,5,64,64,104,190,172,15,138,200,56,198,52,131,79,76,5,15,34,80,109,245,55,56,65,202,31,74,8,0,208,76,44,127,86,203,26,1,215,64,130,0,202,209,98,238,116,186,152,25,1,167,78,3,70,64,215,2,154,226,41,149,144,48,20,132,6,1,111,174,1,25,196,201,131,201,179,227,91,247,82,37,123,212,44,113,248,97,0,0,100,193,99,140,241,231,253,2,0,32,32,11,185,124,239,246,40,107,43,128,168,130,51,119,158,16,245,141,209,196,34,113,138,24,1,138,99,237,31,227,192,4,240,46,1,60,132,92,21,200,48,202,155,36,151,232,253,134,191,247,154,151,13,194,54,139,217,159,170,110,163,4,225,80,222,196,216,150,54,59,0,108,211,221,139,151,96,0,0,242,35,138,130,185,0,216,129,247,61,104,247,10,249,73,252,232,164,100,109,242,216,0,146,226,104,26,59,80,0,124,87,36,192,219,32,16,114,128,2,32,142,11,149,159,89,82,245,36,138,98,134,132,29,83,254,81,12,18,4,65,175,220,7,160,128,101,202,10,136,63,255,105,10,0,224,46,203,251,94,23,22,73,132,188,68,224,7,16,101,8,150,225,216,198,81,0,120,219,12,120,35,1,185,80,180,90,117,243,94,255,216,202,131,239,236,28,221,108,10,0,128,227,193,125,210,5,0,184,63,234,78,111,95,163,1,190,227,223,139,159,246,210,35,175,244,4,241,5,239,3,122,35,119,220,5,64,72,2,9,161,30,201,16,158,94,221,89,217,223,63,56,217,40,245,121,207,233,199,7,34,0,0,72,165,239,42,99,135,178,111,70,64,3,55,191,185,179,184,238,151,69,0,0,0,197,126,93,204,148,135,194,225,70,66,236,38,69,179,82,2,114,34,205,105,5,144,204,0,144,121,140,73,238,206,126,54,74,251,231,154,215,220,16,114,126,241,218,104,90,99,137,35,117,179,192,91,168,12,20,101,169,115,99,227,234,248,112,122,163,19,224,142,35,161,191,236,184,160,96,4,42,151,30,80,225,221,68,27,139,15,229,42,71,1,122,11,111,131,160,50,40,15,30,151,20,143,67,106,32,117,29,110,230,162,102,161,120,73,118,189,226,172,23,119,104,115,10,101,16,198,240,181,178,134,228,122,217,160,14,124,22,208,146,44,122,12,111,131,64,37,103,5,222,48,105,211,174,241,45,73,5,175,212,160,201,117,91,207,2,171,99,117,149,81,206,71,117,191,121,246,106,74,213,85,54,25,191,194,1,122,11,111,131,64,165,42,208,208,203,97,51,208,69,94,180,92,186,141,213,108,39,27,214,37,238,71,154,103,122,69,82,22,94,144,1,142,184,198,5,59,180,103,206,98,7,122,12,111,11,130,65,81,176,217,79,212,236,179,96,17,101,94,20,195,149,50,12,78,90,133,113,115,130,168,43,226,174,100,159,231,34,131,220,81,114,224,164,174,173,200,9,120,139,82,137,45,122,77,10,77,8,228,12,50,20,204,54,221,20,165,52,150,100,85,15,141,203,210,245,173,167,189,206,190,138,180,118,136,193,57,181,179,234,197,48,162,36,198,98,11,152,236,14,209,5,79,103,103,83,0,4,182,61,0,0,0,0,0,0,86,205,77,113,5,0,0,0,204,191,103,125,1,23,122,10,143,6,208,152,10,27,18,152,16,97,36,18,46,59,36,238,74,63,30,103,0};
+
diff --git a/src/spinctld.cpp b/src/spinctld.cpp
new file mode 100644
index 0000000..8ed3aee
--- /dev/null
+++ b/src/spinctld.cpp
@@ -0,0 +1,635 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: spinctld.h
+// Author: John Labenski
+// Created: 11/05/02
+// Copyright: John Labenski, 2002
+// License: wxWidgets
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include <wx/valtext.h> // for wxTextValidator
+ #include <wx/textctrl.h>
+#endif // WX_PRECOMP
+
+#include <wx/tooltip.h>
+#include "spinctld.h"
+#include <cmath>
+
+#if wxCHECK_VERSION(2,5,0)
+ #include "wx/math.h"
+#else
+ #if defined(__VISUALC__) || defined(__BORLANDC__) || defined(__WATCOMC__)
+ #include <float.h>
+ #define wxFinite(x) _finite(x)
+ #elif defined(__GNUG__)||defined(__GNUWIN32__)||defined(__DJGPP__)|| \
+ defined(__SGI_CC__)||defined(__SUNCC__)||defined(__XLC__)|| \
+ defined(__HPUX__)||defined(__MWERKS__)
+ #define wxFinite(x) finite(x)
+ #else
+ #define wxFinite(x) ((x) == (x))
+ #endif
+#endif // wxCHECK_VERSION(2,5,0)
+
+// NOTES : if the textctrl is focused and the program is ending, a killfocus
+// event is sent in MSW, this is why m_textCtrl is set to NULL in it's
+// destructor and there's so many checks for it not being NULL
+
+//----------------------------------------------------------------------------
+// wxSpinCtrlDbl
+//----------------------------------------------------------------------------
+
+// the textctrl used for the wxSpinCtrlDbl, needed for keypresses
+class wxSpinCtrlDblTextCtrl : public wxTextCtrl
+{
+public:
+ wxSpinCtrlDblTextCtrl( wxWindow *parent, wxWindowID id,
+ const wxString &value = wxEmptyString,
+ const wxPoint &pos = wxDefaultPosition,
+ const wxSize &size = wxDefaultSize,
+ long style = 0,
+ const wxValidator& validator = wxDefaultValidator,
+ const wxString &name = wxTextCtrlNameStr);
+
+ // MSW sends extra kill focus event
+ virtual ~wxSpinCtrlDblTextCtrl()
+ {
+ if (m_parent) m_parent->m_textCtrl = NULL;
+ m_parent = NULL;
+ }
+
+ wxSpinCtrlDbl *m_parent;
+
+ void OnChar( wxKeyEvent &event ); // pass chars to wxSpinCtrlDbl
+ void OnKillFocus( wxFocusEvent &event ); // sync the spin to textctrl
+
+private:
+ DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(wxSpinCtrlDblTextCtrl,wxTextCtrl)
+// EVT_TEXT_ENTER( wxID_ANY, wxSpinCtrlDblTextCtrl::OnTextEnter ) // get them from spinctrldbl
+// EVT_TEXT( wxID_ANY, wxSpinCtrlDblTextCtrl::OnTextUpdate ) // get them from spinctrldbl
+ EVT_CHAR( wxSpinCtrlDblTextCtrl::OnChar )
+ EVT_KILL_FOCUS( wxSpinCtrlDblTextCtrl::OnKillFocus )
+END_EVENT_TABLE()
+
+wxSpinCtrlDblTextCtrl::wxSpinCtrlDblTextCtrl( wxWindow *parent, wxWindowID id,
+ const wxString &value,
+ const wxPoint &pos, const wxSize &size,
+ long style,
+ const wxValidator& validator,
+ const wxString &name)
+ :wxTextCtrl( parent, id, value, pos, size, style,
+ validator, name)
+{
+ m_parent = (wxSpinCtrlDbl*)parent;
+}
+
+void wxSpinCtrlDblTextCtrl::OnChar( wxKeyEvent &event )
+{
+ if (m_parent) m_parent->OnChar( event );
+}
+
+void wxSpinCtrlDblTextCtrl::OnKillFocus( wxFocusEvent &event )
+{
+ if (m_parent) m_parent->SyncSpinToText(true);
+ event.Skip();
+}
+
+//----------------------------------------------------------------------------
+// wxSpinCtrlDbl
+//----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS( wxSpinCtrlDbl, wxControl )
+
+BEGIN_EVENT_TABLE(wxSpinCtrlDbl,wxControl)
+ EVT_SPIN_UP ( wxID_ANY, wxSpinCtrlDbl::OnSpinUp )
+ EVT_SPIN_DOWN ( wxID_ANY, wxSpinCtrlDbl::OnSpinDown )
+ EVT_TEXT_ENTER( wxID_ANY, wxSpinCtrlDbl::OnTextEnter )
+ //EVT_TEXT ( wxID_ANY, wxSpinCtrlDbl::OnText )
+ EVT_SET_FOCUS ( wxSpinCtrlDbl::OnFocus )
+ EVT_KILL_FOCUS( wxSpinCtrlDbl::OnKillFocus )
+END_EVENT_TABLE()
+
+void wxSpinCtrlDbl::Init()
+{
+ m_min = 0;
+ m_max = 100;
+ m_value = 0;
+ m_default_value = 0;
+ m_increment = 1;
+ m_digits = wxSPINCTRLDBL_AUTODIGITS;
+ m_snap_ticks = false;
+ m_spinButton = NULL;
+ m_textCtrl = NULL;
+}
+
+bool wxSpinCtrlDbl::Create( wxWindow *parent, wxWindowID id,
+ const wxString& value,
+ const wxPoint& pos, const wxSize& size,
+ long style,
+ double min, double max,
+ double initial,
+ double increment, int digits,
+ const wxString& name)
+{
+ if (!wxControl::Create(parent, id, pos, size, style|wxNO_BORDER,
+ wxDefaultValidator, name))
+ return false;
+
+ wxControl::SetLabel(name);
+ wxControl::SetBackgroundColour(parent->GetBackgroundColour());
+ wxControl::SetForegroundColour(parent->GetForegroundColour());
+
+ int width = size.GetWidth(), height = size.GetHeight();
+
+ wxSize best_size( DoGetBestSize() );
+ if (width == -1) width = best_size.GetWidth();
+ if (height == -1) height = best_size.GetHeight();
+
+ // Create a validator for numbers, +-, and eE for exponential
+ wxTextValidator validator(wxFILTER_INCLUDE_CHAR_LIST);
+
+#if wxCHECK_VERSION(2, 5, 4)
+ wxArrayString list;
+
+ wxString valid_chars(wxT(" 0123456789+-.eE"));
+ size_t len = valid_chars.Length();
+ for (size_t i=0; i<len; i++)
+ list.Add(wxString(valid_chars.GetChar(i)));
+
+ validator.SetIncludes(list);
+#else
+ wxStringList list;
+
+ wxString valid_chars(wxT(" 0123456789+-.eE"));
+ size_t len = valid_chars.Length();
+ for (size_t i=0; i<len; i++)
+ list.Add(wxString(valid_chars.GetChar(i)));
+
+ validator.SetIncludeList(list);
+#endif // wxCHECK_VER(2, 5, 4)
+
+ m_spinButton = new wxSpinButton( this, id, wxPoint(0,0), wxSize(-1, height),
+ wxSP_ARROW_KEYS|wxSP_VERTICAL|wxSP_WRAP);
+ m_textCtrl = new wxSpinCtrlDblTextCtrl( this, id, value,
+ wxPoint(0,0),
+ wxSize(width-m_spinButton->GetSize().GetWidth(), height),
+ wxTE_NOHIDESEL|wxTE_PROCESS_ENTER, validator);
+
+ DoSetSize( pos.x, pos.y, width, height );
+
+ SetInitialBestSize(wxSize(width, height));
+
+ m_min = min;
+ m_max = max;
+ m_value = initial;
+ m_default_value = initial;
+ m_increment = increment;
+ SetDigits( digits );
+
+ // set the value here without generating an event
+ if (!value.IsEmpty())
+ m_textCtrl->SetValue(value);
+ else
+ m_textCtrl->SetValue(wxString::Format(m_textFormat.c_str(), initial));
+
+ return true;
+}
+
+wxSpinCtrlDbl::~wxSpinCtrlDbl()
+{
+ if (m_textCtrl) // null this since MSW sends KILL_FOCUS on deletion
+ {
+ m_textCtrl->m_parent = NULL;
+
+ wxSpinCtrlDblTextCtrl *text = m_textCtrl;
+ m_textCtrl = NULL;
+ delete text;
+ }
+
+ delete m_spinButton;
+ m_spinButton = NULL;
+}
+
+#define wxSPINCTRLDBL_SPIN_WIDTH 15
+#define wxSPINCTRLDBL_SPIN_HEIGHT 22
+
+void wxSpinCtrlDbl::DoSetSize(int x, int y, int width, int height, int sizeFlags)
+{
+ //wxPrintf(wxT("DoSetSize %d, %d %d %d %d %d\n"), GetId(), x, y, width, height, sizeFlags);
+
+ wxSize bestSize( DoGetBestSize() );
+ if (width < 0) width = bestSize.GetWidth();
+ if (height < 0) height = bestSize.GetHeight();
+
+ wxWindow::DoSetSize(x, y, width, height, sizeFlags);
+
+ int spinwidth = wxSPINCTRLDBL_SPIN_WIDTH;
+ int spinheight = wxSPINCTRLDBL_SPIN_HEIGHT;
+ if (m_spinButton)
+ m_spinButton->GetSize( &spinwidth, &spinheight );
+
+#ifdef __WIN95__ // humm... these used to be different
+ if (m_textCtrl) m_textCtrl->SetSize( 0, 0, width - spinwidth, height );
+ if (m_spinButton) m_spinButton->SetSize( width-spinwidth-2, 0, -1, height );
+ //m_textCtrl->SetSize( -3, -3, width - spinwidth, height ); // old wxWin < 2.3.2
+ //m_spinButton->SetSize( width-spinwidth-4, -3, -1, height-1 );
+#else
+ if (m_textCtrl) m_textCtrl->SetSize( 0, 0, width - spinwidth, height );
+ if (m_spinButton) m_spinButton->SetSize( width-spinwidth, 0, -1, height );
+#endif
+}
+
+static wxSize s_spinctrl_bestSize(-999,-999);
+
+wxSize wxSpinCtrlDbl::DoGetBestSize() const
+{
+ //wxPrintf(wxT("GetBestSize %d\n"), GetId());
+ if (s_spinctrl_bestSize.x == -999)
+ {
+ wxSpinCtrl spin((wxWindow*)this, wxID_ANY);
+ s_spinctrl_bestSize = spin.GetBestSize();
+ // oops something went wrong, set to reasonable value
+ if (s_spinctrl_bestSize.GetWidth() < 20)
+ s_spinctrl_bestSize.SetWidth(95);
+ if (s_spinctrl_bestSize.GetHeight() < 10)
+ s_spinctrl_bestSize.SetHeight(wxSPINCTRLDBL_SPIN_HEIGHT);
+ }
+
+ return s_spinctrl_bestSize;
+}
+
+void wxSpinCtrlDbl::DoSetToolTip( wxToolTip *tip )
+{
+ // forward tip to textctrl only since having the tip pop up on the buttons
+ // is distracting.
+ if (tip && m_textCtrl)
+ {
+ wxPrintf(wxT("TIP %s\n"), tip->GetTip().c_str());
+ m_textCtrl->SetToolTip(tip->GetTip());
+ }
+
+ wxControl::DoSetToolTip(tip);
+}
+
+void wxSpinCtrlDbl::DoSendEvent()
+{
+ wxCommandEvent event( wxEVT_COMMAND_SPINCTRL_UPDATED, GetId() );
+ event.SetEventObject( this );
+ event.SetInt( (int)(m_value+0.5) );
+ if (m_textCtrl) event.SetString( m_textCtrl->GetValue() );
+ GetEventHandler()->ProcessEvent( event );
+}
+
+void wxSpinCtrlDbl::OnSpinUp( wxSpinEvent &WXUNUSED(event) )
+{
+ if (m_textCtrl && m_textCtrl->IsModified() )
+ SyncSpinToText(false);
+
+ if ( InRange(m_value + m_increment) )
+ {
+ m_value += m_increment;
+ SetValue( m_value );
+ DoSendEvent();
+ }
+}
+
+void wxSpinCtrlDbl::OnSpinDown( wxSpinEvent &WXUNUSED(event) )
+{
+ if (m_textCtrl && m_textCtrl->IsModified() )
+ SyncSpinToText(false);
+
+ if ( InRange(m_value - m_increment) )
+ {
+ m_value -= m_increment;
+ SetValue( m_value );
+ DoSendEvent();
+ }
+}
+
+void wxSpinCtrlDbl::OnTextEnter( wxCommandEvent &event )
+{
+ SyncSpinToText(true);
+ event.Skip();
+}
+
+void wxSpinCtrlDbl::OnText( wxCommandEvent &event )
+{
+ //wxPrintf(wxT("Text '%s'\n"), event.GetString()); fflush(stdout);
+ event.Skip();
+}
+
+void wxSpinCtrlDbl::OnChar( wxKeyEvent &event )
+{
+ double modifier = 1.0;
+ if ( event.m_shiftDown ) modifier = 2.0;
+ if ( event.m_controlDown ) modifier *= 10.0;
+ if ( event.m_altDown ) modifier *= 100.0;
+
+ switch ( event.GetKeyCode() )
+ {
+ case WXK_UP :
+ {
+ if (m_textCtrl && m_textCtrl->IsModified()) SyncSpinToText(false);
+ SetValue( m_value + m_increment * modifier );
+ DoSendEvent();
+ break;
+ }
+ case WXK_DOWN :
+ {
+ if (m_textCtrl && m_textCtrl->IsModified()) SyncSpinToText(false);
+ SetValue( m_value - m_increment * modifier );
+ DoSendEvent();
+ break;
+ }
+ case WXK_PAGEUP : // pg-up
+ {
+ if (m_textCtrl && m_textCtrl->IsModified()) SyncSpinToText(false);
+ SetValue( m_value + m_increment * 10.0 * modifier );
+ DoSendEvent();
+ break;
+ }
+ case WXK_PAGEDOWN : // pg-down
+ {
+ if (m_textCtrl && m_textCtrl->IsModified()) SyncSpinToText(false);
+ SetValue( m_value - m_increment * 10.0 * modifier );
+ DoSendEvent();
+ break;
+ }
+ case WXK_SPACE :
+ {
+ SetValue(m_value);
+ event.Skip(false);
+ break;
+ }
+ case WXK_ESCAPE :
+ {
+ SetDefaultValue();
+ DoSendEvent();
+ break;
+ }
+ case WXK_TAB :
+ {
+ wxNavigationKeyEvent new_event;
+ new_event.SetEventObject( GetParent() );
+ new_event.SetDirection( !event.ShiftDown() );
+ // CTRL-TAB changes the (parent) window, i.e. switch notebook page
+ new_event.SetWindowChange( event.ControlDown() );
+ new_event.SetCurrentFocus( this );
+ GetParent()->GetEventHandler()->ProcessEvent( new_event );
+ break;
+ }
+ default : event.Skip(); break;
+ }
+}
+
+void wxSpinCtrlDbl::SetValue( double value )
+{
+ if (!m_textCtrl || !InRange(value))
+ return;
+
+ if ( m_snap_ticks && (m_increment != 0) )
+ {
+ double snap_value = (value - m_default_value) / m_increment;
+
+ if (wxFinite(snap_value))
+ {
+ if (snap_value - floor(snap_value) < ceil(snap_value) - snap_value)
+ value = m_default_value + floor(snap_value) * m_increment;
+ else
+ value = m_default_value + ceil(snap_value) * m_increment;
+ }
+ }
+
+ wxString str(wxString::Format(m_textFormat.c_str(), value));
+
+ if ((value != m_value) || (str != m_textCtrl->GetValue()))
+ {
+ m_textCtrl->SetValue( str );
+ m_textCtrl->DiscardEdits();
+ m_value = value;
+ str.ToDouble( &m_value ); // wysiwyg for textctrl
+ }
+}
+
+void wxSpinCtrlDbl::SetValue( const wxString& text, bool force )
+{
+ if (!m_textCtrl) return;
+
+ double value;
+ if ( text.ToDouble(&value) )
+ SetValue( value );
+ else if (force)
+ {
+ m_textCtrl->SetValue( text );
+ m_textCtrl->DiscardEdits();
+ }
+}
+
+void wxSpinCtrlDbl::SetRange( double min_val, double max_val )
+{
+ //wxCHECK_RET(max_val > min_val, wxT("invalid spinctrl range"));
+ m_min = min_val;
+ m_max = max_val;
+
+ if (HasRange())
+ {
+ if (m_value > m_max)
+ SetValue(m_max);
+ else if (m_value < m_min)
+ SetValue(m_min);
+ }
+}
+
+void wxSpinCtrlDbl::SetIncrement( double increment )
+{
+ m_increment = increment;
+ SetValue(m_value);
+}
+
+void wxSpinCtrlDbl::SetDigits( int digits, formatType fmt )
+{
+ wxCHECK_RET(digits >= -1, wxT("invalid spinctrl format"));
+
+ if ((digits == wxSPINCTRLDBL_AUTODIGITS) && (fmt != lg_fmt))
+ {
+ wxString wxstr;
+ int lastplace = -1, extra_digits = 0;
+ if (fmt == le_fmt)
+ {
+ wxstr.Printf(wxT("%le"), m_increment );
+ wxstr.LowerCase();
+ lastplace = wxstr.Find(wxT('e')) - 2;
+ long places;
+ if (wxstr.AfterFirst(wxT('e')).ToLong(&places))
+ extra_digits = int(labs(places));
+ }
+ else if (fmt == lf_fmt)
+ {
+ wxstr.Printf(wxT("%lf"), m_increment );
+ lastplace = wxstr.Len()-1;
+ }
+
+ int decimalplace = wxstr.Find(wxT('.'));
+
+ int i = 0;
+
+ for ( i=lastplace; i>decimalplace; i-- )
+ {
+ if ( wxstr.GetChar(i) != wxT('0') )
+ {
+ m_digits = extra_digits + i-decimalplace;
+ switch (fmt)
+ {
+ case le_fmt : m_textFormat.Printf(wxT("%%.%dle"), m_digits ); break;
+ case lf_fmt :
+ default : m_textFormat.Printf(wxT("%%.%dlg"), m_digits ); break;
+ }
+
+ SetValue(m_value);
+ return;
+ }
+ }
+
+ m_digits = 0; // no digits, I guess
+ }
+ else
+ m_digits = digits;
+
+ switch (fmt)
+ {
+ case le_fmt : m_textFormat.Printf(wxT("%%.%dle"), m_digits ); break;
+ case lg_fmt :
+ {
+ if (m_digits == -1)
+ m_textFormat.Printf(wxT("%%lg") );
+ else
+ m_textFormat.Printf(wxT("%%.%dlg"), m_digits );
+ break;
+ }
+ case lf_fmt :
+ default : m_textFormat.Printf(wxT("%%.%dlf"), m_digits ); break;
+ }
+
+ SetValue(m_value);
+}
+
+void wxSpinCtrlDbl::SetFormat( const wxString& format )
+{
+ wxString wxstr;
+ if ( wxstr.Printf(format.c_str(), 123456.123456) > 0 )
+ m_textFormat = format;
+
+ SetValue(m_value);
+}
+
+void wxSpinCtrlDbl::SetDefaultValue( double default_value )
+{
+ if ( InRange(default_value) )
+ {
+ m_default_value = default_value;
+ SetDefaultValue();
+ }
+}
+
+void wxSpinCtrlDbl::SetSnapToTicks(bool forceTicks)
+{
+ if (m_snap_ticks != forceTicks)
+ {
+ m_snap_ticks = forceTicks;
+ SetValue( m_value );
+ }
+}
+
+void wxSpinCtrlDbl::OnFocus( wxFocusEvent &event )
+{
+ if (m_textCtrl)
+ m_textCtrl->SetFocus(); // this is to pass TAB navigation
+
+ event.Skip();
+}
+
+void wxSpinCtrlDbl::OnKillFocus( wxFocusEvent &event )
+{
+ SyncSpinToText(true);
+ event.Skip();
+}
+
+void wxSpinCtrlDbl::SyncSpinToText(bool send_event, bool force_valid)
+{
+ if (!m_textCtrl)
+ return;
+
+ double txt_value;
+ if ( m_textCtrl->GetValue().ToDouble( &txt_value ) )
+ {
+ if ( force_valid || !HasRange() || InRange(txt_value) )
+ {
+ if (force_valid && HasRange())
+ {
+ if (txt_value > GetMax())
+ txt_value = GetMax();
+ else if (txt_value < GetMin())
+ txt_value = GetMin();
+ }
+
+ if (m_value != txt_value)
+ {
+ SetValue( txt_value );
+ if (send_event) DoSendEvent();
+ }
+ }
+ }
+ else if (force_valid)
+ {
+ // textctrl is out of sync, discard and reset
+ SetValue(GetValue());
+ }
+}
+
+bool wxSpinCtrlDbl::SetFont( const wxFont &font )
+{
+ if (!m_textCtrl) return false;
+ return m_textCtrl->SetFont( font );
+}
+wxFont wxSpinCtrlDbl::GetFont() const
+{
+ if (!m_textCtrl) return GetFont();
+ return m_textCtrl->GetFont();
+}
+
+bool wxSpinCtrlDbl::SetBackgroundColour(const wxColour& colour)
+{
+ if (!m_textCtrl) return wxControl::SetBackgroundColour(colour);
+ bool ret = false;
+ ret = m_textCtrl->SetBackgroundColour(colour);
+ m_textCtrl->Refresh();
+ return ret;
+}
+wxColour wxSpinCtrlDbl::GetBackgroundColour() const
+{
+ if (!m_textCtrl) return wxControl::GetBackgroundColour();
+ return m_textCtrl->GetBackgroundColour();
+}
+
+bool wxSpinCtrlDbl::SetForegroundColour(const wxColour& colour)
+{
+ if (!m_textCtrl) return wxControl::SetForegroundColour(colour);
+ bool ret = false;
+ ret = m_textCtrl->SetForegroundColour(colour);
+ m_textCtrl->Refresh();
+ return ret;
+}
+wxColour wxSpinCtrlDbl::GetForegroundColour() const
+{
+ if (!m_textCtrl) return wxControl::GetForegroundColour();
+ return m_textCtrl->GetForegroundColour();
+}
diff --git a/src/spinctld.h b/src/spinctld.h
new file mode 100644
index 0000000..c7d4db9
--- /dev/null
+++ b/src/spinctld.h
@@ -0,0 +1,206 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: spinctld.h
+// Purpose: A double valued spin control, compatible with wxSpinCtrl
+// Author: John Labenski
+// Created: 11/05/02
+// Copyright: John Labenski, 2002
+// License: wxWidgets
+/////////////////////////////////////////////////////////////////////////////
+
+/*
+wxSpinCtrlDbl is a double valued wxSpinCtrl using non native (wxWidgets) widgets
+
+It consists of a wxSpinButton and a wxTextCtrl on a wxControl and can be used
+as a drop in replacement for the wxSpinCtrl. It's been tested in GTK and MSW
+and should work with MAC, but you may need to fix the sizing perhaps. It
+will not work in Motif as there is no wxSpinButton in Motif.
+
+Differences to wxSpinCtrl:
+
+ It remembers the initial value as a default value, call SetDefaultValue,
+ or press <ESC> to return to it
+
+ Shift + Arrow = *2 increment value
+ Ctrl + Arrow = *10 increment value
+ Alt + Arrow = *100 increment value
+ combinations of Shift, Ctrl, Alt increment by the product of the factors
+
+ PgUp & PgDn = *10 increment * the product of the Shift, Ctrl, Alt factors
+
+ <SPACE> sets the control's value to the it's last valid state
+
+ SetDigits controls the format of the text, # decimal places
+ exponential uses the %.Xle format otherwise %.Xlf, where places = X
+ for arbitray formats subclass control and override SyncSpinToText()
+ for proper behavior when a user types in a value
+*/
+
+#ifndef __wxSPINCTRLDBL_H__
+#define __wxSPINCTRLDBL_H__
+
+#include <wx/spinbutt.h>
+#include <wx/spinctrl.h> // for EVT_SPINCTRL
+#include "thingdef.h"
+
+class wxTextCtrl;
+class wxSpinCtrlDblTextCtrl;
+
+enum
+{
+ wxSPINCTRLDBL_AUTODIGITS = -1 // try to autocalc the # of digits
+};
+
+class wxSpinCtrlDbl: public wxControl
+{
+public:
+ wxSpinCtrlDbl() : wxControl() { Init(); }
+
+ // Native constructor - note &parent, this is to avoid ambiguity
+ wxSpinCtrlDbl( wxWindow &parent, wxWindowID id,
+ const wxString &value = wxEmptyString,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxSize(95,-1),
+ long style = 0,
+ double min = 0.0, double max = 100.0,
+ double initial = 0.0,
+ double increment = 1.0, int digits = wxSPINCTRLDBL_AUTODIGITS,
+ const wxString& name = _T("wxSpinCtrlDbl") )
+ {
+ Init();
+ Create(&parent, id, value, pos, size, style,
+ min, max, initial, increment, digits, name);
+ }
+
+ // wxSpinCtrl compatibility, call SetIncrement(increment,digits) after
+ wxSpinCtrlDbl( wxWindow *parent, wxWindowID id = wxID_ANY,
+ const wxString &value = wxEmptyString,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxSize(95,-1),
+ long style = 0,
+ int min = 0, int max = 100,
+ int initial = 0,
+ const wxString& name = _T("wxSpinCtrlDbl") )
+ {
+ Init();
+ Create(parent, id, value, pos, size, style,
+ (double)min, (double)max, (double)initial, 1.0, -1, name);
+ }
+
+ bool Create( wxWindow *parent,
+ wxWindowID id = wxID_ANY,
+ const wxString &value = wxEmptyString,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxSize(100,-1),
+ long style = 0,
+ double min = 0.0, double max = 100.0,
+ double initial = 0.0,
+ double increment = 1.0, int digits = wxSPINCTRLDBL_AUTODIGITS,
+ const wxString& name = _T("wxSpinCtrlDbl") );
+
+ virtual ~wxSpinCtrlDbl();
+
+ // -----------------------------------------------------------------------
+ // Public (normal usage) functions
+
+ enum formatType
+ {
+ lf_fmt, // %lf
+ le_fmt, // %le
+ lg_fmt // %lg
+ };
+
+ virtual void SetValue( double value );
+ void SetValue( double value, double min, double max, double increment,
+ int digits = wxSPINCTRLDBL_AUTODIGITS, formatType fmt = lg_fmt )
+ { SetRange(min, max); SetIncrement(increment); SetDigits(digits, fmt); SetValue(value); }
+ // Set the value as text, if force then set text as is
+ virtual void SetValue( const wxString& text, bool force );
+ // Set the allowed range, if max_val < min_val then no range and all vals allowed.
+ void SetRange( double min_val, double max_val );
+ // Set the increment to use when the spin button or arrow keys pressed.
+ void SetIncrement( double increment );
+ void SetIncrement( double increment, int digits, formatType fmt = lg_fmt )
+ { SetIncrement(increment); SetDigits(digits, fmt); }
+ // Set the number of digits to show, use wxSPINCTRLDBL_AUTODIGITS
+ // or specify exact number to show i.e. %.[digits]lf
+ // The format type is used to create an appropriate format string.
+ void SetDigits( int digits = wxSPINCTRLDBL_AUTODIGITS, formatType fmt = lg_fmt );
+ // Set the format string to use, ie. format="%.2lf" for .01
+ void SetFormat( const wxString& format );
+ // Set the control the the default value.
+ virtual void SetDefaultValue() { SetValue( m_default_value ); }
+ // Set the value of the default value, default is the inital value.
+ void SetDefaultValue( double default_value );
+ // Force the value to always be divisible by the increment, initially off.
+ // This uses the default_value as the basis, you'll get strange results
+ // for very large differences between the current value and default value
+ // when the increment is very small.
+ void SetSnapToTicks(bool forceTicks);
+
+ double GetValue() const { return m_value; }
+ double GetMin() const { return m_min; }
+ double GetMax() const { return m_max; }
+ virtual bool HasRange() const { return m_max >= m_min; }
+ virtual bool InRange(double value) const { return !HasRange() || ((value >= m_min) && (value <= m_max)); }
+ double GetIncrement() const { return m_increment; }
+ int GetDigits() const { return m_digits; }
+ wxString GetFormat() const { return m_textFormat; }
+ double GetDefaultValue() const { return m_default_value; }
+ bool GetSnapToTicks() const { return m_snap_ticks; }
+
+ bool IsDefaultValue() const { return (m_value == m_default_value); }
+
+ virtual bool SetFont( const wxFont &font );
+ wxFont GetFont() const;
+
+ virtual bool SetBackgroundColour(const wxColour& colour);
+ wxColour GetBackgroundColour() const;
+
+ virtual bool SetForegroundColour(const wxColour& colour);
+ wxColour GetForegroundColour() const;
+
+ // for setting... stuff
+ wxTextCtrl *GetTextCtrl() { return (wxTextCtrl*)m_textCtrl; }
+
+protected:
+ void OnSpinUp( wxSpinEvent &event );
+ void OnSpinDown( wxSpinEvent &event );
+ void OnTextEnter( wxCommandEvent &event );
+ void OnText( wxCommandEvent &event );
+ // the textctrl is subclassed to get at pgup/dn and then sent here
+ void OnChar( wxKeyEvent &event );
+
+ virtual void SyncSpinToText(bool send_event = true, bool force_valid = true);
+
+ void DoSendEvent(); // send an event based on current state
+
+ virtual void DoSetSize(int x, int y, int width, int height,
+ int sizeFlags = wxSIZE_AUTO);
+
+ virtual wxSize DoGetBestSize() const;
+ virtual void DoSetToolTip( wxToolTip *tip );
+
+ void OnFocus( wxFocusEvent& event ); // pass focus to textctrl, for wxTAB_TRAVERSAL
+ void OnKillFocus( wxFocusEvent &event );
+
+ wxSpinButton *m_spinButton;
+ wxSpinCtrlDblTextCtrl *m_textCtrl;
+
+ double m_min; // min allowed value
+ double m_max; // max allowed value
+ double m_value; // current value
+ double m_default_value; // initial value, or SetDefaultValue(value)
+ double m_increment; // how much to to add per spin
+ int m_digits; // number of digits displayed after decimal point
+ bool m_snap_ticks; // value is divisible by increment
+ wxString m_textFormat; // used as wxString.Printf(m_textFormat.c_str(), m_value);
+
+private:
+ friend class wxSpinCtrlDblTextCtrl;
+
+ void Init();
+ DECLARE_DYNAMIC_CLASS(wxSpinCtrlDbl)
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // __wxSPINCTRLDBL_H__
diff --git a/src/spring.cpp b/src/spring.cpp
new file mode 100644
index 0000000..318c104
--- /dev/null
+++ b/src/spring.cpp
@@ -0,0 +1,579 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: Spring
+//
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/file.h>
+#include <wx/intl.h>
+#include <wx/arrstr.h>
+#include <wx/filename.h>
+#include <wx/stdpaths.h>
+#include <stdexcept>
+#include <vector>
+#include <algorithm>
+#include <fstream>
+#include <clocale>
+
+#include "spring.h"
+#include "springprocess.h"
+#include "ui.h"
+#include "mainwindow.h"
+#include "settings++/custom_dialogs.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "settings.h"
+#include "userlist.h"
+#include "battle.h"
+#include "singleplayerbattle.h"
+#include "offlinebattle.h"
+#include "user.h"
+#include "iunitsync.h"
+#include "nonportable.h"
+#include "tdfcontainer.h"
+#ifndef NO_TORRENT_SYSTEM
+#include "torrentwrapper.h"
+#endif
+#include "globalsmanager.h"
+
+BEGIN_EVENT_TABLE( Spring, wxEvtHandler )
+
+ EVT_COMMAND ( PROC_SPRING, wxEVT_SPRING_EXIT, Spring::OnTerminated )
+
+END_EVENT_TABLE();
+
+#define FIRST_UDP_SOURCEPORT 8300
+
+Spring& spring()
+{
+ static GlobalObjectHolder<Spring> m_spring;
+ return m_spring;
+}
+
+Spring::Spring() :
+ m_process(0),
+ m_wx_process(0),
+ m_running(false)
+{ }
+
+
+Spring::~Spring()
+{
+ if ( m_process != 0 )
+ delete m_process;
+}
+
+
+bool Spring::IsRunning() const
+{
+ return m_process != 0;
+}
+
+bool Spring::RunReplay ( const wxString& filename )
+{
+ wxLogMessage( _T("launching spring with replay: ") + filename );
+
+ return LaunchSpring( _T("\"") + filename + _T("\"") );
+}
+
+bool Spring::Run( Battle& battle )
+{
+
+ wxString path = sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T("script.txt");
+
+ try
+ {
+
+ if ( !wxFile::Access( path , wxFile::write ) )
+ {
+ wxLogError( _T("Access denied to script.txt.") );
+ }
+
+ wxFile f( path, wxFile::write );
+ battle.DisableHostStatusInProxyMode( true );
+ f.Write( WriteScriptTxt(battle) );
+ battle.DisableHostStatusInProxyMode( false );
+ f.Close();
+
+ } catch (...)
+ {
+ wxLogError( _T("Couldn't write script.txt") );
+ return false;
+ }
+
+ #ifndef NO_TORRENT_SYSTEM
+ wxString CommandForAutomaticTeamSpeak = _T("SCRIPT|") + battle.GetFounder().GetNick() + _T("|");
+ for ( UserList::user_map_t::size_type i = 0; i < battle.GetNumUsers(); i++ )
+ {
+ CommandForAutomaticTeamSpeak << TowxString<unsigned int>( battle.GetUser(i).BattleStatus().ally) << _T("|") << battle.GetUser(i).GetNick() << _T("|");
+ }
+ torrent().SendMessageToCoordinator(CommandForAutomaticTeamSpeak);
+ #endif
+
+ wxString cmd;
+ if ( battle.GetAutoHost().GetEnabled() )
+ {
+ // -m, --minimise Start minimised
+ // -q [T], --quit=[T] Quit immediately on game over or after T seconds
+ #ifndef __WXMSW__
+ cmd = _T("--minimise");
+ #else
+ cmd = _T("/minimise");
+ #endif
+ }
+ cmd += _T(" \"") + path + _T("\"");
+
+ return LaunchSpring( cmd );
+}
+
+
+bool Spring::Run( SinglePlayerBattle& battle )
+{
+
+ wxString path = sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T("script.txt");
+
+ try
+ {
+
+ if ( !wxFile::Access( path, wxFile::write ) )
+ {
+ wxLogError( _T("Access denied to script.txt.") );
+ }
+
+ wxFile f( path, wxFile::write );
+ f.Write( WriteScriptTxt(battle) );
+ f.Close();
+
+ } catch (...)
+ {
+ wxLogError( _T("Couldn't write script.txt") );
+ return false;
+ }
+
+ return LaunchSpring( _T("\"") + path + _T("\"") );
+}
+
+bool Spring::Run( OfflineBattle& battle )
+{
+
+ wxString path = battle.GetPlayBackFilePath();
+
+ return LaunchSpring( _T("\"") + path + _T("\"") );
+}
+
+
+bool Spring::LaunchSpring( const wxString& params )
+{
+ if ( m_running )
+ {
+ wxLogError( _T("Spring already running!") );
+ return false;
+ }
+ if ( !wxFile::Exists( sett().GetCurrentUsedSpringBinary() ) ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _T("The spring executable was not found at the set location, please re-check."), _T("Executable not found") );
+ ui().mw().ShowConfigure( MainWindow::OPT_PAGE_SPRING );
+ return false;
+ }
+
+ wxString configfileflags = sett().GetCurrentUsedSpringConfigFilePath();
+ if ( !configfileflags.IsEmpty() )
+ {
+
+ configfileflags = _T("--config=\"") + configfileflags + _T("\" ");
+ #ifdef __WXMSW__
+ if ( usync().GetSpringVersion().Contains(_T("0.78.") ) ) configfileflags = _T("");
+ #endif
+ }
+ wxChar sep = wxFileName::GetPathSeparator();
+ wxString cmd = _T("\"") + sett().GetCurrentUsedSpringBinary();
+ #ifdef __WXMAC__
+ if ( sett().GetCurrentUsedSpringBinary().AfterLast(_T('.')) == _T("app") ) cmd += sep + wxString(_T("Contents")) + sep + wxString(_T("MacOS")) + sep + wxString(_T("spring")); // append app bundle inner path
+ #endif
+ cmd += _T("\" ") + configfileflags + params;
+ wxLogMessage( _T("spring call params: %s"), cmd.c_str() );
+ wxSetWorkingDirectory( sett().GetCurrentUsedDataDir() );
+ if ( sett().UseOldSpringLaunchMethod() )
+ {
+ if ( m_wx_process == 0 ) m_wx_process = new wxSpringProcess( *this );
+ if ( wxExecute( cmd , wxEXEC_ASYNC, m_wx_process ) == 0 ) return false;
+ }
+ else
+ {
+ if ( m_process == 0 ) m_process = new SpringProcess( *this );
+ m_process->Create();
+ m_process->SetCommand( cmd );
+ m_process->Run();
+ }
+
+ m_running = true;
+ return true;
+}
+
+
+
+void Spring::OnTerminated( wxCommandEvent& event )
+{
+ wxLogDebugFunc( _T("") );
+ m_running = false;
+ m_process = 0; // NOTE I'm not sure if this should be deleted or not, according to wx docs it shouldn't.
+ m_wx_process = 0;
+ ui().OnSpringTerminated( event.GetExtraLong() );
+}
+
+
+wxString Spring::WriteScriptTxt( IBattle& battle ) const
+{
+ wxLogMessage(_T("0 WriteScriptTxt called "));
+
+ wxString ret;
+
+ TDFWriter tdf(ret);
+
+ // Start generating the script.
+ tdf.EnterSection( _T("GAME") );
+
+ if ( battle.IsFounderMe() )
+ {
+ tdf.Append( _T("HostIP"), _T("localhost") );
+ if ( battle.GetNatType() == NAT_Hole_punching ) tdf.Append( _T("HostPort"), battle.GetMyInternalUdpSourcePort() );
+ else tdf.Append(_T("HostPort"), battle.GetHostPort() );
+
+ }
+ else
+ {
+ tdf.Append( _T("HostIP"), battle.GetHostIp() );
+ tdf.Append( _T("HostPort"), battle.GetHostPort() );
+ if ( battle.GetNatType() == NAT_Hole_punching )
+ {
+ tdf.Append( _T("SourcePort"), battle.GetMyInternalUdpSourcePort() );
+ }
+ else if ( sett().GetClientPort() != 0){ /// this allows to play with broken router by setting SourcePort to some forwarded port.
+ tdf.Append( _T("SourcePort"), sett().GetClientPort() );
+ }
+ }
+ tdf.Append( _T("IsHost"), battle.IsFounderMe() );
+
+ tdf.Append(_T("MyPlayerName"), battle.GetMe().GetNick() );
+
+ if ( !battle.IsFounderMe() )
+ {
+ tdf.LeaveSection();
+ return ret;
+ }
+
+ /**********************************************************************************
+ Host-only section
+ **********************************************************************************/
+
+ tdf.AppendLineBreak();
+
+ tdf.Append(_T("ModHash"), battle.LoadMod().hash );
+ tdf.Append(_T("MapHash"), battle.LoadMap().hash );
+
+ tdf.Append( _T("Mapname"), battle.GetHostMapName() );
+ tdf.Append( _T("GameType"), battle.GetHostModName() );
+
+ tdf.AppendLineBreak();
+
+ switch ( battle.GetBattleType() )
+ {
+ case BT_Played: break;
+ case BT_Replay:
+ {
+ wxString path = battle.GetPlayBackFilePath();
+ if ( path.Contains(_T("/")) ) path.BeforeLast(_T('/'));
+ tdf.Append( _T("DemoFile"), path );
+ tdf.AppendLineBreak();
+ break;
+ }
+ case BT_Savegame:
+ {
+ wxString path = battle.GetPlayBackFilePath();
+ if ( path.Contains(_T("/")) ) path.BeforeLast(_T('/'));
+ tdf.Append( _T("Savefile"), path );
+ tdf.AppendLineBreak();
+ break;
+ }
+ default:
+ wxLogDebugFunc( _T("") ); break;
+ }
+
+ long startpostype;
+ battle.CustomBattleOptions().getSingleValue( _T("startpostype"), OptionsWrapper::EngineOption ).ToLong( &startpostype );
+
+ std::vector<StartPos> remap_positions;
+ if ( battle.IsProxy() && ( startpostype != IBattle::ST_Pick ) && ( startpostype != IBattle::ST_Choose ) )
+ {
+ std::set<int> parsedteams;
+ unsigned int NumUsers = battle.GetNumUsers();
+ unsigned int NumTeams = 0;
+ for ( unsigned int i = 0; i < NumUsers; i++ )
+ {
+ User& usr = battle.GetUser( i );
+ UserBattleStatus& status = usr.BattleStatus();
+ if ( status.spectator ) continue;
+ if ( parsedteams.find( status.team ) != parsedteams.end() ) continue; // skip duplicates
+ parsedteams.insert( status.team );
+ NumTeams++;
+ }
+
+ MapInfo infos = battle.LoadMap().info;
+ unsigned int maxpositions = sizeof ( infos.positions ) / sizeof( StartPos );
+ unsigned int copysize = std::min( maxpositions, NumTeams );
+ remap_positions = std::vector<StartPos> ( infos.positions, infos.positions + copysize ); // only add the first x positions
+
+ if ( startpostype == IBattle::ST_Random )
+ {
+ random_shuffle( remap_positions.begin(), remap_positions.end() ); // shuffle the positions
+ }
+
+ }
+ if ( battle.IsProxy() )
+ {
+ if ( ( startpostype == IBattle::ST_Random ) || ( startpostype == IBattle::ST_Fixed ) )
+ {
+ tdf.Append( _T("startpostype"), IBattle::ST_Pick );
+ }
+ else tdf.Append( _T("startpostype"), startpostype );
+ }
+ else tdf.Append( _T("startpostype"), startpostype );
+
+ tdf.EnterSection( _T("mapoptions") );
+ OptionsWrapper::wxStringTripleVec optlistMap = battle.CustomBattleOptions().getOptions( OptionsWrapper::MapOption );
+ for (OptionsWrapper::wxStringTripleVec::const_iterator it = optlistMap.begin(); it != optlistMap.end(); ++it)
+ {
+ tdf.Append(it->first,it->second.second);
+ }
+ tdf.LeaveSection();
+
+
+ tdf.EnterSection(_T("modoptions"));
+ OptionsWrapper::wxStringTripleVec optlistMod = battle.CustomBattleOptions().getOptions( OptionsWrapper::ModOption );
+ for (OptionsWrapper::wxStringTripleVec::const_iterator it = optlistMod.begin(); it != optlistMod.end(); ++it)
+ {
+ tdf.Append(it->first,it->second.second);
+ }
+ tdf.LeaveSection();
+
+ std::map<wxString,int> units = battle.RestrictedUnits();
+ tdf.Append( _T("NumRestrictions"), units.size());
+ tdf.EnterSection( _T("RESTRICT") );
+ int restrictcount = 0;
+ for ( std::map<wxString, int>::iterator itor = units.begin(); itor != units.end(); itor++ )
+ {
+ tdf.Append(_T("Unit") + TowxString( restrictcount ), itor->first );
+ tdf.Append(_T("Limit") + TowxString( restrictcount ), itor->second );
+ restrictcount++;
+ }
+ tdf.LeaveSection();
+
+
+ tdf.AppendLineBreak();
+
+ if ( battle.IsProxy() )
+ {
+ tdf.Append( _T("NumPlayers"), battle.GetNumPlayers() -1 );
+ tdf.Append( _T("NumUsers"), battle.GetNumUsers() -1 );
+ }
+ else
+ {
+ tdf.Append( _T("NumPlayers"), battle.GetNumPlayers() );
+ tdf.Append( _T("NumUsers"), battle.GetNumUsers() );
+ }
+
+ tdf.AppendLineBreak();
+
+ unsigned int NumUsers = battle.GetNumUsers();
+
+ typedef std::map<int, int> ProgressiveTeamsVec;
+ typedef ProgressiveTeamsVec::iterator ProgressiveTeamsVecIter;
+ ProgressiveTeamsVec teams_to_sorted_teams; // original team -> progressive team
+ int free_team = 0;
+ std::map<User*, int> player_to_number; // player -> ordernumber
+
+ for ( unsigned int i = 0; i < NumUsers; i++ )
+ {
+ User& user = battle.GetUser( i );
+ UserBattleStatus& status = user.BattleStatus();
+ if ( !status.spectator )
+ {
+ ProgressiveTeamsVecIter itor = teams_to_sorted_teams.find ( status.team );
+ if ( itor == teams_to_sorted_teams.end() )
+ {
+ teams_to_sorted_teams[status.team] = free_team;
+ free_team++;
+ }
+ }
+ if ( battle.IsProxy() && ( user.GetNick() == battle.GetFounder().GetNick() ) ) continue;
+ if ( status.IsBot() ) continue;
+ tdf.EnterSection( _T("PLAYER") + TowxString( i ) );
+ tdf.Append( _T("Name"), user.GetNick() );
+ tdf.Append( _T("CountryCode"), user.GetCountry().Lower());
+ tdf.Append( _T("Spectator"), status.spectator );
+ tdf.Append( _T("Rank"), (int)user.GetRank() );
+ tdf.Append( _T("IsFromDemo"), int(status.isfromdemo) );
+ if ( !status.spectator )
+ {
+ tdf.Append( _T("Team"), teams_to_sorted_teams[status.team] );
+ }
+ else
+ {
+ int speccteam = 0;
+ ProgressiveTeamsVecIter itor = teams_to_sorted_teams.find ( status.team );
+ if ( itor == teams_to_sorted_teams.end() )
+ {
+ srand ( time(NULL) );
+ if ( teams_to_sorted_teams.size() != 0 ) speccteam = rand() % teams_to_sorted_teams.size();
+ }
+ else speccteam = itor->second;
+ tdf.Append( _T("Team"), speccteam );
+ }
+ tdf.LeaveSection();
+ player_to_number[&user] = i;
+ }
+ if ( usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) )
+ {
+ for ( unsigned int i = 0; i < NumUsers; i++ )
+ {
+ User& user = battle.GetUser( i );
+ UserBattleStatus& status = user.BattleStatus();
+ if ( !status.IsBot() ) continue;
+ tdf.EnterSection( _T("AI") + TowxString( i ) );
+ tdf.Append( _T("Name"), user.GetNick() ); // AI's nick;
+ tdf.Append( _T("ShortName"), status.aishortname ); // AI libtype
+ tdf.Append( _T("Version"), status.aiversion ); // AI libtype version
+ tdf.Append( _T("Team"), teams_to_sorted_teams[status.team] );
+ tdf.Append( _T("IsFromDemo"), int(status.isfromdemo) );
+ tdf.Append( _T("Host"), player_to_number[&battle.GetUser( status.owner )] );
+ tdf.EnterSection( _T("Options") );
+ int optionmapindex = battle.CustomBattleOptions().GetAIOptionIndex( user.GetNick() );
+ if ( optionmapindex > 0 )
+ {
+ OptionsWrapper::wxStringTripleVec optlistMod = battle.CustomBattleOptions().getOptions( (OptionsWrapper::GameOption)optionmapindex );
+ for (OptionsWrapper::wxStringTripleVec::const_iterator it = optlistMod.begin(); it != optlistMod.end(); ++it)
+ {
+ tdf.Append(it->first,it->second.second);
+ }
+ }
+ tdf.LeaveSection();
+ tdf.LeaveSection();
+ player_to_number[&user] = i;
+ }
+ }
+
+ tdf.AppendLineBreak();
+
+ std::set<int> parsedteams;
+ wxArrayString sides = usync().GetSides( battle.GetHostModName() );
+ for ( unsigned int i = 0; i < NumUsers; i++ )
+ {
+ User& usr = battle.GetUser( i );
+ UserBattleStatus& status = usr.BattleStatus();
+ if ( status.spectator ) continue;
+ if ( parsedteams.find( status.team ) != parsedteams.end() ) continue; // skip duplicates
+ parsedteams.insert( status.team );
+
+ tdf.EnterSection( _T("TEAM") + TowxString( teams_to_sorted_teams[status.team] ) );
+ if ( !usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) && status.IsBot() )
+ {
+ tdf.Append( _T("AIDLL"), status.aishortname );
+ tdf.Append( _T("TeamLeader"), player_to_number[&battle.GetUser( status.owner )] ); // bot owner is the team leader
+ }
+ else
+ {
+ if ( status.IsBot() )
+ {
+ tdf.Append( _T("TeamLeader"), player_to_number[&battle.GetUser( status.owner )] );
+ }
+ else
+ {
+ tdf.Append( _T("TeamLeader"), player_to_number[&usr] );
+ }
+ }
+ if ( battle.IsProxy() )
+ {
+ if ( startpostype == IBattle::ST_Pick )
+ {
+ tdf.Append(_T("StartPosX"), status.pos.x );
+ tdf.Append(_T("StartPosZ"), status.pos.y );
+ }
+ else if ( ( startpostype == IBattle::ST_Fixed ) || ( startpostype == IBattle::ST_Random ) )
+ {
+ int teamnumber = teams_to_sorted_teams[status.team];
+ if ( teamnumber < remap_positions.size() ) // don't overflow
+ {
+ StartPos position = remap_positions[teamnumber];
+ tdf.Append(_T("StartPosX"), position.x );
+ tdf.Append(_T("StartPosZ"), position.y );
+ }
+ }
+ }
+ else
+ {
+ if ( startpostype == IBattle::ST_Pick )
+ {
+ tdf.Append(_T("StartPosX"), status.pos.x );
+ tdf.Append(_T("StartPosZ"), status.pos.y );
+ }
+ }
+
+ tdf.Append( _T("AllyTeam"),status.ally );
+
+ wxString colourstring =
+ TowxString( status.colour.Red()/255.0 ) + _T(' ') +
+ TowxString( status.colour.Green()/255.0 ) + _T(' ') +
+ TowxString( status.colour.Blue()/255.0 );
+ tdf.Append( _T("RGBColor"), colourstring);
+
+ unsigned int side = status.side;
+ if ( side < sides.GetCount() ) tdf.Append( _T("Side"), sides[side] );
+ tdf.Append( _T("Handicap"), status.handicap );
+ tdf.LeaveSection();
+ }
+
+ tdf.AppendLineBreak();
+
+
+ int maxiter = std::max( NumUsers, battle.GetLastRectIdx() + 1 );
+ std::set<int> parsedallys;
+ for ( unsigned int i = 0; i < maxiter; i++ )
+ {
+
+ User& usr = battle.GetUser( i );
+ UserBattleStatus& status = usr.BattleStatus();
+ BattleStartRect sr = battle.GetStartRect( i );
+ if ( status.spectator && !sr.IsOk() ) continue;
+ int ally = status.ally;
+ if ( status.spectator ) ally = i;
+ if ( parsedallys.find( ally ) != parsedallys.end() ) continue; // skip duplicates
+ sr = battle.GetStartRect( ally );
+ parsedallys.insert( ally );
+
+ tdf.EnterSection( _T("ALLYTEAM") + TowxString( ally ) );
+ tdf.Append( _T("NumAllies"), 0 );
+ if ( sr.IsOk() )
+ {
+ const char* old_locale = std::setlocale(LC_NUMERIC, "C");
+
+ tdf.Append( _T("StartRectLeft"), wxString::Format( _T("%.3f"), sr.left / 200.0 ) );
+ tdf.Append( _T("StartRectTop"), wxString::Format( _T("%.3f"), sr.top / 200.0 ) );
+ tdf.Append( _T("StartRectRight"), wxString::Format( _T("%.3f"), sr.right / 200.0 ) );
+ tdf.Append( _T("StartRectBottom"), wxString::Format( _T("%.3f"), sr.bottom / 200.0 ) );
+
+ std::setlocale(LC_NUMERIC, old_locale);
+ }
+ tdf.LeaveSection();
+ }
+
+ tdf.LeaveSection();
+
+ return ret;
+
+}
+
diff --git a/src/spring.h b/src/spring.h
new file mode 100644
index 0000000..3e682cf
--- /dev/null
+++ b/src/spring.h
@@ -0,0 +1,66 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SPRING_H
+#define SPRINGLOBBY_HEADERGUARD_SPRING_H
+
+#include <wx/event.h>
+
+class wxCommandEvent;
+class IBattle;
+class SinglePlayerBattle;
+class OfflineBattle;
+class Battle;
+class SpringProcess;
+class wxSpringProcess;
+class wxString;
+
+
+class Spring: public wxEvtHandler
+{
+ public:
+ Spring();
+ ~Spring();
+
+ bool IsRunning() const;
+ bool Run( Battle& battle );
+ bool Run( SinglePlayerBattle& battle );
+ bool Run( OfflineBattle& battle );
+
+ //! executes spring with replay as parameter
+ /*!
+ * \param filename the full path for the replayfile
+ */
+ bool RunReplay ( const wxString& filename );
+
+ wxString WriteScriptTxt( IBattle& battle ) const;
+ void OnTerminated( wxCommandEvent& event );
+
+ protected:
+ bool LaunchSpring( const wxString& params );
+
+ SpringProcess* m_process;
+ wxSpringProcess* m_wx_process;
+ bool m_running;
+
+ DECLARE_EVENT_TABLE()
+};
+
+Spring& spring();
+
+#endif // SPRINGLOBBY_HEADERGUARD_SPRING_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/springlobby.desktop b/src/springlobby.desktop
new file mode 100644
index 0000000..13834a5
--- /dev/null
+++ b/src/springlobby.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=SpringLobby
+Comment=Play real-time strategy games using the Spring engine
+Exec=springlobby
+Icon=springlobby.svg
+Terminal=false
+Type=Application
+Categories=Application;Game;StrategyGame;
+X-SuSE-translate=false
diff --git a/src/springlobby.rc b/src/springlobby.rc
new file mode 100644
index 0000000..e69aab2
--- /dev/null
+++ b/src/springlobby.rc
@@ -0,0 +1,6 @@
+#include <wx/msw/wx.rc>
+springlobby ICON "images/SpringLobby.ico"
+
+#ifndef _RC_MSVC //don't use this on visual studio - it enables all the UAC rights and XP style management on its own.
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "springlobby.exe.manifest"
+#endif
diff --git a/src/springlobbyapp.cpp b/src/springlobbyapp.cpp
new file mode 100644
index 0000000..d311987
--- /dev/null
+++ b/src/springlobbyapp.cpp
@@ -0,0 +1,461 @@
+/* Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: SpringLobbyApp
+//
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/intl.h>
+#include <wx/msgdlg.h>
+#include <wx/timer.h>
+#include <wx/stdpaths.h>
+#include <wx/filefn.h>
+#include <wx/image.h>
+#include <wx/cmdline.h>
+#include <wx/choicdlg.h>
+#include <wx/filename.h>
+#include <wx/dirdlg.h>
+#include <wx/tooltip.h>
+#include <wx/file.h>
+#include <wx/wfstream.h>
+#include <wx/fs_zip.h> //filesystem zip handler
+#include <wx/socket.h>
+#ifdef __WXMSW__
+ #include <wx/msw/registry.h>
+#endif
+#include <wx/utils.h>
+#include <wx/wfstream.h>
+
+#include "useractions.h"
+#include "springlobbyapp.h"
+#include "mainwindow.h"
+#include "settings.h"
+#include "crashreport.h"
+#include "utils/controls.h"
+#include "utils/platform.h"
+#include "ui.h"
+#include "iunitsync.h"
+#include "channel/channel.h"
+#include "settings++/custom_dialogs.h"
+#include "settings++/se_utils.h"
+#ifndef NO_TORRENT_SYSTEM
+#include "torrentwrapper.h"
+#endif
+#include "updater/updater.h"
+#include "globalsmanager.h"
+#include "Helper/wxTranslationHelper.h"
+#include "Helper/tasclientimport.h"
+#include "playback/playbacktraits.h"
+#include "playback/playbacktab.h"
+#include "updater/versionchecker.h"
+
+const unsigned int TIMER_ID = 101;
+const unsigned int TIMER_INTERVAL = 100;
+
+
+#if 0
+/// testing TDF parser
+#include "tdfcontainer.h"
+#include <iostream>
+#include <fstream>
+void TestTDFParser(){
+ PDataList parsetree(new DataList);
+ Tokenizer tokenizer;
+ std::ifstream f("/home/dmytry/.spring/script.txt");
+ tokenizer.EnterStream(f);
+ parsetree->Load(tokenizer);
+ wxString result;
+ TDFWriter writer(result);
+ parsetree->Save(writer);
+ wxLogMessage(_T("Testing tdf parser: result %s "), result.c_str());
+}
+#endif
+
+IMPLEMENT_APP(SpringLobbyApp)
+
+BEGIN_EVENT_TABLE(SpringLobbyApp, wxApp)
+
+ EVT_TIMER(TIMER_ID, SpringLobbyApp::OnTimer)
+
+
+END_EVENT_TABLE()
+
+SpringLobbyApp::SpringLobbyApp()
+ : m_timer ( new wxTimer(this, TIMER_ID) ),
+ quit_called( false ),
+ m_translationhelper( NULL ),
+ m_log_verbosity( 3 ),
+ m_log_console( true ),
+ m_log_window_show( false ),
+ m_crash_handle_disable( false ),
+ m_updateing_only( false )
+{
+ SetAppName( _T("springlobby") );
+}
+
+SpringLobbyApp::~SpringLobbyApp()
+{
+ delete m_timer;
+}
+
+
+//! @brief Initializes the application.
+//!
+//! It will open the main window and connect default to server or open the connect window.
+bool SpringLobbyApp::OnInit()
+{
+ //this triggers the Cli Parser amongst other stuff
+ if (!wxApp::OnInit())
+ return false;
+
+ //initialize all loggers, we'll use the returned pointer to set correct parent window later
+ wxLogChain* logchain = 0;
+ wxLogWindow *loggerwin = InitializeLoggingTargets( 0, m_log_console, m_log_window_show, !m_crash_handle_disable, m_log_verbosity, logchain );
+
+#if wxUSE_ON_FATAL_EXCEPTION && !defined(__WXMAC__)
+ if (!m_crash_handle_disable) wxHandleFatalExceptions( true );
+#endif
+
+ //this needs to called _before_ mainwindow instance is created
+ wxInitAllImageHandlers();
+ //TODO needed?
+ wxImage::AddHandler(new wxPNGHandler);
+ wxFileSystem::AddHandler(new wxZipFSHandler);
+ wxSocketBase::Initialize();
+
+
+#ifdef __WXMSW__
+ wxString path = wxPathOnly( wxStandardPaths::Get().GetExecutablePath() ) + wxFileName::GetPathSeparator() + _T("locale");
+#else
+ #if defined(LOCALEDIR)
+ wxString path ( _T(LOCALEDIR) );
+ #else
+ // use a dummy name here, we're only interested in the base path
+ wxString path = wxStandardPaths::Get().GetLocalizedResourcesDir(_T("noneWH"),wxStandardPaths::ResourceCat_Messages);
+ path = path.Left( path.First(_T("noneWH") ) );
+ #endif
+#endif
+ m_translationhelper = new wxTranslationHelper( *( (wxApp*)this ), path );
+ m_translationhelper->Load();
+
+ if ( !wxDirExists( wxStandardPaths::Get().GetUserDataDir() ) )
+ wxMkdir( wxStandardPaths::Get().GetUserDataDir() );
+
+ sett().RefreshSpringVersionList();
+ usync().ReloadUnitSyncLib(); // first time load of unitsync
+
+ //everything below should not be executing when updating, so we can ensure no GUI window is created, torrent system isn't started, etc.
+ // NOTE: this assumes no one will try to update at firstRun
+ if ( m_updateing_only )
+ return true;
+
+ CacheAndSettingsSetup();
+ ui().ShowMainWindow();
+ SetTopWindow( &ui().mw() );
+
+ if ( sett().IsFirstRun() )
+ {
+#ifdef __WXMSW__
+ sett().SetOldSpringLaunchMethod( true );
+#endif
+
+ wxLogMessage( _T("first time startup"));
+ wxMessageBox(_("Hi ") + wxGetUserName() + _(",\nIt looks like this is your first time using SpringLobby. I have guessed a configuration that I think will work for you but you should review it, especially the Spring configuration. \n\nWhen you are done you can go to the File menu, connect to a server, and enjoy a nice game of Spring :)"), _("Welcome"),
+ wxOK | wxICON_INFORMATION, &ui().mw() );
+
+
+ customMessageBoxNoModal(SL_MAIN_ICON, _("By default SpringLobby reports some usage statistics.\nYou can disable that on options tab --> General."),_("Notice"),wxOK );
+
+
+ // copy uikeys.txt
+ wxPathList pl;
+ pl.AddEnvList( _T("%ProgramFiles%") );
+ pl.AddEnvList( _T("XDG_DATA_DIRS") );
+ pl = sett().GetAdditionalSearchPaths( pl );
+ wxString uikeyslocation = pl.FindValidPath( _T("uikeys.txt") );
+ if ( !uikeyslocation.IsEmpty() )
+ {
+ wxCopyFile( uikeyslocation, sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T("uikeys.txt"), false );
+ }
+
+ #ifdef __WXMSW__
+ if ( TASClientPresent() &&
+ customMessageBox(SL_MAIN_ICON, _("Should I try to import (some) TASClient settings?\n" ),_("Import settings?"), wxYES_NO ) == wxYES )
+ {
+ ImportTASClientSettings();
+ }
+ #endif
+
+ ui().mw().ShowConfigure();
+ }
+ else
+ {
+ ui().mw().ShowSingleplayer();
+ }
+
+#ifndef NO_TORRENT_SYSTEM
+ if( sett().GetTorrentSystemAutoStartMode() == 1 ) torrent().ConnectToP2PSystem();
+#endif
+
+ //starts the replay loading process in a thread
+ ui().mw().GetReplayTab().ReloadList();
+ ui().mw().GetSavegameTab().ReloadList();
+ wxLogMessage( _T("Replaytab updated") );
+
+ m_timer->Start( TIMER_INTERVAL );
+
+ ui().mw().SetLogWin( loggerwin, logchain );
+
+ return true;
+}
+
+
+//! @brief Finalizes the application
+int SpringLobbyApp::OnExit()
+{
+ if ( quit_called )
+ return 0;
+
+ quit_called = true;
+ wxLogDebugFunc( _T("") );
+
+ if(m_translationhelper)
+ {
+ wxDELETE(m_translationhelper);
+ }
+
+
+ m_timer->Stop();
+
+ sett().SaveSettings(); // to make sure that cache path gets saved before destroying unitsync
+
+ DestroyGlobals();
+
+ return 0;
+}
+
+//! @brief is called when the app crashes
+void SpringLobbyApp::OnFatalException()
+{
+#if wxUSE_DEBUGREPORT && defined(ENABLE_DEBUG_REPORT)
+ crashreport().GenerateReport(wxDebugReport::Context_Exception);
+#else
+ wxMessageBox( _("The application has generated a fatal error and will be terminated\nGenerating a bug report is not possible\n\nplease get a wxWidgets library that supports wxUSE_DEBUGREPORT"),_("Critical error"), wxICON_ERROR | wxOK );
+#endif
+}
+
+
+//! @brief Is called every 1/10 seconds to update statuses
+void SpringLobbyApp::OnTimer( wxTimerEvent& event )
+{
+ ui().OnUpdate( event.GetInterval() );
+}
+
+bool SpringLobbyApp::SelectLanguage()
+{
+ wxArrayString names;
+ wxArrayLong identifiers;
+ int current_selection_index;
+ m_translationhelper->GetInstalledLanguages( names, identifiers, current_selection_index );
+ bool ret = m_translationhelper->AskUserForLanguage( names, identifiers, current_selection_index );
+ if ( ret ) m_translationhelper->Save();
+ return ret;
+}
+
+void SpringLobbyApp::OnInitCmdLine(wxCmdLineParser& parser)
+{
+ wxCmdLineEntryDesc cmdLineDesc[] =
+ {
+ { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _("show this help message"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
+ { wxCMD_LINE_SWITCH, _T("nc"), _T("no-crash-handler"), _("don't use the crash handler (useful for debugging)"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+#if wxUSE_STD_IOSTREAM
+ { wxCMD_LINE_SWITCH, _T("cl"), _T("console-logging"), _("shows application log to the console(if available)"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+#endif
+ { wxCMD_LINE_SWITCH, _T("gl"), _T("gui-logging"), _("enables application log window"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+#ifdef __WXMSW__
+ { wxCMD_LINE_SWITCH, _T("u"), _T("update"), _("only run update, quit immediately afterwards"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+#endif
+// { wxCMD_LINE_OPTION, _T("c"), _T("config-file"), _("override default choice for config-file"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_NEEDS_SEPARATOR },
+ { wxCMD_LINE_OPTION, _T("l"), _T("log-verbosity"), _("overrides default logging verbosity, can be:\n 0: no log\n 1: critical errors\n 2: errors\n 3: warnings (default)\n 4: messages\n 5: function trace"), wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL },
+ { wxCMD_LINE_NONE }
+
+ };
+
+ parser.SetDesc( cmdLineDesc );
+ parser.SetSwitchChars (wxT("-"));
+}
+
+//! @brief parses the command line and sets global app options like log verbosity or log target
+bool SpringLobbyApp::OnCmdLineParsed(wxCmdLineParser& parser)
+{
+ #if wxUSE_CMDLINE_PARSER
+ if ( !parser.Parse(true) )
+ {
+ m_log_console = parser.Found(_T("console-logging"));
+ m_log_window_show = parser.Found(_T("gui-logging"));
+ m_crash_handle_disable = parser.Found(_T("no-crash-handler"));
+
+// Settings::m_user_defined_config = parser.Found( _T("config-file"), &Settings::m_user_defined_config_path );
+
+ if ( !parser.Found(_T("log-verbosity"), &m_log_verbosity ) )
+ m_log_verbosity = 5;
+
+ if ( parser.Found(_T("help")) )
+ return false; // not a syntax error, but program should stop if user asked for command line usage
+#ifdef __WXMSW__
+ if ( parser.Found(_T("update")) ) {
+ m_updateing_only = true;
+ wxString latestVersion = GetLatestVersion();
+ Updater().StartUpdate( latestVersion );
+ return true;
+ }
+#endif
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ #else // wxUSE_CMDLINE_PARSER
+ return true;
+ #endif
+}
+
+void SpringLobbyApp::CacheAndSettingsSetup()
+{
+ if( sett().IsFirstRun() )
+ {
+ wxString defaultconfigpath = GetExecutableFolder() + wxFileName::GetPathSeparator() + _T("springlobby.global.conf");
+ if ( wxFileName::FileExists( defaultconfigpath ) )
+ {
+ wxFileInputStream instream( defaultconfigpath );
+
+ if ( instream.IsOk() )
+ {
+ #ifdef __WXMSW__
+ SL_WinConf defaultconf( instream );
+ #else
+ wxConfig defaultconf( instream );
+ #endif
+ sett().SetDefaultConfigs( defaultconf );
+ }
+ }
+ }
+
+ SetSettingsStandAlone( false );
+
+ if ( sett().IsFirstRun() && !wxDirExists( wxStandardPaths::Get().GetUserDataDir() ) )
+ wxMkdir( wxStandardPaths::Get().GetUserDataDir() );
+
+ if ( (sett().GetCacheVersion() < CACHE_VERSION) && !sett().IsFirstRun() )
+ {
+ sett().SetMapCachingThreadProgress( 0 ); // reset map cache thread
+ sett().SetModCachingThreadProgress( 0 ); // reset mod cache thread
+ if ( wxDirExists( sett().GetCachePath() ) )
+ {
+ wxLogWarning( _T("erasing old cache ver %d (app cache ver %d)"), sett().GetCacheVersion(), CACHE_VERSION );
+ wxString file = wxFindFirstFile( sett().GetCachePath() + wxFILE_SEP_PATH + _T("*") );
+ while ( !file.empty() )
+ {
+ wxRemoveFile( file );
+ file = wxFindNextFile();
+ }
+ }
+ }
+
+ if ( !sett().IsFirstRun() )
+ {
+ if ( sett().GetSettingsVersion() < 3 )
+ sett().ConvertOldSpringDirsOptions();
+ if ( sett().GetSettingsVersion() < 4 )
+ {
+ if ( sett().GetTorrentPort() == DEFSETT_SPRING_PORT )
+ sett().SetTorrentPort( DEFSETT_SPRING_PORT + 1 );
+ }
+ if ( sett().GetSettingsVersion() < 5 )
+ {
+ wxArrayString list = sett().GetServers();
+ int count = list.GetCount();
+ wxArrayString wordlist = sett().GetHighlightedWords();
+ for ( int i= 0; i < count; i++ )
+ {
+ wxString nick = sett().GetServerAccountNick( list[i] );
+ if ( wordlist.Index( nick ) == -1 )
+ {
+ wordlist.Add( nick );
+ }
+ }
+ sett().SetHighlightedWords( wordlist );
+ }
+ if ( sett().GetSettingsVersion() < 6 )
+ {
+ sett().ConvertOldServerSettings();
+ }
+ if ( sett().GetSettingsVersion() < 7 )
+ {
+ sett().AddChannelJoin( _T("springlobby"), _T("") );
+ }
+ if ( sett().GetSettingsVersion() < 8 )
+ {
+ sett().DeleteServer( _T("Backup server") );
+ sett().SetServer( _T("Backup server 1"), _T("springbackup1.servegame.com"), 8200 );
+ sett().SetServer( _T("Backup server 2"), _T("springbackup2.servegame.org"), 8200 );
+ sett().SetServer( _T("Test server"), _T("taspringmaster.servegame.com"), 8300 );
+ }
+ if ( sett().GetSettingsVersion() < 10 )
+ {
+ sett().ConvertOldColorSettings();
+ }
+ if ( sett().GetSettingsVersion() < 11 )
+ {
+ if( IsUACenabled() )
+ {
+ usync().ReloadUnitSyncLib();
+ if ( usync().IsLoaded() )
+ usync().SetSpringDataPath(_T("")); // UAC is on, fix the spring data path
+ }
+ }
+ if ( sett().GetSettingsVersion() < 12 )
+ {
+ sett().ConvertOldChannelSettings();
+ }
+ if ( sett().GetSettingsVersion() < 13 )
+ {
+ sett().ConvertOldHiglightSettings();
+ }
+ if ( sett().GetSettingsVersion() < 15 )
+ {
+ sett().TranslateSavedColumWidths();
+ }
+ }
+
+ if ( sett().ShouldAddDefaultServerSettings() || ( sett().GetSettingsVersion() < 14 && sett().GetServers().Count() < 2 ) )
+ sett().SetDefaultServerSettings();
+
+ if ( sett().ShouldAddDefaultChannelSettings() )
+ {
+ sett().AddChannelJoin( _T("main"), _T("") );
+ sett().AddChannelJoin( _T("newbies"), _T("") );
+ }
+
+ if ( sett().ShouldAddDefaultGroupSettings() )
+ {
+ sett().AddGroup( _("Default") );
+ sett().AddGroup( _("Ignore PM") );
+ useractions().ChangeAction( _("Ignore PM"), UserActions::ActIgnorePM );
+ sett().AddGroup( _("Ignore chat") );
+ useractions().ChangeAction( _("Ignore chat"), UserActions::ActIgnoreChat );
+ sett().AddGroup( _("Battle Autokick") );
+ useractions().ChangeAction( _("Battle Autokick"), UserActions::ActAutokick );
+ sett().AddGroup( _("Friends") );
+ useractions().ChangeAction( _("Friends"), UserActions::ActNotifBattle );
+ useractions().ChangeAction( _("Friends"), UserActions::ActHighlight );
+ useractions().ChangeAction( _("Friends"), UserActions::ActNotifLogin );
+ useractions().SetGroupColor( _("Friends"), wxColour( 0, 0, 255 ) );
+ }
+}
diff --git a/src/springlobbyapp.h b/src/springlobbyapp.h
new file mode 100644
index 0000000..5cde8e9
--- /dev/null
+++ b/src/springlobbyapp.h
@@ -0,0 +1,71 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SPRINGLOBBYAPP_H
+#define SPRINGLOBBY_HEADERGUARD_SPRINGLOBBYAPP_H
+
+#include <wx/app.h>
+
+class wxTimer;
+class wxTimerEvent;
+class wxIcon;
+class wxLocale;
+class wxTranslationHelper;
+
+//! @brief SpringLobby wxApp
+class SpringLobbyApp : public wxApp
+{
+ public:
+ SpringLobbyApp();
+ ~SpringLobbyApp();
+
+ virtual bool OnInit();
+ virtual int OnExit();
+
+ virtual void OnFatalException();
+
+ // System Events
+ void OnTimer( wxTimerEvent& event );
+ bool SelectLanguage();
+
+ virtual void OnInitCmdLine(wxCmdLineParser& parser);
+ virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
+
+
+ protected:
+
+ void CacheAndSettingsSetup();
+
+ wxTimer* m_timer;
+
+ bool quit_called;
+
+ wxTranslationHelper* m_translationhelper;
+
+ DECLARE_EVENT_TABLE()
+
+ long m_log_verbosity;
+ bool m_log_console;
+ bool m_log_window_show;
+ bool m_crash_handle_disable;
+ bool m_updateing_only;
+};
+
+DECLARE_APP(SpringLobbyApp)
+
+#endif // SPRINGLOBBY_HEADERGUARD_SPRINGLOBBYAPP_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/springoptionstab.cpp b/src/springoptionstab.cpp
new file mode 100644
index 0000000..fd6d2b4
--- /dev/null
+++ b/src/springoptionstab.cpp
@@ -0,0 +1,312 @@
+/* Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: SpringOptionsTab
+//
+
+#include "springoptionstab.h"
+
+#include <wx/filedlg.h>
+#include <wx/dirdlg.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/intl.h>
+#include <wx/textctrl.h>
+#include <wx/radiobut.h>
+#include <wx/stattext.h>
+#include <wx/button.h>
+#include <wx/checkbox.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/stdpaths.h>
+#include <wx/dir.h>
+#include <wx/file.h>
+#include <wx/choicdlg.h>
+#include <wx/stdpaths.h>
+#include <wx/scrolbar.h> // added for scroll bar powers
+#include <wx/log.h>
+
+#ifdef __WXMSW__
+#include <wx/msw/registry.h>
+#endif
+
+#include "nonportable.h"
+#include "ui.h"
+#include "iunitsync.h"
+#include "utils/controls.h"
+#include "utils/platform.h"
+#include "uiutils.h"
+#include "settings.h"
+#include "mainwindow.h"
+#include "settings++/custom_dialogs.h"
+
+BEGIN_EVENT_TABLE( SpringOptionsTab, wxPanel )
+
+ EVT_BUTTON ( SPRING_EXECBROWSE, SpringOptionsTab::OnBrowseExec )
+ EVT_BUTTON ( SPRING_SYNCBROWSE, SpringOptionsTab::OnBrowseSync )
+ EVT_BUTTON ( SPRING_AUTOCONF, SpringOptionsTab::OnAutoConf )
+ EVT_BUTTON ( SPRING_EXECFIND, SpringOptionsTab::OnFindExec )
+ EVT_BUTTON ( SPRING_SYNCFIND, SpringOptionsTab::OnFindSync )
+ EVT_BUTTON ( SPRING_DATADIR, SpringOptionsTab::OnDataDir )
+ EVT_CHECKBOX( SPRING_DONTSEARCH, SpringOptionsTab::OnDontSearch )
+
+END_EVENT_TABLE()
+
+
+SpringOptionsTab::SpringOptionsTab( wxWindow* parent, Ui& ui ) : wxScrolledWindow( parent, -1 ), m_ui( ui )
+{
+ m_dontsearch_chkbox = new wxCheckBox( this, SPRING_DONTSEARCH, _( "Search only in current installed path" ), wxDefaultPosition, wxSize( -1, CONTROL_HEIGHT ) );
+ m_dontsearch_chkbox->SetValue( sett().GetSearchSpringOnlyInSLPath() );
+#ifndef __WXMSW__
+ m_dontsearch_chkbox->Disable();
+#endif
+ /* ================================
+ * Spring executable
+ */
+ m_exec_box = new wxStaticBox( this, -1, _( "Spring executable" ) );
+
+ m_exec_loc_text = new wxStaticText( this, -1, _( "Location" ) );
+ m_exec_edit = new wxTextCtrl( this, -1, sett().GetCurrentUsedSpringBinary() );
+ m_exec_browse_btn = new wxButton( this, SPRING_EXECBROWSE, _( "Browse" ) );
+ m_exec_find_btn = new wxButton( this, SPRING_EXECFIND, _( "Find" ) );
+
+ /* ================================
+ * UnitSync
+ */
+ m_sync_box = new wxStaticBox( this, -1, _( "UnitSync library" ) );
+
+ m_sync_edit = new wxTextCtrl( this, -1, sett().GetCurrentUsedUnitSync() );
+ m_sync_loc_text = new wxStaticText( this, -1, _( "Location" ) );
+ m_sync_browse_btn = new wxButton( this, SPRING_SYNCBROWSE, _( "Browse" ) );
+ m_sync_find_btn = new wxButton( this, SPRING_SYNCFIND, _( "Find" ) );
+
+ m_auto_btn = new wxButton( this, SPRING_AUTOCONF, _( "Auto Configure" ) );
+ m_datadir_btn = new wxButton( this, SPRING_DATADIR, _( "Change Datadir path" ) );
+
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+ m_aconf_sizer = new wxBoxSizer( wxVERTICAL );
+ m_exec_loc_sizer = new wxBoxSizer( wxHORIZONTAL );
+ m_sync_loc_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_exec_loc_sizer->Add( m_exec_loc_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2 );
+ m_exec_loc_sizer->Add( m_exec_edit, 1, wxEXPAND );
+ m_exec_loc_sizer->Add( m_exec_browse_btn );
+ m_exec_loc_sizer->Add( m_exec_find_btn );
+
+ m_sync_loc_sizer->Add( m_sync_loc_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2 );
+ m_sync_loc_sizer->Add( m_sync_edit, 1, wxEXPAND );
+ m_sync_loc_sizer->Add( m_sync_browse_btn );
+ m_sync_loc_sizer->Add( m_sync_find_btn );
+
+ m_exec_box_sizer = new wxStaticBoxSizer( m_exec_box, wxVERTICAL );
+ m_sync_box_sizer = new wxStaticBoxSizer( m_sync_box, wxVERTICAL );
+
+ m_exec_box_sizer->Add( m_exec_loc_sizer, 0, wxEXPAND | wxALL, 2 );
+
+ m_sync_box_sizer->Add( m_sync_loc_sizer, 0, wxEXPAND | wxALL, 2 );
+
+ m_aconf_sizer->AddStretchSpacer();
+ m_aconf_sizer->Add( m_auto_btn );
+ m_aconf_sizer->Add( m_datadir_btn );
+
+ m_main_sizer->Add( m_dontsearch_chkbox, 0, wxEXPAND | wxALL, 5 );
+ m_main_sizer->Add( m_exec_box_sizer, 0, wxEXPAND | wxALL, 5 );
+ m_main_sizer->Add( m_sync_box_sizer, 0, wxEXPAND | wxALL, 5 );
+
+ m_main_sizer->Add( m_aconf_sizer, 0, wxEXPAND | wxALL, 5 );
+ m_main_sizer->AddStretchSpacer();
+
+ SetSizer( m_main_sizer );
+
+ SetScrollRate( 3, 3 );
+
+ Layout();
+
+ DoRestore();
+
+ if ( sett().IsPortableMode() || sett().GetSearchSpringOnlyInSLPath() )
+ {
+ m_exec_box->Disable();
+ m_sync_box->Disable();
+ m_auto_btn->Disable();
+ m_datadir_btn->Disable();
+ }
+
+ if ( sett().IsFirstRun() )
+ {
+ sett().SetSpringBinary( sett().GetCurrentUsedSpringIndex(), m_exec_edit->GetValue() );
+ sett().SetUnitSync( sett().GetCurrentUsedSpringIndex(), m_sync_edit->GetValue() );
+ sett().SetSearchSpringOnlyInSLPath( m_dontsearch_chkbox->IsChecked() );
+ }
+
+}
+
+
+SpringOptionsTab::~SpringOptionsTab()
+{
+
+}
+
+
+void SpringOptionsTab::DoRestore()
+{
+#ifdef __WXMSW__
+ m_dontsearch_chkbox->SetValue( sett().GetSearchSpringOnlyInSLPath() );
+#endif
+ m_sync_edit->SetValue( sett().GetCurrentUsedUnitSync() );
+ m_exec_edit->SetValue( sett().GetCurrentUsedSpringBinary() );
+}
+
+
+void SpringOptionsTab::OnAutoConf( wxCommandEvent& event )
+{
+ OnFindExec( event );
+ OnFindSync( event );
+}
+
+
+void SpringOptionsTab::OnFindExec( wxCommandEvent& /*unused*/ )
+{
+ wxString found = sett().AutoFindSpringBin();
+ if ( !found.IsEmpty() ) m_exec_edit->SetValue( found );
+}
+
+
+void SpringOptionsTab::OnFindSync( wxCommandEvent& /*unused*/ )
+{
+ wxString found = sett().AutoFindUnitSync();
+ if ( !found.IsEmpty() ) m_sync_edit->SetValue( found );
+}
+
+void SpringOptionsTab::OnBrowseExec( wxCommandEvent& /*unused*/ )
+{
+ wxFileDialog pick( this, _( "Choose a Spring executable" ),
+ wxPathOnly( sett().GetCurrentUsedSpringBinary() ),
+ wxString( SPRING_BIN ), CHOOSE_EXE );
+ if ( pick.ShowModal() == wxID_OK ) m_exec_edit->SetValue( pick.GetPath() );
+}
+
+void SpringOptionsTab::OnBrowseSync( wxCommandEvent& /*unused*/ )
+{
+ wxString filefilter = wxString( _( "Library" ) ) << _T( "(*" ) << GetLibExtension() << _T( ")|*" ) + GetLibExtension();
+#ifdef __WXMAC__
+ filefilter << _T( "|" ) << _( "Library" ) << _T( "(*.dylib)|*.dylib" );
+#endif
+ filefilter << _T( "|" ) << wxString( _( "Any File" ) ) << _T( " (*.*)|*.*" );
+ wxFileDialog pick( this, _( "Choose UnitSync library" ),
+ wxPathOnly( sett().GetCurrentUsedSpringBinary() ),
+ _T( "unitsync" ) + GetLibExtension(),
+ wxString( _( "Library" ) ) + _T( "(*" ) + GetLibExtension() + _T( ")|*" ) + GetLibExtension() + _T( "|" ) + wxString( _( "Any File" ) ) + _T( " (*.*)|*.*" ) );
+ if ( pick.ShowModal() == wxID_OK ) m_sync_edit->SetValue( pick.GetPath() );
+}
+
+
+void SpringOptionsTab::OnApply( wxCommandEvent& /*unused*/ )
+{
+ sett().SetSpringBinary( sett().GetCurrentUsedSpringIndex(), m_exec_edit->GetValue() );
+ sett().SetUnitSync( sett().GetCurrentUsedSpringIndex(), m_sync_edit->GetValue() );
+#ifdef __WXMSW__
+ sett().SetSearchSpringOnlyInSLPath( m_dontsearch_chkbox->IsChecked() );
+#endif
+
+ if ( sett().IsFirstRun() ) return;
+
+ sett().RefreshSpringVersionList();
+ if ( !usync().LoadUnitSyncLib( sett().GetCurrentUsedUnitSync() ) )
+ {
+ wxLogWarning( _T( "Cannot load UnitSync" ) );
+ customMessageBox( SL_MAIN_ICON,
+ _( "SpringLobby is unable to load your UnitSync library.\n\nYou might want to take another look at your unitsync setting." ),
+ _( "Spring error" ), wxOK );
+ }
+
+ m_ui.mw().OnUnitSyncReloaded();
+}
+
+
+void SpringOptionsTab::OnRestore( wxCommandEvent& /*unused*/ )
+{
+ DoRestore();
+}
+
+void SpringOptionsTab::OnDataDir( wxCommandEvent& /*unused*/ )
+{
+ SetupUserFolders();
+}
+
+void SpringOptionsTab::OnDontSearch( wxCommandEvent& /*unused*/ )
+{
+ if ( m_dontsearch_chkbox->IsChecked() ) {
+ m_exec_box->Disable();
+ m_sync_box->Disable();
+ m_auto_btn->Disable();
+ m_datadir_btn->Disable();
+ }
+ else {
+ m_exec_box->Enable();
+ m_sync_box->Enable();
+ m_auto_btn->Enable();
+ m_datadir_btn->Enable();
+ }
+}
+
+/** Try to create the named directory, if it doesn't exist.
+ *
+ * @param name Path to directory that should exist or be created.
+ *
+ * @param perm Value of @p perm parameter for wxFileName::Mkdir.
+ *
+ * @param flags Value of @p flags parameter for wxFileName::Mkdir.
+ *
+ * @return @c true if the directory already exists, or the return
+ * value of wxFileName::Mkdir if it does not.
+ */
+inline bool
+tryCreateDirectory( const wxString& name, int perm = 0775, int flags = 0 )
+{
+ if ( wxFileName::DirExists( name ) )
+ return true;
+ else
+ return wxFileName::Mkdir( name, perm, flags );
+}
+
+void SpringOptionsTab::SetupUserFolders()
+{
+ wxString sep = wxFileName::GetPathSeparator();
+ wxString defaultdir = wxFileName::GetHomeDir() + sep + _T( ".spring" );
+
+ int result = wxMessageBox( _( "Do you want to change spring's datadir location? (select yes only if you know what you're doing)" ), _( "Data dir wizard" ), wxICON_QUESTION | wxYES_NO, &ui().mw() );
+
+ if ( result != wxYES ) return;
+
+ wxString dir = wxDirSelector( _( "Choose a folder" ), defaultdir );
+
+ if ( dir.IsEmpty() ||
+ ( !tryCreateDirectory( dir, 0775 ) ||
+ ( !tryCreateDirectory( dir + sep + _T( "mods" ), 0775 ) ||
+ !tryCreateDirectory( dir + sep + _T( "maps" ), 0775 ) ||
+ !tryCreateDirectory( dir + sep + _T( "base" ), 0775 ) ||
+ !tryCreateDirectory( dir + sep + _T( "demos" ), 0775 ) ||
+ !tryCreateDirectory( dir + sep + _T( "screenshots" ), 0775 ) )
+ )
+ )
+ {
+ if ( dir.IsEmpty() ) dir = defaultdir;
+ wxMessageBox( _( "Something went wrong when creating the directories\nPlease create manually the following folders:" ) + wxString( _T( "\n" ) ) + dir + _T( "\n" ) + dir + sep + _T( "mods\n" ) + dir + sep + _T( "maps\n" ) + dir + sep + _T( "base\n" ) );
+ return;
+ }
+ if ( usync().IsLoaded() )
+ {
+ usync().SetSpringDataPath( dir );
+ }
+
+ // copy uikeys.txt
+ wxPathList pl;
+ pl.AddEnvList( _T( "%ProgramFiles%" ) );
+ pl.AddEnvList( _T( "XDG_DATA_DIRS" ) );
+ pl = sett().GetAdditionalSearchPaths( pl );
+ wxString uikeyslocation = pl.FindValidPath( _T( "uikeys.txt" ) );
+ if ( !uikeyslocation.IsEmpty() )
+ {
+ wxCopyFile( uikeyslocation, sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T( "uikeys.txt" ), false );
+ }
+}
diff --git a/src/springoptionstab.h b/src/springoptionstab.h
new file mode 100644
index 0000000..4090fd0
--- /dev/null
+++ b/src/springoptionstab.h
@@ -0,0 +1,112 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SPRINGOPTIONSTAB_H
+#define SPRINGLOBBY_HEADERGUARD_SPRINGOPTIONSTAB_H
+
+#include <wx/scrolwin.h>
+
+class wxStaticBoxSizer;
+class wxStaticBox;
+class wxStaticText;
+class wxRadioButton;
+class wxButton;
+class wxTextCtrl;
+class wxBoxSizer;
+class Ui;
+class wxCheckBox;
+
+class SpringOptionsTab : public wxScrolledWindow
+{
+ public:
+ SpringOptionsTab( wxWindow* parent, Ui& ui );
+ ~SpringOptionsTab();
+
+ void DoRestore();
+
+ void OnBrowseExec( wxCommandEvent& event );
+ void OnBrowseSync( wxCommandEvent& event );
+
+ void OnApply( wxCommandEvent& event );
+ void OnRestore( wxCommandEvent& event );
+
+ void OnAutoConf( wxCommandEvent& event );
+ void OnFindExec( wxCommandEvent& event );
+ void OnFindSync( wxCommandEvent& event );
+
+ void OnDataDir( wxCommandEvent& event );
+
+ void OnDontSearch( wxCommandEvent& event );
+
+ protected:
+
+ void SetupUserFolders();
+
+ wxStaticText* m_exec_loc_text;
+ wxStaticText* m_sync_loc_text;
+
+ wxButton* m_exec_browse_btn;
+ wxButton* m_exec_find_btn;
+ wxButton* m_sync_browse_btn;
+ wxButton* m_sync_find_btn;
+ wxButton* m_datadir_btn;
+
+ wxButton* m_auto_btn;
+
+ wxRadioButton* m_exec_def_radio;
+ wxRadioButton* m_exec_spec_radio;
+ wxRadioButton* m_sync_def_radio;
+ wxRadioButton* m_sync_spec_radio;
+
+ wxTextCtrl* m_exec_edit;
+ wxTextCtrl* m_sync_edit;
+
+ wxStaticBox* m_exec_box;
+ wxStaticBox* m_sync_box;
+ wxStaticBox* m_web_box;
+ wxStaticBoxSizer* m_exec_box_sizer;
+ wxStaticBoxSizer* m_sync_box_sizer;
+
+
+ wxBoxSizer* m_main_sizer;
+ wxBoxSizer* m_aconf_sizer;
+ wxBoxSizer* m_exec_loc_sizer;
+ wxBoxSizer* m_sync_loc_sizer;
+
+ wxCheckBox* m_dontsearch_chkbox;
+
+ Ui& m_ui;
+
+ enum {
+ SPRING_EXECBROWSE = wxID_HIGHEST,
+ SPRING_SYNCBROWSE,
+ SPRING_WEBBROWSE,
+ SPRING_DEFEXE,
+ SPRING_DEFUSYNC,
+ SPRING_DEFWEB,
+ SPRING_AUTOCONF,
+ SPRING_EXECFIND,
+ SPRING_SYNCFIND,
+ SPRING_DATADIR,
+ SPRING_DONTSEARCH
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_SPRINGOPTIONSTAB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/springprocess.cpp b/src/springprocess.cpp
new file mode 100644
index 0000000..586f12a
--- /dev/null
+++ b/src/springprocess.cpp
@@ -0,0 +1,67 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include "springprocess.h"
+#include "spring.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include <wx/log.h>
+
+
+DEFINE_LOCAL_EVENT_TYPE( wxEVT_SPRING_EXIT )
+
+
+SpringProcess::SpringProcess( Spring& sp ) :
+ m_sp( sp ), m_exit_code( 0 )
+{
+ wxLogDebugFunc( _T( "" ) );
+}
+
+
+SpringProcess::~SpringProcess()
+{
+ wxLogDebugFunc( _T( "" ) );
+}
+
+
+void SpringProcess::SetCommand( const wxString& cmd )
+{
+ m_cmd = cmd;
+}
+
+
+void SpringProcess::OnExit()
+{
+ wxLogDebugFunc( _T( "" ) );
+ wxCommandEvent event( wxEVT_SPRING_EXIT, PROC_SPRING );
+ event.SetExtraLong( m_exit_code );
+ m_sp.AddPendingEvent( event );
+}
+
+
+void* SpringProcess::Entry()
+{
+ wxLogDebugFunc( _T( "" ) );
+ m_exit_code = system( m_cmd.mb_str( wxConvUTF8 ) );
+ wxLogMessage( _T( "Spring closed." ) );
+ return 0;
+}
+
+wxSpringProcess::wxSpringProcess( Spring& sp ) :
+ m_sp( sp )
+{
+ wxLogDebugFunc( _T( "" ) );
+}
+
+
+wxSpringProcess::~wxSpringProcess()
+{
+ wxLogDebugFunc( _T( "" ) );
+}
+
+void wxSpringProcess::OnTerminate( int pid, int status )
+{
+ wxCommandEvent event( wxEVT_SPRING_EXIT, PROC_SPRING );
+ event.SetExtraLong( status );
+ m_sp.AddPendingEvent( event );
+}
+
diff --git a/src/springprocess.h b/src/springprocess.h
new file mode 100644
index 0000000..16aee0a
--- /dev/null
+++ b/src/springprocess.h
@@ -0,0 +1,64 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SPRINGPROCESS_H
+#define SPRINGLOBBY_HEADERGUARD_SPRINGPROCESS_H
+
+#include <wx/thread.h>
+#include <wx/string.h>
+#include <wx/process.h>
+
+BEGIN_DECLARE_EVENT_TYPES()
+DECLARE_LOCAL_EVENT_TYPE( wxEVT_SPRING_EXIT, 1 )
+END_DECLARE_EVENT_TYPES()
+
+class Spring;
+
+class SpringProcess: public wxThread
+{
+ public:
+ SpringProcess( Spring& sp );
+ ~SpringProcess();
+
+ void OnExit();
+
+ void SetCommand( const wxString& cmd );
+
+ void* Entry();
+
+ protected:
+ Spring& m_sp;
+ wxString m_cmd;
+ int m_exit_code;
+};
+
+class wxSpringProcess: public wxProcess
+{
+ public:
+ wxSpringProcess( Spring& sp );
+ ~wxSpringProcess();
+
+ void OnTerminate( int pid, int status );
+
+ protected:
+ Spring& m_sp;
+};
+
+const int PROC_SPRING = wxID_HIGHEST;
+
+#endif // SPRINGLOBBY_HEADERGUARD_SPRINGPROCESS_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/springunitsync.cpp b/src/springunitsync.cpp
new file mode 100644
index 0000000..ee1900e
--- /dev/null
+++ b/src/springunitsync.cpp
@@ -0,0 +1,1215 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include "springunitsync.h"
+
+#include <algorithm>
+#include <wx/dynlib.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/image.h>
+#include <wx/intl.h>
+#include <wx/msgdlg.h>
+#include <wx/mstream.h>
+#include <wx/stdpaths.h>
+#include <wx/string.h>
+#include <wx/file.h>
+#include <wx/tokenzr.h>
+#include <wx/log.h>
+//#include <wx/txtstrm.h>
+//#include <wx/wfstream.h>
+#include <wx/textfile.h>
+#include <cmath>
+#include <stdexcept>
+#include <clocale>
+
+#include "settings.h"
+#include "springunitsynclib.h"
+#include "settings++/custom_dialogs.h"
+#include "unitsyncthread.h"
+#include "globalsmanager.h"
+#include "uiutils.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "utils/misc.h"
+
+
+#define LOCK_UNITSYNC wxCriticalSectionLocker lock_criticalsection(m_lock)
+
+const wxEventType UnitSyncAsyncOperationCompletedEvt = wxNewEventType();
+
+
+IUnitSync& usync()
+{
+ static GlobalObjectHolder<SpringUnitSync> m_sync;
+ return m_sync;
+}
+
+
+SpringUnitSync::SpringUnitSync()
+ : m_map_image_cache( 3, _T("m_map_image_cache") ) // may take about 3M per image ( 1024x1024 24 bpp minimap )
+ , m_tiny_minimap_cache( 200, _T("m_tiny_minimap_cache") ) // takes at most 30k per image ( 100x100 24 bpp minimap )
+ , m_mapinfo_cache( 1000000, _T("m_mapinfo_cache") ) // this one is just misused as thread safe std::map ...
+ , m_sides_cache( 200, _T("m_sides_cache") ) // another misuse
+{
+ m_cache_thread.Create();
+ m_cache_thread.SetPriority( WXTHREAD_MIN_PRIORITY );
+ m_cache_thread.Run();
+}
+
+
+SpringUnitSync::~SpringUnitSync()
+{
+ m_cache_thread.Wait();
+}
+
+
+bool SpringUnitSync::LoadUnitSyncLib( const wxString& unitsyncloc )
+{
+ LOCK_UNITSYNC;
+ wxLogDebugFunc( _T("") );
+ bool ret = _LoadUnitSyncLib( unitsyncloc );
+ if (ret)
+ {
+ m_cache_path = sett().GetCachePath();
+ PopulateArchiveList();
+ }
+ return ret;
+}
+
+
+void SpringUnitSync::PopulateArchiveList()
+{
+ m_maps_list.clear();
+ m_mods_list.clear();
+ m_mod_array.Empty();
+ m_map_array.Empty();
+ m_map_image_cache.Clear();
+ m_mapinfo_cache.Clear();
+
+ int numMaps = susynclib().GetMapCount();
+ for ( int i = 0; i < numMaps; i++ )
+ {
+ wxString name, hash, archivename, unchainedhash;
+ try
+ {
+ name = susynclib().GetMapName( i );
+ hash = susynclib().GetMapChecksum( i );
+ int count = susynclib().GetMapArchiveCount( i );
+ if ( count > 0 )
+ {
+ archivename = susynclib().GetMapArchiveName( 0 );
+ unchainedhash = susynclib().GetArchiveChecksum( archivename );
+ }
+ //PrefetchMap( name ); // DEBUG
+ } catch (...) { continue; }
+ try
+ {
+ m_maps_list[name] = hash;
+ if ( !unchainedhash.IsEmpty() ) m_maps_unchained_hash[name] = unchainedhash;
+ if ( !archivename.IsEmpty() ) m_maps_archive_name[name] = archivename;
+ m_map_array.Add( name );
+ } catch (...)
+ {
+ wxLogError( _T("Found map with hash collision: ") + name + _T(" hash: ") + hash );
+ }
+ }
+ int numMods = susynclib().GetPrimaryModCount();
+ for ( int i = 0; i < numMods; i++ )
+ {
+ wxString name, hash, archivename, unchainedhash;
+ try
+ {
+ name = susynclib().GetPrimaryModName( i );
+ hash = susynclib().GetPrimaryModChecksum( i );
+ int count = susynclib().GetPrimaryModArchiveCount( i );
+ if ( count > 0 )
+ {
+ archivename = susynclib().GetPrimaryModArchive( 0 );
+ unchainedhash = susynclib().GetArchiveChecksum( archivename );
+ }
+ } catch (...) { continue; }
+ try
+ {
+ m_mods_list[name] = hash;
+ if ( !unchainedhash.IsEmpty() ) m_mods_unchained_hash[name] = unchainedhash;
+ if ( !archivename.IsEmpty() ) m_mods_archive_name[name] = archivename;
+ m_mod_array.Add( name );
+ } catch (...)
+ {
+ wxLogError( _T("Found mod with hash collision: ") + name + _T(" hash: ") + hash );
+ }
+ }
+}
+
+
+
+bool SpringUnitSync::_LoadUnitSyncLib( const wxString& unitsyncloc )
+{
+ try {
+ susynclib().Load( unitsyncloc, sett().GetForcedSpringConfigFilePath() );
+ } catch (...) {
+ return false;
+ }
+ return true;
+}
+
+
+void SpringUnitSync::FreeUnitSyncLib()
+{
+ LOCK_UNITSYNC;
+ wxLogDebugFunc( _T("") );
+ susynclib().Unload();
+}
+
+
+bool SpringUnitSync::IsLoaded()
+{
+ return susynclib().IsLoaded();
+}
+
+
+wxString SpringUnitSync::GetSpringVersion()
+{
+ wxLogDebugFunc( _T("") );
+ wxString ret;
+ try
+ {
+ ret = susynclib().GetSpringVersion();
+ }
+ catch (...){}
+ return ret;
+}
+
+
+bool SpringUnitSync::VersionSupports( GameFeature feature )
+{
+ return susynclib().VersionSupports( feature );
+}
+
+
+int SpringUnitSync::GetNumMods()
+{
+ wxLogDebugFunc( _T("") );
+ return m_mod_array.GetCount();
+}
+
+
+wxArrayString SpringUnitSync::GetModList()
+{
+ return m_mod_array;
+}
+
+
+int SpringUnitSync::GetModIndex( const wxString& name )
+{
+ wxLogDebugFunc( _T("name = \"") + name + _T("\"") );
+ try
+ {
+ return susynclib().GetModIndex( name );
+ } catch (...){}
+ return -1;
+}
+
+
+bool SpringUnitSync::ModExists( const wxString& modname )
+{
+ return (m_mods_list.find(modname) != m_mods_list.end());
+}
+
+
+bool SpringUnitSync::ModExists( const wxString& modname, const wxString& hash )
+{
+ LocalArchivesVector::iterator itor = m_mods_list.find(modname);
+ if ( itor == m_mods_list.end() ) return false;
+ return itor->second == hash;
+}
+
+bool SpringUnitSync::ModExistsCheckHash( const wxString& hash ) const
+{
+ LocalArchivesVector::const_iterator itor = m_mods_list.begin();
+ for ( ; itor != m_mods_list.end(); ++itor ) {
+ if ( itor->second == hash )
+ return true;
+ }
+ return false;
+}
+
+UnitSyncMod SpringUnitSync::GetMod( const wxString& modname )
+{
+ wxLogDebugFunc( _T("modname = \"") + modname + _T("\"") );
+ UnitSyncMod m;
+
+ m.name = modname;
+ m.hash = m_mods_list[modname];
+
+ return m;
+}
+
+
+UnitSyncMod SpringUnitSync::GetMod( int index )
+{
+ wxLogDebugFunc( _T("") );
+ UnitSyncMod m;
+ susynclib().GetPrimaryModCount();
+ m.name = susynclib().GetPrimaryModName( index );
+ m.hash = susynclib().GetPrimaryModChecksum( index );
+
+ return m;
+ }
+
+int SpringUnitSync::GetNumMaps()
+{
+ wxLogDebugFunc( _T("") );
+ return m_map_array.GetCount();
+}
+
+
+wxArrayString SpringUnitSync::GetMapList()
+{
+ return m_map_array;
+}
+
+
+wxArrayString SpringUnitSync::GetModValidMapList( const wxString& modname )
+{
+ wxArrayString ret;
+ try
+ {
+ unsigned int mapcount = susynclib().GetValidMapCount( modname );
+ for ( unsigned int i = 0; i < mapcount; i++ ) ret.Add( susynclib().GetValidMapName( i ) );
+ } catch ( assert_exception& e ) {}
+ return ret;
+}
+
+
+bool SpringUnitSync::MapExists( const wxString& mapname )
+{
+ return (m_maps_list.find(mapname) != m_maps_list.end());
+}
+
+
+bool SpringUnitSync::MapExists( const wxString& mapname, const wxString& hash )
+{
+ LocalArchivesVector::iterator itor = m_maps_list.find(mapname);
+ if ( itor == m_maps_list.end() ) return false;
+ return itor->second == hash;
+}
+
+
+UnitSyncMap SpringUnitSync::GetMap( const wxString& mapname )
+{
+ wxLogDebugFunc( _T("") );
+ UnitSyncMap m;
+
+ m.name = mapname;
+ m.hash = m_maps_list[mapname];
+
+ return m;
+}
+
+
+UnitSyncMap SpringUnitSync::GetMap( int index )
+{
+ wxLogDebugFunc( _T("") );
+ UnitSyncMap m;
+
+ m.name = m_map_array[index];
+ m.hash = m_maps_list[m.name];
+
+ return m;
+ }
+
+
+UnitSyncMap SpringUnitSync::GetMapEx( int index )
+{
+ UnitSyncMap m;
+
+ if ( index < 0 ) return m;
+
+ m.name = m_map_array[index];
+ m.hash = m_maps_list[m.name];
+
+ m.info = _GetMapInfoEx( m.name );
+
+ return m;
+}
+
+void GetOptionEntry( const int i, GameOptions& ret)
+{
+ //all section values for options are converted to lower case
+ //since usync returns the key of section type keys lower case
+ //otherwise comapring would be a real hassle
+ wxString key = susynclib().GetOptionKey(i);
+ wxString name = susynclib().GetOptionName(i);
+ switch (susynclib().GetOptionType(i))
+ {
+ case opt_float:
+ {
+ ret.float_map[key] = mmOptionFloat( name, key,
+ susynclib().GetOptionDesc(i), susynclib().GetOptionNumberDef(i),
+ susynclib().GetOptionNumberStep(i),
+ susynclib().GetOptionNumberMin(i), susynclib().GetOptionNumberMax(i),
+ susynclib().GetOptionSection(i).Lower(), susynclib().GetOptionStyle(i) );
+ break;
+ }
+ case opt_bool:
+ {
+ ret.bool_map[key] = mmOptionBool( name, key,
+ susynclib().GetOptionDesc(i), susynclib().GetOptionBoolDef(i),
+ susynclib().GetOptionSection(i).Lower(), susynclib().GetOptionStyle(i) );
+ break;
+ }
+ case opt_string:
+ {
+ ret.string_map[key] = mmOptionString( name, key,
+ susynclib().GetOptionDesc(i), susynclib().GetOptionStringDef(i),
+ susynclib().GetOptionStringMaxLen(i),
+ susynclib().GetOptionSection(i).Lower(), susynclib().GetOptionStyle(i) );
+ break;
+ }
+ case opt_list:
+ {
+ ret.list_map[key] = mmOptionList(name,key,
+ susynclib().GetOptionDesc(i),susynclib().GetOptionListDef(i),
+ susynclib().GetOptionSection(i).Lower(),susynclib().GetOptionStyle(i));
+
+ int listItemCount = susynclib().GetOptionListCount(i);
+ for (int j = 0; j < listItemCount; ++j)
+ {
+ wxString descr = susynclib().GetOptionListItemDesc(i,j);
+ ret.list_map[key].addItem(susynclib().GetOptionListItemKey(i,j),susynclib().GetOptionListItemName(i,j), descr);
+ }
+ break;
+ }
+ case opt_section:
+ {
+ ret.section_map[key] = mmOptionSection( name, key, susynclib().GetOptionDesc(i),
+ susynclib().GetOptionSection(i).Lower(), susynclib().GetOptionStyle(i) );
+ }
+ }
+}
+
+
+GameOptions SpringUnitSync::GetMapOptions( const wxString& name )
+{
+ wxLogDebugFunc( name );
+ GameOptions ret;
+ int count = susynclib().GetMapOptionCount(name);
+ for (int i = 0; i < count; ++i)
+ {
+ GetOptionEntry( i, ret );
+ }
+ return ret;
+}
+
+wxArrayString SpringUnitSync::GetMapDeps( const wxString& mapname )
+{
+ wxArrayString ret;
+ try
+ {
+ ret = susynclib().GetMapDeps( GetMapIndex( mapname ) );
+ }
+ catch( unitsync_assert ) {}
+ return ret;
+}
+
+
+UnitSyncMap SpringUnitSync::GetMapEx( const wxString& mapname )
+{
+ wxLogDebugFunc( _T("") );
+ int i = GetMapIndex( mapname );
+ ASSERT_LOGIC( i >= 0, _T("Map does not exist") );
+ return GetMapEx( i );
+}
+
+
+int SpringUnitSync::GetMapIndex( const wxString& name )
+{
+ int result = m_map_array.Index( name );
+ if ( result == wxNOT_FOUND ) result = -1;
+ return result;
+}
+
+
+wxString SpringUnitSync::GetModArchive( int index )
+{
+ wxLogDebugFunc( _T("") );
+
+ return susynclib().GetPrimaryModArchive( index );
+}
+
+
+wxString SpringUnitSync::GetMapArchive( int index )
+{
+ wxLogDebugFunc( _T("") );
+
+ int count = susynclib().GetMapArchiveCount( index );
+
+ if ( count > 0 )
+ return susynclib().GetMapArchiveName( 0 );
+ else
+ return _T("");
+}
+
+
+GameOptions SpringUnitSync::GetModOptions( const wxString& name )
+{
+ wxLogDebugFunc( name );
+ GameOptions ret;
+ int count = susynclib().GetModOptionCount(name);
+ for (int i = 0; i < count; ++i)
+ {
+ GetOptionEntry( i, ret );
+ }
+ return ret;
+}
+
+wxArrayString SpringUnitSync::GetModDeps( const wxString& modname )
+{
+ wxArrayString ret;
+ try
+ {
+ ret = susynclib().GetModDeps( GetModIndex( modname ) );
+ }
+ catch( unitsync_assert ) {}
+ return ret;
+}
+
+wxArrayString SpringUnitSync::GetSides( const wxString& modname )
+{
+ wxArrayString ret;
+ if ( ! m_sides_cache.TryGet( modname, ret ) ) {
+ try
+ {
+ ret = susynclib().GetSides( modname );
+ m_sides_cache.Add( modname, ret );
+ }
+ catch( unitsync_assert ) {}
+ }
+ return ret;
+}
+
+
+wxImage SpringUnitSync::GetSidePicture( const wxString& modname, const wxString& SideName )
+{
+ wxLogDebugFunc( _T("") );
+
+ wxImage cache;
+
+ susynclib().SetCurrentMod( modname );
+ wxLogDebugFunc( _T("SideName = \"") + SideName + _T("\"") );
+ wxString ImgName = _T("SidePics");
+ ImgName += _T("/");
+ ImgName += SideName.Upper();
+ ImgName += _T(".bmp");
+
+ int ini = susynclib().OpenFileVFS (ImgName );
+ ASSERT_EXCEPTION( ini, _T("cannot find side image") );
+
+ int FileSize = susynclib().FileSizeVFS(ini);
+ if (FileSize == 0) {
+ susynclib().CloseFileVFS(ini);
+ ASSERT_EXCEPTION( FileSize, _T("side image has size 0") );
+ }
+
+ uninitialized_array<char> FileContent(FileSize);
+ susynclib().ReadFileVFS(ini, FileContent, FileSize);
+ wxMemoryInputStream FileContentStream( FileContent, FileSize );
+
+ cache.LoadFile( FileContentStream, wxBITMAP_TYPE_ANY, -1);
+ cache.InitAlpha();
+ for ( int x = 0; x < cache.GetWidth(); x++ )
+ for ( int y = 0; y < cache.GetHeight(); y++ )
+ if ( cache.GetBlue( x, y ) == 255 && cache.GetGreen( x, y ) == 255 && cache.GetRed( x, y ) == 255 ) cache.SetAlpha( x, y, 0 ); // set pixel to be transparent
+ return cache;
+}
+
+
+wxArrayString SpringUnitSync::GetAIList( const wxString& modname )
+{
+ wxLogDebugFunc( _T("") );
+
+ wxArrayString ret;
+
+ if ( usync().VersionSupports( USYNC_GetSkirmishAI ) )
+ {
+ int total = susynclib().GetSkirmishAICount( modname );
+ for ( int i = 0; i < total; i++ )
+ {
+ wxArrayString infos = susynclib().GetAIInfo( i );
+ int namepos = infos.Index( _T("shortName") );
+ int versionpos = infos.Index( _T("version") );
+ wxString ainame;
+ if ( namepos != wxNOT_FOUND ) ainame += infos[namepos +1];
+ if ( versionpos != wxNOT_FOUND ) ainame += _T(" ") + infos[versionpos +1];
+ ret.Add( ainame );
+ }
+ }
+ else
+ {
+ // list dynamic link libraries
+ wxArrayString dlllist = susynclib().FindFilesVFS( wxDynamicLibrary::CanonicalizeName(_T("AI/Bot-libs/*"), wxDL_MODULE) );
+ for( int i = 0; i < dlllist.GetCount(); i++ )
+ {
+ if ( ret.Index( dlllist[i].BeforeLast( '/') ) == wxNOT_FOUND ) ret.Add ( dlllist[i] ); // don't add duplicates
+ }
+ // list jar files (java AIs)
+ wxArrayString jarlist = susynclib().FindFilesVFS( _T("AI/Bot-libs/*.jar") );
+ for( int i = 0; i < jarlist.GetCount(); i++ )
+ {
+ if ( ret.Index( jarlist[i].BeforeLast( '/') ) == wxNOT_FOUND ) ret.Add ( jarlist[i] ); // don't add duplicates
+ }
+
+ // luaai
+ try
+ {
+ const int LuaAICount = susynclib().GetLuaAICount( modname );
+ for ( int i = 0; i < LuaAICount; i++ )
+ {
+ ret.Add( _T( "LuaAI:" ) + susynclib().GetLuaAIName( i ) );
+ }
+ } catch (...) {}
+ }
+
+ return ret;
+}
+
+wxArrayString SpringUnitSync::GetAIInfos( int index )
+{
+ wxArrayString ret;
+ try
+ {
+ ret = susynclib().GetAIInfo( index );
+ }
+ catch ( unitsync_assert ) {}
+ return ret;
+}
+
+GameOptions SpringUnitSync::GetAIOptions( const wxString& modname, int index )
+{
+ wxLogDebugFunc( TowxString(index) );
+ GameOptions ret;
+ int count = susynclib().GetAIOptionCount(modname, index);
+ for (int i = 0; i < count; ++i)
+ {
+ GetOptionEntry( i, ret );
+ }
+ return ret;
+}
+
+int SpringUnitSync::GetNumUnits( const wxString& modname )
+{
+ wxLogDebugFunc( _T("") );
+
+ susynclib().AddAllArchives( susynclib().GetPrimaryModArchive( susynclib().GetModIndex( modname ) ) );
+ susynclib().ProcessUnitsNoChecksum();
+
+ return susynclib().GetUnitCount();
+}
+
+
+wxArrayString SpringUnitSync::GetUnitsList( const wxString& modname )
+{
+ wxLogDebugFunc( modname );
+
+ wxArrayString cache;
+ try
+ {
+ cache = GetCacheFile( GetFileCachePath( modname, _T(""), true ) + _T(".units") );
+ } catch(...)
+ {
+ susynclib().SetCurrentMod( modname );
+ while ( susynclib().ProcessUnitsNoChecksum() );
+ unsigned int unitcount = susynclib().GetUnitCount();
+ for ( unsigned int i = 0; i < unitcount; i++ )
+ {
+ cache.Add( susynclib().GetFullUnitName(i) << _T(" (") << susynclib().GetUnitName(i) << _T(")") );
+ }
+
+ SetCacheFile( GetFileCachePath( modname, _T(""), true ) + _T(".units"), cache );
+
+ }
+
+ return cache;
+}
+
+
+wxImage SpringUnitSync::GetMinimap( const wxString& mapname )
+{
+ wxLogDebugFunc( mapname );
+ return _GetMapImage( mapname, _T(".minimap.png"), &SpringUnitSyncLib::GetMinimap );
+}
+
+
+wxImage SpringUnitSync::GetMinimap( const wxString& mapname, int width, int height )
+{
+ wxLogDebugFunc( mapname + _T(" size: ") + TowxString( width ) + _T("x") + TowxString( height ) );
+
+ const bool tiny = ( width <= 100 && height <= 100 );
+ wxImage img;
+
+ if ( tiny && m_tiny_minimap_cache.TryGet( mapname, img ) )
+ {
+ wxSize image_size = MakeFit(wxSize(img.GetWidth(), img.GetHeight()), wxSize(width, height));
+
+ if ( image_size.GetWidth() != img.GetWidth() || image_size.GetHeight() != img.GetHeight() )
+ img.Rescale( image_size.GetWidth(), image_size.GetHeight() );
+
+ return img;
+ }
+
+ img = GetMinimap( mapname );
+
+ // special resizing code because minimap is always square,
+ // and we need to resize it to the correct aspect ratio.
+ if (img.GetWidth() > 1 && img.GetHeight() > 1)
+ {
+ try {
+ MapInfo mapinfo = _GetMapInfoEx( mapname );
+
+ wxSize image_size = MakeFit(wxSize(mapinfo.width, mapinfo.height), wxSize(width, height));
+ img.Rescale( image_size.GetWidth(), image_size.GetHeight() );
+ }
+ catch (...) {
+ img = wxImage( 1, 1 );
+ }
+ }
+
+ if ( tiny ) m_tiny_minimap_cache.Add( mapname, img );
+
+ return img;
+}
+
+
+wxImage SpringUnitSync::GetMetalmap( const wxString& mapname )
+{
+ wxLogDebugFunc( mapname );
+ return _GetMapImage( mapname, _T(".metalmap.png"), &SpringUnitSyncLib::GetMetalmap );
+}
+
+
+wxImage SpringUnitSync::GetMetalmap( const wxString& mapname, int width, int height )
+{
+ wxLogDebugFunc( mapname + _T(" size: ") + TowxString( width ) + _T("x") + TowxString( height ) );
+ return _GetScaledMapImage( mapname, &SpringUnitSync::GetMetalmap, width, height );
+}
+
+
+wxImage SpringUnitSync::GetHeightmap( const wxString& mapname )
+{
+ wxLogDebugFunc( mapname );
+ return _GetMapImage( mapname, _T(".heightmap.png"), &SpringUnitSyncLib::GetHeightmap );
+}
+
+
+wxImage SpringUnitSync::GetHeightmap( const wxString& mapname, int width, int height )
+{
+ wxLogDebugFunc( mapname + _T(" size: ") + TowxString( width ) + _T("x") + TowxString( height ) );
+ return _GetScaledMapImage( mapname, &SpringUnitSync::GetHeightmap, width, height );
+}
+
+
+wxImage SpringUnitSync::_GetMapImage( const wxString& mapname, const wxString& imagename, wxImage (SpringUnitSyncLib::*loadMethod)(const wxString&) )
+{
+ wxImage img;
+
+ if ( m_map_image_cache.TryGet( mapname + imagename, img ) ) return img;
+
+ wxString originalsizepath = GetFileCachePath( mapname, m_maps_unchained_hash[mapname], false ) + imagename;
+
+ try
+ {
+ ASSERT_EXCEPTION( wxFileExists( originalsizepath ), _T("File cached image does not exist") );
+
+ img = wxImage( originalsizepath, wxBITMAP_TYPE_PNG );
+ ASSERT_EXCEPTION( img.Ok(), _T("Failed to load cache image") );
+ }
+ catch (...)
+ {
+ try
+ {
+ img = (susynclib().*loadMethod)( mapname );
+
+ img.SaveFile( originalsizepath, wxBITMAP_TYPE_PNG );
+ }
+ catch (...)
+ {
+ img = wxImage( 1, 1 );
+ }
+ }
+
+ m_map_image_cache.Add( mapname + imagename, img );
+
+ return img;
+}
+
+
+wxImage SpringUnitSync::_GetScaledMapImage( const wxString& mapname, wxImage (SpringUnitSync::*loadMethod)(const wxString&), int width, int height )
+{
+ wxImage img = (this->*loadMethod) ( mapname );
+
+ if (img.GetWidth() > 1 && img.GetHeight() > 1)
+ {
+ wxSize image_size = MakeFit(wxSize(img.GetWidth(), img.GetHeight()), wxSize(width, height));
+ img.Rescale( image_size.GetWidth(), image_size.GetHeight() );
+ }
+
+ return img;
+}
+
+
+MapInfo SpringUnitSync::_GetMapInfoEx( const wxString& mapname )
+{
+ MapInfo info;
+
+ if ( m_mapinfo_cache.TryGet( mapname, info ) ) return info;
+
+ wxArrayString cache;
+ try {
+ try
+ {
+ cache = GetCacheFile( GetFileCachePath( mapname, m_maps_unchained_hash[mapname], false ) + _T(".infoex") );
+
+ ASSERT_EXCEPTION( cache.GetCount() >= 11, _T("not enough lines found in cache info ex") );
+ info.author = cache[0];
+ info.tidalStrength = s2l( cache[1] );
+ info.gravity = s2l( cache[2] );
+ info.maxMetal = s2d( cache[3] );
+ info.extractorRadius = s2d( cache[4] );
+ info.minWind = s2l( cache[5] );
+ info.maxWind = s2l( cache[6] );
+ info.width = s2l( cache[7] );
+ info.height = s2l( cache[8] );
+ info.posCount = s2l( cache[9] );
+
+ wxArrayString posinfo = wxStringTokenize( cache[10], _T(' '), wxTOKEN_RET_EMPTY );
+ for ( int i = 0; i < info.posCount; i++)
+ {
+ StartPos position;
+ position.x = s2l( posinfo[i].BeforeFirst( _T('-') ) );
+ position.y = s2l( posinfo[i].AfterFirst( _T('-') ) );
+ info.positions[i] = position;
+ }
+
+ unsigned int LineCount = cache.GetCount();
+ for ( unsigned int i = 11; i < LineCount; i++ ) info.description << cache[i] << _T('\n');
+
+ }
+ catch (...)
+ {
+ info = susynclib().GetMapInfoEx( mapname, 1 );
+
+ cache.Add ( info.author );
+ cache.Add( TowxString( info.tidalStrength ) );
+ cache.Add( TowxString( info.gravity ) );
+ cache.Add( TowxString( info.maxMetal ) );
+ cache.Add( TowxString( info.extractorRadius ) );
+ cache.Add( TowxString( info.minWind ) );
+ cache.Add( TowxString( info.maxWind ) );
+ cache.Add( TowxString( info.width ) );
+ cache.Add( TowxString( info.height ) );
+ cache.Add( TowxString( info.posCount ) );
+
+ wxString postring;
+ for ( int i = 0; i < info.posCount; i++)
+ {
+ postring << TowxString( info.positions[i].x ) << _T('-') << TowxString( info.positions[i].y ) << _T(' ');
+ }
+ cache.Add( postring );
+
+ wxArrayString descrtoken = wxStringTokenize( info.description, _T('\n') );
+ unsigned int desclinecount = descrtoken.GetCount();
+ for ( unsigned int count = 0; count < desclinecount; count++ ) cache.Add( descrtoken[count] );
+
+ SetCacheFile( GetFileCachePath( mapname, m_maps_unchained_hash[mapname], false ) + _T(".infoex"), cache );
+ }
+ }
+ catch ( ... ) {
+ info.posCount = 0;
+ info.width = 1;
+ info.height = 1;
+ }
+
+ m_mapinfo_cache.Add( mapname, info );
+
+ return info;
+}
+
+
+bool SpringUnitSync::ReloadUnitSyncLib()
+{
+ return LoadUnitSyncLib( sett().GetCurrentUsedUnitSync() );
+}
+
+
+void SpringUnitSync::SetSpringDataPath( const wxString& path )
+{
+ susynclib().SetSpringConfigString( _T("SpringData"), path );
+}
+
+
+wxString SpringUnitSync::GetFileCachePath( const wxString& name, const wxString& hash, bool IsMod )
+{
+ LOCK_UNITSYNC;
+
+ wxString ret = m_cache_path;
+ if ( !name.IsEmpty() ) ret << name;
+ else return wxEmptyString;
+ if ( !hash.IsEmpty() ) ret << _T("-") << hash;
+ else
+ {
+ if ( IsMod ) ret << _T("-") << m_mods_list[name];
+ else
+ {
+ ret << _T("-") << m_maps_list[name];
+ }
+ }
+ return ret;
+}
+
+
+wxArrayString SpringUnitSync::GetCacheFile( const wxString& path )
+{
+ wxArrayString ret;
+ wxTextFile file( path );
+ file.Open();
+ ASSERT_EXCEPTION( file.IsOpened() , wxString::Format( _T("cache file( %s ) not found"), path.c_str() ) );
+ unsigned int linecount = file.GetLineCount();
+ for ( unsigned int count = 0; count < linecount; count ++ )
+ {
+ ret.Add( file[count] );
+ }
+ return ret;
+}
+
+
+void SpringUnitSync::SetCacheFile( const wxString& path, const wxArrayString& data )
+{
+ wxTextFile file( path );
+ unsigned int arraycount = data.GetCount();
+ for ( unsigned int count = 0; count < arraycount; count++ )
+ {
+ file.AddLine( data[count] );
+ }
+ file.Write();
+ file.Close();
+}
+
+wxArrayString SpringUnitSync::GetPlaybackList( bool ReplayType )
+{
+ wxLogDebug( _T("") );
+
+ wxArrayString ret;
+ if ( !IsLoaded() ) return ret;
+
+ if ( ReplayType )
+ return susynclib().FindFilesVFS( _T("demos/*.sdf") );
+ else
+ return susynclib().FindFilesVFS( _T("Saves/*.ssf") );
+}
+
+bool SpringUnitSync::FileExists( const wxString& name )
+{
+ int handle = susynclib().OpenFileVFS(name);
+ if ( handle == 0 ) return false;
+ susynclib().CloseFileVFS(handle);
+ return true;
+}
+
+
+wxString SpringUnitSync::GetArchivePath( const wxString& name )
+{
+ wxLogDebugFunc( name );
+
+ return susynclib().GetArchivePath( name );
+}
+
+wxArrayString SpringUnitSync::GetScreenshotFilenames()
+{
+ wxSortedArrayString ret;
+ if ( !IsLoaded() ) return ret;
+
+ ret = susynclib().FindFilesVFS( _T("screenshots/*.*") );
+ for ( int i = 0; i < ret.Count() - 1; ++i ) {
+ if ( ret[i] == ret[i+1] )
+ ret.RemoveAt( i+1 );
+ }
+ return ret;
+}
+
+wxString SpringUnitSync::GetDefaultNick()
+{
+ wxString name = susynclib().GetSpringConfigString( _T("name"), _T("Player") );
+ if ( name.IsEmpty() ) {
+ susynclib().SetSpringConfigString( _T("name"), _T("Player") );
+ return _T("Player");
+ }
+ return name;
+}
+
+void SpringUnitSync::SetDefaultNick( const wxString& nick )
+{
+ susynclib().SetSpringConfigString( _T("name"), nick );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////// Unitsync prefetch/background thread code
+
+namespace
+{
+ typedef wxImage (SpringUnitSync::*LoadMethodPtr)(const wxString&);
+ typedef wxImage (SpringUnitSync::*ScaledLoadMethodPtr)(const wxString&, int, int);
+
+ class CacheMapWorkItem : public WorkItem
+ {
+ public:
+ SpringUnitSync* m_usync;
+ wxString m_mapname;
+ LoadMethodPtr m_loadMethod;
+
+ void Run()
+ {
+ (m_usync->*m_loadMethod)( m_mapname );
+ }
+
+ CacheMapWorkItem( SpringUnitSync* usync, const wxString& mapname, LoadMethodPtr loadMethod )
+ : m_usync(usync), m_mapname(mapname.c_str()), m_loadMethod(loadMethod) {}
+ };
+
+ class CacheMinimapWorkItem : public WorkItem
+ {
+ public:
+ wxString m_mapname;
+
+ void Run()
+ {
+ // Fetch rescaled minimap using this specialized class instead of
+ // CacheMapWorkItem with a pointer to SpringUnitSync::GetMinimap,
+ // to ensure SpringUnitSync::_GetMapInfoEx will be called too, and
+ // hence it's data cached.
+
+ // This reduces main thread blocking while waiting for WorkerThread
+ // to release it's lock while e.g. scrolling through battle list.
+
+ // 98x98 because battle list map preview is 98x98
+ usync().GetMinimap( m_mapname, 98, 98 );
+ }
+
+ CacheMinimapWorkItem( const wxString& mapname )
+ : m_mapname(mapname.c_str()) {}
+ };
+
+ class GetMapImageAsyncResult : public WorkItem // TODO: rename
+ {
+ public:
+ void Run()
+ {
+ try
+ {
+ RunCore();
+ }
+ catch (...)
+ {
+ // Event without mapname means some async job failed.
+ // This is sufficient for now, we just need symmetry between
+ // number of initiated async jobs and number of finished/failed
+ // async jobs.
+ m_mapname = wxEmptyString;
+ }
+ PostEvent();
+ }
+
+ protected:
+ SpringUnitSync* m_usync;
+ wxString m_mapname;
+ int m_evtHandlerId;
+ int m_evtId;
+
+ void PostEvent()
+ {
+ wxCommandEvent evt( UnitSyncAsyncOperationCompletedEvt, m_evtId );
+ evt.SetString( m_mapname );
+ m_usync->PostEvent( m_evtHandlerId, evt );
+ }
+
+ virtual void RunCore() = 0;
+
+ GetMapImageAsyncResult( SpringUnitSync* usync, const wxString& mapname, int evtHandlerId, int evtId )
+ : m_usync(usync), m_mapname(mapname.c_str()), m_evtHandlerId(evtHandlerId), m_evtId(evtId) {}
+ };
+
+ class GetMapImageAsyncWorkItem : public GetMapImageAsyncResult
+ {
+ public:
+ void RunCore()
+ {
+ (m_usync->*m_loadMethod)( m_mapname );
+ }
+
+ LoadMethodPtr m_loadMethod;
+
+ GetMapImageAsyncWorkItem( SpringUnitSync* usync, const wxString& mapname, int evtHandlerId, LoadMethodPtr loadMethod )
+ : GetMapImageAsyncResult( usync, mapname, evtHandlerId, 1 ), m_loadMethod(loadMethod) {}
+ };
+
+ class GetScaledMapImageAsyncWorkItem : public GetMapImageAsyncResult
+ {
+ public:
+ void RunCore()
+ {
+ (m_usync->*m_loadMethod)( m_mapname, m_width, m_height );
+ }
+
+ int m_width;
+ int m_height;
+ ScaledLoadMethodPtr m_loadMethod;
+
+ GetScaledMapImageAsyncWorkItem( SpringUnitSync* usync, const wxString& mapname, int w, int h, int evtHandlerId, ScaledLoadMethodPtr loadMethod )
+ : GetMapImageAsyncResult( usync, mapname, evtHandlerId, 2 ), m_width(w), m_height(h), m_loadMethod(loadMethod) {}
+ };
+
+ class GetMapExAsyncWorkItem : public GetMapImageAsyncResult
+ {
+ public:
+ void RunCore()
+ {
+ m_usync->GetMapEx( m_mapname );
+ }
+
+ GetMapExAsyncWorkItem( SpringUnitSync* usync, const wxString& mapname, int evtHandlerId )
+ : GetMapImageAsyncResult( usync, mapname, evtHandlerId, 3 ) {}
+ };
+};
+
+
+void SpringUnitSync::PrefetchMap( const wxString& mapname )
+{
+ wxLogDebugFunc( mapname );
+
+ // Use a simple hash based on 3 characters from the mapname
+ // (without '.smf') as negative priority for the WorkItems.
+ // This ensures WorkItems for the same map are put together,
+ // which improves caching performance.
+
+ // Measured improvement: 60% more cache hits while populating replay tab.
+ // 50% hits without, 80% hits with this code. (cache size 20 images)
+
+ const int length = std::max(0, int(mapname.length()) - 4);
+ const int hash = (mapname[length * 1/4] << 16)
+ | (mapname[length * 2/4] << 8)
+ | (mapname[length * 3/4]);
+ const int priority = -hash;
+
+ {
+ CacheMinimapWorkItem* work;
+
+ work = new CacheMinimapWorkItem( mapname );
+ m_cache_thread.DoWork( work, priority );
+ }
+ {
+ CacheMapWorkItem* work;
+
+ work = new CacheMapWorkItem( this, mapname, &SpringUnitSync::GetMetalmap );
+ m_cache_thread.DoWork( work, priority );
+
+ work = new CacheMapWorkItem( this, mapname, &SpringUnitSync::GetHeightmap );
+ m_cache_thread.DoWork( work, priority );
+ }
+}
+
+int SpringUnitSync::RegisterEvtHandler( wxEvtHandler* evtHandler )
+{
+ return m_evt_handlers.Add( evtHandler );
+}
+
+void SpringUnitSync::UnregisterEvtHandler( int evtHandlerId )
+{
+ m_evt_handlers.Remove( evtHandlerId );
+}
+
+void SpringUnitSync::PostEvent( int evtHandlerId, wxEvent& evt )
+{
+ m_evt_handlers.PostEvent( evtHandlerId, evt );
+}
+
+void SpringUnitSync::_GetMapImageAsync( const wxString& mapname, wxImage (SpringUnitSync::*loadMethod)(const wxString&), int evtHandlerId )
+{
+ GetMapImageAsyncWorkItem* work;
+
+ work = new GetMapImageAsyncWorkItem( this, mapname, evtHandlerId, loadMethod );
+ m_cache_thread.DoWork( work, 100 );
+}
+
+void SpringUnitSync::GetMinimapAsync( const wxString& mapname, int evtHandlerId )
+{
+ wxLogDebugFunc( mapname );
+ _GetMapImageAsync( mapname, &SpringUnitSync::GetMinimap, evtHandlerId );
+}
+
+void SpringUnitSync::GetMinimapAsync( const wxString& mapname, int width, int height, int evtHandlerId )
+{
+ wxLogDebugFunc( mapname + _T(" size: ") + TowxString(width) + _T("x") + TowxString(height) );
+
+ GetScaledMapImageAsyncWorkItem* work;
+
+ work = new GetScaledMapImageAsyncWorkItem( this, mapname, width, height, evtHandlerId, &SpringUnitSync::GetMinimap );
+ m_cache_thread.DoWork( work, 100 );
+}
+
+void SpringUnitSync::GetMetalmapAsync( const wxString& mapname, int evtHandlerId )
+{
+ wxLogDebugFunc( mapname );
+ _GetMapImageAsync( mapname, &SpringUnitSync::GetMetalmap, evtHandlerId );
+}
+
+void SpringUnitSync::GetMetalmapAsync( const wxString& mapname, int width, int height, int evtHandlerId )
+{
+ GetMetalmapAsync( mapname, evtHandlerId );
+}
+
+void SpringUnitSync::GetHeightmapAsync( const wxString& mapname, int evtHandlerId )
+{
+ wxLogDebugFunc( mapname );
+ _GetMapImageAsync( mapname, &SpringUnitSync::GetHeightmap, evtHandlerId );
+}
+
+void SpringUnitSync::GetHeightmapAsync( const wxString& mapname, int width, int height, int evtHandlerId )
+{
+ GetHeightmapAsync( mapname, evtHandlerId );
+}
+
+void SpringUnitSync::GetMapExAsync( const wxString& mapname, int evtHandlerId )
+{
+ wxLogDebugFunc( mapname );
+
+ GetMapExAsyncWorkItem* work;
+
+ work = new GetMapExAsyncWorkItem( this, mapname, evtHandlerId );
+ m_cache_thread.DoWork( work, 200 /* higher prio then GetMinimapAsync */ );
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////// EvtHandlerCollection code
+
+int EvtHandlerCollection::Add( wxEvtHandler* evtHandler )
+{
+ wxCriticalSectionLocker lock(m_lock);
+ ++m_last_id;
+ m_items[m_last_id] = evtHandler;
+ return m_last_id;
+}
+
+void EvtHandlerCollection::Remove( int evtHandlerId )
+{
+ wxCriticalSectionLocker lock(m_lock);
+ EvtHandlerMap::iterator it = m_items.find( evtHandlerId );
+ if ( it != m_items.end() ) m_items.erase( it );
+}
+
+void EvtHandlerCollection::PostEvent( int evtHandlerId, wxEvent& evt )
+{
+ wxCriticalSectionLocker lock(m_lock);
+ EvtHandlerMap::iterator it = m_items.find( evtHandlerId );
+ if ( it != m_items.end() ) wxPostEvent( it->second, evt );
+}
diff --git a/src/springunitsync.h b/src/springunitsync.h
new file mode 100644
index 0000000..5c529f8
--- /dev/null
+++ b/src/springunitsync.h
@@ -0,0 +1,299 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SPRINGUNITSYNC_H
+#define SPRINGLOBBY_HEADERGUARD_SPRINGUNITSYNC_H
+
+#include <list>
+#include <map>
+
+#include "iunitsync.h"
+#include "thread.h"
+
+#include "utils/conversion.h" //remove after MRU impl moved to cpp
+#include "utils/debug.h" //remove after MRU impl moved to cpp
+#include <wx/log.h>//remove after MRU impl moved to cpp
+
+class wxCriticalSection;
+class wxDynamicLibrary;
+class wxImage;
+struct CachedMapInfo;
+struct SpringMapInfo;
+class SpringUnitSyncLib;
+
+typedef std::map<wxString,wxString> LocalArchivesVector;
+
+
+/// Thread safe MRU cache (works like a std::map but has maximum size)
+template<typename TKey, typename TValue>
+class MostRecentlyUsedCache
+{
+ public:
+ //! name parameter might be used to identify stats in dgb output
+ MostRecentlyUsedCache(int max_size, const wxString& name = _T("") )
+ : m_size(0), m_max_size(max_size), m_cache_hits(0), m_cache_misses(0), m_name(name)
+ {
+ }
+
+ ~MostRecentlyUsedCache()
+ {
+ wxLogDebugFunc( m_name + _T("cache hits: ") + TowxString( m_cache_hits ) );
+ wxLogDebugFunc( m_name + _T("cache misses: ") + TowxString( m_cache_misses ) );
+ }
+
+ void Add( const TKey& name, const TValue& img )
+ {
+ wxCriticalSectionLocker lock(m_lock);
+ while ( m_size >= m_max_size ) {
+ --m_size;
+ m_iterator_map.erase( m_items.back().first );
+ m_items.pop_back();
+ }
+ ++m_size;
+ m_items.push_front( CacheItem( name, img ) );
+ m_iterator_map[name] = m_items.begin();
+ }
+
+ bool TryGet( const TKey& name, TValue& img )
+ {
+ wxCriticalSectionLocker lock(m_lock);
+ typename IteratorMap::iterator it = m_iterator_map.find( name );
+ if ( it == m_iterator_map.end() ) {
+ ++m_cache_misses;
+ return false;
+ }
+ // reinsert at front, so that most recently used items are always at front
+ m_items.push_front( *it->second );
+ m_items.erase( it->second );
+ it->second = m_items.begin();
+ // return image
+ img = it->second->second;
+ ++m_cache_hits;
+ return true;
+ }
+
+ void Clear()
+ {
+ wxCriticalSectionLocker lock(m_lock);
+ m_size = 0;
+ m_items.clear();
+ m_iterator_map.clear();
+ }
+
+ private:
+ typedef std::pair<TKey, TValue> CacheItem;
+ typedef std::list<CacheItem> CacheItemList;
+ typedef std::map<TKey, typename CacheItemList::iterator> IteratorMap;
+
+ mutable wxCriticalSection m_lock;
+ CacheItemList m_items;
+ IteratorMap m_iterator_map;
+ int m_size;
+ const int m_max_size;
+ int m_cache_hits;
+ int m_cache_misses;
+ const wxString m_name;
+};
+
+typedef MostRecentlyUsedCache<wxString,wxImage> MostRecentlyUsedImageCache;
+typedef MostRecentlyUsedCache<wxString,MapInfo> MostRecentlyUsedMapInfoCache;
+typedef MostRecentlyUsedCache<wxString,wxArrayString> MostRecentlyUsedArrayStringCache;
+
+
+/// Thread safe mapping from evtHandlerId to wxEvtHandler*
+class EvtHandlerCollection
+{
+ public:
+ EvtHandlerCollection() : m_last_id(0) {}
+
+ int Add( wxEvtHandler* evtHandler );
+ void Remove( int evtHandlerId );
+ void PostEvent( int evtHandlerId, wxEvent& evt );
+
+ private:
+ typedef std::map<int, wxEvtHandler*> EvtHandlerMap;
+
+ mutable wxCriticalSection m_lock;
+ EvtHandlerMap m_items;
+ int m_last_id;
+};
+
+
+class SpringUnitSync : public IUnitSync
+{
+ public:
+ SpringUnitSync();
+ ~SpringUnitSync();
+
+ int GetNumMods();
+ wxArrayString GetModList();
+ bool ModExists( const wxString& modname );
+ bool ModExists( const wxString& modname, const wxString& hash );
+ bool ModExistsCheckHash( const wxString& hash ) const;
+ UnitSyncMod GetMod( const wxString& modname );
+ UnitSyncMod GetMod( int index );
+ int GetModIndex( const wxString& name );
+ wxString GetModArchive( int index );
+ GameOptions GetModOptions( const wxString& name );
+ wxArrayString GetModDeps( const wxString& name );
+
+ int GetNumMaps();
+ wxArrayString GetMapList();
+ wxArrayString GetModValidMapList( const wxString& modname );
+ bool MapExists( const wxString& mapname );
+ bool MapExists( const wxString& mapname, const wxString& hash );
+
+ UnitSyncMap GetMap( const wxString& mapname );
+ UnitSyncMap GetMap( int index );
+ UnitSyncMap GetMapEx( const wxString& mapname );
+ UnitSyncMap GetMapEx( int index );
+ wxString GetMapArchive( int index );
+ GameOptions GetMapOptions( const wxString& name );
+ wxArrayString GetMapDeps( const wxString& name );
+
+ //! function to fetch default singplayer/replay/savegame's default nick
+ wxString GetDefaultNick();
+ //! function to set default singplayer/replay/savegame's default nick
+ void SetDefaultNick( const wxString& nick );
+
+ int GetMapIndex( const wxString& name );
+
+ wxArrayString GetSides( const wxString& modname );
+ wxImage GetSidePicture( const wxString& modname, const wxString& SideName );
+
+ bool LoadUnitSyncLib( const wxString& unitsyncloc );
+ void FreeUnitSyncLib();
+
+ bool IsLoaded();
+
+ wxString GetSpringVersion();
+ //! function wich checks if the version returned from unitsync matches a table of supported feature
+ bool VersionSupports( GameFeature feature );
+
+ wxArrayString GetAIList( const wxString& modname );
+ wxArrayString GetAIInfos( int index );
+ GameOptions GetAIOptions( const wxString& modname, int index );
+
+
+ int GetNumUnits( const wxString& modname );
+ wxArrayString GetUnitsList( const wxString& modname );
+
+ /// get minimap with native width x height
+ wxImage GetMinimap( const wxString& mapname );
+ /// get minimap rescaled to given width x height
+ wxImage GetMinimap( const wxString& mapname, int width, int height );
+ /// get metalmap with native width x height
+ wxImage GetMetalmap( const wxString& mapname );
+ /// get metalmap rescaled to given width x height
+ wxImage GetMetalmap( const wxString& mapname, int width, int height );
+ /// get heightmap with native width x height
+ wxImage GetHeightmap( const wxString& mapname );
+ /// get heightmap rescaled to given width x height
+ wxImage GetHeightmap( const wxString& mapname, int width, int height );
+
+ bool ReloadUnitSyncLib();
+
+ void SetSpringDataPath( const wxString& path );
+
+ wxArrayString GetPlaybackList( bool ReplayType = true ); //savegames otehrwise
+
+ bool FileExists( const wxString& name );
+
+ wxString GetArchivePath( const wxString& name );
+
+ /// schedule a map for prefetching
+ void PrefetchMap( const wxString& mapname );
+
+ int RegisterEvtHandler( wxEvtHandler* evtHandler );
+ void UnregisterEvtHandler( int evtHandlerId );
+ void PostEvent( int evtHandlerId, wxEvent& evt ); // helper for WorkItems
+
+ void GetMinimapAsync( const wxString& mapname, int evtHandlerId );
+ void GetMinimapAsync( const wxString& mapname, int width, int height, int evtHandlerId );
+ void GetMetalmapAsync( const wxString& mapname, int evtHandlerId );
+ void GetMetalmapAsync( const wxString& mapname, int width, int height, int evtHandlerId );
+ void GetHeightmapAsync( const wxString& mapname, int evtHandlerId );
+ void GetHeightmapAsync( const wxString& mapname, int width, int height, int evtHandlerId );
+ void GetMapExAsync( const wxString& mapname, int evtHandlerId );
+
+ wxArrayString GetScreenshotFilenames();
+
+ private:
+
+ LocalArchivesVector m_maps_list; /// mapname -> hash
+ LocalArchivesVector m_mods_list; /// modname -> hash
+ LocalArchivesVector m_mods_unchained_hash; /// modname -> unchained hash
+ LocalArchivesVector m_maps_unchained_hash; /// mapname -> unchained hash
+ LocalArchivesVector m_mods_archive_name; /// modname -> archive name
+ LocalArchivesVector m_maps_archive_name; /// mapname -> archive name
+ wxArrayString m_map_array;
+ wxArrayString m_mod_array;
+
+ /// caches sett().GetCachePath(), because that method calls back into
+ /// susynclib(), there's a good chance main thread blocks on some
+ /// WorkerThread operation... cache is invalidated on reload.
+ wxString m_cache_path;
+
+ mutable wxCriticalSection m_lock;
+ WorkerThread m_cache_thread;
+ EvtHandlerCollection m_evt_handlers;
+
+ /// this cache facilitates async image fetching (image is stored in cache
+ /// in background thread, then main thread gets it from cache)
+ MostRecentlyUsedImageCache m_map_image_cache;
+ /// this cache is a real cache, it stores minimaps with max size 100x100
+ MostRecentlyUsedImageCache m_tiny_minimap_cache;
+
+ /// this caches MapInfo to facilitate GetMapExAsync
+ MostRecentlyUsedMapInfoCache m_mapinfo_cache;
+
+ MostRecentlyUsedArrayStringCache m_sides_cache;
+
+ //! this function returns only the cache path without the file extension,
+ //! the extension itself would be added in the function as needed
+ wxString GetFileCachePath( const wxString& name, const wxString& hash, bool IsMod );
+
+ //! returns an array where each element is a line of the file
+ wxArrayString GetCacheFile( const wxString& path );
+ //! write a file where each element of the array is a line
+ void SetCacheFile( const wxString& path, const wxArrayString& data );
+
+ bool _LoadUnitSyncLib( const wxString& unitsyncloc );
+ void _FreeUnitSyncLib();
+
+ bool _ModExists( const wxString& modname );
+ UnitSyncMod _GetMod( int index );
+ wxString _GetModArchive( int index );
+
+ int _GetMapIndex( const wxString& name );
+ UnitSyncMap _GetMap( int index, bool getmapinfo = false );
+ UnitSyncMap _GetMap( const wxString& mapname, bool getmapinfo = false );
+ UnitSyncMap _GetMapEx( const wxString& mapname, bool force = false );
+ MapInfo _GetMapInfoEx( const wxString& mapname );
+
+ void PopulateArchiveList();
+
+ double _GetSpringVersion();
+
+ wxImage _GetMapImage( const wxString& mapname, const wxString& imagename, wxImage (SpringUnitSyncLib::*loadMethod)(const wxString&) );
+ wxImage _GetScaledMapImage( const wxString& mapname, wxImage (SpringUnitSync::*loadMethod)(const wxString&), int width, int height );
+
+ void _GetMapImageAsync( const wxString& mapname, wxImage (SpringUnitSync::*loadMethod)(const wxString&), int evtHandlerId );
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_SPRINGUNITSYNC_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/springunitsynclib.cpp b/src/springunitsynclib.cpp
new file mode 100644
index 0000000..4cda251
--- /dev/null
+++ b/src/springunitsynclib.cpp
@@ -0,0 +1,1606 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include <wx/filename.h>
+#include <wx/dynlib.h>
+#include <wx/image.h>
+#include <wx/log.h>
+#include <stdexcept>
+#include <cmath>
+
+#include "springunitsynclib.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "utils/misc.h"
+#include "globalsmanager.h"
+
+#define LOCK_UNITSYNC wxCriticalSectionLocker lock_criticalsection(m_lock)
+
+//! Macro that checks if a function is present/loaded, unitsync is loaded, and locks it on call.
+#define InitLib( arg ) \
+ LOCK_UNITSYNC; \
+ UNITSYNC_EXCEPTION( m_loaded, _T("Unitsync not loaded.") ); \
+ UNITSYNC_EXCEPTION( arg, _T("Function was not in unitsync library.") );
+
+
+SpringUnitSyncLib::SpringUnitSyncLib():
+ m_loaded(false),
+ m_libhandle(NULL),
+ m_path(wxEmptyString),
+ m_init(NULL),
+ m_uninit(NULL)
+{
+}
+
+
+SpringUnitSyncLib::~SpringUnitSyncLib()
+{
+ Unload();
+}
+
+
+SpringUnitSyncLib& susynclib()
+{
+ static GlobalObjectHolder<SpringUnitSyncLib> lib;
+ return lib.GetInstance();
+}
+
+
+void SpringUnitSyncLib::Load( const wxString& path, const wxString& ForceConfigFilePath )
+{
+ LOCK_UNITSYNC;
+
+ _Load( path );
+
+ if ( !ForceConfigFilePath.IsEmpty() )
+ {
+ if ( m_set_spring_config_file_path )
+ {
+ m_set_spring_config_file_path( ForceConfigFilePath.mb_str() );
+ }
+ }
+
+ _Init();
+}
+
+
+void SpringUnitSyncLib::_Load( const wxString& path )
+{
+ if ( _IsLoaded() && path == m_path ) return;
+
+ _Unload();
+
+ m_path = path;
+
+ // Load the library.
+ wxLogMessage( _T("Loading from: %s"), path.c_str() );
+
+ // Check if library exists
+ if ( !wxFileName::FileExists( path ) )
+ {
+ wxLogError( _T("File not found: %s"), path.c_str() );
+ ASSERT_EXCEPTION( false, _T("Failed to load Unitsync lib.") );
+ }
+
+ {
+ wxLog *currentarget = wxLog::GetActiveTarget();
+ wxLog *templogger = new wxLogGui();
+ wxLog::SetActiveTarget( templogger );
+ try {
+ #ifdef __WXMSW__
+ wxSetWorkingDirectory( path.BeforeLast('\\') );
+ #endif
+ m_libhandle = new wxDynamicLibrary( path );
+ if ( !m_libhandle->IsLoaded() ) {
+ delete m_libhandle;
+ m_libhandle = 0;
+ }
+ } catch(...) {
+ m_libhandle = 0;
+ }
+ wxLog::SetActiveTarget( currentarget );
+ delete templogger;
+ }
+
+ ASSERT_EXCEPTION( m_libhandle != 0, _T("Couldn't load the unitsync library") );
+
+ // Load all function from library.
+ try {
+ m_init = (InitPtr)_GetLibFuncPtr(_T("Init"));
+ m_uninit = (UnInitPtr)_GetLibFuncPtr(_T("UnInit"));
+ m_get_next_error = (GetNextErrorPtr)_GetLibFuncPtr(_T("GetNextError"));
+ m_get_writeable_data_dir = (GetWritableDataDirectoryPtr)_GetLibFuncPtr(_T("GetWritableDataDirectory"));
+
+ m_get_map_count = (GetMapCountPtr)_GetLibFuncPtr(_T("GetMapCount"));
+ m_get_map_checksum = (GetMapChecksumPtr)_GetLibFuncPtr(_T("GetMapChecksum"));
+ m_get_map_name = (GetMapNamePtr)_GetLibFuncPtr(_T("GetMapName"));
+ m_get_map_info_ex = (GetMapInfoExPtr)_GetLibFuncPtr(_T("GetMapInfoEx"));
+ m_get_minimap = (GetMinimapPtr)_GetLibFuncPtr(_T("GetMinimap"));
+ m_get_infomap_size = (GetInfoMapSizePtr)_GetLibFuncPtr(_T("GetInfoMapSize"));
+ m_get_infomap = (GetInfoMapPtr)_GetLibFuncPtr(_T("GetInfoMap"));
+
+ m_get_mod_checksum = (GetPrimaryModChecksumPtr)_GetLibFuncPtr(_T("GetPrimaryModChecksum"));
+ m_get_mod_index = (GetPrimaryModIndexPtr)_GetLibFuncPtr(_T("GetPrimaryModIndex"));
+ m_get_mod_name = (GetPrimaryModNamePtr)_GetLibFuncPtr(_T("GetPrimaryModName"));
+ m_get_mod_count = (GetPrimaryModCountPtr)_GetLibFuncPtr(_T("GetPrimaryModCount"));
+ m_get_mod_archive = (GetPrimaryModArchivePtr)_GetLibFuncPtr(_T("GetPrimaryModArchive"));
+
+ m_get_side_count = (GetSideCountPtr)_GetLibFuncPtr(_T("GetSideCount"));
+ m_get_side_name = (GetSideNamePtr)_GetLibFuncPtr(_T("GetSideName"));
+
+ m_add_all_archives = (AddAllArchivesPtr)_GetLibFuncPtr(_T("AddAllArchives"));
+ m_remove_all_archives = (RemoveAllArchivesPtr)_GetLibFuncPtr(_T("RemoveAllArchives"));
+
+ m_get_unit_count = (GetUnitCountPtr)_GetLibFuncPtr(_T("GetUnitCount"));
+ m_get_unit_name = (GetUnitNamePtr)_GetLibFuncPtr(_T("GetUnitName"));
+ m_get_unit_full_name = (GetFullUnitNamePtr)_GetLibFuncPtr(_T("GetFullUnitName"));
+ m_proc_units_nocheck = (ProcessUnitsNoChecksumPtr)_GetLibFuncPtr(_T("ProcessUnitsNoChecksum"));
+
+ m_init_find_vfs = (InitFindVFSPtr)_GetLibFuncPtr(_T("InitFindVFS"));
+ m_find_files_vfs = (FindFilesVFSPtr)_GetLibFuncPtr(_T("FindFilesVFS"));
+ m_open_file_vfs = (OpenFileVFSPtr)_GetLibFuncPtr(_T("OpenFileVFS"));
+ m_file_size_vfs = (FileSizeVFSPtr)_GetLibFuncPtr(_T("FileSizeVFS"));
+ m_read_file_vfs = (ReadFileVFSPtr)_GetLibFuncPtr(_T("ReadFileVFS"));
+ m_close_file_vfs = (CloseFileVFSPtr)_GetLibFuncPtr(_T("CloseFileVFS"));
+
+ m_get_spring_version = (GetSpringVersionPtr)_GetLibFuncPtr(_T("GetSpringVersion"));
+
+ m_process_units = (ProcessUnitsPtr)_GetLibFuncPtr(_T("ProcessUnits"));
+ m_add_archive = (AddArchivePtr)_GetLibFuncPtr(_T("AddArchive"));
+ m_get_archive_checksum = (GetArchiveChecksumPtr)_GetLibFuncPtr(_T("GetArchiveChecksum"));
+ m_get_archive_path = (GetArchivePathPtr)_GetLibFuncPtr(_T("GetArchivePath"));
+
+ m_get_map_archive_count = (GetMapArchiveCountPtr)_GetLibFuncPtr(_T("GetMapArchiveCount"));
+ m_get_map_archive_name = (GetMapArchiveNamePtr)_GetLibFuncPtr(_T("GetMapArchiveName"));
+ m_get_map_checksum = (GetMapChecksumPtr)_GetLibFuncPtr(_T("GetMapChecksum"));
+ m_get_map_checksum_from_name = (GetMapChecksumFromNamePtr)_GetLibFuncPtr(_T("GetMapChecksumFromName"));
+
+ m_get_primary_mod_short_name = (GetPrimaryModShortNamePtr)_GetLibFuncPtr(_T("GetPrimaryModShortName"));
+ m_get_primary_mod_version = (GetPrimaryModVersionPtr)_GetLibFuncPtr(_T("GetPrimaryModVersion"));
+ m_get_primary_mod_mutator = (GetPrimaryModMutatorPtr)_GetLibFuncPtr(_T("GetPrimaryModMutator"));
+ m_get_primary_mod_game = (GetPrimaryModGamePtr)_GetLibFuncPtr(_T("GetPrimaryModGame"));
+ m_get_primary_mod_short_game = (GetPrimaryModShortGamePtr)_GetLibFuncPtr(_T("GetPrimaryModShortGame"));
+ m_get_primary_mod_description = (GetPrimaryModDescriptionPtr)_GetLibFuncPtr(_T("GetPrimaryModDescription"));
+ m_get_primary_mod_archive = (GetPrimaryModArchivePtr)_GetLibFuncPtr(_T("GetPrimaryModArchive"));
+ m_get_primary_mod_archive_count = (GetPrimaryModArchiveCountPtr)_GetLibFuncPtr(_T("GetPrimaryModArchiveCount"));
+ m_get_primary_mod_archive_list = (GetPrimaryModArchiveListPtr)_GetLibFuncPtr(_T("GetPrimaryModArchiveList"));
+ m_get_primary_mod_checksum_from_name = (GetPrimaryModChecksumFromNamePtr)_GetLibFuncPtr(_T("GetPrimaryModChecksumFromName"));
+
+ m_get_mod_valid_map_count = (GetModValidMapCountPtr)_GetLibFuncPtr(_T("GetModValidMapCount"));
+ m_get_valid_map = (GetModValidMapPtr)_GetLibFuncPtr(_T("GetModValidMap"));
+
+ m_get_luaai_count = (GetLuaAICountPtr)_GetLibFuncPtr(_T("GetLuaAICount"));
+ m_get_luaai_name = (GetLuaAINamePtr)_GetLibFuncPtr(_T("GetLuaAIName"));
+ m_get_luaai_desc = (GetLuaAIDescPtr)_GetLibFuncPtr(_T("GetLuaAIDesc"));
+
+ m_get_map_option_count = (GetMapOptionCountPtr)_GetLibFuncPtr(_T("GetMapOptionCount"));
+ m_get_mod_option_count = (GetModOptionCountPtr)_GetLibFuncPtr(_T("GetModOptionCount"));
+ m_get_skirmish_ai_option_count = (GetSkirmishAIOptionCountPtr)_GetLibFuncPtr(_T("GetSkirmishAIOptionCount"));
+ m_get_option_key = (GetOptionKeyPtr)_GetLibFuncPtr(_T("GetOptionKey"));
+ m_get_option_name = (GetOptionNamePtr)_GetLibFuncPtr(_T("GetOptionName"));
+ m_get_option_desc = (GetOptionDescPtr)_GetLibFuncPtr(_T("GetOptionDesc"));
+ m_get_option_type = (GetOptionTypePtr)_GetLibFuncPtr(_T("GetOptionType"));
+ m_get_option_section = (GetOptionSectionPtr)_GetLibFuncPtr(_T("GetOptionSection"));
+ m_get_option_style = (GetOptionStylePtr)_GetLibFuncPtr(_T("GetOptionStyle"));
+ m_get_option_bool_def = (GetOptionBoolDefPtr)_GetLibFuncPtr(_T("GetOptionBoolDef"));
+ m_get_option_number_def = (GetOptionNumberDefPtr)_GetLibFuncPtr(_T("GetOptionNumberDef"));
+ m_get_option_number_min = (GetOptionNumberMinPtr)_GetLibFuncPtr(_T("GetOptionNumberMin"));
+ m_get_option_number_max = (GetOptionNumberMaxPtr)_GetLibFuncPtr(_T("GetOptionNumberMax"));
+ m_get_option_number_step = (GetOptionNumberStepPtr)_GetLibFuncPtr(_T("GetOptionNumberStep"));
+ m_get_option_string_def = (GetOptionStringDefPtr)_GetLibFuncPtr(_T("GetOptionStringDef"));
+ m_get_option_string_max_len = (GetOptionStringMaxLenPtr)_GetLibFuncPtr(_T("GetOptionStringMaxLen"));
+ m_get_option_list_count = (GetOptionListCountPtr)_GetLibFuncPtr(_T("GetOptionListCount"));
+ m_get_option_list_def = (GetOptionListDefPtr)_GetLibFuncPtr(_T("GetOptionListDef"));
+ m_get_option_list_item_key = (GetOptionListItemKeyPtr)_GetLibFuncPtr(_T("GetOptionListItemKey"));
+ m_get_option_list_item_name = (GetOptionListItemNamePtr)_GetLibFuncPtr(_T("GetOptionListItemName"));
+ m_get_option_list_item_desc = (GetOptionListItemDescPtr)_GetLibFuncPtr(_T("GetOptionListItemDesc"));
+
+ m_set_spring_config_file_path = (SetSpringConfigFilePtr)_GetLibFuncPtr(_T("SetSpringConfigFile"));
+ m_get_spring_config_file_path = (GetSpringConfigFilePtr)_GetLibFuncPtr(_T("GetSpringConfigFile"));
+
+ m_open_archive = (OpenArchivePtr)_GetLibFuncPtr(_T("OpenArchive"));
+ m_close_archive = (CloseArchivePtr)_GetLibFuncPtr(_T("CloseArchive"));
+ m_find_Files_archive = (FindFilesArchivePtr)_GetLibFuncPtr(_T("FindFilesArchive"));
+ m_open_archive_file = (OpenArchiveFilePtr)_GetLibFuncPtr(_T("OpenArchiveFile"));
+ m_read_archive_file = (ReadArchiveFilePtr)_GetLibFuncPtr(_T("ReadArchiveFile"));
+ m_close_archive_file = (CloseArchiveFilePtr)_GetLibFuncPtr(_T("CloseArchiveFile"));
+ m_size_archive_file = (SizeArchiveFilePtr)_GetLibFuncPtr(_T("SizeArchiveFile"));
+
+ m_set_spring_config_float = (SetSpringConfigFloatPtr)_GetLibFuncPtr(_T("SetSpringConfigFloat"));
+ m_get_spring_config_float = (GetSpringConfigFloatPtr)_GetLibFuncPtr(_T("GetSpringConfigFloat"));
+ m_get_spring_config_int = (GetSpringConfigIntPtr)_GetLibFuncPtr(_T("GetSpringConfigInt"));
+ m_get_spring_config_string = (GetSpringConfigStringPtr)_GetLibFuncPtr(_T("GetSpringConfigString"));
+ m_set_spring_config_string = (SetSpringConfigStringPtr)_GetLibFuncPtr(_T("SetSpringConfigString"));
+ m_set_spring_config_int = (SetSpringConfigIntPtr)_GetLibFuncPtr(_T("SetSpringConfigInt"));
+
+ m_get_skirmish_ai_count = (GetSkirmishAICountPtr)_GetLibFuncPtr(_T("GetSkirmishAICount"));
+ m_get_skirmish_ai_info_count = (GetSkirmishAIInfoCountPtr)_GetLibFuncPtr(_T("GetSkirmishAIInfoCount"));
+ m_get_skirmish_ai_info_key = (GetInfoKeyPtr)_GetLibFuncPtr(_T("GetInfoKey"));
+ m_get_skirmish_ai_info_value = (GetInfoValuePtr)_GetLibFuncPtr(_T("GetInfoValue"));
+ m_get_skirmish_ai_info_description = (GetInfoDescriptionPtr)_GetLibFuncPtr(_T("GetInfoDescription"));
+
+ // begin lua parser calls
+
+ m_parser_close = (lpClosePtr)_GetLibFuncPtr(_T("lpClose"));
+ m_parser_open_file = (lpOpenFilePtr)_GetLibFuncPtr(_T("lpOpenFile"));
+ m_parser_open_source = (lpOpenSourcePtr)_GetLibFuncPtr(_T("lpOpenSource"));
+ m_parser_execute = (lpExecutePtr)_GetLibFuncPtr(_T("lpExecute"));
+ m_parser_error_log = (lpErrorLogPtr)_GetLibFuncPtr(_T("lpErrorLog"));
+
+ m_parser_add_table_int = (lpAddTableIntPtr)_GetLibFuncPtr(_T("lpAddTableInt"));
+ m_parser_add_table_string = (lpAddTableStrPtr)_GetLibFuncPtr(_T("lpAddTableStr"));
+ m_parser_end_table = (lpEndTablePtr)_GetLibFuncPtr(_T("lpEndTable"));
+ m_parser_add_int_key_int_value = (lpAddIntKeyIntValPtr)_GetLibFuncPtr(_T("lpAddIntKeyIntVal"));
+ m_parser_add_string_key_int_value = (lpAddStrKeyIntValPtr)_GetLibFuncPtr(_T("lpAddStrKeyIntVal"));
+ m_parser_add_int_key_bool_value = (lpAddIntKeyBoolValPtr)_GetLibFuncPtr(_T("lpAddIntKeyBoolVal"));
+ m_parser_add_string_key_bool_value = (lpAddStrKeyBoolValPtr)_GetLibFuncPtr(_T("lpAddStrKeyBoolVal"));
+ m_parser_add_int_key_float_value = (lpAddIntKeyFloatValPtr)_GetLibFuncPtr(_T("lpAddIntKeyFloatVal"));
+ m_parser_add_string_key_float_value = (lpAddStrKeyFloatValPtr)_GetLibFuncPtr(_T("lpAddStrKeyFloatVal"));
+ m_parser_add_int_key_string_value = (lpAddIntKeyStrValPtr)_GetLibFuncPtr(_T("lpAddIntKeyStrVal"));
+ m_parser_add_string_key_string_value = (lpAddStrKeyStrValPtr)_GetLibFuncPtr(_T("lpAddStrKeyStrVal"));
+
+ m_parser_root_table = (lpRootTablePtr)_GetLibFuncPtr(_T("lpRootTable"));
+ m_parser_root_table_expression = (lpRootTableExprPtr)_GetLibFuncPtr(_T("lpRootTableExpr"));
+ m_parser_sub_table_int = (lpSubTableIntPtr)_GetLibFuncPtr(_T("lpSubTableInt"));
+ m_parser_sub_table_string = (lpSubTableStrPtr)_GetLibFuncPtr(_T("lpSubTableStr"));
+ m_parser_sub_table_expression = (lpSubTableExprPtr)_GetLibFuncPtr(_T("lpSubTableExpr"));
+ m_parser_pop_table = (lpPopTablePtr)_GetLibFuncPtr(_T("lpPopTable"));
+
+ m_parser_key_int_exists = (lpGetKeyExistsIntPtr)_GetLibFuncPtr(_T("lpGetKeyExistsInt"));
+ m_parser_key_string_exists = (lpGetKeyExistsStrPtr)_GetLibFuncPtr(_T("lpGetKeyExistsStr"));
+
+ m_parser_int_key_get_type = (lpGetIntKeyTypePtr)_GetLibFuncPtr(_T("lpGetIntKeyType"));
+ m_parser_string_key_get_type = (lpGetStrKeyTypePtr)_GetLibFuncPtr(_T("lpGetStrKeyType"));
+
+ m_parser_int_key_get_list_count = (lpGetIntKeyListCountPtr)_GetLibFuncPtr(_T("lpGetIntKeyListCount"));
+ m_parser_int_key_get_list_entry = (lpGetIntKeyListEntryPtr)_GetLibFuncPtr(_T("lpGetIntKeyListEntry"));
+ m_parser_string_key_get_list_count = (lpGetStrKeyListCountPtr)_GetLibFuncPtr(_T("lpGetStrKeyListCount"));
+ m_parser_string_key_get_list_entry = (lpGetStrKeyListEntryPtr)_GetLibFuncPtr(_T("lpGetStrKeyListEntry"));
+
+ m_parser_int_key_get_int_value = (lpGetIntKeyIntValPtr)_GetLibFuncPtr(_T("lpGetIntKeyIntVal"));
+ m_parser_string_key_get_int_value = (lpGetStrKeyIntValPtr)_GetLibFuncPtr(_T("lpGetStrKeyIntVal"));
+ m_parser_int_key_get_bool_value = (lpGetIntKeyBoolValPtr)_GetLibFuncPtr(_T("lpGetIntKeyBoolVal"));
+ m_parser_string_key_get_bool_value = (lpGetStrKeyBoolValPtr)_GetLibFuncPtr(_T("lpGetStrKeyBoolVal"));
+ m_parser_int_key_get_float_value = (lpGetIntKeyFloatValPtr)_GetLibFuncPtr(_T("lpGetIntKeyFloatVal"));
+ m_parser_string_key_get_float_value = (lpGetStrKeyFloatValPtr)_GetLibFuncPtr(_T("lpGetStrKeyFloatVal"));
+ m_parser_int_key_get_string_value = (lpGetIntKeyStrValPtr)_GetLibFuncPtr(_T("lpGetIntKeyStrVal"));
+ m_parser_string_key_get_string_value = (lpGetStrKeyStrValPtr)_GetLibFuncPtr(_T("lpGetStrKeyStrVal"));
+
+ // only when we end up here unitsync was succesfully loaded.
+ m_loaded = true;
+ }
+ catch ( ... )
+ {
+ // don't uninit unitsync in _Unload -- it hasn't been init'ed yet
+ m_uninit = NULL;
+ _Unload();
+ ASSERT_EXCEPTION( false, _T("Failed to load Unitsync lib.") );
+ }
+}
+
+
+void SpringUnitSyncLib::_Init()
+{
+ if ( _IsLoaded() && m_init != NULL )
+ {
+ wxLog *currentarget = wxLog::GetActiveTarget();
+ wxLog *templogger = new wxLogGui();
+ wxLog::SetActiveTarget( templogger );
+
+ m_current_mod = wxEmptyString;
+ m_init( true, 1 );
+
+ wxArrayString errors = GetUnitsyncErrors();
+ for ( unsigned int i = 0; i < errors.GetCount(); i++ )
+ {
+ wxLogError( _T("%s"), errors[i].c_str() );
+ }
+
+ wxLog::SetActiveTarget( currentarget );
+ delete templogger;
+ }
+}
+
+
+void SpringUnitSyncLib::_RemoveAllArchives()
+{
+ if (m_remove_all_archives)
+ m_remove_all_archives();
+ else
+ _Init();
+}
+
+
+void SpringUnitSyncLib::Unload()
+{
+ if ( !_IsLoaded() ) return;// dont even lock anything if unloaded.
+ LOCK_UNITSYNC;
+
+ _Unload();
+}
+
+
+void SpringUnitSyncLib::_Unload()
+{
+ // as soon as we enter m_uninit unitsync technically isn't loaded anymore.
+ m_loaded = false;
+
+ m_path = wxEmptyString;
+
+ // can't call UnSetCurrentMod() because it takes the unitsync lock
+ m_current_mod = wxEmptyString;
+
+ if (m_uninit)
+ m_uninit();
+
+ delete m_libhandle;
+ m_libhandle = NULL;
+
+ m_init = NULL;
+ m_uninit = NULL;
+}
+
+
+bool SpringUnitSyncLib::IsLoaded()
+{
+ return m_loaded;
+}
+
+
+bool SpringUnitSyncLib::_IsLoaded()
+{
+ return m_loaded;
+}
+
+
+void SpringUnitSyncLib::AssertUnitsyncOk()
+{
+ UNITSYNC_EXCEPTION( m_loaded, _T("Unitsync not loaded.") );
+ UNITSYNC_EXCEPTION( m_get_next_error, _T("Function was not in unitsync library.") );
+ UNITSYNC_EXCEPTION( false, WX_STRINGC( m_get_next_error() ) );
+}
+
+
+wxArrayString SpringUnitSyncLib::GetUnitsyncErrors()
+{
+ wxArrayString ret;
+ try
+ {
+ UNITSYNC_EXCEPTION( m_loaded, _T("Unitsync not loaded.") );
+ UNITSYNC_EXCEPTION( m_get_next_error, _T("Function was not in unitsync library.") );
+
+ wxString msg = WX_STRINGC( m_get_next_error() );
+ while ( !msg.IsEmpty() )
+ {
+ ret.Add( msg );
+ msg = WX_STRINGC( m_get_next_error() );
+ }
+ return ret;
+ }
+ catch ( unitsync_assert &e )
+ {
+ ret.Add( WX_STRINGC( e.what() ) );
+ return ret;
+ }
+}
+
+
+bool SpringUnitSyncLib::VersionSupports( IUnitSync::GameFeature feature )
+{
+ LOCK_UNITSYNC;
+
+ switch (feature)
+ {
+ case IUnitSync::USYNC_Sett_Handler: return m_set_spring_config_string;
+ case IUnitSync::USYNC_GetInfoMap: return m_get_infomap_size;
+ case IUnitSync::USYNC_GetDataDir: return m_get_writeable_data_dir;
+ case IUnitSync::USYNC_GetSkirmishAI: return m_get_skirmish_ai_count;
+ default: return false;
+ }
+}
+
+
+void* SpringUnitSyncLib::_GetLibFuncPtr( const wxString& name )
+{
+ ASSERT_LOGIC( m_libhandle != 0, _T("Unitsync not loaded") );
+ if ( m_libhandle->HasSymbol( name ) ){
+ void* ptr = m_libhandle->GetSymbol( name );
+ if ( !ptr ) wxLogMessage( _T("Couldn't load %s from unitsync library"),name.c_str() );
+ return ptr;
+ }
+ wxLogMessage( _T("Couldn't load %s from unitsync library"), name.c_str() );
+ return 0;
+}
+
+
+void SpringUnitSyncLib::_ConvertSpringMapInfo( const SpringMapInfo& in, MapInfo& out )
+{
+ out.author = WX_STRINGC(in.author);
+ out.description = WX_STRINGC(in.description);
+
+ out.extractorRadius = in.extractorRadius;
+ out.gravity = in.gravity;
+ out.tidalStrength = in.tidalStrength;
+ out.maxMetal = in.maxMetal;
+ out.minWind = in.minWind;
+ out.maxWind = in.maxWind;
+
+ out.width = in.width;
+ out.height = in.height;
+ out.posCount = in.posCount;
+ for ( int i = 0; i < in.posCount; i++) out.positions[i] = in.positions[i];
+}
+
+
+void SpringUnitSyncLib::SetCurrentMod( const wxString& modname )
+{
+ InitLib( m_init ); // assumes the others are fine
+ // (m_add_all_archives, m_get_mod_archive, m_get_mod_index)
+
+ _SetCurrentMod( modname );
+}
+
+
+void SpringUnitSyncLib::_SetCurrentMod( const wxString& modname )
+{
+ if ( m_current_mod != modname )
+ {
+ wxLogDebugFunc( modname );
+ if ( !m_current_mod.IsEmpty() ) _RemoveAllArchives();
+ m_add_all_archives( m_get_mod_archive( m_get_mod_index( modname.mb_str( wxConvUTF8 ) ) ) );
+ m_current_mod = modname;
+ }
+}
+
+
+void SpringUnitSyncLib::UnSetCurrentMod( )
+{
+ LOCK_UNITSYNC;
+ if ( !m_current_mod.IsEmpty() ) _RemoveAllArchives();
+ m_current_mod = wxEmptyString;
+}
+
+
+int SpringUnitSyncLib::GetModIndex( const wxString& name )
+{
+ return GetPrimaryModIndex( name );
+}
+
+
+std::map<wxString, wxString> SpringUnitSyncLib::GetSpringVersionList(const std::map<wxString, wxString>& usync_paths)
+{
+ LOCK_UNITSYNC;
+ wxLogDebugFunc(_T(""));
+
+ std::map<wxString, wxString> ret;
+
+ for (std::map<wxString, wxString>::const_iterator it = usync_paths.begin(); it != usync_paths.end(); ++it)
+ {
+ wxString path = it->second;
+ try
+ {
+
+ if ( !wxFileName::FileExists( path ) )
+ {
+ wxLogError( _T("File not found: %s"), path.c_str() );
+ ASSERT_EXCEPTION( false, _T("Failed to load Unitsync lib.") );
+ }
+
+ #ifdef __WXMSW__
+ wxSetWorkingDirectory( path.BeforeLast('\\') );
+ #endif
+ wxDynamicLibrary temphandle( path );
+ ASSERT_EXCEPTION( temphandle.IsLoaded(), _T("Couldn't load the unitsync library") );
+
+ GetSpringVersionPtr getspringversion = 0;
+ wxString functionname = _T("GetSpringVersion");
+ if ( temphandle.HasSymbol( functionname ) )
+ {
+ getspringversion = (GetSpringVersionPtr)temphandle.GetSymbol( functionname );
+ }
+ UNITSYNC_EXCEPTION( getspringversion, _T("getspringversion: function not found") );
+ wxString version = WX_STRINGC( getspringversion() );
+ wxLogMessage( _T("Found spring version: %s"), version.c_str() );
+ ret[it->first] = version;
+
+ }
+ catch(...){}
+ }
+
+ return ret;
+}
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // -- The UnitSync functions --
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+wxString SpringUnitSyncLib::GetSpringVersion()
+{
+ InitLib( m_get_spring_version );
+
+ return WX_STRINGC( m_get_spring_version() );
+}
+
+wxString SpringUnitSyncLib::GetSpringDataDir()
+{
+ InitLib( m_get_writeable_data_dir );
+
+ return WX_STRINGC( m_get_writeable_data_dir() );
+}
+
+wxString SpringUnitSyncLib::GetConfigFilePath()
+{
+ InitLib( m_get_spring_config_file_path );
+
+ return WX_STRINGC( m_get_spring_config_file_path() );
+}
+
+
+int SpringUnitSyncLib::GetMapCount()
+{
+ InitLib( m_get_map_count );
+
+ return m_get_map_count();
+}
+
+
+wxString SpringUnitSyncLib::GetMapChecksum( int index )
+{
+ InitLib( m_get_map_checksum );
+
+ return TowxString( (unsigned int)m_get_map_checksum( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetMapName( int index )
+{
+ InitLib( m_get_map_name );
+
+ return WX_STRINGC( m_get_map_name( index ) );
+}
+
+
+int SpringUnitSyncLib::GetMapArchiveCount( int index )
+{
+ InitLib( m_get_map_archive_count );
+
+ return m_get_map_archive_count( m_get_map_name( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetMapArchiveName( int arnr )
+{
+ InitLib( m_get_map_archive_name );
+
+ return WX_STRINGC( m_get_map_archive_name( arnr ) );
+}
+
+
+wxArrayString SpringUnitSyncLib::GetMapDeps( int index )
+{
+ int count = GetMapArchiveCount( index );
+ wxArrayString ret;
+ for ( int i = 0; i < count; i++ )
+ {
+ ret.Add( GetMapArchiveName( i ) );
+ }
+ return ret;
+}
+
+
+MapInfo SpringUnitSyncLib::GetMapInfoEx( const wxString& mapName, int version )
+{
+ InitLib( m_get_map_info_ex );
+
+ char tmpdesc[256];
+ char tmpauth[256];
+
+ MapInfo info;
+
+ SpringMapInfo tm;
+ tm.description = &tmpdesc[0];
+ tm.author = &tmpauth[0];
+
+ bool result = m_get_map_info_ex( mapName.mb_str( wxConvUTF8 ), &tm, version );
+ ASSERT_EXCEPTION( result, _T("Failed to get map infos") );
+ _ConvertSpringMapInfo( tm, info );
+
+ return info;
+}
+
+
+wxImage SpringUnitSyncLib::GetMinimap( const wxString& mapFileName )
+{
+ InitLib( m_get_minimap );
+
+ const int miplevel = 0; // miplevel should not be 10 ffs
+ const int width = 1024 >> miplevel;
+ const int height = 1024 >> miplevel;
+
+ wxLogMessage( _T("Minimap: %s"), mapFileName.c_str() );
+
+ // this unitsync call returns a pointer to a static buffer
+ unsigned short* colours = (unsigned short*)m_get_minimap( mapFileName.mb_str(wxConvUTF8), miplevel );
+ ASSERT_EXCEPTION( colours, _T("Get minimap failed") );
+
+ typedef unsigned char uchar;
+ wxImage minimap(width, height, false);
+ uchar* true_colours = minimap.GetData();
+
+ for ( int i = 0; i < width*height; i++ ) {
+ true_colours[(i*3) ] = uchar( (( colours[i] >> 11 )/31.0)*255.0 );
+ true_colours[(i*3)+1] = uchar( (( (colours[i] >> 5) & 63 )/63.0)*255.0 );
+ true_colours[(i*3)+2] = uchar( (( colours[i] & 31 )/31.0)*255.0 );
+ }
+
+ return minimap;
+}
+
+
+wxImage SpringUnitSyncLib::GetMetalmap( const wxString& mapFileName )
+{
+ InitLib( m_get_infomap_size ); // assume GetInfoMap is available too
+
+ wxLogMessage( _T("Metalmap: %s"), mapFileName.c_str() );
+
+ int width = 0, height = 0, retval;
+
+ retval = m_get_infomap_size(mapFileName.mb_str(wxConvUTF8), "metal", &width, &height);
+ ASSERT_EXCEPTION( retval != 0 && width * height != 0, _T("Get metalmap size failed") );
+
+ typedef unsigned char uchar;
+ wxImage metalmap(width, height, false);
+ uninitialized_array<uchar> grayscale(width * height);
+ uchar* true_colours = metalmap.GetData();
+
+ retval = m_get_infomap(mapFileName.mb_str(wxConvUTF8), "metal", grayscale, 1 /*byte per pixel*/);
+ ASSERT_EXCEPTION( retval != 0, _T("Get metalmap failed") );
+
+ for ( int i = 0; i < width*height; i++ ) {
+ true_colours[(i*3) ] = 0;
+ true_colours[(i*3)+1] = grayscale[i];
+ true_colours[(i*3)+2] = 0;
+ }
+
+ return metalmap;
+}
+
+
+wxImage SpringUnitSyncLib::GetHeightmap( const wxString& mapFileName )
+{
+ InitLib( m_get_infomap_size ); // assume GetInfoMap is available too
+
+ wxLogMessage( _T("Heightmap: %s"), mapFileName.c_str() );
+
+ int width = 0, height = 0, retval;
+
+ retval = m_get_infomap_size(mapFileName.mb_str(wxConvUTF8), "height", &width, &height);
+ ASSERT_EXCEPTION( retval != 0 && width * height != 0, _T("Get heightmap size failed") );
+
+ typedef unsigned char uchar;
+ typedef unsigned short ushort;
+ wxImage heightmap(width, height, false);
+ uninitialized_array<ushort> grayscale(width * height);
+ uchar* true_colours = heightmap.GetData();
+
+ retval = m_get_infomap(mapFileName.mb_str(wxConvUTF8), "height", grayscale, 2 /*byte per pixel*/);
+ ASSERT_EXCEPTION( retval != 0, _T("Get heightmap failed") );
+
+ // the height is mapped to this "palette" of colors
+ // the colors are linearly interpolated
+
+ const uchar points[][3] = {
+ { 0, 0, 0 },
+ { 0, 0, 255 },
+ { 0, 255, 255 },
+ { 0, 255, 0 },
+ { 255, 255, 0 },
+ { 255, 0, 0 },
+ };
+ const int numPoints = sizeof(points) / sizeof(points[0]);
+
+ // find range of values present in the height data returned by unitsync
+ int min = 65536;
+ int max = 0;
+
+ for ( int i = 0; i < width*height; i++ ) {
+ if (grayscale[i] < min) min = grayscale[i];
+ if (grayscale[i] > max) max = grayscale[i];
+ }
+
+ // prevent division by zero -- heightmap wouldn't contain any information anyway
+ if (min == max)
+ return wxImage( 1, 1 );
+
+ // perform the mapping from 16 bit grayscale to 24 bit true colour
+ const double range = max - min + 1;
+ for ( int i = 0; i < width*height; i++ ) {
+ const double value = (grayscale[i] - min) / (range / (numPoints - 1));
+ const int idx1 = int(value);
+ const int idx2 = idx1 + 1;
+ const int t = int(256.0 * (value - std::floor(value)));
+
+ //assert(idx1 >= 0 && idx1 < numPoints-1);
+ //assert(idx2 >= 1 && idx2 < numPoints);
+ //assert(t >= 0 && t <= 255);
+
+ for ( int j = 0; j < 3; ++j)
+ true_colours[(i*3)+j] = (points[idx1][j] * (255 - t) + points[idx2][j] * t) / 255;
+ }
+
+ return heightmap;
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModChecksum( int index )
+{
+ InitLib( m_get_mod_checksum );
+
+ return TowxString( (unsigned int)m_get_mod_checksum( index ) );
+}
+
+
+int SpringUnitSyncLib::GetPrimaryModIndex( const wxString& modName )
+{
+ InitLib( m_get_mod_index );
+
+ return m_get_mod_index( modName.mb_str( wxConvUTF8 ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModName( int index )
+{
+ InitLib( m_get_mod_name );
+
+ return WX_STRINGC( m_get_mod_name( index ) );
+}
+
+
+int SpringUnitSyncLib::GetPrimaryModCount()
+{
+ InitLib( m_get_mod_count );
+
+ return m_get_mod_count();
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModArchive( int index )
+{
+ InitLib( m_get_mod_archive );
+ UNITSYNC_EXCEPTION( m_get_mod_count, _T("Function was not in unitsync library.") );
+
+ int count = m_get_mod_count();
+ UNITSYNC_EXCEPTION( index < count, _T("index out of bounds") );
+ return WX_STRINGC( m_get_mod_archive( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModShortName( int index )
+{
+ InitLib( m_get_primary_mod_short_name );
+
+ return WX_STRINGC( m_get_primary_mod_short_name( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModVersion( int index )
+{
+ InitLib( m_get_primary_mod_version );
+
+ return WX_STRINGC( m_get_primary_mod_version( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModMutator( int index )
+{
+ InitLib( m_get_primary_mod_mutator );
+
+ return WX_STRINGC( m_get_primary_mod_mutator( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModGame( int index )
+{
+ InitLib( m_get_primary_mod_game );
+
+ return WX_STRINGC( m_get_primary_mod_game( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModShortGame( int index )
+{
+ InitLib( m_get_primary_mod_short_game );
+
+ return WX_STRINGC( m_get_primary_mod_short_game( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModDescription( int index )
+{
+ InitLib( m_get_primary_mod_description );
+
+ return WX_STRINGC( m_get_primary_mod_description( index ) );
+}
+
+
+int SpringUnitSyncLib::GetPrimaryModArchiveCount( int index )
+{
+ InitLib( m_get_primary_mod_archive_count );
+
+ return m_get_primary_mod_archive_count( index );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModArchiveList( int arnr )
+{
+ InitLib( m_get_primary_mod_archive_list );
+
+ return WX_STRINGC( m_get_primary_mod_archive_list( arnr ) );
+}
+
+
+wxString SpringUnitSyncLib::GetPrimaryModChecksumFromName( const wxString& name )
+{
+ InitLib( m_get_primary_mod_checksum_from_name );
+
+ return TowxString( (unsigned int)m_get_primary_mod_checksum_from_name( name.mb_str( wxConvUTF8 ) ) );
+}
+
+
+wxArrayString SpringUnitSyncLib::GetModDeps( int index )
+{
+ int count = GetPrimaryModArchiveCount( index );
+ wxArrayString ret;
+ for ( int i = 0; i < count; i++ )
+ {
+ ret.Add( GetPrimaryModArchiveList( i ) );
+ }
+ return ret;
+}
+
+
+wxArrayString SpringUnitSyncLib::GetSides( const wxString& modName )
+{
+ InitLib( m_get_side_count );
+ UNITSYNC_EXCEPTION( m_get_side_name, _T("Function was not in unitsync library.") )
+
+ _SetCurrentMod( modName );
+ int count = m_get_side_count();
+ wxArrayString ret;
+ for ( int i = 0; i < count; i ++ ) ret.Add( WX_STRINGC( m_get_side_name( i ) ) );
+ return ret;
+}
+
+
+void SpringUnitSyncLib::AddAllArchives( const wxString& root )
+{
+ InitLib( m_add_all_archives );
+
+ m_add_all_archives( root.mb_str() );
+}
+
+
+wxString SpringUnitSyncLib::GetFullUnitName( int index )
+{
+ InitLib( m_get_unit_full_name );
+
+ return WX_STRINGC( m_get_unit_full_name( index ) );
+}
+
+
+wxString SpringUnitSyncLib::GetUnitName( int index )
+{
+ InitLib( m_get_unit_name );
+
+ return WX_STRINGC( m_get_unit_name( index ) );
+}
+
+
+int SpringUnitSyncLib::GetUnitCount()
+{
+ InitLib( m_get_unit_count );
+
+ return m_get_unit_count();
+}
+
+
+int SpringUnitSyncLib::ProcessUnitsNoChecksum()
+{
+ InitLib( m_proc_units_nocheck );
+
+ return m_proc_units_nocheck();
+}
+
+
+wxArrayString SpringUnitSyncLib::FindFilesVFS( const wxString& name )
+{
+ InitLib( m_find_files_vfs );
+ UNITSYNC_EXCEPTION( m_init_find_vfs, _T("Function was not in unitsync library.") );
+ int handle = m_init_find_vfs( name.mb_str(wxConvUTF8) );
+ wxArrayString ret;
+ do
+ {
+ char buffer[1025];
+ handle = m_find_files_vfs( handle, &buffer[0], 1024 );
+ buffer[1024] = 0;
+ ret.Add( WX_STRINGC( &buffer[0] ) );
+ } while ( handle );
+ return ret;
+}
+
+
+int SpringUnitSyncLib::OpenFileVFS( const wxString& name )
+{
+ InitLib( m_open_file_vfs );
+
+ return m_open_file_vfs( name.mb_str( wxConvUTF8 ) );
+}
+
+
+int SpringUnitSyncLib::FileSizeVFS( int handle )
+{
+ InitLib( m_file_size_vfs );
+
+ return m_file_size_vfs( handle );
+}
+
+
+int SpringUnitSyncLib::ReadFileVFS( int handle, void* buffer, int bufferLength )
+{
+ InitLib( m_read_file_vfs );
+
+ return m_read_file_vfs( handle, buffer, bufferLength );
+}
+
+
+void SpringUnitSyncLib::CloseFileVFS( int handle )
+{
+ InitLib( m_close_file_vfs );
+
+ m_close_file_vfs( handle );
+}
+
+
+int SpringUnitSyncLib::GetLuaAICount( const wxString& modname )
+{
+ InitLib( m_get_luaai_count );
+
+ _SetCurrentMod( modname );
+ return m_get_luaai_count();
+}
+
+
+wxString SpringUnitSyncLib::GetLuaAIName( int aiIndex )
+{
+ InitLib( m_get_luaai_name );
+
+ return WX_STRINGC(m_get_luaai_name( aiIndex ));
+}
+
+
+wxString SpringUnitSyncLib::GetLuaAIDesc( int aiIndex )
+{
+ InitLib( m_get_luaai_desc );
+
+ return WX_STRINGC( m_get_luaai_desc( aiIndex ) );
+}
+
+unsigned int SpringUnitSyncLib::GetValidMapCount( const wxString& modname )
+{
+ InitLib( m_get_mod_valid_map_count );
+
+ _SetCurrentMod( modname );
+ return m_get_mod_valid_map_count();
+}
+
+
+wxString SpringUnitSyncLib::GetValidMapName( unsigned int MapIndex )
+{
+ InitLib( m_get_valid_map );
+
+ return WX_STRINGC( m_get_valid_map( MapIndex ) );
+}
+
+
+int SpringUnitSyncLib::GetMapOptionCount( const wxString& name )
+{
+ InitLib( m_get_map_option_count );
+ ASSERT_EXCEPTION( !name.IsEmpty(), _T("passing void mapname to unitsync") );
+
+ return m_get_map_option_count( name.mb_str( wxConvUTF8 ) );
+}
+
+
+int SpringUnitSyncLib::GetModOptionCount( const wxString& name )
+{
+ InitLib( m_get_mod_option_count );
+ ASSERT_EXCEPTION( !name.IsEmpty(), _T("passing void modname to unitsync") );
+
+ _SetCurrentMod( name );
+ return m_get_mod_option_count();
+}
+
+
+int SpringUnitSyncLib::GetAIOptionCount( const wxString& modname, int aiIndex )
+{
+ InitLib( m_get_skirmish_ai_option_count );
+ _SetCurrentMod( modname );
+ ASSERT_EXCEPTION( m_get_skirmish_ai_count , _T("Function was not in unitsync library.") );
+
+ UNITSYNC_EXCEPTION( ( aiIndex >= 0 ) && ( aiIndex < m_get_skirmish_ai_count() ), _T("aiIndex out of bounds") );
+
+ return m_get_skirmish_ai_option_count( aiIndex );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionKey( int optIndex )
+{
+ InitLib( m_get_option_key );
+
+ return WX_STRINGC( m_get_option_key( optIndex ) );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionName( int optIndex )
+{
+ InitLib( m_get_option_name );
+
+ return WX_STRINGC( m_get_option_name( optIndex ) );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionDesc( int optIndex )
+{
+ InitLib( m_get_option_desc );
+
+ return WX_STRINGC( m_get_option_desc( optIndex ) );
+}
+
+wxString SpringUnitSyncLib::GetOptionSection( int optIndex )
+{
+ InitLib( m_get_option_section );
+
+ return WX_STRINGC( m_get_option_section( optIndex ) );
+}
+
+wxString SpringUnitSyncLib::GetOptionStyle( int optIndex )
+{
+ InitLib( m_get_option_style );
+
+ return WX_STRINGC( m_get_option_style( optIndex ) );
+}
+
+
+int SpringUnitSyncLib::GetOptionType( int optIndex )
+{
+ InitLib( m_get_option_type );
+
+ return m_get_option_type( optIndex );
+}
+
+
+int SpringUnitSyncLib::GetOptionBoolDef( int optIndex )
+{
+ InitLib( m_get_option_bool_def );
+
+ return m_get_option_bool_def( optIndex );
+}
+
+
+float SpringUnitSyncLib::GetOptionNumberDef( int optIndex )
+{
+ InitLib( m_get_option_number_def );
+
+ return m_get_option_number_def( optIndex );
+}
+
+
+float SpringUnitSyncLib::GetOptionNumberMin( int optIndex )
+{
+ InitLib( m_get_option_number_min );
+
+ return m_get_option_number_min( optIndex );
+}
+
+
+float SpringUnitSyncLib::GetOptionNumberMax( int optIndex )
+{
+ InitLib( m_get_option_number_max );
+
+ return m_get_option_number_max( optIndex );
+}
+
+
+float SpringUnitSyncLib::GetOptionNumberStep( int optIndex )
+{
+ InitLib( m_get_option_number_step );
+
+ return m_get_option_number_step( optIndex );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionStringDef( int optIndex )
+{
+ InitLib( m_get_option_string_def );
+
+ return WX_STRINGC( m_get_option_string_def( optIndex ) );
+}
+
+
+int SpringUnitSyncLib::GetOptionStringMaxLen( int optIndex )
+{
+ InitLib( m_get_option_string_max_len );
+
+ return m_get_option_string_max_len( optIndex );
+}
+
+
+int SpringUnitSyncLib::GetOptionListCount( int optIndex )
+{
+ InitLib( m_get_option_list_count );
+
+ return m_get_option_list_count( optIndex );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionListDef( int optIndex )
+{
+ InitLib( m_get_option_list_def );
+
+ return WX_STRINGC( m_get_option_list_def( optIndex ) );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionListItemKey( int optIndex, int itemIndex )
+{
+ InitLib( m_get_option_list_item_key );
+
+ return WX_STRINGC( m_get_option_list_item_key( optIndex, itemIndex ) );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionListItemName( int optIndex, int itemIndex )
+{
+ InitLib( m_get_option_list_item_name );
+
+ return WX_STRINGC( m_get_option_list_item_name( optIndex, itemIndex ) );
+}
+
+
+wxString SpringUnitSyncLib::GetOptionListItemDesc( int optIndex, int itemIndex )
+{
+ InitLib( m_get_option_list_item_desc );
+
+ return WX_STRINGC( m_get_option_list_item_desc( optIndex, itemIndex ) );
+}
+
+
+int SpringUnitSyncLib::OpenArchive( const wxString& name )
+{
+ InitLib( m_open_archive );
+
+ return m_open_archive( name.mb_str( wxConvUTF8 ) );
+}
+
+
+void SpringUnitSyncLib::CloseArchive( int archive )
+{
+ InitLib( m_close_archive );
+
+ m_close_archive( archive );
+}
+
+
+int SpringUnitSyncLib::FindFilesArchive( int archive, int cur, wxString& nameBuf )
+{
+ InitLib( m_find_Files_archive );
+
+ char buffer[1025];
+ int size = 1024;
+ bool ret = m_find_Files_archive( archive, cur, &buffer[0], &size );
+ buffer[1024] = 0;
+ nameBuf = WX_STRINGC( &buffer[0] );
+
+ return ret;
+}
+
+
+int SpringUnitSyncLib::OpenArchiveFile( int archive, const wxString& name )
+{
+ InitLib( m_open_archive_file );
+
+ return m_open_archive_file( archive, name.mb_str( wxConvUTF8 ) );
+}
+
+
+int SpringUnitSyncLib::ReadArchiveFile( int archive, int handle, void* buffer, int numBytes)
+{
+ InitLib( m_read_archive_file );
+
+ return m_read_archive_file( archive, handle, buffer, numBytes );
+}
+
+
+void SpringUnitSyncLib::CloseArchiveFile( int archive, int handle )
+{
+ InitLib( m_close_archive_file );
+
+ m_close_archive_file( archive, handle );
+}
+
+
+int SpringUnitSyncLib::SizeArchiveFile( int archive, int handle )
+{
+ InitLib( m_size_archive_file );
+
+ return m_size_archive_file( archive, handle );
+}
+
+
+wxString SpringUnitSyncLib::GetArchivePath( const wxString& name )
+{
+ InitLib( m_get_archive_path );
+
+ return WX_STRINGC( m_get_archive_path( name.mb_str( wxConvUTF8 ) ) );
+}
+
+
+int SpringUnitSyncLib::GetSpringConfigInt( const wxString& key, int defValue )
+{
+ InitLib( m_get_spring_config_int );
+
+ return m_get_spring_config_int( key.mb_str( wxConvUTF8 ), defValue );
+}
+
+
+wxString SpringUnitSyncLib::GetSpringConfigString( const wxString& key, const wxString& defValue )
+{
+ InitLib( m_get_spring_config_string );
+
+ return WX_STRINGC( m_get_spring_config_string( key.mb_str( wxConvUTF8 ), defValue.mb_str( wxConvUTF8 ) ) );
+}
+
+
+float SpringUnitSyncLib::GetSpringConfigFloat( const wxString& key, const float defValue )
+{
+ InitLib( m_get_spring_config_float );
+
+ return m_get_spring_config_float( key.mb_str( wxConvUTF8 ), defValue );
+}
+
+
+void SpringUnitSyncLib::SetSpringConfigString( const wxString& key, const wxString& value )
+{
+ InitLib( m_set_spring_config_string );
+
+ m_set_spring_config_string( key.mb_str( wxConvUTF8 ), value.mb_str( wxConvUTF8 ) );
+}
+
+
+void SpringUnitSyncLib::SetSpringConfigInt( const wxString& key, int value )
+{
+ InitLib( m_set_spring_config_int );
+
+ m_set_spring_config_int( key.mb_str( wxConvUTF8 ), value );
+}
+
+
+void SpringUnitSyncLib::SetSpringConfigFloat( const wxString& key, const float value )
+{
+ InitLib( m_set_spring_config_float );
+
+ m_set_spring_config_float( key.mb_str( wxConvUTF8 ), value );
+}
+
+
+int SpringUnitSyncLib::GetSkirmishAICount( const wxString& modname )
+{
+ InitLib( m_get_skirmish_ai_count );
+ _SetCurrentMod( modname );
+
+ return m_get_skirmish_ai_count();
+}
+
+
+wxArrayString SpringUnitSyncLib::GetAIInfo( int aiIndex )
+{
+ InitLib( m_get_skirmish_ai_count );
+ UNITSYNC_EXCEPTION( m_get_skirmish_ai_info_count, _T("Function was not in unitsync library.") );
+ UNITSYNC_EXCEPTION( m_get_skirmish_ai_info_description, _T("Function was not in unitsync library.") );
+ UNITSYNC_EXCEPTION( m_get_skirmish_ai_info_key, _T("Function was not in unitsync library.") );
+ UNITSYNC_EXCEPTION( m_get_skirmish_ai_info_value, _T("Function was not in unitsync library.") );
+
+ wxArrayString ret;
+ UNITSYNC_EXCEPTION( ( aiIndex >= 0 ) && ( aiIndex < m_get_skirmish_ai_count() ), _T("aiIndex out of bounds") );
+
+ int infoCount = m_get_skirmish_ai_info_count( aiIndex );
+ for( int i = 0; i < infoCount; i++ )
+ {
+ ret.Add( WX_STRINGC( m_get_skirmish_ai_info_key( i ) ) );
+ ret.Add( WX_STRINGC( m_get_skirmish_ai_info_value( i ) ) );
+ ret.Add( WX_STRINGC( m_get_skirmish_ai_info_description( i ) ) );
+ }
+ return ret;
+}
+
+wxString SpringUnitSyncLib::GetArchiveChecksum( const wxString& VFSPath )
+{
+ InitLib( m_get_archive_checksum );
+ return TowxString( m_get_archive_checksum( VFSPath.mb_str() ) );
+}
+
+/// lua parser
+
+void SpringUnitSyncLib::CloseParser()
+{
+ InitLib( m_parser_close );
+
+ m_parser_close();
+}
+
+
+bool SpringUnitSyncLib::OpenParserFile( const wxString& filename, const wxString& filemodes, const wxString& accessModes )
+{
+ InitLib( m_parser_open_file );
+
+ return m_parser_open_file( filename.mb_str(), filemodes.mb_str(), accessModes.mb_str() );
+}
+
+bool SpringUnitSyncLib::OpenParserSource( const wxString& source, const wxString& accessModes )
+{
+ InitLib( m_parser_open_source );
+
+ return m_parser_open_source( source.mb_str(), accessModes.mb_str() );
+}
+
+bool SpringUnitSyncLib::ParserExecute()
+{
+ InitLib( m_parser_execute );
+
+ return m_parser_execute();
+}
+
+wxString SpringUnitSyncLib::ParserErrorLog()
+{
+ InitLib( m_parser_error_log );
+
+ return WX_STRINGC( m_parser_error_log() );
+}
+
+
+void SpringUnitSyncLib::ParserAddTable( int key, bool override )
+{
+ InitLib( m_parser_add_table_int );
+
+ m_parser_add_table_int( key, override );
+}
+
+void SpringUnitSyncLib::ParserAddTable( const wxString& key, bool override )
+{
+ InitLib( m_parser_add_table_string );
+
+ m_parser_add_table_string( key.mb_str(), override );
+}
+
+void SpringUnitSyncLib::ParserEndTable()
+{
+ InitLib( m_parser_end_table );
+
+ m_parser_end_table();
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( int key, int val )
+{
+ InitLib( m_parser_add_int_key_int_value );
+
+ m_parser_add_int_key_int_value( key, val );
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( const wxString& key, int val )
+{
+ InitLib( m_parser_add_string_key_int_value );
+
+ m_parser_add_string_key_int_value( key.mb_str(), val );
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( int key, bool val )
+{
+ InitLib( m_parser_add_int_key_int_value );
+
+ m_parser_add_int_key_int_value( key, val );
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( const wxString& key, bool val )
+{
+ InitLib( m_parser_add_string_key_int_value );
+
+ m_parser_add_string_key_int_value( key.mb_str(), val );
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( int key, const wxString& val )
+{
+ InitLib( m_parser_add_int_key_string_value );
+
+ m_parser_add_int_key_string_value( key, val.mb_str() );
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( const wxString& key, const wxString& val )
+{
+ InitLib( m_parser_add_string_key_string_value );
+
+ m_parser_add_string_key_string_value( key.mb_str(), val.mb_str() );
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( int key, float val )
+{
+ InitLib( m_parser_add_int_key_float_value );
+
+ m_parser_add_int_key_float_value( key, val );
+}
+
+void SpringUnitSyncLib::ParserAddTableValue( const wxString& key, float val )
+{
+ InitLib( m_parser_add_string_key_float_value );
+
+ m_parser_add_string_key_float_value( key.mb_str(), val );
+}
+
+
+bool SpringUnitSyncLib::ParserGetRootTable()
+{
+ InitLib( m_parser_root_table );
+
+ return m_parser_root_table();
+}
+
+bool SpringUnitSyncLib::ParserGetRootTableExpression( const wxString& exp )
+{
+ InitLib( m_parser_root_table_expression );
+
+ return m_parser_root_table_expression( exp.mb_str() );
+}
+
+bool SpringUnitSyncLib::ParserGetSubTableInt( int key )
+{
+ InitLib( m_parser_sub_table_int );
+
+ return m_parser_sub_table_int( key );
+}
+
+bool SpringUnitSyncLib::ParserGetSubTableString( const wxString& key )
+{
+ InitLib( m_parser_sub_table_string );
+
+ return m_parser_sub_table_string( key.mb_str() );
+}
+
+bool SpringUnitSyncLib::ParserGetSubTableInt( const wxString& exp )
+{
+ InitLib( m_parser_sub_table_expression );
+
+ return m_parser_sub_table_expression( exp.mb_str() );
+}
+
+void SpringUnitSyncLib::ParserPopTable()
+{
+ InitLib( m_parser_pop_table );
+
+ m_parser_pop_table();
+}
+
+
+bool SpringUnitSyncLib::ParserKeyExists( int key )
+{
+ InitLib( m_parser_key_int_exists );
+
+ return m_parser_key_int_exists( key );
+}
+
+bool SpringUnitSyncLib::ParserKeyExists( const wxString& key )
+{
+ InitLib( m_parser_key_string_exists );
+
+ return m_parser_key_string_exists( key.mb_str() );
+}
+
+
+int SpringUnitSyncLib::ParserGetKeyType( int key )
+{
+ InitLib( m_parser_int_key_get_type );
+
+ return m_parser_int_key_get_type( key );
+}
+
+int SpringUnitSyncLib::ParserGetKeyType( const wxString& key )
+{
+ InitLib( m_parser_string_key_get_type );
+
+ return m_parser_string_key_get_type( key.mb_str() );
+}
+
+
+int SpringUnitSyncLib::ParserGetIntKeyListCount()
+{
+ InitLib( m_parser_int_key_get_list_count );
+
+ return m_parser_int_key_get_list_count();
+}
+
+int SpringUnitSyncLib::ParserGetIntKeyListEntry( int index )
+{
+ InitLib( m_parser_int_key_get_list_entry );
+
+ return m_parser_int_key_get_list_entry( index );
+}
+
+int SpringUnitSyncLib::ParserGetStringKeyListCount()
+{
+ InitLib( m_parser_string_key_get_list_count );
+
+ return m_parser_string_key_get_list_count();
+}
+
+int SpringUnitSyncLib::ParserGetStringKeyListEntry( int index )
+{
+ InitLib( m_parser_int_key_get_list_entry );
+
+ return m_parser_int_key_get_list_entry( index );
+}
+
+
+int SpringUnitSyncLib::GetKeyValue( int key, int defval )
+{
+ InitLib( m_parser_int_key_get_int_value );
+
+ return m_parser_int_key_get_int_value( key, defval );
+}
+
+bool SpringUnitSyncLib::GetKeyValue( int key, bool defval )
+{
+ InitLib( m_parser_int_key_get_bool_value );
+
+ return m_parser_int_key_get_bool_value( key, defval );
+}
+
+wxString SpringUnitSyncLib::GetKeyValue( int key, const wxString& defval )
+{
+ InitLib( m_parser_int_key_get_string_value );
+
+ return WX_STRINGC( m_parser_int_key_get_string_value( key, defval.mb_str() ) );
+}
+
+float SpringUnitSyncLib::GetKeyValue( int key, float defval )
+{
+ InitLib( m_parser_int_key_get_float_value );
+
+ return m_parser_int_key_get_float_value( key, defval );
+}
+
+int SpringUnitSyncLib::GetKeyValue( const wxString& key, int defval )
+{
+ InitLib( m_parser_string_key_get_int_value );
+
+ return m_parser_string_key_get_int_value( key.mb_str(), defval );
+}
+
+bool SpringUnitSyncLib::GetKeyValue( const wxString& key, bool defval )
+{
+ InitLib( m_parser_string_key_get_bool_value );
+
+ return m_parser_string_key_get_bool_value( key.mb_str(), defval );
+}
+
+wxString SpringUnitSyncLib::GetKeyValue( const wxString& key, const wxString& defval )
+{
+ InitLib( m_parser_string_key_get_string_value );
+
+ return WX_STRINGC( m_parser_string_key_get_string_value( key.mb_str(), defval.mb_str() ) );
+}
+
+float SpringUnitSyncLib::GetKeyValue( const wxString& key, float defval )
+{
+ InitLib( m_parser_string_key_get_float_value );
+
+ return m_parser_string_key_get_float_value( key.mb_str(), defval );
+}
diff --git a/src/springunitsynclib.h b/src/springunitsynclib.h
new file mode 100644
index 0000000..8b4ca90
--- /dev/null
+++ b/src/springunitsynclib.h
@@ -0,0 +1,706 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SPRINGUNITSYNCLIB_H
+#define SPRINGLOBBY_HEADERGUARD_SPRINGUNITSYNCLIB_H
+
+#include <wx/thread.h>
+#include <wx/string.h>
+#include <stdexcept>
+
+#include "nonportable.h"
+#include "iunitsync.h"
+
+class wxString;
+class wxImage;
+struct SpringMapInfo;
+class wxDynamicLibrary;
+
+class unitsync_assert : public std::runtime_error
+{
+ public:
+ unitsync_assert(std::string msg) : std::runtime_error(msg) {};
+};
+
+#define UNITSYNC_EXCEPTION(cond,msg) if(!(cond))\
+{wxLogMessage(_T("unitsync runtime assertion ( %s:%d ): %s"), TowxString(__FILE__).c_str(),__LINE__ , wxString(msg).c_str() );throw unitsync_assert(std::string(wxString(msg).mb_str()));}
+
+
+struct SpringMapInfo
+{
+ char* description;
+ int tidalStrength;
+ int gravity;
+ float maxMetal;
+ int extractorRadius;
+ int minWind;
+ int maxWind;
+
+ int width;
+ int height;
+ int posCount;
+ StartPos positions[16];
+
+ char* author;
+};
+
+
+/**
+ * \defgroup DllPointerTypes Pointer types used with the unitsync library.
+ * \TODO move from global namespace
+ */
+/** @{ */
+
+typedef const char* (USYNC_CALL_CONV *GetSpringVersionPtr)();
+
+typedef int (USYNC_CALL_CONV *InitPtr)(bool, int);
+typedef void (USYNC_CALL_CONV *UnInitPtr)();
+typedef const char* (USYNC_CALL_CONV *GetNextErrorPtr)();
+typedef const char* (USYNC_CALL_CONV *GetWritableDataDirectoryPtr)();
+
+typedef int (USYNC_CALL_CONV *GetMapCountPtr)();
+typedef unsigned int (USYNC_CALL_CONV *GetMapChecksumPtr)(int);
+typedef const char* (USYNC_CALL_CONV *GetMapNamePtr)(int);
+typedef int (USYNC_CALL_CONV *GetMapInfoExPtr)(const char*, SpringMapInfo*, int);
+typedef void* (USYNC_CALL_CONV *GetMinimapPtr)(const char*, int);
+typedef int (USYNC_CALL_CONV *GetInfoMapSizePtr)(const char*, const char*, int*, int*);
+typedef int (USYNC_CALL_CONV *GetInfoMapPtr)(const char*, const char*, void*, int);
+
+typedef unsigned int (USYNC_CALL_CONV *GetPrimaryModChecksumPtr)(int);
+typedef int (USYNC_CALL_CONV *GetPrimaryModIndexPtr)(const char*);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModNamePtr)(int);
+typedef int (USYNC_CALL_CONV *GetPrimaryModCountPtr)();
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModArchivePtr)(int);
+
+typedef int (USYNC_CALL_CONV *GetSideCountPtr)();
+typedef const char* (USYNC_CALL_CONV *GetSideNamePtr)(int);
+
+typedef void (USYNC_CALL_CONV *AddAllArchivesPtr)(const char*);
+typedef void (USYNC_CALL_CONV *RemoveAllArchivesPtr)();
+
+typedef const char * (USYNC_CALL_CONV *GetFullUnitNamePtr)(int);
+typedef const char * (USYNC_CALL_CONV *GetUnitNamePtr)(int);
+typedef int (USYNC_CALL_CONV *GetUnitCountPtr)();
+typedef int (USYNC_CALL_CONV *ProcessUnitsNoChecksumPtr)();
+
+typedef int (USYNC_CALL_CONV *InitFindVFSPtr)(const char*);
+typedef int (USYNC_CALL_CONV *FindFilesVFSPtr)(int, char*, int);
+typedef int (USYNC_CALL_CONV *OpenFileVFSPtr)(const char*);
+typedef int (USYNC_CALL_CONV *FileSizeVFSPtr)(int);
+typedef int (USYNC_CALL_CONV *ReadFileVFSPtr)(int, void*, int);
+typedef void (USYNC_CALL_CONV *CloseFileVFSPtr)(int);
+
+typedef void (USYNC_CALL_CONV *SetSpringConfigFilePtr)(const char*);
+typedef const char * (USYNC_CALL_CONV *GetSpringConfigFilePtr)();
+
+typedef int (USYNC_CALL_CONV *GetSpringConfigIntPtr)(const char*, int );
+typedef const char* (USYNC_CALL_CONV *GetSpringConfigStringPtr)(const char*, const char* );
+typedef float (USYNC_CALL_CONV *GetSpringConfigFloatPtr)(const char*, float );
+
+typedef void (USYNC_CALL_CONV *SetSpringConfigStringPtr)(const char*, const char* );
+typedef void (USYNC_CALL_CONV *SetSpringConfigIntPtr)(const char*, int );
+typedef void (USYNC_CALL_CONV *SetSpringConfigFloatPtr)(const char*, float );
+
+typedef int (USYNC_CALL_CONV *ProcessUnitsPtr)(void);
+typedef void (USYNC_CALL_CONV *AddArchivePtr)(const char* name);
+typedef unsigned int (USYNC_CALL_CONV *GetArchiveChecksumPtr)(const char* arname);
+typedef const char* (USYNC_CALL_CONV *GetArchivePathPtr)(const char* arname);
+typedef int (USYNC_CALL_CONV *GetMapArchiveCountPtr)(const char* mapName);
+typedef const char* (USYNC_CALL_CONV *GetMapArchiveNamePtr)(int index);
+typedef unsigned int (USYNC_CALL_CONV *GetMapChecksumPtr)(int index);
+typedef int (USYNC_CALL_CONV *GetMapChecksumFromNamePtr)(const char* mapName);
+
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModShortNamePtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModVersionPtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModMutatorPtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModGamePtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModShortGamePtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModDescriptionPtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModArchivePtr)(int index);
+typedef int (USYNC_CALL_CONV *GetPrimaryModArchiveCountPtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetPrimaryModArchiveListPtr)(int arnr);
+typedef unsigned int (USYNC_CALL_CONV *GetPrimaryModChecksumFromNamePtr)(const char* name);
+typedef unsigned int (USYNC_CALL_CONV *GetModValidMapCountPtr)();
+typedef const char* (USYNC_CALL_CONV *GetModValidMapPtr)(int index);
+
+typedef int (USYNC_CALL_CONV *GetLuaAICountPtr)();
+typedef const char* (USYNC_CALL_CONV *GetLuaAINamePtr)(int aiIndex);
+typedef const char* (USYNC_CALL_CONV *GetLuaAIDescPtr)(int aiIndex);
+
+typedef int (USYNC_CALL_CONV *GetMapOptionCountPtr)(const char* name);
+typedef int (USYNC_CALL_CONV *GetModOptionCountPtr)();
+typedef int (USYNC_CALL_CONV *GetSkirmishAIOptionCountPtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetOptionKeyPtr)(int optIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionNamePtr)(int optIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionDescPtr)(int optIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionSectionPtr)(int optIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionStylePtr)(int optIndex);
+typedef int (USYNC_CALL_CONV *GetOptionTypePtr)(int optIndex);
+typedef int (USYNC_CALL_CONV *GetOptionBoolDefPtr)(int optIndex);
+typedef float (USYNC_CALL_CONV *GetOptionNumberDefPtr)(int optIndex);
+typedef float (USYNC_CALL_CONV *GetOptionNumberMinPtr)(int optIndex);
+typedef float (USYNC_CALL_CONV *GetOptionNumberMaxPtr)(int optIndex);
+typedef float (USYNC_CALL_CONV *GetOptionNumberStepPtr)(int optIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionStringDefPtr)(int optIndex);
+typedef int (USYNC_CALL_CONV *GetOptionStringMaxLenPtr)(int optIndex);
+typedef int (USYNC_CALL_CONV *GetOptionListCountPtr)(int optIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionListDefPtr)(int optIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionListItemKeyPtr)(int optIndex, int itemIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionListItemNamePtr)(int optIndex, int itemIndex);
+typedef const char* (USYNC_CALL_CONV *GetOptionListItemDescPtr)(int optIndex, int itemIndex);
+
+typedef int (USYNC_CALL_CONV *OpenArchivePtr)(const char* name);
+typedef void (USYNC_CALL_CONV *CloseArchivePtr)(int archive);
+typedef int (USYNC_CALL_CONV *FindFilesArchivePtr)(int archive, int cur, char* nameBuf, int* size);
+typedef int (USYNC_CALL_CONV *OpenArchiveFilePtr)(int archive, const char* name);
+typedef int (USYNC_CALL_CONV *ReadArchiveFilePtr)(int archive, int handle, void* buffer, int numBytes);
+typedef void (USYNC_CALL_CONV *CloseArchiveFilePtr)(int archive, int handle);
+typedef int (USYNC_CALL_CONV *SizeArchiveFilePtr)(int archive, int handle);
+
+typedef int (USYNC_CALL_CONV *GetSkirmishAICountPtr)();
+typedef int (USYNC_CALL_CONV *GetSkirmishAIInfoCountPtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetInfoKeyPtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetInfoValuePtr)(int index);
+typedef const char* (USYNC_CALL_CONV *GetInfoDescriptionPtr)(int index);
+
+/// Unitsync functions wrapping lua parser
+typedef void (USYNC_CALL_CONV *lpClosePtr)();
+typedef int (USYNC_CALL_CONV *lpOpenFilePtr)(const char* filename, const char* fileModes, const char* accessModes);
+typedef int (USYNC_CALL_CONV *lpOpenSourcePtr)(const char* source, const char* accessModes);
+typedef int (USYNC_CALL_CONV *lpExecutePtr)();
+typedef const char* (USYNC_CALL_CONV *lpErrorLogPtr)();
+
+typedef void (USYNC_CALL_CONV *lpAddTableIntPtr)(int key, int override);
+typedef void (USYNC_CALL_CONV *lpAddTableStrPtr)(const char* key, int override);
+typedef void (USYNC_CALL_CONV *lpEndTablePtr)();
+typedef void (USYNC_CALL_CONV *lpAddIntKeyIntValPtr)(int key, int val);
+typedef void (USYNC_CALL_CONV *lpAddStrKeyIntValPtr)(const char* key, int val);
+typedef void (USYNC_CALL_CONV *lpAddIntKeyBoolValPtr)(int key, int val);
+typedef void (USYNC_CALL_CONV *lpAddStrKeyBoolValPtr)(const char* key, int val);
+typedef void (USYNC_CALL_CONV *lpAddIntKeyFloatValPtr)(int key, float val);
+typedef void (USYNC_CALL_CONV *lpAddStrKeyFloatValPtr)(const char* key, float val);
+typedef void (USYNC_CALL_CONV *lpAddIntKeyStrValPtr)(int key, const char* val);
+typedef void (USYNC_CALL_CONV *lpAddStrKeyStrValPtr)(const char* key, const char* val);
+
+typedef int (USYNC_CALL_CONV *lpRootTablePtr)();
+typedef int (USYNC_CALL_CONV *lpRootTableExprPtr)(const char* expr);
+typedef int (USYNC_CALL_CONV *lpSubTableIntPtr)(int key);
+typedef int (USYNC_CALL_CONV *lpSubTableStrPtr)(const char* key);
+typedef int (USYNC_CALL_CONV *lpSubTableExprPtr)(const char* expr);
+typedef void (USYNC_CALL_CONV *lpPopTablePtr)();
+
+typedef int (USYNC_CALL_CONV *lpGetKeyExistsIntPtr)(int key);
+typedef int (USYNC_CALL_CONV *lpGetKeyExistsStrPtr)(const char* key);
+
+typedef int (USYNC_CALL_CONV *lpGetIntKeyTypePtr)(int key);
+typedef int (USYNC_CALL_CONV *lpGetStrKeyTypePtr)(const char* key);
+
+typedef int (USYNC_CALL_CONV *lpGetIntKeyListCountPtr)();
+typedef int (USYNC_CALL_CONV *lpGetIntKeyListEntryPtr)(int index);
+typedef int (USYNC_CALL_CONV *lpGetStrKeyListCountPtr)();
+typedef const char* (USYNC_CALL_CONV *lpGetStrKeyListEntryPtr)(int index);
+
+typedef int (USYNC_CALL_CONV *lpGetIntKeyIntValPtr)(int key, int defVal);
+typedef int (USYNC_CALL_CONV *lpGetStrKeyIntValPtr)(const char* key, int defVal);
+typedef int (USYNC_CALL_CONV *lpGetIntKeyBoolValPtr)(int key, int defVal);
+typedef int (USYNC_CALL_CONV *lpGetStrKeyBoolValPtr)(const char* key, int defVal);
+typedef float (USYNC_CALL_CONV *lpGetIntKeyFloatValPtr)(int key, float defVal);
+typedef float (USYNC_CALL_CONV *lpGetStrKeyFloatValPtr)(const char* key, float defVal);
+typedef const char* (USYNC_CALL_CONV *lpGetIntKeyStrValPtr)(int key, const char* defVal);
+typedef const char* (USYNC_CALL_CONV *lpGetStrKeyStrValPtr)(const char* key, const char* defVal);
+
+
+/** @} */
+
+/**
+ * Primitive class handeling the unitsync library.
+ *
+ * This class is - in a limited way - thread safe but may block execution
+ * in case two threads use it at the same time. The thread safety ensures
+ * there can never be multiple threads executing unitsync functions at the
+ * same time. However, many unitsync functions use (hidden) global state,
+ * so often there is a need for running multiple unitsync methods while
+ * holding a single lock continuously.
+ */
+class SpringUnitSyncLib
+{
+ public:
+
+ /**
+ * Constructor.
+ */
+ SpringUnitSyncLib();
+
+ /**
+ * Destructor, unloads unitsync if loaded.
+ */
+ ~SpringUnitSyncLib();
+
+ /**
+ * Loads the unitsync library from path.
+ * @param path path to the unitsync lib.
+ * @param ForceConfigFilePath if set forces unitsync to use pointed config file, if empty leaves to spring's default
+ * @see Unload().
+ * @note Throws runtime_error if load failed.
+ */
+ void Load( const wxString& path, const wxString& ForceConfigFilePath );
+
+ /**
+ * Unload the unitsync library. Does nothing if not loaded.
+ * @see Load().
+ */
+ void Unload();
+
+ /**
+ * Returns true if the library is loaded.
+ */
+ bool IsLoaded();
+
+ /**
+ * Gets last error from unitsync library
+ * @note throws unitsync_assert in case of error
+ * @note this method should only be used after using directly an unitsync call to catch it's errors
+ */
+ void AssertUnitsyncOk();
+
+ /**
+ * Get list of errors from unitsync library in an array
+ */
+ wxArrayString GetUnitsyncErrors();
+
+ bool VersionSupports( IUnitSync::GameFeature feature );
+
+
+ int GetModIndex( const wxString& name );
+
+ wxString GetSpringVersion();
+
+ /**
+ * Loads unitsync from any number of paths in succession,
+ * queries the Spring versions supported by these unitsyncs,
+ * and returns those.
+ *
+ * This is done by a single function because this "transaction"
+ * needs to hold the unitsync lock the entire time.
+ */
+ std::map<wxString, wxString> GetSpringVersionList(const std::map<wxString, wxString>& usync_paths);
+
+ wxString GetSpringDataDir();
+ wxString GetConfigFilePath();
+
+ int GetMapCount();
+ wxString GetMapChecksum( int index );
+ wxString GetMapName( int index );
+ int GetMapArchiveCount( int index );
+ wxString GetMapArchiveName( int arnr );
+ wxArrayString GetMapDeps( int index );
+
+ /**
+ * @brief Get information about a map.
+ * @param version will get author if >=1.
+ * @note Throws assert_exception if unsuccessful.
+ */
+ MapInfo GetMapInfoEx( const wxString& mapName, int version );
+
+ /**
+ * @brief Get minimap.
+ * @note Throws assert_exception if unsuccessful.
+ */
+ wxImage GetMinimap( const wxString& mapFileName );
+
+ /**
+ * @brief Get metalmap.
+ * @note Throws assert_exception if unsuccessful.
+ */
+ wxImage GetMetalmap( const wxString& mapFileName );
+
+ /**
+ * @brief Get heightmap.
+ * @note Throws assert_exception if unsuccesful.
+ */
+ wxImage GetHeightmap( const wxString& mapFileName );
+
+ wxString GetPrimaryModChecksum( int index );
+ int GetPrimaryModIndex( const wxString& modName );
+ wxString GetPrimaryModName( int index );
+ int GetPrimaryModCount();
+ wxString GetPrimaryModArchive( int index );
+ wxString GetPrimaryModShortName( int index );
+ wxString GetPrimaryModVersion( int index );
+ wxString GetPrimaryModMutator( int index );
+ wxString GetPrimaryModGame( int index );
+ wxString GetPrimaryModShortGame( int index );
+ wxString GetPrimaryModDescription( int index );
+ int GetPrimaryModArchiveCount( int index );
+ wxString GetPrimaryModArchiveList( int arnr );
+ wxString GetPrimaryModChecksumFromName( const wxString& name );
+ wxArrayString GetModDeps( int index );
+
+ wxArrayString GetSides( const wxString& modName );
+
+ /**
+ * Add all achives.
+ * @note Not sure what this does, but adding the mod archive path to this when setting new mod seems to work :)
+ */
+ void AddAllArchives( const wxString& root );
+
+ void SetCurrentMod( const wxString& modname );
+ void UnSetCurrentMod( );
+
+ wxString GetFullUnitName( int index );
+ wxString GetUnitName( int index );
+ int GetUnitCount();
+ int ProcessUnitsNoChecksum();
+
+ /**
+ * Search for a file pattern.
+ * @param the search patterns
+ * @return wxarraystring of results
+ */
+ wxArrayString FindFilesVFS( const wxString& name );
+ int OpenFileVFS( const wxString& name );
+ int FileSizeVFS( int handle );
+ int ReadFileVFS( int handle, void* buffer, int bufferLength );
+ void CloseFileVFS( int handle );
+
+ int GetLuaAICount( const wxString& modname );
+ wxString GetLuaAIName( int aiIndex );
+ wxString GetLuaAIDesc( int aiIndex );
+
+ unsigned int GetValidMapCount( const wxString& modname );
+ wxString GetValidMapName( unsigned int MapIndex );
+
+ int GetMapOptionCount( const wxString& name );
+ int GetModOptionCount( const wxString& name );
+ int GetAIOptionCount( const wxString& modname, int index );
+ wxString GetOptionKey( int optIndex );
+ wxString GetOptionName( int optIndex );
+ wxString GetOptionDesc( int optIndex );
+ wxString GetOptionSection( int optIndex );
+ wxString GetOptionStyle( int optIndex );
+ int GetOptionType( int optIndex );
+ int GetOptionBoolDef( int optIndex );
+ float GetOptionNumberDef( int optIndex );
+ float GetOptionNumberMin( int optIndex );
+ float GetOptionNumberMax( int optIndex );
+ float GetOptionNumberStep( int optIndex );
+ wxString GetOptionStringDef( int optIndex );
+ int GetOptionStringMaxLen( int optIndex );
+ int GetOptionListCount( int optIndex );
+ wxString GetOptionListDef( int optIndex );
+ wxString GetOptionListItemKey( int optIndex, int itemIndex );
+ wxString GetOptionListItemName( int optIndex, int itemIndex );
+ wxString GetOptionListItemDesc( int optIndex, int itemIndex );
+
+ int OpenArchive( const wxString& name );
+ void CloseArchive( int archive );
+ int FindFilesArchive( int archive, int cur, wxString& nameBuf );
+ int OpenArchiveFile( int archive, const wxString& name );
+ int ReadArchiveFile( int archive, int handle, void* buffer, int numBytes) ;
+ void CloseArchiveFile( int archive, int handle );
+ int SizeArchiveFile( int archive, int handle );
+ wxString GetArchivePath( const wxString& name );
+
+ int GetSpringConfigInt( const wxString& key, int defValue );
+ wxString GetSpringConfigString( const wxString& key, const wxString& defValue );
+ float GetSpringConfigFloat( const wxString& key, const float defValue );
+ void SetSpringConfigString( const wxString& key, const wxString& value );
+ void SetSpringConfigInt( const wxString& key, int value );
+ void SetSpringConfigFloat( const wxString& key, const float value );
+
+ /// AI info
+ int GetSkirmishAICount( const wxString& modname );
+ /**
+ * Get next search result.
+ * @param the AI index within range of GetSkirmishAIInfoCount
+ * @return an array made of blocks with this layout { key, value, description }
+ */
+ wxArrayString GetAIInfo( int index );
+
+ wxString GetArchiveChecksum( const wxString& VFSPath );
+
+ /// lua parser
+
+ void CloseParser();
+ bool OpenParserFile( const wxString& filename, const wxString& filemodes, const wxString& accessModes );
+ bool OpenParserSource( const wxString& source, const wxString& accessModes );
+ bool ParserExecute();
+ wxString ParserErrorLog();
+
+ void ParserAddTable( int key, bool override );
+ void ParserAddTable( const wxString& key, bool override );
+ void ParserEndTable();
+ void ParserAddTableValue( int key, int val );
+ void ParserAddTableValue( const wxString& key, int val );
+ void ParserAddTableValue( int key, bool val );
+ void ParserAddTableValue( const wxString& key, bool val );
+ void ParserAddTableValue( int key, const wxString& val );
+ void ParserAddTableValue( const wxString& key, const wxString& val );
+ void ParserAddTableValue( int key, float val );
+ void ParserAddTableValue( const wxString& key, float val );
+
+ bool ParserGetRootTable();
+ bool ParserGetRootTableExpression( const wxString& exp );
+ bool ParserGetSubTableInt( int key );
+ bool ParserGetSubTableString( const wxString& key );
+ bool ParserGetSubTableInt( const wxString& exp );
+ void ParserPopTable();
+
+ bool ParserKeyExists( int key );
+ bool ParserKeyExists( const wxString& key );
+
+ int ParserGetKeyType( int key );
+ int ParserGetKeyType( const wxString& key );
+
+ int ParserGetIntKeyListCount();
+ int ParserGetIntKeyListEntry( int index );
+ int ParserGetStringKeyListCount();
+ int ParserGetStringKeyListEntry( int index );
+
+ int GetKeyValue( int key, int defval );
+ bool GetKeyValue( int key, bool defval );
+ wxString GetKeyValue( int key, const wxString& defval );
+ float GetKeyValue( int key, float defval );
+ int GetKeyValue( const wxString& key, int defval );
+ bool GetKeyValue( const wxString& key, bool defval );
+ wxString GetKeyValue( const wxString& key, const wxString& defval );
+ float GetKeyValue( const wxString& key, float defval );
+
+
+ protected:
+ SpringUnitSyncLib( const SpringUnitSyncLib& );
+ //! Keeps track if unitsync is loaded or not.
+ bool m_loaded;
+
+ //! Handle to the unitsync library.
+ wxDynamicLibrary* m_libhandle;
+
+ //! Critical section controlling access to unitsync functions.
+ mutable wxCriticalSection m_lock;
+
+ //! Path to unitsync.
+ wxString m_path;
+
+ //! the current loaded mod.
+ wxString m_current_mod;
+
+ /**
+ * Loads a function pointer from unitsync.
+ */
+ void* _GetLibFuncPtr( const wxString& name );
+
+ /**
+ * Loads the unitsync library from path.
+ * @note this function is not threadsafe if called from code not locked.
+ * @see Load()
+ */
+ void _Load( const wxString& path );
+
+ /**
+ * Initializes unitsync.
+ */
+ void _Init();
+
+ /**
+ * Calls RemoveAllArchives if available, _Init() otherwise.
+ */
+ void _RemoveAllArchives();
+
+ /**
+ * Internal Unload() function.
+ * @note this function is not threadsafe if called from code not locked.
+ * @see Unload()
+ */
+ void _Unload();
+
+ /**
+ * Returns true if the library is loaded. Internal.
+ */
+ bool _IsLoaded();
+
+ void _ConvertSpringMapInfo( const SpringMapInfo& in, MapInfo& out );
+
+ void _SetCurrentMod( const wxString& modname );
+
+ /**
+ * \defgroup DllFuncPointers Pointers to the functions in unitsync.
+ */
+ /*@{*/
+
+ InitPtr m_init;
+ UnInitPtr m_uninit;
+ GetNextErrorPtr m_get_next_error;
+ GetWritableDataDirectoryPtr m_get_writeable_data_dir;
+
+ GetMapCountPtr m_get_map_count;
+ GetMapChecksumPtr m_get_map_checksum;
+ GetMapNamePtr m_get_map_name;
+ GetMapInfoExPtr m_get_map_info_ex;
+ GetMinimapPtr m_get_minimap;
+ GetInfoMapSizePtr m_get_infomap_size;
+ GetInfoMapPtr m_get_infomap;
+
+ GetPrimaryModChecksumPtr m_get_mod_checksum;
+ GetPrimaryModIndexPtr m_get_mod_index;
+ GetPrimaryModNamePtr m_get_mod_name;
+ GetPrimaryModCountPtr m_get_mod_count;
+ GetPrimaryModArchivePtr m_get_mod_archive;
+
+ GetSideCountPtr m_get_side_count;
+ GetSideNamePtr m_get_side_name;
+
+ AddAllArchivesPtr m_add_all_archives;
+ RemoveAllArchivesPtr m_remove_all_archives;
+
+ GetUnitCountPtr m_get_unit_count;
+ GetUnitNamePtr m_get_unit_name;
+ GetFullUnitNamePtr m_get_unit_full_name;
+ ProcessUnitsNoChecksumPtr m_proc_units_nocheck;
+
+ InitFindVFSPtr m_init_find_vfs;
+ FindFilesVFSPtr m_find_files_vfs;
+ OpenFileVFSPtr m_open_file_vfs;
+ FileSizeVFSPtr m_file_size_vfs;
+ ReadFileVFSPtr m_read_file_vfs;
+ CloseFileVFSPtr m_close_file_vfs;
+
+ GetSpringVersionPtr m_get_spring_version;
+
+ ProcessUnitsPtr m_process_units;
+ AddArchivePtr m_add_archive;
+ GetArchiveChecksumPtr m_get_archive_checksum;
+ GetArchivePathPtr m_get_archive_path;
+ GetMapArchiveCountPtr m_get_map_archive_count;
+ GetMapArchiveNamePtr m_get_map_archive_name;
+ GetMapChecksumFromNamePtr m_get_map_checksum_from_name;
+
+ GetPrimaryModShortNamePtr m_get_primary_mod_short_name;
+ GetPrimaryModVersionPtr m_get_primary_mod_version;
+ GetPrimaryModMutatorPtr m_get_primary_mod_mutator;
+ GetPrimaryModGamePtr m_get_primary_mod_game;
+ GetPrimaryModShortGamePtr m_get_primary_mod_short_game;
+ GetPrimaryModDescriptionPtr m_get_primary_mod_description;
+ GetPrimaryModArchivePtr m_get_primary_mod_archive;
+ GetPrimaryModArchiveCountPtr m_get_primary_mod_archive_count;
+ GetPrimaryModArchiveListPtr m_get_primary_mod_archive_list;
+ GetPrimaryModChecksumFromNamePtr m_get_primary_mod_checksum_from_name;
+ GetModValidMapCountPtr m_get_mod_valid_map_count;
+ GetModValidMapPtr m_get_valid_map;
+
+ GetLuaAICountPtr m_get_luaai_count;
+ GetLuaAINamePtr m_get_luaai_name;
+ GetLuaAIDescPtr m_get_luaai_desc;
+
+ GetMapOptionCountPtr m_get_map_option_count;
+ GetModOptionCountPtr m_get_mod_option_count;
+ GetSkirmishAIOptionCountPtr m_get_skirmish_ai_option_count;
+ GetOptionKeyPtr m_get_option_key;
+ GetOptionNamePtr m_get_option_name;
+ GetOptionDescPtr m_get_option_desc;
+ GetOptionTypePtr m_get_option_type;
+ GetOptionSectionPtr m_get_option_section;
+ GetOptionStylePtr m_get_option_style;
+ GetOptionBoolDefPtr m_get_option_bool_def;
+ GetOptionNumberDefPtr m_get_option_number_def;
+ GetOptionNumberMinPtr m_get_option_number_min;
+ GetOptionNumberMaxPtr m_get_option_number_max;
+ GetOptionNumberStepPtr m_get_option_number_step;
+ GetOptionStringDefPtr m_get_option_string_def;
+ GetOptionStringMaxLenPtr m_get_option_string_max_len;
+ GetOptionListCountPtr m_get_option_list_count;
+ GetOptionListDefPtr m_get_option_list_def;
+ GetOptionListItemKeyPtr m_get_option_list_item_key;
+ GetOptionListItemNamePtr m_get_option_list_item_name;
+ GetOptionListItemDescPtr m_get_option_list_item_desc;
+
+ OpenArchivePtr m_open_archive;
+ CloseArchivePtr m_close_archive;
+ FindFilesArchivePtr m_find_Files_archive;
+ OpenArchiveFilePtr m_open_archive_file;
+ ReadArchiveFilePtr m_read_archive_file;
+ CloseArchiveFilePtr m_close_archive_file;
+ SizeArchiveFilePtr m_size_archive_file;
+
+ SetSpringConfigFilePtr m_set_spring_config_file_path;
+ GetSpringConfigFilePtr m_get_spring_config_file_path;
+ SetSpringConfigFloatPtr m_set_spring_config_float;
+ GetSpringConfigFloatPtr m_get_spring_config_float;
+ GetSpringConfigIntPtr m_get_spring_config_int;
+ GetSpringConfigStringPtr m_get_spring_config_string;
+ SetSpringConfigStringPtr m_set_spring_config_string;
+ SetSpringConfigIntPtr m_set_spring_config_int;
+
+ GetSkirmishAICountPtr m_get_skirmish_ai_count;
+ GetSkirmishAIInfoCountPtr m_get_skirmish_ai_info_count;
+ GetInfoKeyPtr m_get_skirmish_ai_info_key;
+ GetInfoValuePtr m_get_skirmish_ai_info_value;
+ GetInfoDescriptionPtr m_get_skirmish_ai_info_description;
+
+ // lua parser section
+
+ lpClosePtr m_parser_close;
+ lpOpenFilePtr m_parser_open_file;
+ lpOpenSourcePtr m_parser_open_source;
+ lpExecutePtr m_parser_execute;
+ lpErrorLogPtr m_parser_error_log;
+
+ lpAddTableIntPtr m_parser_add_table_int;
+ lpAddTableStrPtr m_parser_add_table_string;
+ lpEndTablePtr m_parser_end_table;
+ lpAddIntKeyIntValPtr m_parser_add_int_key_int_value;
+ lpAddStrKeyIntValPtr m_parser_add_string_key_int_value;
+ lpAddIntKeyBoolValPtr m_parser_add_int_key_bool_value;
+ lpAddStrKeyBoolValPtr m_parser_add_string_key_bool_value;
+ lpAddIntKeyFloatValPtr m_parser_add_int_key_float_value;
+ lpAddStrKeyFloatValPtr m_parser_add_string_key_float_value;
+ lpAddIntKeyStrValPtr m_parser_add_int_key_string_value;
+ lpAddStrKeyStrValPtr m_parser_add_string_key_string_value;
+
+ lpRootTablePtr m_parser_root_table;
+ lpRootTableExprPtr m_parser_root_table_expression;
+ lpSubTableIntPtr m_parser_sub_table_int;
+ lpSubTableStrPtr m_parser_sub_table_string;
+ lpSubTableExprPtr m_parser_sub_table_expression;
+ lpPopTablePtr m_parser_pop_table;
+
+ lpGetKeyExistsIntPtr m_parser_key_int_exists;
+ lpGetKeyExistsStrPtr m_parser_key_string_exists;
+
+ lpGetIntKeyTypePtr m_parser_int_key_get_type;
+ lpGetStrKeyTypePtr m_parser_string_key_get_type;
+
+ lpGetIntKeyListCountPtr m_parser_int_key_get_list_count;
+ lpGetIntKeyListEntryPtr m_parser_int_key_get_list_entry;
+ lpGetStrKeyListCountPtr m_parser_string_key_get_list_count;
+ lpGetStrKeyListEntryPtr m_parser_string_key_get_list_entry;
+
+ lpGetIntKeyIntValPtr m_parser_int_key_get_int_value;
+ lpGetStrKeyIntValPtr m_parser_string_key_get_int_value;
+ lpGetIntKeyBoolValPtr m_parser_int_key_get_bool_value;
+ lpGetStrKeyBoolValPtr m_parser_string_key_get_bool_value;
+ lpGetIntKeyFloatValPtr m_parser_int_key_get_float_value;
+ lpGetStrKeyFloatValPtr m_parser_string_key_get_float_value;
+ lpGetIntKeyStrValPtr m_parser_int_key_get_string_value;
+ lpGetStrKeyStrValPtr m_parser_string_key_get_string_value;
+
+ /*@}*/
+};
+
+SpringUnitSyncLib& susynclib();
+
+#endif //SPRINGLOBBY_HEADERGUARD_SPRINGUNITSYNCLIB_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/tasserver.cpp b/src/tasserver.cpp
new file mode 100644
index 0000000..e7a1223
--- /dev/null
+++ b/src/tasserver.cpp
@@ -0,0 +1,2488 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/string.h>
+#include <wx/regex.h>
+#include <wx/intl.h>
+#include <wx/protocol/http.h>
+#include <wx/socket.h>
+#include <wx/log.h>
+#include <wx/tokenzr.h>
+#include <wx/platinfo.h>
+#include <wx/stopwatch.h>
+
+#include <stdexcept>
+#include <algorithm>
+
+#include <map>
+
+#include "base64.h"
+#include "utils/md5.h"
+#include "tasserver.h"
+#include "iunitsync.h"
+#include "user.h"
+#include "utils/debug.h"
+#include "utils/tasutil.h"
+#include "utils/conversion.h"
+#include "utils/platform.h"
+#include "battle.h"
+#include "serverevents.h"
+#include "socket.h"
+#include "channel/channel.h"
+#include "tasservertokentable.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif //HAVE_CONFIG_H
+
+#ifndef VERSION
+ #define VERSION "unknown"
+#endif //VERSION
+
+// for SL_MAIN_ICON
+#include "settings++/custom_dialogs.h"
+
+#include "settings.h"
+
+
+const int udp_reply_timeout=10;
+
+
+//! @brief Struct used internally by the TASServer class to get client status information.
+struct TASClientstatus
+{
+unsigned int in_game :
+ 1;
+unsigned int away :
+ 1;
+unsigned int rank :
+ 3;
+unsigned int moderator :
+ 1;
+unsigned int bot :
+ 1;
+};
+
+
+//! @brief Union used internally by the TASServer class to get client status information.
+union UTASClientStatus
+{
+ unsigned char byte;
+ TASClientstatus tasdata;
+};
+
+
+//! @brief Struct used internally by the TASServer class to get battle status information.
+//!TODO is that last member necessary? throws a warning baout bein used uninited
+struct TASBattleStatus
+{
+unsigned int :
+ 1;
+unsigned int ready :
+ 1;
+unsigned int team :
+ 4;
+unsigned int ally :
+ 4;
+unsigned int player :
+ 1;
+unsigned int handicap:
+ 7;
+unsigned int :
+ 4;
+unsigned int sync :
+ 2;
+unsigned int side :
+ 4;
+unsigned int :
+ 4;
+};
+
+//! @brief Union used internally by the TASServer class to get battle status information.
+union UTASBattleStatus
+{
+ int data;
+ TASBattleStatus tasdata;
+};
+
+//! @brief struct used internallby by tasserver to convert offer file bitfields
+struct OfferFileData
+{
+ bool autoopen :
+ 1;
+ bool closelobbyondownload :
+ 1;
+ bool disconnectonrefuse :
+ 1;
+};
+
+//! @brief Union used internally by the TASServer class to get battle status information.
+union UTASOfferFileData
+{
+ int data;
+ OfferFileData tasdata;
+};
+
+
+struct TASColor
+{
+unsigned int red :
+ 8;
+unsigned int green :
+ 8;
+unsigned int blue :
+ 8;
+unsigned int zero:
+ 8;
+};
+
+
+union UTASColor
+{
+ int data;
+ TASColor color;
+};
+
+
+/*
+
+myteamcolor: Should be 32-bit signed integer in decimal form (e.g. 255 and not FF) where each color channel should occupy 1 byte (e.g. in hexdecimal: $00BBGGRR, B = blue, G = green, R = red). Example: 255 stands for $000000FF.
+
+*/
+
+UserStatus ConvTasclientstatus( TASClientstatus );
+UserBattleStatus ConvTasbattlestatus( TASBattleStatus );
+TASBattleStatus ConvTasbattlestatus( UserBattleStatus );
+IBattle::StartType IntToStartType( int start );
+NatType IntToNatType( int nat );
+IBattle::GameType IntToGameType( int gt );
+
+TASServer::TASServer():
+m_ser_ver(0),
+m_connected(false),
+m_online(false),
+m_debug_dont_catch( false ),
+m_id_transmission( false ),
+m_redirecting( false ),
+m_buffer(_T("")),
+m_last_udp_ping(0),
+m_last_net_packet(0),
+m_last_id(0),
+m_udp_private_port(0),
+m_battle_id(-1),
+m_do_finalize_join_battle(false),
+m_finalize_join_battle_id(-1),
+m_token_transmission( false )
+{
+ m_se = new ServerEvents( *this );
+ FillAliasMap();
+ m_relay_host_manager_list.Clear();
+}
+
+TASServer::~TASServer()
+{
+ Disconnect();
+ delete m_sock;
+ m_sock = 0;
+ delete m_se;
+}
+
+
+bool TASServer::ExecuteSayCommand( const wxString& cmd )
+{
+ wxArrayString arrayparams = wxStringTokenize( cmd, _T(" ") );
+ if ( arrayparams.GetCount() == 0 ) return false;
+ wxString subcmd = arrayparams[0];
+ wxString params = cmd.AfterFirst( ' ' );
+ if ( subcmd == _T("/ingame") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("GETINGAMETIME"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/kick") )
+ {
+ if ( arrayparams.GetCount() < 2 ) return false;
+ SendCmd( _T("KICKUSER"), params );
+ return true;
+ }
+ else if ( subcmd == _T("/ban") )
+ {
+ if ( arrayparams.GetCount() < 2 ) return false;
+ SendCmd( _T("BAN"), params );
+ return true;
+ }
+ else if ( subcmd == _T("/unban") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("UNBAN"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/banlist") )
+ {
+ SendCmd( _T("BANLIST") );
+ return true;
+ }
+ else if ( subcmd == _T("/topic") )
+ {
+ params.Replace( _T("\n"), _T("\\n") );
+ SendCmd( _T("CHANNELTOPIC"), params );
+ return true;
+ }
+ else if ( subcmd == _T("/chanmsg") )
+ {
+ if ( arrayparams.GetCount() < 2 ) return false;
+ SendCmd( _T("CHANNELMESSAGE"), params );
+ return true;
+ }
+ else if ( subcmd == _T("/ring") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("RING"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/ip") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("GETIP"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/mute") )
+ {
+ if ( arrayparams.GetCount() < 4 ) return false;
+ if ( arrayparams.GetCount() > 5 ) return false;
+ SendCmd( _T("MUTE"), params );
+ return true;
+ }
+ else if ( subcmd == _T("/unmute") )
+ {
+ if ( arrayparams.GetCount() != 3 ) return false;
+ SendCmd( _T("UNMUTE"), arrayparams[1] + _T(" ") + arrayparams[2] );
+ return true;
+ }
+ else if ( subcmd == _T("/mutelist") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("MUTELIST"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/lastlogin") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("GETLASTLOGINTIME"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/findip") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("FINDIP"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/lastip") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("GETLASTIP"), arrayparams[1] );
+ return true;
+ }
+ else if ( subcmd == _T("/rename") )
+ {
+ if ( arrayparams.GetCount() != 2 ) return false;
+ SendCmd( _T("RENAMEACCOUNT"), arrayparams[1] );
+ sett().SetServerAccountNick( sett().GetDefaultServer(), arrayparams[1] ); // this code assumes that default server hasn't changed since login ( like it should atm )
+ return true;
+ }
+ else if ( subcmd == _T("/testmd5") )
+ {
+ ExecuteCommand( _T("SERVERMSG"), GetPasswordHash(params) );
+ return true;
+ }
+ else if ( subcmd == _T("/hook") )
+ {
+ SendCmd( _T("HOOK"), params );
+ return true;
+ }
+ else if ( subcmd == _T("/quit") )
+ {
+ Disconnect();
+ return true;
+ }
+ else if ( subcmd == _T("/changepassword") )
+ {
+ if ( arrayparams.GetCount() != 3 ) return false;
+ wxString oldpassword = GetPasswordHash( arrayparams[1] );
+ wxString newpassword = GetPasswordHash( arrayparams[2] );
+ SendCmd( _T("CHANGEPASSWORD"), oldpassword + _T(" ") + newpassword );
+ return true;
+ }
+ else if ( subcmd == _T("/ping") )
+ {
+ Ping();
+ return true;
+ }
+ return false;
+}
+
+
+void TASServer::Connect( const wxString& servername ,const wxString& addr, const int port )
+{
+ m_server_name = servername;
+ m_addr=addr;
+ m_buffer = _T("");
+ m_buffer = _T("");
+ m_sock->Connect( addr, port );
+ if ( IsConnected() )
+ {
+ m_last_udp_ping = time( 0 );
+ m_connected = true;
+ }
+ m_sock->SetPingInfo( _T("PING\n"), 10000 );
+ m_sock->SetSendRateLimit( 800 ); // 1250 is the server limit but 800 just to make sure :)
+ m_online = false;
+ m_redirecting = false;
+ m_agreement = _T("");
+ m_crc.ResetCRC();
+ m_last_net_packet = time( 0 );
+ wxString handle = m_sock->GetHandle();
+ if ( !handle.IsEmpty() ) m_crc.UpdateData( STD_STRING( wxString( handle + m_addr ) ) );
+}
+
+void TASServer::Disconnect()
+{
+ if (!m_connected)
+ {
+ return;
+ }
+ SendCmd( _T("EXIT") ); // EXIT command for new protocol compatibility
+ m_sock->Disconnect();
+ m_connected = false;
+}
+
+bool TASServer::IsConnected()
+{
+ return (m_sock->State() == SS_Open);
+}
+
+
+bool TASServer::Register( const wxString& addr, const int port, const wxString& nick, const wxString& password, wxString& reason )
+{
+ wxLogDebugFunc( _T("") );
+ FakeNetClass temp;
+ Socket tempsocket( temp, true );
+ tempsocket.Connect( addr, port );
+ if ( tempsocket.State() != SS_Open ) return false;
+
+ wxString data = tempsocket.Receive().BeforeLast(_T('\n'));
+ if ( data.Contains( _T("\r") ) ) data = data.BeforeLast(_T('\r'));
+ if ( GetWordParam( data ) != _T("TASServer") ) return false;
+
+ tempsocket.Send( _T("REGISTER ") + nick + _T(" ") + GetPasswordHash( password ) + _T("\n") );
+
+ data = tempsocket.Receive().BeforeLast(_T('\n'));
+ tempsocket.Disconnect();
+ if ( data.Contains( _T("\r") ) ) data = data.BeforeLast(_T('\r'));
+ if ( data.IsEmpty() )
+ {
+ reason = _("Connection timed out");
+ return false;
+ }
+ wxString cmd = GetWordParam( data );
+ if ( cmd == _T("REGISTRATIONACCEPTED"))
+ {
+ return true;
+ }
+ else if ( cmd == _T("REGISTRATIONDENIED") )
+ {
+ reason = data;
+ return false;
+ }
+ reason = _("Unknown answer from server");
+ return false;
+}
+
+
+bool TASServer::IsPasswordHash( const wxString& pass ) const
+{
+ return pass.length() == 24 && pass[22] == '=' && pass[23] == '=';
+}
+
+
+wxString TASServer::GetPasswordHash( const wxString& pass ) const
+{
+ if ( IsPasswordHash(pass) ) return pass;
+
+ md5_state_t state;
+ md5_byte_t digest[16];
+ char hex_output[16*2 + 1];
+ int di;
+
+ std::string str = STD_STRING(pass);
+ char* cstr = new char [str.size()+1];
+ strcpy (cstr, str.c_str());
+
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t *) cstr, strlen( cstr ));
+ md5_finish(&state, digest);
+ for (di = 0; di < 16; ++di)
+ sprintf(hex_output + di * 2, "%02x", digest[di]);
+
+ wxString coded = wxBase64::Encode( digest, 16 );
+ return coded;
+}
+
+
+User& TASServer::GetMe() const
+{
+ return GetUser( m_user );
+}
+
+
+void TASServer::Login()
+{
+ wxLogDebugFunc( _T("") );
+ wxString pass = GetPasswordHash( m_pass );
+ wxString protocol = _T("\t") + TowxString( m_crc.GetCRC() );
+ wxString localaddr;
+ localaddr = m_sock->GetLocalAddress();
+ if ( localaddr.IsEmpty() ) localaddr = _T("*");
+ SendCmd ( _T("LOGIN"), m_user + _T(" ") + pass + _T(" ") +
+ GetHostCPUSpeed() + _T(" ") + localaddr + _T(" SpringLobby ") + GetSpringLobbyVersion() + protocol + _T("\ta"));
+}
+
+void TASServer::Logout()
+{
+ wxLogDebugFunc( _T("") );
+ Disconnect();
+}
+
+bool TASServer::IsOnline() const
+{
+ if ( !m_connected ) return false;
+ return m_online;
+}
+
+
+void TASServer::RequestChannels()
+{
+ SendCmd( _T("CHANNELS") );
+}
+
+
+void TASServer::AcceptAgreement()
+{
+ SendCmd( _T("CONFIRMAGREEMENT") );
+}
+
+
+void TASServer::Update( int mselapsed )
+{
+
+ m_sock->OnTimer( mselapsed );
+
+ if ( !m_connected ) // We are not formally connected yet, but might be.
+ {
+ if ( IsConnected() )
+ {
+ m_last_udp_ping = time( 0 );
+ m_connected = true;
+ }
+ return;
+ }
+ else // We are connected already.
+ {
+ if ( !IsConnected() ) return;
+
+ time_t now = time( 0 );
+
+//disabled until better timing is miplemented
+// if ( ( m_last_net_packet > 0 ) && ( ( now - m_last_net_packet ) > PING_TIMEOUT ) )
+// {
+// m_se->OnServerMessage( _("Timeout assumed, disconnecting") );
+// Disconnect();
+// }
+
+ // joining battle with nat traversal:
+ // if we havent finalized joining yet, and udp_reply_timeout seconds has passed since
+ // we did UdpPing(our name) , join battle anyway, but with warning message that nat failed.
+ // (if we'd receive reply from server, we'd finalize already)
+ //
+ if (m_do_finalize_join_battle&&(m_last_udp_ping+udp_reply_timeout<now))
+ {
+ customMessageBoxNoModal(SL_MAIN_ICON,_("Failed to punch through NAT, playing this battle might not work for you or for other players."),_("Error"), wxICON_ERROR);
+ //wxMessageBox()
+ FinalizeJoinBattle();
+ //wxMessageBox(_("Failed to punch through NAT"), _("Error"), wxICON_INFORMATION, NULL/* m_ui.mw()*/ );
+ };
+
+ if ( ( m_last_udp_ping + m_keepalive ) < now )
+ {
+ // Is it time for a nat traversal PING?
+ m_last_udp_ping = now;
+ // Nat travelsal "ping"
+ if ( m_battle_id != -1 )
+ {
+ Battle *battle=GetCurrentBattle();
+ if (battle)
+ {
+ if ( ( battle->GetNatType() == NAT_Hole_punching || ( battle->GetNatType() == NAT_Fixed_source_ports ) ) && !battle->GetInGame() )
+ {
+ if ( battle->IsFounderMe() )
+ {
+ UdpPingTheServer(m_user);
+ UdpPingAllClients();
+ }
+ else
+ {
+ UdpPingTheServer(m_user);
+ }
+ }
+ else
+ {
+ // old logging for debug
+ //if(battle->GetNatType()!=NAT_Hole_punching)wxLogMessage( _T("pinging: current battle not using NAT_Hole_punching") );
+ //if(battle->GetInGame())wxLogMessage( _T("pinging: current battle is in game") );
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+void TASServer::ExecuteCommand( const wxString& in )
+{
+ wxLogMessage( _T("%s"), in.c_str() );
+ wxString cmd;
+ wxString params = in;
+ long replyid = 0;
+
+ if ( in.empty() ) return;
+ try
+ {
+ ASSERT_LOGIC( params.AfterFirst( '\n' ).IsEmpty(), _T("losing data") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ if ( params[0] == '#' )
+ {
+ wxString id = params.BeforeFirst( ' ' ).AfterFirst( '#' );
+ params = params.AfterFirst( ' ' );
+ id.ToLong( &replyid );
+ }
+ cmd = params.BeforeFirst( ' ' );
+ params = params.AfterFirst( ' ' );
+
+ // decode message if tokenized
+ wxString copy = cmd;
+ cmd = DecodeTokenMessage( cmd );
+ if ( copy != cmd ) m_token_transmission = true;
+ cmd.UpperCase();
+
+ if ( m_debug_dont_catch )
+ {
+ ExecuteCommand( cmd, params, replyid );
+ }
+ else
+ {
+ try
+ {
+ ExecuteCommand( cmd, params, replyid );
+ }
+ catch ( ... ) // catch everything so the app doesn't crash, may makes odd beahviours but it's better than crashing randomly for normal users
+ {
+ }
+ }
+}
+
+
+void TASServer::ExecuteCommand( const wxString& cmd, const wxString& inparams, int replyid )
+{
+ wxString params = inparams;
+ int pos, cpu, id, nat, port, maxplayers, rank, specs, units, top, left, right, bottom, ally, type;
+ bool haspass,lanmode = false;
+ wxString hash;
+ wxString nick, contry, host, map, title, mod, channel, error, msg, owner, ai, supported_spring_version, topic;
+ //NatType ntype;
+ UserStatus cstatus;
+ UTASClientStatus tasstatus;
+ UTASBattleStatus tasbstatus;
+ UserBattleStatus bstatus;
+ UTASColor color;
+
+ if ( cmd == _T("TASSERVER"))
+ {
+ mod = GetWordParam( params );
+ mod.ToDouble( &m_ser_ver );
+ supported_spring_version = GetWordParam( params );
+ m_nat_helper_port = (unsigned long)GetIntParam( params );
+ lanmode = GetBoolParam( params );
+ m_server_lanmode = lanmode;
+ m_se->OnConnected( m_server_name, mod, (m_ser_ver > 0), supported_spring_version, lanmode );
+ }
+ else if ( cmd == _T("ACCEPTED") )
+ {
+ if ( m_online ) return; // in case is the server sends WTF
+ m_online = true;
+ m_user = params;
+ m_se->OnLogin( );
+ }
+ else if ( cmd == _T("MOTD") )
+ {
+ m_se->OnMotd( params );
+ }
+ else if ( cmd == _T("ADDUSER") )
+ {
+ nick = GetWordParam( params );
+ contry = GetWordParam( params );
+ cpu = GetIntParam( params );
+ id = GetIntParam( params );
+ m_se->OnNewUser( nick, contry, cpu, TowxString(id) );
+ if ( nick == m_relay_host_bot )
+ {
+ RelayCmd( _T("OPENBATTLE"), m_delayed_open_command ); // relay bot is deployed, send host command
+ m_delayed_open_command = _T("");
+ }
+ }
+ else if ( cmd == _T("CLIENTSTATUS") )
+ {
+ nick = GetWordParam( params );
+ tasstatus.byte = GetIntParam( params );
+ cstatus = ConvTasclientstatus( tasstatus.tasdata );
+ m_se->OnUserStatus( nick, cstatus );
+ }
+ else if ( cmd == _T("BATTLEOPENED") )
+ {
+ id = GetIntParam( params );
+ type = GetIntParam( params );
+ nat = GetIntParam( params );
+ nick = GetWordParam( params );
+ host = GetWordParam( params );
+ port = GetIntParam( params );
+ maxplayers = GetIntParam( params );
+ haspass = GetBoolParam( params );
+ rank = GetIntParam( params );
+ hash = MakeHashUnsigned( GetWordParam( params ) );
+ map = GetSentenceParam( params );
+ title = GetSentenceParam( params );
+ mod = GetSentenceParam( params );
+ m_se->OnBattleOpened( id, (BattleType)type, IntToNatType( nat ), nick, host, port, maxplayers,
+ haspass, rank, hash, map, title, mod );
+ if ( nick == m_relay_host_bot )
+ {
+ GetBattle( id ).SetIsProxy( true );
+ JoinBattle( id, sett().GetLastHostPassword() ); // autojoin relayed host battles
+ }
+ }
+ else if ( cmd == _T("JOINEDBATTLE") )
+ {
+ id = GetIntParam( params );
+ nick = GetWordParam( params );
+ m_se->OnUserJoinedBattle( id, nick );
+ }
+ else if ( cmd == _T("UPDATEBATTLEINFO") )
+ {
+ id = GetIntParam( params );
+ specs = GetIntParam( params );
+ haspass = GetBoolParam( params );
+ hash = MakeHashUnsigned( GetWordParam( params ) );
+ map = GetSentenceParam( params );
+ m_se->OnBattleInfoUpdated( id, specs, haspass, hash, map );
+ }
+ else if ( cmd == _T("LOGININFOEND") )
+ {
+ if ( sett().GetReportStats() )
+ {
+ wxString version = WX_STRINGC(VERSION).BeforeFirst( _T(' ') );
+ wxString aux;
+ #ifdef AUX_VERSION
+ aux = WX_STRINGC(AUX_VERSION);
+ aux.Replace( _T(" "), _T("") );
+ aux = _T(" ") + aux;
+ #endif
+ wxString os = wxPlatformInfo::Get().GetOperatingSystemIdName();
+ os.Replace( _T(" "), _T("") );
+ wxString wxversion = wxVERSION_STRING;
+ wxversion.Replace( _T(" "), _T("") );
+ wxString reportstring = _T("stats.report ") + version + _T(" ") + wxversion + _T(" ") + os + aux;
+ if ( UserExists( _T("insanebot") ) ) SayPrivate( _T("insanebot"), reportstring );
+ if ( UserExists( _T("SL_bot") ) ) SayPrivate( _T("SL_bot"), reportstring );
+ }
+ if ( UserExists( _T("RelayHostManagerList") ) ) SayPrivate( _T("RelayHostManagerList"), _T("!listmanagers") );
+ m_se->OnLoginInfoComplete();
+ }
+ else if ( cmd == _T("REMOVEUSER") )
+ {
+ nick = GetWordParam( params );
+ if ( nick == m_user ) return; // to prevent peet doing nasty stuff to you, watch your back!
+ m_se->OnUserQuit( nick );
+ }
+ else if ( cmd == _T("BATTLECLOSED") )
+ {
+ id = GetIntParam( params );
+ if ( m_battle_id == id ) m_relay_host_bot = _T("");
+ m_se->OnBattleClosed( id );
+ }
+ else if ( cmd == _T("LEFTBATTLE") )
+ {
+ id = GetIntParam( params );
+ nick = GetWordParam( params );
+ m_se->OnUserLeftBattle( id, nick );
+ }
+ else if ( cmd == _T("PONG") )
+ {
+ HandlePong( replyid );
+ }
+ else if ( cmd == _T("JOIN") )
+ {
+ channel = GetWordParam( params );
+ m_se->OnJoinChannelResult( true, channel, _T("") );
+ }
+ else if ( cmd == _T("JOIN") )
+ {
+ channel = GetWordParam( params );
+ error = GetSentenceParam( params );
+ m_se->OnJoinChannelResult( false, channel, error );
+ }
+ else if ( cmd == _T("SAID") )
+ {
+ channel = GetWordParam( params );
+ nick = GetWordParam( params );
+ m_se->OnChannelSaid( channel, nick, params );
+ }
+ else if ( cmd == _T("JOINED") )
+ {
+ channel = GetWordParam( params );
+ nick = GetWordParam( params );
+ m_se->OnUserJoinChannel( channel, nick );
+ }
+ else if ( cmd == _T("LEFT") )
+ {
+ channel = GetWordParam( params );
+ nick = GetWordParam( params );
+ msg = GetSentenceParam( params );
+ m_se->OnChannelPart( channel, nick, msg );
+ }
+ else if ( cmd == _T("CHANNELTOPIC") )
+ {
+ channel = GetWordParam( params );
+ nick = GetWordParam( params );
+ pos = GetIntParam( params );
+ params.Replace( _T("\\n"), _T("\n") );
+ m_se->OnChannelTopic( channel, nick, params, pos/1000 );
+ }
+ else if ( cmd == _T("SAIDEX") )
+ {
+ channel = GetWordParam( params );
+ nick = GetWordParam( params );
+ m_se->OnChannelAction( channel, nick, params );
+ }
+ else if ( cmd == _T("CLIENTS") )
+ {
+ channel = GetWordParam( params );
+ while ( (nick = GetWordParam( params )) != _T("") )
+ {
+ m_se->OnChannelJoin( channel, nick );
+ }
+ }
+ else if ( cmd == _T("SAYPRIVATE") )
+ {
+ nick = GetWordParam( params );
+ if ( ( ( nick == m_relay_host_bot ) || ( nick == m_relay_host_manager ) ) && params.StartsWith( _T("!") ) ) return; // drop the message
+ if ( ( nick == _T("RelayHostManagerList") ) && ( params == _T("!listmanagers") ) ) return;// drop the message
+ if ( nick == _T("SL_bot") || ( nick == _T("insanebot") ) )
+ {
+ if ( params.StartsWith( _T("stats.report") ) ) return;
+ }
+ m_se->OnPrivateMessage( nick, params, true );
+ }
+ else if ( cmd == _T("SAIDPRIVATE") )
+ {
+ nick = GetWordParam( params );
+ if ( nick == m_relay_host_manager )
+ {
+ if ( params.StartsWith( _T("\001") ) ) // error code
+ {
+ m_se->OnServerMessageBox( params.AfterFirst( _T(' ') ) );
+ }
+ else
+ {
+ m_relay_host_bot = params;
+ }
+ m_relay_host_manager = _T("");
+ return;
+ }
+ if ( nick == _T("RelayHostManagerList") )
+ {
+ if ( params.StartsWith(_T("managerlist ")) )
+ {
+ wxString list = params.AfterFirst( _T(' ') );
+ m_relay_host_manager_list = wxStringTokenize( list, _T("\t") );
+ return;
+ }
+ }
+ m_se->OnPrivateMessage( nick, params, false );
+ }
+ else if ( cmd == _T("JOINBATTLE") )
+ {
+ id = GetIntParam( params );
+ hash = MakeHashUnsigned( GetWordParam( params ) );
+ m_battle_id = id;
+ m_se->OnJoinedBattle( id, hash );
+ m_se->OnBattleInfoUpdated( m_battle_id );
+ }
+ else if ( cmd == _T("CLIENTBATTLESTATUS") )
+ {
+ nick = GetWordParam( params );
+ tasbstatus.data = GetIntParam( params );
+ bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
+ color.data = GetIntParam( params );
+ bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
+ m_se->OnClientBattleStatus( m_battle_id, nick, bstatus );
+ }
+ else if ( cmd == _T("ADDSTARTRECT") )
+ {
+ //ADDSTARTRECT allyno left top right bottom
+ ally = GetIntParam( params );
+ left = GetIntParam( params );
+ top = GetIntParam( params );
+ right = GetIntParam( params );
+ bottom = GetIntParam( params );;
+ m_se->OnBattleStartRectAdd( m_battle_id, ally, left, top, right, bottom );
+ }
+ else if ( cmd == _T("REMOVESTARTRECT") )
+ {
+ //REMOVESTARTRECT allyno
+ ally = GetIntParam( params );
+ m_se->OnBattleStartRectRemove( m_battle_id, ally );
+ }
+ else if ( cmd == _T("ENABLEALLUNITS") )
+ {
+ //"ENABLEALLUNITS" params: "".
+ m_se->OnBattleEnableAllUnits( m_battle_id );
+ }
+ else if ( cmd == _T("ENABLEUNITS") )
+ {
+ //ENABLEUNITS unitname1 unitname2
+ while ( (nick = GetWordParam( params )) !=_T( "") )
+ {
+ m_se->OnBattleEnableUnit( m_battle_id, nick );
+ }
+ }
+ else if ( cmd == _T("DISABLEUNITS") )
+ {
+ //"DISABLEUNITS" params: "arm_advanced_radar_tower arm_advanced_sonar_station arm_advanced_torpedo_launcher arm_dragons_teeth arm_energy_storage arm_eraser arm_fark arm_fart_mine arm_fibber arm_geothermal_powerplant arm_guardian"
+ while ( (nick = GetWordParam( params )) != _T("") )
+ {
+ m_se->OnBattleDisableUnit( m_battle_id, nick );
+ }
+ }
+ else if ( cmd == _T("CHANNEL") )
+ {
+ channel = GetWordParam( params );
+ units = GetIntParam( params );
+ topic = GetSentenceParam( params );
+ m_se->OnChannelList( channel, units, topic );
+ }
+ else if ( cmd == _T("ENDOFCHANNELS") )
+ {
+ //Cmd: ENDOFCHANNELS params:
+ }
+ else if ( cmd == _T("REQUESTBATTLESTATUS") )
+ {
+ m_se->OnRequestBattleStatus( m_battle_id );
+ }
+ else if ( cmd == _T("SAIDBATTLE") )
+ {
+ nick = GetWordParam( params );
+ m_se->OnSaidBattle( m_battle_id, nick, params );
+ }
+ else if ( cmd == _T("SAIDBATTLEEX") )
+ {
+ nick = GetWordParam( params );
+ m_se->OnBattleAction( m_battle_id, nick, params );
+ }
+ else if ( cmd == _T("AGREEMENT") )
+ {
+ msg = GetSentenceParam( params );
+ m_agreement += msg + _T("\n");
+ }
+ else if ( cmd == _T("AGREEMENTEND") )
+ {
+ m_se->OnAcceptAgreement( m_agreement );
+ m_agreement = _T("");
+ }
+ else if ( cmd == _T("OPENBATTLE") )
+ {
+ m_battle_id = GetIntParam( params );
+ m_se->OnHostedBattle( m_battle_id );
+ }
+ else if ( cmd == _T("ADDBOT") )
+ {
+ // ADDBOT BATTLE_ID name owner battlestatus teamcolor {AIDLL}
+ id = GetIntParam( params );
+ nick = GetWordParam( params );
+ owner = GetWordParam( params );
+ tasbstatus.data = GetIntParam( params );
+ bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
+ color.data = GetIntParam( params );
+ bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
+ wxString ai = GetSentenceParam( params );
+ if ( ai.IsEmpty() ) {
+ wxLogWarning( wxString::Format( _T("Recieved illegal ADDBOT (empty dll field) from %s for battle %d"), nick.c_str(), id ) );
+ ai = _T("INVALID|INVALID");
+ }
+ if( usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) )
+ {
+ bstatus.aiversion = ai.AfterLast( _T('|') );
+ ai = ai.BeforeLast( _T('|') );
+ bstatus.aishortname = ai;
+ }
+ else
+ {
+ bstatus.aishortname = ai;
+ }
+ bstatus.owner =owner;
+ m_se->OnBattleAddBot( id, nick, bstatus );
+ }
+ else if ( cmd == _T("UPDATEBOT") )
+ {
+ id = GetIntParam( params );
+ nick = GetWordParam( params );
+ tasbstatus.data = GetIntParam( params );
+ bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
+ color.data = GetIntParam( params );
+ bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
+ m_se->OnBattleUpdateBot( id, nick, bstatus );
+ //UPDATEBOT BATTLE_ID name battlestatus teamcolor
+ }
+ else if ( cmd == _T("REMOVEBOT") )
+ {
+ id = GetIntParam( params );
+ nick = GetWordParam( params );
+ m_se->OnBattleRemoveBot( id, nick );
+ //REMOVEBOT BATTLE_ID name
+ }
+ else if ( cmd == _T("RING") )
+ {
+ nick = GetWordParam( params );
+ m_se->OnRing( nick );
+ //RING username
+ }
+ else if ( cmd == _T("SERVERMSG") )
+ {
+ m_se->OnServerMessage( params );
+ //SERVERMSG {message}
+ }
+ else if ( cmd == _T("JOINBATTLEFAILED") )
+ {
+ msg = GetSentenceParam( params );
+ m_se->OnServerMessage( _T("Failed to join battle. ") + msg );
+ //JOINBATTLEFAILED {reason}
+ }
+ else if ( cmd == _T("OPENBATTLEFAILED") )
+ {
+ msg = GetSentenceParam( params );
+ m_se->OnServerMessage( _T("Failed to host new battle on server. ") + msg );
+ //OPENBATTLEFAILED {reason}
+ }
+ else if ( cmd == _T("JOINFAILED") )
+ {
+ channel = GetWordParam( params );
+ msg = GetSentenceParam( params );
+ m_se->OnServerMessage( _T("Failed to join channel #") + channel + _T(". ") + msg );
+ //JOINFAILED channame {reason}
+ }
+ else if ( cmd == _T("CHANNELMESSAGE") )
+ {
+ channel = GetWordParam( params );
+ m_se->OnChannelMessage( channel, params );
+ //CHANNELMESSAGE channame {message}
+ }
+ else if ( cmd == _T("ACQUIREUSERID") )
+ {
+ SendCmd( _T("USERID"), TowxString( m_crc.GetCRC() ) );
+ }
+ else if ( cmd == _T("FORCELEAVECHANNEL") )
+ {
+ channel = GetWordParam( params );
+ nick = GetWordParam( params );
+ msg = GetSentenceParam( params );
+ m_se->OnChannelPart( channel, GetMe().GetNick(), _T("Kicked by <") + nick + _T("> ") + msg );
+ //FORCELEAVECHANNEL channame username [{reason}]
+ }
+ else if ( cmd == _T("DENIED") )
+ {
+ if ( m_online ) return;
+ m_last_denied = msg = GetSentenceParam( params );
+ m_se->OnServerMessage( msg );
+ Disconnect();
+ //Command: "DENIED" params: "Already logged in".
+ }
+ else if ( cmd == _T("HOSTPORT") )
+ {
+ unsigned int tmp_port = (unsigned int)GetIntParam( params );
+ m_se->OnHostExternalUdpPort( tmp_port );
+ //HOSTPORT port
+ }
+ else if ( cmd == _T("UDPSOURCEPORT") )
+ {
+ unsigned int tmp_port = (unsigned int)GetIntParam( params );
+ m_se->OnMyExternalUdpSourcePort( tmp_port );
+ if (m_do_finalize_join_battle)FinalizeJoinBattle();
+ //UDPSOURCEPORT port
+ }
+ else if (cmd == _T("CLIENTIPPORT"))
+ {
+ // clientipport username ip port
+ nick=GetWordParam( params );
+ wxString ip=GetWordParam(params);
+ unsigned int port=(unsigned int)GetIntParam( params );
+ m_se->OnClientIPPort(nick, ip, port);
+ }
+ else if ( cmd == _T("SETSCRIPTTAGS") )
+ {
+ wxString command;
+ while ( (command = GetSentenceParam( params )) != _T("") )
+ {
+ wxString key = command.BeforeFirst( '=' ).Lower();
+ wxString value = command.AfterFirst( '=' );
+ m_se->OnSetBattleInfo( m_battle_id, key, value );
+ }
+ m_se->OnBattleInfoUpdated( m_battle_id );
+ // !! Command: "SETSCRIPTTAGS" params: "game/startpostype=0 game/maxunits=1000 game/limitdgun=0 game/startmetal=1000 game/gamemode=0 game/ghostedbuildings=-1 game/startenergy=1000 game/diminishingmms=0"
+ }
+ else if ( cmd == _T("SCRIPTSTART") )
+ {
+ m_se->OnScriptStart( m_battle_id );
+ // !! Command: "SCRIPTSTART" params: ""
+ }
+ else if ( cmd == _T("SCRIPTEND") )
+ {
+ m_se->OnScriptEnd( m_battle_id );
+ // !! Command: "SCRIPTEND" params: ""
+ }
+ else if ( cmd == _T("SCRIPT") )
+ {
+ m_se->OnScriptLine( m_battle_id, params );
+ // !! Command: "SCRIPT" params: "[game]"
+ }
+ else if ( cmd == _T("FORCEQUITBATTLE"))
+ {
+ m_relay_host_bot = _T("");
+ m_se->OnKickedFromBattle();
+ }
+ else if ( cmd == _T("BROADCAST"))
+ {
+ m_se->OnServerMessage( params );
+ }
+ else if ( cmd == _T("SERVERMSGBOX"))
+ {
+ m_se->OnServerMessageBox( params );
+ }
+ else if ( cmd == _T("REDIRECT") )
+ {
+ if ( m_online ) return;
+ wxString address = GetWordParam( params );
+ unsigned int port = GetIntParam( params );
+ if ( address.IsEmpty() ) return;
+ if ( port == 0 ) port = DEFSETT_DEFAULT_SERVER_PORT;
+ m_redirecting = true;
+ m_se->OnRedirect( address, port, m_user, m_pass );
+ }
+ else if ( cmd == _T("MUTELISTBEGIN") )
+ {
+ m_current_chan_name_mutelist = GetWordParam( params );
+ m_se->OnMutelistBegin( m_current_chan_name_mutelist );
+
+ }
+ else if ( cmd == _T("MUTELIST") )
+ {
+ wxString mutee = GetWordParam( params );
+ wxString description = GetWordParam( params );
+ m_se->OnMutelistItem( m_current_chan_name_mutelist, mutee, description );
+ }
+ else if ( cmd == _T("MUTELISTEND") )
+ {
+ m_se->OnMutelistEnd( m_current_chan_name_mutelist );
+ m_current_chan_name_mutelist = _T("");
+ }
+ // OFFERFILE options {filename} {url} {description}
+ else if ( cmd == _T("OFFERFILE") )
+ {
+ UTASOfferFileData parsingdata;
+ parsingdata.data = GetIntParam( params );
+ wxString FileName = GetSentenceParam( params );
+ wxString url = GetSentenceParam( params );
+ wxString description = GetSentenceParam( params );
+ m_se->OnFileDownload( parsingdata.tasdata.autoopen, parsingdata.tasdata.closelobbyondownload, parsingdata.tasdata.disconnectonrefuse, FileName, url, description );
+ }
+ else
+ {
+ wxLogMessage( _T("??? Cmd: %s params: %s"), cmd.c_str(), params.c_str() );
+ m_se->OnUnknownCommand( cmd, params );
+ }
+}
+
+
+void TASServer::RelayCmd( const wxString& command, const wxString& param )
+{
+ if ( m_relay_host_bot.IsEmpty() )
+ {
+ wxLogWarning( _T("Trying to send relayed commands but no relay bot is set!") );
+ return;
+ }
+
+ wxString msg = _T("!"); // prefix comma,nds with !
+ if ( param.IsEmpty() ) msg << command.Lower();
+ else msg << command.Lower() << _T(" ") << param;
+ SayPrivate( m_relay_host_bot, msg );
+}
+
+
+void TASServer::SendCmd( const wxString& command, const wxString& param )
+{
+ wxString cmd, msg;
+ if ( m_id_transmission )
+ {
+ m_last_id++;
+ msg = msg + _T("#") + TowxString( m_last_id ) + _T(" ");
+ }
+ if ( m_token_transmission )
+ {
+ cmd = EncodeTokenMessage( command );
+ }
+ else cmd = command;
+ if ( param.IsEmpty() ) msg = msg + cmd + _T("\n");
+ else msg = msg + cmd + _T(" ") + param + _T("\n");
+ m_sock->Send( msg );
+ wxLogMessage( _T("sent: %s"), msg.c_str() );
+}
+
+void TASServer::Ping()
+{
+ //wxLogDebugFunc( _T("") );
+ m_id_transmission = true;
+ SendCmd( _T("PING") );
+ m_id_transmission = false;
+ TASPingListItem pli;
+ pli.id = m_last_id;
+ pli.t = wxGetLocalTimeMillis();
+ m_pinglist.push_back ( pli );
+}
+
+
+void TASServer::HandlePong( int replyid )
+{
+ std::list<TASPingListItem>::iterator it;
+
+ bool found = false;
+ for ( it = m_pinglist.begin(); it != m_pinglist.end(); it++ )
+ {
+ if (it->id == replyid )
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if ( found )
+ {
+ m_se->OnPong( (wxGetLocalTimeMillis() - it->t) );
+ m_pinglist.erase( it );
+ }
+}
+
+
+void TASServer::JoinChannel( const wxString& channel, const wxString& key )
+{
+ //JOIN channame [key]
+ wxLogDebugFunc( channel );
+
+ m_channel_pw[channel] = key;
+
+ SendCmd ( _T("JOIN"), channel + _T(" ") + key );
+}
+
+
+void TASServer::PartChannel( const wxString& channel )
+{
+ //LEAVE channame
+ wxLogDebugFunc( channel );
+
+ SendCmd( _T("LEAVE"), channel );
+
+}
+
+
+void TASServer::DoActionChannel( const wxString& channel, const wxString& msg )
+{
+ //SAYEX channame {message}
+ wxLogDebugFunc( _T("") );
+
+ SendCmd( _T("SAYEX"), channel + _T(" ") + msg );
+}
+
+
+void TASServer::SayChannel( const wxString& channel, const wxString& msg )
+{
+ //SAY channame {message}
+ wxLogDebugFunc( _T("") );
+
+ SendCmd( _T("SAY"), channel + _T(" ") + msg );
+}
+
+
+void TASServer::SayPrivate( const wxString& nick, const wxString& msg )
+{
+ //SAYPRIVATE username {message}
+ wxLogDebugFunc( _T("") );
+
+ SendCmd( _T("SAYPRIVATE"), nick + _T(" ") + msg );
+}
+
+
+void TASServer::DoActionPrivate( const wxString& nick, const wxString& msg )
+{
+ wxLogDebugFunc( _T("") );
+
+ SendCmd( _T("SAYPRIVATEEX"), nick + _T(" ") + msg );
+}
+
+
+void TASServer::SayBattle( int /*unused*/, const wxString& msg )
+{
+ wxLogDebugFunc( _T("") );
+
+ SendCmd( _T("SAYBATTLE"), msg );
+}
+
+
+void TASServer::DoActionBattle( int /*unused*/, const wxString& msg )
+{
+ wxLogDebugFunc( _T("") );
+
+ SendCmd( _T("SAYBATTLEEX"), msg );
+}
+
+
+void TASServer::Ring( const wxString& nick )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_EXCEPTION( m_battle_id != -1, _T("invalid m_battle_id value") );
+ ASSERT_EXCEPTION( BattleExists(m_battle_id), _T("battle doesn't exists") );
+
+ Battle& battle = GetBattle( m_battle_id );
+ ASSERT_EXCEPTION( battle.IsFounderMe(), _T("I'm not founder") );
+
+ if ( battle.IsProxy() )
+ {
+ RelayCmd( _T("RING"), nick );
+ }
+ else
+ {
+ SendCmd( _T("RING"), nick );
+ }
+
+ }
+ catch (...)
+ {
+ }
+ SendCmd( _T("RING"), nick );
+}
+
+
+
+
+void TASServer::ModeratorSetChannelTopic( const wxString& channel, const wxString& topic )
+{
+ wxString msgcopy = topic;
+ msgcopy.Replace( _T("\n"), _T("\\n") );
+ SendCmd( _T("CHANNELTOPIC"), channel + _T(" ") + msgcopy );
+}
+
+
+void TASServer::ModeratorSetChannelKey( const wxString& channel, const wxString& key)
+{
+ SendCmd( _T("SETCHANNELKEY"), channel + _T(" ") + key );
+}
+
+
+void TASServer::ModeratorMute( const wxString& channel, const wxString& nick, int duration, bool byip )
+{
+ SendCmd( _T("MUTE"), channel + _T(" ") + nick + _T(" ") + wxString::Format( _T("%d"), duration) + (byip?_T(" ip"):_T("") ) );
+}
+
+
+void TASServer::ModeratorUnmute( const wxString& channel, const wxString& nick )
+{
+ SendCmd( _T("UNMUTE"), channel + _T(" ") + nick );
+}
+
+
+void TASServer::ModeratorKick( const wxString& channel, const wxString& reason )
+{
+ SendCmd( _T("KICKUSER"), channel + _T(" ") + reason );
+}
+
+
+void TASServer::ModeratorBan( const wxString& /*unused*/, bool /*unused*/ )
+{
+ // FIXME TASServer::ModeratorBan not yet implemented
+}
+
+
+void TASServer::ModeratorUnban( const wxString& /*unused*/ )
+{
+ // FIXME TASServer::ModeratorUnban not yet implemented
+}
+
+
+void TASServer::ModeratorGetIP( const wxString& nick )
+{
+ SendCmd( _T("GETIP"), nick );
+}
+
+
+void TASServer::ModeratorGetLastLogin( const wxString& nick )
+{
+ SendCmd( _T("GETLASTLOGINTIME"), nick );
+}
+
+
+void TASServer::ModeratorGetLastIP( const wxString& nick )
+{
+ SendCmd( _T("GETLASTIP"), nick );
+}
+
+
+void TASServer::ModeratorFindByIP( const wxString& ipadress )
+{
+ SendCmd( _T("FINDIP"), ipadress );
+}
+
+
+void TASServer::AdminGetAccountAccess( const wxString& /*unused*/ )
+{
+ // FIXME TASServer::AdminGetAccountAccess not yet implemented
+}
+
+
+void TASServer::AdminChangeAccountAccess( const wxString& /*unused*/, const wxString& /*unused*/ )
+{
+ // FIXME TASServer::AdminChangeAccountAccess not yet implemented
+}
+
+
+void TASServer::AdminSetBotMode( const wxString& nick, bool isbot )
+{
+ SendCmd( _T("SETBOTMODE"), nick + _T(" ") + (isbot?_T("1"):_T("0")) );
+}
+
+
+
+
+
+void TASServer::HostBattle( BattleOptions bo, const wxString& password )
+{
+ wxLogDebugFunc( _T("") );
+
+ // to see ip addresses of users as they join (in the log), pretend you're hosting with NAT.
+ int nat_type=bo.nattype;
+ /*
+ if(nat_type==0 && sett().GetShowIPAddresses()){
+ nat_type=1;
+ }*/
+ wxLogMessage(_T("hosting with nat type %d"),nat_type);
+
+ wxString cmd = wxString::Format( _T("0 %d "), nat_type );
+ cmd += (password.IsEmpty())?_T("*"):password;
+ cmd += wxString::Format( _T(" %d %d "), bo.port, bo.maxplayers );
+ cmd += MakeHashSigned( bo.modhash );
+ cmd += wxString::Format( _T(" %d "), bo.rankneeded );
+ cmd += MakeHashSigned( bo.maphash ) + _T(" ");
+ cmd += bo.mapname + _T("\t");
+ cmd += bo.description + _T("\t");
+ cmd += bo.modname;
+
+ m_delayed_open_command = _T("");
+ if ( !bo.isproxy )
+ {
+ SendCmd( _T("OPENBATTLE"), cmd );
+ }
+ else
+ {
+ if ( bo.relayhost.IsEmpty() )
+ {
+ wxArrayString relaylist = GetRelayHostList();
+ unsigned int numbots = relaylist.GetCount();
+ if ( numbots > 0 )
+ {
+ srand ( time(NULL) );
+ unsigned int choice = rand() % numbots;
+ m_relay_host_manager = relaylist[choice];
+ m_delayed_open_command = cmd;
+ SayPrivate( m_relay_host_manager, _T("!spawn") );
+ }
+ }
+ else
+ {
+ m_relay_host_manager = bo.relayhost;
+ m_delayed_open_command = cmd;
+ SayPrivate(bo.relayhost,_T("!spawn"));
+ }
+ }
+
+ if (bo.nattype>0)UdpPingTheServer(m_user);
+
+ // OPENBATTLE type natType password port maphash {map} {title} {modname}
+}
+
+
+void TASServer::JoinBattle( const int& battleid, const wxString& password )
+{
+ //JOINBATTLE BATTLE_ID [parameter]
+ wxLogDebugFunc( _T("") );
+
+ m_finalize_join_battle_pw=password;
+ m_finalize_join_battle_id=battleid;
+
+ if (BattleExists(battleid))
+ {
+ Battle *battle=&GetBattle(battleid);
+
+ if (battle)
+ {
+ if ( ( battle->GetNatType() == NAT_Hole_punching ) || ( battle->GetNatType() == NAT_Fixed_source_ports ) )
+ {
+ m_udp_private_port=sett().GetClientPort();
+
+ m_last_udp_ping = time(0);
+ // its important to set time now, to prevent Update()
+ // from calling FinalizeJoinBattle() on timeout.
+ // m_do_finalize_join_battle must be set to true after setting time, not before.
+ m_do_finalize_join_battle=true;
+ for (int n=0;n<5;++n) // do 5 udp pings with tiny interval
+ {
+ UdpPingTheServer( m_user );
+ // sleep(0);// sleep until end of timeslice.
+ }
+ m_last_udp_ping = time(0);// set time again
+ }
+ else
+ {
+ // if not using nat, finalize now.
+ m_do_finalize_join_battle=true;
+ FinalizeJoinBattle();
+ }
+ }
+ else
+ {
+ wxLogMessage( _T("battle doesnt exist (null)") );
+ }
+ }
+ else
+ {
+ wxLogMessage( _T("battle doesnt exist") );
+ }
+ //SendCmd( _T("JOINBATTLE"), wxString::Format( _T("%d"), battleid ) + _T(" ") + password );
+}
+
+
+void TASServer::FinalizeJoinBattle()
+{
+ if (m_do_finalize_join_battle)
+ {
+ SendCmd( _T("JOINBATTLE"), wxString::Format( _T("%d"), m_finalize_join_battle_id ) + _T(" ") + m_finalize_join_battle_pw);
+ m_do_finalize_join_battle=false;
+ }
+}
+
+
+void TASServer::LeaveBattle( const int& /*unused*/ )
+{
+ //LEAVEBATTLE
+ wxLogDebugFunc( _T("") );
+ m_relay_host_bot = _T("");
+ SendCmd( _T("LEAVEBATTLE") );
+}
+
+
+void TASServer::SendHostInfo( HostInfo update )
+{
+ wxLogDebugFunc( _T("") );
+
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ Battle& battle = GetBattle( m_battle_id );
+ try
+ {
+ ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ //BattleOptions bo = battle.opts();
+
+ if ( ( update & ( IBattle::HI_Map | IBattle::HI_Locked | IBattle::HI_Spectators ) ) > 0 )
+ {
+ // UPDATEBATTLEINFO SpectatorCount locked maphash {mapname}
+ wxString cmd = wxString::Format( _T("%d %d "), battle.GetSpectators(), battle.IsLocked() );
+ cmd += MakeHashSigned( battle.LoadMap().hash ) + _T(" ");
+ cmd += battle.LoadMap().name;
+
+ if ( !battle.IsProxy() ) SendCmd( _T("UPDATEBATTLEINFO"), cmd );
+ else RelayCmd( _T("UPDATEBATTLEINFO"), cmd );
+ }
+ if ( ( update & IBattle::HI_Send_All_opts ) > 0 )
+ {
+ wxString cmd;
+
+ OptionsWrapper::wxStringTripleVec optlistMap = battle.CustomBattleOptions().getOptions( OptionsWrapper::MapOption );
+ for (OptionsWrapper::wxStringTripleVec::iterator it = optlistMap.begin(); it != optlistMap.end(); ++it)
+ {
+ cmd << _T("game/mapoptions/") << it->first + _T("=") << it->second.second << _T("\t");
+ }
+ OptionsWrapper::wxStringTripleVec optlistMod = battle.CustomBattleOptions().getOptions( OptionsWrapper::ModOption );
+ for (OptionsWrapper::wxStringTripleVec::iterator it = optlistMod.begin(); it != optlistMod.end(); ++it)
+ {
+ cmd << _T("game/modoptions/") << it->first << _T("=") << it->second.second << _T("\t");
+ }
+ OptionsWrapper::wxStringTripleVec optlistEng = battle.CustomBattleOptions().getOptions( OptionsWrapper::EngineOption );
+ for (OptionsWrapper::wxStringTripleVec::iterator it = optlistEng.begin(); it != optlistEng.end(); ++it)
+ {
+ cmd << _T("game/") << it->first << _T("=") << it->second.second << _T("\t");
+ }
+
+ if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
+ else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
+ }
+
+ if ( (update & IBattle::HI_StartRects) > 0 ) // Startrects should be updated.
+ {
+ unsigned int numrects = battle.GetLastRectIdx();
+ for ( unsigned int i = 0; i <= numrects; i++ ) // Loop through all, and remove updated or deleted.
+ {
+ wxString cmd;
+ BattleStartRect sr = battle.GetStartRect( i );
+ if ( !sr.exist ) continue;
+ if ( sr.todelete )
+ {
+ if ( !battle.IsProxy() ) SendCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
+ else RelayCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
+ battle.StartRectRemoved( i );
+ }
+ else if ( sr.toadd )
+ {
+ if ( !battle.IsProxy() ) SendCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
+ else RelayCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
+ battle.StartRectAdded( i );
+ }
+ else if ( sr.toresize )
+ {
+ if ( !battle.IsProxy() )
+ {
+ SendCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
+ SendCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
+ }
+ else
+ {
+ RelayCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
+ RelayCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
+ }
+ battle.StartRectResized( i );
+ }
+ }
+
+ }
+ if ( (update & IBattle::HI_Restrictions) > 0 )
+ {
+ std::map<wxString, int> units = battle.RestrictedUnits();
+ if ( !battle.IsProxy() ) SendCmd( _T("ENABLEALLUNITS") );
+ else RelayCmd( _T("ENABLEALLUNITS") );
+ if ( units.size() > 0 )
+ {
+ wxString msg;
+ wxString scriptmsg;
+ for ( std::map<wxString, int>::iterator itor = units.begin(); itor != units.end(); itor++ )
+ {
+ msg << itor->first + _T(" ");
+ scriptmsg << _T("game/restrict/") + itor->first + _T("=") + TowxString(itor->second) + _T('\t'); // this is a serious protocol abuse, but on the other hand, the protocol fucking suck and it's unmaintained so it will do for now
+ }
+ if ( !battle.IsProxy() )
+ {
+ SendCmd( _T("DISABLEUNITS"), msg );
+ SendCmd( _T("SETSCRIPTTAGS"), scriptmsg );
+ }
+ else
+ {
+ RelayCmd( _T("DISABLEUNITS"), msg );
+ RelayCmd( _T("SETSCRIPTTAGS"), scriptmsg );
+ }
+ }
+ }
+}
+
+
+void TASServer::SendHostInfo( const wxString& Tag )
+{
+ wxLogDebugFunc( _T("") );
+
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ Battle& battle = GetBattle( m_battle_id );
+
+ try
+ {
+ Battle& battle = GetBattle( m_battle_id );
+ ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ wxString cmd;
+
+ long type;
+ Tag.BeforeFirst( '_' ).ToLong( &type );
+ wxString key = Tag.AfterFirst( '_' );
+ if ( type == OptionsWrapper::MapOption )
+ {
+ cmd << _T("game/mapoptions/") << key << _T("=") << battle.CustomBattleOptions().getSingleValue( key, OptionsWrapper::MapOption );
+ }
+ else if ( type == OptionsWrapper::ModOption )
+ {
+ cmd << _T("game/modoptions/") << key << _T("=") << battle.CustomBattleOptions().getSingleValue( key, OptionsWrapper::ModOption );
+ }
+ else if ( type == OptionsWrapper::EngineOption )
+ {
+ cmd << _T("game/") << key << _T("=") << battle.CustomBattleOptions().getSingleValue( key, OptionsWrapper::EngineOption );
+ }
+ if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
+ else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
+}
+
+
+void TASServer::SendUserPosition( const User& user )
+{
+ wxLogDebugFunc( _T("") );
+
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+
+ Battle& battle = GetBattle( m_battle_id );
+ ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
+
+ UserBattleStatus status = user.BattleStatus();
+ wxString msgx = _T("game/Team") + TowxString( status.team ) + _T("/StartPosX=") + TowxString( status.pos.x );
+ wxString msgy = _T("game/Team") + TowxString( status.team ) + _T("/StartPosY=") + TowxString( status.pos.y );
+ wxString netmessage = msgx + _T("\t") + msgy;
+ if ( battle.IsProxy() )
+ {
+ RelayCmd( _T("SETSCRIPTTAGS"), netmessage );
+ }
+ else
+ {
+ SendCmd( _T("SETSCRIPTTAGS"), netmessage );
+ }
+
+ }
+ catch (...)
+ {
+ return;
+ }
+}
+
+void TASServer::SendRaw( const wxString& raw )
+{
+ SendCmd( raw );
+}
+
+
+void TASServer::RequestInGameTime( const wxString& nick )
+{
+ SendCmd( _T("GETINGAMETIME"), nick );
+}
+
+
+Battle* TASServer::GetCurrentBattle()
+{
+ try
+ {
+ ASSERT_EXCEPTION( m_battle_id != -1, _T("invalid m_battle_id value") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ }
+ catch (...)
+ {
+ return NULL;
+ }
+
+ return &GetBattle( m_battle_id );
+}
+
+
+void TASServer::SendMyBattleStatus( UserBattleStatus& bs )
+{
+ wxLogDebugFunc( _T("") );
+
+ GetMe().UpdateBattleStatus( bs );
+
+ UTASBattleStatus tasbs;
+ tasbs.tasdata = ConvTasbattlestatus( bs );
+ UTASColor tascl;
+ tascl.color.red = bs.colour.Red();
+ tascl.color.green = bs.colour.Green();
+ tascl.color.blue = bs.colour.Blue();
+ tascl.color.zero = 0;
+ //MYBATTLESTATUS battlestatus myteamcolor
+ SendCmd( _T("MYBATTLESTATUS"), wxString::Format( _T("%d %d"), tasbs.data, tascl.data ) );
+}
+
+
+void TASServer::SendMyUserStatus()
+{
+ wxLogDebugFunc( _T("") );
+
+ UserStatus& us = GetMe().Status();
+
+ UTASClientStatus taus;
+ taus.tasdata.in_game = us.in_game;
+ taus.tasdata.away = us.away;
+ taus.tasdata.rank = us.rank;
+ taus.tasdata.moderator = us.moderator;
+ taus.tasdata.bot = us.bot;
+
+ SendCmd( _T("MYSTATUS"), wxString::Format( _T("%d"), taus.byte ) );
+}
+
+
+void TASServer::StartHostedBattle()
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ Battle *battle=GetCurrentBattle();
+ if (battle)
+ {
+ if ( ( battle->GetNatType() == NAT_Hole_punching ) || ( battle->GetNatType() == NAT_Fixed_source_ports ) )
+ {
+ UdpPingTheServer(m_user);
+ for (int i=0;i<5;++i)UdpPingAllClients();
+ }
+ }
+
+ m_se->OnStartHostedBattle( m_battle_id );
+}
+
+
+void TASServer::ForceSide( int battleid, User& user, int side )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ UserBattleStatus& status = user.BattleStatus();
+
+ if ( &user == &GetMe() )
+ {
+ status.side = side;
+ SendMyBattleStatus( status );
+ return;
+ }
+
+ if ( status.IsBot() )
+ {
+ status.side = side;
+ UpdateBot( battleid, user, status );
+ }
+}
+
+
+void TASServer::ForceTeam( int battleid, User& user, int team )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+ if ( user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().team = team;
+ UpdateBot( battleid, user, user.BattleStatus() );
+ return;
+ }
+ if ( &user == &GetMe() )
+ {
+ GetMe().BattleStatus().team = team;
+ SendMyBattleStatus( GetMe().BattleStatus() );
+ return;
+ }
+ if ( !GetBattle(battleid).IsFounderMe() )
+ {
+ DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" changes to team #") + wxString::Format( _T("%d"), team + 1 ) + _T(".") );
+ return;
+ }
+
+ //FORCETEAMNO username teamno
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCETEAMNO"), user.GetNick() + wxString::Format(_T(" %d"), team ) );
+ else RelayCmd( _T("FORCETEAMNO"), user.GetNick() + wxString::Format(_T(" %d"), team ) );
+}
+
+
+void TASServer::ForceAlly( int battleid, User& user, int ally )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ if ( user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().ally = ally;
+ UpdateBot( battleid, user, user.BattleStatus() );
+ return;
+ }
+
+ if ( &user == &GetMe() )
+ {
+ GetMe().BattleStatus().ally = ally;
+ SendMyBattleStatus( GetMe().BattleStatus() );
+ return;
+ }
+
+ if ( !GetBattle(battleid).IsFounderMe() )
+ {
+ DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" changes to ally #") + wxString::Format( _T("%d"), ally + 1 ) + _T(".") );
+ return;
+ }
+
+ //FORCEALLYNO username teamno
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCEALLYNO"), user.GetNick() + wxString::Format( _T(" %d"), ally ) );
+ else RelayCmd( _T("FORCEALLYNO"), user.GetNick() + wxString::Format( _T(" %d"), ally ) );
+}
+
+
+void TASServer::ForceColour( int battleid, User& user, const wxColour& col )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ if ( user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().colour = col;
+ UpdateBot( battleid, user, user.BattleStatus() );
+ return;
+ }
+ if ( &user == &GetMe() )
+ {
+ GetMe().BattleStatus().colour = col;
+ SendMyBattleStatus( GetMe().BattleStatus() );
+ return;
+ }
+ if ( !GetBattle(battleid).IsFounderMe() )
+ {
+ DoActionBattle( battleid, _T("sugests that ") + user.GetNick() + _T(" changes colour.") );
+ return;
+ }
+
+ UTASColor tascl;
+ tascl.color.red = col.Red();
+ tascl.color.green = col.Green();
+ tascl.color.blue = col.Blue();
+ tascl.color.zero = 0;
+ //FORCETEAMCOLOR username color
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCETEAMCOLOR"), user.GetNick() + _T(" ") + wxString::Format( _T("%d"), tascl.data ) );
+ else RelayCmd( _T("FORCETEAMCOLOR"), user.GetNick() + _T(" ") + wxString::Format( _T("%d"), tascl.data ) );
+}
+
+
+void TASServer::ForceSpectator( int battleid, User& user, bool spectator )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ if ( user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().spectator = spectator;
+ UpdateBot( battleid, user, user.BattleStatus() );
+ return;
+ }
+ if ( &user == &GetMe() )
+ {
+ GetMe().BattleStatus().spectator = spectator;
+ SendMyBattleStatus( GetMe().BattleStatus() );
+ return;
+ }
+ if ( !GetBattle(battleid).IsFounderMe() )
+ {
+ if ( spectator ) DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" becomes a spectator.") );
+ else DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" plays.") );
+ return;
+ }
+
+ //FORCESPECTATORMODE username
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCESPECTATORMODE"), user.GetNick() );
+ else RelayCmd( _T("FORCESPECTATORMODE"), user.GetNick() );
+}
+
+
+void TASServer::BattleKickPlayer( int battleid, User& user )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ if ( user.BattleStatus().IsBot() )
+ {
+ RemoveBot( battleid, user );
+ return;
+ }
+ if ( &user == &GetMe() )
+ {
+ LeaveBattle( battleid );
+ return;
+ }
+ if ( !GetBattle(battleid).IsFounderMe() )
+ {
+ DoActionBattle( battleid, _T("thinks ") + user.GetNick() + _T(" should leave.") );
+ return;
+ }
+
+ //KICKFROMBATTLE username
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("KICKFROMBATTLE"), user.GetNick() );
+ else RelayCmd( _T("KICKFROMBATTLE"), user.GetNick() );
+}
+
+void TASServer::SetHandicap( int battleid, User& user, int handicap)
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ if ( user.BattleStatus().IsBot() )
+ {
+ user.BattleStatus().handicap = handicap;
+ UpdateBot( battleid, user, user.BattleStatus() );
+ return;
+ }
+
+ if ( !GetBattle(battleid).IsFounderMe() )
+ {
+ DoActionBattle( battleid, _T("thinks ") + user.GetNick() + _T(" should get a ") + wxString::Format( _T("%d"), handicap) + _T("% resource bonus") );
+ return;
+ }
+
+ //HANDICAP username value
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("HANDICAP"), user.GetNick() + wxString::Format( _T(" %d"), handicap ) );
+ else RelayCmd( _T("HANDICAP"), user.GetNick() + wxString::Format( _T(" %d"), handicap ) );
+}
+
+
+void TASServer::AddBot( int battleid, const wxString& nick, UserBattleStatus& status )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ UTASBattleStatus tasbs;
+ tasbs.tasdata = ConvTasbattlestatus( status );
+ UTASColor tascl;
+ tascl.color.red = status.colour.Red();
+ tascl.color.green = status.colour.Green();
+ tascl.color.blue = status.colour.Blue();
+ tascl.color.zero = 0;
+ //ADDBOT name battlestatus teamcolor {AIDLL}
+ wxString msg;
+ wxString ailib;
+ ailib += status.aishortname;
+ if ( usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) ) ailib += _T("|") + status.aiversion;
+ SendCmd( _T("ADDBOT"), nick + wxString::Format( _T(" %d %d "), tasbs.data, tascl.data ) + ailib );
+}
+
+
+void TASServer::RemoveBot( int battleid, User& bot )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ Battle& battle = GetBattle( battleid );
+ ASSERT_LOGIC( &bot != 0, _T("Bot does not exist.") );
+
+ if ( !( battle.IsFounderMe() || ( bot.BattleStatus().owner == GetMe().GetNick() ) ) )
+ {
+ DoActionBattle( battleid, _T("thinks the bot ") + bot.GetNick() + _T(" should be removed.") );
+ return;
+ }
+
+ //REMOVEBOT name
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("REMOVEBOT"), bot.GetNick() );
+ else RelayCmd( _T("REMOVEBOT"), bot.GetNick() );
+}
+
+
+void TASServer::UpdateBot( int battleid, User& bot, UserBattleStatus& status )
+{
+ wxLogDebugFunc( _T("") );
+ try
+ {
+ ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
+ ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
+ ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
+ }
+ catch (...)
+ {
+ return;
+ }
+
+ UTASBattleStatus tasbs;
+ tasbs.tasdata = ConvTasbattlestatus( status );
+ UTASColor tascl;
+ tascl.color.red = status.colour.Red();
+ tascl.color.green = status.colour.Green();
+ tascl.color.blue = status.colour.Blue();
+ tascl.color.zero = 0;
+ //UPDATEBOT name battlestatus teamcolor
+ if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("UPDATEBOT"), bot.GetNick() + wxString::Format( _T(" %d %d"), tasbs.data, tascl.data ) );
+ else RelayCmd( _T("UPDATEBOT"), bot.GetNick() + wxString::Format( _T(" %d %d"), tasbs.data, tascl.data ) );
+}
+
+void TASServer::SendScriptToProxy( const wxString& script )
+{
+ RelayCmd( _T("CLEANSCRIPT") );
+ wxStringTokenizer tkzr( script, _T("\n") );
+ while ( tkzr.HasMoreTokens() )
+ {
+ wxString line = tkzr.GetNextToken();
+ RelayCmd( _T("APPENDSCRIPTLINE"), line );
+ }
+ RelayCmd( _T("STARTGAME") );
+}
+
+void TASServer::SendScriptToClients( const wxString& script )
+{
+ SendCmd( _T("SCRIPTSTART") );
+ wxStringTokenizer tkzr( script, _T("\n") );
+ while ( tkzr.HasMoreTokens() )
+ {
+ wxString line = tkzr.GetNextToken();
+ SendCmd( _T("SCRIPT"), line );
+ }
+ SendCmd( _T("SCRIPTEND") );
+}
+
+void TASServer::OnConnected( Socket* /*unused*/ )
+{
+ wxLogDebugFunc( _T("") );
+ //TASServer* serv = (TASServer*)sock->GetUserdata();
+ m_last_udp_ping = time( 0 );
+ m_connected = true;
+ m_online = false;
+ m_token_transmission = false;
+ m_relay_host_manager_list.Clear();
+ m_last_denied = _T("");
+}
+
+
+void TASServer::OnDisconnected( Socket* /*unused*/ )
+{
+ wxLogDebugFunc( TowxString(m_connected) );
+ bool connectionwaspresent = m_online || !m_last_denied.IsEmpty() || m_redirecting;
+ m_last_denied = _T("");
+ m_connected = false;
+ m_online = false;
+ m_redirecting = false;
+ m_token_transmission = false;
+ m_buffer = _T("");
+ m_relay_host_manager_list.Clear();
+ m_se->OnDisconnected( connectionwaspresent );
+ Server::OnDisconnected();
+}
+
+
+void TASServer::OnDataReceived( Socket* sock )
+{
+ if ( sock == 0 ) return;
+ m_last_net_packet = time( 0 );
+ wxString data = sock->Receive();
+ m_buffer << data;
+ m_buffer.Replace( _T("\r\n"), _T("\n") );
+ int returnpos = m_buffer.Find( _T("\n") );
+ while ( returnpos != -1 )
+ {
+ wxString cmd = m_buffer.Left( returnpos );
+ m_buffer = m_buffer.Mid( returnpos + 1 );
+ ExecuteCommand( cmd );
+ returnpos = m_buffer.Find( _T("\n") );
+ }
+}
+
+
+//! @brief Send udp ping.
+//! @note used for nat travelsal.
+
+unsigned int TASServer::UdpPing(unsigned int src_port, const wxString &target, unsigned int target_port, const wxString &message)// full parameters version, used to ping all clients when hosting.
+{
+ int result=0;
+ wxLogMessage(_T("UdpPing src_port=%d , target='%s' , target_port=%d , message='%s'"),src_port,target.c_str(),target_port, message.c_str());
+ wxIPV4address local_addr;
+ local_addr.AnyAddress(); // <--- THATS ESSENTIAL!
+ local_addr.Service(src_port);
+
+ wxDatagramSocket udp_socket(local_addr,/* wxSOCKET_WAITALL*/wxSOCKET_NONE);
+
+ wxIPV4address wxaddr;
+ wxaddr.Hostname(target);
+ wxaddr.Service(target_port);
+
+ if (udp_socket.IsOk()&&!udp_socket.Error())
+ {
+ std::string m=STD_STRING(message);
+ udp_socket.SendTo( wxaddr, m.c_str(), m.length() );
+ wxIPV4address true_local_addr;
+ if (udp_socket.GetLocal(true_local_addr))
+ {
+ result=true_local_addr.Service();
+ }
+ }
+ else
+ {
+ wxLogMessage(_T("socket's IsOk() is false, no UDP ping done."));
+ }
+
+ if (udp_socket.Error())wxLogWarning(_T("wxDatagramSocket Error=%d"),udp_socket.LastError());
+ return result;
+}
+
+void TASServer::UdpPingTheServer(const wxString &message)
+{
+ unsigned int port=UdpPing(m_udp_private_port,m_addr,m_nat_helper_port,message);
+ if (port>0)
+ {
+ m_udp_private_port=port;
+ m_se->OnMyInternalUdpSourcePort( m_udp_private_port );
+ }
+}
+
+
+// copypasta from spring.cpp , to get users ordered same way as in tasclient.
+struct UserOrder
+{
+ int index;// user number for GetUser
+ int order;// user order (we'll sort by it)
+ bool operator<(UserOrder b) const // comparison function for sorting
+ {
+ return order<b.order;
+ }
+};
+
+
+void TASServer::UdpPingAllClients()// used when hosting with nat holepunching. has some rudimentary support for fixed source ports.
+{
+ Battle *battle=GetCurrentBattle();
+ if (!battle)return;
+ if (!battle->IsFounderMe())return;
+ wxLogMessage(_T("UdpPingAllClients()"));
+
+ // I'm gonna mimic tasclient's behavior.
+ // It of course doesnt matter in which order pings are sent,
+ // but when doing "fixed source ports", the port must be
+ // FIRST_UDP_SOURCEPORT + index of user excluding myself
+ // so users must be reindexed in same way as in tasclient
+ // to get same source ports for pings.
+
+
+ // copypasta from spring.cpp
+ std::vector<UserOrder> ordered_users;
+
+
+ for ( UserList::user_map_t::size_type i = 0; i < battle->GetNumUsers(); i++ )
+ {
+ User &user=battle->GetUser(i);
+ if (&user == &(battle->GetMe()))continue;// dont include myself (change in copypasta)
+
+ UserOrder tmp;
+ tmp.index=i;
+ ordered_users.push_back(tmp);
+ }
+ std::sort(ordered_users.begin(),ordered_users.end());
+
+
+ for (int i=0;i<int(ordered_users.size());++i)
+ {
+ User &user=battle->GetUser(ordered_users[i].index);
+
+ wxString ip=user.BattleStatus().ip;
+ unsigned int port=user.BattleStatus().udpport;
+
+ unsigned int src_port=m_udp_private_port;
+ if ( battle->GetNatType() == NAT_Fixed_source_ports )
+ {
+ port = FIRST_UDP_SOURCEPORT + i;
+ }
+
+ wxLogMessage(_T(" pinging nick=%s , ip=%s , port=%u"),user.GetNick().c_str(),ip.c_str(),port);
+
+ if (port!=0 && !ip.empty())
+ {
+ UdpPing(src_port,ip,port,_T("hai!"));
+ }
+ }
+}
+
+
+//! @brief used to check if the NAT is done properly when hosting
+int TASServer::TestOpenPort( unsigned int port )
+{
+ wxIPV4address local_addr;
+ local_addr.AnyAddress(); // <--- THATS ESSENTIAL!
+ local_addr.Service(port);
+
+ wxSocketServer udp_socket(local_addr, wxSOCKET_NONE);
+
+ wxHTTP connect_to_server;
+ connect_to_server.SetTimeout( 10 );
+
+ if ( !connect_to_server.Connect( _T("zjt3.com") ) ) return porttest_unreachable;
+ connect_to_server.GetInputStream(wxString::Format( _T("/porttest.php?port=%u"), port));
+
+ if (udp_socket.IsOk())
+ {
+ if ( !udp_socket.WaitForAccept( 10 ) ) return porttest_timeout;
+ }
+ else
+ {
+ wxLogMessage(_T("socket's IsOk() is false, no UDP packets can be checked"));
+ return porttest_socketNotOk;
+ }
+ if (udp_socket.Error())
+ {
+ wxLogMessage(_T("Error=%d"),udp_socket.LastError());
+ return porttest_socketError;
+ }
+ return porttest_pass;
+}
+
+void TASServer::RequestSpringUpdate()
+{
+ SendCmd( _T("REQUESTUPDATEFILE"), _T("Spring ") + usync().GetSpringVersion() );
+}
+
+wxArrayString TASServer::GetRelayHostList()
+{
+ wxArrayString ret;
+ for ( unsigned int i = 0; i < m_relay_host_manager_list.GetCount(); i++ )
+ {
+ try
+ {
+ User& manager = GetUser( m_relay_host_manager_list[i] );
+ if ( manager.Status().in_game ) continue; // skip the manager is not connected or reports it's ingame ( no slots available ), or it's away ( functionality disabled )
+ if ( manager.Status().away ) continue;
+ ret.Add( m_relay_host_manager_list[i] );
+ }
+ catch(...){}
+ }
+ return ret;
+}
+
+////////////////////////
+// Utility functions
+//////////////////////
+
+UserStatus ConvTasclientstatus( TASClientstatus tas )
+{
+ UserStatus stat;
+ stat.in_game = tas.in_game;
+ stat.away = tas.away;
+ stat.rank = (UserStatus::RankContainer)tas.rank;
+ stat.moderator = tas.moderator;
+ stat.bot = tas.bot;
+ return stat;
+}
+
+UserBattleStatus ConvTasbattlestatus( TASBattleStatus tas )
+{
+ UserBattleStatus stat;
+ stat.ally = tas.ally;
+ stat.handicap = tas.handicap;
+ stat.ready = (tas.ready==1)?true:false;
+ stat.side = tas.side;
+ stat.spectator = (tas.player == 0)?true:false;
+ stat.sync = tas.sync;
+ stat.team = tas.team;
+ return stat;
+}
+
+
+TASBattleStatus ConvTasbattlestatus( UserBattleStatus bs)
+{
+ TASBattleStatus stat;
+ stat.ally = bs.ally;
+ stat.handicap = bs.handicap;
+ stat.ready = bs.ready?1:0;
+ stat.side = bs.side;
+ stat.player = bs.spectator?0:1;
+ stat.sync = bs.sync;
+ stat.team = bs.team;
+ return stat;
+}
+
+
+IBattle::StartType IntToStartType( int start )
+{
+ switch ( start )
+ {
+ case 0:
+ return IBattle::ST_Fixed;
+ case 1:
+ return IBattle::ST_Random;
+ case 2:
+ return IBattle::ST_Choose;
+ default:
+ ASSERT_EXCEPTION( false, _T("invalid value") );
+ };
+ return IBattle::ST_Fixed;
+}
+
+
+NatType IntToNatType( int nat )
+{
+ switch ( nat )
+ {
+ case 0:
+ return NAT_None;
+ case 1:
+ return NAT_Hole_punching;
+ case 2:
+ return NAT_Fixed_source_ports;
+ default:
+ ASSERT_EXCEPTION( false, _T("invalid value") );
+ };
+ return NAT_None;
+}
+
+
+IBattle::GameType IntToGameType( int gt )
+{
+ switch ( gt )
+ {
+ case 0:
+ return IBattle::GT_ComContinue;
+ case 1:
+ return IBattle::GT_ComEnds;
+ case 2:
+ return IBattle::GT_Lineage;
+ default:
+ ASSERT_EXCEPTION( false, _T("invalid value") );
+ };
+ return IBattle::GT_ComContinue;
+}
diff --git a/src/tasserver.h b/src/tasserver.h
new file mode 100644
index 0000000..6bc2ef4
--- /dev/null
+++ b/src/tasserver.h
@@ -0,0 +1,215 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_TASSERVER_H
+#define SPRINGLOBBY_HEADERGUARD_TASSERVER_H
+
+#include <wx/string.h>
+#include <wx/longlong.h>
+#include <list>
+
+#include "server.h"
+#include "crc.h"
+
+const unsigned int FIRST_UDP_SOURCEPORT = 8300;
+
+class Ui;
+class Socket;
+class User;
+struct UserBattleStatus;
+class ServerEvents;
+class wxString;
+
+//! @brief TASServer protocol implementation.
+class TASServer : public Server
+{
+ public:
+ TASServer();
+ ~TASServer();
+
+ // Overloaded functions from Server
+ bool ExecuteSayCommand( const wxString& cmd );
+
+ void SetSocket( Socket* sock );
+
+ bool Register( const wxString& addr, const int port, const wxString& nick, const wxString& password,wxString& reason );
+ void AcceptAgreement();
+
+ void Connect( const wxString& servername, const wxString& addr, const int port );
+ void Disconnect();
+ bool IsConnected();
+
+ void Login();
+ void Logout();
+ bool IsOnline() const;
+
+ void Update( int mselapsed );
+
+ void Ping();
+
+ void UDPPing();/// used for nat travelsal
+ /// generic udp "ping" function
+ /// return value: actual source port which was used. May differ from src_port
+ /// 0 if udp ping failed
+ unsigned int UdpPing(unsigned int src_port, const wxString &target, unsigned int target_port, const wxString &message);
+ /// specialized udp ping functions
+ void UdpPingTheServer( const wxString &message );/// used for nat travelsal. pings the server.
+ void UdpPingAllClients();/// used when hosting with nat holepunching
+
+ User& GetMe() const;
+
+ void JoinChannel( const wxString& channel, const wxString& key );
+ void PartChannel( const wxString& channel );
+
+ void DoActionChannel( const wxString& channel, const wxString& msg );
+ void SayChannel( const wxString& channel, const wxString& msg );
+
+ void DoActionPrivate( const wxString& nick, const wxString& msg );
+ void SayPrivate( const wxString& nick, const wxString& msg );
+
+ void SayBattle( int battleid, const wxString& msg );
+ void DoActionBattle( int battleid, const wxString& msg );
+
+ void Ring( const wxString& nick );
+
+ void ModeratorSetChannelTopic( const wxString& channel, const wxString& topic );
+ void ModeratorSetChannelKey( const wxString& channel, const wxString& key );
+ void ModeratorMute( const wxString& channel, const wxString& nick, int duration, bool byip );
+ void ModeratorUnmute( const wxString& channel, const wxString& nick );
+ void ModeratorKick( const wxString& channel, const wxString& reason );
+ void ModeratorBan( const wxString& nick, bool byip );
+ void ModeratorUnban( const wxString& nick );
+ void ModeratorGetIP( const wxString& nick );
+ void ModeratorGetLastLogin( const wxString& nick );
+ void ModeratorGetLastIP( const wxString& nick );
+ void ModeratorFindByIP( const wxString& ipadress );
+
+ void AdminGetAccountAccess( const wxString& nick );
+ void AdminChangeAccountAccess( const wxString& nick, const wxString& accesscode );
+ void AdminSetBotMode( const wxString& nick, bool isbot );
+
+ void HostBattle( BattleOptions bo, const wxString& password = _T("") );
+ void JoinBattle( const int& battleid, const wxString& password = _T("") );
+ void LeaveBattle( const int& battleid );
+ void SendMyBattleStatus( UserBattleStatus& bs );
+ void SendMyUserStatus();
+
+ void ForceSide( int battleid, User& user, int side );
+ void ForceTeam( int battleid, User& user, int team );
+ void ForceAlly( int battleid, User& user, int ally );
+ void ForceColour( int battleid, User& user, const wxColour& col );
+ void ForceSpectator( int battleid, User& user, bool spectator );
+ void BattleKickPlayer( int battleid, User& user );
+ void SetHandicap( int battleid, User& user, int handicap);
+
+ void AddBot( int battleid, const wxString& nick, UserBattleStatus& status );
+ void RemoveBot( int battleid, User& bot );
+ void UpdateBot( int battleid, User& bot, UserBattleStatus& status );
+
+ void StartHostedBattle();
+ void SendHostInfo( HostInfo update );
+ void SendHostInfo( const wxString& Tag );
+ void SendUserPosition( const User& user );
+
+ void SendRaw( const wxString& raw );
+
+ void RequestInGameTime( const wxString& nick );
+
+ void SendUdpSourcePort( int udpport );
+ void SendNATHelperInfos( const wxString& username, const wxString& ip, int port );
+
+ Battle* GetCurrentBattle();
+
+ void RequestChannels();
+ // TASServer specific functions
+ void ExecuteCommand( const wxString& in );
+ void ExecuteCommand( const wxString& cmd, const wxString& inparams, int replyid = -1 );
+
+ void HandlePong( int replyid );
+
+ void OnConnected( Socket* sock );
+ void OnDisconnected( Socket* sock );
+ void OnDataReceived( Socket* sock );
+
+ bool IsPasswordHash( const wxString& pass ) const;
+ wxString GetPasswordHash( const wxString& pass ) const;
+
+ int TestOpenPort( unsigned int port );
+
+ void SendScriptToProxy( const wxString& script );
+
+ void SendScriptToClients( const wxString& script );
+
+ void RequestSpringUpdate();
+
+ wxArrayString GetRelayHostList();
+
+ protected:
+
+ //! @brief Struct used internally by the TASServer class to calculate ping roundtimes.
+ struct TASPingListItem {
+ int id;
+ wxLongLong t;
+ };
+
+ CRC m_crc;
+
+ ServerEvents* m_se;
+ double m_ser_ver;
+
+ wxString m_last_denied;
+ bool m_connected;
+ bool m_online;
+ bool m_debug_dont_catch;
+ bool m_id_transmission;
+ bool m_redirecting;
+ wxString m_buffer;
+ time_t m_last_udp_ping;
+ time_t m_last_net_packet;
+ unsigned int m_last_id;
+ std::list<TASPingListItem> m_pinglist;
+
+ unsigned long m_udp_private_port;
+ unsigned long m_nat_helper_port;
+
+ int m_battle_id;
+
+ bool m_server_lanmode;
+
+ wxString m_agreement;
+
+ wxString m_addr;
+ wxString m_delayed_open_command;
+
+ bool m_do_finalize_join_battle;
+ int m_finalize_join_battle_id;
+ wxString m_finalize_join_battle_pw;
+ bool m_token_transmission;
+
+ void FinalizeJoinBattle();
+
+ void SendCmd( const wxString& command, const wxString& param = _T("") );
+ void RelayCmd( const wxString& command, const wxString& param = _T("") );
+ void FillAliasMap();
+
+ wxString m_current_chan_name_mutelist;
+
+ wxArrayString m_relay_host_manager_list;
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_TASSERVER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/tasservertokentable.h b/src/tasservertokentable.h
new file mode 100644
index 0000000..de42cbf
--- /dev/null
+++ b/src/tasservertokentable.h
@@ -0,0 +1,143 @@
+#ifndef TASSERVERTOKENTABLE_H_INCLUDED
+#define TASSERVERTOKENTABLE_H_INCLUDED
+
+#include <wx/string.h>
+#include <map>
+
+static std::map<wxString,wxString> m_command_alias;
+static std::map<wxString,wxString> m_send_command_alias;
+
+void TASServer::FillAliasMap()
+{
+ m_command_alias[_T("#")] = _T("PING");
+ m_command_alias[_T("$")] = _T("PONG");
+ m_command_alias[_T("%")] = _T("TASSERVER");
+ m_command_alias[_T("&")] = _T("REQUESTUPDATEFILE");
+ m_command_alias[_T("'")] = _T("REGISTER");
+ m_command_alias[_T("(")] = _T("REGISTRATIONDENIED");
+ m_command_alias[_T(")")] = _T("REGISTRATIONACCEPTED");
+ m_command_alias[_T("*")] = _T("RENAMEACCOUNT");
+ m_command_alias[_T("+")] = _T("CHANGEPASSWORD");
+ m_command_alias[_T(",")] = _T("LOGIN");
+ m_command_alias[_T("-")] = _T("ACCEPTED");
+ m_command_alias[_T(".")] = _T("DENIED");
+ m_command_alias[_T("/")] = _T("LOGININFOEND");
+ m_command_alias[_T("0")] = _T("AGREEMENT");
+ m_command_alias[_T("1")] = _T("AGREEMENTEND");
+ m_command_alias[_T("2")] = _T("CONFIRMAGREEMENT");
+ m_command_alias[_T("3")] = _T("MOTD");
+ m_command_alias[_T("4")] = _T("OFFERFILE");
+ m_command_alias[_T("5")] = _T("UDPSOURCEPORT");
+ m_command_alias[_T("6")] = _T("CLIENTIPPORT");
+ m_command_alias[_T("7")] = _T("HOSTPORT");
+ m_command_alias[_T("8")] = _T("SERVERMSG");
+ m_command_alias[_T("9")] = _T("SERVERMSGBOX");
+ m_command_alias[_T(":")] = _T("ADDUSER");
+ m_command_alias[_T(";")] = _T("REMOVEUSER");
+ m_command_alias[_T("<")] = _T("JOIN");
+ m_command_alias[_T("=")] = _T("JOINFAILED");
+ m_command_alias[_T(">")] = _T("CHANNELS");
+ m_command_alias[_T("?")] = _T("CHANNEL");
+ m_command_alias[_T("@")] = _T("ENDOFCHANNELS");
+ m_command_alias[_T("A")] = _T("MUTELIST");
+ m_command_alias[_T("B")] = _T("MUTELISTBEGIN");
+ m_command_alias[_T("C")] = _T("MUTELISTEND");
+ m_command_alias[_T("D")] = _T("CHANNELTOPIC");
+ m_command_alias[_T("E")] = _T("CLIENTS");
+ m_command_alias[_T("F")] = _T("JOINED");
+ m_command_alias[_T("G")] = _T("LEAVE");
+ m_command_alias[_T("H")] = _T("LEFT");
+ m_command_alias[_T("I")] = _T("FORCELEAVECHANNEL");
+ m_command_alias[_T("J")] = _T("CHANNELMESSAGE");
+ m_command_alias[_T("K")] = _T("SAY");
+ m_command_alias[_T("L")] = _T("SAID");
+ m_command_alias[_T("M")] = _T("SAYEX");
+ m_command_alias[_T("N")] = _T("SAIDEX");
+ m_command_alias[_T("O")] = _T("SAYPRIVATE");
+ m_command_alias[_T("P")] = _T("SAIDPRIVATE");
+ m_command_alias[_T("Q")] = _T("OPENBATTLE");
+ m_command_alias[_T("R")] = _T("BATTLEOPENED");
+ m_command_alias[_T("S")] = _T("BATTLECLOSED");
+ m_command_alias[_T("T")] = _T("JOINBATTLE");
+ m_command_alias[_T("U")] = _T("JOINEDBATTLE");
+ m_command_alias[_T("V")] = _T("LEFTBATTLE");
+ m_command_alias[_T("W")] = _T("LEAVEBATTLE");
+ m_command_alias[_T("X")] = _T("JOINBATTLEFAILED");
+ m_command_alias[_T("Y")] = _T("OPENBATTLEFAILED");
+ m_command_alias[_T("Z")] = _T("UPDATEBATTLEINFO");
+ m_command_alias[_T("[")] = _T("SAYBATTLE");
+ m_command_alias[_T("\\")] = _T("SAIDBATTLE");
+ m_command_alias[_T("]")] = _T("SAYBATTLEEX");
+ m_command_alias[_T("^")] = _T("SAIDBATTLEEX");
+ m_command_alias[_T("_")] = _T("MYSTATUS");
+ m_command_alias[_T("`")] = _T("CLIENTSTATUS");
+ m_command_alias[_T("a")] = _T("MYBATTLESTATUS");
+ m_command_alias[_T("b")] = _T("CLIENTBATTLESTATUS");
+ m_command_alias[_T("c")] = _T("REQUESTBATTLESTATUS");
+ m_command_alias[_T("d")] = _T("HANDICAP");
+ m_command_alias[_T("e")] = _T("KICKFROMBATTLE");
+ m_command_alias[_T("f")] = _T("FORCEQUITBATTLE");
+ m_command_alias[_T("g")] = _T("FORCETEAMNO");
+ m_command_alias[_T("h")] = _T("FORCEALLYNO");
+ m_command_alias[_T("i")] = _T("FORCETEAMCOLOR");
+ m_command_alias[_T("j")] = _T("FORCESPECTATORMODE");
+ m_command_alias[_T("k")] = _T("DISABLEUNITS");
+ m_command_alias[_T("l")] = _T("ENABLEUNITS");
+ m_command_alias[_T("m")] = _T("ENABLEALLUNITS");
+ m_command_alias[_T("n")] = _T("RING");
+ m_command_alias[_T("o")] = _T("REDIRECT");
+ m_command_alias[_T("p")] = _T("BROADCAST");
+ m_command_alias[_T("q")] = _T("ADDBOT");
+ m_command_alias[_T("r")] = _T("REMOVEBOT");
+ m_command_alias[_T("s")] = _T("UPDATEBOT");
+ m_command_alias[_T("t")] = _T("ADDSTARTRECT");
+ m_command_alias[_T("u")] = _T("REMOVESTARTRECT");
+ m_command_alias[_T("v")] = _T("MAPGRADES");
+ m_command_alias[_T("w")] = _T("MAPGRADESFAILED");
+ m_command_alias[_T("x")] = _T("SCRIPTSTART");
+ m_command_alias[_T("y")] = _T("SCRIPT");
+ m_command_alias[_T("z")] = _T("SCRIPTEND");
+ m_command_alias[_T("{")] = _T("SETSCRIPTTAGS");
+ m_command_alias[_T("|")] = _T("TESTLOGIN");
+ m_command_alias[_T("}")] = _T("TESTLOGINACCEPT");
+ m_command_alias[_T("~")] = _T("TESTLOGINDENY");
+ m_command_alias[_T("")] = _T("ACQUIREUSERID");
+ m_command_alias[_T("Â")] = _T("USERID");
+ for ( std::map<wxString,wxString>::iterator i = m_command_alias.begin(); i != m_command_alias.end(); i++) m_send_command_alias[i->second] = i->first; //swap content for second map
+}
+
+// returns original if not found
+wxString DecodeTokenMessage( const wxString& cmd )
+{
+ std::map<wxString,wxString>::iterator it = m_command_alias.find( cmd );
+ if ( it != m_command_alias.end() ) return it->second;
+ else return cmd;
+}
+
+// returns original if not found
+wxString EncodeTokenMessage( const wxString& cmd )
+{
+ std::map<wxString,wxString>::iterator it = m_send_command_alias.find( cmd );
+ if ( it != m_send_command_alias.end() ) return it->second;
+ else return cmd;
+}
+
+#endif // TASSERVERTOKENTABLE_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/tdfcontainer.cpp b/src/tdfcontainer.cpp
new file mode 100644
index 0000000..d1a9242
--- /dev/null
+++ b/src/tdfcontainer.cpp
@@ -0,0 +1,726 @@
+#include "tdfcontainer.h"
+
+#include "utils/conversion.h"
+#include "utils/debug.h"
+#include <wx/intl.h>
+#include <wx/tokenzr.h>
+#include <wx/log.h>
+#include <cmath>
+
+TDFWriter::TDFWriter( wxString &s ):
+ m_stream( s ),
+ m_depth( 0 )
+{
+
+}
+
+TDFWriter::~TDFWriter() {
+ Close();
+}
+void TDFWriter::EnterSection( const wxString &name ) {
+ Indent();
+ m_stream << _T( "[" ) << name << _T( "]\n" );
+ Indent();
+ m_stream << _T( "{\n" );
+ m_depth++;
+}
+void TDFWriter::LeaveSection() {
+ m_depth--;
+ Indent();
+ m_stream << _T( "}\n" );
+}
+void TDFWriter::Indent() {
+ for ( int i = 0;i < m_depth;++i )m_stream << _T( "\t" );
+}
+//wxString GetCurrentPath();
+void TDFWriter::Append( const wxString &name, wxString value ) {
+ Indent();
+ m_stream << name << _T( "=" ) << value << _T( ";\n" );
+}
+
+void TDFWriter::Close() {
+ while ( m_depth > 0 )LeaveSection();
+ if ( m_depth < 0 )wxLogWarning( _T( "error in TDFWriter usage: more LeaveSection() calls than EnterSection(). Please contact springlobby developers" ) );
+}
+
+void TDFWriter::AppendLineBreak() {
+ m_stream << _T( "\n" );
+}
+
+#include "sstream"
+#include "fstream"
+#include <iomanip>
+#include <algorithm>
+
+
+void Tokenizer::ReportError( const Token &t, const wxString &err ) {
+ wxLogMessage( _T( "TDF parsing error at (%s), on token \"%s\" : %s" ), t.pos_string.c_str(), t.value_s.c_str(), err.c_str() );
+ errors++;
+}
+
+//#define ReportError(a) {std::cerr<<"error "<<(a);}
+//#define ReportError(a) {wxLogMessage(_T("error %s"),TowxString(a).c_str());}
+
+void Tokenizer::EnterStream( std::istream &stream_, const wxString &name ) {
+ skip_eol = false;
+ include_stack.push_back( IncludeCacheEntry( &stream_, false ) );
+ include_stack.back().name = name;
+ include_stack.back().line = 1;
+ include_stack.back().column = 1;
+};
+void Tokenizer::UnwindStack() {
+ while ( ( !include_stack.empty() ) && include_stack.back().stream && ( !include_stack.back().stream->good() ) ) {
+ include_stack.pop_back();
+ }
+};
+
+char Tokenizer::PeekNextChar() {
+ UnwindStack();
+ //std::string tmp;
+ char tmp = 0;
+ if ( !include_stack.empty() )tmp = ( *include_stack.back().stream ).peek();
+ return tmp;
+}
+
+char Tokenizer::GetNextChar() {
+ UnwindStack();
+ //std::string tmp;
+ if ( include_stack.empty() )return 0;
+
+ char c = ( *include_stack.back().stream ).get();
+
+ if ( ( !skip_eol ) && ( c == 10 || c == 13 ) ) {// end of line
+ include_stack.back().line += 1;
+ include_stack.back().column = 1;
+
+ // if next is different we'll skip it.
+ //std::istream &stream=(*include_stack.back().stream);
+ char nc = ( *include_stack.back().stream ).peek();
+ if ( ( nc == 10 || nc == 13 ) && ( nc != c ) )skip_eol = true;
+ } else {
+ if ( !skip_eol )include_stack.back().column += 1;
+ skip_eol = false;
+ }
+
+ return c;
+};
+bool Tokenizer::Good() {
+ UnwindStack();
+ return !include_stack.empty();
+};
+
+void Tokenizer::ReadToken( Token &token ) {
+start:
+
+ SkipSpaces();
+
+
+ token.value_s.clear();
+
+ if ( !Good() ) {
+ token.type = Token::type_eof;
+ token.pos_string = _T( "EOF" );
+ return;
+ }
+
+ token.pos_string = wxString();
+ if ( !include_stack.empty() && !include_stack.back().name.empty() )token.pos_string << include_stack.back().name << _T( " , " );
+ token.pos_string << _( "line " ) << include_stack.back().line << _( " , column " ) << include_stack.back().column;
+
+ char c = GetNextChar();
+ token.value_s += c;
+ // first find what token is it, and handle all except numbers
+ switch ( c ) {
+ case '[': {
+ token.type = Token::type_section_name;
+ token.value_s.clear();
+ bool skip_next_eol_char = false;
+ while ( Good() ) {
+ c = GetNextChar();
+ // wxString has problem with zero characters, replace by space.
+ if ( c == 0 ) {
+ c = ' ';
+ }
+ if ( c == '\\' ) {
+ if ( Good() ) {
+ token.value_s += GetNextChar();
+ } else {
+ ReportError( token, wxT( "Quotes not closed before end of file" ) );
+ return;
+ }
+ } else if ( c == ']' ) {
+ return;
+ } else
+ {
+ token.value_s += c;
+ }
+ // handle end of line
+ if ( skip_next_eol_char ) {
+ skip_next_eol_char = false;
+ } else if ( c == 10 || c == 13 ) {
+ //++line;
+ //column=1;
+ if ( ( PeekNextChar() == 10 || PeekNextChar() == 13 ) && ( PeekNextChar() != c ) )skip_next_eol_char = true;
+ }
+ }
+ ReportError( token, wxT( "Quotes not closed before end of file" ) );
+ }
+ case '{':
+ token.type = Token::type_enter_section;
+ return;
+ case '}':
+ token.type = Token::type_leave_section;
+ return;
+ case ';':
+ token.type = Token::type_semicolon;
+ return;
+ case '=':
+ token.type = Token::type_entry_value;
+ token.value_s = _T( "" );
+ while ( Good() && PeekNextChar() != ';' ) {
+ unsigned char c = GetNextChar();
+ token.value_s += c;
+ }
+ return;
+ case '/':// handle comments
+ if ( PeekNextChar() == '/' ) {
+ //SkipToEOL();
+ if ( !include_stack.empty() ) {
+ std::string tmp;
+ std::getline( ( *include_stack.back().stream ), tmp );
+ include_stack.back().line += 1;
+ include_stack.back().column = 1;
+ }
+
+ goto start;
+ }
+ else if ( PeekNextChar() == '*' ) {// multi-line comment
+ while ( Good() ) {
+ char c1 = GetNextChar();
+ if ( ( c1 == '*' ) && ( PeekNextChar() == '/' ) ) {
+ GetNextChar();
+ break;
+ }
+ }
+ goto start;
+ }
+ default:
+ while ( Good() && PeekNextChar() != '=' ) {
+ unsigned char c = GetNextChar();
+ token.value_s += c;
+ }
+ token.type = Token::type_entry_name;
+ return;
+ }
+};
+
+void Tokenizer::SkipSpaces() {
+ while ( Good() && IsWhitespace( PeekNextChar() ) ) {
+ GetNextChar();
+ }
+}
+
+Token Tokenizer::GetToken( int i ) {
+ int p = buffer_pos + i;
+ if ( p < 0 )return Token();
+ while ( int( token_buffer.size() ) < p + 1 ) {
+ Token t;
+ ReadToken( t );
+ if ( t.IsEOF() )return t;
+ token_buffer.push_back( t );
+ }
+
+ return token_buffer[p];
+};
+
+void Tokenizer::Step( int i ) {
+ buffer_pos += i;
+};
+
+Node::~Node() {
+ //if(parent)parent->Remove(name);
+}
+
+DataList* Node::Parent() const { // parent list
+ return parent;
+}
+
+bool Node::IsChildOf( DataList *what ) const {
+ DataList *current = Parent();
+ while ( current ) {
+ if ( current == what )return true;
+ current = current->Parent();
+ }
+ return false;
+}
+
+void Node::ListRemove() {
+ //if(parent->list_first==this)parent->list_first=next;
+ //if(parent->list_last==this)parent->list_last=prev;
+ if ( list_prev ) {
+ list_prev->list_next = this->list_next;
+ }
+ if ( list_next ) {
+ list_next->list_prev = this->list_prev;
+ }
+ list_prev = NULL;
+ list_next = NULL;
+}
+
+void Node::ListInsertAfter( Node *what ) {
+ ListRemove();
+ if ( !what )return;
+ this->list_next = what->list_next;
+ if ( what->list_next )what->list_next->list_prev = this;
+ what->list_next = this;
+ this->list_prev = what;
+}
+
+wxString Node::Name() {
+ return name;
+}
+bool Node::SetName( const wxString &name_ ) {
+ if ( parent ) {
+ return parent->Rename( name, name_ );
+ }
+ name = name_;
+ return true;
+}
+
+void Node::Save( TDFWriter &/*unused*/ ) {
+ /// nothing to save there.
+}
+void Node::Load( Tokenizer &/*unused*/ ) {
+ /// nothing to load there.
+ //ASSERT_LOGIC(0,_T("this function should not be called."));
+}
+
+/// ***********************************************************
+/// class DataList
+/// ***********************************************************
+
+DataList::DataList() {
+ //parent = NULL;
+ list_loop.list_prev = &list_loop;
+ list_loop.list_next = &list_loop;
+ list_loop.parent = this;
+ list_loop.Reference();
+}
+
+DataList::~DataList() {// disconnect from childs
+ PNode node = First();
+ while ( node.Ok() && node != End() ) {
+ //std::cout<<"printing"<<std::endl;
+ PNode nextnode = Next( node );
+ node->parent = NULL;
+ node->ListRemove();
+ node = nextnode;
+ }
+}
+
+bool DataList::Insert( PNode node )/// return false if such entry already exists.
+{
+ if ( !node.Ok() )return false;
+ bool inserted = nodes.insert( std::pair<wxString, PNode>( ( *node ).name.Lower(), node ) ).second;
+ if ( !inserted )return false;
+
+ node->parent = this;
+ node->ListInsertAfter( list_loop.list_prev );
+ return true;
+}
+
+bool DataList::InsertAt( PNode node, PNode where )/// return false if such entry already exists.
+{
+ if ( !node.Ok() )return false;
+ if ( !( where->list_prev ) )return false;
+ bool inserted = nodes.insert( std::pair<wxString, PNode>( ( *node ).name, node ) ).second;
+ if ( !inserted )return false;
+
+ node->parent = this;
+ node->ListInsertAfter( where->list_prev );
+ return true;
+}
+
+#ifdef use_std_string
+static const char* rename_prefix = "!";
+#else
+static const wxChar* rename_prefix = _T( "!" );
+#endif
+
+void DataList::InsertRename( PNode node ) {/// rename if such entry already exists. str contains new name.
+ if ( !node.Ok() )return;
+
+ if ( !Insert( node ) ) {
+ wxString original_name = node->Name();
+ for ( int n = 0;n < 10000;++n ) {
+ //wxString tmp=str+wxString(rename_prefix);
+#ifdef use_std_string
+ std::ostringstream os;
+ os << original_name << rename_prefix << n;
+ node->name = os.str();
+#else
+ wxString tmp;
+ tmp << original_name;
+ tmp << rename_prefix;
+ tmp << n;
+ node->name = tmp;
+#endif
+ if ( Insert( node ) ) {
+ return;
+ }
+ }
+ wxLogError( _T( "insertRename: iterated over 10 000 names, way too many" ) );
+ }
+}
+
+void DataList::InsertRenameAt( PNode node, PNode where ) {// rename if such entry already exists. str contains new name.
+ if ( !node.Ok() )return;
+ if ( !where->list_prev )return;
+
+ if ( !InsertAt( node, where ) ) {
+ for ( int n = 0;n < 10000;++n ) {
+
+#ifdef use_std_string
+ std::ostringstream os;
+ os << node->Name() << rename_prefix << n;
+ node->name = os.str();
+#else
+ wxString tmp;
+ tmp << ( node->Name() );
+ tmp << rename_prefix;
+ tmp << n;
+ node->name = tmp;
+#endif
+ if ( InsertAt( node, where ) ) {
+ return;
+ }
+ }
+ wxLogError( _T( "insertRename: iterated over 10 000 names, way too many" ) );
+ }
+}
+
+bool DataList::Remove( const wxString &str ) {
+ //PNode node=nodes.find(str.Lower())->last;
+ PNode node = Find( str );
+ if ( !node.Ok() )return false;
+ if ( nodes.erase( str.Lower() ) <= 0 ) return false;
+
+ node->parent = NULL;
+ node->ListRemove();
+ return true;
+}
+
+bool DataList::Remove( PNode node ) {
+ if ( !node.Ok() )return false;
+ if ( nodes.erase( node->Name().Lower() ) <= 0 ) return false;
+
+ node->parent = NULL;
+ node->ListRemove();
+ return true;
+}
+
+bool DataList::Rename( const wxString &old_name, const wxString &new_name ) {
+ // check that new name is not used up.
+ if ( nodes.find( new_name.Lower() ) != nodes.end() )return false;
+ nodes_iterator i = nodes.find( old_name.Lower() );
+ if ( i == nodes.end() )return false;
+ PNode node = i->second;
+
+ ASSERT_LOGIC( node.Ok(), _T( "Internal TDF tree consistency (1)" ) );
+ ASSERT_LOGIC( node->Name().Lower() == old_name.Lower(), _T( "Internal TDF tree consistency (2)" ) );
+
+ node->name = new_name.Lower();
+ nodes.erase( i );
+ bool inserted = nodes.insert( std::pair<wxString, PNode>( ( *node ).name.Lower(), node ) ).second;
+ ASSERT_LOGIC( inserted, _T( "DataList::Rename failed" ) );
+ return inserted;
+}
+
+/// find by name. unused.
+PNode DataList::Find( const wxString &str ) {
+ if ( str == _T( ".." ) )return Parent();
+ if ( str == _T( "." ) )return this;
+ nodes_iterator i = nodes.find( str.Lower() );
+ if ( i != nodes.end() ) {
+ ASSERT_LOGIC( i->second->Name().Lower() == str.Lower(), _T( "Internal TDF tree consistency (3)" ) );
+ return i->second;
+ }
+ return NULL;
+}
+
+wxString DataList::Path() {
+ wxString result;
+ PDataList tmp( this );
+ while ( tmp.Ok() ) {
+ result = wxString( _T( "/" ) ) + tmp->Name();
+ tmp = tmp->Parent();
+ }
+ return name;
+}
+
+PNode DataList::FindByPath( const wxString &str ) {
+ if ( str.empty() )return this;
+ int i = 0;
+ wxString buff;
+ PDataList current_dir( this );
+ if ( str[i] == '/' ) {// go to root
+ PDataList tmp = Parent();
+ while ( tmp.Ok() ) {
+ current_dir = tmp;
+ tmp = tmp->Parent();
+ }
+ }
+ else {
+ buff += str[0];
+
+ }
+ i = 1;
+ while ( ( unsigned int )( i ) < str.size() ) {
+ if ( str[i] == '/' ) {
+ if ( buff == _T( ".." ) ) {
+ current_dir = current_dir->Parent();
+ if ( !current_dir.Ok() )
+ return NULL;
+ }
+ else if ( buff != _T( "." ) && !buff.empty() ) {//
+ PNode node = current_dir->Find( buff );
+ if ( !node.Ok() )
+ return NULL;
+ PDataList datalist( node );
+ if ( datalist.Ok() ) {
+ current_dir = datalist;
+ }
+ else
+ return NULL;
+ }
+ buff = _T( "" );
+ }
+ else {
+ buff += str[i];
+ }
+ ++i;
+ }
+ if ( current_dir.Ok() ) {
+ if ( !buff.empty() ) {
+ return current_dir->Find( buff );
+ }
+ else
+ return PNode( current_dir );
+ }
+ else {
+ return NULL;
+ }
+}
+
+PNode DataList::Next( PNode what ) {
+ if ( what.Ok() )return what->list_next;
+ return NULL;
+}
+PNode DataList::Prev( PNode what ) {
+ if ( what.Ok() )return what->list_prev;
+ return NULL;
+}
+PNode DataList::End() {
+ return PNode( &list_loop );
+}
+PNode DataList::First() {
+ return PNode( list_loop.list_next );
+}
+PNode DataList::Last() {
+ return PNode( list_loop.list_prev );
+}
+
+/*
+void DataList::PrintContent(std::ostream &s) {
+ PNode node=First();
+
+ while(node.Ok() && node!=End()){
+ //std::cout<<"printing"<<std::endl;
+ #ifdef use_std_string
+ s<<std::endl<<"'"<<node->Name()<<"'={";
+ node->PrintContent(s);
+ s<<"}"<<std::endl;
+ #else
+ s<<std::endl<<"'"<<node->Name().mb_str()<<"'={";
+ node->PrintContent(s);
+ s<<"}"<<std::endl;
+ #endif
+ node=Next(node);
+ }
+}*/
+void DataList::Save( TDFWriter &f ) {
+ PNode node = First();
+ if ( node == End() )return;
+
+ while ( node.Ok() && node != End() ) {
+ // if class name is not set properly, continue
+ //if(node->ClassName().empty())continue;
+ PDataList list( node );
+ if ( list.Ok() ) {
+ f.EnterSection( list->Name() );
+ list->Save( f );
+ f.LeaveSection();
+ } else {
+ PDataLeaf leaf( node );
+ if ( leaf.Ok() ) {
+ leaf->Save( f );
+ }
+ }
+ node = Next( node );
+ }
+
+}
+
+void DataList::Load( Tokenizer &f ) {
+ while ( f.Good() ) {
+ Token t = f.TakeToken();
+ switch ( t.type ) {
+ case Token::type_leave_section:
+ case Token::type_eof:
+ return;
+ case Token::type_entry_name:
+ {
+ PDataLeaf new_leaf( new DataLeaf );
+ new_leaf->SetName( t.value_s );
+ new_leaf->Load( f );
+ Insert( PNode( new_leaf ) );
+ }
+ break;
+
+ case Token::type_section_name:
+ {
+ Token t2 = f.TakeToken();
+ if ( t2.type != Token::type_enter_section ) {
+ f.ReportError( t, _T( "'{' expected" ) );
+ } else {
+ PDataList new_list( new DataList );
+ new_list->SetName( t.value_s );
+ new_list->Load( f );// will eat the '}'
+ Insert( PNode( new_list ) );
+ }
+ }
+ break;
+ default:
+ f.ReportError( t, _T( "[sectionname] or entryname= expected." ) );
+ }
+
+ }
+}
+
+
+int DataList::GetInt( const wxString &name, int default_value, bool *it_worked ) {
+ PDataLeaf leaf( Find( name ) );
+ if ( !leaf.ok() ) {
+ if ( it_worked ) {
+ *it_worked = false;
+ }
+ return default_value;
+ }
+ wxString s = leaf->GetValue();
+ long result = default_value;
+ if ( !s.ToLong( &result ) ) {
+ if ( it_worked ) {
+ *it_worked = false;
+ }
+ return result;
+ }
+ if ( it_worked ) {
+ *it_worked = true;
+ }
+ return result;
+}
+double DataList::GetDouble( const wxString &name, double default_value, bool *it_worked ) {
+ PDataLeaf leaf( Find( name ) );
+ if ( !leaf.ok() ) {
+ if ( it_worked ) {
+ *it_worked = false;
+ }
+ return default_value;
+ }
+ wxString s = leaf->GetValue();
+ double result = default_value;
+ if ( !s.ToDouble( &result ) ) {
+ if ( it_worked ) {
+ *it_worked = false;
+ }
+ return result;
+ }
+ if ( it_worked ) {
+ *it_worked = true;
+ }
+ return result;
+
+}
+wxString DataList::GetString( const wxString &name, const wxString &default_value, bool *it_worked ) {
+ PDataLeaf leaf( Find( name ) );
+ if ( !leaf.ok() ) {
+ if ( it_worked ) {
+ *it_worked = false;
+ }
+ return default_value;
+ }
+ if ( it_worked ) {
+ *it_worked = true;
+ }
+ return leaf->GetValue();
+}
+int DataList::GetDoubleArray( const wxString &name, int n_values, double *values ) {
+ PDataLeaf leaf( Find( name ) );
+ if ( !leaf.ok() ) {
+ return 0;
+ }
+ wxStringTokenizer tok( leaf->GetValue() );
+ int i = 0;
+ int values_read = 0;
+ for ( i = 0;i < n_values && tok.HasMoreTokens();++i ) {
+ wxString s = tok.GetNextToken();
+ if ( s.ToDouble( values + i ) )values_read++;
+ }
+ return values_read;
+}
+
+wxColour DataList::GetColour( const wxString &name, const wxColour &default_value, bool *it_worked ) {
+ double values[3];
+ if ( GetDoubleArray( name, 3, values ) != 3 ) {
+ if ( it_worked ) {
+ *it_worked = false;
+ }
+ return default_value;
+ }
+ if ( it_worked ) {
+ *it_worked = true;
+ }
+ return wxColour( values[0]*255.99, values[1]*255.99, values[2]*255.99 );
+}
+
+
+wxString DataLeaf::GetValue() {
+ return value;
+}
+void DataLeaf::SetValue( const wxString &value_ ) {
+ value = value_;
+}
+
+void DataLeaf::Save( TDFWriter &f ) {
+ f.Append( Name(), GetValue() );
+}
+void DataLeaf::Load( Tokenizer &f ) {
+ Token t = f.TakeToken();
+ value = t.value_s;
+ t = f.TakeToken();
+ if ( t.value_s != _T( ";" ) ) {
+ f.ReportError( t, _T( "; expected" ) );
+ }
+}
+
+
+PDataList ParseTDF( std::istream &s, int *error_count ) {
+ Tokenizer t;
+ t.EnterStream( s );
+ PDataList result( new DataList );
+ result->Load( t );
+ if ( error_count ) {
+ *error_count = t.NumErrors();
+ }
+ return result;
+}
diff --git a/src/tdfcontainer.h b/src/tdfcontainer.h
new file mode 100644
index 0000000..4861a62
--- /dev/null
+++ b/src/tdfcontainer.h
@@ -0,0 +1,315 @@
+#ifndef TDFCONTAINER_H
+#define TDFCONTAINER_H
+
+#include <wx/string.h>
+#include <wx/colour.h>
+#include <wx/log.h>
+//#include "utils.h"
+
+class wxColour;
+/// Todo: add TDFContainer class.
+///
+
+class TDFWriter
+{
+ public:
+ TDFWriter( wxString &s );
+ ~TDFWriter();
+ void EnterSection( const wxString &name );
+ void LeaveSection();
+ void Indent();
+ wxString GetCurrentPath();
+ void Append( const wxString &name, wxString value );
+ template<class T>
+ void Append( const wxString &name, T value );
+
+ /// works like algorithms such as std::sort
+ template<class T> void Append( const wxString &name, T begin, T end );
+
+ void AppendLineBreak();
+ void Close();
+ protected:
+ private:
+ wxString &m_stream;
+ int m_depth;
+};
+
+///
+/// Parsing classes contributed by dmytry aka dizekat, copypasted from personal
+/// project: render_control_new/utils/parsing.h and cpp , database.h and cpp
+///
+
+#include <sstream>
+#include <vector>
+#include <deque>
+#include <map>
+
+#include "autopointers.h"
+
+class Node;
+typedef RefcountedPointer<Node> PNode;
+class DataList;
+typedef RefcountedPointer<DataList> PDataList;
+class DataLeaf;
+typedef RefcountedPointer<DataLeaf> PDataLeaf;
+
+class Tokenizer;
+
+class Node: public RefcountedContainer {
+ friend class DataList;
+ protected:
+ DataList *parent;
+ Node *list_prev;
+ Node *list_next;
+ void ListRemove();
+ void ListInsertAfter( Node *what );
+ wxString name;
+ public:
+
+ wxString Name();
+
+ // Sets the name, and updates parent if present
+ bool SetName( const wxString &name_ );
+ Node(): parent( NULL ), list_prev( NULL ), list_next( NULL ) {}
+ virtual ~Node();
+ DataList* Parent() const;// parent list
+ //void SetParent(DataList *parent_);
+ bool IsChildOf( DataList *what ) const;
+
+ virtual void Save( TDFWriter &f );
+ virtual void Load( Tokenizer &f );
+};
+
+
+/// Usage
+/// Parsing:
+
+/// int errs=0;
+/// PDataList root(ParseTDF(some istream, &errs));// errs is optional, gives number of errors when loading.
+
+/// Getting values:
+
+/// PDataList game(root->Find(_T("GAME")))
+/// if(!game.ok()){wxLogMessage(_T("Game tag is missing"));return false;}
+/// wxString gamename=game->GetString(_T("Mapname"));
+
+/// (see optional parameters for setting default and knowing if it failed)
+/// and so on and so forth.
+/// Saving tdf:
+///
+
+
+class DataList: public Node {
+ protected:
+ std::map<wxString, PNode> nodes;
+ Node list_loop;// next is first, prev is last in the list
+ typedef std::map<wxString, PNode>::iterator nodes_iterator;
+ public:
+ DataList();
+ ~DataList();
+
+ bool Insert( PNode node );// return false if such entry already exists.
+ bool InsertAt( PNode node, PNode where );// return false if such entry already exists. Inserts right before given
+
+ // rename if such entry already exists. Names is like name!1 or name!2 etc
+ void InsertRename( PNode node );
+ void InsertRenameAt( PNode node, PNode where );
+ bool Remove( const wxString &str );
+ bool Remove( PNode node );
+ bool Rename( const wxString &old_name, const wxString &new_name );
+ PNode Find( const wxString &str );// find by name
+
+ wxString Path();
+
+ PNode FindByPath( const wxString &str );
+
+ PNode Next( PNode what );
+ PNode Prev( PNode what );
+ PNode End();
+ PNode First();
+ PNode Last();
+
+ virtual void Save( TDFWriter &f );
+ virtual void Load( Tokenizer &f );
+
+ int GetInt( const wxString &name, int default_value = 0, bool *it_worked = NULL );
+ double GetDouble( const wxString &name, double default_value = 0, bool *it_worked = NULL );
+ wxString GetString( const wxString &name, const wxString &default_value = wxString(), bool *it_worked = NULL );
+ /// returns number of values that were successfully read
+ int GetDoubleArray( const wxString &name, int n_values, double *values );
+
+ wxColour GetColour( const wxString &name, const wxColour &default_value = wxColour( 0, 0, 0 ), bool *it_worked = NULL );
+
+};
+
+class DataLeaf: public Node {
+ friend class DataList;
+ protected:
+ wxString value;
+ public:
+ wxString GetValue();
+ void SetValue( const wxString &value );
+
+ virtual void Save( TDFWriter &f );
+ virtual void Load( Tokenizer &f );
+};
+
+inline bool IsLetter( char c ) {
+ return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c == '_' );
+}
+inline bool IsNum( char c ) {
+ return c >= '0' && c <= '9';
+}
+inline bool IsNumDot( char c ) {
+ return ( c >= '0' && c <= '9' ) || c == '.';
+}
+inline bool IsAlphaNum( char c ) {
+ return IsLetter( c ) || IsNum( c );
+}
+inline bool IsWhitespace( char c ) {
+ return ( c == ' ' ) || ( c == 10 ) || ( c == 13 ) || ( c == '\t' );
+}
+struct Token {
+ enum TokenType {
+ type_none,
+ type_section_name,
+ type_enter_section,
+ type_leave_section,
+ type_entry_name,
+ type_entry_value,
+ type_semicolon,
+ type_eof
+ };
+ TokenType type;
+ wxString value_s;
+
+ wxString pos_string;// for error reporting
+
+ bool IsEOF() {
+ return ( type == type_eof );
+ }
+ Token(): type( type_eof )
+ {
+ }
+
+};
+
+class Tokenizer {
+ /// todo: clean up, move to CPP file
+ struct IncludeCacheEntry {// simple reference counted pointer to stream.
+ wxString name;/// used for error reporting
+ int line, column;
+
+ std::istream *stream;
+ //bool must_delete;
+ int *refcount;
+ IncludeCacheEntry( std::istream *stream_, bool must_delete_ = false ):
+ stream( stream_ ),
+ refcount( NULL )
+ {
+ line = 1;
+ column = 1;
+ if ( must_delete_ ) {
+ refcount = new int;
+ ( *refcount ) = 1;
+ }
+ }
+ IncludeCacheEntry( const IncludeCacheEntry &other ) {
+ stream = other.stream;
+ refcount = other.refcount;
+ if ( refcount )( *refcount ) += 1;
+ }
+ ~IncludeCacheEntry()
+ {
+ if ( refcount ) {
+ ( *refcount )--;
+ if ( ( *refcount ) <= 0 ) {
+ delete stream;
+ delete refcount;
+ }
+ }
+ }
+ };
+ std::vector<IncludeCacheEntry> include_stack;
+ void UnwindStack();
+
+ std::deque<Token> token_buffer;
+ //size_t max_buffer_size;
+ size_t buffer_pos;
+
+ bool skip_eol;
+ char GetNextChar();
+ char PeekNextChar();
+
+ void ReadToken( Token &token );
+ void SkipSpaces();
+
+ int errors;
+
+ public:
+ Tokenizer(): buffer_pos( 0 ), skip_eol( false ), errors( 0 )
+ {
+ }
+
+ void EnterStream( std::istream &stream_, const wxString &name = _T( "" ) );
+
+ Token GetToken( int i = 0 );
+ void Step( int i = 1 );
+ inline Token TakeToken() {
+ Token result = GetToken();
+ Step();
+ return result;
+ }
+
+ bool Good();
+
+ void ReportError( const Token &t, const wxString &err );
+
+ int NumErrors() {
+ return errors;
+ }
+};
+
+inline Tokenizer &operator >>( Tokenizer &tokenizer, Token &token ) {
+ token = tokenizer.TakeToken();
+ return tokenizer;
+};
+
+PDataList ParseTDF( std::istream &s, int *error_count = NULL );
+
+//Defintions to not clutter up the class declaration
+template<class T> void TDFWriter:: Append( const wxString &name, T value )
+{
+ Append( name, TowxString( value ) );
+}
+
+template<class T>
+void TDFWriter::Append( const wxString &name, T begin, T end ) {
+ Indent();
+ m_stream << name << _T( "=" );
+ for ( T it = begin;it != end;++it ) {
+ if ( it != begin )m_stream << _T( " " );
+ m_stream << ( *it );
+ }
+ m_stream << _T( ";\n" );
+}
+
+#endif // TDFCONTAINER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/thingdef.h b/src/thingdef.h
new file mode 100644
index 0000000..713323e
--- /dev/null
+++ b/src/thingdef.h
@@ -0,0 +1,78 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: thingdef.h
+// Purpose: Definitions for wxThings
+// Author: John Labenski
+// Modified by:
+// Created: 1/08/1999
+// RCS-ID: $Id: thingdef.h,v 1.3 2006/08/24 19:35:58 jrl1 Exp $
+// Copyright: (c) John Labenski
+// Licence: wxWidgets licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef __WX_THINGDEF_H__
+#define __WX_THINGDEF_H__
+
+#include "wx/defs.h"
+
+//-----------------------------------------------------------------------------
+// The version of wxThings
+//-----------------------------------------------------------------------------
+
+#define WXTHINGS_MAJOR_VERSION 1
+#define WXTHINGS_MINOR_VERSION 0
+#define WXTHINGS_RELEASE_VERSION 0
+#define WXTHINGS_SUBRELEASE_VERSION 0
+#define WXTHINGS_VERSION_STRING _T("wxThings 1.0.0")
+
+// For non-Unix systems (i.e. when building without a configure script),
+// users of this component can use the following macro to check if the
+// current version is at least major.minor.release
+#define wxCHECK_WXTHINGS_VERSION(major,minor,release) \
+ (WXTHINGS_MAJOR_VERSION > (major) || \
+ (WXTHINGS_MAJOR_VERSION == (major) && WXTHINGS_MINOR_VERSION > (minor)) || \
+ (WXTHINGS_MAJOR_VERSION == (major) && WXTHINGS_MINOR_VERSION == (minor) && WXTHINGS_RELEASE_VERSION >= (release)))
+
+// ----------------------------------------------------------------------------
+// DLLIMPEXP macros
+// ----------------------------------------------------------------------------
+
+// These are our DLL macros (see the contrib libs like wxPlot)
+#ifdef WXMAKINGDLL_THINGS
+ #define WXDLLIMPEXP_THINGS WXEXPORT
+ #define WXDLLIMPEXP_DATA_THINGS(type) WXEXPORT type
+#elif defined(WXUSINGDLL)
+ #define WXDLLIMPEXP_THINGS WXIMPORT
+ #define WXDLLIMPEXP_DATA_THINGS(type) WXIMPORT type
+#else // not making nor using DLL
+ #define WXDLLIMPEXP_THINGS
+ #define WXDLLIMPEXP_DATA_THINGS(type) type
+#endif
+
+// ----------------------------------------------------------------------------
+// wxWidgets backwards compatibility macros
+// ----------------------------------------------------------------------------
+
+#include "wx/dynarray.h"
+#ifndef WX_DECLARE_OBJARRAY_WITH_DECL // for wx2.4 backwards compatibility
+ #define WX_DECLARE_OBJARRAY_WITH_DECL(T, name, expmode) WX_DECLARE_USER_EXPORTED_OBJARRAY(T, name, WXDLLIMPEXP_THINGS)
+#endif
+
+#endif // __WX_THINGDEF_H__
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/thread.cpp b/src/thread.cpp
new file mode 100644
index 0000000..d6ab90c
--- /dev/null
+++ b/src/thread.cpp
@@ -0,0 +1,156 @@
+#include "thread.h"
+#include <algorithm>
+#include <wx/log.h>
+
+Thread::Thread():
+ wxThread( wxTHREAD_JOINABLE ),
+ m_thread_sleep_semaphore( 0, 0 ),
+ m_must_exit( false )
+{
+}
+
+/** TODO this causes a segfault on exit for me (koshi) sometimes
+http://docs.wxwidgets.org/stable/wx_wxthread.html#wxthreadwait
+says to only call wxThread::Wait from another thread context
+**/
+Thread::~Thread() {
+ if ( IsAlive() )Wait();
+}
+
+bool Thread::Sleep( int milliseconds ) {
+ wxSemaError err = m_thread_sleep_semaphore.WaitTimeout( milliseconds );
+ return err == wxSEMA_TIMEOUT;
+}
+
+void Thread::WakeUp() {
+ m_thread_sleep_semaphore.Post();
+}
+
+Thread::ExitCode Thread::Wait() {
+ m_must_exit = true;
+ WakeUp();
+ return wxThread::Wait();
+}
+
+wxThreadError Thread::Run() {
+ m_must_exit = false;
+ return wxThread::Run();
+}
+
+bool Thread::TestDestroy() {
+ return wxThread::TestDestroy() || m_must_exit;
+}
+
+
+namespace
+{
+ struct WorkItemCompare
+ {
+ bool operator()( const WorkItem* a, const WorkItem* b )
+ {
+ return a->GetPriority() < b->GetPriority();
+ }
+ };
+};
+
+
+bool WorkItem::Cancel()
+{
+ wxLogMessage( _T( "cancelling WorkItem %p" ), this );
+ if ( m_queue == NULL ) return false;
+ return m_queue->Remove( this );
+}
+
+
+void WorkItemQueue::Push( WorkItem* item )
+{
+ if ( item == NULL ) return;
+ wxCriticalSectionLocker lock( m_lock );
+ m_queue.push_back( item );
+ std::push_heap( m_queue.begin(), m_queue.end(), WorkItemCompare() );
+ item->m_queue = this;
+}
+
+WorkItem* WorkItemQueue::Pop()
+{
+ wxCriticalSectionLocker lock( m_lock );
+ if ( m_queue.empty() ) return NULL;
+ WorkItem* item = m_queue.front();
+ std::pop_heap( m_queue.begin(), m_queue.end(), WorkItemCompare() );
+ m_queue.pop_back();
+ item->m_queue = NULL;
+ return item;
+}
+
+bool WorkItemQueue::Remove( WorkItem* item )
+{
+ wxCriticalSectionLocker lock( m_lock );
+ if ( m_queue.empty() ) return false;
+ // WARNING: this destroys the heap...
+ std::vector<WorkItem*>::iterator new_end =
+ std::remove( m_queue.begin(), m_queue.end(), item );
+ // did a WorkerThread process the item just before we got here?
+ if ( new_end == m_queue.end() ) return false;
+ m_queue.erase( new_end, m_queue.end() );
+ // recreate the heap...
+ std::make_heap( m_queue.begin(), m_queue.end(), WorkItemCompare() );
+ item->m_queue = NULL;
+ return true;
+}
+
+
+void WorkerThread::DoWork( WorkItem* item, int priority, bool toBeDeleted )
+{
+ wxLogMessage( _T( "scheduling WorkItem %p, prio = %d" ), item, priority );
+ item->m_priority = priority;
+ item->m_toBeDeleted = toBeDeleted;
+ m_workItems.Push( item );
+ WakeUp();
+}
+
+void* WorkerThread::Entry()
+{
+ WorkItem* item;
+
+ wxLogMessage( _T( "WorkerThread started" ) );
+
+ while ( !TestDestroy() ) {
+ // sleep an hour or until a new WorkItem arrives (DoWork() will wake us up).
+ Sleep( 3600 * 1000 );
+ while ( !TestDestroy() && ( item = m_workItems.Pop() ) != NULL ) {
+ try {
+ wxLogMessage( _T( "running WorkItem %p, prio = %d" ), item, item->m_priority );
+ item->Run();
+ }
+ catch ( ... ) {
+ // better eat all exceptions thrown by WorkItem::Run(),
+ // don't want to let the thread die on a single faulty WorkItem.
+ wxLogMessage( _T( "WorkerThread caught exception thrown by WorkItem::Run" ) );
+ }
+ CleanupWorkItem( item );
+ // give other threads some air
+ Yield();
+ }
+ }
+
+ // cleanup leftover WorkItems
+ while ( ( item = m_workItems.Pop() ) != NULL ) {
+ CleanupWorkItem( item );
+ }
+
+ wxLogMessage( _T( "WorkerThread stopped" ) );
+ return 0;
+}
+
+void WorkerThread::CleanupWorkItem( WorkItem* item )
+{
+ if ( item->m_toBeDeleted ) {
+ try {
+ delete item;
+ }
+ catch ( ... ) {
+ // idem, eat exceptions from destructor
+ wxLogMessage( _T( "WorkerThread caught exception thrown by WorkItem::~WorkItem" ) );
+ }
+ }
+}
diff --git a/src/thread.h b/src/thread.h
new file mode 100644
index 0000000..8dadd28
--- /dev/null
+++ b/src/thread.h
@@ -0,0 +1,120 @@
+#ifndef THREAD_H
+#define THREAD_H
+#include <wx/thread.h>
+#include <vector>
+
+/// joinable thread, with overridden Sleep and Wait methods.
+/// Sleep wakes up when you call Wait()
+class Thread: public wxThread
+{
+ public:
+ Thread();
+ /// destructor Waits for thread to complete
+ ~Thread();
+ /// overrides wxThread::Wait . Wakes up from sleep if sleeping, to prevent delay.
+ ExitCode Wait();
+ /// returns false when woken up
+ bool Sleep(int milliseconds);
+ /// call this from outside thread to wake up Sleep - ing thread
+ void WakeUp();
+
+ /// overrides wxThread::TestDestroy , which can fail on Wait
+ bool TestDestroy();
+ wxThreadError Run();
+ protected:
+ wxSemaphore m_thread_sleep_semaphore;
+ /// workaround for old wxWidgets bug
+ bool m_must_exit;
+};
+
+
+class WorkItemQueue;
+
+
+/** @brief Abstraction of a piece of work to be done by WorkerThread
+ Inherit this class to define concrete work items. */
+class WorkItem
+{
+ public:
+
+ /** @brief Construct a new WorkItem */
+ WorkItem() : m_priority(0), m_toBeDeleted(true) {}
+
+ /** @brief Destructor */
+ virtual ~WorkItem() {}
+
+ /** @brief Implement this in derived class to do the work */
+ virtual void Run() = 0;
+
+ /** @brief Cancel this WorkItem, remove it from queue
+ @return true if it was removed, false otherwise */
+ bool Cancel();
+
+ int GetPriority() const { return m_priority; }
+
+ private:
+ int m_priority; ///< Priority of item, highest is run first
+ volatile bool m_toBeDeleted; ///< Should this item be deleted after it has run?
+ WorkItemQueue* m_queue;
+
+ friend class WorkItemQueue;
+ friend class WorkerThread;
+};
+
+
+/** @brief Priority queue of work items */
+class WorkItemQueue
+{
+ public:
+ /** @brief Push more work onto the queue */
+ void Push(WorkItem* item);
+
+ /** @brief Pop one work item from the queue
+ @return A work item or NULL when the queue is empty */
+ WorkItem* Pop();
+
+ /** @brief Remove a specific workitem from the queue
+ @return true if it was removed, false otherwise */
+ bool Remove(WorkItem* item);
+
+ private:
+ wxCriticalSection m_lock;
+ // this is a priority queue maintained as a heap stored in a vector :o
+ std::vector<WorkItem*> m_queue;
+};
+
+
+/** @brief Thread which processes WorkItems in it's WorkItemQueue */
+class WorkerThread : public Thread
+{
+ public:
+ /** @brief Adds a new WorkItem to the queue */
+ void DoWork(WorkItem* item, int priority = 0, bool toBeDeleted = true);
+ /** @brief Overrides wxThread::Entry, thread entry point */
+ void* Entry();
+
+ private:
+ void CleanupWorkItem(WorkItem* item);
+
+ WorkItemQueue m_workItems;
+};
+
+#endif // THREAD_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/torrentlistctrl.cpp b/src/torrentlistctrl.cpp
new file mode 100644
index 0000000..279e382
--- /dev/null
+++ b/src/torrentlistctrl.cpp
@@ -0,0 +1,507 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#ifndef NO_TORRENT_SYSTEM
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/intl.h>
+#include <wx/menu.h>
+
+#include "torrentlistctrl.h"
+#include "torrentwrapper.h"
+//#include "utils/.h"
+#include "iconimagelist.h"
+
+BEGIN_EVENT_TABLE( TorrentListCtrl, CustomListCtrl )
+
+ EVT_LIST_ITEM_RIGHT_CLICK( TLIST_CLICK, TorrentListCtrl::OnListRightClick )
+ EVT_LIST_COL_CLICK( TLIST_CLICK, TorrentListCtrl::OnColClick )
+ #if wxUSE_TIPWINDOW
+ #ifndef __WXMSW__ //disables tooltips on win
+ EVT_MOTION( TorrentListCtrl::OnMouseMotion )
+ #endif
+ #endif
+END_EVENT_TABLE()
+
+map_infos* TorrentListCtrl::m_info_map = 0;
+
+TorrentListCtrl::TorrentListCtrl( wxWindow* parent, Ui& ui ):
+ CustomListCtrl( parent, TLIST_CLICK, wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_ALIGN_LEFT, _T("TorrentListCtrl"), 10 )
+
+{
+ wxListItem col;
+
+ col.SetText( _( "Name" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 0, col, _T( "Name" ), true );
+
+ col.SetText( _( "Numcopies" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 1, col, _T( "complete numcopies" ), true );
+
+ col.SetText( _( "MB downloaded" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 2, col, _T( "MB downloaded" ), true );
+
+ col.SetText( _( "MB uploaded" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 3, col, _T( "MB uploaded" ) );
+
+ col.SetText( _( "Status" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 4, col, _T( "Status" ) );
+
+ col.SetText( _( "% complete" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 5, col, _T( "% complete" ) );
+
+ col.SetText( _( "KB/s up" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 6, col, _T( "KB/s upload" ) );
+
+ col.SetText( _( "KB/s down" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 7, col, _T( "KB/s download" ), true );
+
+ col.SetText( _( "ETA (s)" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 8, col, _T( "Estimated time of arrival" ), true );
+
+ col.SetText( _( "Filesize (MB)" ) );
+ col.SetImage( icons().ICON_NONE );
+ InsertColumn( 9, col, _T( "Filesize" ), true );
+
+// sortorder: name --> percent completed --> mb donwloaded
+
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = true;
+ m_sortorder[1].col = 5;
+ m_sortorder[1].direction = true;
+ m_sortorder[2].col = 2;
+ m_sortorder[2].direction = true;
+
+ Sort( );
+
+ //TODO this'll need fixing on win i assume [koshi]
+ SetColumnWidth( 0, 250 );
+ SetColumnWidth( 1, wxLIST_AUTOSIZE_USEHEADER );
+ SetColumnWidth( 2, wxLIST_AUTOSIZE_USEHEADER );
+ SetColumnWidth( 7, 80 );
+ SetColumnWidth( 8, wxLIST_AUTOSIZE_USEHEADER );
+ SetColumnWidth( 9, wxLIST_AUTOSIZE_USEHEADER );
+
+
+ SetColumnWidth( 3, 100 );
+ SetColumnWidth( 4, 70 );
+ SetColumnWidth( 5, 100 );
+ SetColumnWidth( 6, 70 );
+
+// m_popup = new wxMenu( _T("") );
+// // &m enables shortcout "alt + m" and underlines m
+// m_popup->Append( BLIST_DLMAP, _("Download &map") );
+// m_popup->Append( BLIST_DLMOD, _("Download m&od") );
+}
+void TorrentListCtrl::SetInfoMap( map_infos* map )
+{
+ m_info_map = map;
+}
+
+TorrentListCtrl::~TorrentListCtrl()
+{
+// delete m_popup;
+}
+
+
+void TorrentListCtrl::OnListRightClick( wxListEvent& /*unused*/ )
+{
+// PopupMenu( m_popup );
+}
+
+
+void TorrentListCtrl::OnColClick( wxListEvent& event )
+{
+ if ( event.GetColumn() == -1 ) return;
+ wxListItem col;
+ GetColumn( m_sortorder[0].col, col );
+ col.SetImage( icons().ICON_NONE );
+ SetColumn( m_sortorder[0].col, col );
+
+ int i;
+ for ( i = 0; m_sortorder[i].col != event.GetColumn() && i < 4; ++i ) {}
+ if ( i > 3 ) { i = 3; }
+ for ( ; i > 0; i-- ) { m_sortorder[i] = m_sortorder[i-1]; }
+ m_sortorder[0].col = event.GetColumn();
+ m_sortorder[0].direction = !m_sortorder[0].direction;
+
+
+ GetColumn( m_sortorder[0].col, col );
+// col.SetImage( ( m_sortorder[0].direction )?ICON_UP:ICON_DOWN );
+ SetColumn( m_sortorder[0].col, col );
+
+ Sort();
+}
+
+
+void TorrentListCtrl::Sort()
+{
+ for ( int i = 3; i >= 0; i-- )
+ {
+ switch ( m_sortorder[ i ].col )
+ {
+ case 0 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareNameUP:&CompareNameDOWN , 0 );
+ break;
+ case 1 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareCopiesUP:&CompareCopiesDOWN , 0 );
+ break;
+ case 2 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareDownSizeUP:&CompareDownSizeDOWN , 0 );
+ break;
+ case 3 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareUpSizeUP:&CompareUpSizeDOWN , 0 );
+ break;
+ case 4 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareLeechUP:&CompareLeechDOWN , 0 );
+ break;
+ case 5 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareCompletedUP:&CompareCompletedDOWN , 0 );
+ break;
+ case 6 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareUpSpeedUP:&CompareUpSpeedDOWN , 0 );
+ break;
+ case 7 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareDownSpeedUP:&CompareDownSpeedDOWN , 0 );
+ break;
+ case 8 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareEtaUP:&CompareEtaDOWN , 0 );
+ break;
+ case 9 :
+ SortItems(( m_sortorder[ i ].direction )?&CompareFileSizeUP:&CompareFileSizeDOWN , 0 );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareNameUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.name < info2.name )
+ return -1;
+ if ( info1.name > info2.name )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareNameDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.name < info2.name )
+ return -1;
+ if ( info1.name > info2.name )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareDownSizeUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.downloaded > info2.downloaded )
+ return -1;
+ if ( info1.downloaded < info2.downloaded )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareDownSizeDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.downloaded < info2.downloaded )
+ return 1;
+ if ( info1.downloaded > info2.downloaded )
+ return -1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareCopiesUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.numcopies < info2.numcopies )
+ return -1;
+ if ( info1.numcopies > info2.numcopies )
+ return 1;
+
+ return 0;
+}
+
+
+
+int wxCALLBACK TorrentListCtrl::CompareCopiesDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.numcopies < info2.numcopies )
+ return 1;
+ if ( info1.numcopies > info2.numcopies )
+ return -1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareUpSizeUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.uploaded < info2.uploaded )
+ return -1;
+ if ( info1.uploaded > info2.uploaded )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareUpSizeDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.uploaded < info2.uploaded )
+ {
+ return 1;
+ }
+ if ( info1.uploaded > info2.uploaded )
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareLeechUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.downloadstatus < info2.downloadstatus )
+ return -1;
+ if ( info1.downloadstatus > info2.downloadstatus )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareLeechDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.downloadstatus < info2.downloadstatus )
+ return 1;
+ if ( info1.downloadstatus > info2.downloadstatus )
+ return -1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareCompletedUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.progress < info2.progress )
+ return -1;
+ if ( info1.progress > info2.progress )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareCompletedDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.progress < info2.progress )
+ return 1;
+ if ( info1.progress > info2.progress )
+ return -1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareUpSpeedUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.outspeed < info2.outspeed )
+ return -1;
+ if ( info1.outspeed > info2.outspeed )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareUpSpeedDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.outspeed < info2.outspeed )
+ return 1;
+ if ( info1.outspeed > info2.outspeed )
+ return -1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareDownSpeedUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.inspeed < info2.inspeed )
+ return -1;
+ if ( info1.inspeed > info2.inspeed )
+ return 1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareDownSpeedDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.inspeed < info2.inspeed )
+ return 1;
+ if ( info1.inspeed > info2.inspeed )
+ return -1;
+
+ return 0;
+}
+
+
+int wxCALLBACK TorrentListCtrl::CompareEtaUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.eta < info2.eta )
+ return -1;
+ if ( info1.eta > info2.eta )
+ return 1;
+
+ return 0;
+}
+
+
+
+int wxCALLBACK TorrentListCtrl::CompareEtaDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.eta < info2.eta )
+ return 1;
+ if ( info1.eta > info2.eta )
+ return -1;
+
+ return 0;
+}
+
+int wxCALLBACK TorrentListCtrl::CompareFileSizeUP( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.filesize < info2.filesize )
+ return -1;
+ if ( info1.filesize > info2.filesize )
+ return 1;
+
+ return 0;
+}
+
+int wxCALLBACK TorrentListCtrl::CompareFileSizeDOWN( long item1, long item2, long sortData )
+{
+ map_infos info_map = *m_info_map;
+ TorrentInfos& info1 = info_map[item1];
+ TorrentInfos& info2 = info_map[item2];
+
+ if ( info1.filesize < info2.filesize )
+ return 1;
+ if ( info1.filesize > info2.filesize )
+ return -1;
+
+ return 0;
+}
+
+void TorrentListCtrl::SetTipWindowText( const long item_hit, const wxPoint position)
+{
+ m_tiptext = _T("");
+}
+
+void TorrentListCtrl::HighlightItem( long /*unused*/ )
+{
+
+}
+
+#endif
diff --git a/src/torrentlistctrl.h b/src/torrentlistctrl.h
new file mode 100644
index 0000000..993485b
--- /dev/null
+++ b/src/torrentlistctrl.h
@@ -0,0 +1,90 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_TORRENTLISTCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_TORRENTLISTCTRL_H
+
+#ifndef NO_TORRENT_SYSTEM
+
+#include "customlistctrl.h"
+
+#include <map>
+
+struct TorrentInfos;
+class wxMenu;
+class Battle;
+class wxListEvent;
+class wxCommandEvent;
+class Ui;
+
+typedef std::map<int,TorrentInfos> map_infos;
+
+/** \brief list all currently active (queued,lecching,seeding) torrents with their infos
+ * the list is newly populated every n-seconds from Ui::OnUpdate()
+ */
+class TorrentListCtrl : public CustomListCtrl
+{
+ public:
+ TorrentListCtrl( wxWindow* parent, Ui& ui );
+ ~TorrentListCtrl();
+
+ void Sort();
+
+ void OnListRightClick( wxListEvent& event );
+
+ virtual void SetTipWindowText( const long item_hit, const wxPoint position);
+ void OnColClick( wxListEvent& event );
+ void SetInfoMap( map_infos* map);
+ virtual void HighlightItem( long item );
+
+ protected:
+ static int wxCALLBACK CompareNameUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareNameDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareCompletedUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareCompletedDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareDownSizeUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareDownSizeDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareUpSizeUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareUpSizeDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareDownSpeedUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareDownSpeedDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareUpSpeedUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareUpSpeedDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareLeechUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareLeechDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareEtaUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareEtaDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareCopiesUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareCopiesDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareFileSizeUP(long item1, long item2, long sortData);
+ static int wxCALLBACK CompareFileSizeDOWN(long item1, long item2, long sortData);
+ static map_infos* m_info_map;
+
+
+ enum {
+ TLIST_CLICK
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+
+
+#endif
+
+#endif // SPRINGLOBBY_HEADERGUARD_TORRENTLISTCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/torrentoptionspanel.cpp b/src/torrentoptionspanel.cpp
new file mode 100644
index 0000000..9ce868b
--- /dev/null
+++ b/src/torrentoptionspanel.cpp
@@ -0,0 +1,178 @@
+#ifndef NO_TORRENT_SYSTEM
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/textctrl.h>
+#include <wx/checkbox.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/stattext.h>
+#include <wx/intl.h>
+#include <wx/radiobut.h>
+#include <wx/button.h>
+
+#include "torrentoptionspanel.h"
+#include "aui/auimanager.h"
+#include "settings.h"
+#include "ui.h"
+#include "torrentwrapper.h"
+#include "utils/conversion.h"
+
+
+BEGIN_EVENT_TABLE( TorrentOptionsPanel, wxScrolledWindow )
+END_EVENT_TABLE()
+
+TorrentOptionsPanel::TorrentOptionsPanel( wxWindow* parent, Ui& ui)
+ : wxScrolledWindow( parent, -1), m_ui(ui)
+{
+ GetAui().manager->AddPane( this, wxLEFT, _T("torrentoptionspanel") );
+
+ wxBoxSizer* mainboxsizer = new wxBoxSizer( wxVERTICAL );
+
+ m_autostart_box = new wxStaticBox(this, -1, _("Torrent system autostart") );
+ wxStaticBoxSizer* m_autostart_box_sizer = new wxStaticBoxSizer( m_autostart_box, wxVERTICAL );
+ m_autostart_logon = new wxRadioButton (this, ID_AUTOSTART_RADIO, _("at lobby connection (default)"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
+ m_autostart_start = new wxRadioButton (this, ID_AUTOSTART_RADIO, _("at lobby start"));
+ m_autostart_manual = new wxRadioButton (this, ID_AUTOSTART_RADIO, _("manual") );
+
+ SetAutoStartRadio();
+
+ m_autostart_box_sizer->Add(m_autostart_logon, 0, wxALL, 5);
+ m_autostart_box_sizer->Add(m_autostart_start, 0, wxALL, 5);
+ m_autostart_box_sizer->Add(m_autostart_manual, 0, wxALL, 5);
+// m_autostart_box_sizer->Add(NULL);
+ mainboxsizer->Add( m_autostart_box_sizer, 0, wxALL, 5 );
+
+ m_gamestart_box = new wxStaticBox(this, -1, _("At game start suspend mode") );
+ wxStaticBoxSizer* m_gamestart_box_sizer = new wxStaticBoxSizer(m_gamestart_box , wxVERTICAL );
+ m_gamestart_pause = new wxRadioButton(this, ID_GAMESTART_RADIO, _("Pause all torrents"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
+ m_gamestart_throttle = new wxRadioButton(this, ID_GAMESTART_RADIO, _("Throttle speeds:") );
+ wxBoxSizer* m_gamestart_input_box1 = new wxBoxSizer( wxHORIZONTAL );
+ wxBoxSizer* m_gamestart_input_box2 = new wxBoxSizer( wxHORIZONTAL );
+ m_gamestart_throttle_up_lbl = new wxStaticText( this, wxID_ANY, _("upload (KB/s)") );
+ m_gamestart_throttle_up = new wxTextCtrl(this, ID_INGAME_UP, TowxString(2));
+ m_gamestart_throttle_down_lbl = new wxStaticText( this, wxID_ANY, _("download (KB/s)") );
+ m_gamestart_throttle_down = new wxTextCtrl(this, ID_INGAME_DOWN, TowxString(2));
+
+ m_gamestart_box_sizer->Add(m_gamestart_pause, 0, wxALL, 5 );
+ m_gamestart_box_sizer->Add(m_gamestart_throttle, 0, wxALL, 5 );
+ m_gamestart_input_box1->Add(m_gamestart_throttle_up_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+ m_gamestart_input_box1->Add(m_gamestart_throttle_up, 0, wxALL, 5);
+ m_gamestart_input_box2->Add(m_gamestart_throttle_down_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
+ m_gamestart_input_box2->Add(m_gamestart_throttle_down, 0, wxALL, 5);
+ m_gamestart_box_sizer->Add(m_gamestart_input_box1, 0, wxALL, 5);
+ m_gamestart_box_sizer->Add(m_gamestart_input_box2, 0, wxALL, 5);
+ mainboxsizer->Add( m_gamestart_box_sizer, 0, wxALL, 5 );
+
+ wxStaticBox* m_numbers_box = new wxStaticBox(this, -1, _("Numbers") );
+ wxStaticBoxSizer* m_numbers_box_sizer = new wxStaticBoxSizer( m_numbers_box , wxVERTICAL );
+ wxBoxSizer* up_siter = new wxBoxSizer( wxHORIZONTAL );
+ m_maxUp = new wxTextCtrl( this, ID_MAXUP, TowxString( sett().GetTorrentUploadRate() ) );
+ wxStaticText* m_maxUp_lbl = new wxStaticText( this, wxID_ANY, _("maximum upload speed in KB/sec(-1 for infinite)") );
+ up_siter->Add( m_maxUp, 0, wxALL, 5 );
+ up_siter->Add( m_maxUp_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+ m_numbers_box_sizer->Add( up_siter, 0, wxALL, 5 );
+
+ wxBoxSizer* down_siter = new wxBoxSizer( wxHORIZONTAL );
+ m_maxDown = new wxTextCtrl( this, ID_MAXDOWN, TowxString( sett().GetTorrentDownloadRate() ) );
+ wxStaticText* m_maxDown_lbl = new wxStaticText( this, wxID_ANY, _("maximum download speed in KB/sec (-1 for infinite)") );
+ down_siter->Add( m_maxDown, 0, wxALL, 5 );
+ down_siter->Add( m_maxDown_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+ m_numbers_box_sizer->Add( down_siter, 0, wxALL, 5 );
+
+ wxBoxSizer* port_siter = new wxBoxSizer( wxHORIZONTAL );
+ m_p2pport = new wxTextCtrl( this, ID_P2PPORT, TowxString( sett().GetTorrentPort() ) );
+ wxStaticText* m_p2pport_lbl = new wxStaticText( this, wxID_ANY, _("port used for torrent connections") );
+ port_siter->Add( m_p2pport, 0, wxALL, 5 );
+ port_siter->Add( m_p2pport_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+ m_numbers_box_sizer->Add( port_siter, 0, wxALL, 5 );
+
+ wxBoxSizer* con_siter = new wxBoxSizer( wxHORIZONTAL );
+ m_maxConnections = new wxTextCtrl( this, ID_MAXUP, TowxString( sett().GetTorrentMaxConnections() ) );
+ wxStaticText* m_maxConnections_lbl = new wxStaticText( this, wxID_ANY, _("maximum number of concurrent connections") );
+ con_siter->Add( m_maxConnections, 0, wxALL, 5 );
+ con_siter->Add( m_maxConnections_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+ m_numbers_box_sizer->Add( con_siter, 0, wxALL, 5 );
+
+ mainboxsizer->Add( m_numbers_box_sizer, 0, wxALL, 5 );
+
+ //the lazy man's solution to options not being set correctly at panel creation
+ wxCommandEvent dummy;
+ OnRestore( dummy );
+
+ SetSizer( mainboxsizer );
+ SetScrollRate( 3, 3 );
+ Layout();
+}
+
+TorrentOptionsPanel::~TorrentOptionsPanel()
+{
+
+}
+
+
+//TODO wtf did i add these for
+void TorrentOptionsPanel::OnMaxUp( wxCommandEvent& /*unused*/ ){}
+void TorrentOptionsPanel::OnMaxDown( wxCommandEvent& /*unused*/ ){}
+void TorrentOptionsPanel::OnP2PPort( wxCommandEvent& /*unused*/ ){}
+void TorrentOptionsPanel::OnMaxConnections( wxCommandEvent& /*unused*/ ){}
+
+
+void TorrentOptionsPanel::OnApply( wxCommandEvent& /*unused*/ )
+{
+
+ sett().SetTorrentSystemAutoStartMode( 0 );
+ sett().SetTorrentUploadRate( FromwxString<long>( m_maxUp->GetValue() ) );
+ sett().SetTorrentDownloadRate( FromwxString<long>( m_maxDown->GetValue() ) );
+ sett().SetTorrentPort( FromwxString<long>( m_p2pport->GetValue() ) );
+ sett().SetTorrentMaxConnections( FromwxString<long>( m_maxConnections->GetValue() ) );
+ sett().SetTorrentThrottledUploadRate( FromwxString<long>( m_gamestart_throttle_up->GetValue() ) );
+ sett().SetTorrentThrottledDownloadRate( FromwxString<long>( m_gamestart_throttle_down->GetValue() ) );
+
+ //last radio box value, will be changed if other box is pressed
+ int autostart_mode = 2;
+ if ( m_autostart_logon->GetValue() )
+ autostart_mode = 0;
+ else if ( m_autostart_start->GetValue() )
+ autostart_mode = 1;
+ sett().SetTorrentSystemAutoStartMode( autostart_mode );
+
+ // if mode == pause selected --> m_gamestart_throttle->GetValue() == 0
+ sett().SetTorrentSystemSuspendMode( m_gamestart_throttle->GetValue() );
+
+ torrent().UpdateSettings();
+}
+
+void TorrentOptionsPanel::OnRestore( wxCommandEvent& /*unused*/ )
+{
+ m_maxConnections->SetValue( TowxString( sett().GetTorrentMaxConnections() ) );
+ m_p2pport->SetValue( TowxString( sett().GetTorrentPort() ) );
+ m_maxDown->SetValue( TowxString( sett().GetTorrentDownloadRate() ) );
+ m_maxUp->SetValue( TowxString( sett().GetTorrentUploadRate() ) );
+ m_gamestart_throttle_up->SetValue( TowxString( sett().GetTorrentThrottledUploadRate() ) );
+ m_gamestart_throttle_down->SetValue( TowxString( sett().GetTorrentThrottledDownloadRate( ) ) );
+ SetAutoStartRadio();
+ m_gamestart_throttle->SetValue( sett().GetTorrentSystemSuspendMode() );
+}
+
+void TorrentOptionsPanel::SetAutoStartRadio()
+{
+ switch ( sett().GetTorrentSystemAutoStartMode() )
+ {
+ case 1:
+ m_autostart_start->SetValue( true );
+ break;
+ case 2:
+ m_autostart_manual->SetValue( true );
+ break;
+ default:
+ m_autostart_logon->SetValue( true );
+ }
+}
+
+#endif
diff --git a/src/torrentoptionspanel.h b/src/torrentoptionspanel.h
new file mode 100644
index 0000000..e92ba80
--- /dev/null
+++ b/src/torrentoptionspanel.h
@@ -0,0 +1,93 @@
+#ifndef SPRINGLOBBY_HEADER_GUARD_TORRENTOPTIONSPANEL_H_INCLUDED
+#define SPRINGLOBBY_HEADER_GUARD_TORRENTOPTIONSPANEL_H_INCLUDED
+
+#ifndef NO_TORRENT_SYSTEM
+
+#include <wx/scrolwin.h>
+
+class wxCheckBox;
+class wxTextCtrl;
+class Ui;
+class wxStaticBox;
+class wxRadioButton;
+class wxButton;
+class wxStaticText;
+
+class TorrentOptionsPanel: public wxScrolledWindow
+{
+ public:
+ TorrentOptionsPanel( wxWindow* parent, Ui& ui);
+ ~TorrentOptionsPanel();
+
+ //void OnEnableP2P( wxCommandEvent& event );
+ void OnMaxUp( wxCommandEvent& event );
+ void OnMaxDown( wxCommandEvent& event );
+ void OnP2PPort( wxCommandEvent& event );
+ void OnMaxConnections( wxCommandEvent& event );
+ void OnApply( wxCommandEvent& event );
+ void OnRestore( wxCommandEvent& event );
+
+ private:
+ wxTextCtrl* m_maxUp;
+ wxTextCtrl* m_maxDown;
+ wxTextCtrl* m_p2pport;
+ wxTextCtrl* m_maxConnections;
+ wxStaticBox* m_autostart_box;
+ wxStaticBox* m_gamestart_box;
+ wxRadioButton* m_autostart_start;
+ wxRadioButton* m_autostart_logon;
+ wxRadioButton* m_autostart_manual;
+ wxRadioButton* m_gamestart_pause;
+ wxRadioButton* m_gamestart_throttle;
+ wxTextCtrl* m_gamestart_throttle_up;
+ wxTextCtrl* m_gamestart_throttle_down;
+ wxStaticText* m_gamestart_throttle_up_lbl;
+ wxStaticText* m_gamestart_throttle_down_lbl;
+
+ Ui& m_ui;
+
+
+ void EnableSettings( bool enable);
+ void SetStatusDisplay();
+ void SetAutoStartRadio();
+
+
+ enum
+ {
+ ID_ENABLEP2P = wxID_HIGHEST,
+ ID_MAXUP,
+ ID_MAXDOWN,
+ ID_P2PPORT,
+ ID_MAXCONNECTIONS,
+ ID_APPLY,
+ ID_RESTORE,
+ ID_AUTOSTART_RADIO,
+ ID_GAMESTART_RADIO,
+ ID_INGAME_UP,
+ ID_INGAME_DOWN
+ };
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
+
+#endif // SPRINGLOBBY_HEADER_GUARD_TORRENTOPTIONSPANEL_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/torrentwrapper.cpp b/src/torrentwrapper.cpp
new file mode 100644
index 0000000..6bac66e
--- /dev/null
+++ b/src/torrentwrapper.cpp
@@ -0,0 +1,1479 @@
+/* Copyright (C) 2007, 2008 The SpringLobby Team. All rights reserved. */
+//
+// Class: TorrentWrapper
+//
+
+#ifndef NO_TORRENT_SYSTEM
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include "settings.h"
+#include "utils/conversion.h"
+#include "utils/debug.h"
+#include "socket.h"
+#include "base64.h"
+#include "globalevents.h"
+
+#include <libtorrent/entry.hpp>
+#include <libtorrent/session.hpp>
+#include <libtorrent/bencode.hpp>
+#include <libtorrent/storage.hpp>
+#include <libtorrent/hasher.hpp>
+#include <libtorrent/file_pool.hpp>
+#include <libtorrent/torrent_info.hpp>
+#include <libtorrent/file.hpp>
+#if LIBTORRENT_VERSION_MINOR >= 14
+ #include <libtorrent/create_torrent.hpp>
+#endif
+#include <libtorrent/extensions/metadata_transfer.hpp>
+#include <libtorrent/extensions/ut_pex.hpp>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/format.hpp>
+
+#include <fstream>
+
+#include <wx/tokenzr.h>
+#include <wx/protocol/http.h>
+#include <wx/filename.h>
+#include <wx/file.h>
+#include <wx/filefn.h>
+#include <wx/wfstream.h>
+#include <wx/msgdlg.h>
+#include <wx/app.h>
+#include <wx/event.h>
+
+#include "torrentwrapper.h"
+#include "settings++/custom_dialogs.h"
+#include "globalsmanager.h"
+
+
+/** Get the name of the Spring data subdirectory that corresponds to a
+ * given IUnitSync::MediaType value.
+ */
+inline wxString
+getDataSubdirForType(const IUnitSync::MediaType type)
+{
+ switch ( type)
+ {
+ case IUnitSync::map:
+ return _T("maps");
+ case IUnitSync::mod:
+ return _T("mods");
+ default:
+ ASSERT_EXCEPTION(false, _T("Unhandled IUnitSync::MediaType value"));
+ }
+}
+
+TorrentMaintenanceThread::TorrentMaintenanceThread( TorrentWrapper* parent ):
+m_stop_thread( false ),
+m_parent( *parent )
+{
+}
+
+void TorrentMaintenanceThread::Init()
+{
+ Create();
+ SetPriority( WXTHREAD_MIN_PRIORITY );
+ Run();
+}
+
+void TorrentMaintenanceThread::Stop()
+{
+ m_stop_thread = true;
+}
+
+void* TorrentMaintenanceThread::Entry()
+{
+ while ( !TestDestroy() )
+ {
+ if( !Sleep( 2000 ) ) break;
+ if ( m_parent.IsConnectedToP2PSystem() )
+ {
+ // DON'T alter function call order here or bad things may happend like locust, earthquakes or raptor attack
+ m_parent.JoinRequestedTorrents();
+ m_parent.RemoveUnneededTorrents();
+ m_parent.TryToJoinQueuedTorrents();
+ m_parent.SearchAndGetQueuedDependencies();
+ }
+ }
+ return 0;
+}
+
+bool TorrentMaintenanceThread::TestDestroy()
+{
+ return Thread::TestDestroy() || m_stop_thread;
+}
+
+/** Get the wxFileName of a wxTorrentFile given its wxHash (where a
+ * wxHash is a wxString).
+ *
+ * This is a wxConvienceFunction. wxEnjoy!
+ */
+static inline wxFileName
+torrentFileName(const wxString& hash)
+{
+ return sett().GetTorrentDir().GetPathWithSep() + MakeHashSigned(hash) + _T(".torrent");
+}
+
+bool TorrentTable::IsConsistent()
+{
+#ifdef TorrentTable_validate
+ for (std::set<TorrentTable::PRow>::iterator i=all_torrents.begin();i!=all_torrents.end();++i)
+ {
+ if (hash_index.count((*i)->hash)==0)return false;
+ if (name_index.count((*i)->name)==0)return false;
+ // handle_index might not contain the torrent with invalid/null handle
+ }
+#endif
+ return true;
+}
+
+void TorrentTable::FlushData()
+{
+#ifdef TorrentTable_validate
+ all_torrents.clear();
+#endif
+ hash_index.clear();
+ name_index.clear();
+ handle_index.clear();
+ seed_requests.clear();
+ queued_torrents.clear();
+ seed_sent_data.clear();
+ dep_check_queue.clear();
+
+ m_seed_count = 0;
+ m_leech_count = 0;
+}
+
+void TorrentTable::InsertRow(TorrentTable::PRow row)
+{
+ if (!row.ok())return;
+
+#ifdef TorrentTable_validate
+ if (all_torrents.count(row))
+ {
+ wxLogWarning(_T("TorrentTable: inserting the row twice!"));
+ }
+ all_torrents.insert(row);
+#endif
+ int duplicates=0;
+ if (hash_index.count(row->hash))
+ {
+ wxLogWarning(_T("TorrentTable: inserting row with duplicate hash!"));
+ duplicates++;
+ }
+ if (name_index.count(row->name))
+ {
+ wxLogWarning(_T("TorrentTable: inserting row with duplicate name!"));
+ duplicates++;
+ }
+ // enforce all duplicates or no duplicates for now.
+ if (duplicates!=0 && duplicates!=2)
+ {
+ wxLogWarning(_T("TorrentTable: insert would cause inconsistency, not all keys are duplicated!"));
+ wxLogWarning(_T("TorrentTable: insert not done!"));
+ return;
+ }
+
+ // duplicate handles are not so bad, but a message may be useful
+ if (handle_index.count(row->handle))
+ {
+ wxLogMessage(_T("TorrentTable: inserting row with duplicate handle."));
+ }
+
+ hash_index[row->hash]=row;
+ name_index[row->name]=row;
+
+ if (row->handle.is_valid())handle_index[row->handle]=row;
+}
+
+void TorrentTable::RemoveRow(TorrentTable::PRow row)
+{
+ if (!row.ok())return;
+ hash_index.erase(row->hash);
+ name_index.erase(row->name);
+ handle_index.erase(row->handle);
+ seed_requests.erase(row);
+ queued_torrents.erase(row);
+}
+
+void TorrentTable::SetRowHandle(TorrentTable::PRow row, const libtorrent::torrent_handle &handle)
+{
+ handle_index.erase(row->handle);
+ row->handle=handle;
+ if (row->handle!=libtorrent::torrent_handle())handle_index[row->handle]=row;
+}
+
+void TorrentTable::AddRowToDependencyCheckQueue(PRow row)
+{
+ if (!row.ok())return;
+ dep_check_queue.insert( row );
+}
+
+void TorrentTable::RemoveRowFromDependencyCheckQueue( PRow row )
+{
+ if (!row.ok())return;
+ dep_check_queue.erase( row );
+}
+
+void TorrentTable::RemoveRowHandle( PRow row )
+{
+ if (!row.ok())return;
+ handle_index.erase(row->handle);
+ row->handle= libtorrent::torrent_handle();
+}
+
+void TorrentTable::SetRowStatus( TorrentTable::PRow row, P2P::FileStatus status )
+{
+ if (!row.ok())return;
+ if ( row->status != P2P::seeding && status == P2P::seeding ) m_seed_count++;
+ if ( row->status != P2P::leeching && status == P2P::leeching ) m_leech_count++;
+ if ( row->status == P2P::seeding && status != P2P::seeding ) m_seed_count--;
+ if ( row->status == P2P::leeching && status != P2P::leeching ) m_leech_count--;
+ if ( row->status != P2P::queued && status == P2P::queued ) queued_torrents.insert( row );
+ if ( row->status == P2P::queued && status != P2P::queued ) queued_torrents.erase( row );
+ if ( row->status == P2P::seeding || row->status == P2P::leeching )
+ {
+ if ( status != P2P::seeding && status != P2P::leeching ) RemoveRowHandle( row );
+ }
+ row->status = status;
+}
+
+void TorrentTable::SetRowTransferredData( PRow row, TransferredData data )
+{
+ if (!row.ok())return;
+ seed_sent_data[row] = data;
+}
+
+void TorrentTable::AddSeedRequest(TorrentTable::PRow row)
+{
+ if (!row.ok())return;
+ seed_requests.insert(row);
+}
+void TorrentTable::RemoveSeedRequest(TorrentTable::PRow row)
+{
+ if (!row.ok())return;
+ seed_requests.erase(row);
+}
+
+bool TorrentTable::IsSeedRequest(TorrentTable::PRow row)
+{
+ if (!row.ok()) return false;
+ return seed_requests.count(row)>0;
+}
+
+TorrentTable::PRow TorrentTable::RowByHash(const wxString &hash)
+{
+ std::map<wxString,PRow>::iterator i=hash_index.find(hash);
+ return i!=hash_index.end() ? i->second : PRow(NULL);
+}
+
+TorrentTable::PRow TorrentTable::RowByName(const wxString &name)
+{
+ std::map<wxString,PRow>::iterator i=name_index.find(name);
+ return i!=name_index.end() ? i->second : PRow(NULL);
+}
+
+TorrentTable::PRow TorrentTable::RowByHandle(libtorrent::torrent_handle handle)
+{
+ std::map<libtorrent::torrent_handle,PRow>::iterator i=handle_index.find(handle);
+ return i!=handle_index.end() ? i->second : PRow(NULL);
+}
+
+std::map<wxString, TorrentTable::PRow> TorrentTable::RowsByHash()
+{
+ return hash_index;
+}
+
+
+std::set<TorrentTable::PRow> TorrentTable::SeedRequestsByRow()
+{
+ return seed_requests;
+}
+
+std::map<libtorrent::torrent_handle, TorrentTable::PRow> TorrentTable::RowByTorrentHandles()
+{
+ return handle_index;
+}
+
+std::set<TorrentTable::PRow> TorrentTable::QueuedTorrentsByRow()
+{
+ return queued_torrents;
+}
+
+std::map<TorrentTable::PRow, TorrentTable::TransferredData> TorrentTable::TransferredDataByRow()
+{
+ return seed_sent_data;
+}
+
+std::set<TorrentTable::PRow> TorrentTable::DependencyCheckQueuebyRow()
+{
+ return dep_check_queue;
+}
+
+unsigned int TorrentTable::GetOpenSeedsCount()
+{
+ return m_seed_count;
+}
+
+unsigned int TorrentTable::GetOpenLeechsCount()
+{
+ return m_leech_count;
+}
+
+
+TorrentWrapper& torrent()
+{
+ static GlobalObjectHolder<TorrentWrapper> m_torr_wrap;
+ return m_torr_wrap;
+}
+
+
+TorrentWrapper::TorrentWrapper():
+ ingame(false),
+ m_timer_count(0),
+ m_maintenance_thread(this),
+ m_is_connecting(false),
+ m_started(false)
+{
+ wxLogMessage(_T("TorrentWrapper::TorrentWrapper()"));
+ m_tracker_urls.Add( _T("tracker.caspring.org"));
+ m_tracker_urls.Add( _T("tracker2.caspring.org"));
+ m_tracker_urls.Add( _T("backup-tracker.licho.eu"));
+ m_torr = new libtorrent::session();
+ try
+ {
+ m_torr->add_extension(&libtorrent::create_metadata_plugin);
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ try
+ {
+ m_torr->add_extension(&libtorrent::create_ut_pex_plugin);
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ try
+ {
+ m_torr->start_upnp();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ try
+ {
+ m_torr->start_natpmp();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ try
+ {
+ m_torr->start_lsd();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ m_socket_class = new Socket( *this );
+ UpdateSettings();
+}
+
+
+TorrentWrapper::~TorrentWrapper()
+{
+ wxLogMessage(_T("TorrentWrapper::~TorrentWrapper()"));
+ m_maintenance_thread.Stop();
+ try
+ {
+ m_torr->stop_upnp();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ try
+ {
+ m_torr->stop_natpmp();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ try
+ {
+ m_torr->stop_lsd();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ m_socket_class->SetTimeout( 1 );
+ DisconnectFromP2PSystem();
+ delete m_torr;
+ delete m_socket_class;
+}
+
+
+////////////////////////////////////////////////////////
+//// gui interface ////
+////////////////////////////////////////////////////////
+
+bool TorrentWrapper::ConnectToP2PSystem( const unsigned int tracker_no )
+{
+ if ( IsConnectedToP2PSystem() ) return true;
+ if ( tracker_no >= m_tracker_urls.GetCount() )
+ {
+ m_is_connecting = false;
+ m_connected_tracker_index = 0;
+ customMessageBoxNoModal( SL_MAIN_ICON, _("Tried all known trackers for torrent system. No connection could be established"),
+ _("Torrent system failure") );
+ return false;
+ }
+ m_socket_class->Connect( m_tracker_urls[tracker_no], DEFAULT_P2P_COORDINATOR_PORT );
+ m_connected_tracker_index= tracker_no;
+ m_is_connecting = true;
+
+ return IsConnectedToP2PSystem();
+}
+
+
+void TorrentWrapper::DisconnectFromP2PSystem()
+{
+ if ( IsConnectedToP2PSystem() )
+ m_socket_class->Disconnect();
+}
+
+
+bool TorrentWrapper::IsConnectedToP2PSystem()
+{
+ if ( m_socket_class == 0 ) return false;
+ return (m_socket_class->State() == SS_Open);
+}
+
+
+void TorrentWrapper::UpdateSettings()
+{
+ int uploadLimit, downloadLimit;
+
+ try
+ {
+ if ( !ingame || sett().GetTorrentSystemSuspendMode() == 0 )
+ {
+ uploadLimit = sett().GetTorrentUploadRate();
+ downloadLimit = sett().GetTorrentDownloadRate();
+ }
+ else
+ {
+ uploadLimit = sett().GetTorrentThrottledUploadRate();
+ downloadLimit = sett().GetTorrentThrottledDownloadRate();
+ }
+
+ uploadLimit = uploadLimit < 0 ? -1 : uploadLimit * 1024;
+ downloadLimit = downloadLimit < 0 ? -1 : downloadLimit * 1024;
+
+ m_torr->set_upload_rate_limit(uploadLimit);
+ m_torr->set_download_rate_limit(downloadLimit);
+
+ m_torr->set_max_connections(sett().GetTorrentMaxConnections());
+
+ m_torr->listen_on(std::make_pair(sett().GetTorrentPort(), sett().GetTorrentPort()));
+
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) ); // TODO (BrainDamage#1#): add message to user on failure
+ }
+}
+
+
+bool TorrentWrapper::IsFileInSystem( const wxString& hash )
+{
+ return GetTorrentTable().RowByHash(hash).ok();
+}
+
+
+bool TorrentWrapper::RemoveTorrentByHash( const wxString& hash )
+{
+ TorrentTable::PRow row=GetTorrentTable().RowByHash(hash);
+ if (!row.ok())return false;
+ return RemoveTorrentByRow( row );
+}
+
+
+
+int TorrentWrapper::GetTorrentSystemStatus()
+{
+ if (!IsConnectedToP2PSystem()) return 0;
+ if (ingame) return 2;
+ return 1;
+}
+
+
+/*
+HashToTorrentData& TorrentWrapper::GetSystemFileList()
+{
+ return m_torrent_infos;
+}
+*/
+
+////////////////////////////////////////////////////////
+//// lobby interface ////
+////////////////////////////////////////////////////////
+
+
+TorrentWrapper::DownloadRequestStatus TorrentWrapper::RequestFileByHash( const wxString& hash )
+{
+ TorrentTable::PRow row=GetTorrentTable().RowByHash(hash);
+ if ( !row.ok() ) return missing_in_table;
+ return QueueFileByRow( row );
+}
+
+
+TorrentWrapper::DownloadRequestStatus TorrentWrapper::RequestFileByName( const wxString& name )
+{
+ TorrentTable::PRow row=GetTorrentTable().RowByName(name);
+ if ( !row.ok() ) return missing_in_table;
+ return QueueFileByRow( row );
+}
+
+
+void TorrentWrapper::SetIngameStatus( bool status )
+{
+ if ( status == ingame ) return; // no change needed
+ ingame = status;
+ if ( ingame ) m_maintenance_thread.Pause();
+ else m_maintenance_thread.Resume();
+ if ( !IsConnectedToP2PSystem() ) return;
+ try
+ {
+ std::vector<libtorrent::torrent_handle> TorrentList = m_torr->get_torrents();
+ if ( ingame ) // going ingame, pause all torrents (or throttle speeds) and disable dht
+ {
+ if ( sett().GetTorrentSystemSuspendMode() == 0 ) for ( unsigned int i = 0; i < TorrentList.size(); i++) TorrentList[i].pause();
+ else
+ {
+ m_torr->set_upload_rate_limit(sett().GetTorrentThrottledUploadRate() * 1024);
+ m_torr->set_download_rate_limit(sett().GetTorrentThrottledDownloadRate() *1024 );
+ }
+ m_torr->stop_dht();
+ }
+ else// game closed, resume all torrents (or reset normal speed) and reactivate dht
+ {
+ m_torr->start_dht();
+ if ( sett().GetTorrentSystemSuspendMode() == 0 ) for ( unsigned int i = 0; i < TorrentList.size(); i++) TorrentList[i].resume();
+ else
+ {
+ m_torr->set_upload_rate_limit(sett().GetTorrentUploadRate() * 1024);
+ m_torr->set_download_rate_limit(sett().GetTorrentDownloadRate() *1024 );
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) ); // TODO (BrainDamage#1#): add message to user on failure
+ }
+}
+
+
+void TorrentWrapper::UpdateFromTimer( int mselapsed )
+{
+ m_timer_count++;
+ if ( m_timer_count < 20 ) return;//update every 2 sec
+ m_timer_count = 0;
+ if ( m_is_connecting )
+ {
+ if ( IsConnectedToP2PSystem() )
+ m_is_connecting = false;
+ else
+ ConnectToP2PSystem( m_connected_tracker_index +1 );
+ }
+}
+
+void TorrentWrapper::ResumeFromList()
+{
+ wxArrayString TorrentsToResume = sett().GetTorrentListToResume();
+ unsigned int ResumeCount = TorrentsToResume.GetCount();
+ if ( ResumeCount > 0 )
+ {
+ //request all hashes in list, remember successes
+ std::vector<int> successfulIndices;
+ for ( unsigned int i = 0; i < ResumeCount; i++ )
+ {
+ if (scheduled_in_cue == RequestFileByHash( TorrentsToResume[i] ) ) // resume all open leeched files when system as disconnected last time
+ successfulIndices.push_back(i);
+ }
+
+
+ //remove successfully resumed torrents from list
+ std::vector<int>::const_iterator it = successfulIndices.begin();
+ for ( ; it != successfulIndices.end(); ++it )
+ TorrentsToResume.RemoveAt( *it );
+ //save new list (hopefully empty)
+ sett().SetTorrentListToResume( TorrentsToResume );
+ }
+}
+
+////////////////////////////////////////////////////////
+//// private functions to interface with the system ////
+////////////////////////////////////////////////////////
+
+TorrentWrapper::DownloadRequestStatus TorrentWrapper::QueueFileByRow( const TorrentTable::PRow& row )
+{
+ if (ingame) return paused_ingame;
+ if ( !IsConnectedToP2PSystem() ) return not_connected;
+
+ if (!row.ok())return file_not_found;
+
+ if (row->status==P2P::leeching||(row->status&P2P::stored) || (row->status == P2P::queued) ) return duplicate_request;
+
+ GetTorrentTable().SetRowStatus( row, P2P::queued );
+ return scheduled_in_cue;
+}
+
+TorrentWrapper::DownloadRequestStatus TorrentWrapper::RequestFileByRow( const TorrentTable::PRow& row )
+{
+ if (ingame) return paused_ingame;
+ if ( !IsConnectedToP2PSystem() ) return not_connected;
+
+ if (!row.ok())return file_not_found;
+
+ if (row->status==P2P::leeching||(row->status&P2P::stored) ) return duplicate_request;
+
+ if ( GetTorrentTable().GetOpenLeechsCount() > 4 )
+ {
+ GetTorrentTable().SetRowStatus( row, P2P::queued );
+ return scheduled_in_cue;
+ }
+
+ if ( !JoinTorrent( row, false ) )
+ {
+ GetTorrentTable().SetRowStatus( row, P2P::not_stored ); // remove from queue list or it will keep failing
+ return torrent_join_failed;
+ }
+ return success;
+}
+
+
+bool TorrentWrapper::RemoveTorrentByRow( const TorrentTable::PRow& row )
+{
+ if (!row.ok())return false;
+ wxLogDebugFunc( row->name );
+ if ( row->status==P2P::queued )
+ {
+ TorrentTable().SetRowStatus( row, P2P::not_stored );
+ return true;
+ }
+ try
+ {
+ bool filecompleted = row->handle.is_seed();
+ m_torr->remove_torrent( row->handle );
+
+ if ( filecompleted ) GetTorrentTable().SetRowStatus( row, P2P::stored ); // fix the file status and automatically remove row handle
+ else
+ {
+ GetTorrentTable().SetRowStatus( row, P2P::not_stored );
+ SendMessageToCoordinator( _T("N-|") + MakeHashSigned(row->hash) + _T("\n") ); //notify the system we don't need the file anymore
+ }
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ return false;
+ }
+ return true;
+}
+
+
+std::map<int,TorrentInfos> TorrentWrapper::CollectGuiInfos()
+{
+ std::map<int,TorrentInfos> ret;
+ try
+ {
+ TorrentInfos globalinfos;
+ libtorrent::session_status s = m_torr->status();
+ globalinfos.downloadstatus = P2P::leeching;
+ globalinfos.progress = 0.0f;
+ globalinfos.downloaded = s.total_download;
+ globalinfos.uploaded = s.total_upload;
+ globalinfos.outspeed = s.upload_rate;
+ globalinfos.inspeed = s.download_rate;
+ globalinfos.numcopies = 0.0f;
+ globalinfos.filesize = 0;
+ ret[0] = globalinfos;
+
+ if ( ingame || !IsConnectedToP2PSystem() ) return ret; // stop updating the gui if disconneted
+
+ std::vector<libtorrent::torrent_handle> TorrentList = m_torr->get_torrents();
+ for ( std::vector<libtorrent::torrent_handle>::iterator i = TorrentList.begin(); i != TorrentList.end(); i++)
+ {
+ TorrentInfos CurrentTorrent;
+ libtorrent::torrent_status s = i->status();
+ CurrentTorrent.name = TowxString(i->name()).BeforeFirst(_T('|'));
+ CurrentTorrent.progress = s.progress;
+ CurrentTorrent.downloaded = s.total_payload_download;
+ CurrentTorrent.uploaded = s.total_payload_upload;
+ CurrentTorrent.inspeed = s.download_payload_rate;
+ CurrentTorrent.outspeed = s.upload_payload_rate;
+ CurrentTorrent.numcopies = s.distributed_copies;
+ CurrentTorrent.filesize = i->get_torrent_info().total_size();
+
+ TorrentTable::PRow row=GetTorrentTable().RowByHandle(*i);
+ if (!row.ok()) continue;
+ CurrentTorrent.hash=row->hash;
+ CurrentTorrent.downloadstatus = row->status;
+
+ ret[s2l(CurrentTorrent.hash)] = CurrentTorrent;
+ }
+ }
+ catch (std::exception& e)
+ {
+ wxLogError(_T("%s"), TowxString(e.what()).c_str());
+ }
+
+ // display infos about queued torrents
+
+ std::set<TorrentTable::PRow> queuedrequests = GetTorrentTable().QueuedTorrentsByRow();
+ for ( std::set<TorrentTable::PRow>::iterator it = queuedrequests.begin(); ( it != queuedrequests.end() ) && ( GetTorrentTable().GetOpenLeechsCount() < 4 ); it++ )
+ {
+ TorrentInfos QueuedTorrent;
+ QueuedTorrent.numcopies = -1;
+ QueuedTorrent.hash = (*it)->hash;
+ QueuedTorrent.downloadstatus = P2P::queued;
+ QueuedTorrent.name=(*it)->name;
+ ret[s2l(QueuedTorrent.hash)] = QueuedTorrent;
+ }
+
+ return ret;
+}
+
+
+void TorrentWrapper::SendMessageToCoordinator( const wxString& message )
+{
+ if ( IsConnectedToP2PSystem() )
+ {
+ wxLogMessage( _T("T send: %s"), message.c_str() );
+ m_socket_class->Send( message + _T("\n") );
+ }
+}
+
+
+bool TorrentWrapper::JoinTorrent( const TorrentTable::PRow& row, bool IsSeed )
+{
+ if ( !row.ok() ) return false;
+ wxLogMessage(_T("(1) Joining torrent, name=%s"),row->name.c_str());
+ if (ingame) return false;
+
+ wxLogMessage(_T("(2) Joining torrent. IsSeed: ") + TowxString(IsSeed) + _T(" status: ") + TowxString(row->status) );
+
+ if ( IsSeed && ( row->status != P2P::stored ) ) return false;
+ if ( !IsSeed && ( row->status != P2P::queued ) && ( row->status != P2P::not_stored ) ) return false;
+
+ wxString torrent_name=row->name;
+ wxString torrent_infohash_b64=row->infohash;
+ wxFileName path;
+
+ switch (row->type)
+ {
+ case IUnitSync::map:
+ {
+ torrent_name = torrent_name + _T("|MAP");
+ break;
+ }
+ case IUnitSync::mod:
+ {
+ torrent_name = torrent_name + _T("|MOD");
+ break;
+ }
+ default:
+ wxLogDebugFunc( _T("row-type unhandled") );
+ break;
+ }
+
+ if ( IsSeed )
+ {
+ wxString archivename;
+ switch ( row->type ) // if file is not present locally you can't seed it
+ {
+ case IUnitSync::map:
+ {
+ if ( !usync().MapExists( row->name, row->hash ) ) return false;
+ int index = usync().GetMapIndex( row->name );
+ if ( index == -1 ) return false;
+ archivename = usync().GetMapArchive( index );
+ break;
+ }
+ case IUnitSync::mod:
+ {
+ if ( !usync().ModExists( row->name, row->hash ) ) return false;
+ int index = usync().GetModIndex( row->name );
+ if ( index == -1 ) return false;
+ archivename = usync().GetModArchive( index );
+ break;
+ }
+ default:
+ wxLogDebugFunc( _T("row-type unhandled") );
+ break;
+ }
+
+ try
+ {
+ // dizekat> i'm getting archivename == /home/dmytry/.spring/maps/Whatever.sdf and getting archivepath == /home/dmytry/.spring/maps/
+ // dizekat> so i changed it to prepend path only if path isnt found here.
+ wxLogMessage( _T("seeding from archive name: %s"), archivename.c_str() );
+ wxFileName archivepath(usync().GetArchivePath( archivename ));
+ int i = archivename.Find( archivepath.GetFullPath() );
+ if (i<0)
+ {
+ path = archivepath.GetPathWithSep() + archivename;
+ }
+ else
+ {
+ path = wxFileName(archivename);
+ }
+
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ wxLogMessage( _T("Local filepath couldn't be determined") );
+ return false;
+ }
+ wxLogMessage( _T("seeding from local filename: %s"), path.GetFullPath().c_str() );
+ }
+ else /* if(IsSeed) */
+ {
+ path = sett().GetTorrentDataDir();
+ path.AppendDir( getDataSubdirForType(row->type) );
+ if ( !path.DirExists() ) path.Mkdir(0755);
+ wxLogMessage(_T("downloading to path: =%s"), path.GetFullPath().c_str());
+ }
+
+
+ wxLogMessage(_T("(3) Joining torrent: downloading info file"));
+ if (!DownloadTorrentFileFromTracker( MakeHashSigned( row->hash ) ))
+ {
+ wxLogError(_T("(3) info file download failed"));
+ return false;
+ }
+
+ #if LIBTORRENT_VERSION_MINOR < 14
+ // read torrent from file
+ std::ifstream in( torrentFileName(row->hash).GetFullPath().mb_str(), std::ios_base::binary);
+ in.unsetf(std::ios_base::skipws);
+ libtorrent::entry e;
+ try
+ {
+ // decode the torrent infos from the file
+ e = libtorrent::bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
+
+ }
+ catch ( std::exception& exc )
+ {
+ wxLogMessage( _T("torrent has invalid encoding") );
+ return false;
+ }
+
+ libtorrent::torrent_info t_info (e);
+
+ if ( t_info.num_files() != 1 )
+ {
+ wxLogMessage( _T("torrent contains an invalid number of files") );
+ return false;
+ }
+
+ wxString torrentfilename = TowxString( t_info.begin_files()->path.string() ); // get the file name in the torrent infos
+
+ #else
+ libtorrent::add_torrent_params p;
+
+ try
+ {
+ // the torrent_info is stored in an intrusive_ptr
+ p.ti = new libtorrent::torrent_info(boost::filesystem::path(torrentFileName(row->hash).GetFullPath().mb_str()));
+
+ }
+ catch ( std::exception& exc )
+ {
+ wxLogMessage( _T("torrent has invalid encoding") );
+ return false;
+ }
+ //decode success
+
+ boost::intrusive_ptr<libtorrent::torrent_info> t_info = p.ti;
+
+ if ( t_info->num_files() != 1 )
+ {
+ wxLogMessage( _T("torrent contains an invalid number of files") );
+ return false;
+ }
+
+ wxString torrentfilename = TowxString( t_info->file_at(0).path.string() ); // get the file name in the torrent infos
+ #endif
+
+
+ wxLogMessage( _T("requested filename: %s"), torrentfilename.c_str() );
+
+ wxFileName archive_filename(path);
+ wxFileName torrent_filename(torrentfilename);
+
+ if ( IsSeed && ( torrent_filename.GetFullName() != archive_filename.GetFullName() ) )
+ {
+ wxLogMessage(_T("filename differs from torrent, renaming file in torrent info"));
+ if ( !( torrent_filename.GetExt() == archive_filename.GetExt() ) ) // different extension, won't work
+ {
+ wxLogMessage( _T("file extension locally differs, not joining torrent") );
+ return false;
+ }
+ wxLogMessage(_T("New filename in torrent: %s"), archive_filename.GetFullName().c_str());
+ #if LIBTORRENT_VERSION_MINOR < 14
+ std::vector<libtorrent::file_entry> map;
+ libtorrent::file_entry foo = t_info.file_at(0);
+ map.push_back( foo );
+ map.front().path = boost::filesystem::path(STD_STRING( archive_filename.GetFullName() ) );
+ wxLogMessage(_T("New filename in torrent: %s"), archive_filename.GetFullName().c_str() );
+ if ( !t_info.remap_files(map) )
+ {
+ wxLogMessage(_T("Cannot remap filenames in the torrent, aborting seed"));
+ return false;
+ }
+ #else
+ t_info->files().rename_file(0, std::string(archive_filename.GetFullName().mb_str()));
+ #endif
+ }
+ wxLogMessage(_T("(4) Joining torrent: add_torrent(%s,[%s],%s,[%s])"),m_tracker_urls[m_connected_tracker_index].c_str(),torrent_infohash_b64.c_str(),row->name.c_str(),path.GetFullPath().c_str());
+
+ try
+ {
+ #if LIBTORRENT_VERSION_MINOR < 14
+ GetTorrentTable().SetRowHandle(row, m_torr->add_torrent( t_info, boost::filesystem::path(path.GetFullPath().mb_str())));
+ #else
+ p.save_path = path.GetFullPath().mb_str();
+ GetTorrentTable().SetRowHandle(row, m_torr->add_torrent(p));
+ #endif
+
+ }
+ catch (std::exception& e)
+ {
+ wxLogError(_T("%s"),TowxString( e.what()).c_str()); // TODO (BrainDamage#1#): add message to user on failure
+ return false;
+ }
+ try
+ {
+ if (IsSeed)
+ {
+ if (row->handle.is_valid())
+ {
+ #if LIBTORRENT_VERSION_MINOR < 14
+ std::vector<bool> tmp(1,true);
+ row->handle.filter_files(tmp);
+ #else
+ // there's only one file in the torrent, set its priority to 0
+ row->handle.file_priority(0, 0);
+ #endif
+ }
+ else
+ {
+ wxLogMessage(_T("Cant set seed not to download"));
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ wxLogError(_T("%s"),TowxString( e.what()).c_str()); // TODO (BrainDamage#1#): add message to user on failure
+ }
+
+ if ( IsSeed ) GetTorrentTable().SetRowStatus( row, P2P::seeding );
+ else
+ {
+ GetTorrentTable().SetRowStatus( row, P2P::leeching );
+ SendMessageToCoordinator( wxString::Format( _T("N+|%s\n"), MakeHashSigned(row->hash).c_str() ) ); // request for seeders for the file
+ }
+
+ wxLogMessage(_T("(5) Joining torrent: done"));
+ return true;
+}
+
+
+void TorrentWrapper::CreateTorrent( const wxString& hash, const wxString& name, IUnitSync::MediaType type )
+{
+ if (ingame) return;
+
+
+ if ( sett().GetCurrentUsedDataDir().IsEmpty() ) return; // no good things can happend if you don't know which folder to r/w files from
+
+ # if LIBTORRENT_VERSION_MINOR >= 14
+
+ libtorrent::file_storage files;
+
+ wxString archivename;
+
+ switch ( type )
+ {
+ case IUnitSync::map :
+ {
+ if ( !usync().MapExists( name, hash ) ) return;
+ int index = usync().GetMapIndex( name );
+ if ( index == -1 ) return;
+ archivename = usync().GetMapArchive( index );
+ break;
+ }
+ case IUnitSync::mod :
+ {
+ if ( !usync().ModExists( name, hash ) ) return;
+ int index = usync().GetModIndex( name );
+ if ( index == -1 ) return;
+ archivename = usync().GetModArchive( index );
+ break;
+ }
+ default:
+ wxLogDebugFunc( _T("row-type unhandled") );
+ break;
+ }
+
+ wxString archivepath = usync().GetArchivePath( archivename );
+ int i = archivename.Find( archivepath );
+ wxString path;
+ if (i<0)
+ {
+ path = archivepath + archivename;
+ }
+ else
+ {
+ path = archivename;
+ }
+
+ boost::filesystem::path InputFilePath = complete(boost::filesystem::path( STD_STRING( path ) ) );
+
+ files.add_file( InputFilePath.branch_path(), boost::filesystem::file_size( InputFilePath ) );
+
+ libtorrent::create_torrent newtorrent(files);
+
+ for ( unsigned int i = 0; i < m_tracker_urls.GetCount(); i++ )
+ {
+ newtorrent.add_tracker( STD_STRING(m_tracker_urls[i] + _T(":DEFAULT_P2P_TRACKER_PORT/announce") ) );
+ }
+
+ // calculate the hash for all pieces
+ set_piece_hashes(newtorrent, InputFilePath.branch_path());
+
+ switch (type)
+ {
+ case IUnitSync::map:
+ newtorrent.set_comment( wxString( name + _T("|MAP") ).mb_str() );
+ break;
+ case IUnitSync::mod:
+ newtorrent.set_comment( wxString( name + _T("|MOD") ).mb_str() );
+ break;
+ default:
+ wxLogDebugFunc( _T("row-type unhandled") );
+ break;
+ }
+
+ libtorrent::entry e = newtorrent.generate();
+ // TODO: e needs to be encoded and saved to a .torrent file
+ // or added to m_torr
+
+ #endif
+}
+
+
+bool TorrentWrapper::DownloadTorrentFileFromTracker( const wxString& hash )
+{
+ if ( sett().GetCurrentUsedDataDir().IsEmpty() ) return false; // no good things can happend if you don't know which folder to r/w files from
+
+ wxFileName filename( torrentFileName(hash) );
+
+ bool readable(filename.IsFileReadable());
+
+ if ( readable ) return true; //file already present locally
+
+ wxLogMessage(_T("torrent system downloading torrent info %s"), hash.c_str() );
+
+ wxHTTP fileRequest;
+ //versionRequest.SetHeader(_T("Content-type"), _T(""));
+ // normal timeout is 10 minutes.. set to 2 secs.
+ fileRequest.SetTimeout(2);
+ fileRequest.Connect( m_tracker_urls[m_connected_tracker_index], 80);
+ wxInputStream *stream = fileRequest.GetInputStream( _T("/torrents/") + hash + _T(".torrent") );
+ bool ret = false;
+ if (fileRequest.GetError() == wxPROTO_NOERR)
+ {
+
+ wxFileOutputStream output( filename.GetFullPath() );
+ if ( output.Ok() )
+ {
+ stream->Read(output);
+ ret = true;
+ }
+
+ }
+
+ wxDELETE(stream);
+ fileRequest.Close();
+ if (ret) wxLogMessage(_T("torrent system downloading torrent info %s successful"), hash.c_str() );
+ else wxLogMessage(_T("torrent system downloading torrent info %s failed"), hash.c_str() );
+ return ret;
+}
+
+
+void TorrentWrapper::JoinRequestedTorrents()
+{
+ std::set<TorrentTable::PRow> seedrequests= GetTorrentTable().SeedRequestsByRow();
+ for (std::set<TorrentTable::PRow>::iterator it = seedrequests.begin(); it != seedrequests.end(); ++it)
+ {
+ if (!it->ok())continue;
+
+ if ( GetTorrentTable().GetOpenSeedsCount() > 9 ) break; // too many seeds open
+
+ if ( (*it)->status != P2P::stored ) continue; // torrent must be present locally and not seeding/leeching
+
+ if ( !JoinTorrent( *it, true ) ) GetTorrentTable().RemoveSeedRequest( *it );
+
+ }
+
+}
+
+void TorrentWrapper::RemoveUnneededTorrents()
+{
+ std::map<libtorrent::torrent_handle, TorrentTable::PRow> torrenthandles = GetTorrentTable().RowByTorrentHandles();
+ std::map<TorrentTable::PRow, TorrentTable::TransferredData> transfer_data_map = GetTorrentTable().TransferredDataByRow();
+ for (std::map<libtorrent::torrent_handle, TorrentTable::PRow>::iterator it = torrenthandles.begin(); it != torrenthandles.end(); ++it)
+ {
+ if ( !it->first.is_valid() ) continue;
+ if ( !it->first.is_seed() ) continue;
+
+ // save how much the torrent has seeded
+ unsigned int payload_upload = it->first.status().total_payload_upload;
+
+ TorrentTable::TransferredData old_data = transfer_data_map[it->second];
+ if ( payload_upload == old_data.sentdata )
+ {
+ old_data.failed_check_counts = old_data.failed_check_counts + 1;
+ }
+ else old_data.sentdata = payload_upload;
+ GetTorrentTable().SetRowTransferredData( it->second, old_data );
+ // if the torrent didn't seed any data in the last 2 minutes, remove it from the request list
+ if ( old_data.failed_check_counts > 60 ) GetTorrentTable().RemoveSeedRequest( it->second );
+
+ if ( it->second->status == P2P::leeching ) // if torrent was opened in leech mode but now it's seeding it means it was requested from the user but now it's completed
+ {
+ //torrent has finished download, refresh unitsync and remove file from list
+ try
+ {
+ /* Grab the source (temporary) and destination (final) filenames BEFORE we remove the download. */
+ wxString sourceName( TowxString( ( it->first.save_path() / it->first.name() ).file_string() ) );
+ wxString basepath = sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + getDataSubdirForType(it->second->type);
+ wxString targetName = basepath + wxFileName::GetPathSeparator() + TowxString(it->first.name());
+
+ if ( !wxFileName::DirExists( basepath ) ) wxFileName::Mkdir( basepath, 0755 );
+ ASSERT_EXCEPTION( RemoveTorrentByRow( it->second ), _T("failed to remove torrent: ")+ it->second->hash );
+
+ /* Move file from temporary download directory to final destination. `false' for
+ * parameter 3 means don't overwrite the file if it already exists.
+ */
+ if ( ! wxRenameFile(sourceName, targetName, false) ) wxLogError(wxString::Format(_T("torrent: Failed to move \"%s\" to \"%s\""), sourceName.c_str(), targetName.c_str()));
+ else wxLogMessage(wxString::Format(_T("torrent: Moved \"%s\" to \"%s\""), sourceName.c_str(), targetName.c_str()));
+
+ GetTorrentTable().AddRowToDependencyCheckQueue( it->second );
+
+ wxCommandEvent refreshevt(UnitSyncReloadRequest); // request an unitsync reload
+ wxPostEvent( &SL_GlobalEvtHandler::GetSL_GlobalEvtHandler(), refreshevt );
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ }
+
+ if ( !GetTorrentTable().IsSeedRequest( it->second ) )// if torrent not in request list but still seeding then remove
+ {
+ try
+ {
+ ASSERT_EXCEPTION( RemoveTorrentByRow( it->second ), _T("failed to remove torrent: ")+ it->second->hash );
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) );
+ }
+ }
+ }
+
+}
+
+
+void TorrentWrapper::TryToJoinQueuedTorrents()
+{
+
+ if ( GetTorrentTable().GetOpenLeechsCount() < 5 )
+ {
+ // join queued files if there are available slots
+ std::set<TorrentTable::PRow> queuedrequests = GetTorrentTable().QueuedTorrentsByRow();
+ for ( std::set<TorrentTable::PRow>::iterator it = queuedrequests.begin(); ( it != queuedrequests.end() ) && ( GetTorrentTable().GetOpenLeechsCount() < 4 ); it++ )
+ {
+ if ( !it->ok() ) continue;
+ RequestFileByRow( *it );
+ }
+ }
+
+}
+
+void TorrentWrapper::SearchAndGetQueuedDependencies()
+{
+ std::set<TorrentTable::PRow> listcopy = GetTorrentTable().DependencyCheckQueuebyRow();
+ for ( std::set<TorrentTable::PRow>::iterator itor = listcopy.begin(); itor != listcopy.end(); itor++ )
+ {
+ TorrentTable::PRow row = *itor;
+ if ( row->type == IUnitSync::map )
+ {
+ if ( usync().MapExists( row->name, row->hash ) )
+ {
+ wxArrayString deps = usync().GetMapDeps( row->name );
+ int count = deps.GetCount();
+ for ( int i = 0; i < count; i++ )
+ {
+ RequestFileByName( deps[i] );
+ }
+ GetTorrentTable().RemoveRowFromDependencyCheckQueue( row );
+ }
+ }
+ else if ( row->type == IUnitSync::mod )
+ {
+ if ( usync().ModExists( row->name, row->hash ) )
+ {
+ wxArrayString deps = usync().GetModDeps( row->name );
+ int count = deps.GetCount();
+ for ( int i = 0; i < count; i++ )
+ {
+ RequestFileByName( deps[i] );
+ }
+ GetTorrentTable().RemoveRowFromDependencyCheckQueue( row );
+ }
+ }
+ }
+
+}
+
+void TorrentWrapper::ReceiveandExecute( const wxString& msg )
+{
+ wxLogMessage(_T("T recive: %s"), msg.c_str() );
+
+ wxArrayString data = wxStringTokenize( msg, _T('|') );
+
+ if ( data.GetCount() == 0 ) return;
+ // T+|hash|name|type informs client that new torrent was added to server (type is either MOD or MAP)
+ else if ( data.GetCount() > 3 && data[0] == _T("T+") )
+ {
+
+ TorrentTable::PRow newtorrent = new TorrentTable::Row;
+
+ newtorrent->hash = MakeHashUnsigned(data[1]);
+ newtorrent->name = data[2];
+ if ( data[3] == _T("MAP") )
+ {
+ newtorrent->type = IUnitSync::map;
+ if ( usync().MapExists( newtorrent->name, newtorrent->hash ) ) newtorrent->status = P2P::stored;
+ }
+ else if ( data[3] == _T("MOD") )
+ {
+ newtorrent->type = IUnitSync::mod;
+ if ( usync().ModExists( newtorrent->name, newtorrent->hash ) ) newtorrent->status = P2P::stored;
+ }
+
+ GetTorrentTable().InsertRow( newtorrent );
+
+ // SendMessageToCoordinator( _T("IH|") + data[1] + _T("\n") );
+
+ // T-|hash informs client that torrent was removed from server
+ }
+ else if ( data[0] == _T("T-") && data.GetCount() > 1 )
+ {
+
+ TorrentTable::PRow row = GetTorrentTable().RowByHash( MakeHashUnsigned(data[1]) );
+ if ( !row.ok() ) return;
+ GetTorrentTable().RemoveRow( row );
+
+ // S+|hash|seeders|leechers tells client that seed is needed for this torrent
+ }
+ else if ( data.GetCount() > 1 && data[0] == _T("S+") )
+ {
+
+ TorrentTable::PRow row = GetTorrentTable().RowByHash( MakeHashUnsigned(data[1]) );
+ if ( !row.ok() ) return;
+ GetTorrentTable().AddSeedRequest( row );
+
+ unsigned long seeders=0;
+ unsigned long leechers=0;
+ if (data.GetCount() > 2)data[2].ToULong(&seeders);
+ if (data.GetCount() > 3)data[3].ToULong(&leechers);
+
+ // S-|hash tells client that seed is no longer neede for this torrent
+ }
+ else if ( data.GetCount() > 1 && data[0] == _T("S-") )
+ {
+
+ TorrentTable::PRow row = GetTorrentTable().RowByHash( MakeHashUnsigned(data[1]) );
+ if ( !row.ok() ) return;
+ GetTorrentTable().RemoveSeedRequest( row );
+
+ // M+|hash|url It tells the client if url is given that http mirror exists for given hash, else there are no mirrors.
+ }
+ else if ( data[0] == _T("M+") && data.GetCount() > 2 )
+ {
+
+ TorrentTable::PRow row = GetTorrentTable().RowByHash( MakeHashUnsigned(data[1]) );
+ if ( !row.ok() ) return;
+
+ for ( unsigned int index = 2; index < data.GetCount(); index++ )
+ {
+ try
+ {
+ row->handle.add_url_seed( STD_STRING( data[index] ) );
+ } catch ( std::exception& e )
+ {
+ }
+ }
+
+ // PING every minute - client must respond with its own "PING"
+ }
+ else if ( data[0] == _T("PING") )
+ {
+
+ SendMessageToCoordinator( _T("PING\n") );
+
+ //IH|hash|infohash infos the client about torrent's infohash b64 encoded
+ }
+ else if ( data.GetCount() > 2 && data[0] == _T("IH") )
+ {
+
+ TorrentTable::PRow row = GetTorrentTable().RowByHash( MakeHashUnsigned(data[1]) );
+ if ( !row.ok() ) return;
+
+ row->infohash = data[2];
+ // QH|query tag|type|name queries clients for spring hashes of given map/mod
+ }
+ else if ( data[0] == _T("QH") && data.GetCount() > 3 )
+ {
+ wxString query_tag = data[1];
+ wxString file_type = data[2];
+ wxString unitsync_name = data[3];
+ wxString hash;
+ if ( file_type == _T("MAP") )
+ {
+ hash = usync().GetMap( unitsync_name ).hash;
+ }
+ else if ( file_type == _T("MOD") )
+ {
+ hash = usync().GetMod( unitsync_name ).hash;
+ }
+ if ( !hash.IsEmpty() )
+ {
+ hash = MakeHashSigned( hash );
+ SendMessageToCoordinator( _T("QH|") + query_tag + _T("|") + hash );
+ }
+ }
+ else if ( data[0] == _T("TLISTDONE") )
+ {
+ ResumeFromList(); // resume download of files
+ }
+}
+
+
+void TorrentWrapper::OnConnected( Socket* /*unused*/ )
+{
+ wxLogMessage(_T("torrent system connected") );
+ m_started = true;
+
+ try
+ {
+ m_torr->start_dht();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) ); // TODO (BrainDamage#1#): add message to user on failure
+ }
+
+ GetTorrentTable().FlushData(); // flush the torrent data
+ m_maintenance_thread.Init();
+
+}
+
+
+void TorrentWrapper::OnDisconnected( Socket* /*unused*/ )
+{
+ wxLogMessage(_T("torrent system disconnected") );
+
+ std::set<TorrentTable::PRow> queued = GetTorrentTable().QueuedTorrentsByRow();
+ wxArrayString TorrentsToResume;
+ for ( std::set<TorrentTable::PRow>::iterator it = queued.begin(); it != queued.end(); it++ ) TorrentsToResume.Add( (*it)->hash );
+
+ std::map<libtorrent::torrent_handle, TorrentTable::PRow> handles = GetTorrentTable().RowByTorrentHandles();
+ for ( std::map<libtorrent::torrent_handle, TorrentTable::PRow>::iterator it = handles.begin(); it != handles.end(); it++ )
+ {
+ if ( !it->first.is_seed() ) TorrentsToResume.Add( it->second->hash ); // save leeching torrents for resume on next connection
+
+ try
+ {
+ m_torr->remove_torrent(it->first); //remove all torrents upon disconnect
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) ); // TODO (BrainDamage#1#): add message to user on failure
+ }
+ }
+
+ try
+ {
+ if (m_started) m_torr->stop_dht();
+ }
+ catch (std::exception& e)
+ {
+ wxLogError( TowxString( e.what() ) ); // TODO (BrainDamage#1#): add message to user on failure
+ }
+
+
+ GetTorrentTable().FlushData(); // flush the torrent data
+
+ try
+ {
+ sett().SetTorrentListToResume( TorrentsToResume );
+ }
+ catch (GlobalDestroyedError)
+ {
+ }
+ m_started = false;
+ m_maintenance_thread.Stop();
+}
+
+
+void TorrentWrapper::OnDataReceived( Socket* sock )
+{
+ if ( sock == 0 ) return;
+
+ wxString data = sock->Receive();
+ m_buffer << data;
+ int returnpos = m_buffer.Find( _T("\n") );
+ while ( returnpos != -1 )
+ {
+ wxString cmd = m_buffer.Left( returnpos );
+ m_buffer = m_buffer.Mid( returnpos + 1 );
+ ReceiveandExecute( cmd );
+ returnpos = m_buffer.Find( _T("\n") );
+ }
+}
+
+#endif
diff --git a/src/torrentwrapper.h b/src/torrentwrapper.h
new file mode 100644
index 0000000..fbe23d2
--- /dev/null
+++ b/src/torrentwrapper.h
@@ -0,0 +1,298 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_TORRENTWRAPPER_H
+#define SPRINGLOBBY_HEADERGUARD_TORRENTWRAPPER_H
+
+#ifndef NO_TORRENT_SYSTEM
+
+//#ifdef _MSC_VER
+/// MSVC can not compile std::pair used in bimap with forward decl only.
+/// GCC cant compile TorrentTable::Row either.
+#include "libtorrent/torrent_handle.hpp"
+//#endif
+
+#include <wx/arrstr.h>
+
+#include <map>
+
+#include "inetclass.h"
+#include "mutexwrapper.h"
+#include "iunitsync.h"
+#include "thread.h"
+
+#include "autopointers.h"
+
+#define DEFAULT_P2P_COORDINATOR_PORT 8202
+#define DEFAULT_P2P_TRACKER_PORT 8201
+/*
+namespace libtorrent{ class session; };
+namespace libtorrent { struct torrent_handle; };
+*/
+class TorrentWrapper;
+
+namespace P2P {
+enum FileStatus
+{
+ /// Dont change values. Bit arithmetics is used in TorrentTable::Row
+ not_stored=0, /// file is not on disk and not downloading
+ queued=1, /// file is not on disk and queued for download
+ leeching=2,/// file is being downloaded
+ stored=128,/// file is on disk
+ seeding=129/// file is on disk and being seeded
+};
+}
+
+struct TorrentInfos
+{
+ float numcopies;
+ wxString name;
+ unsigned int downloaded;
+ unsigned int uploaded;
+ P2P::FileStatus downloadstatus;
+ float progress;
+ float inspeed;
+ float outspeed;
+ unsigned int filesize;
+ wxString hash;
+ int eta; //is set in update function of maintorrenttab
+};
+
+
+#define TorrentTable_validate
+
+class TorrentMaintenanceThread : public Thread
+{
+ public:
+ TorrentMaintenanceThread( TorrentWrapper* parent );
+ void Init();
+ void Stop();
+ void* Entry();
+
+ protected:
+ bool TestDestroy();
+
+ bool m_stop_thread;
+ TorrentWrapper& m_parent;
+};
+
+class TorrentTable
+{
+public:
+
+ bool IsConsistent();
+
+ TorrentTable():
+ m_seed_count(0),
+ m_leech_count(0)
+ {
+ }
+
+class Row: public RefcountedContainer
+ {
+ /// If you want to modify row's keys, you need to remove it from table first,
+ /// then re-insert
+ public:
+ wxString hash;/// key, unitsync hash
+ wxString name;/// key, unitsync name
+ libtorrent::torrent_handle handle;/// key
+ IUnitSync::MediaType type;
+ wxString infohash; /// torrent sha1 infohash in b64
+ //bool ondisk;
+
+ P2P::FileStatus status;
+ bool is_open;
+ Row():
+ type(IUnitSync::map),
+ status(P2P::not_stored)
+ {
+ }
+ bool HasFullFileLocal()
+ {
+ return status & P2P::stored;
+ }
+ void SetHasFullFileLocal(bool b=true)
+ {
+ if (b)
+ {
+ if ( !status & P2P::stored )
+ status=P2P::stored;
+ }
+ else
+ {
+ if ( status & P2P::stored )
+ status=P2P::not_stored;
+ }
+ }
+ };
+ typedef RefcountedPointer<Row> PRow;
+
+
+ struct TransferredData
+ {
+ unsigned int failed_check_counts;
+ unsigned int sentdata;
+ TransferredData(): failed_check_counts(0), sentdata(0) {}
+ };
+
+ // deletes all stored infos
+ void FlushData();
+
+ void InsertRow(PRow row);
+ void RemoveRow(PRow row);
+
+ /// row must be already inserted
+ void AddSeedRequest(PRow row);
+ void RemoveSeedRequest(PRow row);
+ void SetRowHandle(PRow row, const libtorrent::torrent_handle &handle);
+ void AddRowToDependencyCheckQueue(PRow row);
+ void RemoveRowFromDependencyCheckQueue(PRow row);
+ void RemoveRowHandle( PRow row );
+ void SetRowStatus( PRow row, P2P::FileStatus status );
+ void SetRowTransferredData( PRow row, TransferredData data );
+
+ bool IsSeedRequest(PRow row);
+
+/// Following methods return NULL if not found!
+ PRow RowByHash(const wxString &hash);
+ PRow RowByName(const wxString &name);
+ PRow RowByHandle(libtorrent::torrent_handle handle);
+ std::map<wxString, TorrentTable::PRow> RowsByHash();
+ std::set<PRow> SeedRequestsByRow();
+ std::map<libtorrent::torrent_handle, PRow> RowByTorrentHandles();
+ std::set<PRow> QueuedTorrentsByRow();
+ std::map<TorrentTable::PRow, TransferredData> TransferredDataByRow();
+ std::set<TorrentTable::PRow> DependencyCheckQueuebyRow();
+
+ unsigned int GetOpenSeedsCount();
+ unsigned int GetOpenLeechsCount();
+
+private:
+
+
+#ifdef TorrentTable_validate
+ std::set<PRow> all_torrents;
+#endif
+ std::map<wxString, PRow> hash_index;
+ std::map<wxString, PRow> name_index;
+ std::map<libtorrent::torrent_handle, PRow> handle_index;
+ std::set<PRow> seed_requests;
+ std::set<PRow> queued_torrents;
+ std::map<TorrentTable::PRow, TorrentTable::TransferredData> seed_sent_data;
+ std::set<TorrentTable::PRow> dep_check_queue;
+
+ unsigned int m_seed_count;
+ unsigned int m_leech_count;
+};
+
+class TorrentWrapper : public iNetClass
+{
+public:
+
+ TorrentWrapper();
+ ~TorrentWrapper();
+
+ enum DownloadRequestStatus
+ {
+ success,
+ not_connected,
+ paused_ingame,
+ duplicate_request,
+ file_not_found,
+ torrent_join_failed,
+ scheduled_in_cue,
+ missing_in_table
+ };
+
+ /// gui interface
+
+ bool ConnectToP2PSystem(const unsigned int tracker_no = 0);
+ void DisconnectFromP2PSystem();
+ bool IsConnectedToP2PSystem();
+ bool IsFileInSystem( const wxString& hash );
+ bool RemoveTorrentByHash( const wxString& hash );
+ int GetTorrentSystemStatus();
+
+ ///HashToTorrentData& GetSystemFileList();
+
+ /// lobby interface
+ void SetIngameStatus( bool status );
+ DownloadRequestStatus RequestFileByHash( const wxString& hash );
+ DownloadRequestStatus RequestFileByName( const wxString& name );
+ void UpdateSettings();
+ void UpdateFromTimer( int mselapsed );
+ std::map<int,TorrentInfos> CollectGuiInfos();
+ void SendMessageToCoordinator( const wxString& message );
+
+ /// threaded maintenance tasks
+ void JoinRequestedTorrents();
+ void RemoveUnneededTorrents();
+ void TryToJoinQueuedTorrents();
+ void SearchAndGetQueuedDependencies();
+ void ResumeFromList();
+
+ TorrentTable &GetTorrentTable()
+ {
+ ScopedLocker<TorrentTable> l_torrent_table(m_torrent_table);
+ return l_torrent_table.Get();
+ }
+
+private:
+
+ void CreateTorrent( const wxString& uhash, const wxString& name, IUnitSync::MediaType type );
+ DownloadRequestStatus RequestFileByRow( const TorrentTable::PRow& row );
+ DownloadRequestStatus QueueFileByRow( const TorrentTable::PRow& row );
+ bool RemoveTorrentByRow( const TorrentTable::PRow& row );
+ bool JoinTorrent( const TorrentTable::PRow& row, bool IsSeed );
+ bool DownloadTorrentFileFromTracker( const wxString& hash );
+
+ void ReceiveandExecute( const wxString& msg );
+ void OnConnected( Socket* sock );
+ void OnDisconnected( Socket* sock );
+ void OnDataReceived( Socket* sock );
+
+ wxString m_buffer;
+
+ bool ingame;
+ unsigned int m_timer_count;
+
+ wxArrayString m_tracker_urls;
+
+ MutexWrapper<TorrentTable> m_torrent_table;
+
+ TorrentMaintenanceThread m_maintenance_thread;
+
+ libtorrent::session* m_torr;
+ Socket* m_socket_class;
+
+
+ //!we set this when trying a tracker and waiting for connection to be established
+ bool m_is_connecting;
+
+ unsigned int m_connected_tracker_index;
+
+ bool m_started;
+
+};
+
+
+TorrentWrapper& torrent();
+
+#endif
+
+#endif // SPRINGLOBBY_HEADERGUARD_TORRENTWRAPPER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/ui.cpp b/src/ui.cpp
new file mode 100644
index 0000000..38b2e26
--- /dev/null
+++ b/src/ui.cpp
@@ -0,0 +1,1284 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+//
+// Class: Ui
+//
+
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+
+#include <wx/textdlg.h>
+#include <stdexcept>
+#include <wx/thread.h>
+#include <wx/intl.h>
+#include <wx/utils.h>
+#include <wx/debugrpt.h>
+#include <wx/filename.h>
+
+#include "ui.h"
+#include "tasserver.h"
+#include "settings.h"
+#include "server.h"
+#include "spring.h"
+#include "channel/channel.h"
+#include "connectwindow.h"
+#include "mainwindow.h"
+#include "user.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+#include "chatpanel.h"
+#include "battlelisttab.h"
+#include "battleroomtab.h"
+#include "battle.h"
+#include "mainchattab.h"
+#include "mainjoinbattletab.h"
+#include "mainsingleplayertab.h"
+#ifndef NO_TORRENT_SYSTEM
+#include "maintorrenttab.h"
+#include "torrentwrapper.h"
+#endif
+#include "unitsyncthread.h"
+#include "agreementdialog.h"
+#ifdef __WXMSW__
+#include "updater/updater.h"
+#endif
+
+#include "settings++/custom_dialogs.h"
+
+#include "sdlsound.h"
+#include "globalsmanager.h"
+
+Ui& ui()
+{
+ static GlobalObjectHolder<Ui> m_ui;
+ return m_ui;
+}
+
+Ui::Ui() :
+ m_serv(0),
+ m_main_win(0),
+ m_con_win(0),
+ m_upd_counter_torrent(0),
+ m_first_update_trigger(true),
+ m_ingame(false)
+{
+ m_main_win = new MainWindow( *this );
+ CustomMessageBoxBase::setLobbypointer(m_main_win);
+ m_serv = new TASServer();
+}
+
+Ui::~Ui()
+{
+ Disconnect();
+
+ delete m_serv;
+}
+
+Server& Ui::GetServer()
+{
+ ASSERT_LOGIC( m_serv != 0, _T("m_serv NULL!") );
+ return *m_serv;
+}
+
+bool Ui::GetServerStatus()
+{
+ return (bool)(m_serv);
+}
+
+
+ChatPanel* Ui::GetActiveChatPanel()
+{
+ return mw().GetActiveChatPanel();
+}
+
+
+MainWindow& Ui::mw()
+{
+ ASSERT_LOGIC( m_main_win != 0, _T("m_main_win = 0") );
+ return *m_main_win;
+}
+
+
+bool Ui::IsMainWindowCreated()
+{
+ if ( m_main_win == 0 ) return false;
+ else return true;
+}
+
+
+//! @brief Shows the main window on screen
+void Ui::ShowMainWindow()
+{
+ ASSERT_LOGIC( m_main_win != 0, _T("m_main_win = 0") );
+ mw().Show(true);
+}
+
+
+//! @brief Show the connect window on screen
+//!
+//! @note It will create the ConnectWindow if not allready created
+void Ui::ShowConnectWindow()
+{
+ if ( m_con_win == 0 )
+ {
+ ASSERT_LOGIC( m_main_win != 0, _T("m_main_win = 0") );
+ m_con_win = new ConnectWindow( m_main_win, *this );
+ }
+ m_con_win->CenterOnParent();
+ m_con_win->Show(true);
+ m_con_win->Raise();
+}
+
+
+//! @brief Connects to default server or opens the ConnectWindow
+//!
+//! @todo Fix Auto Connect
+//! @see DoConnect
+void Ui::Connect()
+{
+ bool doit = sett().GetAutoConnect();
+ if ( !doit )
+ ShowConnectWindow();
+ else
+ {
+ m_con_win = 0;
+ wxString server_name = sett().GetDefaultServer();
+ wxString nick = sett().GetServerAccountNick( server_name );
+ wxString pass = sett().GetServerAccountPass( server_name );
+ DoConnect( server_name, nick, pass);
+ }
+}
+
+
+void Ui::Reconnect()
+{
+ wxString servname = sett().GetDefaultServer();
+
+ wxString pass = sett().GetServerAccountPass(servname);
+ if ( !sett().GetServerAccountSavePass(servname) )
+ {
+ wxString pass2 = pass;
+ if ( !AskPassword( _("Server password"), _("Password"), pass2 ) ) return;
+ pass = pass2;
+ }
+
+ Disconnect();
+ DoConnect( servname, sett().GetServerAccountNick(servname), pass );
+}
+
+
+void Ui::Disconnect()
+{
+ if ( m_serv != 0 )
+ {
+ if ( IsConnected() ) {
+ GetServer().Disconnect();
+ }
+ }
+}
+
+
+//! @brief Opens the accutial connection to a server.
+void Ui::DoConnect( const wxString& servername, const wxString& username, const wxString& password )
+{
+ wxString host;
+ int port;
+
+ if ( !sett().ServerExists( servername ) )
+ {
+ ASSERT_LOGIC( false, _T("Server does not exist in settings") );
+ return;
+ }
+
+ Disconnect();
+
+ GetServer().SetUsername( username );
+ GetServer().SetPassword( password );
+
+ if ( sett().GetServerAccountSavePass( servername ) )
+ {
+ if ( GetServer().IsPasswordHash(password) ) sett().SetServerAccountPass( servername, password );
+ else sett().SetServerAccountPass( servername, GetServer().GetPasswordHash( password ) );
+ }
+ else
+ {
+ sett().SetServerAccountPass( servername, _T("") );
+ }
+ sett().SaveSettings();
+
+ host = sett().GetServerHost( servername );
+ port = sett().GetServerPort( servername );
+
+ GetServer().uidata.panel = m_main_win->GetChatTab().AddChatPanel( *m_serv, servername );
+ GetServer().uidata.panel->StatusMessage( _T("Connecting to server ") + servername + _T("...") );
+
+ // Connect
+ GetServer().Connect( servername, host, port );
+
+}
+
+
+bool Ui::DoRegister( const wxString& servername, const wxString& username, const wxString& password,wxString& reason)
+{
+ wxString host;
+ int port;
+
+ if ( !sett().ServerExists( servername ) )
+ {
+ ASSERT_LOGIC( false, _T("Server does not exist in settings") );
+ return false;
+ }
+
+ host = sett().GetServerHost( servername );
+ port = sett().GetServerPort( servername );
+ bool success = GetServer().Register( host, port, username, password,reason );
+ if ( success )
+ {
+ customMessageBox(SL_MAIN_ICON, _("Registration successful,\nyou should now be able to login."), _("Registration successful"), wxOK );
+ }
+ else
+ {
+ wxLogWarning( _T("registration failed, reason: %s"), reason.c_str() );
+ if ( reason == _("Connection timed out") || reason.IsEmpty() ) ConnectionFailurePrompt();
+ else customMessageBox(SL_MAIN_ICON,_("Registration failed, the reason was:\n")+ reason , _("Registration failed."), wxOK );
+ }
+ return success;
+
+}
+
+
+bool Ui::IsConnected() const
+{
+ if ( m_serv != 0 ) return m_serv->IsConnected();
+ return false;
+}
+
+void Ui::JoinChannel( const wxString& name, const wxString& password )
+{
+ if ( m_serv != 0 ) GetServer().JoinChannel( name, password );
+}
+
+
+void Ui::StartHostedBattle()
+{
+ ASSERT_LOGIC( m_serv != 0, _T("m_serv = 0") );
+ GetServer().StartHostedBattle();
+ sett().SetLastHostMap( GetServer().GetCurrentBattle()->GetHostMapName() );
+ sett().SaveSettings();
+}
+
+
+bool Ui::IsSpringRunning()
+{
+ return spring().IsRunning();
+}
+
+
+//! @brief Quits the entire application
+void Ui::Quit()
+{
+ Disconnect();
+
+ #ifndef NO_TORRENT_SYSTEM
+ torrent().DisconnectFromP2PSystem();// Cant hurt to disconnect unconditionally.
+ #endif
+
+ if ( m_con_win != 0 )
+ m_con_win->Close();
+}
+
+
+void Ui::ReloadUnitSync()
+{
+ usync().ReloadUnitSyncLib();
+ if ( m_main_win != 0 ) mw().OnUnitSyncReloaded();
+}
+
+
+void Ui::DownloadMap( const wxString& hash, const wxString& name )
+{
+#ifndef NO_TORRENT_SYSTEM
+ DownloadFileP2P( hash, name );
+#else
+ wxString newname = name;
+ newname.Replace( _T(" "), _T("+") );
+ wxString url = _T(" http://spring.jobjol.nl/search_result.php?search_cat=1&select_select=select_file_subject&Submit=Search&search=") + newname;
+ OpenWebBrowser ( url );
+#endif
+}
+
+
+void Ui::DownloadMod( const wxString& hash, const wxString& name )
+{
+#ifndef NO_TORRENT_SYSTEM
+ DownloadFileP2P( hash, name );
+#else
+ wxString newname = name;
+ newname.Replace( _T(" "), _T("+") );
+ wxString url = _T(" http://spring.jobjol.nl/search_result.php?search_cat=1&select_select=select_file_subject&Submit=Search&search=") + newname;
+ OpenWebBrowser ( url );
+#endif
+}
+
+void Ui::DownloadFileP2P( const wxString& hash, const wxString& name )
+{
+#ifndef NO_TORRENT_SYSTEM
+ if ( !torrent().IsConnectedToP2PSystem() ){
+ wxArrayString hashesToResume = sett().GetTorrentListToResume();
+ hashesToResume.Add( hash );
+ sett().SetTorrentListToResume( hashesToResume );
+ torrent().ConnectToP2PSystem();
+ }
+ else {
+
+ //we need a way to have the request happen only after connect is complete
+ TorrentWrapper::DownloadRequestStatus status;
+ if ( !hash.IsEmpty() ) {
+ status = torrent().RequestFileByHash( hash );
+ }
+ else if ( !name.IsEmpty() )
+ status = torrent().RequestFileByName( name );
+
+//!TODO: put some meaningful err msg here
+// if ( status != TorrentWrapper::success ){
+// customMessageBoxNoModal( SL_MAIN_ICON, _(""), _("") );
+// }
+ }
+#endif
+}
+
+
+void Ui::OpenWebBrowser( const wxString& url )
+{
+ if ( sett().GetWebBrowserUseDefault()
+ // These shouldn't happen, but if they do we use the default browser anyway.
+ || sett().GetWebBrowserPath() == wxEmptyString
+ || sett().GetWebBrowserPath() == _T("use default") )
+ {
+ if ( !wxLaunchDefaultBrowser( url ) )
+ {
+ wxLogWarning( _T("can't launch default browser") );
+ customMessageBoxNoModal(SL_MAIN_ICON, _("Couldn't launch browser. URL is: ") + url, _("Couldn't launch browser.") );
+ }
+ }
+ else
+ {
+ if ( !wxExecute ( sett().GetWebBrowserPath() + _T(" ") + url, wxEXEC_ASYNC ) )
+ {
+ wxLogWarning( _T("can't launch browser: %s"), sett().GetWebBrowserPath().c_str() );
+ customMessageBoxNoModal(SL_MAIN_ICON, _("Couldn't launch browser. URL is: ") + url + _("\nBroser path is: ") + sett().GetWebBrowserPath(), _("Couldn't launch browser.") );
+ }
+
+ }
+}
+
+
+//! @brief Display a dialog asking a question with OK and Canel buttons
+//!
+//! @return true if OK button was pressed
+//! @note this does not return until the user pressed any of the buttons or closed the dialog.
+bool Ui::Ask( const wxString& heading, const wxString& question )
+{
+ int answer = customMessageBox( SL_MAIN_ICON, question, heading, wxYES_NO );
+ return ( answer == wxYES );
+}
+
+
+bool Ui::AskPassword( const wxString& heading, const wxString& message, wxString& password )
+{
+ wxPasswordEntryDialog pw_dlg( &mw(), message, heading, password );
+ int res = pw_dlg.ShowModal();
+ password = pw_dlg.GetValue();
+ return ( res == wxID_OK );
+}
+
+
+bool Ui::AskText( const wxString& heading, const wxString& question, wxString& answer, long style )
+{
+ wxTextEntryDialog name_dlg( &mw(), question, heading, answer, style );
+ int res = name_dlg.ShowModal();
+ answer = name_dlg.GetValue();
+
+ return ( res == wxID_OK );
+}
+
+
+void Ui::ShowMessage( const wxString& heading, const wxString& message )
+{
+
+ if ( m_main_win == 0 ) return;
+ serverMessageBox( SL_MAIN_ICON, message, heading, wxOK);
+
+}
+
+
+bool Ui::ExecuteSayCommand( const wxString& cmd )
+{
+
+ if ( !IsConnected() ) return false;
+ //TODO insert logic for joining multiple channels at once
+ //or remove that from "/help"
+ if ( (cmd.BeforeFirst(' ').Lower() == _T("/join")) || (cmd.BeforeFirst(' ').Lower() == _T("/j")) )
+ {
+ wxString channel = cmd.AfterFirst(' ');
+ wxString pass = channel.AfterFirst(' ');
+ if ( !pass.IsEmpty() ) channel = channel.BeforeFirst(' ');
+ if ( channel.StartsWith(_T("#")) ) channel.Remove( 0, 1 );
+ GetServer().JoinChannel( channel, pass );
+ return true;
+ }
+ else if ( cmd.BeforeFirst(' ').Lower() == _T("/away") )
+ {
+ GetServer().GetMe().Status().away = true;
+ GetServer().GetMe().SendMyUserStatus();
+ return true;
+ }
+ else if ( cmd.BeforeFirst(' ').Lower() == _T("/back") )
+ {
+ if ( IsConnected() )
+ {
+ GetServer().GetMe().Status().away = false;
+ GetServer().GetMe().SendMyUserStatus();
+ return true;
+ }
+ }
+ else if ( cmd.BeforeFirst(' ').Lower() == _T("/ingame") )
+ {
+ wxString nick = cmd.AfterFirst(' ');
+ GetServer().RequestInGameTime( nick );
+ return true;
+ }
+ else if ( cmd.BeforeFirst(' ').Lower() == _T("/help") )
+ {
+ wxString topic = cmd.AfterFirst(' ');
+ ConsoleHelp( topic.Lower() );
+ return true;
+ }
+ else if ( cmd.BeforeFirst(' ').Lower() == _T("/msg") )
+ {
+ wxString user = cmd.AfterFirst(' ').BeforeFirst(' ');
+ wxString msg = cmd.AfterFirst(' ').AfterFirst(' ');
+ GetServer().SayPrivate( user, msg );
+ return true;
+ }
+ else if ( cmd.BeforeFirst(' ').Lower() == _T("/channels") )
+ {
+ mw().ShowChannelChooser();
+ return true;
+ }
+ return false;
+}
+
+
+void Ui::ConsoleHelp( const wxString& topic )
+{
+ ChatPanel* panel = GetActiveChatPanel();
+ if ( panel == 0 )
+ {
+ ShowMessage( _("Help error"), _("Type /help in a chat box.") );
+ return;
+ }
+ if ( topic == wxEmptyString )
+ {
+ panel->ClientMessage( _("SpringLobby commands help.") );
+ panel->ClientMessage( _T("") );
+ panel->ClientMessage( _("Global commands:") );
+ panel->ClientMessage( _(" \"/away\" - Sets your status to away.") );
+ panel->ClientMessage( _(" \"/back\" - Resets your away status.") );
+ panel->ClientMessage( _(" \"/changepassword oldpassword newpassword\" - Changes the current active account's password.") );
+ panel->ClientMessage( _(" \"/channels\" - Lists currently active channels.") );
+ panel->ClientMessage( _(" \"/help [topic]\" - Put topic if you want to know more specific information about a command.") );
+ panel->ClientMessage( _(" \"/join channel [password] [,channel2 [password2]]\" - Joins a channel.") );
+ panel->ClientMessage( _(" \"/j\" - Alias to /join.") );
+ panel->ClientMessage( _(" \"/ingame\" - Shows how much time you have in game.") );
+ panel->ClientMessage( _(" \"/msg username [text]\" - Sends a private message containing text to username.") );
+ panel->ClientMessage( _(" \"/part\" - Leaves current channel.") );
+ panel->ClientMessage( _(" \"/p\" - Alias to /part.") );
+ panel->ClientMessage( _(" \"/rename newalias\" - Changes your nickname to newalias.") );
+ panel->ClientMessage( _(" \"/sayver\" - Says what version of springlobby you have in chat.") );
+ panel->ClientMessage( _(" \"/testmd5 text\" - Returns md5-b64 hash of given text.") );
+ panel->ClientMessage( _(" \"/ver\" - Displays what version of SpringLobby you have.") );
+ panel->ClientMessage( _(" \"/clear\" - Clears all text from current chat panel") );
+ panel->ClientMessage( _T("") );
+ panel->ClientMessage( _("Chat commands:") );
+ panel->ClientMessage( _(" \"/me action\" - Say IRC style action message.") );
+ panel->ClientMessage( _T("") );
+ panel->ClientMessage( _("If you are missing any commands, go to #springlobby and try to type it there :)") );
+// panel->ClientMessage( _(" \"/\" - .") );
+ }
+ else if ( topic == _T("topics") )
+ {
+ panel->ClientMessage( _("No topics written yet.") );
+ }
+ else
+ {
+ panel->ClientMessage( _("The topic \"") + topic + _("\" was not found. Type \"/help topics\" only for available topics.") );
+ }
+}
+
+
+ChatPanel* Ui::GetChannelChatPanel( const wxString& channel )
+{
+ return mw().GetChannelChatPanel( channel );
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// EVENTS
+////////////////////////////////////////////////////////////////////////////////////////////
+
+
+void Ui::OnUpdate( int mselapsed )
+{
+ if ( GetServerStatus() )
+ {
+ GetServer().Update( mselapsed );
+ }
+
+ if ( m_first_update_trigger )
+ {
+ m_first_update_trigger = false;
+
+ if ( sett().GetAutoConnect() ) {
+ Connect(); //the start tab is set from UI::onLoggedin
+ }
+ else {
+ mw().ShowTab( sett().GetStartTab() );
+ }
+#ifdef __WXMSW__
+ if ( sett().GetAutoUpdate() )Updater().CheckForUpdates();
+#endif
+ }
+
+#ifndef NO_TORRENT_SYSTEM
+ if (m_upd_counter_torrent % 20 == 0 )
+ {
+ if ( sett().GetTorrentSystemAutoStartMode() == 1 && !torrent().IsConnectedToP2PSystem() ) torrent().ConnectToP2PSystem();
+ else if ( GetServerStatus() && GetServer().IsOnline() && !torrent().IsConnectedToP2PSystem() && sett().GetTorrentSystemAutoStartMode() == 0 ) torrent().ConnectToP2PSystem();
+ if ( ( !GetServerStatus() || !GetServer().IsOnline() ) && torrent().IsConnectedToP2PSystem() && sett().GetTorrentSystemAutoStartMode() == 0 ) torrent().DisconnectFromP2PSystem();
+ mw().GetTorrentTab().OnUpdate();
+ }
+ torrent().UpdateFromTimer( mselapsed );
+ m_upd_counter_torrent++;
+#endif
+}
+
+
+//! @brief Called when connected to a server
+//!
+//! @todo Display in servertab
+void Ui::OnConnected( Server& server, const wxString& server_name, const wxString& /*unused*/, bool supported )
+{
+ wxLogDebugFunc( _T("") );
+ if ( !m_last_used_backup_server.IsEmpty() )
+ {
+ m_last_used_backup_server = _T("");
+ }
+ else // connect successful & it's not a backup server fallback -> save as default
+ {
+ sett().SetDefaultServer( server_name );
+ }
+ if ( !IsSpringCompatible() )
+ {
+ #ifdef __WXMSW__
+ if ( Ask( _T("Request update"), _T("Would you like to query the server for a spring update?\n The server is totally demential and will disconnect you if no automatic update will be available") ) ) server.RequestSpringUpdate();
+ #endif
+ }
+
+ if ( server.uidata.panel ) server.uidata.panel->StatusMessage( _T("Connected to ") + server_name + _T(".") );
+ mw().GetJoinTab().OnConnected();
+
+}
+
+
+bool Ui::IsSpringCompatible()
+{
+ sett().RefreshSpringVersionList();
+ if ( sett().GetDisableSpringVersionCheck() ) return true;
+ wxString neededversion = GetServer().GetRequiredSpring();
+ if ( neededversion == _T("*") ) return true; // Server accepts any version.
+ else if ( neededversion.IsEmpty() ) return false;
+ std::map<wxString, wxString> versionlist = sett().GetSpringVersionList();
+ if ( versionlist.size() == 0 )
+ {
+ wxLogWarning( _T("can't get spring version from any unitsync") );
+ customMessageBoxNoModal(SL_MAIN_ICON, _("Couldn't get your spring versions from any unitsync library.\n\nOnline play is currently disabled."), _("Spring error"), wxICON_EXCLAMATION|wxOK );
+ return false;
+ }
+ for ( std::map<wxString, wxString>::iterator itor = versionlist.begin(); itor != versionlist.end(); itor++ )
+ {
+ if ( itor->second == neededversion )
+ {
+ if ( sett().GetCurrentUsedSpringIndex() != itor->first )
+ {
+ wxLogMessage(_T("server enforce usage of version: %s, switching to profile: %s"), neededversion.c_str(), itor->first.c_str() );
+ sett().SetUsedSpringIndex( itor->first );
+ ReloadUnitSync();
+ }
+ return true;
+ }
+ }
+ wxString message = wxString::Format( _("No compatible installed spring version has been found, this server requires version: %s\n"), neededversion.c_str() );
+ message << _("Your current installed versions are:");
+ for ( std::map<wxString, wxString>::iterator itor = versionlist.begin(); itor != versionlist.end(); itor++ ) message << _T(" ") << itor->second;
+ message << _T("\n") << _("Online play is currently disabled.");
+ customMessageBoxNoModal (SL_MAIN_ICON, message, _("Spring error"), wxICON_EXCLAMATION|wxOK );
+ wxLogWarning ( _T("no spring version supported by the server found") );
+ return false; // no compatible version found
+}
+
+
+void Ui::OnLoggedIn( )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetChatTab().RejoinChannels();
+ if ( sett().GetAutoConnect() )
+ mw().ShowTab( sett().GetStartTab() );
+}
+
+
+void Ui::OnDisconnected( Server& server, bool wasonline )
+{
+ if ( m_main_win == 0 ) return;
+ wxLogDebugFunc( _T("") );
+ if (!&server)
+ {
+ wxLogError(_T("WTF got null reference!!!"));
+ return;
+ }
+
+ mw().GetJoinTab().LeaveCurrentBattle();
+ mw().GetJoinTab().GetBattleListTab().RemoveAllBattles();
+
+ mw().GetChatTab().LeaveChannels();
+
+ if ( server.uidata.panel )
+ {
+ server.uidata.panel->StatusMessage( _("Disconnected from server.") );
+
+ server.uidata.panel->SetServer( 0 );
+ }
+ if ( !wasonline ) // couldn't even estabilish a socket, prompt the user to switch to another server
+ {
+ ConnectionFailurePrompt();
+ }
+}
+
+void Ui::ConnectionFailurePrompt()
+{
+ wxMessageDialog dlg( &mw(), _("A connection couldn't be established with the server\nWould you like to try again with the same server?\nNo to switch to next server in the list"), _("Connection failure"), wxYES_NO | wxCANCEL | wxNO_DEFAULT );
+ switch ( dlg.ShowModal() )
+ {
+ case wxID_YES: // try again with the same server/settings
+ {
+ Reconnect();
+ break;
+ }
+ case wxID_NO: // switch to next server in the list
+ {
+ SwitchToNextServer();
+ ShowConnectWindow();
+ break;
+ }
+ default:
+ case wxID_CANCEL: // do nothing
+ {
+ return;
+ }
+ }
+}
+
+void Ui::SwitchToNextServer()
+{
+ wxString previous_server = m_last_used_backup_server;
+ if ( previous_server.IsEmpty() ) previous_server = sett().GetDefaultServer();
+ wxArrayString serverlist = sett().GetServers();
+ int position = serverlist.Index( previous_server );
+ if ( position == wxNOT_FOUND ) position = -1;
+ position = ( position + 1) % serverlist.GetCount(); // switch to next in the list
+ m_last_used_backup_server = serverlist[position];
+ sett().SetDefaultServer( m_last_used_backup_server );
+ if ( m_con_win ) // we don't necessarily have that constructed yet (autojoin)
+ m_con_win->ReloadServerList();
+ sett().SetDefaultServer( previous_server ); // don't save the new server as default when switched this way
+}
+
+static inline bool IsAutoJoinChannel( Channel& chan )
+{
+ typedef std::vector<ChannelJoinInfo>
+ Vec;
+ typedef Vec::const_iterator
+ VecIt;
+ const Vec chans = sett().GetChannelsJoin();
+ for ( VecIt it = chans.begin(); it != chans.end(); ++it ) {
+ if ( it->name == chan.GetName() )
+ return true;
+ }
+ return false;
+}
+//! @brief Called when client has joined a channel
+//!
+//! @todo Check if a pannel allready exists for this channel
+void Ui::OnJoinedChannelSuccessful( Channel& chan )
+{
+ if ( m_main_win == 0 ) return;
+ wxLogDebugFunc( _T("") );
+
+ chan.uidata.panel = 0;
+
+ mw().OpenChannelChat( chan, !sett().GetAutoConnect() || !IsAutoJoinChannel( chan ) );
+}
+
+
+//! @brief Called when something is said in a channel
+void Ui::OnChannelSaid( Channel& channel, User& user, const wxString& message )
+{
+ wxLogDebugFunc( _T("") );
+ if ( channel.uidata.panel == 0 )
+ {
+ wxLogError( _T("ud->panel NULL") );
+ return;
+ }
+ channel.uidata.panel->Said( user.GetNick(), message );
+}
+
+
+void Ui::OnChannelDidAction( Channel& channel , User& user, const wxString& action )
+{
+ wxLogDebugFunc( _T("") );
+ if ( channel.uidata.panel == 0 )
+ {
+ wxLogError( _T("ud->panel NULL") );
+ return;
+ }
+ channel.uidata.panel->DidAction( user.GetNick(), action );
+}
+
+
+void Ui::OnChannelMessage( const wxString& channel, const wxString& msg )
+{
+ ChatPanel* panel = GetChannelChatPanel( channel );
+ if ( panel != 0 )
+ {
+ panel->StatusMessage( msg );
+ }
+}
+
+
+/** \brief this was used when channel was left via raw command in server tab, now it's not used by anything */
+void Ui::OnLeaveChannel( wxString& name )
+{
+ ChatPanel* panel = GetChannelChatPanel( name );
+
+ if (panel)
+ mw().GetChatTab().RemoveChatPanel( panel );
+}
+
+
+void Ui::OnUserJoinedChannel( Channel& chan, User& user )
+{
+ //wxLogDebugFunc( _T("") );
+ if ( chan.uidata.panel == 0 )
+ {
+ wxLogError( _T("ud->panel NULL") );
+ return;
+ }
+ chan.uidata.panel->Joined( user );
+}
+
+
+void Ui::OnChannelJoin( Channel& chan, User& user )
+{
+ //wxLogDebugFunc( _T("") );
+ if ( chan.uidata.panel == 0 )
+ {
+ wxLogError( _T("ud->panel NULL") );
+ return;
+ }
+ chan.uidata.panel->OnChannelJoin( user );
+}
+
+
+void Ui::OnUserLeftChannel( Channel& chan, User& user, const wxString& reason )
+{
+ //wxLogDebugFunc( _T("") );
+ if ( chan.uidata.panel == 0 )
+ {
+ wxLogError( _T("ud->panel NULL") );
+ return;
+ }
+ chan.uidata.panel->Parted( user, reason );
+}
+
+
+void Ui::OnChannelTopic( Channel& channel, const wxString& user, const wxString& topic )
+{
+ wxLogDebugFunc( _T("") );
+ if ( channel.uidata.panel == 0 )
+ {
+ wxLogError( _T("ud->panel NULL") );
+ return;
+ }
+ channel.uidata.panel->SetTopic( user, topic );
+}
+
+
+void Ui::OnChannelList( const wxString& channel, const int& numusers )
+{
+ ChatPanel* panel = GetActiveChatPanel();
+ if ( panel == 0 )
+ {
+ ShowMessage( _("error"), _("no active chat panels open.") );
+ return;
+ }
+ panel->StatusMessage( channel + wxString::Format( _("(%d users)"), numusers) );
+}
+
+
+void Ui::OnUserOnline( User& user )
+{
+ if ( m_main_win == 0 ) return;
+ /* UiUserData* data = new UiUserData();
+ data->panel = 0;
+
+ user.SetUserData( (void*)data );*/
+
+ mw().GetChatTab().OnUserConnected( user );
+}
+
+
+void Ui::OnUserOffline( User& user )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetChatTab().OnUserDisconnected( user );
+ if ( user.uidata.panel )
+ {
+ user.uidata.panel->SetUser( 0 );
+ user.uidata.panel = 0;
+ }
+ /* UiUserData* data = (UiUserData*)user.GetUserData();
+ if ( data == 0) return;
+
+ delete data;*/
+}
+
+
+void Ui::OnUserStatusChanged( User& user )
+{
+ if ( m_main_win == 0 ) return;
+ for ( int i = 0; i < GetServer().GetNumChannels(); i++ )
+ {
+ Channel& chan = GetServer().GetChannel( i );
+ if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) )
+ {
+ chan.uidata.panel->UserStatusUpdated( user );
+ }
+ }
+ if ( user.GetStatus().in_game ) mw().GetJoinTab().GetBattleListTab().UserUpdate( user );
+}
+
+
+void Ui::OnUnknownCommand( Server& server, const wxString& command, const wxString& params )
+{
+ if ( server.uidata.panel != 0 ) server.uidata.panel->UnknownCommand( command, params );
+}
+
+
+void Ui::OnMotd( Server& server, const wxString& message )
+{
+ if ( server.uidata.panel != 0 ) server.uidata.panel->Motd( message );
+}
+
+
+void Ui::OnServerMessage( Server& server, const wxString& message )
+{
+ if ( server.uidata.panel != 0 ) server.uidata.panel->StatusMessage( message );
+ else
+ {
+ ShowMessage( _("Server message"), message );
+ }
+}
+
+
+void Ui::OnUserSaid( User& user, const wxString& message, bool fromme )
+{
+ if ( m_main_win == 0 ) return;
+ if ( user.uidata.panel == 0 )
+ {
+ mw().OpenPrivateChat( user );
+ }
+ if ( fromme ) user.uidata.panel->Said( GetServer().GetMe().GetNick(), message );
+ else user.uidata.panel->Said( user.GetNick(), message );
+}
+
+
+void Ui::OnBattleOpened( IBattle& battle )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().GetBattleListTab().AddBattle( battle );
+ try
+ {
+ User& user = battle.GetFounder();
+ for ( int i = 0; i < GetServer().GetNumChannels(); i++ )
+ {
+ Channel& chan = GetServer().GetChannel( i );
+ if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) )
+ {
+ chan.uidata.panel->UserStatusUpdated( user );
+ }
+ }
+ }catch(...){}
+}
+
+
+void Ui::OnBattleClosed( IBattle& battle )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().GetBattleListTab().RemoveBattle( battle );
+ try
+ {
+ if ( &mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle )
+ {
+ if (!battle.IsFounderMe() )
+ customMessageBoxNoModal(SL_MAIN_ICON,_("The current battle was closed by the host."),_("Battle closed"));
+ mw().GetJoinTab().LeaveCurrentBattle();
+ }
+ }
+ catch (...){}
+ for ( unsigned int b = 0; b < battle.GetNumUsers(); b++ )
+ {
+ User& user = battle.GetUser( b );
+ user.SetBattle(0);
+ for ( int i = 0; i < GetServer().GetNumChannels(); i++ )
+ {
+ Channel& chan = GetServer().GetChannel( i );
+ if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) )
+ {
+ chan.uidata.panel->UserStatusUpdated( user );
+ }
+ }
+ }
+}
+
+
+void Ui::OnUserJoinedBattle( IBattle& battle, User& user )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().GetBattleListTab().UpdateBattle( battle );
+
+ try
+ {
+ if ( &mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle )
+ {
+ mw().GetJoinTab().GetBattleRoomTab().OnUserJoined( user );
+ OnBattleInfoUpdated( battle );
+ }
+ }
+ catch (...){}
+
+ for ( int i = 0; i < GetServer().GetNumChannels(); i++ )
+ {
+ Channel& chan = GetServer().GetChannel( i );
+ if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) )
+ {
+ chan.uidata.panel->UserStatusUpdated( user );
+ }
+ }
+}
+
+
+void Ui::OnUserLeftBattle( IBattle& battle, User& user )
+{
+ if ( m_main_win == 0 ) return;
+ user.SetSideiconIndex( -1 ); //just making sure he's not running around with some icon still set
+ user.BattleStatus().side = 0; // and reset side, so after rejoin we don't potentially stick with a num higher than avail
+ mw().GetJoinTab().GetBattleListTab().UpdateBattle( battle );
+ try
+ {
+ if ( &mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle )
+ {
+ mw().GetJoinTab().GetBattleRoomTab().OnUserLeft( user );
+ OnBattleInfoUpdated( battle );
+ if ( &user == &GetServer().GetMe() )
+ {
+ mw().GetJoinTab().LeaveCurrentBattle();
+ }
+ }
+ }
+ catch (...) {}
+ if ( user.BattleStatus().IsBot() ) return;
+ for ( int i = 0; i < GetServer().GetNumChannels(); i++ )
+ {
+ Channel& chan = GetServer().GetChannel( i );
+ if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) )
+ {
+ chan.uidata.panel->UserStatusUpdated( user );
+ }
+ }
+}
+
+void Ui::OnBattleInfoUpdated( IBattle& battle )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().GetBattleListTab().UpdateBattle( battle );
+ if ( mw().GetJoinTab().GetCurrentBattle() == &battle )
+ {
+ mw().GetJoinTab().UpdateCurrentBattle();
+ }
+}
+
+void Ui::OnBattleInfoUpdated( IBattle& battle, const wxString& Tag )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().GetBattleListTab().UpdateBattle( battle );
+ if ( mw().GetJoinTab().GetCurrentBattle() == &battle )
+ {
+ mw().GetJoinTab().UpdateCurrentBattle( Tag );
+ }
+}
+
+
+void Ui::OnJoinedBattle( Battle& battle )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().JoinBattle( battle );
+ if ( !usync().IsLoaded() )
+ {
+ customMessageBox(SL_MAIN_ICON, _("Your spring settings are probably not configured correctly,\nyou should take another look at your settings before trying\nto play online."), _("Spring settings error"), wxOK );
+ }
+ if ( battle.GetNatType() != NAT_None )
+ {
+ wxLogWarning( _T("joining game with NAT transversal") );
+ }
+}
+
+
+void Ui::OnHostedBattle( Battle& battle )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().HostBattle( battle );
+}
+
+
+void Ui::OnUserBattleStatus( IBattle& battle, User& user )
+{
+ if ( m_main_win == 0 ) return;
+ mw().GetJoinTab().BattleUserUpdated( user );
+ OnBattleInfoUpdated( battle );
+}
+
+
+void Ui::OnRequestBattleStatus( IBattle& battle )
+{
+ if ( m_main_win == 0 ) return;
+ try
+ {
+ if ( &mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle )
+ {
+ mw().GetJoinTab().GetBattleRoomTab().GetBattle().OnRequestBattleStatus();
+ }
+ }
+ catch (...) {}
+}
+
+
+void Ui::OnBattleStarted( Battle& battle )
+{
+ if ( m_main_win == 0 ) return;
+ wxLogDebugFunc( _T("") );
+ mw().GetJoinTab().GetBattleListTab().UpdateBattle( battle );
+}
+
+
+void Ui::OnSaidBattle( IBattle& /*battle*/, const wxString& nick, const wxString& msg )
+{
+ if ( m_main_win == 0 ) return;
+ try
+ {
+ mw().GetJoinTab().GetBattleRoomTab().GetChatPanel().Said( nick, msg );
+ }
+ catch (...) {}
+}
+
+
+void Ui::OnBattleAction( IBattle& /*battle*/, const wxString& nick, const wxString& msg )
+{
+ if ( m_main_win == 0 ) return;
+ try
+ {
+ mw().GetJoinTab().GetBattleRoomTab().GetChatPanel().DidAction( nick, msg );
+ }
+ catch (...){}
+}
+
+void Ui::OnSpringStarting()
+{
+ m_ingame = true;
+#ifndef NO_TORRENT_SYSTEM
+ torrent().SetIngameStatus(m_ingame);
+#endif
+}
+
+
+void Ui::OnSpringTerminated( long exit_code )
+{
+ m_ingame = false;
+#ifndef NO_TORRENT_SYSTEM
+ torrent().SetIngameStatus(m_ingame);
+#endif
+ if ( !m_serv ) return;
+
+ try {
+ GetServer().GetMe().Status().in_game = false;
+ GetServer().GetMe().SendMyUserStatus();
+ Battle *battle = GetServer().GetCurrentBattle();
+ if ( !battle )
+ return;
+ if( battle->IsFounderMe() && battle->GetAutoLockOnStart() ) {
+ battle->SetIsLocked( false );
+ battle->SendHostInfo( IBattle::HI_Locked );
+ }
+ } catch ( assert_exception ){}
+
+ if ( exit_code ) {
+// wxDebugReportCompress report;
+// wxString dir = sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator();
+// wxString tmp_filename = wxPathOnly( wxFileName::CreateTempFileName(_T("dummy")) ) + wxFileName::GetPathSeparator() + _T("settings.txt");
+// wxCopyFile( sett().GetCurrentUsedSpringConfigFilePath(), tmp_filename );
+// report.AddFile( dir + _T("infolog.txt"), _T("Infolog") );
+// report.AddFile( dir + _T("script.txt"), _T("Script") );
+// report.AddFile( dir + _T("ext.txt"), _T("Infolog") );
+// report.AddFile( dir + _T("unitsync.log"), _T("Infolog") );
+// report.AddFile( tmp_filename, _T("Settings") );
+// wxString info;
+// info << wxGetOsDescription() << ( wxIsPlatform64Bit() ? _T(" 64bit\n") : _T(" 32bit\n") );
+// report.AddText( _T("platform.txt"), info, _T("Platform") );
+// wxDebugReportPreviewStd().Show( report );
+// report.Process();
+ if ( customMessageBox( SL_MAIN_ICON, _T("The game has crashed.\nOpen infolog.txt?"), _T("Crash"), wxYES_NO ) == wxYES )
+ OpenFileInEditor( sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T("infolog.txt") );
+ }
+}
+
+
+void Ui::OnAcceptAgreement( const wxString& agreement )
+{
+ AgreementDialog dlg( m_main_win, agreement );
+ if ( dlg.ShowModal() == 1 )
+ {
+ GetServer().AcceptAgreement();
+ GetServer().Login();
+ }
+}
+
+
+void Ui::OnRing( const wxString& /*from */)
+{
+ if ( m_main_win == 0 ) return;
+ m_main_win->RequestUserAttention();
+
+#ifndef DISABLE_SOUND
+ if ( sett().GetChatPMSoundNotificationEnabled() )
+ sound().ring();
+#else
+ wxBell();
+#endif
+}
+
+
+void Ui::OnMapInfoCached( const wxString& /*unused*/ )
+{
+ if ( m_main_win == 0 ) return;
+ mw().OnUnitSyncReloaded();
+}
+
+
+void Ui::OnMinimapCached( const wxString& /*unused*/ )
+{
+ if ( m_main_win == 0 ) return;
+ mw().OnUnitSyncReloaded();
+}
+
+
+void Ui::OnModUnitsCached( const wxString& /*unused*/ )
+{
+}
+
+void Ui::OnMainWindowDestruct()
+{
+ //this is rather ugly and therefore disabled
+ //m_main_win = 0;
+}
+
+bool Ui::IsThisMe(User& other)
+{
+ return IsThisMe( other.GetNick() );
+}
+
+bool Ui::IsThisMe(User* other)
+{
+ return ( ( other != 0 ) && IsThisMe( other->GetNick() ) );
+}
+
+bool Ui::IsThisMe(const wxString& other)
+{
+ //if i'm not connected i have no identity
+ if (!IsConnected() || m_serv==0)
+ return false;
+ else
+ return ( other == GetServer().GetMe().GetNick() );
+}
+
+int Ui::TestHostPort( unsigned int port )
+{
+ return GetServer().TestOpenPort( port );
+}
+
+void Ui::ReloadPresetList()
+{
+ try
+ {
+ mw().GetSPTab().ReloadPresetList();
+ }
+ catch (...) {}
+ try
+ {
+ mw().GetJoinTab().ReloadPresetList();
+ }
+ catch (...) {}
+}
+
+bool Ui::OnPresetRequiringMap( const wxString& mapname )
+{
+ if ( wxYES == customMessageBox( SL_MAIN_ICON,
+ _("The selected preset requires the map ") + mapname + _(". Should it be downloaded? \
+ \n Selecting \"no\" will remove the missing map from the preset.\n\
+ Please reselect the preset after download finished"),
+ _("Map missing"),
+ wxYES_NO ) )
+ {
+ DownloadMap( _T("") , mapname );
+ return true;
+ }
+ return false;
+}
+
+void Ui::OpenFileInEditor( const wxString& filepath )
+{
+ wxString editor_path = sett().GetEditorPath( );
+ if ( editor_path == wxEmptyString ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _T("You have not chosen an external text editor to open files with.\nPlease Select one now."), _T("No editor set") );
+ mw().ShowConfigure( MainWindow::OPT_PAGE_GENERAL );
+ return;
+ }
+ bool success = ( wxExecute( editor_path + _T(" \"") + filepath + _T("\""), wxEXEC_ASYNC ) != 0 );
+ if ( !success ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _T("There was a problem launching the editor.\nPlease make sure the path is correct and the binary executable for your user.\nNote it's currently not possible to use shell-only editors like ed, vi, etc."), _T("Problem launching editor") );
+ mw().ShowConfigure( MainWindow::OPT_PAGE_GENERAL );
+ }
+
+}
diff --git a/src/ui.h b/src/ui.h
new file mode 100644
index 0000000..07fa63e
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,201 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_UI_H
+#define SPRINGLOBBY_HEADERGUARD_UI_H
+
+class Server;
+class TASServer;
+class ConnectWindow;
+class Spring;
+class MainWindow;
+class wxString;
+class Channel;
+class User;
+class IBattle;
+class Battle;
+class SinglePlayerBattle;
+class OfflineBattle;
+class ChatPanel;
+
+//this removes the necessity to drag wx/event.h into almost every other file for a single type
+//if it's too "hackish" for someone's taste, just include that header again and remove this (koshi)
+#ifndef wxEventType
+typedef int wxEventType;
+#endif
+
+typedef int AlertEventType;
+
+extern const wxEventType torrentSystemStatusUpdateEvt;
+
+
+//! @brief UI main class
+class Ui
+{
+ public:
+
+ Ui();
+ ~Ui();
+
+ enum PlaybackEnum {
+ ReplayPlayback,
+ SavegamePlayback
+ };
+
+ Server& GetServer();
+ bool GetServerStatus();
+ ChatPanel* GetActiveChatPanel();
+ ChatPanel* GetChannelChatPanel( const wxString& channel );
+
+ bool ExecuteSayCommand( const wxString& cmd );
+ void ConsoleHelp( const wxString& topic );
+
+ void ShowMainWindow();
+ void ShowConnectWindow();
+ void Connect();
+ void Disconnect();
+ void Reconnect();
+ void DoConnect( const wxString& servername, const wxString& username, const wxString& password );
+
+ void ConnectionFailurePrompt();
+ void SwitchToNextServer();
+
+ bool DoRegister( const wxString& servername, const wxString& username, const wxString& password, wxString& reason );
+
+ bool IsConnected() const;
+ void JoinChannel( const wxString& name, const wxString& password );
+
+ bool IsSpringCompatible();
+
+ bool IsSpringRunning();
+
+ void StartHostedBattle();
+ //void SendHostInfo( HostInfo update );
+
+ void Quit();
+
+ void ReloadUnitSync();
+
+ void DownloadMap( const wxString& hash, const wxString& name );
+ void DownloadMod( const wxString& hash, const wxString& name );
+
+ void OpenWebBrowser( const wxString& url );
+
+ bool Ask( const wxString& heading, const wxString& question );
+ bool AskText( const wxString& heading, const wxString& question, wxString& answer, long style = wxOK | wxCANCEL | wxCENTRE );
+ bool AskPassword( const wxString& heading, const wxString& message, wxString& password );
+ void ShowMessage( const wxString& heading, const wxString& message );
+ //void OnAlertEvent( AlertEventType ); //TODO alert system
+
+ MainWindow& mw();
+
+ bool IsMainWindowCreated();
+
+ void OnUpdate( int mselapsed );
+
+ void OnConnected( Server& server, const wxString& server_name, const wxString& server_ver, bool supported );
+ void OnLoggedIn( );
+ void OnDisconnected( Server& server, bool wasonline );
+
+ void OnJoinedChannelSuccessful( Channel& chan );
+ void OnUserJoinedChannel( Channel& chan, User& user );
+ void OnChannelJoin( Channel& chan, User& user );
+ void OnUserLeftChannel( Channel& chan, User& user, const wxString& reason );
+
+ void OnChannelTopic( Channel& channel , const wxString& user, const wxString& topic );
+ void OnChannelSaid( Channel& channel , User& user, const wxString& message );
+ void OnChannelDidAction( Channel& channel , User& user, const wxString& action );
+ void OnChannelMessage( const wxString& channel, const wxString& msg );
+
+ void OnLeaveChannel( wxString& name );
+ void OnChannelList( const wxString& channel, const int& numusers );
+ void OnUserOnline( User& user );
+ void OnUserOffline( User& user );
+ void OnUserStatusChanged( User& user );
+ void OnUserSaid( User& user, const wxString& message, bool me = false );
+
+ void OnUnknownCommand( Server& server, const wxString& command, const wxString& params );
+ void OnMotd( Server& server, const wxString& message );
+ void OnServerMessage( Server& server, const wxString& message );
+
+ void OnBattleOpened( IBattle& battle );
+ void OnBattleClosed( IBattle& battle );
+ void OnUserJoinedBattle( IBattle& battle, User& user );
+ void OnUserLeftBattle( IBattle& battle, User& user );
+ void OnBattleInfoUpdated( IBattle& battle );
+ void OnBattleInfoUpdated( IBattle& battle, const wxString& Tag );
+ void OnBattleStarted( Battle& battle );
+
+ void OnJoinedBattle( Battle& battle );
+ void OnHostedBattle( Battle& battle );
+ void OnUserBattleStatus( IBattle& battle, User& user );
+ void OnRequestBattleStatus( IBattle& battle );
+
+ void OnSaidBattle( IBattle& battle, const wxString& nick, const wxString& msg );
+ void OnBattleAction( IBattle& battle, const wxString& nick, const wxString& msg );
+
+ void OnSpringStarting();
+ void OnSpringTerminated( long exit_code );
+
+ void OnAcceptAgreement( const wxString& agreement );
+
+ void OnMainWindowDestruct();
+
+ void OnRing( const wxString& from );
+
+ void OnMapInfoCached( const wxString& mapname );
+ void OnMinimapCached( const wxString& mapname );
+ void OnModUnitsCached( const wxString& modname );
+ //! ask to download missing map, return true if download attempted
+ bool OnPresetRequiringMap( const wxString& mapname );
+
+ bool IsThisMe(User& other);
+ bool IsThisMe(User* other);
+ bool IsThisMe(const wxString& other);
+
+ int TestHostPort( unsigned int port );
+
+ void ReloadPresetList();
+
+ void OpenFileInEditor( const wxString& filepath );
+
+ protected:
+ Server* m_serv;
+ MainWindow* m_main_win;
+ ConnectWindow* m_con_win;
+
+ wxString m_last_used_backup_server;
+
+ unsigned int m_upd_counter_torrent;
+
+ bool m_first_update_trigger;
+
+ bool m_ingame;
+
+ //! does actual work, called from downloadmap/mod
+ void DownloadFileP2P( const wxString& hash, const wxString& name );
+
+ private:
+ Ui( const Ui& );
+
+};
+
+Ui& ui();
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_UI_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/uiutils.cpp b/src/uiutils.cpp
new file mode 100644
index 0000000..1e706ad
--- /dev/null
+++ b/src/uiutils.cpp
@@ -0,0 +1,498 @@
+/// \file uiutils.cpp
+
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+#include <wx/colour.h>
+#include <wx/image.h>
+#include <wx/mstream.h>
+#include <wx/bitmap.h>
+#include <wx/log.h>
+#include <wx/image.h>
+#include <wx/clipbrd.h>
+#include <wx/cmndata.h>
+#include <wx/colordlg.h>
+#include <wx/dataobj.h>
+
+#include <cmath>
+
+#include "uiutils.h"
+#include "utils/math.h"
+#include "utils/conversion.h"
+#include "utils/debug.h"
+#include "settings++/custom_dialogs.h"
+#include "settings.h"
+
+wxString RefineMapname( const wxString& mapname )
+{
+ wxString ret = mapname;
+ ret = ret.BeforeLast( '.' );
+ ret.Replace(_T("_"), _T(" ") );
+ ret.Replace(_T("-"), _T(" ") );
+ return ret;
+}
+
+
+wxString RefineModname( const wxString& modname )
+{
+ wxString ret = modname;
+ ret.Replace(_T("Absolute Annihilation"), _T("AA") );
+ ret.Replace(_T("Complete Annihilation"), _T("CA") );
+ ret.Replace(_T("Balanced Annihilation"), _T("BA") );
+ ret.Replace(_T("Expand and Exterminate"), _T("EE") );
+ ret.Replace(_T("War Evolution"), _T("WarEv") );
+ ret.Replace(_T("TinyComm"), _T("TC") );
+ ret.Replace(_T("BETA"), _T("b") );
+ ret.Replace(_T("Public Alpha"), _T("pa") );
+ ret.Replace(_T("Public Beta"), _T("pb") );
+ ret.Replace(_T("Public"), _T("p") );
+ ret.Replace(_T("Alpha"), _T("a") );
+ ret.Replace(_T("Beta"), _T("b") );
+ return ret;
+}
+
+
+wxString RTFtoText( const wxString& rtfinput )
+{
+ wxString ret = rtfinput;
+ ret = ret.AfterFirst( '{' ).BeforeLast( '}' );
+
+ ret.Replace( _T("\\pard"), _T("") ); // remove a ambiguus char
+
+ ret.Replace( _T("\\par"), _T(" \n") ); // convert the end of lines
+
+ wxString BeforeBrack = ret.BeforeFirst( '{' );
+ wxString AfterBrack = ret.AfterLast( '}' );
+ ret = BeforeBrack + AfterBrack; // remove everyhting that matches { text }
+
+ wxString out;
+ while ( ret.Find('\\') >= 0 ) //remove anything in the form \please\ignore\this
+ {
+ out += ret.BeforeFirst( '\\' );
+ ret = ret.AfterFirst ( '\\' );
+ ret = ret.AfterFirst ( ' ' );
+ } ;
+
+ return out;
+}
+
+bool AreColoursSimilar( const wxColour& col1, const wxColour& col2, int mindiff )
+{
+ int r,g,b;
+ r = col1.Red() - col2.Red();
+ g = col1.Green() - col2.Green();
+ b = col1.Blue() - col2.Blue();
+ r = r>0?r:-r;
+ g = g>0?g:-g;
+ b = b>0?b:-b;
+ int difference = std::min( r, g );
+ difference = std::min( difference, b );
+ return difference < mindiff;
+}
+
+
+void ColourDelta( int& r, int& g, int& b, const int& delta )
+{
+ int tmpdelta;
+ if ( delta > 0 )
+ {
+ r += delta;
+ tmpdelta = delta;
+ if ( r > 255 )
+ {
+ tmpdelta += r - 255;
+ r = 255;
+ }
+ g += tmpdelta;
+ tmpdelta = delta;
+ if ( g > 255 )
+ {
+ tmpdelta += g - 255;
+ g = 255;
+ }
+ b += tmpdelta;
+ if ( b > 255 ) b = 255;
+ }
+ else
+ {
+ r += delta;
+ tmpdelta = -delta;
+ if ( r < 0 )
+ {
+ tmpdelta -= r;
+ r = 0;
+ }
+ g -= tmpdelta;
+ tmpdelta = -delta;
+ if ( g < 0 )
+ {
+ tmpdelta -= g;
+ g = 0;
+ }
+ b -= tmpdelta;
+ if ( b < 0 ) b = 0;
+ }
+}
+
+wxColour ColourDelta( const wxColour& colour, const int& delta )
+{
+ int r = colour.Red();
+ int g = colour.Green();
+ int b = colour.Blue();
+ ColourDelta( r, g, b, delta );
+ return wxColour( r, g, b );
+}
+
+
+
+wxColour GetColorFromFloatStrng( const wxString& color )
+{
+ wxString c = color;
+ float r = 0, g = 0, b = 0;
+ r = FromwxString<double>(c.BeforeFirst( ' ' ));
+ c = c.AfterFirst( ' ' );
+ g = FromwxString<double>( c.BeforeFirst( ' ' ));
+ c = c.AfterFirst( ' ' );
+ b = FromwxString<double>(c.BeforeFirst( ' ' ));
+ r = clamp( r, 0.f, 1.f );
+ g = clamp( g, 0.f, 1.f );
+ b = clamp( b, 0.f, 1.f );
+ return wxColour( (unsigned char)(r*256), (unsigned char)(g*256), (unsigned char)(b*256) );
+}
+
+/**
+ @brief Blends two images based on alpha channel present in foreground image.
+ @param foreground Foreground image, must have an alpha channel
+ @param background Background image, may have an alpha channel
+ @param blend_alpha Whether the returned image will have an alpha channel.
+ @return A copy of the background image with the foreground image blended on
+ top of it. The returned image will have an alpha channel iff the background
+ image has an alpha channel. In that case the alpha channel is blended
+ identical to the red/green/blue channels.
+*/
+wxImage BlendImage( const wxImage& foreground, const wxImage& background, bool blend_alpha )
+{
+ if ( ( foreground.GetWidth() != background.GetWidth() ) || ( background.GetHeight() != foreground.GetHeight() ) )
+ {
+ wxLogDebugFunc(_T("size mismatch while blending"));
+ return background;
+ }
+
+ bool zhu = blend_alpha && background.HasAlpha();
+ if ( foreground.HasAlpha() )
+ {
+ wxImage ret( background.GetWidth(), foreground.GetHeight() );
+ const unsigned char* background_data = background.GetData();
+ const unsigned char* foreground_data = foreground.GetData();
+ const unsigned char* background_alpha = NULL;
+ const unsigned char* foreground_alpha = foreground.GetAlpha();
+ unsigned char* result_data = ret.GetData();
+ unsigned char* result_alpha = NULL;
+ unsigned int pixel_count = background.GetWidth() * background.GetHeight();
+
+ if ( zhu )
+ {
+ background_alpha = background.GetAlpha();
+ ret.InitAlpha();
+ result_alpha = ret.GetAlpha();
+ }
+
+ for ( unsigned int i = 0, i_a = 0; i < pixel_count * 3; i+=3, i_a++ )
+ {
+ unsigned char fore_alpha = foreground_alpha[i_a] ;
+ float back_blend_fac = ( 255 - fore_alpha)/255.0;
+ float fore_blend_fac = fore_alpha/255.0 ;
+
+ result_data[i] = foreground_data[i] * fore_blend_fac + background_data[i] * back_blend_fac ;
+ result_data[i+1] = foreground_data[i+1] * fore_blend_fac + background_data[i+1] * back_blend_fac ;
+ result_data[i+2] = foreground_data[i+2] * fore_blend_fac + background_data[i+2] * back_blend_fac ;
+
+ if ( zhu )
+ {
+ unsigned char back_alpha = background_alpha[i_a] ;
+ result_alpha[i_a] = fore_alpha * fore_blend_fac + back_alpha * back_blend_fac ;
+ }
+ }
+ return ret;
+ }
+ wxLogDebugFunc(_T("cannot blend without alpha"));
+ return background;
+}
+
+wxBitmap charArr2wxBitmap(const unsigned char * arg, int size)
+{
+ return wxBitmap( charArr2wxImage( arg, size) );
+}
+
+//wxBitmap charArr2wxBitmap(const unsigned char * arg, int size)
+//{
+// return wxBitmap( charArr2wxImage( arg, size) );
+//}
+
+wxImage charArr2wxImage(const unsigned char * arg, int size)
+{
+ wxMemoryInputStream istream( arg, size );
+ return wxImage( istream, wxBITMAP_TYPE_PNG );
+}
+
+wxBitmap charArr2wxBitmapWithBlending(const unsigned char * dest, int dest_size, const unsigned char * text, int text_size )
+{
+ wxImage dest_img( charArr2wxImage( dest, dest_size ) );
+ wxImage text_img( charArr2wxImage( text, text_size ) );
+ wxImage ret = BlendImage(text_img, dest_img );
+
+ return wxBitmap( ret );
+}
+
+wxBitmap BlendBitmaps( const wxBitmap& background, const wxBitmap& overlay, const int /*dim*/ )
+{
+ wxImage back = background.ConvertToImage();
+ wxImage front = overlay.ConvertToImage();
+ wxImage ret = BlendImage( front, back );
+ return wxBitmap( ret );
+}
+
+
+namespace {
+struct Resizer
+{
+ // Helper class for BorderInvariantResizeImage
+ // Author: Tobi Vollebregt
+
+ Resizer( wxImage& result, const wxImage& image, bool alpha )
+ : width( result.GetWidth() )
+ , height( result.GetHeight() )
+ , imwidth( image.GetWidth() )
+ , imheight( image.GetHeight() )
+ , half_min_width( (std::min(width, imwidth) + 1) / 2 ) // round up to cover middle pixel
+ , half_min_height( (std::min(height, imheight) + 1) / 2 ) // if new width/height is uneven.
+ , bytes_per_pixel( alpha ? 1 : 3 )
+ , image_data( alpha ? image.GetAlpha() : image.GetData() )
+ , result_data( alpha ? result.GetAlpha() : result.GetData() )
+ {
+ }
+
+ void CopyRow( int result_y, int image_y )
+ {
+ unsigned char* result_row = result_data + bytes_per_pixel * result_y * width;
+ const unsigned char* image_row = image_data + bytes_per_pixel * image_y * imwidth;
+ const int bytes = bytes_per_pixel * half_min_width;
+
+ memcpy( result_row, image_row, bytes );
+ memcpy( result_row + bytes_per_pixel * width - bytes, image_row + bytes_per_pixel * imwidth - bytes, bytes );
+
+ if ( width > imwidth )
+ {
+ unsigned char* result_pixel = result_row + bytes;
+ const unsigned char* image_pixel = image_row + bytes;
+
+ for (int x = half_min_width; x < width - half_min_width; ++x, result_pixel += bytes_per_pixel)
+ {
+ memcpy( result_pixel, image_pixel, bytes_per_pixel );
+ }
+ }
+ }
+
+ void CopyTopAndBottomRows()
+ {
+ for (int y = 0; y < half_min_height; ++y)
+ {
+ CopyRow( y, y );
+ CopyRow( height - 1 - y, imheight - 1 - y );
+ }
+ }
+
+ void CopyCenterRows()
+ {
+ for (int y = half_min_height; y < height - half_min_height; ++y)
+ {
+ CopyRow( y, half_min_height - 1 );
+ }
+ }
+
+ void operator () ()
+ {
+ CopyTopAndBottomRows();
+ CopyCenterRows();
+ }
+
+ const int width, height;
+ const int imwidth, imheight;
+ const int half_min_width, half_min_height;
+ const int bytes_per_pixel;
+ const unsigned char* const image_data;
+ unsigned char* const result_data;
+};
+}
+
+typedef std::vector<double> huevec;
+
+
+void hue(huevec& out, int amount, int level)
+{
+ if (level <= 1) {
+ if (out.size() < amount) out.push_back(0.0);
+ if (out.size() < amount) out.push_back(0.5);
+ }
+ else {
+ hue(out, amount, level - 1);
+ const int lower = out.size();
+ hue(out, amount, level - 1);
+ const int upper = out.size();
+ for (int i = lower; i < upper; ++i)
+ out.at(i) += 1.0 / (1 << level);
+ }
+}
+
+void hue(huevec& out, int amount)
+{
+ int level = 0;
+ while ((1 << level) < amount) ++level;
+
+ out.reserve(amount);
+ hue(out, amount, level);
+}
+
+std::vector<wxColour>& GetBigFixColoursPalette( int numteams )
+{
+ static std::vector<wxColour> result;
+ wxLogDebugFunc( TowxString(numteams) );
+ huevec huevector;
+ static int satvalbifurcatepos;
+ static std::vector<double> satvalsplittings;
+ if ( satvalsplittings.empty() ) // insert ranges to bifurcate
+ {
+ satvalsplittings.push_back( 1 );
+ satvalsplittings.push_back( 0 );
+ satvalbifurcatepos = 0;
+ }
+ hue( huevector, numteams );
+ int bisectionlimit = 20;
+ for ( int i = result.size(); i < numteams; i++ )
+ {
+ double hue = huevector[i];
+ double saturation = 1;
+ double value = 1;
+ int switccolors = i % 3; // why only 3 and not all combinations? because it's easy, plus the bisection limit cannot be divided integer by it
+
+ if ( ( i % bisectionlimit ) == 0 )
+ {
+ satvalbifurcatepos = satvalbifurcatepos % ( satvalsplittings.size() -1 );
+ std::vector<double>::iterator toinsert = satvalsplittings.begin() + satvalbifurcatepos + 1;
+ satvalsplittings.insert( toinsert, ( satvalsplittings[satvalbifurcatepos] - satvalsplittings[satvalbifurcatepos + 1] ) / 2 + satvalsplittings[satvalbifurcatepos + 1] );
+ satvalbifurcatepos += 2;
+ }
+
+ if ( switccolors == 1 )
+ {
+ saturation = satvalsplittings[satvalbifurcatepos -1];
+ }
+ else if ( switccolors == 2 )
+ {
+ value = satvalsplittings[satvalbifurcatepos -1];
+ }
+ hue += 0.17; // use as starting point a zone where color band is narrow so that small variations means high change in visual effect
+ if ( hue > 1 ) hue-= 1;
+ wxImage::HSVValue hsvcolor( hue, saturation, value );
+ wxImage::RGBValue rgbvalue = wxImage::HSVtoRGB( hsvcolor );
+ wxColour col( rgbvalue.red, rgbvalue.green, rgbvalue.blue );
+ result.push_back( col );
+ }
+ return result;
+}
+
+
+wxImage BorderInvariantResizeImage( const wxImage& image, int width, int height )
+{
+ if ( !image.IsOk() || (width == image.GetWidth() && height == image.GetHeight()) )
+ return image;
+
+ wxImage ret( width, height );
+ Resizer data_resize( ret, image, false );
+ data_resize();
+
+ if ( image.HasAlpha() )
+ {
+ ret.InitAlpha();
+ Resizer alpha_resize( ret, image, true );
+ alpha_resize();
+ }
+
+ return ret;
+}
+
+
+wxColour GetColourFromUser(wxWindow *parent, const wxColour& colInit, const wxString& caption, const wxString& palette)
+{
+ wxColourData data;
+ data = sett().GetCustomColors( palette );
+ data.SetChooseFull(true);
+ if ( colInit.Ok() )
+ {
+ data.SetColour((wxColour &)colInit); // const_cast
+ }
+
+ wxColour colRet;
+ wxColourDialog dialog(parent, &data);
+ if (!caption.empty())
+ dialog.SetTitle(caption);
+ if ( dialog.ShowModal() == wxID_OK )
+ {
+ colRet = dialog.GetColourData().GetColour();
+ }
+ //else: leave it invalid
+ sett().SaveCustomColors( dialog.GetColourData(), palette );
+
+ return colRet;
+}
+
+wxImage ReplaceChannelStatusColour( wxBitmap img, const wxColour& colour )
+{
+ wxImage ret = img.ConvertToImage();
+ wxImage::HSVValue origcolour = wxImage::RGBtoHSV( wxImage::RGBValue::RGBValue( colour.Red(), colour.Green(), colour.Blue() ) );
+
+ double bright = origcolour.value - 0.1*origcolour.value;
+ bright = clamp( bright, 0.0, 1.0 );
+ wxImage::HSVValue hsvdarker1( origcolour.hue, origcolour.saturation, bright );
+ bright = origcolour.value - 0.5*origcolour.value;
+ bright = clamp( bright, 0.0, 1.0 );
+ wxImage::HSVValue hsvdarker2( origcolour.hue, origcolour.saturation, bright );
+
+ wxImage::RGBValue rgbdarker1 = wxImage::HSVtoRGB( hsvdarker1 );
+ wxImage::RGBValue rgbdarker2 = wxImage::HSVtoRGB( hsvdarker2 );
+
+
+ ret.Replace( 164, 147, 0, rgbdarker2.red, rgbdarker2.green, rgbdarker2.blue );
+
+ ret.Replace( 255, 228, 0, rgbdarker1.red, rgbdarker1.green, rgbdarker1.blue );
+
+ ret.Replace( 255, 253, 234, colour.Red(), colour.Green(), colour.Blue() );
+
+ return ret;
+
+}
+
+wxSize MakeFit(const wxSize &original, const wxSize &bounds)
+{
+ if( ( bounds.GetWidth() <= 0 ) || ( bounds.GetHeight() <= 0 ) ) return wxSize(0,0);
+ int sizex = ( original.GetWidth() * bounds.GetHeight() ) / original.GetHeight();
+ if( sizex <= bounds.GetWidth() )
+ {
+ return wxSize( sizex, bounds.GetHeight() );
+ }
+ else
+ {
+ int sizey = ( original.GetHeight() * bounds.GetWidth() ) / original.GetWidth();
+ return wxSize( bounds.GetWidth(), sizey );
+ }
+}
+
+void CopyToClipboard( const wxString& text )
+{
+ if ( wxTheClipboard->Open() ) {
+ // This data objects are held by the clipboard,
+ // so do not delete them in the app.
+ wxTheClipboard->SetData( new wxTextDataObject( text ) );
+ wxTheClipboard->Close();
+ }
+}
+
diff --git a/src/uiutils.h b/src/uiutils.h
new file mode 100644
index 0000000..2456478
--- /dev/null
+++ b/src/uiutils.h
@@ -0,0 +1,74 @@
+/// \file uiutils.h
+
+#ifndef SPRINGLOBBY_HEADERGUARD_UIUTILS_H
+#define SPRINGLOBBY_HEADERGUARD_UIUTILS_H
+
+#include <wx/intl.h>
+#include <vector>
+
+class wxColour;
+class wxImage;
+class wxBitmap;
+
+
+#define wxDefaultBitmap wxBitmap()
+
+#define IsColourOk() IsOk()
+
+
+wxString RefineMapname( const wxString& mapname );
+wxString RefineModname( const wxString& modname );
+wxString RTFtoText( const wxString& rtfinput );
+bool AreColoursSimilar( const wxColour& col1, const wxColour& col2, int mindiff = 10 );
+
+void ColourDelta( int& r, int& g, int& b, const int& delta );
+wxColour ColourDelta( const wxColour& colour, const int& delta );
+
+wxColour GetColorFromFloatStrng( const wxString& color );
+
+//! takes best fitting size of original inside bounds keeping aspect ratio
+wxSize MakeFit(const wxSize &original, const wxSize &bounds);
+
+//! apply standard alpha blending to images
+wxImage BlendImage( const wxImage& foreground, const wxImage& background, bool blend_alpha = true );
+wxBitmap BlendBitmaps( const wxBitmap& background, const wxBitmap& overlay, const int dim = 16 );
+//! used to load png data into a wxImage
+wxImage charArr2wxImage(const unsigned char * arg, int size);
+//! used to load png data into a wxBitmap
+wxBitmap charArr2wxBitmap(const unsigned char * arg, int size);
+wxBitmap charArr2wxBitmapWithBlending(const unsigned char * arg, int size,
+ const unsigned char * text, int text_size);
+
+//! shrinks/expands image by removing/duplicating rows/columns from the center of the image
+wxImage BorderInvariantResizeImage( const wxImage& image, int width, int height );
+
+
+wxImage ReplaceChannelStatusColour( wxBitmap img, const wxColour& colour );
+
+std::vector<wxColour>& GetBigFixColoursPalette( int numteams );
+
+
+void CopyToClipboard( const wxString& text );
+
+#endif
+// SPRINGLOBBY_HEADERGUARD_UIUTILS_H
+
+
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/unitsyncthread.cpp b/src/unitsyncthread.cpp
new file mode 100644
index 0000000..e85c901
--- /dev/null
+++ b/src/unitsyncthread.cpp
@@ -0,0 +1,155 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+
+
+/*
+#include <wx/image.h>
+
+#include "unitsyncthread.h"
+#include "iunitsync.h"
+#include "utils.h"
+#include "settings.h"
+#include "springunitsynclib.h"
+#include "globalsmanager.h"
+
+#define LOCK_CACHE wxCriticalSectionLocker lock_criticalsection(m_lock)
+
+
+UnitSyncThread& CacheThread()
+{
+ static GlobalObjectHolder<UnitSyncThread> m_cache_thread;
+ return m_cache_thread;
+}
+
+UnitSyncThread::UnitSyncThread()
+{
+ LoadSettingsFromFile();
+}
+
+
+UnitSyncThread::~UnitSyncThread()
+{
+ sett().SetMapCachingThreadProgress( m_map_thread.GetCurrentIndex() );
+ sett().SetModCachingThreadProgress( m_mod_thread.GetCurrentIndex() );
+ Stop();
+}
+
+
+void UnitSyncThread::Pause()
+{
+ if ( m_map_thread.IsRunning() ) m_map_thread.Pause();
+ if ( m_mod_thread.IsRunning() ) m_mod_thread.Pause();
+ wxLogMessage( _T("caching thread paused") );
+}
+
+
+void UnitSyncThread::Resume()
+{
+ if ( !m_map_thread.IsRunning() ) m_map_thread.Resume();
+ if ( !m_mod_thread.IsRunning() ) m_mod_thread.Resume();
+ wxLogMessage( _T("caching thread resumed") );
+}
+
+
+void UnitSyncThread::Start()
+{
+ m_map_thread.Init();
+ m_mod_thread.Init();
+ wxLogMessage( _T("caching thread started") );
+}
+
+
+void UnitSyncThread::Stop()
+{
+ if( m_map_thread.IsAlive() ) m_map_thread.Stop();
+ if( m_mod_thread.IsAlive() ) m_mod_thread.Stop();
+ wxLogMessage( _T("caching thread stopped") );
+}
+
+
+void UnitSyncThread::LoadSettingsFromFile()
+{
+ m_map_thread.SetCurrentIndex( sett().GetModCachingThreadProgress() );
+ m_mod_thread.SetCurrentIndex( sett().GetMapCachingThreadProgress() );
+}
+
+
+void UnitSyncThread::UnitSyncThreadImpl::Init()
+{
+ Create();
+ SetPriority( WXTHREAD_MIN_PRIORITY );
+ Run();
+}
+
+
+void* UnitSyncThread::MapCacheThread::Entry()
+{
+ // crashes - here for test to see why
+ susynclib().GetMapCount();
+ while ( !TestDestroy() )
+ {
+ if(!Sleep( 20000 ))break;
+ // cache map infos
+ if( usync().IsLoaded() )
+ {
+ wxArrayString totalmaps = usync().GetMapList();
+ if ( m_current_index > totalmaps.GetCount() ) m_current_index = 0;
+ wxString mapname = totalmaps[m_current_index];
+ try
+ {
+ usync().GetMapOptions( mapname );
+ usync().GetMapEx( m_current_index );
+ usync().GetMinimap( mapname, -1, -1 );
+ } catch (...) {}
+ m_current_index++;
+ }
+ }
+ return 0;
+}
+
+
+void* UnitSyncThread::ModCacheThread::Entry()
+{
+ while ( !TestDestroy() )
+ {
+ if(!Sleep( 67000 ))break;
+ // cache mod infos
+ if( usync().IsLoaded() )
+ {
+ wxArrayString totalmods = usync().GetModList();
+ if ( m_current_index > totalmods.GetCount() ) m_current_index = 0;
+ wxString modname = totalmods[m_current_index];
+ try
+ {
+ usync().GetModOptions( modname );
+ usync().GetUnitsList( modname );
+ } catch (...) {}
+ m_current_index++;
+ }
+ }
+ return 0;
+}
+
+void UnitSyncThread::UnitSyncThreadImpl::Stop()
+{
+ m_stop_thread = true;
+}
+
+
+bool UnitSyncThread::UnitSyncThreadImpl::TestDestroy()
+{
+ return Thread::TestDestroy() || m_stop_thread;
+}
+
+
+unsigned int UnitSyncThread::UnitSyncThreadImpl::GetCurrentIndex()
+{
+ return m_current_index;
+}
+
+
+void UnitSyncThread::UnitSyncThreadImpl::SetCurrentIndex( unsigned int index )
+{
+ m_current_index = index;
+}
+
+*/
diff --git a/src/unitsyncthread.h b/src/unitsyncthread.h
new file mode 100644
index 0000000..fd64402
--- /dev/null
+++ b/src/unitsyncthread.h
@@ -0,0 +1,84 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_UNITSYNCTHREAD_H
+#define SPRINGLOBBY_HEADERGUARD_UNITSYNCTHREAD_H
+
+/*
+#include "thread.h"
+
+
+class UnitSyncThread
+{
+ public:
+
+ UnitSyncThread();
+ ~UnitSyncThread();
+
+ void Pause();
+ void Resume();
+ void Start();
+ void Stop();
+
+ void LoadSettingsFromFile();
+
+ protected:
+
+ class UnitSyncThreadImpl : public Thread
+ {
+ public:
+ UnitSyncThreadImpl() : m_stop_thread( false ) {}
+ void Init();
+ void Stop();
+
+ unsigned int GetCurrentIndex();
+ void SetCurrentIndex( unsigned int index );
+
+ protected:
+ bool TestDestroy();
+
+ bool m_stop_thread;
+ unsigned int m_current_index;
+ };
+
+ class MapCacheThread : public UnitSyncThreadImpl
+ {
+ public:
+ MapCacheThread() {}
+ protected:
+ void* Entry();
+ };
+
+ class ModCacheThread : public UnitSyncThreadImpl
+ {
+ public:
+ ModCacheThread() {}
+ protected:
+ void* Entry();
+ };
+
+ MapCacheThread m_map_thread;
+ ModCacheThread m_mod_thread;
+
+ wxCriticalSection m_lock;
+};
+
+UnitSyncThread& CacheThread();
+*/
+
+#endif // SPRINGLOBBY_HEADERGUARD_UNITSYNCTHREAD_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/updater/updater.cpp b/src/updater/updater.cpp
new file mode 100644
index 0000000..954ba24
--- /dev/null
+++ b/src/updater/updater.cpp
@@ -0,0 +1,170 @@
+
+#include "updater.h"
+#include "versionchecker.h"
+#include "../settings++/custom_dialogs.h"
+#include "../utils/platform.h"
+#include "../settings.h"
+#include "../globalsmanager.h"
+#include "../ui.h"
+#include "../mainwindow.h"
+#include "../httpdownloader.h"
+
+#include <wx/stdpaths.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+
+
+BEGIN_EVENT_TABLE(UpdaterClass, wxEvtHandler)
+ EVT_COMMAND(wxID_ANY, httpDownloadEvtComplete, UpdaterClass::OnDownloadEvent)
+ EVT_COMMAND(wxID_ANY, httpDownloadEvtFailed, UpdaterClass::OnDownloadEvent)
+END_EVENT_TABLE()
+
+UpdaterClass& Updater()
+{
+ static GlobalObjectHolder<UpdaterClass> m_upd;
+ return m_upd;
+}
+
+
+UpdaterClass::UpdaterClass()
+{
+}
+
+
+UpdaterClass::~UpdaterClass()
+{
+}
+
+void UpdaterClass::CheckForUpdates()
+{
+ m_cur_mw_title = ui().mw().GetTitle();
+
+ wxString latestVersion = GetLatestVersion();
+
+ if (latestVersion == _T("-1"))
+ {
+ customMessageBoxNoModal(SL_MAIN_ICON, _("There was an error checking for the latest version.\nPlease try again later.\nIf the problem persists, please use Help->Report Bug to report this bug."), _("Error"));
+ return;
+ }
+ wxString myVersion = GetSpringLobbyVersion() ;
+
+ wxString msg = _("Your Version: ") + myVersion + _T("\n") + _("Latest Version: ") + latestVersion;
+ if ( !latestVersion.IsSameAs(myVersion, false) )
+ {
+ #ifdef __WXMSW__
+ int answer = customMessageBox(SL_MAIN_ICON, _("Your SpringLobby version is not up to date.\n\n") + msg + _("\n\nWould you like for me to autodownload the new version? Changes will take effect next you launch the lobby again."), _("Not up to date"), wxYES_NO);
+ if (answer == wxYES)
+ {
+ if ( IsUACenabled() ) {
+ WinExecuteAdmin( wxStandardPaths::Get().GetExecutablePath(), _T("-u") );
+ }
+ else {
+ ui().mw().SetTitle( _("SpringLobby -- downloading update") ); // doesn't make sense when launching the new instance, since we never get the return code atm
+ StartUpdate( latestVersion );
+ }
+
+ }
+ #else
+ customMessageBox(SL_MAIN_ICON, _("Your SpringLobby version is not up to date.\n\n") + msg, _("Not up to Date") );
+ #endif
+ }
+}
+
+#ifdef __WXMSW__
+//! DO NOT use mw() global unless fromCli is false !
+void UpdaterClass::StartUpdate( const wxString& latestVersion, bool fromCli )
+{
+ m_fromCli = fromCli;
+ wxString sep = wxFileName::GetPathSeparator();
+ wxString currentexe = wxStandardPaths::Get().GetExecutablePath();
+ if ( !wxFileName::IsDirWritable( currentexe.BeforeLast( wxFileName::GetPathSeparator() ) + wxFileName::GetPathSeparator() ) )
+ {
+ customMessageBoxNoModal(SL_MAIN_ICON, _("Unable to write to the lobby installation directory.\nPlease update manually or enable write permissions for the current user."), _("Error"));
+ return;
+ }
+ m_newexe = sett().GetLobbyWriteDir() + _T("update") + sep;
+ if ( !wxDirExists( m_newexe ) )
+ wxMkdir( m_newexe );
+ wxString url = _T("springlobby.info/windows/springlobby-") + latestVersion + _T("-win32.zip");
+ new HttpDownloaderThread<UpdaterClass>( url, m_newexe + _T("temp.zip"), *this, wxID_HIGHEST + 10000, true, true );
+}
+#endif
+
+//! DO NOT use mw() global unless fromCli is false !
+void UpdaterClass::OnDownloadEvent( wxCommandEvent& event )
+{
+ int code = event.GetInt();
+ if ( code != 0) customMessageBox(SL_MAIN_ICON, _("There was an error downloading for the latest version.\nPlease try again later.\nIf the problem persists, please use Help->Report Bug to report this bug."), _("Error"));
+ else
+ {
+ if ( !UpdateExe( m_newexe , false ) ) {
+ if ( !m_fromCli ) {
+ customMessageBoxNoModal(SL_MAIN_ICON, wxString::Format( _("There was an error while trying to replace the current executable version\n manual copy is necessary from: %s\n to: %s\nPlease use Help->Report Bug to report this bug."), m_newexe.c_str(), wxStandardPaths::Get().GetExecutablePath().c_str() ), _("Error"));
+ }
+ else {
+ customMessageBox(SL_MAIN_ICON, wxString::Format( _("There was an error while trying to replace the current executable version\n manual copy is necessary from: %s\n to: %s\nPlease use Help->Report Bug to report this bug."), m_newexe.c_str(), wxStandardPaths::Get().GetExecutablePath().c_str() ), _("Error"));
+ }
+ }
+ else
+ {
+ bool locale_ok = UpdateLocale( m_newexe, false );
+ if ( locale_ok ) {
+ if ( !m_fromCli ) {
+ customMessageBoxNoModal(SL_MAIN_ICON, _("Update complete. The changes will be available next lobby start."), _("Success"));
+ }
+ else {
+ customMessageBox(SL_MAIN_ICON, _("Update complete. The changes will be available next lobby start."), _("Success"));
+ wxRmdir( m_newexe );
+ wxTheApp->ExitMainLoop();
+ }
+ }
+ else {
+ if ( !m_fromCli ) {
+ customMessageBoxNoModal(SL_MAIN_ICON, _("Binary updated successfully. \nSome translation files could not be updated.\nPlease report this in #springlobby after restarting."), _("Partial success"));
+ }
+ else {
+ customMessageBox(SL_MAIN_ICON, _("Binary updated successfully. \nSome translation files could not be updated.\nPlease report this in #springlobby after restarting."), _("Partial success"));
+ wxRmdir( m_newexe );
+ wxTheApp->ExitMainLoop();
+ }
+ }
+ wxRmdir( m_newexe );
+ }
+ }
+
+ if ( !m_fromCli )
+ ui().mw().SetTitle( m_cur_mw_title );
+}
+
+//! DO NOT use mw() global unless fromCli is false !
+bool UpdaterClass::UpdateLocale( const wxString& tempdir, bool /*unused*/ )
+{
+ wxString target = wxPathOnly( wxStandardPaths::Get().GetExecutablePath() ) + wxFileName::GetPathSeparator() + _T("locale");
+ wxString origin = tempdir + _T("locale") + wxFileName::GetPathSeparator() ;
+ return CopyDir( origin, target );
+}
+
+//! DO NOT use mw() global unless fromCli is false !
+bool UpdaterClass::UpdateExe( const wxString& newexe, bool /*unused*/ )
+{
+ //this always returns false on msw
+// if ( !wxFileName::IsFileExecutable( newexe + _T("springlobby.exe") ) )
+// {
+// customMessageBoxNoModal(SL_MAIN_ICON, _("not exe."), _("Error"));
+// return false;
+// }
+ wxString currentexe = wxStandardPaths::Get().GetExecutablePath();
+
+ wxString backupfile = currentexe + _T(".bak");
+ wxRemoveFile( backupfile );
+ if ( !wxRenameFile( currentexe, backupfile ) )
+ return false;
+
+ if ( !wxCopyFile( newexe + _T("springlobby.exe"), currentexe ) )
+ {
+ wxRenameFile( backupfile, currentexe.AfterLast( wxFileName::GetPathSeparator() ) ); //restore original file from backup on update failure
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/updater/updater.h b/src/updater/updater.h
new file mode 100644
index 0000000..d224902
--- /dev/null
+++ b/src/updater/updater.h
@@ -0,0 +1,54 @@
+#ifndef SPRINGLOBBY_UPDATER_H_INCLUDED
+#define SPRINGLOBBY_UPDATER_H_INCLUDED
+
+#include <wx/event.h>
+
+
+class UpdaterClass : public wxEvtHandler
+{
+ public:
+ UpdaterClass();
+ ~UpdaterClass();
+ void CheckForUpdates();
+
+#ifdef __WXMSW__
+ void StartUpdate( const wxString& rev, bool fromCli = false );
+#endif
+ void OnDownloadEvent( wxCommandEvent& event );
+
+protected:
+
+ bool UpdateExe( const wxString& newexe, bool WaitForReboot );
+ bool UpdateLocale( const wxString& newdir, bool WaitForReboot );
+
+ wxString m_newexe;
+
+ DECLARE_EVENT_TABLE()
+
+ wxString m_cur_mw_title;
+
+ bool m_fromCli;
+
+};
+
+UpdaterClass& Updater();
+
+#endif // SPRINGLOBBY_GLOBALEVENTS_H_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/updater/versionchecker.cpp b/src/updater/versionchecker.cpp
new file mode 100644
index 0000000..f1e0531
--- /dev/null
+++ b/src/updater/versionchecker.cpp
@@ -0,0 +1,84 @@
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include <wx/sstream.h>
+#include <wx/protocol/http.h>
+#include <wx/log.h>
+
+#include "../utils/debug.h"
+#include "../settings++/custom_dialogs.h"
+
+
+//! @brief gets latest version from version.springlobby.info via HTTP
+wxString GetLatestVersion()
+{
+ wxHTTP versionRequest;
+
+ versionRequest.SetHeader(_T("Content-type"), _T("text/html; charset=utf-8"));
+ // normal timeout is 10 minutes.. set to 10 secs.
+ versionRequest.SetTimeout(10);
+ versionRequest.Connect( _T("version.springlobby.info"), 80);
+ wxInputStream *stream = versionRequest.GetInputStream( _T("/latest.txt") );
+ wxString result;
+
+ if (versionRequest.GetError() == wxPROTO_NOERR)
+ {
+
+ wxStringOutputStream output(&result);
+ stream->Read(output);
+ }
+ else
+ {
+ wxString err;
+ switch (versionRequest.GetError())
+ {
+
+ case wxPROTO_NETERR:
+ err = _T("Network Error");
+ break;
+ case wxPROTO_PROTERR:
+ err = _T("Negotiation error");
+ break;
+ case wxPROTO_CONNERR:
+ err = _T("Failed to connect to server");
+ break;
+ case wxPROTO_INVVAL:
+ err = _T("Invalid Value");
+ break;
+ case wxPROTO_NOHNDLR:
+ err = _T("No Handler");
+ break;
+ case wxPROTO_NOFILE:
+ err = _T("File doesn't exit");
+ break;
+ case wxPROTO_ABRT:
+ err = _T("Action Aborted");
+ break;
+ case wxPROTO_RCNCT:
+ err = _T("Reconnection Error");
+ break;
+ default:
+ err = _T("Unknown Error");
+ break;
+ }
+
+ wxLogDebugFunc(_T("Error connecting! Error is: ") + err);
+ customMessageBoxNoModal(SL_MAIN_ICON, _T("Error connecting! Error is: ") + err, _T(""));
+
+ return _T("-1");
+ }
+
+ wxDELETE(stream);
+ versionRequest.Close();
+
+ // Need to replace crap chars or versions will always be inequal
+ result.Replace(_T(" "), _T(""), true);
+ result.Replace(_T("\n"), _T(""), true);
+ result.Replace(_T("\t"), _T(""), true);
+
+ return result;
+}
diff --git a/src/updater/versionchecker.h b/src/updater/versionchecker.h
new file mode 100644
index 0000000..caaf3a8
--- /dev/null
+++ b/src/updater/versionchecker.h
@@ -0,0 +1,26 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_VERSIONCHECKER_H
+#define SPRINGLOBBY_HEADERGUARD_VERSIONCHECKER_H
+
+class wxString;
+
+wxString GetLatestVersion();
+
+#endif // SPRINGLOBBY_HEADERGUARD_VERSIONCHECKER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/user.cpp b/src/user.cpp
new file mode 100644
index 0000000..6a0452f
--- /dev/null
+++ b/src/user.cpp
@@ -0,0 +1,237 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+//
+// Class: User
+//
+
+#include "user.h"
+#include "battle.h"
+#include "server.h"
+//#include "utils.h"
+#include "chatpanel.h"
+#include "iconimagelist.h"
+
+#include <wx/string.h>
+#include <wx/intl.h>
+
+User::User( Server& serv )
+ : CommonUser( _T(""),_T(""),0 ),
+ m_serv(&serv),
+ m_battle(0),
+ m_flagicon_idx( icons().GetFlagIcon( _T("") ) ),
+ m_rankicon_idx( icons().GetRankIcon( 0 ) ),
+ m_statusicon_idx( icons().GetUserListStateIcon( m_status, false, false ) )
+{}
+
+User::User( const wxString& nick, Server& serv )
+ : CommonUser( nick,_T(""),0 ),
+ m_serv(&serv),
+ m_battle(0),
+ m_flagicon_idx( icons().GetFlagIcon( _T("") ) ),
+ m_rankicon_idx( icons().GetRankIcon( 0 ) ),
+ m_statusicon_idx( icons().GetUserListStateIcon( m_status, false, false ) )
+{}
+
+User::User( const wxString& nick, const wxString& country, const int& cpu, Server& serv)
+ : CommonUser( nick,country,cpu ),
+ m_serv(&serv),
+ m_battle(0),
+ m_flagicon_idx( icons().GetFlagIcon( country ) ),
+ m_rankicon_idx( icons().GetRankIcon( 0 ) ),
+ m_statusicon_idx( icons().GetUserListStateIcon( m_status, false, false ) )
+{}
+
+User::User( const wxString& nick )
+ : CommonUser( nick, wxEmptyString, 0 ),
+ m_serv(0),
+ m_battle(0),
+ m_flagicon_idx( icons().GetFlagIcon( _T("") ) ),
+ m_rankicon_idx( icons().GetRankIcon( 0 ) ),
+ m_statusicon_idx( icons().GetUserListStateIcon( m_status, false, false ) )
+{}
+
+User::User( const wxString& nick, const wxString& country, const int& cpu )
+ : CommonUser( nick,country,cpu ) ,
+ m_serv(0),
+ m_battle(0),
+ m_flagicon_idx( icons().GetFlagIcon( country ) ),
+ m_rankicon_idx( icons().GetRankIcon( 0 ) ),
+ m_statusicon_idx( icons().GetUserListStateIcon( m_status, false, false ) )
+{}
+
+User::User()
+ : CommonUser( wxEmptyString, wxEmptyString, 0 ),
+ m_serv(0),
+ m_battle(0),
+ m_flagicon_idx( icons().GetFlagIcon( _T("") ) ),
+ m_rankicon_idx( icons().GetRankIcon( 0 ) ),
+ m_statusicon_idx( icons().GetUserListStateIcon( m_status, false, false ) )
+{}
+
+User::~User(){
+ if(uidata.panel)uidata.panel->SetUser( 0 );
+}
+
+wxString UserStatus::GetDiffString ( const UserStatus& old ) const
+{
+ if ( old.away != away )
+ return ( away ? _("away") : _("back") );
+ if ( old.in_game != in_game )
+ return ( in_game ? _("ingame") : _("back from game") );
+ return
+ wxEmptyString;
+}
+
+void User::Said( const wxString& /*message*/ ) const
+{
+}
+
+
+void User::Say( const wxString& message ) const
+{
+ GetServer().SayPrivate( m_nick, message );
+}
+
+
+void User::DoAction( const wxString& message ) const
+{
+ GetServer().DoActionPrivate( m_nick, message );
+}
+
+
+Battle* User::GetBattle() const
+{
+ return m_battle;
+}
+
+
+void User::SetBattle( Battle* battle )
+{
+ m_battle = battle;
+ m_statusicon_idx = icons().GetUserListStateIcon( m_status, false, m_battle != 0 );
+}
+
+void User::SetStatus( const UserStatus& status )
+{
+ m_status = status;
+ // If user is host of a game, then his in_game status tells if the game is on!
+ if ( m_battle != 0 ) {
+ try
+ {
+ User& user = m_battle->GetFounder();
+ if ( user.GetNick() == m_nick ) {
+ m_battle->Update();
+ }
+ }catch(...){}
+ }
+
+ m_statusicon_idx = icons().GetUserListStateIcon( m_status, false, m_battle != 0 );
+ m_rankicon_idx = icons().GetRankIcon( m_status.rank );
+}
+
+void User::SetCountry( const wxString& country )
+{
+ m_country = country;
+ m_flagicon_idx = icons().GetFlagIcon( country );
+};
+
+void CommonUser::UpdateBattleStatus( const UserBattleStatus& status )
+{
+
+ // total 16 members to update.
+
+ m_bstatus.team = status.team;
+ m_bstatus.ally = status.ally;
+ m_bstatus.colour = status.colour;
+ m_bstatus.color_index = status.color_index;
+ m_bstatus.handicap = status.handicap;
+ m_bstatus.side = status.side;
+ m_bstatus.sync = status.sync;
+ m_bstatus.spectator = status.spectator;
+ m_bstatus.ready = status.ready;
+ if( !status.aishortname.IsEmpty() ) m_bstatus.aishortname = status.aishortname;
+ if( !status.aiversion.IsEmpty() ) m_bstatus.aiversion = status.aiversion;
+ if( !status.aitype > 0 ) m_bstatus.aitype = status.aitype;
+ if( !status.owner.IsEmpty() ) m_bstatus.owner = status.owner;
+ if( status.pos.x > 0 ) m_bstatus.pos.x = status.pos.x;
+ if( status.pos.y > 0 ) m_bstatus.pos.y = status.pos.y;
+
+ // update ip and port if those were set.
+ if( !status.ip.IsEmpty() ) m_bstatus.ip = status.ip;
+ if( status.udpport != 0 ) m_bstatus.udpport = status.udpport;// 15
+}
+
+
+void User::SendMyUserStatus() const
+{
+ GetServer().SendMyUserStatus();
+}
+
+
+bool User::ExecuteSayCommand( const wxString& cmd ) const
+{
+ if ( cmd.BeforeFirst(' ').Lower() == _T("/me") ) {
+ GetServer().DoActionPrivate( m_nick, cmd.AfterFirst(' ') );
+ return true;
+ } else return false;
+}
+
+UserStatus::RankContainer User::GetRank()
+{
+ return GetStatus().rank;
+}
+
+wxString User::GetRankName(UserStatus::RankContainer rank)
+{
+ //TODO: better interface to ranks?
+ switch( rank )
+ {
+ case UserStatus::RANK_1: return _("Newbie");
+ case UserStatus::RANK_2: return _("Beginner");
+ case UserStatus::RANK_3: return _("Average");
+ case UserStatus::RANK_4: return _("Above average");
+ case UserStatus::RANK_5: return _("Experienced");
+ case UserStatus::RANK_6: return _("Highly experienced");
+ case UserStatus::RANK_7: return _("Veteran");
+ default: return _("Unknown");
+ }
+}
+
+float User::GetBalanceRank()
+{
+ return 1.0 + 0.1 * float( GetStatus().rank - UserStatus::RANK_1 ) / float( UserStatus::RANK_7 - UserStatus::RANK_1 );
+}
+
+wxString User::GetClan()
+{
+ wxString tmp = m_nick.AfterFirst('[');
+ if ( tmp != m_nick )
+ {
+ wxString clan = tmp.BeforeFirst(']');
+ if ( clan != tmp ) return clan;
+ }
+ return _T("");
+}
+
+void CommonUser::SetStatus( const UserStatus& status )
+{
+ m_status = status;
+}
+
+//User& User::operator= ( const User& other )
+//{
+// if( this != &other ) {
+// //m_serv = (other.GetServer());
+// m_status = other.GetStatus();
+// m_battle = other.GetBattle();
+// m_nick = other.GetNick();
+// m_cpu = other.GetCpu();
+// m_country = other.GetCountry();
+// m_bstatus = other.GetBattleStatus();
+// uidata = other.uidata;
+//
+//
+// }
+// return *this;
+//}
+
+
diff --git a/src/user.h b/src/user.h
new file mode 100644
index 0000000..1c20e45
--- /dev/null
+++ b/src/user.h
@@ -0,0 +1,223 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_USER_H
+#define SPRINGLOBBY_HEADERGUARD_USER_H
+
+#include <wx/string.h>
+#include <wx/colour.h>
+
+class Server;
+
+const unsigned int SYNC_UNKNOWN = 0;
+const unsigned int SYNC_SYNCED = 1;
+const unsigned int SYNC_UNSYNCED = 2;
+
+//! @brief Struct used to store a client's status.
+struct UserStatus
+{
+ enum RankContainer
+ {
+ RANK_1,
+ RANK_2,
+ RANK_3,
+ RANK_4,
+ RANK_5,
+ RANK_6,
+ RANK_7
+ };
+
+ bool in_game;
+ bool away;
+ RankContainer rank;
+ bool moderator;
+ bool bot;
+ UserStatus(): in_game(false), away(false), rank(RANK_1), moderator(false), bot(false) {}
+ wxString GetDiffString ( const UserStatus& other ) const;
+};
+
+struct UserPosition
+{
+ int x;
+ int y;
+ UserPosition(): x(-1), y(-1) {}
+};
+
+struct UserBattleStatus
+{
+ // when adding something to this struct, also modify User::UpdateBattleStatus()
+ // total 17 members here
+ int team;
+ int ally;
+ wxColour colour;
+ int color_index;
+ int handicap;
+ int side;
+ unsigned int sync;
+ bool spectator;
+ bool ready;
+ bool isfromdemo;
+ UserPosition pos; // for startpos = 4
+ // bot-only stuff
+ wxString owner;
+ wxString aishortname;
+ wxString aiversion;
+ int aitype;
+ // for nat holepunching
+ wxString ip;
+ unsigned int udpport;
+ bool IsBot() const { return !aishortname.IsEmpty(); }
+ UserBattleStatus(): team(0),ally(0),colour(wxColour(0,0,0)),color_index(-1),handicap(0),side(0),sync(SYNC_UNKNOWN),spectator(false),ready(false), isfromdemo(false), aitype(-1), udpport(0) {}
+ bool operator == ( const UserBattleStatus& s ) const
+ {
+ return ( ( team == s.team ) && ( colour == s.colour ) && ( handicap == s.handicap ) && ( side == s.side ) && ( sync == s.sync ) && ( spectator == s.spectator ) && ( ready == s.ready ) && ( owner == s.owner ) && ( aishortname == s.aishortname ) && ( isfromdemo == s.isfromdemo ) && ( aitype == s.aitype ) );
+ }
+ bool operator != ( const UserBattleStatus& s ) const
+ {
+ return ( ( team != s.team ) || ( colour != s.colour ) || ( handicap != s.handicap ) || ( side != s.side ) || ( sync != s.sync ) || ( spectator != s.spectator ) || ( ready != s.ready ) || ( owner != s.owner ) || ( aishortname != s.aishortname ) || ( isfromdemo != s.isfromdemo ) || ( aitype != s.aitype ) );
+ }
+};
+
+class ChatPanel;
+class Battle;
+
+struct UiUserData {
+ UiUserData(): panel(0) {}
+ ChatPanel* panel;
+};
+
+//! parent class leaving out server related functionality
+class CommonUser
+{
+ public:
+ CommonUser(const wxString& nick, const wxString& country, const int& cpu)
+ : m_nick(nick), m_country(country), m_cpu(cpu) {};
+
+ virtual ~CommonUser(){}
+
+ wxString GetNick() const { return m_nick; }
+ virtual void SetNick( const wxString& nick ) { m_nick = nick; }
+
+ wxString GetCountry() const { return m_country; }
+ virtual void SetCountry( const wxString& country ) { m_country = country; }
+
+ int GetCpu() const { return m_cpu; }
+ void SetCpu( const int& cpu ) { m_cpu = cpu; }
+
+ wxString GetID() const { return m_id; }
+ void SetID( const wxString& id ) { m_id = id; }
+
+ UserStatus& Status() { return m_status; }
+
+ UserStatus GetStatus() const { return m_status; }
+ virtual void SetStatus( const UserStatus& status );
+
+ UserBattleStatus& BattleStatus() { return m_bstatus; }
+
+ UserBattleStatus GetBattleStatus() const { return m_bstatus; }
+
+ /** Read-only variant of BattleStatus() above.
+ */
+ const UserBattleStatus&
+ BattleStatus() const {
+ return m_bstatus;
+ }
+
+ //void SetBattleStatus( const UserBattleStatus& status );/// dont use this to avoid overwriting data like ip and port, use following method.
+ void UpdateBattleStatus( const UserBattleStatus& status );
+
+ /* void SetUserData( void* userdata ) { m_data = userdata; }
+ void* GetUserData() { return m_data; }*/
+
+ bool Equals( const CommonUser& other ) const { return ( m_nick == other.GetNick() ); }
+
+
+ protected:
+ wxString m_nick;
+ wxString m_country;
+ wxString m_id;
+ int m_cpu;
+ UserStatus m_status;
+ UserBattleStatus m_bstatus;
+
+ //void* m_data;
+
+};
+
+//! Class containing all the information about a user
+class User : public CommonUser
+{
+ public:
+
+ mutable UiUserData uidata;
+
+ User( Server& serv );
+ User( const wxString& nick, Server& serv );
+ User( const wxString& nick, const wxString& country, const int& cpu, Server& serv);
+ User( const wxString& nick );
+ User( const wxString& nick, const wxString& country, const int& cpu );
+ User();
+
+ virtual ~User();
+
+ // User interface
+
+ Server& GetServer() const { return *m_serv; }
+
+ void Said( const wxString& message ) const;
+ void Say( const wxString& message ) const;
+ void DoAction( const wxString& message ) const;
+
+ Battle* GetBattle() const;
+ void SetBattle( Battle* battle );
+
+ void SendMyUserStatus() const;
+ void SetStatus( const UserStatus& status );
+ void SetCountry( const wxString& country );
+
+ bool ExecuteSayCommand( const wxString& cmd ) const;
+
+ static wxString GetRankName(UserStatus::RankContainer rank);
+
+ float GetBalanceRank();
+ UserStatus::RankContainer GetRank();
+ wxString GetClan();
+
+ int GetFlagIconIndex() const { return m_flagicon_idx; }
+ int GetRankIconIndex() const { return m_rankicon_idx; }
+ int GetStatusIconIndex() const { return m_statusicon_idx; }
+ //bool operator< ( const User& other ) const { return m_nick < other.GetNick() ; }
+ //User& operator= ( const User& other );
+
+ int GetSideiconIndex() const { return m_sideicon_idx; }
+ void SetSideiconIndex( const int idx ) { m_sideicon_idx = idx; }
+
+ protected:
+ // User variables
+
+ Server* m_serv;
+ Battle* m_battle;
+ int m_flagicon_idx;
+ int m_rankicon_idx;
+ int m_statusicon_idx;
+ int m_sideicon_idx;
+
+ //! copy-semantics?
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_USER_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/useractions.cpp b/src/useractions.cpp
new file mode 100644
index 0000000..633ca5b
--- /dev/null
+++ b/src/useractions.cpp
@@ -0,0 +1,193 @@
+#include "useractions.h"
+
+#include <wx/intl.h>
+#include <wx/colour.h>
+#include "settings.h"
+#include <cmath>
+#include "settings++/custom_dialogs.h"
+
+//for updating ui, anybody feel free to replace with fancy events stuff :P
+#include "ui.h"
+#include "mainwindow.h"
+#include "mainjoinbattletab.h"
+#include "mainchattab.h"
+#include "battlelisttab.h"
+#include "battleroomtab.h"
+#include "chatpanel.h"
+#include "mainoptionstab.h"
+#include "groupoptionspanel.h"
+#include "globalsmanager.h"
+
+UserActions& useractions()
+{
+ static GlobalObjectHolder<UserActions> m_useractions;
+ return m_useractions;
+}
+
+UserActions::UserActions()
+{
+ Init();
+}
+
+UserActions::~UserActions()
+{
+
+}
+
+bool UserActions::DoActionOnUser( const ActionType action, const wxString& name )
+{
+ // preventing action on oneself wasn't the best idea, login gets disabled
+ //if ( m_knownUsers.Index( name ) == -1 || ui().IsThisMe(name) || action == ActNone )
+
+ if ( m_knownUsers.Index( name ) == -1 || action == ActNone )
+ return false;
+ else
+ return ( m_actionsGroups.find( action ) != m_actionsGroups.end() && m_actionsPeople[action].Index( name ) != -1 );
+
+ return false;
+}
+
+void UserActions::Init()
+{
+ m_groupNames = sett().GetGroups();
+ m_groupMap.clear();
+ m_groupActions.clear();
+ m_actionsGroups.clear();
+ m_actionsPeople.clear();
+ m_knownUsers.Clear();
+ for ( unsigned int i = 0; i < m_groupNames.GetCount(); ++i)
+ {
+ wxString name = m_groupNames[i];
+ m_groupMap[name] = sett().GetPeopleList( name );
+ for ( unsigned int k = 0; k < m_groupMap[name].GetCount(); ++k)
+ {
+ wxString user = m_groupMap[name][k];
+ m_knownUsers.Add( user );
+ m_peopleGroup[ user ] = name;
+ }
+ m_groupActions[name] = sett().GetGroupActions( name );
+ }
+ for ( int i = 0; i < m_numActions; ++i)
+ {
+ ActionType cur = (ActionType) (int) std::pow( 2.0, i);
+ wxSortedArrayString tmp;
+ for ( unsigned int i = 0; i < m_groupNames.GetCount(); ++i)
+ {
+ wxString name = m_groupNames[i];
+ if ( ( m_groupActions[name] & cur ) != 0 )
+ {
+ tmp.Add( name );
+ for ( unsigned int k = 0; k < m_groupMap[name].GetCount(); ++k)
+ {
+ m_actionsPeople[cur].Add( (m_groupMap[name])[k] );
+ }
+ }
+ }
+ m_actionsGroups[cur] = tmp;
+ }
+ m_actionsGroups[ActNone] = m_groupNames;
+
+}
+
+void UserActions::UpdateUI()
+{
+ try
+ {
+ ui().mw().GetJoinTab().GetBattleListTab().UpdateHighlights();
+ } catch(...){}
+
+ try
+ {
+ ui().mw().GetChatTab().UpdateNicklistHighlights();
+ } catch(...){}
+
+ try
+ {
+ ui().mw().GetJoinTab().GetBattleRoomTab().UpdateHighlights();
+ } catch(...){}
+
+ try
+ {
+ ui().mw().GetOptionsTab().GetGroupOptionsPanel().Update();
+ } catch(...){}
+}
+
+wxSortedArrayString UserActions::GetGroupNames() const
+{
+ return m_groupNames;
+}
+
+void UserActions::AddUserToGroup( const wxString& group, const wxString& name )
+{
+ if ( IsKnown( name , false ) || ui().IsThisMe( name ) )
+ return;
+ m_groupMap[group].Add(name);
+ sett().SetPeopleList( m_groupMap[group], group );
+ Init();
+ UpdateUI();
+}
+
+void UserActions::DeleteGroup(const wxString& name )
+{
+ sett().DeleteGroup( name );
+ Init();
+ UpdateUI();
+}
+
+void UserActions::AddGroup(const wxString& name )
+{
+ sett().AddGroup( name );
+ Init();
+ UpdateUI();
+}
+
+void UserActions::ChangeAction( const wxString& group, const ActionType action, bool add )
+{
+ ActionType old = m_groupActions[group];
+ old = (ActionType) ( add ? (old | action) : (old & ~action ) );
+ sett().SetGroupActions( group, old );
+ Init();
+ UpdateUI();
+}
+
+UserActions::ActionType UserActions::GetGroupAction( const wxString& group )
+{
+ return m_groupActions[group];
+}
+
+wxString UserActions::GetGroupOfUser( const wxString& user )
+{
+ return m_peopleGroup[ user ];
+}
+
+void UserActions::SetGroupColor( const wxString& group, const wxColour& color )
+{
+ sett().SetGroupHLColor( color, group );
+ Init();
+ UpdateUI();
+}
+
+wxColour UserActions::GetGroupColor( const wxString& group )
+{
+ return sett().GetGroupHLColor( group );
+}
+
+bool UserActions::IsKnown( const wxString& name, bool outputWarning ) const
+{
+ bool ret = m_knownUsers.Index( name ) != -1;
+ if ( outputWarning ){
+ customMessageBoxNoModal( SL_MAIN_ICON, _("To prevent logical inconsistencies, adding a user to more than one group is not allowed"),
+ _("Cannot add user to group") );
+ }
+
+ return ret;
+}
+
+void UserActions::RemoveUser(const wxString& name )
+{
+ wxString group = m_peopleGroup[name];
+ m_groupMap[group].Remove(name);
+ sett().SetPeopleList( m_groupMap[group], group );
+ Init();
+ UpdateUI();
+}
diff --git a/src/useractions.h b/src/useractions.h
new file mode 100644
index 0000000..9a757a3
--- /dev/null
+++ b/src/useractions.h
@@ -0,0 +1,113 @@
+#ifndef USERACTIONS_HH_INCLUDED
+#define USERACTIONS_HH_INCLUDED
+
+#include <wx/intl.h>
+#include <wx/arrstr.h>
+#include <map>
+
+class wxColour;
+
+//!provide a simple mapping between enum type and string to display in gui
+const wxString m_actionNames[] = { _("none"),_("highlight"),_("notify login/out"),_("ignore chat"),_("ignore pm"),
+ _("autokick"), _("notify hosted battle"),_("notify status change")};
+
+//! Provide the names to be used by config file.
+const wxString m_configActionNames[] = { _T("none"),_T("highlight"),_T("notify_login"),_T("ignore_chat"),_T("ignore_pm"),
+ _T("autokick"), _T("notify_hosted"),_T("notify_status")};
+
+//!same for tooltips
+const wxString m_actionTooltips[] = { _("no action at all"), _("highlight user in nick list and battles he participates in"),
+ _("popup a message box when user logs in/out from the server"), _T("you won't see message by these users in normal channels"),
+ _("ignore private messages of these users, no pm window will open if any of these try to contact you privately"),
+ _T("automatically kick users from battles hosted by yourself"), _("popup a message box when user hosts a new battle"),
+ _("popup a message box when user changes away status") };
+
+
+//! data handling for group / action management
+/** one single static instance is exposed as a global \n
+ by forcing a write to settings handler on every change data consistency is ensured \n
+ to keep runtime overhead as small as possible for the often called query funcs, all data is structured in multiple
+ maps and wherever possible sortedArrays (binary search instead of linear!) are used \n
+ the price is that on every change operation (very rare compared to queries) maps need to be cleared/reloaded \n
+ currently Gui updates are handled old fashoined way by hangling around classes, this should be improved to dynamic events
+
+**/
+class UserActions {
+
+public:
+ UserActions();
+ ~UserActions();
+
+ enum ActionType {
+ ActNone = 1,
+ ActHighlight = 2,
+ ActNotifLogin = 4,
+ ActIgnoreChat = 8,
+ ActIgnorePM = 16,
+ ActAutokick = 32,
+ ActNotifBattle = 64,
+ ActNotifStatus = 128,
+ /// update this when adding new actions.
+ ActLast=ActNotifStatus
+ };
+ static const int m_numActions = sizeof(m_actionNames) / sizeof(wxString);
+ bool DoActionOnUser( const ActionType action, const wxString& name ) ;
+ wxSortedArrayString GetGroupNames() const;
+ void AddUserToGroup( const wxString& group, const wxString& name );
+ void AddGroup(const wxString& name );
+ void DeleteGroup(const wxString& name );
+ void RemoveUser(const wxString& name );
+ void ChangeAction( const wxString& group, const ActionType action, bool add = true );
+ ActionType GetGroupAction( const wxString& group );
+ wxString GetGroupOfUser( const wxString& user ) ;
+ void SetGroupColor( const wxString& group, const wxColour& color );
+ wxColour GetGroupColor( const wxString& group );
+ bool IsKnown( const wxString& name, bool outputWarning = false ) const;
+
+protected:
+ //lotsa maps to keep runtime finds, etc ti a minimum
+ typedef std::map<wxString,wxSortedArrayString> GroupMap;
+ /// groupname --> array of people in the group
+ GroupMap m_groupMap;
+ typedef std::map<wxString,ActionType> GroupActionMap;
+ /// groupname --> ActionType for that group
+ GroupActionMap m_groupActions;
+ typedef std::map<ActionType,wxSortedArrayString> ActionGroupsMap;
+ /// ActionType --> array of groups with that actiontype
+ ActionGroupsMap m_actionsGroups;
+ typedef std::map<ActionType,wxSortedArrayString> ActionPeopleMap;
+ /// ActionType --> array of people with that actiontype
+ ActionPeopleMap m_actionsPeople;
+ ///nickname --> group map (we don't allow users to be in more than one group
+ typedef std::map<wxString,wxString> PeopleGroupMap;
+ PeopleGroupMap m_peopleGroup;
+ ///list all known users in groups
+ wxSortedArrayString m_knownUsers;
+
+ //reload all maps and stuff
+ void Init();
+ void UpdateUI();
+
+ wxSortedArrayString m_groupNames;
+};
+
+UserActions& useractions();
+#endif // USERACTIONS_HH_INCLUDED
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/userlist.cpp b/src/userlist.cpp
new file mode 100644
index 0000000..810c309
--- /dev/null
+++ b/src/userlist.cpp
@@ -0,0 +1,56 @@
+/* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
+#include <iterator>
+#include <stdexcept>
+#include <wx/log.h>
+
+#include "userlist.h"
+#include "user.h"
+#include "utils/debug.h"
+#include "utils/conversion.h"
+
+const UserList::user_map_t::size_type SEEKPOS_INVALID = UserList::user_map_t::size_type(-1);
+
+UserList::UserList(): m_seek(m_users.end()), m_seekpos(SEEKPOS_INVALID)
+{ }
+
+void UserList::AddUser( User& user )
+{
+ m_users[user.GetNick()] = &user;
+ m_seekpos = SEEKPOS_INVALID;
+}
+
+void UserList::RemoveUser( const wxString& nick )
+{
+ m_users.erase(nick);
+ m_seekpos = SEEKPOS_INVALID;
+}
+
+User& UserList::GetUser( const wxString& nick ) const
+{
+ user_const_iter_t u = m_users.find(nick);
+ ASSERT_EXCEPTION( u != m_users.end(), _T("UserList::GetUser(\"") + nick + _T("\"): no such user") );
+ //ASSERT_LOGIC( u != m_users.end(), _T("UserList::GetUser(\"") + nick + _T("\"): no such user") );
+ return *u->second;
+}
+
+User& UserList::GetUser( user_map_t::size_type index ) const
+{
+ if ((m_seekpos == SEEKPOS_INVALID) || (m_seekpos > index)) {
+ m_seek = m_users.begin();
+ m_seekpos = 0;
+ }
+ std::advance( m_seek, index - m_seekpos );
+ m_seekpos = index;
+ return *m_seek->second;
+}
+
+bool UserList::UserExists( wxString const& nick ) const
+{
+ return m_users.find(nick) != m_users.end();
+}
+
+UserList::user_map_t::size_type UserList::GetNumUsers() const
+{
+ return m_users.size();
+}
+
diff --git a/src/userlist.h b/src/userlist.h
new file mode 100644
index 0000000..2aa9343
--- /dev/null
+++ b/src/userlist.h
@@ -0,0 +1,52 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_USERLIST_H
+#define SPRINGLOBBY_HEADERGUARD_USERLIST_H
+
+#include <map>
+#include <wx/string.h>
+
+class User;
+
+class UserList
+{
+ public:
+ //! @brief mapping from nick to user object
+ typedef std::map<wxString, User*> user_map_t;
+ //! @brief iterator for user map
+ typedef user_map_t::iterator user_iter_t;
+ typedef user_map_t::const_iterator user_const_iter_t;
+
+ UserList();
+ virtual ~UserList() {}
+ void AddUser( User& user );
+ void RemoveUser( wxString const& nick );
+ User& GetUser( wxString const& nick ) const;
+ User& GetUser( user_map_t::size_type index ) const;
+ bool UserExists( wxString const& nick ) const;
+ user_map_t::size_type GetNumUsers() const;
+
+ private:
+ user_map_t m_users;
+ // The following are used as internal cache to speed up random access:
+ mutable user_const_iter_t m_seek;
+ mutable user_map_t::size_type m_seekpos;
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_USERLIST_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/userlistctrl.cpp b/src/userlistctrl.cpp
new file mode 100644
index 0000000..d6596f4
--- /dev/null
+++ b/src/userlistctrl.cpp
@@ -0,0 +1,218 @@
+#include "userlistctrl.h"
+#include "ui.h"
+#include "tasserver.h"
+#include "user.h"
+#include "iconimagelist.h"
+
+BEGIN_EVENT_TABLE( UserListctrl, CustomListCtrl )
+ EVT_LIST_COL_CLICK( USERLIST, UserListctrl::OnColClick )
+END_EVENT_TABLE()
+
+UserListctrl::UserListctrl(wxWindow* parent, const wxString& name, bool highlight,wxWindowID id)
+ : CustomListCtrl( parent,id,wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT, name, 2, highlight )
+{
+ wxListItem col;
+
+ col.SetImage( -1 );
+ InsertColumn( 0, col, _T("Country") );
+
+ col.SetText( _("Nickname") );
+ col.SetImage( -1 );
+ InsertColumn( 1, col, _T("Nickname") );
+
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = false;
+ m_sortorder[1].col = 1;
+ m_sortorder[1].direction = true;
+
+ SetColumnWidths();
+
+}
+
+void UserListctrl::SetColumnWidths()
+{
+ #if defined(__WXMAC__)
+ // autosize is entirely broken on wxmac.
+ SetColumnWidth( 0, 20 );
+ SetColumnWidth( 1, 228 );
+ #else
+ // on wxGTK it works, sort of.
+ SetColumnWidth( 0, wxLIST_AUTOSIZE_USEHEADER );
+ SetColumnWidth( 1, 160 );
+ #endif
+}
+
+UserListctrl::~UserListctrl()
+{
+ //dtor
+}
+
+void UserListctrl::AddUser( const UserDataMap& userdata )
+{
+ for ( UserDataMapConstIter it = userdata.begin(); it != userdata.end(); ++it)
+ {
+ AddUser( it->second );
+ }
+ //SetColumnWidths();
+}
+
+const UserListctrl::UserDataMap& UserListctrl::GetUserData() const
+{
+ return m_userdata;
+}
+
+void UserListctrl::AddUser( const UserData userdata )
+{
+ SetSelectionRestorePoint();
+
+ if ( IsInList ( userdata ) )
+ return;
+
+ int index = InsertItem( GetItemCount(), icons().GetFlagIcon( userdata.second ) );
+ SetItem( index, 1, userdata.first );
+
+ //highlight
+ HighlightItemUser( index, userdata.first );
+ m_userdata[index] = userdata;
+ SetItemData(index, (long)&m_userdata[index] );
+
+ Sort();
+ RestoreSelection();
+
+}
+
+
+void UserListctrl::Sort()
+{
+ for (int i = 1; i >= 0; i--) {
+ switch ( m_sortorder[ i ].col ) {
+ case 0 : SortItems( ( m_sortorder[ i ].direction )?&ComparePlayercountryUP:&ComparePlayercountryDOWN , 0 ); break;
+ case 1 : SortItems( ( m_sortorder[ i ].direction )?&ComparePlayernameUP:&ComparePlayernameDOWN , 0 ); break;
+ default: break;
+ }
+ }
+}
+
+void UserListctrl::SetTipWindowText( const long /*unused*/, const wxPoint /*unused*/){}
+
+wxArrayString UserListctrl::GetUserNicks( ) const
+{
+ wxArrayString ret;
+ for ( UserDataMapConstIter it = m_userdata.begin(); it != m_userdata.end(); ++it)
+ {
+ ret.Add( (*it).second.first );
+ }
+ return ret;
+}
+
+UserListctrl::UserDataMap UserListctrl::GetSelectedUserData() const
+{
+ UserDataMap ret;
+ long item = -1;
+ for ( long i = 0; i < GetSelectedItemCount(); ++i )
+ {
+ item = GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
+ if ( item == -1 ) // means nothing was found
+ return ret;
+ UserData data = *((UserData*) GetItemData( item ));
+ ret[item] = data;
+ }
+
+ return ret;
+}
+
+void UserListctrl::RemoveUsers( const UserDataMap& userdata )
+{
+ std::vector<UserDataMapIter> todelete;
+ for ( UserDataMapConstIter it = userdata.begin(); it != userdata.end(); ++it)
+ {
+ UserDataMapIter data = FindData( it->second );
+ if ( data != m_userdata.end() )
+ {
+ todelete.push_back( data );
+ }
+ }
+ std::vector<UserDataMapIter>::const_iterator it = todelete.begin();
+ for( ; it != todelete.end(); ++it)
+ m_userdata.erase( (*it) );
+
+ UserDataMap tmp = m_userdata;
+ m_userdata.clear();
+ DeleteAllItems();
+ AddUser( tmp );
+ SelectNone();
+
+
+}
+
+UserListctrl::UserDataMapIter UserListctrl::FindData( const UserData userdata )
+{
+ for ( UserDataMapIter it = m_userdata.begin(); it != m_userdata.end(); ++it)
+ {
+ if ( it->second.first == userdata.first )
+ return it;
+ }
+ return m_userdata.end();
+}
+
+bool UserListctrl::IsInList( const UserData userdata )
+{
+ UserDataMapConstIter it = FindData( userdata );
+ return ( it != m_userdata.end() );
+}
+
+void UserListctrl::HighlightItem( long /*item */)
+{
+
+}
+
+int wxCALLBACK UserListctrl::ComparePlayercountryDOWN(long item1, long item2, long /*unused*/)
+{
+ return ( (UserData*) item1)->first.Upper().CompareTo( ( (UserData*) item2)->first.Upper() ) ;
+}
+
+int wxCALLBACK UserListctrl::ComparePlayercountryUP(long item1, long item2, long /*unused*/)
+{
+ return ( (UserData*) item2)->first.Upper().CompareTo( ( (UserData*) item1)->first.Upper() ) ;
+}
+
+int wxCALLBACK UserListctrl::ComparePlayernameDOWN(long item1, long item2, long /*unused*/)
+{
+ return ( (UserData*) item1)->second.Upper().CompareTo( ( (UserData*) item2)->second.Upper() ) ;
+}
+
+int wxCALLBACK UserListctrl::ComparePlayernameUP(long item1, long item2, long /*unused*/)
+{
+ return ( (UserData*) item2)->second.Upper().CompareTo( ( (UserData*) item1)->second.Upper()) ;
+}
+
+void UserListctrl::OnColClick( wxListEvent& event )
+{
+ if ( event.GetColumn() == -1 ) return;
+ wxListItem col;
+ GetColumn( m_sortorder[0].col, col );
+ col.SetImage( -1 );
+ SetColumn( m_sortorder[0].col, col );
+
+ int i;
+ for ( i = 0; m_sortorder[i].col != event.GetColumn() && i < 2; ++i ) {}
+ if (i > 1) { i = 1; }
+ for ( ; i > 0; i--) { m_sortorder[i] = m_sortorder[i-1]; }
+ m_sortorder[0].col = event.GetColumn();
+ m_sortorder[0].direction = !m_sortorder[0].direction;
+
+
+ GetColumn( m_sortorder[0].col, col );
+ col.SetImage( ( m_sortorder[0].direction )?icons().ICON_UP:icons().ICON_DOWN );
+ SetColumn( m_sortorder[0].col, col );
+
+ Sort();
+}
+
+void UserListctrl::Clear()
+{
+ DeleteAllItems();
+ m_userdata.clear();
+ SelectNone();
+}
diff --git a/src/userlistctrl.h b/src/userlistctrl.h
new file mode 100644
index 0000000..7d948cd
--- /dev/null
+++ b/src/userlistctrl.h
@@ -0,0 +1,79 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_USERLISTCTRL_H
+#define SPRINGLOBBY_HEADERGUARD_USERLISTCTRL_H
+
+#include "customlistctrl.h"
+
+//! a rather sneaky approach to resue NickList for both off/online users
+/**
+ Don't ever use this for anything that needs constant updating, context menus sorting and the like.\n
+ Basically don't use it outside the groupuserdialog without extreme caution.
+**/
+class UserListctrl : public CustomListCtrl
+{
+ public:
+ //! nickname - country
+ typedef std::pair<wxString, wxString> UserData;
+ typedef std::map<unsigned int, UserData> UserDataMap;
+ typedef UserDataMap::const_iterator UserDataMapConstIter;
+ typedef UserDataMap::iterator UserDataMapIter;
+
+ public:
+ UserListctrl( wxWindow* parent, const wxString& name = _T("usergrouplist"), bool highlight = false,wxWindowID id=USERLIST );
+ virtual ~UserListctrl();
+
+ void AddUser( const UserData userdata );
+ void AddUser( const UserDataMap& userdata );
+ const UserDataMap& GetUserData() const;
+ void RemoveUsers( const UserDataMap& userdata );
+ UserDataMap GetSelectedUserData() const;
+ wxArrayString GetUserNicks( ) const;
+ void SetColumnWidths();
+ void OnColClick( wxListEvent& event );
+ //! delete both all items and associated data, handle with care!
+ void Clear();
+
+ protected:
+ UserDataMap m_userdata;
+
+ //! no-op atm, so i don't get segfault because of missing data
+ virtual void Sort();
+ virtual void SetTipWindowText( const long item_hit, const wxPoint position);
+
+ void HighlightItem( long item );
+
+ bool IsInList( const UserData userdata );
+ UserDataMapIter FindData( const UserData userdata );
+
+ static int wxCALLBACK ComparePlayernameUP(long item1, long item2, long sortData);
+ static int wxCALLBACK ComparePlayernameDOWN(long item1, long item2, long sortData);
+ static int wxCALLBACK ComparePlayercountryUP(long item1, long item2, long sortData);
+ static int wxCALLBACK ComparePlayercountryDOWN(long item1, long item2, long sortData);
+
+ enum {
+ USERLIST = 2312
+ };
+
+
+ DECLARE_EVENT_TABLE()
+
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_USERLISTCTRL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/usermenu.h b/src/usermenu.h
new file mode 100644
index 0000000..2a48825
--- /dev/null
+++ b/src/usermenu.h
@@ -0,0 +1,125 @@
+#ifndef SPRINGLOBBY_USERMENU_H
+#define SPRINGLOBBY_USERMENU_H
+
+#include <wx/menu.h>
+#include <map>
+
+#define GROUP_ID 24567
+#include "ui.h"
+#include "useractions.h"
+
+namespace SL_GENERIC {
+template < class EventHandler_ >
+class UserMenu : public wxMenu
+{
+ protected:
+ typedef EventHandler_ EventHandler;
+
+ public:
+ UserMenu(wxWindow* parent, const wxString& title = wxEmptyString, long style = 0)
+ : wxMenu( title, style ),m_groupsMenu(0), m_parent(parent),m_groupCounter(0)
+ {
+ m_groupsMenu = new wxMenu();
+ m_groupsnewItem = new wxMenuItem( m_groupsMenu, GROUP_ID - 2, _("Create new group...") );
+ m_parent->Connect( GROUP_ID - 2, wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler( EventHandler::OnUserMenuCreateGroup ) );
+ m_groupsMenu->Append( m_groupsnewItem );
+ m_groupsMenu->AppendSeparator();
+ // if ( !ui().IsThisMe( m_parent->GetSelectedUser() ) )
+ m_groupsMenuItem = AppendSubMenu( m_groupsMenu, _("Add to group..."));
+ m_groupsDeleteItem = new wxMenuItem( m_groupsMenu, GROUP_ID - 1, _("Remove from group") );
+ m_parent->Connect( GROUP_ID - 1, wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler( EventHandler::OnUserMenuDeleteFromGroup ) );
+ Append( m_groupsDeleteItem );
+ }
+
+ ~UserMenu(){}
+
+ void EnableItems(bool isUserSelected, const wxString& nick)
+ {
+ if ( isUserSelected )
+ {
+ bool enable = ( !ui().IsThisMe( nick ) );
+ m_groupsMenuItem->Enable( enable && !useractions().IsKnown( nick ) ) ;
+ m_groupsnewItem->Enable( enable && !useractions().IsKnown( nick ) ) ;
+ m_groupsDeleteItem->Enable( enable && useractions().IsKnown( nick ) ) ;
+ UpdateGroups();
+ }
+ else
+ {
+ m_groupsMenuItem->Enable( false ) ;
+ m_groupsDeleteItem->Enable( false ) ;
+ m_groupsnewItem->Enable( false );
+ }
+
+ }
+
+ wxString GetGroupByEvtID( const unsigned int id )
+ {
+ if ( id < m_idNameMap.size() )
+ return m_idNameMap[id];
+ else
+ return wxEmptyString;
+ }
+
+ protected:
+ wxMenu* m_groupsMenu;
+ wxMenuItem* m_groupsMenuItem;
+ wxMenuItem* m_groupsDeleteItem;
+ wxMenuItem* m_groupsnewItem;
+ wxArrayString m_oldGroups;
+ wxWindow* m_parent;
+ unsigned int m_groupCounter;
+ std::map<unsigned int, wxString> m_idNameMap;
+ std::map<wxString, unsigned int> m_NameIdMap;
+
+ void UpdateGroups()
+ {
+ wxSortedArrayString groupNames = useractions().GetGroupNames();
+ bool first = m_oldGroups.GetCount() == 0;
+ if ( first )
+ m_oldGroups = groupNames;
+ for ( unsigned int i = 0; i < groupNames.GetCount(); ++i)
+ {
+ if ( m_oldGroups.Index( groupNames[i] ) == wxNOT_FOUND || first )
+ {
+ m_idNameMap[m_groupCounter] = groupNames[i];
+ wxMenuItem* addItem = new wxMenuItem( m_groupsMenu, GROUP_ID + m_groupCounter , groupNames[i] , wxEmptyString, wxITEM_NORMAL );
+ m_groupsMenu->Append( addItem );
+ m_parent->Connect( GROUP_ID + m_groupCounter, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( EventHandler::OnUserMenuAddToGroup ) );
+ m_oldGroups.Add( groupNames[i] );
+ m_idNameMap[GROUP_ID + m_groupCounter] = groupNames[i];
+ m_NameIdMap[groupNames[i]] = GROUP_ID + m_groupCounter;
+ m_groupCounter++;
+ }
+ else
+ {
+ //wxMenuItem* old = FindItem( m_NameIdMap[groupNames[i]] );
+ Destroy( m_NameIdMap[groupNames[i]] );
+ }
+ }
+ }
+ //DECLARE_EVENT_TABLE();
+
+};
+
+}
+#endif // SPRINGLOBBY_USERMENU_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ springsettings is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ springsettings is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
+
diff --git a/src/utils/controls.cpp b/src/utils/controls.cpp
new file mode 100644
index 0000000..580ad42
--- /dev/null
+++ b/src/utils/controls.cpp
@@ -0,0 +1,8 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+#include "controls.h"
+#include "../settings.h"
+
+const wxChar* TooltipEnable(const wxChar* input)
+{
+ return sett().GetShowTooltips() ? input : _("");
+}
diff --git a/src/utils/controls.h b/src/utils/controls.h
new file mode 100644
index 0000000..0984002
--- /dev/null
+++ b/src/utils/controls.h
@@ -0,0 +1,52 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CONTROLS_H
+#define SPRINGLOBBY_HEADERGUARD_CONTROLS_H
+
+class wxWindow;
+class wxColour;
+
+#include <wx/intl.h>
+
+#ifdef __WXMSW__
+#define CONTROL_HEIGHT 22
+#else
+#define CONTROL_HEIGHT 28
+#endif
+
+#define bool2yn(b) ((b)?_("Yes"):_("No"))
+
+#ifdef __WXMSW__
+ const wxString DEFAULT_COLORDLG_TITLE = _("Choose color");
+#else
+ const wxString DEFAULT_COLORDLG_TITLE = _("Choose color (only first 16 will be saved)");
+#endif
+
+
+//! when querying for a color, always use this (it'll autosave/retrieve custom defined colors)
+wxColour GetColourFromUser(wxWindow *parent, const wxColour& colInit,
+ const wxString& caption = DEFAULT_COLORDLG_TITLE, const wxString& palette = _T("Default") );
+
+#define TE(v) TooltipEnable(v)
+
+/** @brief when setting tooltips use output of this func as input
+ it outputs empty string if tooltips are disabled in SL settings
+*/
+const wxChar* TooltipEnable(const wxChar* input);
+
+#endif // SPRINGLOBBY_HEADERGUARD_CONTROLS_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/utils/conversion.cpp b/src/utils/conversion.cpp
new file mode 100644
index 0000000..b5343ed
--- /dev/null
+++ b/src/utils/conversion.cpp
@@ -0,0 +1,23 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+#include "conversion.h"
+
+#include <wx/arrstr.h>
+
+int ConvertWXArrayToC(const wxArrayString& aChoices, wxString **choices)
+{
+ int n = aChoices.GetCount();
+ *choices = new wxString[n];
+
+ for ( int i = 0; i < n; i++ )
+ {
+ (*choices)[i] = aChoices[i];
+ }
+
+ return n;
+}
+
+TransformedArrayString::TransformedArrayString( const wxArrayString& original, wxString trans_op (const wxString& ) )
+{
+ for ( size_t i = 0; i < original.Count(); i++ )
+ Add( trans_op( original[i] ) );
+}
diff --git a/src/utils/conversion.h b/src/utils/conversion.h
new file mode 100644
index 0000000..31b9ce3
--- /dev/null
+++ b/src/utils/conversion.h
@@ -0,0 +1,113 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_CONVERSION_H
+#define SPRINGLOBBY_HEADERGUARD_CONVERSION_H
+
+/** \name Type conversions
+ **/
+ //! Converts an std::string to a wxString
+//static inline wxString WX_STRING( const std::string& v ) {
+// return wxString(v.c_str(),wxConvUTF8);
+//}
+
+#ifdef _MSC_VER
+typedef __int64 int64_t;
+#endif
+
+//! Converts a wxString to an std::string
+#define STD_STRING(v) std::string((const char*)(v).mb_str(wxConvUTF8))
+
+#include <wx/string.h>
+#include <sstream>
+
+#include <wx/arrstr.h>
+
+template<class T>
+static inline wxString TowxString(T arg){
+ std::stringstream s;
+ s << arg;
+ return wxString(s.str().c_str(),wxConvUTF8);
+}
+
+//template<>
+//inline wxString TowxString(const std::string& arg){
+// return wxString( arg.c_str(), wxConvUTF8 );
+//}
+
+template<>
+inline wxString TowxString(wxString arg){
+ return arg;
+}
+
+template<>
+inline wxString TowxString(const wxChar *arg){
+ return wxString(arg);
+}
+
+static inline wxString TowxString(){
+ return wxString();
+}
+
+template<class T>
+static inline T FromwxString(const wxString& arg){
+ std::stringstream s;
+ s << STD_STRING(arg);
+ int64_t ret;
+ s >> ret;
+ return (T)ret;
+}
+
+#define WX_STRINGC(v) wxString(v,wxConvUTF8)
+
+static inline long s2l( const wxString& arg )
+{
+ long ret;
+ arg.ToLong(&ret);
+ return ret;
+}
+
+static inline double s2d( const wxString& arg )
+{
+ double ret;
+ arg.ToDouble(&ret);
+ return ret;
+}
+
+
+/** @} */
+
+static inline wxString MakeHashUnsigned( const wxString& hash )
+{
+ return TowxString( FromwxString<unsigned int>( hash ) );
+}
+
+static inline wxString MakeHashSigned( const wxString& hash )
+{
+ return TowxString( FromwxString<int>( hash ) );
+}
+
+//! convert wxArrayString into a wxString[] which must be delete[]d by caller
+int ConvertWXArrayToC(const wxArrayString& aChoices, wxString **choices);
+
+
+class TransformedArrayString : public wxArrayString {
+ public:
+ TransformedArrayString( const wxArrayString& original, wxString trans_op (const wxString& ) );
+};
+
+#endif // SPRINGLOBBY_HEADERGUARD_CONVERSION_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp
new file mode 100644
index 0000000..3632720
--- /dev/null
+++ b/src/utils/debug.cpp
@@ -0,0 +1,2 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+
diff --git a/src/utils/debug.h b/src/utils/debug.h
new file mode 100644
index 0000000..cacef26
--- /dev/null
+++ b/src/utils/debug.h
@@ -0,0 +1,54 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_DEBUG_H
+#define SPRINGLOBBY_HEADERGUARD_DEBUG_H
+
+#include <stdexcept>
+
+class assert_exception : public std::runtime_error
+{
+ public:
+ assert_exception(std::string msg) : std::runtime_error(msg) {};
+};
+
+#ifndef __WXDEBUG__
+#define wxLogDebugFunc( params ) wxLogVerbose( _T("%s"), wxString(wxString(__FUNCTION__, wxConvUTF8 ) + _T(" ( ") + wxString(params) + _T(" )")).c_str() )
+#else
+#define wxLogDebugFunc( params ) wxLogTrace(_T("function calls"), params )
+#endif
+
+#if wxUSE_DEBUGREPORT
+#define ASSERT_LOGIC(cond,msg) if(!(cond))\
+{\
+ wxLogError(_T("logic error ( %s:%d ): %s"), TowxString(__FILE__).c_str(),__LINE__ , wxString(msg).c_str() );\
+ throw std::logic_error(std::string(wxString(msg).mb_str()));\
+}
+#else
+#define ASSERT_LOGIC(cond,msg) if(!(cond))\
+{\
+ wxLogError(_T("logic error ( %s:%d ): %s"), TowxString(__FILE__).c_str(),__LINE__ , wxString(msg).c_str() );\
+ throw std::logic_error(std::string(wxString(msg).mb_str()));\
+}
+#endif
+
+#define ASSERT_EXCEPTION(cond,msg) if(!(cond))\
+{wxLogMessage(_T("runtime assertion ( %s:%d ): %s"), TowxString(__FILE__).c_str(),__LINE__ , wxString(msg).c_str() );throw assert_exception(std::string(wxString(msg).mb_str()));}
+
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_DEBUG_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/utils/math.cpp b/src/utils/math.cpp
new file mode 100644
index 0000000..3632720
--- /dev/null
+++ b/src/utils/math.cpp
@@ -0,0 +1,2 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+
diff --git a/src/utils/math.h b/src/utils/math.h
new file mode 100644
index 0000000..a821b0e
--- /dev/null
+++ b/src/utils/math.h
@@ -0,0 +1,32 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MATH_H
+#define SPRINGLOBBY_HEADERGUARD_MATH_H
+
+#include <algorithm>
+
+template <typename T> T clamp(const T var,const T min,const T max)
+{ return ( (var < min) ? min : ( var > max ) ? max : var ); }
+
+template<typename T>
+T min(T a, T b, T c)
+{
+ return std::min(a, std::min(b, c));
+}
+
+#endif // SPRINGLOBBY_HEADERGUARD_MATH_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/utils/md5.c b/src/utils/md5.c
new file mode 100644
index 0000000..c35d96c
--- /dev/null
+++ b/src/utils/md5.c
@@ -0,0 +1,381 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost at aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost at aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/src/utils/md5.h b/src/utils/md5.h
new file mode 100644
index 0000000..698c995
--- /dev/null
+++ b/src/utils/md5.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost at aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost at aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke at bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/src/utils/misc.cpp b/src/utils/misc.cpp
new file mode 100644
index 0000000..1dfa9d8
--- /dev/null
+++ b/src/utils/misc.cpp
@@ -0,0 +1,59 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+#include "misc.h"
+
+#include "math.h"
+
+#include <wx/string.h>
+#include <wx/arrstr.h>
+#include <wx/log.h>
+#include <vector>
+
+
+double LevenshteinDistance(wxString s, wxString t)
+{
+ s.MakeLower(); // case insensitive edit distance
+ t.MakeLower();
+
+ const int m = s.length(), n = t.length(), _w = m + 1;
+ std::vector<unsigned char> _d((m + 1) * (n + 1));
+#define D(x, y) _d[(y) * _w + (x)]
+
+ for (int i = 0; i <= m; ++i) D(i,0) = i;
+ for (int j = 0; j <= n; ++j) D(0,j) = j;
+
+ for (int i = 1; i <= m; ++i)
+ {
+ for (int j = 1; j <= n; ++j)
+ {
+ const int cost = (s[i - 1] != t[j - 1]);
+ D(i,j) = min(D(i-1,j) + 1, // deletion
+ D(i,j-1) + 1, // insertion
+ D(i-1,j-1) + cost); // substitution
+ }
+ }
+ double d = (double) D(m,n) / std::max(m, n);
+ wxLogMessage( _T("LevenshteinDistance('%s', '%s') = %g"), s.c_str(), t.c_str(), d );
+ return d;
+#undef D
+}
+
+wxString GetBestMatch(const wxArrayString& a, const wxString& s, double* distance )
+{
+ const unsigned int count = a.GetCount();
+ double minDistance = 1.0;
+ int minDistanceIndex = -1;
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ const double distance = LevenshteinDistance(a[i], s);
+ if (distance < minDistance)
+ {
+ minDistance = distance;
+ minDistanceIndex = i;
+ }
+ }
+ if (distance != NULL) *distance = minDistance;
+ if (minDistanceIndex == -1) return _T("");
+ return a[minDistanceIndex];
+}
+
+
diff --git a/src/utils/misc.h b/src/utils/misc.h
new file mode 100644
index 0000000..833860b
--- /dev/null
+++ b/src/utils/misc.h
@@ -0,0 +1,71 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_MISC_H
+#define SPRINGLOBBY_HEADERGUARD_MISC_H
+
+
+class wxArrayString;
+class wxString;
+
+/** @brief Array with runtime determined size which is not initialized on creation.
+
+This RAII type is ment as output buffer for interfaces with e.g. C, where
+initializing a temp buffer to zero is waste of time because it gets overwritten
+with real data anyway.
+
+It's ment as replacement for the error prone pattern of allocating scratch/buffer
+memory using new/delete and using a std::vector "cast" to a C style array.
+*/
+template<typename T>
+class uninitialized_array
+{
+ public:
+ uninitialized_array(int numElem)
+ : elems( reinterpret_cast<T*>( operator new[]( numElem * sizeof(T) ) ) ) {
+ }
+ ~uninitialized_array() {
+ operator delete[]( elems );
+ }
+
+ /// this opens the door to basically any operation allowed on C style arrays
+ operator T*() { return elems; }
+
+ private:
+ T* elems;
+
+ // copying not allowed
+ uninitialized_array(const uninitialized_array&);
+ uninitialized_array& operator=(const uninitialized_array&);
+};
+
+
+/**
+ * @brief Computes Levenshtein distance (edit distance) between two strings.
+ * @return the Levenshtein distance normalized by the longest string's length.
+ * @note Source: http://en.wikipedia.org/wiki/Levenshtein_distance
+ */
+double LevenshteinDistance(wxString s, wxString t);
+
+
+/**
+ * @brief Gets the closest match for s in a, using LevenshteinDistance.
+ * @param distance If not NULL, *distance is set to the edit distance from s to the return value.
+ */
+wxString GetBestMatch(const wxArrayString& a, const wxString& s, double* distance = 0 );
+
+#endif // SPRINGLOBBY_HEADERGUARD_MISC_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/utils/platform.cpp b/src/utils/platform.cpp
new file mode 100644
index 0000000..b8293bf
--- /dev/null
+++ b/src/utils/platform.cpp
@@ -0,0 +1,269 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+
+#include "platform.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef VERSION
+ #define VERSION "unknown"
+#endif
+
+#include <wx/string.h>
+#include <wx/log.h>
+#include <wx/dynlib.h>
+#include <wx/stdpaths.h>
+#include <wx/textfile.h>
+#include <wx/filename.h>
+#include <wx/dir.h>
+
+#ifdef __WXMSW__
+ #include <wx/msw/registry.h>
+#endif
+
+#include <iostream>
+
+#include "conversion.h"
+#include "math.h"
+
+wxString GetLibExtension()
+{
+ return wxDynamicLibrary::CanonicalizeName(_T(""), wxDL_MODULE);
+}
+
+
+//! @brief Initializes the logging functions.
+///initializes logging in an hidden stream and std::cout/gui messages
+wxLogWindow* InitializeLoggingTargets( wxFrame* parent, bool console, bool showgui, bool logcrash, int verbosity, wxLogChain* logChain )
+{
+ wxLogWindow* loggerwin = 0;
+
+#if wxUSE_STD_IOSTREAM
+ if ( console && verbosity != 0 )
+ {
+ ///std::cout logging
+ logChain = new wxLogChain( new wxLogStream( &std::cout ) );
+ }
+#endif
+
+ if ( showgui && verbosity != 0 )
+ {
+ ///gui window logging
+ loggerwin = new wxLogWindow( (wxWindow*) parent, _T("SpringLobby error console"), showgui );
+ logChain = new wxLogChain( loggerwin );
+ }
+
+ #if 0 //TODO reenable wxUSE_DEBUGREPORT
+ if ( logcrash )
+ {
+ ///hidden stream logging for crash reports, verbosity ignores command line params
+ wxLog *loggercrash = new wxLogStream( &crashreport().crashlog );
+ wxLogChain *logCrashChain = new wxLogChain( loggercrash );
+ lastlog = logCrashChain;
+ }
+
+ #if wxUSE_DEBUGREPORT && defined(ENABLE_DEBUG_REPORT)
+ ///hidden stream logging for crash reports
+ wxLog *loggercrash = new wxLogStream( &crashreport().crashlog );
+ wxLogChain *logCrashChain = new wxLogChain( loggercrash );
+ logCrashChain->SetLogLevel( wxLOG_Trace );
+ logCrashChain->SetVerbose( true );
+ #endif
+
+ #endif
+
+
+ if ( !( console || showgui ) || verbosity == 0 ){
+ new wxLogNull;
+ return loggerwin;
+ }
+
+ if ( logChain )
+ {
+ switch (verbosity)
+ {
+ case 1:
+ logChain->SetLogLevel( wxLOG_FatalError ); break;
+ case 2:
+ logChain->SetLogLevel( wxLOG_Error ); break;
+ case 3:
+ logChain->SetLogLevel( wxLOG_Warning ); break;
+ case 4:
+ logChain->SetLogLevel( wxLOG_Message ); break;
+ case 5:
+ logChain->SetLogLevel( wxLOG_Trace );
+ logChain->SetVerbose( true ); break;
+ default://meaning loglevel < 0 or > 5 , == 0 is handled seperately
+ logChain->SetLogLevel( wxLOG_Warning ); break;
+ }
+ }
+
+ return loggerwin;
+}
+
+
+
+wxString GetSpringLobbyVersion()
+{
+#ifndef AUX_VERSION
+ return (TowxString(VERSION)).BeforeFirst( _T(' ') );
+#else
+ return (TowxString(VERSION)).BeforeFirst( _T(' ') ) + TowxString(AUX_VERSION);
+#endif
+
+}
+
+wxString GetExecutableFolder()
+{
+ return wxStandardPathsBase::Get().GetExecutablePath().BeforeLast( wxFileName::GetPathSeparator() );
+}
+
+
+// ------------------------------------------------------------------------------------------------------------------------
+///
+/// Read out Host's CPU Speed
+///
+/// \return Sum of each CPU's Speed of this Computer
+///
+///
+// ------------------------------------------------------------------------------------------------------------------------
+wxString GetHostCPUSpeed()
+{
+
+ int cpu_count = 0;
+ int max_cpu_speed=0;
+
+#ifdef __WXMSW__
+
+ //afaik there is no way to determine the number of sub keys for a given key
+ //so i'll hardcode some value here and hope bd doesn't hit me with a stick :P
+ for (int i = 0; i< 16; ++i)
+ {
+ wxRegKey programreg( _T("HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\")+ wxString::Format(_T("%d"), i));
+ long tmp;
+ if ( programreg.QueryValue( _T("~MHz"), &tmp ) )
+ {
+ if ( max_cpu_speed < tmp ) max_cpu_speed = tmp;
+ cpu_count++;
+ }
+
+ }
+
+#else
+
+ wxTextFile file( _T("/proc/cpuinfo") );
+ if ( file.Exists() )
+ {
+ file.Open();
+ for ( wxString line = file.GetFirstLine(); !file.Eof(); line = file.GetNextLine() )
+ {
+ if ( line.Left(7) == _T("cpu MHz") )
+ {
+ line = line.AfterLast( _T(' ') ).BeforeLast( _T('.') );
+ cpu_count++;
+ int tmp = s2l( line );
+ if ( max_cpu_speed < tmp ) max_cpu_speed = tmp;
+ }
+ }
+ }
+#endif
+ return TowxString( clamp( max_cpu_speed,0,max_cpu_speed ) );
+}
+
+
+// copied from http://wxforum.shadonet.com/viewtopic.php?t=2080
+//slightly modified
+bool CopyDir( wxString from, wxString to, bool overwrite )
+{
+ wxString sep = wxFileName::GetPathSeparator();
+
+ // append a slash if there is not one (for easier parsing)
+ // because who knows what people will pass to the function.
+ if ( !to.EndsWith( sep ) ) {
+ to += sep;
+ }
+ // for both dirs
+ if ( !from.EndsWith( sep ) ) {
+ from += sep;
+ }
+
+ // first make sure that the source dir exists
+ if(!wxDir::Exists(from)) {
+ wxLogError(from + _T(" does not exist. Can not copy directory.") );
+ return false;
+ }
+
+ if (!wxDirExists(to))
+ wxMkdir(to);
+
+ wxDir dir(from);
+ wxString filename;
+ bool bla = dir.GetFirst(&filename);
+
+ if (bla){
+ do {
+
+ if (wxDirExists(from + filename) )
+ {
+ wxMkdir(to + filename);
+ CopyDir(from + filename, to + filename, overwrite);
+ }
+ else{
+ wxCopyFile(from + filename, to + filename, overwrite);
+ }
+ }
+ while (dir.GetNext(&filename) );
+ }
+ return true;
+}
+
+bool IsUACenabled()
+{
+#ifdef __WXMSW__
+ wxRegKey UACpath( _T("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System") ); // check if UAC is on, skip dialog if not
+ if( UACpath.Exists() )
+ {
+ long value;
+ if( UACpath.QueryValue( _T("EnableLUA"), &value ) ) // reg key not present -> not vista
+ {
+ if( value != 0 )
+ {
+ return true;
+ }
+ }
+ }
+#endif
+ return false;
+}
+
+#ifdef __WXMSW__
+#include <windows.h>
+#include <wx/msw/winundef.h>
+#include <shellapi.h>
+
+int WinExecuteAdmin( const wxString& command, const wxString& params )
+{
+ SHELLEXECUTEINFO shExecInfo;
+
+ shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
+
+ shExecInfo.fMask = NULL;
+ shExecInfo.hwnd = NULL;
+ shExecInfo.lpVerb = _T("runas");
+#ifdef _MSC_VER //some strange compiler stupidity going on here
+ shExecInfo.lpFile = command.c_str();
+ shExecInfo.lpParameters = params.c_str();
+#else
+ shExecInfo.lpFile = command.wc_str();
+ shExecInfo.lpParameters = params.wc_str();
+#endif
+ shExecInfo.lpDirectory = NULL;
+ shExecInfo.nShow = SW_MAXIMIZE;
+ shExecInfo.hInstApp = NULL;
+
+ ShellExecuteEx(&shExecInfo);
+
+ return 0;
+}
+#endif
diff --git a/src/utils/platform.h b/src/utils/platform.h
new file mode 100644
index 0000000..48a37c1
--- /dev/null
+++ b/src/utils/platform.h
@@ -0,0 +1,50 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_PLATFORM_H
+#define SPRINGLOBBY_HEADERGUARD_PLATFORM_H
+
+class wxLogWindow;
+class wxFrame;
+class wxString;
+class wxLogChain;
+
+/**
+ let origin be /path/to/some/dir and destination /some/other/path
+ this will copy dir (and everything below that recursively to /some/other/path/dir
+ \return true if successful
+*/
+bool CopyDir( wxString origin, wxString destination, bool overwrite = true);
+
+/** \brief execute command with admin temp eleveation **/
+int WinExecuteAdmin( const wxString& command, const wxString& params );
+
+//! returns false on !win, checks for regkey on win
+bool IsUACenabled();
+
+/** \brief initialize logchain
+
+ \return Logwindow pointer (may be 0), useful if parent frame should be created _after_ logging is set up
+**/
+wxLogWindow* InitializeLoggingTargets( wxFrame* parent, bool console, bool showgui, bool logcrash, int verbosity, wxLogChain* logChain );
+
+wxString GetSpringLobbyVersion();
+wxString GetExecutableFolder();
+wxString GetLibExtension();
+wxString GetHostCPUSpeed();
+
+#endif // SPRINGLOBBY_HEADERGUARD_PLATFORM_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/utils/sltipwin.cpp b/src/utils/sltipwin.cpp
new file mode 100644
index 0000000..cf68465
--- /dev/null
+++ b/src/utils/sltipwin.cpp
@@ -0,0 +1,19 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+#include "sltipwin.h"
+
+#if wxUSE_TIPWINDOW
+
+BEGIN_EVENT_TABLE(SLTipWindow, wxTipWindow)
+ EVT_MOUSEWHEEL(SLTipWindow::Cancel)
+END_EVENT_TABLE()
+
+SLTipWindow::SLTipWindow(wxWindow *parent, const wxString &text)
+ : wxTipWindow(parent,text)
+{}
+
+void SLTipWindow::Cancel(wxMouseEvent& /*unused*/)
+{
+ wxTipWindow::Close();
+}
+
+#endif
diff --git a/src/utils/sltipwin.h b/src/utils/sltipwin.h
new file mode 100644
index 0000000..b159c60
--- /dev/null
+++ b/src/utils/sltipwin.h
@@ -0,0 +1,36 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_UTIL_TIPWIN_H
+#define SPRINGLOBBY_HEADERGUARD_UTIL_TIPWIN_H
+
+#include <wx/platform.h>
+#if wxUSE_TIPWINDOW
+#include <wx/tipwin.h>
+
+class SLTipWindow : public wxTipWindow{
+ public:
+ SLTipWindow(wxWindow *parent, const wxString &text);
+
+ void Cancel(wxMouseEvent& event);
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
+
+#endif // SPRINGLOBBY_HEADERGUARD_UTIL_TIPWIN_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/utils/tasutil.cpp b/src/utils/tasutil.cpp
new file mode 100644
index 0000000..a2251df
--- /dev/null
+++ b/src/utils/tasutil.cpp
@@ -0,0 +1,62 @@
+/* Copyright (C) 2007-2009 The SpringLobby Team. All rights reserved. */
+#include "tasutil.h"
+#include "conversion.h"
+
+#include <wx/regex.h>
+
+wxString GetWordParam( wxString& params )
+{
+ return GetParamByChar( params, _T(' ') );
+}
+
+
+wxString GetSentenceParam( wxString& params )
+{
+ return GetParamByChar( params, _T('\t') );
+}
+
+
+long GetIntParam( wxString& params )
+{
+ return s2l( GetParamByChar( params, _T(' ') ) );
+}
+
+wxString GetParamByChar( wxString& params, const wxChar& sep )
+{
+ int pos = params.Find( sep );
+ wxString ret;
+ if ( pos != -1 )
+ {
+ ret = params.Left( pos );
+ params = params.Mid( pos + 1 );
+ }
+ else
+ {
+ ret = params;
+ params = _T("");
+ }
+ return ret;
+}
+
+
+bool GetBoolParam( wxString& params )
+{
+ return (bool)GetIntParam( params );
+}
+
+bool IsValidNickname( const wxString& _name )
+{
+ wxString name = _name;
+ // The Regex Container
+ //wxRegEx regex( wxT("[:graph:]") );
+ wxRegEx regex( wxT("[ \t\r\n\v\föäüÃ, .:<>\\!§$%&+-]" ));
+
+ // We need to escape all regular Expression Characters, that have a special Meaning
+ name.Replace( _T("["), _T("") );
+ name.Replace( _T("]"), _T("") );
+
+ if ( name.IsEmpty() ) return false;
+
+ return !regex.Matches( name );
+}
+
diff --git a/src/utils/tasutil.h b/src/utils/tasutil.h
new file mode 100644
index 0000000..90964ee
--- /dev/null
+++ b/src/utils/tasutil.h
@@ -0,0 +1,35 @@
+#ifndef SPRINGLOBBY_HEADERGUARD_SERVERUTIL_H
+#define SPRINGLOBBY_HEADERGUARD_SERVERUTIL_H
+
+#include <wx/string.h>
+#include <wx/wxchar.h>
+class wxString;
+
+wxString GetWordParam( wxString& params );
+wxString GetSentenceParam( wxString& params );
+long GetIntParam( wxString& params );
+bool GetBoolParam( wxString& params );
+wxString GetParamByChar( wxString& params, const wxChar& sep );
+
+//! matches against regex for printable ascii chars, excluding space
+bool IsValidNickname( const wxString& name );
+
+
+#endif // SPRINGLOBBY_HEADERGUARD_SERVERUTIL_H
+
+/**
+ This file is part of SpringLobby,
+ Copyright (C) 2007-09
+
+ SpringLobby is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as published by
+ the Free Software Foundation.
+
+ SpringLobby is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with SpringLobby. If not, see <http://www.gnu.org/licenses/>.
+**/
diff --git a/src/widgets/downloaddialog.cpp b/src/widgets/downloaddialog.cpp
new file mode 100644
index 0000000..1b234fb
--- /dev/null
+++ b/src/widgets/downloaddialog.cpp
@@ -0,0 +1,38 @@
+#include "downloaddialog.h"
+
+#include <wx/sizer.h>
+
+#include "downloadpanel.h"
+#include "../settings.h"
+
+WidgetDownloadDialog::WidgetDownloadDialog(wxWindow* parent, wxWindowID id,
+ const wxString& title, long style )
+ : wxDialog ( parent, id, title, wxDefaultPosition, wxDefaultSize, style, _T("WIDGETDIALOG") )
+{
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+
+ m_widgets_panel = new WidgetDownloadPanel( this, -1, _("widgets") );
+ m_main_sizer->Add( m_widgets_panel, 1, wxALL | wxEXPAND, 5 );
+
+ SetSizer( m_main_sizer );
+
+ wxString name = GetName();
+ wxPoint pos = sett().GetWindowPos( name, wxDefaultPosition );
+ wxSize size = sett().GetWindowSize( name, wxSize( 670, 400 ) );
+ SetSize( pos.x , pos.y, size.GetWidth(), size.GetHeight() );
+ Layout();
+}
+
+WidgetDownloadDialog::~WidgetDownloadDialog()
+{
+
+}
+
+bool WidgetDownloadDialog::Show( bool show )
+{
+ if ( !show ) {
+ sett().SetWindowSize( GetName(), GetSize() );
+ sett().SetWindowPos( GetName(), GetPosition() );
+ }
+ return wxDialog::Show( show );
+}
diff --git a/src/widgets/downloaddialog.h b/src/widgets/downloaddialog.h
new file mode 100644
index 0000000..9e7374e
--- /dev/null
+++ b/src/widgets/downloaddialog.h
@@ -0,0 +1,23 @@
+#ifndef SPRINGLOBBY_WIDGETDOWNLOADDIALOG_H_INCLUDED
+#define SPRINGLOBBY_WIDGETDOWNLOADDIALOG_H_INCLUDED
+
+#include <wx/dialog.h>
+
+class wxBoxSizer;
+class WidgetDownloadPanel;
+
+class WidgetDownloadDialog : public wxDialog
+{
+ public:
+ WidgetDownloadDialog(wxWindow* parent, wxWindowID id, const wxString& title,
+ long style = wxCAPTION | wxRESIZE_BORDER | wxCLOSE_BOX | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxDEFAULT_DIALOG_STYLE );
+ virtual ~WidgetDownloadDialog();
+
+ bool Show( bool show = true );
+
+ protected:
+ wxBoxSizer* m_main_sizer;
+ WidgetDownloadPanel* m_widgets_panel;
+};
+
+#endif // SPRINGLOBBY_WIDGETDOWNLOADDIALOG_H_INCLUDED
diff --git a/src/widgets/downloadlistctrl.cpp b/src/widgets/downloadlistctrl.cpp
new file mode 100644
index 0000000..7c603ad
--- /dev/null
+++ b/src/widgets/downloadlistctrl.cpp
@@ -0,0 +1,153 @@
+#include "downloadlistctrl.h"
+
+#include "../utils/conversion.h"
+
+template<> SortOrder WidgetDownloadListctrl::BaseType::m_sortorder = SortOrder();
+
+const unsigned int column_count = 4;
+
+BEGIN_EVENT_TABLE( WidgetDownloadListctrl, WidgetDownloadListctrl::BaseType )
+ EVT_LIST_ITEM_ACTIVATED( WIDGETLISTCTRL_ID, WidgetDownloadListctrl::OnActivateItem )
+ EVT_LIST_COL_CLICK( WIDGETLISTCTRL_ID, WidgetDownloadListctrl::OnColClick )
+END_EVENT_TABLE()
+
+WidgetDownloadListctrl::WidgetDownloadListctrl(wxWindow* parent, wxWindowID /*unused*/, const wxString& /*unused*/,
+ long /*unused*/, const wxPoint&/*unused*/, const wxSize& /*unused*/)
+ : WidgetDownloadListctrl::BaseType(parent, WIDGETLISTCTRL_ID, wxDefaultPosition, wxDefaultSize,
+ wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_ALIGN_LEFT, _T("WidgetDownloadListCtrl"), column_count, 3, &CompareOneCrit)
+{
+ const int as = wxLIST_AUTOSIZE;
+#if defined(__WXMSW__)
+ const int widths [column_count] = { as, as, as, as };
+#elif defined(__WXMAC__)
+ const int widths [column_count] = { as, as, as, as };
+#else
+ const int widths [column_count] = { as, as, as, as };
+#endif
+
+ AddColumn( 0, widths[0], _("Name"), _T("Name") );
+ AddColumn( 1, widths[1], _T("Author"), _T("Author") );
+ AddColumn( 2, widths[2], _T("Mods"), _T("Compatible mods") );
+ AddColumn( 3, widths[3], _T("Downloads"), _T("Downloads") );
+
+ if ( m_sortorder.size() == 0 ) {
+ m_sortorder[2].col = 2;
+ m_sortorder[2].direction = 1;
+ m_sortorder[0].col = 0;
+ m_sortorder[0].direction = 1;
+ m_sortorder[1].col = 1;
+ m_sortorder[1].direction = 1;
+ }
+}
+
+WidgetDownloadListctrl::~WidgetDownloadListctrl()
+{
+ //dtor
+}
+
+int WidgetDownloadListctrl::CompareOneCrit( DataType u1, DataType u2, int col, int dir )
+{
+ switch ( col ) {
+ case 0: return dir * u1.name.CmpNoCase( u2.name );
+// case 1: return dir * u1.short_description.CmpNoCase( u2.short_description );
+ case 1: return dir * u1.author.CmpNoCase( u2.author );
+ case 2: return dir * u1.mods.CmpNoCase( u2.mods );
+ case 3: return dir * compareSimple( u1.num_downloads, u2.num_downloads );
+// case 5: return dir * u1.date.CmpNoCase( u2.date );
+ default: return 0;
+ }
+}
+
+void WidgetDownloadListctrl::AddWidget( const Widget widget )
+{
+ if ( AddItem( widget ) )
+ return;
+
+ wxLogWarning( _T("Widget already in list.") );
+}
+
+wxString WidgetDownloadListctrl::GetItemText(long item, long column) const
+{
+ if ( item > m_data.size() || item < 0 )
+ return wxEmptyString;
+
+ const Widget& widget = m_data[item];
+ switch ( column ) {
+ default: return wxEmptyString;
+ case 0: return widget.name;
+// case 1: return widget.short_description;
+ case 1: return widget.author;
+ case 2: return widget.mods;
+ case 3: return TowxString( widget.num_downloads );
+// case 5: return widget.date;
+ }
+
+}
+
+int WidgetDownloadListctrl::GetItemImage(long /*unused*/) const
+{
+ return -1;
+}
+
+int WidgetDownloadListctrl::GetItemColumnImage(long /*unused*/, long /*unused*/) const
+{
+ return -1;
+}
+
+void WidgetDownloadListctrl::HighlightItem( long /*unused*/ )
+{
+
+}
+
+void WidgetDownloadListctrl::Sort()
+{
+ if ( m_data.size() > 0 )
+ {
+ SaveSelection();
+ SLInsertionSort( m_data, m_comparator );
+ RestoreSelection();
+ }
+}
+
+int WidgetDownloadListctrl::GetIndexFromData( const DataType& data ) const
+{
+ static long seekpos;
+ seekpos = clamp( seekpos, 0l , (long)m_data.size() );
+ int index = seekpos;
+
+ for ( DataCIter f_idx = m_data.begin() + seekpos; f_idx != m_data.end() ; ++f_idx )
+ {
+ if ( data.Equals( *f_idx ) )
+ {
+ seekpos = index;
+ return seekpos;
+ }
+ index++;
+ }
+ //it's ok to init with seekpos, if it had changed this would not be reached
+ int r_index = seekpos - 1;
+ for ( DataRevCIter r_idx = m_data.rbegin() + ( m_data.size() - seekpos ); r_idx != m_data.rend() ; ++r_idx )
+ {
+ if ( data.Equals( *r_idx ) )
+ {
+ seekpos = r_index;
+ return seekpos;
+ }
+ r_index--;
+ }
+
+ return -1;
+}
+
+Widget& WidgetDownloadListctrl::GetSelectedWidget()
+{
+ return m_data[m_selected_index];
+}
+
+void WidgetDownloadListctrl::OnActivateItem( wxListEvent& event )
+{
+ int index = event.GetIndex();
+ if ( index == -1 ) return;
+// WidgetInfoDialog* dl = new WidgetInfoDialog( m_data[index], (wxWindow*)this, -1, _("stuff") );
+// dl->Show(true);
+}
diff --git a/src/widgets/downloadlistctrl.h b/src/widgets/downloadlistctrl.h
new file mode 100644
index 0000000..40ce820
--- /dev/null
+++ b/src/widgets/downloadlistctrl.h
@@ -0,0 +1,44 @@
+#ifndef WIDGETDOWNLOADLISTCTRL_H
+#define WIDGETDOWNLOADLISTCTRL_H
+
+#include "../customvirtlistctrl.h"
+#include "widget.h"
+
+
+class WidgetDownloadListctrl : public CustomVirtListCtrl<Widget,WidgetDownloadListctrl >
+{
+ public:
+ WidgetDownloadListctrl(wxWindow* parent, wxWindowID id, const wxString& name = _T("WidgetDownloadListCtrl"),
+ long style = wxSUNKEN_BORDER | wxLC_REPORT | wxLC_ALIGN_LEFT, const wxPoint& pt = wxDefaultPosition,
+ const wxSize& sz = wxDefaultSize);
+ virtual ~WidgetDownloadListctrl();
+
+ void AddWidget( const Widget widget );
+ Widget& GetSelectedWidget();
+
+ //these are overloaded to use list in virtual style
+ wxString GetItemText(long item, long column) const;
+ int GetItemImage(long item) const;
+ int GetItemColumnImage(long item, long column) const;
+ wxListItemAttr* GetItemAttr(long /*unused*/) const {return 0;}
+
+ void Sort();
+
+ protected:
+ static int CompareOneCrit( DataType u1, DataType u2, int col, int dir ) ;
+
+ void HighlightItem( long item );
+ void OnActivateItem( wxListEvent& event );
+
+ int GetIndexFromData( const DataType& data ) const;
+
+ public:
+ enum {
+ WIDGETLISTCTRL_ID
+ };
+
+ protected:
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // WIDGETDOWNLOADLISTCTRL_H
diff --git a/src/widgets/downloadpanel.cpp b/src/widgets/downloadpanel.cpp
new file mode 100644
index 0000000..79a3b4e
--- /dev/null
+++ b/src/widgets/downloadpanel.cpp
@@ -0,0 +1,163 @@
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include "downloadpanel.h"
+
+#include <wx/protocol/http.h>
+#include <wx/xml/xml.h>
+#include <wx/sizer.h>
+#include <wx/splitter.h>
+
+#include "../utils/conversion.h"
+#include "downloadlistctrl.h"
+#include "infopanel.h"
+
+const int invalid_id = -1;
+const unsigned int max_short_desc_length = 50;
+
+
+BEGIN_EVENT_TABLE( WidgetDownloadPanel , wxScrolledWindow)
+
+ EVT_SPLITTER_SASH_POS_CHANGED( wxID_ANY, WidgetDownloadPanel::OnSashChanged )
+ EVT_LIST_ITEM_SELECTED ( WidgetDownloadListctrl::WIDGETLISTCTRL_ID, WidgetDownloadPanel::OnSelect )
+
+END_EVENT_TABLE()
+
+WidgetDownloadPanel::WidgetDownloadPanel(wxWindow* parent, wxWindowID id, const wxString& /*unused*/,
+ const wxPoint& pos , const wxSize& size , long style )
+ : wxScrolledWindow (parent, id, pos, size, style, _T("widget-dl") )
+{
+ m_splitter = new wxSplitterWindow( this, -1, wxDefaultPosition, wxDefaultSize );
+
+ m_main_sizer = new wxBoxSizer ( wxHORIZONTAL );
+ m_list = new WidgetDownloadListctrl( m_splitter, WidgetDownloadListctrl::WIDGETLISTCTRL_ID );
+ PopulateList();
+ m_list->ResetColumnSizes();
+
+ Widget dummy;
+ m_info_panel = new WidgetInfoPanel( dummy, m_splitter, ID_PANEL );
+ m_info_panel->Create();
+
+ m_splitter->SplitVertically( m_list, m_info_panel );
+ m_main_sizer->Add( m_splitter, 1, wxEXPAND|wxALL, 4 );
+
+ m_splitter->SetMinimumPaneSize( 400 );
+ m_splitter->SetSashPosition( sett().GetSashPosition( GetName() ) );
+
+ SetSizer( m_main_sizer );
+ Layout();
+ m_list->SortList( true );
+}
+
+WidgetDownloadPanel::~WidgetDownloadPanel()
+{
+ sett().SetSashPosition( GetName(), m_splitter->GetSashPosition( ) );
+}
+
+void WidgetDownloadPanel::OnSashChanged( wxSplitterEvent& evt )
+{
+ sett().SetSashPosition( GetName(), evt.GetSashPosition( ) );
+ evt.Skip();
+}
+
+void WidgetDownloadPanel::OnSelect( wxListEvent& event )
+{
+ m_list->OnSelected( event );
+
+ m_splitter->Unsplit();
+ m_info_panel = new WidgetInfoPanel( m_list->GetSelectedWidget(), m_splitter, ID_PANEL );
+ m_splitter->SplitVertically( m_list, m_info_panel );
+ m_splitter->SetSashPosition( sett().GetSashPosition( GetName() ) );
+
+ m_info_panel->Create();
+ Layout();
+}
+
+bool WidgetDownloadPanel::PopulateList()
+{
+ bool success = true;
+ wxHTTP http;
+
+ http.SetTimeout(6);
+ http.Connect(_T("spring.vsync.de"));
+ // PHP file sending XML content
+ wxInputStream *httpStream = http.GetInputStream(_T("/luaManager/lua_manager.php?m=0"));
+
+ if (http.GetError() == wxPROTO_NOERR)
+ {
+ wxXmlDocument xml(*httpStream);
+
+ wxXmlNode *node = xml.GetRoot()->GetChildren();
+ while (node)
+ {
+ int id = FromwxString<long>( node->GetPropVal( _T("ID"), TowxString( invalid_id ) ) );
+ if ( id != invalid_id ) {
+ Widget w;
+ w.w_id = id;
+
+ wxXmlNode* item = node->GetChildren();
+ while( item ) {
+ wxString name = item->GetName();
+ if ( name == _T("ImageCount") ) {
+ w.num_images = s2l( item->GetNodeContent() );
+ }
+ else if ( name == _T("DownloadCount") ) {
+ w.num_downloads = s2l( item->GetNodeContent() );
+ }
+ else if ( name == _T("Version") ) {
+ wxString rev = item->GetNodeContent();
+ w.rev_major = s2l( rev.BeforeFirst( '.' ) );
+ w.rev_minor = s2l( rev.AfterFirst( '.' ) );
+ w.rev = rev;
+ }
+ else if ( name == _T("NameId") ) {
+ w.n_id = s2l( item->GetNodeContent() );
+ }
+ else if ( name == _T("Changelog") ) {
+ w.changelog = item->GetNodeContent();
+ }
+ else if ( name == _T("Mods") ) {
+ w.mods = item->GetNodeContent();
+ }
+ else if ( name == _T("Description") ) {
+ wxString desc = item->GetNodeContent();
+ w.description = desc;
+ desc.Replace( _T("\r\n"), _T(" "), true );
+ desc.Replace( _T("\n"), _T(" "), true );
+ desc.Replace( _T("\r"), _T(" "), true );
+ if ( desc.Len() > max_short_desc_length ) {
+ desc = desc.Left( max_short_desc_length -1 ) + _T("...");
+ }
+ w.short_description = desc;
+ }
+ else if ( name == _T("Author") ) {
+ w.author = item->GetNodeContent();
+ }
+ else if ( name == _T("Entry") ) {
+ w.date = item->GetNodeContent();
+ }
+ else if ( name == _T("Name") ) {
+ w.name = item->GetNodeContent();
+ }
+
+ item = item->GetNext();
+ }
+
+ m_list->AddWidget( w );
+ }
+
+ node = node->GetNext();
+ }
+ }
+ else
+ success = false;
+
+ http.Close();
+ wxDELETE(httpStream);
+
+ return success;
+}
diff --git a/src/widgets/downloadpanel.h b/src/widgets/downloadpanel.h
new file mode 100644
index 0000000..9e091e4
--- /dev/null
+++ b/src/widgets/downloadpanel.h
@@ -0,0 +1,45 @@
+#ifndef SPRINGLOBBY_WIDGETDOWNLOADPANEL_H_INCLUDED
+#define SPRINGLOBBY_WIDGETDOWNLOADPANEL_H_INCLUDED
+
+#include <wx/scrolwin.h>
+
+class WidgetDownloadListctrl;
+class WidgetInfoPanel;
+class wxBoxSizer;
+class wxButton;
+class wxTextCtrl;
+class wxStaticText;
+class wxListEvent;
+class wxSplitterWindow;
+class wxSplitterEvent;
+
+class WidgetDownloadPanel : public wxScrolledWindow
+{
+ public:
+ WidgetDownloadPanel(wxWindow* parent, wxWindowID id, const wxString& title = _T(""), const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = wxHSCROLL | wxVSCROLL );
+ virtual ~WidgetDownloadPanel();
+
+ protected:
+ bool PopulateList();
+ void OnSelect( wxListEvent& event );
+
+ WidgetDownloadListctrl* m_list;
+ WidgetInfoPanel* m_info_panel;
+
+ wxSplitterWindow* m_splitter;
+ wxBoxSizer* m_main_sizer;
+
+ void OnSashChanged( wxSplitterEvent& evt );
+
+ enum {
+ ID_LIST,
+ ID_PANEL
+ };
+
+ protected:
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // SPRINGLOBBY_WIDGETDOWNLOADPANEL_H_INCLUDED
diff --git a/src/widgets/infopanel.cpp b/src/widgets/infopanel.cpp
new file mode 100644
index 0000000..5d2b7ce
--- /dev/null
+++ b/src/widgets/infopanel.cpp
@@ -0,0 +1,182 @@
+#include "infopanel.h"
+
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/statline.h>
+#include <wx/stattext.h>
+#include <wx/statbox.h>
+#include <wx/file.h>
+#include <wx/tokenzr.h>
+#include <wx/icon.h>
+#include <wx/textctrl.h>
+#include <wx/statline.h>
+#include <wx/wupdlock.h>
+
+#include "widget.h"
+#include "../aui/artprovider.h"
+#include "../aui/slbook.h"
+#include "../utils/conversion.h"
+#include "../settings++/custom_dialogs.h"
+#include "../Helper/imageviewer.h"
+#include "../Helper/slhtmlwindow.h"
+
+BEGIN_EVENT_TABLE( WidgetInfoPanel, wxPanel)
+ EVT_BUTTON( WidgetInfoPanel::BUT_DOWNLOAD, WidgetInfoPanel::OnDownload )
+ EVT_BUTTON( WidgetInfoPanel::BUT_REMOVE, WidgetInfoPanel::OnRemove )
+ EVT_BUTTON( WidgetInfoPanel::BUT_UPDATE, WidgetInfoPanel::OnUpdate )
+END_EVENT_TABLE()
+
+WidgetInfoPanel::WidgetInfoPanel( Widget& widget, wxWindow* parent, wxWindowID id, const wxString& /*unused*/,
+ const wxPoint& pos , const wxSize& size , long style )
+ : wxScrolledWindow (parent, id, pos, size, style),
+ m_widget( widget )
+{
+ m_busy_notice = new wxBoxSizer( wxVERTICAL );
+ wxStaticText* m_busy_notice_lbl = new wxStaticText( this, -1, _("getting infos") );
+ m_busy_notice->Add( m_busy_notice_lbl, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL );
+ SetSizer( m_busy_notice );
+
+}
+
+void WidgetInfoPanel::Create()
+{
+ wxWindowUpdateLocker locked( this );
+
+ if ( !m_widget.extendedinfo.parsed ) {
+ m_widget.GetFileInfos();
+ m_widget.GetImageInfos();
+ m_widget.DownloadImages();
+ }
+ m_widget.extendedinfo.parsed = true;
+ m_busy_notice->DeleteWindows();
+ m_busy_notice->Show( false );
+// m_busy_notice->Destroy();
+ m_main_sizer = new wxBoxSizer( wxVERTICAL );
+ m_left_sizer = new wxBoxSizer( wxVERTICAL );
+ m_left_button_sizer = new wxBoxSizer( wxHORIZONTAL );
+
+ m_grid_sizer = new wxGridSizer( 2, 5, 5 );
+ wxStaticText* name_lbl = new wxStaticText( this, -1, _("Name") );
+ m_grid_sizer->Add( name_lbl );
+ wxStaticText* name = new wxStaticText( this, -1, m_widget.name );
+ m_grid_sizer->Add( name );
+
+ wxStaticText* author_lbl = new wxStaticText( this, -1, _("Author") );
+ m_grid_sizer->Add( author_lbl );
+ wxStaticText* author = new wxStaticText( this, -1, m_widget.author );
+ m_grid_sizer->Add( author );
+
+ wxStaticText* mods_lbl = new wxStaticText( this, -1, _("Suitable mods") );
+ m_grid_sizer->Add( mods_lbl );
+ wxStaticText* mods = new wxStaticText( this, -1, m_widget.mods );
+ m_grid_sizer->Add( mods );
+
+ wxStaticText* rev_lbl = new wxStaticText( this, -1, _("Current version") );
+ m_grid_sizer->Add( rev_lbl );
+ wxStaticText* rev = new wxStaticText( this, -1, m_widget.rev );
+ m_grid_sizer->Add( rev );
+
+ wxStaticText* dl_lbl = new wxStaticText( this, -1, _("# downloaded") );
+ m_grid_sizer->Add( dl_lbl );
+ wxStaticText* dl = new wxStaticText( this, -1, TowxString( m_widget.num_downloads ) );
+ m_grid_sizer->Add( dl );
+
+ wxStaticText* publ_lbl = new wxStaticText( this, -1, _("Published on") );
+ m_grid_sizer->Add( publ_lbl );
+ wxStaticText* publ = new wxStaticText( this, -1, m_widget.date );
+ m_grid_sizer->Add( publ );
+
+ m_left_sizer->Add( m_grid_sizer, 0, wxEXPAND | wxALL, 5 );
+
+ m_download = new wxButton( this, BUT_DOWNLOAD, _("Download") );
+// m_update = new wxButton( this, BUT_UPDATE, _("Update") );
+ m_remove = new wxButton( this, BUT_REMOVE, _("Remove") );
+
+ const int flag = wxALL;
+ const int spc = 5;
+ m_left_button_sizer->Add( m_download, 0, flag, spc );
+// m_button_sizer->Add( m_update, 0, flag, spc );
+ m_left_button_sizer->Add( m_remove, 0, flag, spc );
+ m_left_sizer->Add( m_left_button_sizer, 0, wxALL, 0 );
+
+
+ m_right_sizer = new wxBoxSizer ( wxVERTICAL );
+
+ m_desc = new slHtmlWindow( this, CTL_DESC, wxDefaultPosition,
+ wxDefaultSize, wxHW_NO_SELECTION|wxHW_SCROLLBAR_AUTO );
+ wxString ct = _T("<html><body>") + m_widget.description + _T("</body></html>") ;//content
+ m_desc->SetPage( ct );
+
+
+ m_changelog = new wxTextCtrl( this, -1, _T( "" ), wxDefaultPosition,
+ wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY );
+
+ wxStringTokenizer tk( m_widget.changelog, _T("\r\n") );
+ while ( tk.HasMoreTokens() )
+ m_changelog->AppendText( tk.GetNextToken() );
+
+ m_ext_info = new SLNotebook( this, -1, wxDefaultPosition, wxDefaultSize, wxAUI_NB_LEFT );
+ m_ext_info->SetArtProvider(new SLArtProvider);
+ m_ext_info->AddPage( m_desc, _("Description") , true );
+ m_ext_info->AddPage( m_changelog, _("Changelog") , false );
+
+
+ if ( m_widget.GetImageFilenames().GetCount() > 0 ) {
+ m_imageviewer = new ImageViewerPanel( m_widget.GetImageFilenames(), false, this, -1, 0);
+ m_ext_info->AddPage( m_imageviewer, _("Screenshots") , false );
+ }
+
+ m_right_sizer->Add( m_ext_info, 1, wxEXPAND, 5 );
+
+ wxStaticBoxSizer* top_box = new wxStaticBoxSizer ( wxVERTICAL, this );
+ top_box->Add( m_left_sizer );
+ m_main_sizer->Add( top_box, 0, wxLEFT | wxEXPAND, 5 );
+ m_main_sizer->Add( new wxStaticLine( this ), 0, wxEXPAND );
+ m_main_sizer->Add( m_right_sizer, 1, wxLEFT|wxEXPAND, 5 );
+ SetButtonStates();
+
+ SetSizer( m_main_sizer );
+ Layout();
+
+}
+
+void WidgetInfoPanel::SetButtonStates()
+{
+ m_download->Enable( !m_widget.is_installed );
+// m_update->Enable( false );
+ m_remove->Enable( m_widget.is_installed );
+}
+
+WidgetInfoPanel::~WidgetInfoPanel()
+{
+ //dtor
+}
+
+void WidgetInfoPanel::OnDownload( wxCommandEvent& /*unused*/ )
+{
+ if ( m_widget.Install() ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("Widget files have been installed."), _("Success") );
+ }
+ else {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("Widget files have not been installed."), _("Error") );
+ }
+ SetButtonStates();
+}
+
+
+void WidgetInfoPanel::OnRemove( wxCommandEvent& /*unused*/ )
+{
+ if ( m_widget.Remove() ) {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("Widget files have been removed."), _("Success") );
+ }
+ else {
+ customMessageBoxNoModal( SL_MAIN_ICON, _("Widget files have not been removed."), _("Error") );
+ }
+ SetButtonStates();
+}
+
+void WidgetInfoPanel::OnUpdate( wxCommandEvent& /*unused*/ )
+{
+
+}
+
diff --git a/src/widgets/infopanel.h b/src/widgets/infopanel.h
new file mode 100644
index 0000000..f935472
--- /dev/null
+++ b/src/widgets/infopanel.h
@@ -0,0 +1,76 @@
+#ifndef SPRINGLOBBY_WIDGETINFOPANEL_H_INCLUDED
+#define SPRINGLOBBY_WIDGETINFOPANEL_H_INCLUDED
+
+#include <wx/scrolwin.h>
+
+class Widget;
+class wxGridSizer;
+class wxBoxSizer;
+class wxButton;
+class wxCommandEvent;
+class wxTextUrlEvent;
+class ServerMessageBox;
+class wxTextCtrl;
+class ImageViewerPanel;
+class wxHtmlWindow;
+class SLNotebook;
+
+class WidgetInfoPanel : public wxScrolledWindow
+{
+ public:
+ WidgetInfoPanel( Widget& widget, wxWindow* parent, wxWindowID id, const wxString& title = _T(""), const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = wxHSCROLL | wxVSCROLL );
+ virtual ~WidgetInfoPanel();
+
+ void Create();
+
+ protected:
+ Widget& m_widget;
+ wxBoxSizer* m_main_sizer;
+ wxBoxSizer* m_left_sizer;
+ wxBoxSizer* m_right_sizer;
+ wxBoxSizer* m_left_button_sizer;
+// wxBoxSizer* m_right_button_sizer;
+ wxGridSizer* m_grid_sizer;
+// wxBoxSizer* m_desc_sizer;
+// wxBoxSizer* m_screeny_sizer;
+// wxBoxSizer* m_chglog_sizer;
+ wxBoxSizer* m_variable_info_sizer;
+
+ wxBoxSizer* m_busy_notice;
+
+ wxTextCtrl* m_changelog;
+ ImageViewerPanel* m_imageviewer;
+ wxHtmlWindow* m_desc;
+
+ SLNotebook* m_ext_info;
+ wxButton* m_update;
+ wxButton* m_remove;
+ wxButton* m_download;
+
+
+ void SetButtonStates();
+
+ void OnDownload( wxCommandEvent& evt );
+ void OnPics( wxCommandEvent& evt );
+ void OnChangeLog( wxCommandEvent& evt );
+ void OnDescription( wxCommandEvent& evt );
+ void OnRemove( wxCommandEvent& evt );
+ void OnUpdate( wxCommandEvent& evt );
+
+ enum {
+ BUT_DOWNLOAD,
+ BUT_CHG_LOG,
+ BUT_UPDATE,
+ BUT_REMOVE,
+ BUT_PICS,
+ CTL_DESC,
+ BUT_DESC
+ };
+
+ protected:
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // SPRINGLOBBY_WIDGETINFOPANEL_H_INCLUDED
diff --git a/src/widgets/widget.cpp b/src/widgets/widget.cpp
new file mode 100644
index 0000000..e0e0f6f
--- /dev/null
+++ b/src/widgets/widget.cpp
@@ -0,0 +1,277 @@
+#ifdef _MSC_VER
+#ifndef NOMINMAX
+ #define NOMINMAX
+#endif // NOMINMAX
+#include <winsock2.h>
+#endif // _MSC_VER
+
+#include "widget.h"
+
+#include <wx/arrstr.h>
+#include <wx/sstream.h>
+#include <wx/wfstream.h>
+#include <wx/filename.h>
+#include <wx/protocol/http.h>
+#include <wx/xml/xml.h>
+
+//#include "../utils/.h"
+#include "../settings.h"
+#include "../springunitsync.h"
+
+const int invalid_id = -1;
+
+Widget::Widget()
+{
+ //ctor
+}
+
+Widget::~Widget()
+{
+ //dtor
+}
+
+bool Widget::IsInstalled()
+{
+ return false;
+}
+
+wxArrayString Widget::GetImageFilenames()
+{
+ wxArrayString ret;
+ ExtendedInfo::Images::const_iterator it = extendedinfo.images.begin();
+ for ( ; it != extendedinfo.images.end(); ++it ) {
+ ret.Add( it->local_path );
+ }
+ return ret;
+}
+
+bool Widget::GetImageInfos()
+{
+ bool success = true;
+ wxHTTP http;
+
+ http.SetTimeout(6);
+ http.Connect(_T("spring.vsync.de"));
+ wxString query_url = _T("/luaManager/lua_manager.php?m=4&id=") + TowxString( n_id );
+ // PHP file sending XML content
+ wxInputStream *httpStream = http.GetInputStream( query_url );
+
+ if (http.GetError() == wxPROTO_NOERR)
+ {
+ // will crash here, if xml content is not formatted PERFECTLY
+ wxXmlDocument xml(*httpStream);
+ wxXmlNode *node = xml.GetRoot()->GetChildren();
+ while (node)
+ {
+ int id = FromwxString<long>( node->GetPropVal( _T("ID"), TowxString( invalid_id ) ) );
+ if ( id != invalid_id ) {
+ WidgetImage file;
+ file.id = id;
+
+ wxXmlNode* item = node->GetChildren();
+ while( item ) {
+ wxString name = item->GetName();
+ if ( name == _T("Url") ) {
+ file.url = item->GetNodeContent();
+ }
+ item = item->GetNext();
+ }
+ extendedinfo.images.push_back( file );
+ }
+
+ node = node->GetNext();
+ }
+ }
+ else
+ success = false;
+
+ http.Close();
+ wxDELETE(httpStream);
+
+ return success;
+}
+
+bool Widget::DownloadImages()
+{
+ wxString sep ( wxFileName::GetPathSeparator() );
+
+ ExtendedInfo::Images& images = extendedinfo.images;
+ ExtendedInfo::Images::iterator it = images.begin();
+ for ( ; it != images.end(); ++it ) {
+
+ wxString fileurl = it->url;
+ fileurl.Replace( _T("http://") , _T("") );
+ wxString destpath = sett().GetCachePath() + fileurl.AfterLast(_T('/'));
+ it->local_path = destpath;
+
+ if ( wxFileExists( destpath ) ) // no need to redownload images
+ continue;
+
+
+ wxHTTP FileDownloading;
+ /// normal timeout is 10 minutes.. set to 10 secs.
+ FileDownloading.SetTimeout(10);
+ FileDownloading.Connect( fileurl.BeforeFirst(_T('/')), 80);
+
+ wxInputStream* httpstream = FileDownloading.GetInputStream( _T("/") + fileurl.AfterFirst(_T('/')) );
+
+ if ( httpstream )
+ {
+ try
+ {
+ wxFileOutputStream outs( destpath );
+ httpstream->Read(outs);
+ outs.Close();
+ delete httpstream;
+ httpstream = 0;
+ //download success
+
+ }
+ catch (...)
+ {
+ wxLogMessage(_T("exception on download of") + fileurl);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool Widget::GetFileInfos()
+{
+ bool success = true;
+ unsigned int file_present_count = 0;
+ wxString sep ( wxFileName::GetPathSeparator() );
+ wxHTTP http;
+
+ http.SetTimeout(6);
+ http.Connect(_T("spring.vsync.de"));
+ wxString query_url = _T("/luaManager/lua_manager.php?m=1&id=") + TowxString( w_id );
+ // PHP file sending XML content
+ wxInputStream *httpStream = http.GetInputStream( query_url );
+ if (http.GetError() == wxPROTO_NOERR)
+ {
+ // will crash here, if xml content is not formatted PERFECTLY
+ wxXmlDocument xml(*httpStream);
+
+ wxXmlNode *node = xml.GetRoot()->GetChildren();
+ while (node)
+ {
+ int id = FromwxString<long>( node->GetPropVal( _T("ID"), TowxString( invalid_id ) ) );
+ if ( id != invalid_id ) {
+ WidgetFile file;
+ file.id = id;
+
+ wxXmlNode* item = node->GetChildren();
+ while( item ) {
+ wxString name = item->GetName();
+ if ( name == _T("Url") ) {
+ file.url = item->GetNodeContent();
+ }
+ else if ( name == _T("MD5") ) {
+ file.md5 = item->GetNodeContent();
+ }
+ else if ( name == _T("LocalPath") ) {
+ file.local_path = item->GetNodeContent();
+ file_present_count += usync().FileExists( file.local_path );
+ }
+ item = item->GetNext();
+ }
+
+ extendedinfo.files.push_back( file );
+ }
+
+ node = node->GetNext();
+ }
+ }
+ else
+ success = false;
+
+ http.Close();
+ wxDELETE(httpStream);
+
+ if ( file_present_count == extendedinfo.files.size() )
+ is_installed = true;
+
+ return success;
+}
+
+bool Widget::Install()
+{
+ if ( !extendedinfo.parsed )
+ return false;
+
+ wxString sep ( wxFileName::GetPathSeparator() );
+ wxChar sep_c ( wxFileName::GetPathSeparator() );
+
+ ExtendedInfo::Files& files = extendedinfo.files;
+ ExtendedInfo::Files::iterator it = files.begin();
+ for ( ; it != files.end(); ++it ) {
+
+ wxString fileurl = it->url;
+ fileurl.Replace( _T("http://") , _T("") );
+ wxString destpath = sett().GetCurrentUsedDataDir() + it->local_path;
+
+ wxHTTP FileDownloading;
+ /// normal timeout is 10 minutes.. set to 10 secs.
+ FileDownloading.SetTimeout(10);
+ FileDownloading.Connect( fileurl.BeforeFirst(_T('/')), 80);
+
+ wxInputStream* httpstream = FileDownloading.GetInputStream( _T("/") + fileurl.AfterFirst(_T('/')) );
+
+ if ( httpstream )
+ {
+ try
+ {
+ if ( !wxFileName::DirExists( destpath.BeforeLast( sep_c ) ) ) {
+ wxFileName::Mkdir( destpath.BeforeLast( sep_c ), 0755, wxPATH_MKDIR_FULL );
+ }
+ wxFileOutputStream outs( destpath );
+ httpstream->Read(outs);
+ outs.Close();
+ delete httpstream;
+ httpstream = 0;
+ //download success
+
+ }
+ catch (...)
+ {
+ wxLogMessage(_T("exception on download of") + fileurl);
+ return false;
+ }
+ }
+ }
+ is_installed = true;
+ return true;
+
+}
+
+bool Widget::Remove()
+{
+ if ( !extendedinfo.parsed || !is_installed )
+ return false;
+
+ unsigned int file_remove_successes = 0;
+
+ ExtendedInfo::Files& files = extendedinfo.files;
+ ExtendedInfo::Files::const_iterator it = files.begin();
+ for ( ; it != files.end(); ++it ) {
+ wxString destpath = sett().GetCurrentUsedDataDir() + it->local_path;
+ file_remove_successes += wxRemoveFile( destpath );
+ }
+
+ if ( file_remove_successes == files.size() ) {
+ is_installed = false;
+ return true;
+ }
+ if ( file_remove_successes < files.size() && file_remove_successes > 0 ) {
+ is_installed = false;
+ return false;
+ }
+ return false;
+}
+
+bool Widget::Equals( const Widget& other ) const
+{
+ return w_id == other.w_id && ( rev.CmpNoCase( other.rev ) == 0 );
+}
diff --git a/src/widgets/widget.h b/src/widgets/widget.h
new file mode 100644
index 0000000..79e8b65
--- /dev/null
+++ b/src/widgets/widget.h
@@ -0,0 +1,69 @@
+#ifndef SPRINGLOBBY_WIDGET_H_INCLUDED
+#define SPRINGLOBBY_WIDGET_H_INCLUDED
+
+#include <wx/string.h>
+#include <vector>
+
+class wxArrayString;
+
+struct WidgetFile
+{
+ wxString url;
+ wxString local_path;
+ wxString md5;
+ long id;
+};
+
+struct WidgetImage
+{
+ wxString url;
+ wxString local_path;
+ long id;
+};
+
+struct ExtendedInfo
+{
+ ExtendedInfo():parsed(false) {}
+ bool parsed;
+
+ typedef std::vector< WidgetFile > Files;
+ Files files;
+
+ typedef std::vector< WidgetImage > Images;
+ Images images;
+};
+
+struct Widget
+{
+ public:
+ Widget();
+ virtual ~Widget();
+ long w_id;
+ long n_id;
+ wxString name;
+ wxString description;
+ wxString short_description;
+ long num_downloads;
+ wxString mods;
+ wxString author;
+ long num_images;
+ long rev_major;
+ long rev_minor;
+ wxString rev;
+ wxString date;
+ wxString changelog;
+ ExtendedInfo extendedinfo;
+ bool is_installed;
+
+ bool IsInstalled();
+ wxArrayString GetImageFilenames();
+ bool GetImageInfos();
+ bool DownloadImages();
+ bool GetFileInfos();
+ bool Install();
+ bool Remove();
+
+ bool Equals( const Widget& other ) const ;
+};
+
+#endif // SPRINGLOBBY_WIDGET_H_INCLUDED
--
single/multiplayer lobby for the Spring RTS engine
More information about the Pkg-games-commits
mailing list